在Axapta3中计算科目余额以及期间发生额经常要用到LedgerBalanceSum开头的一些类,比如计算本位币金额用到的类LedgerBalanceSum_CurrentMST,这些类的继承关系为:
LedgerBalance->LedgerBalanceSum->LedgerBalanceSum_Current->LedgerBalanceSum_CurrentMST。下面以LedgerBalanceSum_CurrentMST为例来分析大致的计算过程。
LedgerBalance是一个虚类,定义一些基本的成员变量,比如fromdate、todate、debit、credit的计算等。LedgerBalanceSum从LedgerBalance扩展,定义了三个最主要的方法:
- balance(LedgerAccount accountNum, companyId company = '') - 计算余额发生额的主要方法,由它返回需要计算的金额,根据传入科目的类型来分别调用SumBalance()或者SumTransact(),如果科目类型为 LedgerAccountType::sum即Total类型则调用SumBalance(),如果科目为LedgerAccountType::AccountLiable及其以下的类型(包括Liability、Assert、Balance、Cost、Revenue、Profit&Loss)则调用SubTransact()计算。
- sumBalance(LedgerAccount accountNum, companyId company) - 如前所说,这个函数用来计算Total类型的科目余额发生额,首先从LedgerTableInterval查找这个Total科目所包含的子科目段,再从所有科目段中取出所有子科目,对这些子科目一一调用balance()计算其余额发生额并汇总,函数的返回值为汇总额。
- sumTransact(LedgerAccount accountNum,companyId company) - 用于计算交易类型的科目,在LedgerBalanceSum类中是个空的虚函数。
类LedgerBalanceSum_Current从LedgerBalanceSum扩展,添加函数initPeriod()用来初始化fromdate、todate、opening、closing等成员变量;添加 q_AddDebCredCriteria(QueryBuildDataSource qB)对传入的QueryBuildDataSource增加针对LedgerTrans表的crediting字段的过滤;添加q_AddDimCriteria(QueryBuildDataSource qB)对传入的QueryBuildDataSource增加针对LedgerTrans表的dimension字段的过滤;添加 q_AddOperationsTax(QueryBuildDataSource qB)对传入的QueryBuildDataSource增加针对LedgerTrans表的operationsTax字段的过滤,实际上这三个q_开头的函数在后续的计算中并没有用到。添加空的虚函数buildQuery()用于后续扩展类构建Query。
我们真正用来计算科目余额发生额的类是LedgerBalanceSum_CurrentMST,从LedgerBalanceSum_Current扩展,重载基类的buildQuery()和 sumTransact()两个函数:
- void buildQuery() — 用于构建Query和QueryRun,如果包含期间opening,从LedgerBalancesDim视图创建Query q_BalanceOpening,对它添加LedgerBalancesDim字段transDate值为fromdate的过滤,添加periodCode字段值为PeriodCode::Opening的过滤,以及dimension字段的过滤,然后从q_BalanceOpening创建QueryRun保存到qR_BalanceOpening;如果还包含Regular(Normal)或者Closing的期间,则从LedgerBalancesDim视图创建Query q_BalanceRegular,对它添加LedgerBalancesDim字段transDate值为fromdate到todate的过滤,添加periodCode字段值为PeriodCode::Regular或者/以及PeriodCode::Closing的过滤,以及dimension字段的过滤,然后从q_BalanceRegular创建QueryRun保存到qR_BalanceRegular。
- real sumTransact(LedgerAccount accountNum, companyId company) - 如果qR_BalanceOpening不是null,对其添加accountNum字段值为要计算的科目代码的过滤,随后对这个QueryRun循环取出ledgerBalancesDim记录,对所有ledgerBalancesDim记录调用balance()并汇总;同样如果qR_BalanceRegular不是null,对其添加accountNum字段值为要计算的科目代码的过滤,随后对这个QueryRun循环取出ledgerBalancesDim记录,对所有ledgerBalancesDim记录调用balance()并汇总。两个Query的汇总结果合并为返回值。
有必要来看看视图LedgerBalancesDim,它是对表LedgerBalancesDimTrans根据字段AccountNum、TransDate、PeriodCode、Dimension、SystemGeneratedUltimo对DebitMST,CreditMST等字段的汇总,表LedgerBalancesDimTrans的记录是在过账LedgerTrans时自动生成或更新,目的就是建立对AccountNum、TransDate、PeriodCode、Dimension、SystemGeneratedUltimo这些字段对总账交易汇总索引,方便后续直接汇总计算,而不需要再从原始LedgerTrans汇总以加快计算速度。
梳理一下LedgerBalanceSum_CurrentMST的计算,简单的讲,首先根据总账科目的类型,如果是Total类型的科目,则计算其下子科目的balance汇总,如果是交易类型的科目,根据是否包含opening、normal期间分别创建对LedgerBalancesDim视图相应期间类型的汇总查询相应的字段为balance。
看一下LedgerBalanceSum_CurrentMST的构造函数,它的参数繁多:
void new(TransDate _fromDate,//起始日期 TransDate _toDate,//终止日期 DimensionCriteria _dimCriteria = dimensionCriteriaDefault,//交易Dimension NoYes _regular = NoYes::Yes,//是否包含Normal期间 NoYes _opening = NoYes::No,//是否包含Opening期间 NoYes _closing = NoYes::Yes, //是否包含Closing期间 OperationsTax _operationsTax = OperationsTax::Current,//税金类型 DebCredProposal _debCredSpec = DebCredProposal::None,//如何计算credit/debit,None为包含两者合计 NoYes _cache = NoYes::No,//是否使用cache,后续调用balance不再重新计算,而是从cache取值 NoYes _sumAccounts = NoYes::No,//没有使用 NoYes _closingBySystem = NoYes::No) //是否包含系统关账,影响SystemGeneratedUltimo的过滤
如果要计算一个科目在某个日期的余额,可以这样来用:
DimensionCriteria dimensionCriteriaEmpty; LedgerBalanceSum_CurrentMST banlanceMST; FromDate fromDate=datenull(); ToDate toDate=str2date('2013-1-14',321); ; banlanceMST=new LedgerBalanceSum_CurrentMST(fromDate, toDate, dimensionCriteriaEmpty, NoYes::Yes, NoYes::Yes, NoYes::Yes); print banlanceMST.balance('123201000000');
如果是要计算科目在某个日期的当期余额(财务期间的开始日期到当前日期):
DimensionCriteria dimensionCriteriaEmpty; LedgerBalanceSum_CurrentMST banlanceMST; ToDate toDate=str2date('2013-1-14',321); FromDate fromDate= LedgerPeriod::findOpeningDate(todate); ; banlanceMST=new LedgerBalanceSum_CurrentMST(fromDate, toDate, dimensionCriteriaEmpty, NoYes::Yes, NoYes::Yes, NoYes::Yes); print banlanceMST.balance('123201000000');
如果是计算科目在某段日期类的发生额:
DimensionCriteria dimensionCriteriaEmpty; LedgerBalanceSum_CurrentMST banlanceMST; ToDate toDate=str2date('2013-1-14',321); FromDate fromDate=EndMth(PrevMth(todate))+1; ; banlanceMST=new LedgerBalanceSum_CurrentMST(fromDate, toDate, dimensionCriteriaEmpty, NoYes::Yes, NoYes::No, NoYes::No); print banlanceMST.balance('123201000000');
另一个用得比较多的balance计算类是LedgerBalanceSum_CurrentCur,也是从LedgerBalanceSum_Current扩展而来,计算的是总账交易原币金额的余额发生额,所不同的是在buildQuery中从LedgerTrans表创建Query,对LedgerTrans表的AmountMST或者AmountCUR根据TransDate、PeriodCode、CurrencyCode、AccountNum汇总查询,相应的sumTransact()从LedgerTrans汇总的结果得到Balance,其构造函数和LedgerBalanceSum_CurrentMST类似:
void new(CurrencyCode _currencyCode,//币种 NoYes _conversion, //是否转化为本位币 TransDate _fromDate,//起始日期 TransDate _toDate,//终止日期 DimensionCriteria _dimCriteria = dimensionCriteriaDefault,//交易Dimension NoYes _regular = NoYes::Yes,//是否包含Normal期间 NoYes _opening = NoYes::No,//是否包含Opening期间 NoYes _closing = NoYes::Yes, //是否包含Closing期间 OperationsTax _dS = OperationsTax::Current,//税金类型 DebCredProposal _debCredSpec = DebCredProposal::None,//如何计算credit/debit,None为包含两者合计 NoYes _cache = NoYes::No,//是否使用cache,后续调用balance不再重新计算,而是从cache取值 NoYes _sumAccounts = NoYes::No,//没有使用 NoYes _closingBySystem = NoYes::No) //是否包含系统关账,影响SystemGeneratedUltimo的过滤
它的具体使用方法不再赘述。
以上分析基于Axapta 版本3.0 SP4。