交付出件箱

← 返回出件箱

批 B 收尾完成报告 · 2026-08-15

分支 feature/wechatpay-pay-core · 本次新增 7 个 commit(累计领先 test 26 个)
工作区干净 · 未发版(等长官现场令)


一、结论先说

批 B 剩余 6 项全部完成。过程中挖出 3 个原本就埋着的真 bug,其中 1 个是致命的——
门店根本付不了钱。

交接件写的「后端全通」不成立:那份判断来自「测试全绿」,而那些测试全是直接调
service 函数,没有一条真打过 HTTP、也没有一条用真实门店会话打过。


二、挖出的 3 个真 bug

🔴 Bug 2 最要命:门店付款链路全 403

实打结果(造真 JWT + ASGI 直打):

GET  /api/store/service/wxpay/price  (scope=store_review) -> 403 门店服务访问权限不足
POST /api/store/service/wxpay/prepay (scope=store_review) -> 403 门店服务访问权限不足

根因:支付页拿的是复核链接换来的会话(scope=store_review),而这两个端点挂的是
require_store_service(只认 scope=store_service)。且首开阶段拿不到 service 链接
——那要机构「已开通」才发得出——所以不是前端换个 token 就能解决。

为什么一直没暴露:
1. 前端取价失败被 catch 吞了("取价失败不阻断页面"),界面上只是价格空着
2. 后端只验过「无会话要拒绝」,没有一条用真实 store_review 会话打过

修法:新增 require_store_pay,两种门店会话各校各的前提,一道都不放松。
只换两个付款端点的守卫,其余 5 处 require_store_service 未动。

Bug 1:/records 被路由遮蔽,接口实际调不通

GET /api/admin/payment-vouchers/records 实打返 422:
{"type":"uuid_parsing","loc":["path","voucher_id"],"input":"records"}

端点注册在 /{voucher_id} 之后,FastAPI 按注册顺序匹配,"records" 先落进
{voucher_id} 当 uuid 解析。原有 14 条用例全是直调 service 函数,所以全绿却掩盖了接口不通。

已修 + 补真打钉子;并遍历 app.routes 用 starlette Match 全仓扫描同类遮蔽 = 0 处。

Bug 3:参数名 status 遮蔽 fastapi 的 status 模块(这个是我引入的)

端点加了个叫 status 的 query 参数后,函数体里 status.HTTP_400_BAD_REQUEST 当场炸 500
(AttributeError: 'NoneType' object has no attribute 'HTTP_400_BAD_REQUEST')。
没有用例走过非法 org_id,所以全绿也发现不了。已改 alias 写法 + 补钉子 + AST 扫全 app = 0 处。


三、6 项交付内容

# 项 要点
1 路由遮蔽修复 端点上移 + 真打 HTTP 钉子 + 全仓扫描
2 records 补字段 + 筛选下推 渠道/执照/时间点字段;6 项筛选整体搬后端
3 PC 支付记录页 9 列不增不减、6 筛选只改名、微信详情弹窗、退款标记
4 手机端支付记录页 新端点复用同 service、两类混排、来源标识、退款入口
5 老档案临时授权补录 付款前就地补授权 → 写回档案 → 继续下单
6 删 openid 探针 self-check 按长官令留到联调后

方案硬约束的物理判据


四、判据(都是硬的,不是"看起来对")

判据 做法 结果
日期口径 把 RECORD_TZ 临时换成 UTC 跑用例 "应搜到 2 条,实得 0" → 换回即绿
死路提示 临时改回 setPayError 那句 钉子当场变红 → 还原即绿
前后端契约 AST 解析后端两处 append 的 key vs 前端类型 两类 key 完全一致、双向零差集
不是我打坏的 在 origin/test 建 worktree 跑同一套全量 见下

全量套件与基线比对

本分支:18 failed / 640 passed
基线  :17 failed / 552 passed   (passed 差额 = 批 B 已有 commit 的测试 + 本次新增 22 条)

差集里那 3 条,同一份代码连跑两次全量,清单本身就在漂移:

只在第 2 次红:test_range_spans_months / test_inreview_resubmit_leaves_contract_untouched
              / test_missing_license_company_name_is_data_error_not_core_error
只在第 3 次红:test_missing_version_param_still_works

单独跑全绿;与我的新测试并跑 24 passed 不复现 → 既有并跑串扰,非本次引入。
(失败总数 17~18,正是交接件记录的基线抖动区间。)


五、还没做的

  1. ⬜ 发 test(等长官现场令)
  2. ⬜ 联调:长官手机扫码 → 授权 → 填资料 → 提交 → 付 0.01 元 ⚠️ 真扣钱
  3. ⬜ 联调后删 GET /api/wxpay/self-check
  4. ⬜ 上生产前必须先切结算生产流水线源(settle-prod 仍指旧仓,详见 batch-b-production-checklist.md)

六、本机验不了的部分(如实说)


七、自伤记账

  1. 同一个坑踩两次:写前端源码契约断言时用裸词做判据,两次都被自己写的解释性注释
    打中(第一次 filteredItems,第二次「请从签约链接重新进入」)。已都改成钉"代码形式"
    而非"提及"。
  2. 写了一行恒真断言(assert '...' or True)——正是交接件 0.2 记的那个错,当场删掉。
  3. 自己引入了 Bug 3(参数遮蔽模块名),靠补测试才发现。