Richie

Sometimes at night when I look up at the stars, and see the whole sky just laid out there, don't you think I ain't remembering it all. I still got dreams like anybody else, and ever so often, I am thinking about how things might of been. And then, all of a sudden, I'm forty, fifty, sixty years old, you know?

分析模式 - 库存和账务模式

对财务系统没有经验,基于自己有限的认识记录一下对Accounting Model的理解

1. 账务模式基本模型
:
   
Account: 如果是指个人理财方面(分析模式书中的示例场景),当译做账号;如果指财务会计方面,当译做科目
Entry: 交易条目
Accounting Transaction: 交易

简单ER设计示例:
   
加了个"科目平衡 Banalce 1"的表,是因为Martin在这一节中不少地方都使用Account balance: Quantity表达,即Account对象有个balance属性,对个人理财的示例而言balance应当指账户的当前余额,而对于财务会计而言balance具有更多意义,即科目平衡表,在概念上科目、科目平衡表是独立的

这反映的是复式计账法(double entry bookkeeping)的基本设计方案,例如从支票账号(checking: Account)兑现100$到现金帐号(cash: Account),则交易和交易条目如下图:
   
这个交易包含两个条目,一个对应到现金帐号,数量是+100,表示现金帐号增加100$;另一个对应到支票账号,数量是-100,表示支票账号减少100$。交易中两个条目的数量之和为0
财务会计中使用借贷属性来表示,上面这个交易借记现金帐号,贷记支票账号,规则就是交易的借记汇总数量必须等于贷记汇总数量

备注:
a.) 不同业务环境下具体实现差异比较大,这个模式提供的是基本思想,只是一种参考不要生搬硬套
   库存方面参考: 库存系统设计示例
   财务系统、ERP财务模块基本原理跟模型一致: 账必须绝对平衡。但涉及的方面太多所以情况很复杂,例如科目繁多并涉及到企业经营中的各种业务概念;现金、资产、应收、应付等各个方面都有复杂的操作流程,它们可能衍生出复杂的业务模块,例如应收、应付在很多ERP中作为独立的模块。一种设计方式是集中管理,不过面对的复杂性和压力比较大,设计难度很高;另外一种是分散管理,例如应收、应付模块有自己的交易表;库存交易是固定资产中的一种,另外的是办公设备、生产设备等,他们更侧重于对损耗折旧、维修维护等方面的管理;针对现金管理也可能单独设计一个交易表。(例如库存系统设计示例中是一个中型ERP系统的设计,库存交易表中设计了单价、币别、交易成本等数据,他们将与应收、应付模块结合起来实现财务方面的部分逻辑)。后面这种设计方案下财务交易只是一种抽象概念,具体实现上被分散到了不同的地方,月结时综合考虑各个分散的部分。另外针对总账设计一些平衡表,例如月度、季度、年度损益表和资产负债表,以反映财务的汇总体状况。这种设计在各个业务模块与财务模块之间在复杂性上实现了一定平衡考量,但随着各个业务模块和财务模块需要支持更复杂的逻辑时将面临比较大的困难,因为他们之间的逻辑耦合性太高
   对于银行系统,个人、公司等客户的存、提款是基本业务;从个人账户角度看,基本关注点是交易条目这个对象,即自己在什么时候、用什么方式(柜台、ATM、刷卡消费等)、在什么地点存、取了多少金额,以及当前账户余额之类;从银行全局角度来看,它需要关注交易的全部、整体,例如银行内部转账、跨行转账时资金在不同账户间的流向、平衡等;银行业务种类越来越多,例如个人网上支付、协议交费业务、刷卡消费、房贷车贷等,尤其对公司业务的支持更复杂,例如代发工资(一个交易涉及到很多账户,即在一个交易中将工资总额从公司帐户划拨到各个员工账户上)等,因此它的交易系统与财务系统差别很大
   另外对于网上支付等虚拟交易系统,以及其它各方面,基本原理类似,但实际设计都有各自的特点和针对性
b.) 示例中相关设计使用了公司代码,因为假设财务范围为公司层级
   示例中的科目设计采用了简单的Adjacency List Model,也可以采用责任模式等其它方法
   类似库存系统设计示例中提到的,借贷属性可以使用正负金额或其它设计方式
   示例中交易和交易条目采用了一对多的设计,因此能够支持多条目的交易,对于只需支持两个条目的交易可以采用类似库存系统设计示例中的方法

2. 汇总科目(Summary Account)、明细科目
一般交易科目只是明细科目
科目本身维护相当简单,复杂在于对各种企业活动进行财务记账时对科目的使用方面。总体来讲一级科目分类为资产类、负债类、成本类等,伴随着科目层级细分下去直到最终的各个分录,这是这些规则分解细化的主体思路
除了从不同国家地区、公司、行业的财务规范、操作流程方面考量来设计财务系统的账务模式之外(高抽象层次的规则设计),基于科目针对一些细节方面进行规则设计也能带来很大的使用灵活性,以SAP为例:
科目过账容差设计(Tolerance Groups & Tolerance): 针对会计人员做账时的容差设计,例如单笔金额容差不能超过多少、支付差额(客户多付少付金额等)不能超过多少等等
科目组的输入控制: 属于该组中的科目哪些参数必须维护、哪些参数可选维护、哪些不能维护
字段状态变式(Field Status Variants): 录入该科目的凭证单据时哪些辅助核算项目必须维护、哪些不能维护

3. 备注科目(Memo Account)
书中所举的例子比较直观很好理解。基于国外自行进行税务申报的体制,从个人理财角度来看,当月有一笔收入时,必须除去税收之后的剩余金额才是个人实际收入所得,但税务申报只在固定时刻发生,如果不做特别处理则下个月度查看上月财务状况时得到的是不准确的报告。因此设计一个应付税科目(tax liability account),该科目只是一个虚拟科目,因为实际的缴税活动还没有发生,只是为了让个人的财务统计状况更准确而以。备注科目不参与账务平衡计算(因为实际的交易活动并未发生),但相关科目的交易发生时(例如有收入进入个人收入科目),必须为备注科目产生交易条目
ERP中的应收、应付之类基本概念类似,不过需要面对企业财务的标准、更多复杂情况而以
例如SAP中专门设计统驭科目GRIR等,解决OA30、TT30等不同付款方式造成的货到票未到、票到货未到等特殊情况,其基本含义也就类似上面
因为特定的流程、逻辑太多,所以应收、应付通常被设计为独立的模块、组件,相关的数据也被分离到另外独立的表中存储

4. 过账规则(Posting Rules)
以应付税科目为例,在个人收入科目有收入交易时,系统需要自动计算应付税额,为应付税科目添加一个交易条目。应付税额不是简单运算能得到,例如国内的个人所得税计税方式就有应税基数,分级进行税额计算,这是一组复杂的计算规则,并且这些规则经常会调整,所以设计一个可配置的过账规则非常必要
另外分析模式书中提到的工资计算问题,对生产线上严格按刷卡时间计算薪水的情况是很普遍的,多长时间算是正常工作时间,什么情况才算加班,不同情况下的加班费用如何计算,迟到请假如何扣薪等,都是很复杂的规则配置
ERP中大量的使用过账规则的设计,例如采购入库、销售出库等能够自动产生相应科目的应收、应付条目
对过账规则设计应注意可反向冲销(reversibility),保持绝对严格的事务一致性

过账规则实现方法
a.) 单类 Singleton Class
   
   对每一个过账规则使用一个派生类

b.) 策略模式 Strategy Pattern
   

c.) 内部条件语句实现
   使用if..else..或者swich..case..实现

d.) 参数化方法 Parameterized Method
   
   上图示例不同地区、不同性别的人缴税规则不一样,过账规则处理时根据条件加载正确的规则,根据规则的参数进行处理

e.) 解释器 Interpreter
   使用字符串描述规则,用解释器解析、处理这些规则

相对于单类方式,策略模式降低耦合带来更多一点灵活性;参数化方法可以减少派生类的数量;解释器针对特定方面进一步加强参数法方法的表现力
对于类似工资计算的过账规则,采用策略模式+参数化方法+解释器可以做的比较灵活;对于一般复杂度的规则使用参数化方法或者加上策略模式等应当基本足够

过账规则的执行
a.) 主动触发 Eager Firing
   一种实时处理方式。一种实现方式是创建交易或交易条目时加载相关的过账规则,处理完交易条目后逐个处理过账规则;另一种方式是使用观察者模式,观察者过账规则,被观察者为科目或交易条目
b.) 基于科目的触发 Account-based Firing
   一种延时处理方式。对应每个科目维护一个未处理交易条目列表,交易完成时只是将交易产生的各个条目添加到相应科目的未处理列表中,使用另外的服务周期性的处理各科目的未处理列表,同时加载与科目相关的过账规则并进行处理
   需要注意各个条目和过账规则的先后处理顺序
c.) 基于过账规则的处罚 Posting-rule-based Firing
   有点类似基于Account-based Firing,是一种延时处理方式,不过未处理队列不是按照科目而是基于过账规则设计
d.) 内部链触发 Backward-chained Firing
   一种延时处理方式,基本类似Account-based Firing,不过在处理交易条目和过账规则时,将交易条目和过账规则组织成一个处理链的方式进行

5. 行业惯例 Accounting Practice
不管库存管理还是财务会计或者金融交易系统等,都存在很多行业标准、操作习惯,从设计上看就是一组系统预设规则的组合,这里讨论如何把过账规则组合起来进行处理
可能不同的行业、不同国家地区这些惯例会不一样,所以会使用一些设计方法处理这方面问题

6. 平衡表和收入清单 Balance Sheet and Income Statement
应当是财务会计方面比较专业的词汇了,他们是不同的概念,设计上也应当分开考虑
收入清单应当对应到企业财务中的损益表(利润表),资金平衡表则应当对应到资产负债表
可以用过账规则来处理,企业库存、财务管理简单的可以在月结动作中完成

7. 错误调整
财务会计中记错帐也是不可避免的事情,对错误进行调整有几种方案
a.) 替换调整 Replacement Adjustment
   这种方法是直接将错误的交易条目修改或替换为正确的。一般财务会计、金融系统等都不允许这样做,例如你3月份打印一个银行帐单,里面一条记录是某天在某商场刷卡消费1000块,但到了4月份你再次打印3月份的账单时这笔消费变成了1500块,这是不允许的,因为我们无法信任这个打印的账单
b.) 反向调整 Reversal Adjustment
   仍以a中的例子说明,4月份银行发现这笔消费记录做错了,但前提是不能直接修改这个历史交易条目,因此先在个人账户和商场账户之间补做一笔反向交易(将3月份已发生的交易看作正向,即从个人账户转账1000元到商场账户,那反向交易则数量仍然是1000元,转账方向是从商场账户转账到个人账户),以抵消3月份的错误交易条目,然后重新做一笔数量为1500元的交易,方向是个人账户转账到商场账户,这样结果就正确了
   当然银行在这样做之前先必须在商场和个人之间达成许可协议,这样商场和个人对4月份反向调整产生的2笔交易条目都清楚其原因
c.) 差异调整 Difference Adjustment
   仍以a中的例子说明,这次不用先做1000元的反向交易冲销错误记录,而是先计算好错误结果和正确结果之间的差异1500-1000=500元,因此直接补做一笔500元的交易,从个人账户转账到商场账户,这样结果也正确了

8. 来自Martin的校正、对照
在Martin网站可以看到最新的分析模式描述,与原来书中有一些差别,可能是打算过出新版吧
大致浏览了一下,差异主要在于整体组织结构的调整(分成主要的几个部分分别阐述,每个部分先提出问题,接着讨论使用时机,最后给出示例代码讲解);对原来缺失的内容补充(例如上面7中的错误调整方式)

关于模式内容方面主要是显示的提出"事件"这一概念,涉及到的一些方面都围绕"事件"进行了一点调整
   
企业财务和库存系统中,用户是看不到"交易"这样一个概念的,交易只是系统内部的一种机制,用户在系统中录入一张单据,或者执行某个操作等各种事件发生时,将触发创建交易的操作
所以Martin将这个过程更抽象一点,引入事件(Event)、事件类型(Event Type)、协议(Agreement)这几个概念
每个事件将对应到一个事件类型Event Type;一个事件类型将关联一组过账规则Posting Rules,用于处理属于该类型的各个具体事件;在设计层面事件类型反映出来的是一个协议Agreement,该协议决定了这类事件的处理逻辑

从上图来看,对事件类型和协议可能有一些疑惑: 事件类型已经关联了一组过账规则,事件发生时直接加载这些过账规则逐个处理就是了,为什么还需要"协议"这个对象?
从前面过账规则的定义来看,它的职责是处理一些附加的事情(类似使用AOP将其它方面的一些事情插入到某个交易逻辑中),或者交易处理逻辑本身非常复杂并且需要做成一组组灵活的可以修改、替换的规则,而采用过账规则来实现。而协议Agreement则是完成交易逻辑的统筹者,包括加载过账规则并正确执行他们。尽管理论上也可以将协议Agreement全都实现为过账规则,通过事件类型配置起来,不过钻到实际情况中就可以体会到这样做的难度,从上图来看,会计条目Accounting Entry是由过账规则而并不是协议Agreement创建,看来Martin应当正是指的这种方法了,如果这样协议Agreement的主要职责就是处理不同的上下文内容,以及对过账规则的调度处理

posted on 2008-04-14 19:56  riccc  阅读(5293)  评论(3编辑  收藏  举报

导航