08 — 扫尾:查询对等物、配置与开发环境

What to build: 在收不到第三方回调的环境里,把剩下几处「只有回调能推进」补齐查询路径;把两处会静默失效的配置收口;把后台已有但没接线的两个按钮接上;给开发环境一个走真实对账逻辑的加速入口。

本票的判定是 ADR 0004:**凡状态推进都必须存在一条不依赖回调的路径,回调只用于缩短收敛时间**。用户没有公网服务器,所以这条不只是开发便利——回调会丢(订单 520/521 的悬账根因就是回调没到达)。

要点

补查询对等物(两处)

  • 进件后新增的结算卡:状态现在只有绑定回调能推进;初次进件那张卡有查询对等物,但只认「进件时那一张」。把**已有的人工刷新**路径推广到该门店所有待处理卡。**不新增定时任务。**
  • 资金回退状态与「同一天的确认中」:补偿任务只扫「待确认/确认中」,回退中的记录**永远没人再看**,撤销核销可能被永久卡住;同一天的「确认中」也要等到次日才重认领。放宽**已有的**补偿任务,并接上**已实现却从未被调用**的确认查询接口。**不新增任务。**

配置收口

  • 绑卡回调地址缺失:该配置键在配置文件里根本不存在,绑卡回调从未在通道侧注册——这是生产 bug,不只是开发环境问题。补齐它;并让**回调地址为空时显式记录「回调未启用」**,不要静默指向一个不可达地址。
  • 定时对账开关:间隔靠注解默认值生效、没写进配置;而注解上开关的默认值是关,靠配置里那一行打开——删掉那一行,支付与退款唯一的后台兜底会**静默消失**。把间隔写进配置,并让默认值与配置一致。
  • 交易确认补偿的开关:代码注释宣称有开关,但那个配置键**从未被读取**,任务永远在跑。要么实现它,要么改正注释——建议实现。

后台按钮

  • 「刷新退款」与「查询通道状态」两个接口已存在但前端没接,线上排查只能手写 SQL 或干等定时任务。接到管理端页面。

开发环境

  • 缩短对账间隔 + 提供**人工触发**的「立即对账 / 立即刷新」入口,走**真实**对账逻辑。人工触发不是定时轮询,不违反 ADR-0001。

明确不做

  • 给**进件进度**加定时查询:那是 ADR 0001 由用户明确选择的取舍,后果已写在文档里(没有回调且无人刷新时进度保持最后已知状态)。开发环境用人工触发解决。
  • 任何「跳过真实通道直接置为已支付」的捷径(ADR 0004,与审计 §7 同款)。

Blocked by: 04

Status: 已验收 —— 2026-09-17 用户人工验收通过(真机走查;本轮新增回归见 Comments)

  • [x] 进件后新增的待处理结算卡,能通过人工刷新收敛为已批准:MerchantExistingOnboardingTests.anAddedBankCardConvergesThroughTheSameManualRefresh(confirmOriginalCard 推广为「该门店所有待处理的卡」,挂在已有的人工刷新路径与银行卡列表读路径上)。
  • [x] 资金回退中与同日「确认中」的记录能被补偿任务收敛;确认查询接口不再是被零调用的死代码:PaymentFundConfirmationTests.anInFlightRevertConvergesThroughTheRetryTask、aConfirmationClaimedTodayConvergesThroughTheConfirmationQuery(delaytrans.confirmquery 接上;reverting 进入扫描范围,重发幂等请求即它的查询对等物)。
  • [x] 未新增定时任务(ADR-0001 / ADR-0002 的边界):本票只放宽与接上已有路径;F2 走人工刷新与读路径收敛。
  • [x] 绑卡回调地址已配置;把任一回调地址置空时,系统明确记录「回调未启用」:application.yml 补上 merchant-business-notify-url;HuifuCallbackUrlAudit 启动时逐个念一遍结论;PaymentSchedulingConfigurationTests.everyHuifuCallbackUrlIsReportedAndBlankOnesAreCalledOut。
  • [x] 对账间隔可从配置读取;开关在注解与配置上的默认值一致(删掉配置行不再让任务静默消失):PaymentSchedulingConfigurationTests(同时断言 yml 里写明了 fixed-delay-ms,以及注解默认值就是 :true)。
  • [x] 交易确认补偿的开关可用:app.payment.fund-confirmation-retry.enabled 现在真的被读取,默认与代码一致。
  • [x] 后台「刷新退款」与「查询通道状态」两个按钮可用:RefundRecordView 的「刷新退款」、MerchantOnboardingDetailView 的「查询通道状态」;talent-card-admin 的 vue-tsc -b 通过(两个接口原先都是零调用的)。
  • [x] 开发环境的「立即对账」入口走真实对账逻辑,且系统内不存在任何伪造资金事实的捷径:订单列表新增「立即对账」按钮 → POST /api/admin/management/payment-reconciliation/run,与定时任务调用同一个 PaymentReconciliationService.reconcile;对账间隔也可用 HUIFU_RECONCILIATION_FIXED_DELAY_MS 调短。
  • [x] 跑测试用 scripts/run-server-tests.ps1:全量 348 项,仅那 3 项已知基线失败,无新增。
  • [x] 顺带把「环境相关失败」修掉:PaymentFundConfirmationTests.aPendingConfirmationOfAVerifiedOrderIsRetriedWithoutAnotherVerification 现在先把自己之外的相关行移出扫描窗口,稳定通过;docs/agents/testing.md 的那一节已改写。
  • [x] 断掉回调走一遍进件、绑卡、核销、撤销核销与退款,全部能从查询路径收敛(2026-09-17 用户人工验收通过):查询对等物齐了、单点回归各有覆盖,整条链路仍待真机/联调走一遍。

验收

在一个收不到任何回调的环境里依次走:进件通过 → 追加一张结算卡 → 人工刷新 → 卡变已批准;核销一笔团购券 → 撤销核销使资金进入回退中 → 等待补偿任务把它收敛;后台一键刷新一笔退款的状态。全程不依赖任何回调到达。

Comments

  • 2026-09-17 发布。本票与 04-payment-converges-per-attempt.md 都改同一片对账代码,故被 04 阻塞,串行以免互踩。
  • 顺带记录一个已知隐患,本票会碰到同一个文件:交易确认补偿任务的用例因为测试库累计的合格行超过扫描上限而**必然失败**(见 docs/agents/testing.md 的「环境相关失败」,机制与 04 要修的「最早 100 条」饥饿同源)。改动它时建议让该用例自己腾出窗口,把它从环境相关失败变成稳定通过。
  • 2026-09-17 实现完成,状态转 ready-for-human。除上面两项外还有一处顺带改动:补偿任务的取行改为「每单只看最新一笔成功支付」(原先 distinct o.id 会把旧 pending 与新 confirmed 混在一起,同一笔钱有两个答案)。
  • 明确没做、按 ADR 0001 保持原样:进件进度仍靠人工刷新,没有加任何定时查询;MerchantOnboardingSchemaInitializer(商户域文件)也没有改——开发库的 V149/V150 改由 scripts/apply-sql-file.ps1 落地并实测。