余额与退款可靠性修复
余额
- 加余额和扣余额请求必须携带 Idempotency-Key(16–64位字母数字或短横线)。
- 表 admin_balance_request 与余额、流水使用同一数据库事务;成功重放直接返回成功,不再次修改余额;相同key换用户/金额/备注拒绝。
- 前端在sessionStorage保留未确认操作key,按后台用户ID、接口、目标用户、金额和备注区分。只有收到业务成功才删除;刷新重试保留。不要关闭标签或清除缓存后盲目重试。
- 不同key仍代表不同操作;不阻止有权限人员主动创建多笔加款,跨设备/关闭标签需先核账。
- 上线先执行 docs/sql/20261021-balance-idempotency.sql,更新前后端。旧客户端无key会被拒绝。不能清理已完成key后重放旧请求。
退款
- 标准订单centerRefund的微信/支付宝/Stripe调用,未显式指定请求号时,使用订单ID和数据库已记录现金退款累计额派生稳定请求号,替代按当前时间生成新号。
- 数据库还没确认结果时重试维持同一请求号;确认退款累计额增加后才生成下一笔请求号。显式批量退款编号不改。
- 同一未确认退款位置变更金额,不应通过换请求号再次出款,应核查渠道结果;渠道对幂等号的返回和参数冲突仍需沙箱验证。
- PayPal、套餐/会员/押金等其他独立链路不在本次稳定编号覆盖范围。历史按时间编号发出的未确认退款,上线前必须对账,不能自动换新号重试。
- 补齐普通订单/套餐订单不存在时的业务错误,避免空指针。
验证范围
余额mock测试、H2 MySQL模式事务重放/回滚测试、退款编号纯函数测试与权限测试均提供源代码;真实MySQL并发、渠道沙箱、生产支付均未执行。H2不是MySQL最终验收替代。
退款意图持久化
标准退款自动生成稳定请求号时,调用渠道前用独立事务将订单ID、金额写入 payment_refund_intent。相同退款号变更金额拒绝,不依赖渠道是否检测参数冲突。先执行 docs/sql/20261021-refund-intent.sql 再部署;首次请求金额填写错误但尚未出款,也不能自行删除记录换金额,开发需先核对渠道状态。
实际回归结果(2026-10-21)
使用IDEA同一Maven/settings/本地仓库:全模块构建成功;指定安全回归service 8项、web 11项全部通过(含2项H2事务测试)。前端10项安全/请求标识测试通过,前端构建通过。不是全量测试,也不包含真实MySQL并发或真实渠道退款。