Skip to content

异步通知与对账

本页覆盖支付结果可靠送达链路:渠道回调 → 订单状态机 → 事件 Outbox → 业务订阅者 / Open Platform Webhook 投递,以及查单补偿、定时任务与对账中心。

渠道异步通知

公开回调端点

text
POST /api/public/payment/notify/{channel}    # channel: wechat | alipay | unionpay

端点为公开路由,渠道服务器不携带管理端 token。安全边界依赖渠道验签、金额校验与状态条件更新。渠道配置的 notifyUrl 为空时,按 PAYMENT_NOTIFY_BASE_URLPUBLIC_BASE_URL 拼接该路径。

处理流程

text
渠道回调
  └─▶ 遍历同渠道启用配置逐个验签
        ├─ 全部失败:写 payment_notify_logs(signatureValid=false),返回 401
        └─ 任一通过:解析订单/退款信息,校验金额,条件更新状态
              ├─ 成功:写日志,记录 Outbox 事件,返回成功 ACK
              └─ 抛错:写日志,返回渠道失败 ACK,等待渠道重发

要点:

  • 微信:平台证书 RSA 验签 + AES-256-GCM 回调解密,平台证书按 Wechatpay-Serial 自动下载并缓存 12h。
  • 支付宝:RSA2/RSA 验签。
  • 云闪付:银联全渠道 5.1.0 signMethod=01(SHA256+RSA)验签。
  • 回调金额必须与本地订单金额一致。
  • applyNotify 使用条件更新推进订单/退款状态,重复通知无副作用。

回调日志

每次渠道回调都会写入 payment_notify_logs,后台「回调日志」页可查:

字段说明
channel / scene渠道、场景(payment/refund)
orderNo解析出的关联订单号
rawBody / headers原始报文与请求头摘要
signatureValid验签结果
result / message处理结果与说明
ip来源 IP

事件 Outbox

订单/退款进入终态时,状态更新与 payment_events 插入在同一事务内完成;事务提交后立即尝试投递,dispatchPaymentEvents cron 每分钟补投 pending/超时事件。

事件说明
payment.succeeded订单支付成功
payment.closed订单关闭
payment.failed渠道下单失败
refund.succeeded退款到账
refund.failed退款失败或审批驳回

投递语义:

  • processEvent 先 claim 事件,再调用 paymentEventBus.dispatch
  • handler 全部成功后置 done
  • handler 抛错时 attempts + 1,未达 5 次保持 pending,达到上限置 failed
  • 「支付事件」页可调用 POST /api/payment/ops/events/{id}/redispatch 将死信重置并重投。

业务订阅者与 Open Platform Webhook 接收方都必须按 eventIdorderNorefundNo 或业务键幂等。

管理入口分为两个受控视图:/payment/webhooks 仅允许支付与退款事件,使用支付中心权限;/open-platform/webhooks 管理完整开放事件目录。两者复用同一订阅和投递表,不维护第二套 Webhook 状态机。

查单补偿

路径说明
paymentReconciliation cron每 10 分钟扫描 paying 且创建超过 2 分钟的订单,调用渠道查单同步终态
POST /api/payment/orders/{id}/query订单详情手动查单
POST /api/payment/refunds/{id}/query退款详情手动查单
syncPaymentTransfers cron每 5 分钟同步处理中转账单
retryFailedSharing cron重试渠道未受理且未达上限的分账单,并同步处理中分账单

查单确认支付成功会走与回调相同的状态更新与 Outbox 事件链路。

支付域定时任务

种子内置支付相关任务(见 packages/shared/src/seed/platform.ts):

handler频率职责
dispatchPaymentEvents每分钟补投支付/退款 Outbox 事件
closeExpiredPaymentOrders每 5 分钟查单确认后关闭过期未支付订单
paymentReconciliation每 10 分钟支付中订单查单补偿
retryFailedSharing每 10 分钟分账失败重试与处理中分账同步
generateDailySettlements每日 01:10T+1 生成昨日渠道 × 租户结算批次
syncPaymentTransfers每 5 分钟同步处理中转账单
autoPaymentRecon每日 02:00拉取昨日渠道账单自动对账
executeDueDeductions每分钟执行到期签约代扣
syncPaymentDisputes每 5 分钟拉取/生成交易投诉工单

对账中心

入口:/payment/recon,接口挂载在 /api/payment/recon

创建对账批次

方式接口说明
手动上传POST /api/payment/recon/batches上传 CSV,与本地成功/退款订单逐笔比对
自动拉取POST /api/payment/recon/auto调用适配器 downloadBill;微信支持交易账单,沙箱使用本地订单生成模拟账单
示例账单GET /api/payment/recon/sample-bill生成示例 CSV 便于联调

支付宝与云闪付适配器未实现 downloadBill,对账以手动上传或沙箱模拟账单为准。 批次来源由服务端固定为 manual_uploadsandbox_generatedprovider_download,客户端不能指定或覆盖。

比对结果与差异处理

逐笔结果枚举:matchedlocal_onlychannel_onlyamount_diffstatus_diff

差异处理状态:

  • adjusted:仅渠道适配器下载的账单可选,根据差异类型推导调账方向与金额并原子写入 recon.adjust 双分录凭证;
  • suspended:终态挂账归档,不自动入账;
  • ignored:确认无需处理。

人工上传和沙箱模拟账单属于不可信资金证据,只能进入 suspendedignored,不能通过差异处理接口改变 merchant_available

处理接口为 PATCH /api/payment/recon/items/{id}/handle,记录处理人、处理时间与备注。

Built with VitePress for local documentation preview.