支付分账
When to Invoke
平台收一笔、再分给门店/景区/达人;微信分账、延迟结算、抽佣。文旅多门店、电商多商家常见面试题。
When NOT
购物车拆子单 → split-order(履约拆单)。平台账本上的应付/账期打款 → finance-settlement(那不是渠道划款)。退款渠道 API → pay-refund-channel。GMV 报表 → finance-stats。
风险(面试考点)
用户付给 平台商户号,门店要钱。实时分账:退款时钱可能已在门店,平台垫退失败。默认 延迟分账(确认收货/核销完成后再分,或 T+N)。
微信官方约束(面试常背错):
- 需分账的订单,资金先 冻结;可实时或 支付后 30 天内 发起分账,逾期自动解冻。
- 一笔订单最多分 50 次,每次最多 50 个 接收方。
- 服务商模式默认最高分账比例约 30%(以商户平台授权为准),不是 100% 随便切。
- 查询
status=FINISHED只表示这次动账跑完;每个接收方看receivers.result(SUCCESS/CLOSED)。 unfreeze_unsplit=true或调 完结分账 后剩余解冻,不能再分。多次分账只在最后一次完结。- 分账回退:已分账后退款,先把钱从接收方拉回再退。仅 MERCHANT_ID 且接收方开通「同意回退」;分给个人零钱不能回退;时限约 180 天;同一分账单回退最多 50 次;
out_return_no稳定,处理中禁止换单号。 - 回退与退款 API 不耦合(微信原文),业务上仍应 先回退成功再退款,否则平台户余额不够垫。
分账失败、部分接收方失败、接收方未入驻,都会导致平台账上有钱门店没收到。要有分账单状态和对账。
分账金额之和 + 平台佣金 = 实付。单位分,四舍五入规则写死(最后一方吃差额)。
渠道已分账则平台结算单只做对账,禁止再打一笔(见 finance-settlement)。
方案选型(轻量优先)
| 模式 | 用在 | 不要用在 |
|---|---|---|
| 不分账,月结打款 | 门店少、能接受账期 | 渠道强制分账 |
| 延迟分账(核销/收货后) | 默认 | 秒级到账承诺没能力时 |
| 支付成功即时分账 | 明确要求且退款能回分 | 高退款、分给个人还要退 |
t_pay_split split_no, pay_trade_no, receiver_mch, amount_fen, status
uk(pay_trade_no, receiver_mch, split_no)
流程:支付 SUCCESS(资金冻结)→ 履约完成事件 → 调渠道分账(幂等 split_no)→ 查单直到各接收方终态 → 最后一笔完结/解冻剩余。退款:未分账直接退(或先完结解冻);已分账先回退再退款。
默认方案
核销完成(文旅)或确认收货(电商)发消息 split-request。不要在支付回调里同步分账。
if (splitMapper.insertIgnore(row) == 0) return; // 已发起
channel.profitShare(splitNo, receivers); // 超时同号重试
// 补偿扫描 PROCESSING;CLOSED 进差错
失败进死信。个人接收方一旦分出,退款只能平台垫,面试要主动说这个限制。
反例
错误:支付成功立刻分完,用户秒退,平台商户号余额不够垫。 正确:延迟到不可逆节点(核销/收货)或冻结期。
错误:拆单金额加总与实付差 1 分没人认。 正确:尾差给平台或最后门店,规则固定。
错误:分账与拆单、结算账单当同一张表一个状态。 正确:子单履约 ≠ 渠道分账成功 ≠ 商家账期应付。
错误:FINISHED 当全员到账;或完结后再补分一笔。 正确:看每个 receiver;完结后只能对账。
错误:给个人分账后调回退 API。 正确:个人不能回退,高退款场景不要分给个人。
验证
- 一父单两门店,核销后两笔分账各一次,金额+佣金=实付。
- 未核销退款:无分账或全额从平台退。
- 已分账再退:有回分(商户接收方)或拦截退款。
- 完结后再次分账被拒。
评审清单
- 默认延迟分账;不在 notify 里同步分
- 分账单幂等;查单看各接收方 result
- 尾差规则;完结/解冻剩余
- 退款与回退顺序写清;个人接收方不可回
- 未与平台结算单双打款