电商系统账务中心架构演化

        随着电商类的在线交易平台越来越多,涉及到资金操作相关逻辑也惨杂其中。然而大多数的程序员并不具备账务领域的专业知识,相关资料也很匮乏,完全靠自己一步一印的踩坑(我也是其中一名)。现将自己这些年接触账务领域的点点滴滴记录下来,旨在给需要的小伙伴扫盲。

     一、账务是什么

        账务就是管控一切资金行为。系统里的账务产生的数据,会提供给公司里的会计或者用户进行对账。而我看到最多的情况就是他们对着对着就账不平了,有的资金错误问题我们发现了会计没发现,有的问题会计发现了我们没发现。甚至有用户(大卖家)经常过来质问“我的钱怎么算出来亏了”,我知晓后不怀好意的揣测:可能这个用户随着在平台上做生意,生活慢慢改善了,房子车子都买了,最后在系统上对账盘利润发现是负的,直接懵逼。讨说法无果后,这个用户只好持续“亏损”状态下挣更多的钱。


        说到这里可能都很好奇,为什么钱会消失?当时的我也很好奇,研发人员就负责功能实现,你要啥就给你实现啥,咋就这么多问题呢?下面就从我所亲身经历的项目来尝试探讨账务的本质。

     二、初识账务

        初工作时被安排到一个新项目组里,负责实现新系统里的订单交易功能(这么重要的功能就丢给我这个菜鸟)。当时的设计非常粗暴,扣款加款都依赖于订单状态,归属于账务领域的表只有:余额表、资金明细表。如下图:


        就这样以最简单的方式把功能实现了,也顺利上线运营了,感觉自己挺牛逼的。过了一段时间偶然发现代码里有个瑕疵(严重bug),订单完成后在某个场景下钱无法加到卖家余额里。排查发现有个卖家账户里少加了几千元,他不知道,公司会计不知道,我是第一个知道,整个公司的生死存亡就看我代码写的怎样了(惶恐中)。

        在这样的模型下,强耦合了订单和余额的关系,所有余额的扣减如果要相对安全准确,就必须和订单表绑定在一个事务里,但后续遇到其他订单或者付款单据时,就得要把余额与所有业务付款单据都进行事务绑定,极其混乱。不久之后在当前SOA大背景下进行了账务中心的拆分,形成领域聚合。

     三、领域聚合

        账务中心拆分出来自成领域服务,需要与订单解耦,此时需要引入账务领域的支付单来代替订单。同时增加了网关单专门与微信等第三方支付渠道对接,这样带来的好处是职责分离,支付单专门对接业务,网关单只对接支付渠道。如下图:


        聚合成账务中心后解决了几个方面的问题:①账务中心抽象出统一的资金行为,支持任意业务单的付款使用;②账务的业务聚合起来由专职团队维护,不会再让我这样的菜鸟程序员有写bug的机会;③可以输出统一的对账数据,避免资金数据散落。

        在不具备账务领域专业知识的背景下,到这步改造已经基本结束了,后续只需根据业务需求再补充一些充值、提现、退款等功能场景。然而异常场景带来的对账问题并没有得到解决,比如说:在线微信支付成功后,支付单支付失败或金额发生变化了该如何保障?订单异常出错卡在已支付未结算时如何对账?

     四、资金落地

        资金落地这个概念极其重要,意思就是所有的资金都必须落在对应的账户余额里,而不能卡在单据里。比如余额支付100元,支付之前这笔100元在买家的账户余额里,支付之后就消失了,同时支付单会变成已支付,在结算成功之后这笔100元才会出现在卖家账户余额里。这种情况下整个系统的账很难核对,特别是在系统出故障后带引起大量的资金悬而未决,需要人工一一核对。引入资金落地后如下图:


        做了两点调整:

        1、所有的在线付款线经过充值再付款,这样做的好处是只要微信等支付渠道回调成功,就可以把在线付款的钱落地到买家账户里,不会因为支付失败而丢失资金;

        2、引入平台担保账户,所有买家已支付,卖家未收到的钱全部入担保账户,这样会计对账时只需要看所有的账户余额就能掌控资金的去向。

     五、中央银行

        引入资金落地概念后让资金变得有迹可循,担保账户的介入让交易资金从原来的凭空消失和凭空出现变成了资金转移。但并不完美,还是存在充值会让资金凭空出现,提现会让资金凭空消失。于是我引入中央银行的概念,彻底消除所有的增与减,让所有资金符合一个规律:“资金不会凭空出现也不会凭空消失,只会从一个账户转移到另一个账户”。如下图:


        中央银行发行账户初始化时发行1亿资金,有用户充值时就从发行账户转账到被充值账户,消灭了充值的无中生有。引入结算单,将支付和结算分离,但结算单会依赖支付单。

        相对于充值、支付、结算等正向流程,逆向流程如下图:


        退款行为做了退款和提现统一抽象,通过逆向网关单与微信等支付渠道打通,整个流程分成三步:

        1、退已经结算给卖家的钱,从卖家账户里把钱扣除退还到平台担保账户里;

        2、退款给买家,从平台担保账户里把钱退给买家;

        3、原路返回,触发退款(提现)行为,从买家账户里把钱先转入在途账户,等微信回调退款成功后再从在途账户里回收到中央银行的发行账户。

        综上所述,做到了任何时刻,系统里所有账户(包括发行账户)总余额是1个亿。与现实世界进行对比,所有充值行为就类比为一种外汇与中央银行兑换本币资金,所有提现就是用本币兑换外汇行为,市面上所有印出来的资金总量是1个亿,当然如果不够用了,介于大量充值行为(外汇担保)继续增加货币发行量。

     六、虚账约束

        在上问的架构设计中,通过引入系统级别的发行账户、担保账户和在途账户,将所有资金被牢牢锁住。这些账户加上所有用户的余额账户均为实账,方便对账和追溯资金来源,但是并不能做代收代付的安全约束,比如支付100元却结算200元,或者是支付100元退款300元等等,甚至每笔支付单还会存在多个返点单。要想解决这个约束问题,需要引入支付单的虚账概念。所有交易资金都会进担保账户,但是担保账户共用的,无法体现在每笔支付单上的分配。可以通过每一笔支付单上设置虚账来记录当前拥有的担保资金余额,每次操作原子性更新,通过支付单来约束相关结算单、返点单、退款单。可以得出所有支付单上记录的担保资金余额总和等于系统担保资金余额,结构关系如下图:


        支付单为每笔交易行为的总管理,正向流程与逆向流程都通过支付单对应的虚账来做控制,可以防范超结算超退,同时也能统计出异常存留的担保资金。

        同样的道理,在途资金映射到每笔提现单上提现的金额也算是提现单的虚账,用户提现后可以看到自己可用余额是多少,冻结余额(在途)是多少,这时展示的冻结余额并没有实际的账户映射,只是方便查看的一种虚账。

     七、总结

        上文的分析做一个归纳总结:

        1、账务中心不依赖其他任何系统,所有的账户余额和单据都归属账务中心所有;

        2、不要在一个单据上做多种行为,支付和结算通过单据隔离;

        3、资金必须落地;

        4、资金不能凭空出现与消失,只能从一个账户到另一个账户(去掉代码里的加钱和减钱行为,只留原子性的转账行为);

        5、系统级的账户有:发行账户(中央银行)、担保账户、在途账户;

        6、账户中心只忠实记录所有的资金行为,千万不要将营销抵用金、记账本等非资金行为引入;

        7、实账容万金,虚账定乾坤。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,492评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,048评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,927评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,293评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,309评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,024评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,638评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,546评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,073评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,188评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,321评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,998评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,678评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,186评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,303评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,663评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,330评论 2 358