Files
junhong_cmp_fiber/openspec/changes/add-refund-methods-and-original-route-refunds/design.md
break 370fd3e67f
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 10m49s
update
2026-09-03 09:28:28 +08:00

4.3 KiB

Context

退款服务已有申请、企业微信审批和钱包审计路径,但现有状态/人工入口不足以表达渠道退款未知结果。支付商户池 Change 完成后,新支付单可读取冻结实际商户;历史单继续走旧支付配置。

Decisions

  • 退款单新增方式、冻结实收金额、套餐使用/材料快照、渠道退款状态/流水/安全失败原因和审批实例历史;金额均为分。
  • 创建、审批消费和渠道执行使用同一退款单锁及条件状态更新。一笔订单的活动退款唯一约束防止并发重复;渠道请求使用稳定请求标识,结果未知进入恢复任务而非重发。
  • 企业微信通过事务内完成套餐失效与钱包退款准备;原路渠道调用使用可靠事件,成功回写退款终态。客户收款信息退款以企微通过终态完成。
  • 移除/拒绝本地人工终审语义,保留历史兼容读取;未成功重提始终冻结新实例快照。

行为契约

退款申请与重提

  • POST /refunds:调用者必须在订单数据范围内。服务锁定订单和既有活动退款,读取订单或原成功支付记录的权威实收金额;缺失、非正或已存在审批中/原路处理中/原路失败申请时拒绝。请求包含退款原因、退款方式、退款金额、客户收款信息及附件(仅客户收款信息方式);金额为正分且不超过冻结实收金额。
  • 服务按实际支付方式生成可选方式:微信/支付宝线上支付为原路或客户收款信息,资产钱包/代理主钱包仅原钱包,后台线下/员工代收仅客户收款信息;不匹配的方式返回“该订单不支持此退款方式”。客户收款信息与至少一个凭证附件必须同时存在,且不读取员工收款方式字典。
  • PUT /refunds/:id 或既有重提入口只允许驳回、关闭或渠道明确失败的未成功申请;重新锁定订单和申请,保存新的原因、方式、金额、收款信息、附件和套餐使用快照,创建新的企业微信审批实例。提交失败或审批未知不是可重提状态;已成功、审批中、原路处理中返回状态冲突。

企业微信终审与权益处理

  • 回调和既有审批恢复任务以审批实例 ID 进入同一幂等用例;移除新业务的本地人工通过、拒绝和退回终审路径,历史接口仅保留兼容读取或明确拒绝。
  • 首次最终通过时锁定退款和订单,校验批准金额不超过冻结实收金额;在事务中标记审批通过、使关联套餐失效、接续下一套餐、评估停机并建立退款执行事实。重复/乱序回调不得再次失效套餐或启动第二次渠道退款。
  • 客户收款信息方式在企业微信通过时标记退款成功;原钱包方式沿用原钱包退款事务;原路方式只写待执行可靠事件,不能在审批事务中假定渠道已成功。

原路执行与恢复

  • 原路执行消费者在调用前锁定退款,验证原支付单、实际收款商户、渠道流水、可退金额和当前商户退款凭证。新支付按冻结 merchant_id 加载商户当前凭证,历史支付按 payment_config_id;商户停用不阻断历史校验。
  • 以退款 ID/稳定渠道请求号至多提交一次可确认请求。渠道明确成功时保存渠道退款流水并转退款成功;超时、未知、凭证失效、余额不足、拒绝均写安全原因并保持处理中或失败恢复状态,不得标记成功或盲目再次调用。
  • 原路失败后若改为客户收款信息退款,必须修改申请材料并走新企业微信审批;审批通过后撤销只记录审批异常,不恢复套餐权益、不取消已提交渠道退款且不自动重提。

读取与审计

  • 退款列表、详情和导出返回冻结实收金额、方式、申请/渠道状态、失败安全摘要、审批实例和渠道流水,并按既有订单数据范围过滤。审计记录申请、重提、审批终态、权益处理、渠道调用和恢复,但不得记录凭证内容、完整收款文本或商户密钥。

Migration Plan

新增成对迁移和活动退款约束,先部署兼容读写与恢复消费者,再关闭人工审批入口;隔离库验证方式矩阵、重复回调、渠道未知、失败重提、权益时点和 up/down/up。