bindbox-game/.trae/documents/支付域持久化与退款幂等改造实施方案.md
邹方成 6ee627139c
Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 40s
feat: 新增支付测试小程序与微信支付集成
feat(pay): 添加支付API基础结构
feat(miniapp): 创建支付测试小程序页面与配置
feat(wechatpay): 配置微信支付参数与证书
fix(guild): 修复成员列表查询条件
docs: 更新代码规范文档与需求文档
style: 统一前后端枚举显示与注释格式
refactor(admin): 重构用户奖励发放接口参数处理
test(title): 添加称号效果参数验证测试
2025-11-17 00:42:08 +08:00

4.0 KiB
Raw Blame History

目标

  • 按真实微信支付流程完善一个完整的支付体系:持久化预下单/交易/退款/通知/对账,统一金额/积分口径,优化退款恢复与幂等,前后端一致展示。

数据库与模型

  • 新增表(均使用“分”为金额单位):
    • payment_preorders(id, order_id, order_no[UNIQUE], channel, prepay_id, out_trade_no[UNIQUE], amount_total, payer_openid, status(created/expired/paid), notify_url, created_at, expired_at)
    • payment_transactions(id, order_id, order_no[UNIQUE], channel, transaction_id[UNIQUE], amount_total, success_time, raw(JSON), created_at)
    • payment_refunds(id, order_id, order_no, refund_no[UNIQUE], channel, status(submitted/success/abnormal/closed), amount_refund, reason, success_time, raw(JSON), created_at)
    • payment_notify_events(id, notify_id[UNIQUE], resource_type, event_type, summary, raw(JSON), processed(bool), created_at)
    • payment_bills(id, bill_date, type(tradebill/refundbill), file_url, digest, imported(bool), created_at)
    • payment_bill_diff(id, bill_date, diff_type(missing/amount_mismatch/extra), local_tx_id, wechat_tx_id, detail, created_at)
  • 订单唯一索引orders.order_no[UNIQUE]
  • 迁移:生成/应用 GORM 迁移脚本;保持向后兼容(不破坏现有数据)。

Repository/DAO

  • 生成 gorm/gen DAO 与 model 文件;在 internal/repository/mysql/dao, model 下新增 payment_* 的 gen 文件。

Service 逻辑

  • 预下单:
    • 校验订单 status=1、金额与归属调用 jsapi.Prepay落库 payment_preordersout_trade_no=order_no, prepay_id回填 orders.pay_preorder_id返回调起参数RSA-SHA256 四行签名)。
  • 支付通知:
    • 验签解密 payments.Transaction幂等notify_id 去重)入库 payment_notify_events写入 payment_transactionstransaction_id/raw/success_timeorders 条件推进 status:1→2写 paid_at。
  • 退款:
    • 管理端主动退款:生成 refund_no 并调用 refunddomestic.Create入库 payment_refundsrefund_no/amount/status/raw
    • 积分恢复(统一口径):
      • 部分退款按比例恢复:恢复积分 = (订单积分抵扣分 × 退款分 ÷ 实付分) ÷ 100累计不超过订单抵扣积分全额退款一次性恢复剩余积分幂等校验累计已恢复积分 vs 目标)。
    • 订单状态:全额退款置 4已退款部分退款维持 2已支付并维护累计已退款金额聚合 payment_refunds
  • 对账:
    • 每日下载交易/退款账单(依 SDK入库 payment_bills比对 payment_transactions/payment_refunds 生成 payment_bill_diff提供导出与差异修复入口。

Admin 接口

  • 订单详情:增加展示字段 transaction_id、累计已退款、每笔退款refund_no/amount/status/时间/原因);可退余额=实付-累计退款。
  • 退款列表与详情GET /api/admin/pay/refunds, GET /api/admin/pay/refunds/:refund_no
  • 对账POST /api/admin/pay/bills/import上传账单并入库GET /api/admin/pay/bills/diffs差异列表

前端

  • 金额统一格式化为“元”展示(两位小数),内部接口仍用“分”;
  • 订单详情页增加 transaction_id/refund_no/channel/支付方式;展示累计已退款与可退余额(元);
  • 退款记录表展示 refund_no/金额(元)/原因/时间;
  • 保持中文枚举一致(状态/来源/发货/抽奖)。

幂等与安全

  • 幂等键order_no预下单/推进、notify_id回调、refund_no退款
  • 唯一索引:预下单/交易/退款/通知表关键字段;
  • 条件更新WHERE status=... 控制并发;
  • 日志与告警:验签失败、金额不一致、退款异常、对账差异。

测试与验收

  • 单元:分↔积分换算、部分/全额退款恢复、幂等重复;
  • 集成:真实预下单→回调→主动退款→详情一致;
  • 对账:拉取账单并生成差异;
  • 验收:管理端全链路可用、金额与积分口径一致、数据持久化完整。