fix(payment): 取消与到期不再赌钱,先与通道确认并在通道侧关单
本地环境收不到汇付回调,所以「订单待支付」只说明本地不知道,不说明没收过钱。原来取消订单只看
本地流水:把流水直接写成 LOCAL_CLOSED、订单置为已取消,钱还在通道、订单却没了,人才端连退款
入口都没有(退款要求订单是已支付)。超时清理走的是同一套判断,只是条件换成时间,同样会把已经
收下钱的订单自动取消。真实数据:2026-09-16 14:22 的一笔 ¥0.02 订单就是这样被取消的。
改为「资金事实以通道为准」,三条入口一起收敛:
- 取消(PendingOrderPortalService.cancel):先问通道,逐笔判定
- 通道确认收款 → 按回调同一条路径落成已支付,并拒绝取消(人才端随即有退款入口);
- 通道处理中或问不到 → 拒绝取消,提示稍后重试(问不清楚绝不动订单);
- 通道确认未收款 → 在通道侧关掉预支付单(新接 V2TradePaymentScanpayCloseRequest),
关单成功才把本地流水记为 CLOSED。
- 关单的三种余下结论各有归宿:关单处理中拒绝取消;关单回执说原交易已成功则拒绝取消并记
PAYMENT_CLOSE_CONFLICT(查单拿不到金额,不能谎称已支付);关单被拒(未满一分钟不允许关单、
不支持关单)或关单请求失败则允许取消,但流水记为 CANCEL_UNCONFIRMED——不记成已关闭,对账
任务会继续重试关单,万一用户后来真付了会留下 CLOSED_LATE_SUCCESS 问题记录,而不是无声消失。
- 重申支付与查支付状态(HuifuPaymentService):先确认,已收款直接返回 PAID,不再把用户送进
「订单已经支付,请勿重复发起支付」的死胡同,也避免同一笔订单再发起一次支付。
两个状态机缺口一并补上(新状态 CANCEL_UNCONFIRMED 必须可结算、可关闭):结算时它要能落成
SUCCEEDED 才会进入「取消后才收到钱」的问题记录;关单成功后也要能从它写回 CLOSED。
到期清理(expireDueOrders / expireOrder)跳过带未定局支付尝试(CREATED / PREPAY_CREATED /
CREATE_UNKNOWN)的订单,交给对账任务先问清楚:通道说收款就落成已支付,说失败就把流水置为
CREATE_FAILED,下一轮清理自然收掉。代价是这类订单晚一个对账周期(分钟级)才释放优惠券。
打开对账补单任务(application.yml,此前默认关闭且无人配置):没有它,回调一丢就只剩「用户点了
取消或重申支付」这一个补救入口;测试 profile 里显式关掉,避免后台任务在共享测试库上改动别的
用例正在断言的流水。
人才端待支付页:订单已支付就跳支付成功页(不再给出「确认支付/取消订单」两个按钮),取消失败后
重新查一次支付状态而不是把用户留在原地反复点。
测试:新增 PendingPaymentConfirmationTests 14 项(分轮先红后绿;「到期不自动取消」那项退掉守卫
验证过会红——旧逻辑下订单确实被取消成 order_status=2)。MerchantVerificationServiceTests 里
「建了预支付单仍可取消」的用例按新契约补上关单回执;PaymentSettlementTests 的用例级隔离补上
CANCEL_UNCONFIRMED(新状态必须跟着进清理集合,否则用例之间会互相污染)。
全量 273 项,仅 docs/agents/testing.md 所列 3 项基线失败,无新增。