会计引擎:交易与核算分离的前世今生
文章来源:e路向上,文章仅供个人学习
一、为什么需要会计引擎
金融产品的设计,一如一块硬币需要兼顾两面:一面是为客户提供好的金融服务,满足客户支付结算、借贷、资产保值增值等方面的需求,并在这个过程中,以数字化的方式做好客户资产的登记,登记的载体,则是“分户”或“台账”,如客户存款户,是一种典型的分户–资金的增减变化都在一个账户中进行体现,而客户购买的银行理财,因为收益率、期限、投资标的不同,每一笔持有就形成一行记录,即为“台账”–这当然是不严谨但相对形象的表述。
但是,“分户”和“台账”并没有必然的区别,以贷款为例,一些银行仍然存在所谓“贷款户”–分户的概念,而有些银行则取消了“贷款户”,直接代之以“借据”–一种典型的台账,其他如定期存款,一张一张的存单,实际上也是一种“台账”的概念,但一直以来的系统设计模式中,通常还是会为客户开立一个“定期账户”–归类到“分户”的概念下;另一面,对银行的经营管理而言–无论是财务会计还是管理会计,当需要了解一家银行当前的负债结构、有哪些生息资产,一个经营周期的收入、成本、利润分别是多少时,显然不能够依靠将银行所有不同种类业务的台账、不同客户的账户进行加总去获得一份统计报表,更遑论商业银行的经营需要满足“会计准则”的一系列要求。于是,在“分户”和“台账”之外,“总账”或者说“科目账”应运而生。总分账户对应关系示意图:
总账台账对应关系示意图:
会计的起源不多做赘述,对开发人员而言,只要知道这是会计人员操持的一种特定语言,一如程序员熟悉的JAVA一样,会计也有一系列自己的框架、约定及处理规则,会计当中有所谓的三表,即“资产负债表”、“利润表”及“现金流量表”,他们的生成均来自“总账”。
对系统的开发人员而言,“资产负债表”和“利润表”中的“资产”、“负债”、“收入”、“支出”这4个类别的科目,加上用于系统间往来或机构间往来的“共同类”科目以及“表外”科目,构成我们在开发当中最常接触的6类科目。
银行在年终结算时会由会计账系统将损益结转至“未分配利润”,算是有限能接触到“所有者权益”科目的场景。“分户”、“台账”的处理基本属于“所见即所得”的范畴,比较容易有体感,比如活期账户存入了一笔钱,对应就是账户余额的增加,支出了一笔钱,对应的是账户余额的减少,收到一笔利息,也是账户余额的增加等等。但是对总账的处理,则进入了会计专业的范畴,不论是分录的生成、借贷平衡测算,还是其他的就不那么容易理解了,尤其是复式记账法涉及的不同类型科目与借贷搅和到一起的时候,就比较费解了。以一笔最简单的贷款放款为例,会计分录为:
DR(借)贷款本金-映射为资产类科目账 |
---|
CR(贷)客户账-映射为负债类科目账 |
其反映的是,银行资产负债表中贷款类资产和存款类负债的同时增加。因为会计科目中,不同类型科目反应余额的方向不同,再叠加权责发生制(摊销和计提)原则的要求,易造成开发同学在“转译”时很难转过弯来,比如资产类科目借方蓝字发生额是余额“增加”,负债类科目贷方蓝字发生额是余额“增加”,收入科目贷方蓝字发生额是增加,支出科目借方蓝字发生额是“增加”等等,很容易就被绕晕了。因此,对开发来说,如何能在服务或产品实现过程中屏蔽会计属性,而仅简单地关注服务实现本身,就是会计引擎要完成的工作了。以刚刚的贷款放款为例,以会计语言表述是上述的借贷分录。而开发人员、产品经理感知到的是:银行将为A客户发放一笔金额为X元人民币的1年期流动资金贷款,贷款发放到A客户的Y账户。
如果有一项功能,能够直接将这一句描述转译成上面的会计分录,则程序员、产品经理的工作都将被大大简化。而会计引擎的设计,核心就是将一系列金融产品发生的业务操作转义为会计语言(分录)的过程。在“银行将为A客户发放一笔金额为X元人民币的1年期流动资金贷款,贷款发放到A客户的Y账户”场景中,开发人员只需要将“什么业务”–1年期流动资金贷款,发生了“何种交易”–贷款发放,“金额”及“币种”–X元人民币,“其他的影响因素”–如客户性质(个人还是企业),这些要素通过消息的方式发送给会计引擎,再有会计引擎直接转译出此前的分录,会计因素对开发和产品设计的侵入将被大大减少。
二、银行系统交易与核算分离的缘起
但是,目前在商业银行已经被普遍接受的“交易与核算分离”,起初的动因似乎并不是为了屏蔽会计对产品及开发的复杂性,而是为了将核算模块从银行的核心系统剥离,主要为实现三个目的:1、降低外围系统与核心系统的耦合度;2、缩短日切时间(传统银行的日切在线处理,互联网银行也有采用离线处理的);3、提高核心系统吞吐能力。传统银行交易与核算分离前后的示意图如下:
交易与核算分离前
交易与核算分离后
采用这一模式分离后,外围产品系统与核心系统之间的关联,仅剩客户账入账部分。而对于以下两类情形则被大大简化:
1、对一些需要内部户核算业务规模的产品,如理财产品发售、国债发售、票据资产的规模等等,内部户的更新在解耦后,产品系统与内部户之间不再采用同步接口方式处理,而改为异步消息方式,内部户中,为避免热点账户问题,则设置消息队列,将消息明细汇总轧差后再去更新内部户余额,大大提高了系统吞吐能力;
2、核心系统的日切实现了全面解耦,大大提高了核心系统日切的处理时效。外围系统在晚间日切处理时,也需要对损益做计提处理,或者将预收利息做摊销处理,计提或摊销的应收付、损益科目都以内部户形式记账,账务更新在分离前,都需要到核心系统进行记账,因此核心的日切完成,就需要等待外围产品系统日切(计提或摊销)完成,分离后,外围产品系统的日切账务仅以消息或文件方式与会计引擎发生关联。
这一分离模式解决了CIO经常关注的日切时效、核心系统吞吐能力问题,但离实现真正的“交易与核算分离”还存在距离。其问题在于会计借贷的组织仍需要由产品系统感知,开发人员在写代码时,仍然需要十分清楚应该借什么账号,贷什么账号,是一借一贷,还是一借多贷。为了实现外部账户(客户账)与科目账的映射,通常会引入一个类似“科目分类码”的字段,在产品工厂进行维护。
在一些宣传文章中,会计属性从产品的剥离,经常被描述为“更专注产品”,有利于产品创新。但这本身是个见仁见智的问题,原因不难解释:首先,所有金融产品在设计时,都需要一体两面的考虑,冰面以上的是面向客户的,强调易获得、交互体验的友好、易理解(比如零钱通就比货币基金亲民多了);冰面以下则是服务于金融机构内部的风险控制、经营管理决策的一系列内部流程、作业要求、经营分析,其中的财务会计、管理会计进行经营决策的重要抓手。一个掌握了会计语言的产品经理,当然也更容易明白CEO在资产负债表中更关注什么内容,CEO对净资产收益率、加权风险资本收益率的偏好会不会决定一款产品的前途;一个掌握了会计语言的开发人员,当然也更容易明白财务或运营人员在提出某个需求时,他实际上要的是什么。比如,对一笔贷款而言,发生核销时财务人员会给出如下的会计分录:
DR 减值准备 |
---|
CR 非应计本金 |
CR 已核销贷款本金–表外 |
这一组会计分录传达的语义实际上就非常丰富,它至少表达了如下两个意思:1)、在该金融机构,只有达到非应计状态的贷款才可以进行核销。而在核销前,不论是逾期状态还是非应计状态,这些资产都还躺在银行的资产负债表内,所以,知道为什么银行股的PB经常低于1吧–很多垃圾资产(坏账)被藏在资产负债表内了;2)、核销后,核销的贷款资产要登记到表外。(深层含义是不知道什么时候指不定这笔贷款又收回来了呢,要备用)。
由产品系统感知会计分录对开发人员理解业务逻辑实际上大有裨益,会计分录实质上是以会计语义讲述业务实质的一种业务语言,理解会计分录对理解业务本质,进行归因思考非常重要,我们以一笔票据转贴现业务为例,再来看一套会计分录中反映的业务语义:
DR 票据卖出临时存欠款项 |
---|
DR 转贴现利息调整(未摊销利息) |
DR 价差损失 |
CR 票据转贴现票面资产(直贴来源或转贴现来源) |
CR 价差收入 |
DR 人行待支付清算资金 |
CR 票据卖出临时存欠款项 |
DR 存放中央银行款项 |
CR 人行待支付清算资金 |
这套分录中,实际上反映了:
1、卖出的票据资产,最终变成了银行存放在央行的存款(通过大额支付系统清算后);
2、卖出的票据资产,有两种来源,一是直贴买入的,另一种是转贴现买入的,其核算科目不一样,需要区分;
3、卖出票据资产时,实际上把票据的收益权也转让给了买家,因此,需要将直贴或转贴买入时还没有摊完的利息核销掉;
4、卖出票据的时候,有可能赚钱,也有可能亏钱,因此有可能产生价差损失,也有可能产生价差收入。
以上4点,都在分录中得到了非常清晰的体现,而且,对会计引擎而言,要去感知转贴现卖出的票源是直贴还是转贴票源,并因此适配不同的会计科目,或是感知是产生了价差收入,还是价差损失,实际上只能依赖开发前票据系统与会计引擎之间的约定。总而言之,将“会计属性”从产品剥离是不是真的能让产品系统更专注“产品创新”,本质上还是要看怎么看待这个问题。
但是,“交易与核算分离”,尤其是将科目内容对一线业务/开发人员屏蔽,确实有利于用“人话”进行展业。笔者曾经在某商业银行做过企业贷款系统,这个信贷系统在支持客户或客户经理(代客)发起放款申请时,有个所谓的“贷款科目码”要求客户或者客户经理填写,填写者碰到这种情况,通常是两种反应:要么懵圈,要么填错。这是一个典型的银行将自己的经营管理要求向客户透出的例子,可以很容易地被归纳到“银行是21世纪待灭绝的恐龙”的证明案例中。实际上,贷款业务中客户需要感知的只应该是如下几个要素:我借的是什么品种的贷款、借款期限是多长、利率是多少、以什么样的方式还款、每期还多少、什么时候还、从哪个账号扣款、违约了怎么办?而根据其中的贷款品种、借款期限以及客户本身的一些属性,金融机构内部实际上就可以自己映射出需要的贷款科目。后来在系统改造过程中,我们将170多款贷款产品全部做了类似映射,想来也是比较简易的“交易与核算分离”。
商业银行在经营过程中,通常以“前台-中台-后台”的结构进行业务分工,前台面向的是客户本身,**对直接接触客户的理财经理、客户经理等人员,不仅是会计术语,所有金融专业的术语都应该谨慎透出(如贸易融资业务中的动态定额控货、核定库存;票据业务中的清单编辑、提示收票待签收等等),要让金融产品尽可能以大众化的语言进行呈现;中台主要是商业银行内部负责经营管理的团队,主要是零售、对公、同业等创利部门,这类部门一般会配置专职的产品经理,这一层一方面需要深刻洞悉客户心智,另一方面又需要具备足够深度的金融专业素养,十分清楚银行内部的运营流程、风险偏好、资金成本、数据产出、经营分析需要等等**,客户的金融服务需求在这一层被转义、分解为银行法务、合规、运营、风险等多个不同后台部门的支持职能;后台部门就包括了风险、运营、财务,还有IT,这类部门的特点是专业部门,在日常工作中都有一套自己的语言,比如风险操持的PD/LGD/EAD/Vintage/KS/AUC等等,IT操持的JAVA、C、GO等开发语言,而对财务,则是会计语言。通过交易与核算的分离,产品、运营、开发同学都不再需要感知会计属性,实际上是一种减负。从这个意义上来说,交易与核算分离,还有两个价值,即:一、有利于提供更符合客户心智的金融产品;二、有利于减轻产品、作业、开发岗的负担,加快产品响应速度。
三、交易与核算分离需要解决的问题
会计引擎设计最核心的就是“是一系列将金融产品发生的业务操作转义为会计语言(分录)的过程”,会计引擎至少有两个组成部分,一个是科目账处理引擎。主要解决分户、台账系统要登记哪个科目总账,及如何登记的问题(会计分录);另一个是内部户处理引擎。主要解决需要跨系统、跨机构,分阶段处理事务时的内部户使用问题。
1、科目总账引擎需要解决的问题
根据复式记账法的要求,一组典型的会计分录主要由如下几个部分组成:借贷方向、借贷科目、记账机构、记账日期、借贷账套。以一笔前置收取手续费的贷款放款为例:
这其中的机构,一般用于区别商业银行的分支机构或部门,便于计算业务规模和收入,记账日期一般在交易流水中提现,所有科目账使用的会计日为同一天,也不需要单独处理。剩下的主要是两个问题:
1)、在记账时使用哪个会计科目
有些金融机构广泛使用“产品码”的概念,通过“产品码”映射“科目码”来实现科目映射,当“产品码”设计粒度或维度有问题时,会造成大量的冗余配置,比如一个人民币活期存款和一个美元活期存款,可以是同一款产品,也可以是两款产品。
我们根因到业务原理,会计处理与业务的操作息息相关,而业务操作相关的科目,包括了资产负债表中的资产及负债科目,也包括利润表中的收入、支出科目。科目的映射,除了跟“产品”有关外,还有很多其他影响因素,以存款为例,就包括客户的类型(个人、企业、同业),存款的性质(理财保证金、外汇保证金、一般政府性存款、财政专用存款等等);在贷款业务中,科目的使用还受到期限的影响,比如短期贷款和中长期贷款一般分开核算,这些要素都会影响到最终使用的核算科目。
那么这里要注意的是,这些影响因素并非完全不可控,在业务大类确定的情况下,影响因素很容易确定,我们要避免使用不带业务含义的“扩展属性”来解决问题;此外,在一个业务交易动作中,除了产品本金外,还有对应的收入、支出、应收、应付、表外等相关的科目,这些科目与我们处理的金额息息相关,需要通过金额类型获得相应的科目。于是,最后在科目映射中的关系就被表述为:业务产品 + 一系列可配置的相关因素 + 金额类型 => 核算科目。
2)、使用什么样的会计账套
在部分金融机构的实践中,每个产品都会配置自己的会计账套,实际上没有这个必要,原因很简单,会计账套只与业务大类有关,在某一业务大类下的产品,其会计账套遵循同一原则。举个例子,以存款产品为例,不论是活期、定期、存款宝还是通知存款,其在存入时,都是贷记存款科目,在计提时,都是“借记利息支出,贷记应付利息”,无一例外。同样的,对贷款产品也是如此,有的银行贷款产品细分有100多种,比如流动资金贷款、项目贷款、设备贷款、固定资产贷款、联保贷款等等,但这些贷款的账套其实都是一样的,从放款、计提、还款,到转非应计、核销等,其会计账套都是一样的,可能出现不同分录的反而是利息收取方式不一样导致的,比如预收息模式要对利息做摊销处理,后收息模式才需要对贷款做利息计提。这是一个影响因素,即会计账套与“业务所属的大类”有关。
另外一个影响因素是业务的操作,在银行一般称为“交易”,由“交易码”进行标识,有金融机构又称为“事件码”或是“原子动作”。这个也很好理解,不同的业务操作,对应的会计账套是不同的,活期存款的原子动作大致有以下这些:存入、存入冲正、支取、支取冲正、计提、计提冲销、结息等等,而贷款的原子动作则有放款、还款、计息、摊销、转非应计、非应计转回、核销、转让、销项税计提等等。因此会计账套的映射可以归纳为:业务大类 + 交易 => 会计账套
有了科目映射和账套映射后,开发同学在编写代码时,就不再需要感知会计分录,而是只要以直观可感受的业务语言,向会计引擎传参,之后会计引擎便可以根据配置表自主完成会计分录。
以个人活期存款为例,当发生存入时,开发人员只要将“个人活期存款(产品及业务所属分类)账户AC(账号),发生存入(交易),本金(金额类型)1000元”发送给会计引擎。开发同学按会计引擎开放的接口,送入产品、账号、交易码、金额类型等要素,即可根据上述的会计引擎设计,自动完成会计分录,实现“交易与核算分离”,这种模式下,大大简化了开发人员的知识负担。
但是,作为一名金融行业开发人员,虽然“交易与核算分离”后解决了开发人员需要感知会计分录的问题,但是熟悉会计对理解金融产品创新,如ABS、买入返售、卖出回购、融资租赁等等,具有非常重要的意义,如立志在这个行业深耕,建议还是要熟练掌握会计相关的知识。
2、内部户记账引擎需要解决的问题
以上描述了一个业务领域内部怎么进行科目映射,这个科目账引擎在处理域内会计分录时没有任何问题,但如果遇到跨系统、跨机构的问题时,则会遇到问题,以一笔贷款放款为例,如果入账账户是行内账户,系统需要处理两笔账务,一是贷款的发放,借记贷款本金;二是存款账户入账,贷记存款科目,两笔分录可以分别由贷记系统和存款系统分别向会计引擎发送一条消息,即可完成。但是,如果一笔贷款,其入账账户是行外账户,或者像互联网信贷一样,收款方是支付账户时,因为涉及到第三方的往来,则在放款的时候,需要将资金暂挂到一个内部户中,待清算中心根据第三方的处理结果再对暂挂的内部户做后续处理。此时就出现了一个问题,因为第三方机构的不同,这个内部户可能是不一样的,这时候是由贷款应用在处理时就感知要使用的支付渠道、对手方,进而确定要使用的内部户,还是由清算中心来感知,是值得讨论的。
从业务合理性上讲,在该场景下,贷款发放后要转账到行外,实际上包含了一个本机构与第三方之间的清算行为,且因为使用的支付渠道不同,造成对应的头寸账户适用不一样,因而,由清算中心来维护这个支付渠道、对手方与内部户之间的关系是合适的, 但因为支付渠道、第三方机构有限,因此很多时候,也可以直接维护在贷款系统中,记账时,由贷款直接填入具体的内部户账号给内部户引擎记账。内部户在商业银行的使用、管理、设计等,另文详述。
3、会计引擎不适合自动映射的场景
那么,有没有无法自动实现账套映射、科目映射的场景,或者说不适合去折腾映射的场景?当然有,上面票据转贴现的案例就是明证,票据来源、是实现了收益还是产生了亏损,只有票据系统自己知道,这种情况下,谁最能将会计语义表达清楚,自然是票据系统自己。因此,很多据称很先进的会计引擎,通常都会鸡贼地再去加上可直接支持会计账套上送的消息接口。其实质是:你这个太复杂了,我转不了,你自己弄好送给我吧。类似的场景比较广泛地出现在同业业务中,债券投资、外汇投资、转贴现业务等等。
四、结语
账务处理是绝大部分金融产品必须面对的一个核心要素,会计是金融行业从业人员始终无法回避的一个高频词。会计引擎对产品经理、程序员屏蔽了会计的复杂性,将一系列金融产品发生的业务操作由系统自动转义为会计语言,其实现的“交易与核算分离”,对简化金融产品创新,加快金融产品开发意义重大。但会计属性是由业务层感知,还是沉淀到会计引擎中统一处理,本身见仁见智,没有好坏之分,诸多金融衍生品玩的都是表内倒表外规避监管的戏法,理解会计原理,对理解金融创新帮助极大,也有助于从本质上判断一款金融产品,究竟是革了金融业的命,还是只是获得了差别化监管红利。从这个意义上讲,优秀的产品经理,或有志于成为资深业务架构师的开发人员,都应该充分掌握银行会计。
会计引擎的建设除了技术侧对会计属性进行抽象、设计外,要取得良好的运用效果,统一的业务治理也同样重要,这里面还包括业务对科目体系的整体规划,对内部户的治理和使用标准的界定、挂销账的要求、科目日结单、总分核对、借贷平衡的检查要求等等。业务思想本质上是金融业务应用开发的灵魂,只有统筹业务需求与IT实现,才能既避免过度设计,有避免扩展性不足。