logo
0
0
WeChat Login

fix(order+payment): B13/B14/B15 业务层中优先级修复#3

Merged
created 2 weeks ago
feature/fb-06-api-contract-validation
feature/order-payment-fixes
Edit
OverviewCommits
5
Files changed
9
Attachments

背景

关闭 foundation-setup 审视剩下的 3 个中优先级业务 Bug,让订单/支付流程真正闭环。

3 个 Bug 与修复

B13 — PaymentService 接口丢失 paymentNo

根因PaymentService.createPayment 签名只返回 String paymentUrl,调用方 OrderServiceImpl 拿不到真实 paymentNo,只能用 "P" + orderNo.substring(1) 脆弱反推。这个反推假设 orderNo 以 O 开头,且支付号编号策略永远跟订单一致 —— 根本是两套编号。

修复

  • 新增 PaymentCreateResultVO { paymentNo, paymentUrl }@Value @Builder 不可变)
  • 接口返回结构化 VO
  • 熔断降级返回字段全 null 的 VO,语义比 String null 清晰

B14 — cancelOrder 未回退库存

根因:取消订单只改状态,库存永久扣减 —— 严重业务 Bug。此前有个 TODO: 回退库存(需要从 order_items 加载) 的注释被忽略。更严重的是:createOrder 本身都没写 order_items,等于这张表一直是空的。

前置:新增 OrderItem Entity + OrderItemMapper(DB 表早已存在,但代码层缺建模)。

修复

  • createOrder 补写入 order_items(product_snapshot 存 JSON 字符串,cast 为 JSONB)
  • cancelOrder 读 order_items 逐行调 InventoryService.restore
  • 单条 restore 失败不回滚整个取消事务(订单已 CANCELED,强制回滚会造成状态不一致;改为记告警指标由补偿任务重试)

B15 — handleCallback 幂等定位顺序

根因:原流程先按 tradeNo 判重、再按 paymentNo 定位。面对攻击者构造"同一 tradeNo 对应不同 paymentNo"时可能错位。

修复

  • 先按本地可信的 paymentNo 定位 → 按状态机分支处理:
    • 不存在 → 404
    • 已 PAID + tradeNo 一致 → 幂等成功
    • 已 PAID + tradeNo 不一致 → 风控拒绝(新增 payment.callback.trade_no_mismatch 指标)
    • PENDING → 金额核对 + CAS 更新 + 发事件
    • 其他 → 拒绝(FAILED 状态不能再改)

5 个 commit

#Commit说明
1feat(order)引入 OrderItem Entity / Mapper(B14 前置)
2fix(payment)PaymentService 接口结构化返回 + handleCallback 状态机化(B13 + B15)
3fix(order)OrderServiceImpl 写明细 + 取消回退库存(B13 + B14)
4test(order)适配新签名 + 新增 2 个 B14 库存回退专项测试
5docs(checkpoint)记录第 10 轮 + .project.json cnb url 对齐

验证

  • mvn clean compile + test-compile BUILD SUCCESS
  • ✅ Docker JDK 17 真实跑单元测试:15/15 PASS(原 13 + 新增 2 个 B14 专项)
  • .codebuddy/ lint 0 错误
  • ✅ CHECKPOINT 未完成清单全清零(B13/B14/B15/FB-06 全 ✅)

合并目标

base 选 feature/fb-06-api-contract-validation 而非 main:依赖 FB-06 PR #2 的工程产物(typed apiClient、生成目录等)作为前置条件。

意外观察

这次修复再次印证 FB-09(scaffold Controller 不带认证上下文)和 FB-03(scaffold DTO 与业务入参错位)的杀伤力:scaffold 出来的 Order 没写 order_items,前端 payment 全是死代码,都是因为 scaffold 只按 Entity 扫一遍就产出 CRUD,缺乏业务语义约束。这些已在上一轮的 scaffold SKILL 局限文档中提醒过。

下一轮可能方向

  • 剩余唯一未完成项:ac3 功能测试的 CI 最终验证(依赖 Linux runner)
  • 如果要进一步加固:给 OrderService + PaymentService 补完整的 unit test(目前主要是 Order 有,Payment 还没有系统化测试)
is using the merge method to merge into5cb382d1
合并来自 feature/order-payment-fixes 的合并请求 #3
added 2 commits
Merge PR #4: 合入 FB-06 + B13/B14/B15 到 main
feat(ci): 接入 CNB 流水线 + 7 个 POSIX shell 自举检查脚本
added 4 commits
docs(checkpoint): 闭环 T-01 + 轮次 6 档案 + 棘轮同步上调
docs(rules): 新增 backend-go.md——Go + Echo + sqlx + goose 参考实现
docs(rules): LESSONS §四 修订——覆盖首次演练错误描述 + A/B 分层 + 反模式 A7
docs(meta): CHECKPOINT §四 轮次 14-e 追加——方向 F1 四 PR 经验回写档案
docs(share): workshop-share.md 新增 M9·CI 平台坑点实证清单(第 9 种治理模式)

Successfully merged and closed

branch can be safely deleted
Reviewer
None yet
Assignee
None yet
Label
None yet
Participant