从业务事件到复式入账:一张流程图和一套前提
把收款、占用、结算、退款和未知结果放进同一条账务流程,说明复式账上线前需要准备什么,以及最后应该达到什么效果。
复式账的难点通常不在“借方加一行、贷方加一行”,而在于业务事件什么时候已经足够确定,可以进入账本。授权通过、通道接受、商户请款、银行到账和页面显示成功,可能是五个不同的时刻。
下面用一条简化流程说明如何把业务状态、账务状态和对账状态分开。流程图是系统设计示意,不是某个国家或企业的会计制度。
业务事件先不要直接改余额
一笔支付先进入业务事件层,保留稳定的业务引用、订单号、阶段、账户、原币金额、币种、来源和发生时间。每次通知的投递编号也要保留,但它可能随重试改变,不能代替业务引用。服务可以先把事件标记为 received、pending 或 unknown,不要因为收到一条回调就直接把账户余额改成一个新数字。
事件层保存“外部发生了什么”和“我们收到了什么证据”。账本层把已经满足当前阶段入账规则的事件转换为凭证和分录。余额层提供快速查询,但应从已过账分录或可核验的快照计算,不承担事件解释。
这样做的好处是,重复通知可以被识别,迟到的成功可以回到原业务,未知结果可以停留在待核对,而不是被迫选择成功或失败。
校验、资格和资金占用
先验证来源与对应关系:回调签名或其他可信来源证明是否有效,通道账户是否映射到正确租户和主体,业务引用、金额、币种与原请求是否匹配。再检查账户状态、金额精度、订单方向和允许的状态迁移。跨境或多币种业务还要检查报价、手续费、限额和账户资格。
发起需要预留资金的授权时,把可用额度检查和占用写入作为同一受控操作,覆盖共享资金池的并发请求。请款或成功回调不能再占一次,而应按实际金额消费已有占用;部分请款、超额请款和剩余释放分别按规则处理。占用成功只说明资金暂时不能被其他操作使用,不等于收入确认或外部结算完成。
如果外部请求已经发出,本地失败或超时不能直接释放占用。只有确认外部未执行、失败或已撤销,并满足释放规则,才做关联释放;结果未知时保留受控占用并继续查询,不能把资金提前交给下一笔交易。
校验失败时记录具体的 reasonCode、requestId 和关联引用,区分账户关闭、币种不支持、额度不足和重复阶段。保留脱敏的决策与资金变化证据,便于之后复盘。
生成并提交一张凭证
先判断“这个业务阶段有什么已经确认的权利义务”,再生成凭证。已确认的请款可能先借记通道应收、贷记商户应付款,之后银行到账再以另一张凭证结清应收;不必等全部外部结算完成才记任何账。但一条“已受理”通知不能单独证明银行存款已经增加。
账本服务按事件类型和版本化的科目映射生成凭证,再强制检查:至少两条分录且借贷都存在,同凭证、账簿、主体和币种内借贷相等,账户与期间允许过账,业务阶段幂等键和凭证号满足唯一约束。失败就不提交,进入有明确原因的异常队列。
这张图可以按七步阅读:
- 校验可信来源、主体、字段和引用,不合格的事件记录原因并停止。
- 按稳定业务引用和阶段幂等:已提交的相同请求返回原结果,载荷冲突拒绝;待定事件补充证据后继续判断。
- 检查本阶段的入账证据;不足则停在未知,经查询、可信回调或核对取得新证据后回到本步骤。
- 证据充分后按版本化映射生成凭证,不把下一阶段的资金结果提前写入。
- 检查借贷、币种、主体、账户、期间和唯一约束;失败整张不生效。
- 在本地事务中提交凭证、全部分录、幂等结果及资金判断所需的余额或占用变化,返回可查询的 postingId。
- 将账内记录与外部报告、银行流水对账;差异复核后产生关联调整,保留原记录。
“原子”是结果要求:并发请求不能看到互相矛盾的中间状态,凭证不能只写一半。跨服务通知可以用事务发件箱传递并由消费方幂等处理;远程通道的最终结果继续通过状态机、查询和对账收敛。
异步结果要保留未知
外部通道可能先受理、之后回调成功,也可能请求超时但实际已经扣款。本地响应、通道响应、账本提交和外部结算要分别记录,不能互相替代。
结果不确定时保留原事件、证据和受控占用,使用支持的查询、可信回调、结算报告和银行流水继续收敛,并明确负责人、重试节奏和升级时限。乱序的旧状态不能覆盖已确认的新状态;迟到的证据应推进正确阶段,而非重新记一次原阶段。
待核对状态不等于可以任意使用待核对科目。银行到账已有证据但归属不明时,可以按批准规则借记银行、贷记暂收;连资金是否发生都不确定时,先保存未决事件,不能用平衡凭证制造已经到账的事实。之前已确认的应收等分录仍保留。
对账要把内部事件、账本分录、外部引用、手续费和实际到账匹配起来。差异记录类型、金额、币种、时间范围和处理状态,不用一条没有来源的手工加减抹平。
退款、冲正和修复
退款、授权撤销、过期释放和结算失败分别有自己的业务阶段,并引用原始交易。不要删除原凭证,也不要把旧分录改成“看起来正确”的数字。
退款根据当时的权利义务和资金位置记账。已结算给商户的款项,退款可能需要确认商户应收或其他已约定的追偿关系,再记录实际退款;不能机械地把最初收款凭证整张反向。部分退款累计检查上限,手续费是否退回单独表达。科目映射错误则保留原凭证,按授权流程生成冲正或调整,并记录原因、审批人和关联关系。
同一业务引用加阶段及必要的子事件引用应只产生一次对应的资金变化。不同投递编号仍可能是同一业务;不同部分请款或退款也不能因金额相同就合并。规则升级不构成重记同一事件的理由。
前提和应该达到的效果
上线前至少需要准备:
- 账户和主体边界:平台、客户、商户、银行或清算方分别是谁。
- 事件字典与证据门槛:授权、占用、请款、清算、到账、退款、冲正和费用分别何时确认。
- 科目映射版本:每种阶段、币种和费用条件如何生成分录。
- 金额规则:精度、舍入、汇率来源、费用承担方和跨币种桥接。
- 一致性机制:稳定业务标识、幂等约束、并发占用、原子提交、权限和期间控制。
- 切换与运营机制:核对期初、盘点在途与未决、确定唯一写入方,以及对账资料、异常负责人和升级时限。
预期效果是每个状态都能解释:随机抽一笔交易,可以还原事件、决策、占用、凭证、外部结果和对账;重复投递不重复入账;超时停在未知;退款与冲正能回到原记录;余额可按账户和币种重算;报表把待核对金额和已结算金额分开。
验收可用重放同一事件、并发争用同一资金池、凭证写入中断、乱序回调和已结算退款等场景检查。它们是待实现账本的目标,本站只展示知识文档,没有运行资金账本或执行这些资金场景。前提不足时先做只读流水和影子对账,再逐步扩大自动过账范围。