Skip to content

产品说「钱自动分给商家」,听起来像加一个接口

产品说「钱自动分给商家」。听起来像加一个接口。

我数了一个真做完的:49 个 Java 类,7608 行,一个独立的 Maven 模块。

用户那头更短。付完款,小程序跳出「支付成功」,商家后台标签变成「分账中」。
两边都以为钱已经到了。

到的是冻结,不是可提现。平台端还要完结。用户再点退款,小程序进度条照走,
回退接口失败——商家已经提现,账上没钱可抽回来。

后端 8 张表。顺利路径只要两张:支付单、分账单。
剩下六张是进件、子支付、提现、回退、退款、补差。
后三张是反向的。 分账真正的体量不在「分」,在「分错了怎么办」。

前端不是一个按钮。平台端 9 个文件,商户端 15 个,进件向导自己就 7 步
开关不在页面上:后端配置关掉,页面只剩一条「未启用」横幅,
比例、重试次数、自动分账,全是只读,改了也不生效。

一单在三端上长什么样

用户付的是微信。回调先改订单,再丢进异步队列去分账。
小程序只认订单已支付,它看不到分账单。

商家打开的是另一套后台。进件走完 7 步,状态显示「分账中」。
这句话的意思是「你被强制纳入了」,不是「这单钱已经进你的卡」。
支付宝、余额、线下那几笔,配置里写明了不走这条分账
联调如果只拿微信跑通,商家会拿着支付宝的单来问:标签也是分账中,钱呢。

平台端有失败重试、成功完结、异常回退。
测试最容易绿的是:微信支付成功 → 分账单成功。
用户退款、商家已提现、回退失败,这条我在测试目录里没找到对应的用例。

产品那句话还是同一句:把用户付的钱按比例分给商家和平台。
你按「一个接口」排期,交付的是 49 个类 + 24 个前端文件

三种最常见的排错:

为了主体不一致去上服务商。 商户号和小程序对不上,有人说「上服务商就没这个问题」。
技术上成立。你省了几天关联,换来一整套资金架构。

没给失败留位置。 余额不够、商家状态异常、超过分账期限,每一种都要有对策。
这套代码里专门有个重试任务在跑。页面上还有「一键重试失败分账」。
按钮在,任务也在,两边对的是同一张失败单。

没想过回退。 用户退款了,已经分出去的钱怎么办?有一张独立的分账回退表。
这不是可选功能。前端退款进度和后端回退结果,不是同一个字段。

先分清楚三件事

这三个词常被揉在一起讲,它们不是一层套一层:

一、普通商户直连。 钱进你的商户号。分给商家是你自己的事,支付平台不管——可以每月手工转。

二、服务商模式(特约商户)。 你是服务商,商家是子商户。钱可以进子商户,也可以进你这儿再分。
主体不一致在这一层被解掉,因为每个子商户有自己的主体。

三、分账。 一笔钱按规则拆给多个接收方。它不依赖第二层——
普通商户在商户平台产品中心自行开通就能用,不需要先当服务商。

两条并列的路,不是两级台阶。

  • 直连商户 + 分账:一个商户号收钱,再拆给几个接收方
  • 服务商 + 子商户:每个商家各自持资质,各自收自己那笔

服务商解决的是多主体收款,不是分账的前置条件。
两件事被并在一起讲了太久,有人为了用分账去申请服务商——不需要。

什么时候该上

判断就一条:钱是不是必须由平台先收、再分给多个主体?

该上: 多商家入驻且各是独立主体、抽佣必须在支付环节完成、资金不能在平台账户长期沉淀。

不该上: 只有你自己一个商家;结算可以月结;只是为了解决主体不一致
现在三五个商家,「以后可能会多」。

最后一条单独说。「以后可能需要」是技术债最常见的入口。
三五个商家手工月结撑得住。真到三十个再上,那时候你对业务的理解也比现在深。

真要上,这四件事必须提前想

一、分账有时间窗口,不是你闲了再跑

支付平台对分账有时间限制,从支付成功起算,不是确认收货。
这套后台把冻结上限写成 180 天,取的是微信那条。
超时不是报个错。资金自动解冻、订单完结,这笔再也分不了。

所以得有个定时任务盯着待分账单,临期的优先。
前端「待分账」列表不是给运营随便点着玩的,是这个窗口的操作台。

二、失败要能重试,而且要幂等

分账会失败:子商户状态异常、金额校验不过、平台侧限流。

真实项目里有一个专门的分账重试任务,页面上有对应的重试按钮。

重试就意味着同一个分账单号不能分两次
跟支付回调的幂等是一回事,只是这次是你主动发起的。
测重试,不要只测按钮亮不亮,要测同一单号打两次,库里还是一条。

三、回退是必须的。商家账上可能已经没钱了

用户退款,钱已经分给商家了,必须发起分账回退,把钱要回来,才能退给用户。

麻烦在这句:商家账户里可能已经没钱了。 提现走了,被别的回退扣了。
回退失败,你的退款就卡住。小程序还停在「退款中」。

设计的时候这三问必须有答案:

  • 回退失败了,退款是继续还是挂起?
  • 挂起的话,谁来处理?走人工吗?
  • 是不是要留一笔不允许提现的保证金?

没有标准答案,但必须有答案。 没想清楚就上线,第一笔退款会卡在那儿。

四、校验放在保存配置时,别等钱已经收了

分账配置很容易错:接收方没进件、比例超过全局上限、接收方类型填错。

这些错在调用接口时才暴露,而那时候钱已经收了。
这套代码里有专门的配置校验器,就是为了在真正分账之前拦掉。
前端保存比例也会先拦一层,但真正的上限在后端配置里。
两层都要拦,只拦页面等于没拦。

校验放在配置保存时,不要放在分账执行时。
前者错了改配置。后者错了,处理的是已经收了钱的订单。

我的判断

绝大多数项目不需要分账。

现在纠结要不要上,答案大概率是不要。真正需要的场景很明确——多主体、必须实时、有合规要求。
不属于这三类,手工结算能撑很久。

如果确实要上,把它当成一个独立模块做,不要散在订单流程里。

理由就是开头那些数字:它最终会长成几十个 Java 文件,外加两套后台。
散在订单代码里,订单服务会慢慢变成一个又管交易又管结算的怪物。
用户那端还会继续用「支付成功」四个字,概括你这 7608 行。

独立模块 + 明确的接口边界,将来要换分账方式,或者砍掉,代价才可控。

八张表里有三张,写的时候会觉得是白写的。真用上的那天你会庆幸它们在。
24 个前端文件里,进件那 7 步看起来最像废话。没走完,后面每张表都是空的。

常见问题对照表

现象真正的原因解法
以为分账是个接口,排期严重不足低估了状态、重试、回退、校验,也没算两套后台按模块排期,把进件和回退算进去
微信单通了,支付宝单商家来问只有微信支付走分账联调把支付渠道当用例,不要只跑微信
前端改了比例,下单还是旧值总开关在后端配置,页面是只读预置先对配置,再改页面
分账失败,订单卡住没有重试机制专门的重试任务 + 分账接口幂等
重试之后分了两次分账接口不幂等用分账单号做幂等,跟支付回调同理
用户退款,钱要不回来商家已提现,账户余额不足保证金或提现延迟;回退失败要有人工兜底
小程序一直「退款中」前端绑的是退款单,回退失败没映射退款状态跟分账回退状态分开展示
分账比例配错,钱分多了校验放在执行时校验前置到配置保存时,前后端都拦
过了时间窗口分不了账没有定时任务盯临期单据定时扫待分账,临期优先
为了解决主体不一致上了服务商用架构决策解配置问题先试跨主体关联,见主体那篇
测试全绿,第一笔退款卡死用例停在「分账成功」补:已提现再退、重复分账单号、非微信渠道

这条链路上的其他几篇

签名-A

大粽子