tasks.md 20 KB

Tasks: OMG AIO 创建支付订单与付款结果回调重建

Input: spec.md, plan.md, research.md, data-model.md, contracts/api.md, quickstart.md

Tests: 本功能强制 TDD。每个生产任务先写失败测试并实际观察失败,再写最小实现。

Scope: 完成测试环境创建支付订单、最终付款结果回调及用户触发的当前支付查询补偿;不实现取号、定时/批量补单、退款、通用支付推送、关账或正式环境。2026-08-28 增量仅追加外送订单支付成功后的骑手开放推送。

Phase 1: 新持久化基础

  • T001 [US1] 在 ruoyi-system/src/test/java/com/ruoyi/system/omgpay/service/OmgPaymentAttemptServiceTest.java 编写新尝试字段校验、CREATED 插入和生成列不由 Java 写入的失败测试
  • T002 [US2] 在 ruoyi-system/src/test/java/com/ruoyi/system/omgpay/mapper/OmgPaymentAttemptMapperContractTest.java 编写 FOR UPDATE、新表名、唯一键及无旧表 SQL 的失败合约测试
  • T003 [US1] 在 updatesql/sql.md 仅追加 pos_order_omg_attempt DDL,不执行数据库变更
  • T004 [US1] 在 ruoyi-system/src/main/java/com/ruoyi/system/omgpay/domain/ 新建 OmgPaymentAttemptOmgPaymentOrderSnapshot
  • T005 [US1] 在 ruoyi-system/src/main/java/com/ruoyi/system/omgpay/mapper/OmgPaymentAttemptMapper.javaruoyi-system/src/main/resources/mapper/omgpay/OmgPaymentAttemptMapper.xml 实现锁定订单、活跃尝试、交易号查询和显式 INSERT
  • T006 [US1] 在 ruoyi-system/src/main/java/com/ruoyi/system/omgpay/service/ 实现 IOmgPaymentAttemptService 与校验严格的 OmgPaymentAttemptServiceImpl
  • T007 [US1] 运行 OmgPaymentAttemptServiceTest,OmgPaymentAttemptMapperContractTest 并确认通过

Checkpoint: 新表 DDL 已登记,system 模块可锁定订单并只写新尝试表。

Phase 2: 官方检查码与表单

  • T008 [US1] 在 OmgCheckMacSignerTest 写入官方期望值 AA5842FDA7E55ACEB7118D6353E9822CA6D6FF09A0D1FC129A879DD5CAF93266、额外字段、空值字段、输入不可变和非法字段失败测试
  • T009 [US1] 在 com.ruoyi.app.omgpay.OmgCheckMacSigner 实现排序、HashKey/HashIV 包夹、官方 .NET URL encode、小写、SHA-256 和大写输出
  • T010 [US1] 运行 OmgCheckMacSignerTest,确认官方向量和字段完整性全部通过
  • T011 [US1] 在 OmgMerchantTradeNoGeneratorTest 编写 20 位大写英数字与样本唯一性失败测试
  • T012 [US1] 在 OmgPaymentFormFactoryTest 编写 Taipei 时间、stage URL、15 字段、固定字段、全部字段签名及不安全 ReturnURL 失败测试
  • T013 [US1] 实现 OmgPaymentPropertiesOmgMerchantTradeNoGeneratorOmgPaymentFormOmgPaymentFormFactory
  • T014 [US1] 在 application.yml 新增独立 omgpay.return-url,新代码不读取旧 omg.* 创建/回调配置
  • T015 [US1] 运行生成器和表单测试并确认通过

Checkpoint: 可从服务端事实生成一份严格 stage-only、全字段签名的表单。

Phase 3: 创建编排与重复防护

  • T016 [US3] 在 OmgPaymentCreateServiceTest 编写订单不存在/越权、非单店、非法状态、已支付、金额、payType、门店和凭证失败矩阵
  • T017 [US2] 在同一测试编写已有活跃尝试时返回 PAYMENT_ATTEMPT_EXISTS 且不调用生成器/表单/凭证的失败测试
  • T018 [US1] 在同一测试编写成功调用顺序、响应白名单和安全内部元数据失败测试
  • T019 [US2] 在同一测试编写 active 唯一键冲突、MerchantTradeNo 冲突三次受控重试和未知重复键失败测试
  • T020 [US1] 实现 OmgPaymentErrorCodeOmgPaymentBusinessExceptionOmgPaymentCreateOutcome 和响应 DTO
  • T021 [US1] 实现 @Transactional OmgPaymentCreateService#create,保证锁订单和活跃查询发生在 MerchantTradeNo 生成前
  • T022 [US2] 实现重复键分类:发现活跃行立即终止,仅交易号碰撞允许最多三次重新生成
  • T023 [US1] 运行 OmgPaymentCreateServiceTest 并检查新包对旧 OMG 类/Service 零引用

Checkpoint: 首次请求创建,重复请求稳定拒绝;没有任何网关 HTTP 或旧支付表访问。

Phase 4: 公共 API、i18n 与排障日志

  • T024 [US3] 在 OmgPaymentControllerTest 编写 /pay/omg/create、token header、显式 DTO、无 Map 入参和请求字段白名单失败测试
  • T025 [US3] 编写 Controller 业务错误、成功、未知异常的响应契约失败测试
  • T026 [US3] 编写 INFO/WARN/ERROR、成功安全上下文、异常堆栈及敏感值不入日志的失败测试
  • T027 [US3] 在 default、zh_CN、zh_TW、en_US、vi 五个 i18n 文件加入完全一致的 omg.pay.* key 集合
  • T028 [US3] 实现 OmgPaymentTokenUserResolver、请求/错误 DTO 与新 OmgPaymentController
  • T029 [US3] 实现创建开始、成功、业务拒绝和非预期异常日志,不记录 token、凭证、完整检查码或表单
  • T030 [US1] 运行 OmgPaymentControllerTest 和 i18n key 对齐检查

Checkpoint: 新 Controller 独占 /pay/omg/create,响应与日志满足安全契约。

Phase 5: 旧 OMG 运行时退役

  • T031 [US3] 保存当前脏文件定向 diff,确认需要保留的 LINE/订单状态改动
  • T032 [US3] 在 OmgLegacyRetirementTest 编写旧 Controller、旧任务、旧支付实体必须不存在及新 Controller 只有 create 路由的失败测试
  • T033 [US3] 删除旧 OmgPayController、专属 DTO、OmgReconcileTaskOmgQueryThrottle 和旧 Controller 测试
  • T034 [US3] 删除旧支付/退款 Entity、Mapper、XML、Service、ServiceImpl 和对应旧测试;保留 pos_store_omg 全部可信实现
  • T035 [US3] 从 UserOrderControllerPosOrderShOprateController 取消链路移除旧 OMG 退款调用,不改变其他取消行为
  • T036 [US3] 从 PosOrderController 移除旧 OMG 补单、退款、人工确认端点及注入/辅助方法
  • T037 [US3] 从 OrderLifecycleService 移除旧表依赖和旧 OMG 补单/退款方法,保留 payType="2" 的支付前进门禁
  • T038 [US3] 定点更新 OrderLifecycleServiceTest,移除旧表测试/构造参数并保留已有 LINE 和订单生命周期测试
  • T039 [US3] 运行 OmgLegacyRetirementTest,OrderLifecycleServiceTest,并确认 main Java/XML 对旧支付/退款表及服务零匹配
  • T040 [US3] 将 application.yml 的旧 omg 配置收敛为凭证验证所需 base-url,移除旧回调/查询/补单/退款配置并保留新 omgpay.return-url
  • T041 [US3] 复核三个原脏文件的无关改动仍在,且没有全文件换行或格式化

Checkpoint: 旧表删除后没有可达运行链路访问它们;旧回调、查询、补单和退款接口全部不可达。

Phase 6: 综合验证与手动验收准备

  • T042 运行全部新 OMG 测试以及 OrderLifecycleServiceTest,LinePayCancellationRaceTest
  • T043 使用 JDK 21 运行 mvn -pl ruoyi-admin -am -DskipTests package
  • T044 检查禁止的 production URL、旧 OMG import、旧表 SQL、敏感日志与实际表单字段集合
  • T045 审查新公开类型、检查码、事务行锁和唯一键处理的必要注释,移除显然代码噪声注释
  • T046 运行 git diff --checkgit status --shortgit diff --stat 并确认无无关文件
  • T047 开发者手动执行 DDL 后,按 quickstart.md 验证首次创建、当前页 POST、重复、真实并发、负例和日志

Phase 7: 回调数据与凭证快照

  • T048 [US4] 更新 pos_order_omg_attempt DDL:新增 HashKey/HashIV 快照、PAID/FAILED/SUPERSEDED 状态、网关结果字段和 trade_no 唯一键;只写 updatesql/sql.md,不执行 SQL
  • T049 [US4] 先编写 Entity/Mapper/Service 合约测试源码,覆盖创建密钥快照、交易号锁定、成功不可逆、失败释放、其他活动尝试关闭与订单仅更新 pay_status
  • T050 [US4] 扩展 OmgPaymentAttempt、Mapper XML 和 IOmgPaymentAttemptService,实现带当前状态条件的原子更新
  • T051 [US4] 修改创建服务,把本次表单使用的 HashKey/HashIV 传入 createCreated 并持久化快照

Phase 8: 原始表单边界与 IPN 流水

  • T052 [US4] 先编写原始 form-urlencoded 解析测试源码,覆盖未知字段、空值、重复字段、非法编码、大小限制和可重放原文
  • T053 [US4] 实现 OmgNotifyRequest 与专用参数解析/ArgumentResolver;Controller 业务入参保持一个 DTO,不使用 Map 或 HttpServletRequest
  • T054 [US4] 先编写 IPN 独立事务测试源码,覆盖每次请求一行、type=omg、完整原文以及日志写入失败不阻断处理
  • T055 [US4] 在 com.ruoyi.system.omgpay 新建 OmgIpnAuditService,以 REQUIRES_NEW 复用 IIpnLogService 写入现有 ipn_log

Phase 9: 验签、状态机与公开回调

  • T056 [US4] 先编写回调服务测试源码,覆盖全部实际字段验签、快照密钥、商户/金额匹配、成功、模拟成功、失败、失败后成功、成功后失败、重复、取消后成功和第二笔迟到成功
  • T057 [US4] 实现 OmgPaymentNotifyService,在一个业务事务内锁定尝试、验签、校验并更新尝试与订单;不触发订单/配送状态、推送或退款副作用
  • T058 [US4] 先编写 Controller 契约测试源码,覆盖匿名 form POST、纯文本 1|OK/0|ERROR、完整请求日志和无旧回调引用
  • T059 [US4] 在新 OmgPaymentController 增加 POST /pay/omg/notify,先独立记录 IPN,再执行业务处理;所有请求完整记录,数据库密钥不入日志
  • T060 [US4] 静态审计 Controller 无 Map/HttpServletRequest 入参、回调只用新尝试表和可信 ipn_log/pos_store_omg 创建来源、无旧 OMG 业务引用

Phase 10: 回调文档与延后验证

  • T061 更新 quickstart.md 的回调重放示例、成功/失败/重复/模拟/取消后付款与 IPN 查询步骤
  • T062 运行 git diff --check、定向 rg 和 staged diff 审计;本阶段不运行 Maven、编译或测试
  • T063 在后续 OMG 查询、补单、退款等功能全部调整完成后,统一运行 JDK 21 定向测试、模块构建和完整回归

Phase 11: 当前有效支付查询与丢失回调补偿

  • T064 [US5] 扩展 Mapper/Service,以订单归属读取唯一 CREATED 或已付款订单的首条 PAID 尝试,不接受客户端指定 MerchantTradeNo
  • T065 [US5] 编写查询响应严格解析、全部实际字段验签、额外/空值字段篡改、当前尝试选择与 Controller 契约测试源码
  • T066 [US5] 新建 OmgPaymentQueryGateway,只 POST OMG stage QueryTradeInfo/V5,使用尝试的 MerchantID/HashKey/HashIV 快照签名并设置连接/读取超时
  • T067 [US5] 实现 POST /pay/omg/query:核验订单归属、交易号、商户号、金额和完整响应签名,只返回字段白名单
  • T068 [US5] 将可信 TradeStatus=1 复用回调同一幂等事务补偿为已付款;0 不修改;10200095 同步失败;任何结果都不得降级已付款事实
  • T069 [US5] 增加查询 i18n、必要安全日志、API/规格说明;不写 ipn_log,因为它不是网关主动 IPN
  • T070 所有 OMG 功能调整完成后,统一执行本阶段测试源码、JDK 21 模块构建和完整回归

Phase 12: 测试环境退款安全拒绝接口

  • T071 [US6] 先编写 Refund Service 与 Controller 测试源码,覆盖 token、显式 orderId DTO、稳定状态、异常映射和无网关/无状态依赖
  • T072 [US6] 新建 OmgRefundPaymentRequestOmgPaymentRefundService,在身份/订单号格式校验后直接返回测试环境不支持
  • T073 [US6] 在新 Controller 增加 POST /pay/omg/refund,返回 PAYMENT_REFUND_UNAVAILABLE_IN_TEST_ENVIRONMENT,不接受金额、交易号或 Action
  • T074 [US6] 增加 default、zh_CN、zh_TW、en_US、vi 一致 i18n 和脱敏拒绝日志
  • T075 [US6] 更新规格与 API 契约,明确不调用正式 OMG 地址、不读取或修改订单/支付/退款状态、不新增 SQL
  • T076 所有 OMG 功能调整完成后,统一执行退款测试源码、JDK 21 模块构建和完整回归

Phase 13: 旧实现与旧表最终清理

  • T077 扩展 OmgLegacyRetirementTest,先确认旧 com.ruoyi.app.utils.omg 三个类仍存在而失败
  • T078 为门店凭证联网探测编写签名、完整响应验签和额外字段篡改测试,再在 com.ruoyi.app.omgpay 实现 OmgStoreCredentialVerifier
  • T079 将 PosStoreOmgController 切换到新 verifier,删除旧工具类、旧工具测试和 omg.base-url;保留 pos_store_omg 全部凭证持久化与管理能力
  • T080 在 updatesql/sql.md 追加删除 pos_order_omg_refundpos_order_omg_payment 的 SQL,不执行数据库变更
  • T081 静态检查源码旧包/旧表引用为零,并用 JDK 21 运行完整 Maven 回归

Phase 14: App 销毁 WebView 后重新支付

  • T082 [US7] 先编写 retry Service、Controller、精确活动尝试替换与并发状态变化测试,并观察当前实现因缺少接口和行为而失败
  • T083 [US7] 扩展 Attempt Mapper/Service,以 id + CREATED 条件原子更新单条尝试为 SUPERSEDED;复用现有表结构,不新增或执行 SQL
  • T084 [US7] 在创建服务实现订单锁、订单再次校验、已验证 MerchantTradeNo 精确比较、旧尝试关闭与新表单创建的同事务替换
  • T085 [US7] 实现 OmgPaymentRetryServicePOST /pay/omg/retry,按 PAID/FAILED/UNPAID/UNKNOWN 安全分流并增加五语言错误状态
  • T086 [US7] 更新 API 契约与 App 接入文档,明确不保存/恢复 WebView、不重放旧表单,App 仍只有 OMG/LINE Pay 顶层选择
  • T087 使用 JDK 21 运行 retry、OMG 回归、模块构建与最终 diff/暂存范围检查

Phase 15: OMG 官方支付方式选择页渠道过滤

  • T088 [US1] 更新表单工厂测试源码,断言 ChoosePayment=ALLIgnorePayment=ATM#CVS#BarcodeATM 且不发送 UnionPay,并检查两个固定字段进入签名集合
  • T089 [US1] 修改 OmgPaymentFormFactory,由服务端固定生成并签名上述渠道参数,不改变创建、retry 请求或响应结构
  • T090 [US1] 更新规格、契约、快速验收和 App 接入文档,明确 App 继续直接提交 OMG 表单、不增加二级选择页面,AFTEE 由 OMG 商户侧关闭
  • T091 [US1] 在全部 OMG 功能调整完成后的统一验证阶段,使用 JDK 21 运行表单定向测试、OMG 回归和模块构建,并检查签名字段集合
  • T092 [US1] 在 OMG stage 手动确认信用卡可用、Apple Pay 在适用环境可用、ATM/CVS/BarcodeATM 不显示,并确认 OMG 商户侧已关闭 AFTEE

Phase 16: retry 查询稀疏响应兼容

  • T093 [US7] 为已签名但省略非核心字段的 TradeStatus=0/10200095 响应编写回归测试,并观察固定字段校验导致测试失败
  • T094 [US7] 将查询校验拆分为所有状态必需的核心身份字段与仅 PAID 必需的结算字段;所有实际字段继续参与验签
  • T095 [US7] 增加缺少核心字段、签名错误和已付款缺少结算字段的 fail-closed 测试,并确保诊断日志不记录字段值或完整响应
  • T096 [US7] 按 OMG stage 实际响应增加 10200047 + TradeAmt=0 回归测试,并验证非零金额时 fail closed
  • T097 [US7] 将签名有效且身份匹配的 10200047 + TradeAmt=0 同步为失败,释放旧尝试并复用 retry 新表单流程
  • T098 使用 JDK 21 运行查询定向测试、全部 OMG 回归、模块构建与最终 diff/暂存范围检查

Phase 17: iOS WebView 返回交接

  • T099 [US8] 在用户端 App pages/OrderList/buy/omgCheckout.vue 确认 renderjs Form 替换当前页面 WebView,并记录旧版本停留结果页的失败基线
  • T100 [US8] 在 omgCheckout.vue 的普通 <script> 中仅对 App-Plus iOS 监听当前 this.$scope.$getAppWebview()loaded,不得读取 children()[0]
  • T101 [US8] 精确识别 https://foodieapi.waimai-paotui.com/pay/omg/result 及其 query/hash 形式,只触发一次 handleOmgReturnDetected({ orderId, currentUrl }),页面卸载时移除监听
  • T102 [US8] 使用 JDK 21 运行 OmgPaymentClientReturnServiceTest,确认后端现有 HTML、繁体提示、“返回 App”按钮与 Scheme 兜底保持不变
  • T103 [US8] 使用 iPhone 真机验证 result_page_detected 单次触发,并用中间页/取消页、Android 和外部浏览器完成负例及兼容验收

Phase 18: App 信用卡与 Apple Pay 双入口

  • T104 [US1] 更新现有规格、研究结论、实施计划、API 契约、快速验收与 App 交接文档,以本阶段设计取代 ALL + IgnorePayment 方案
  • T105 [US1] 在同一批次补充 create/retry DTO、Controller、Service 与表单工厂测试源码,覆盖 CREDIT/APPLE_PAY、非法枚举无副作用、动态字段集合和完整签名输入
  • T106 [US1] 为 create/retry 增加受控 paymentMethod,统一映射 CREDIT -> Credit + UnionPay=2APPLE_PAY -> ApplePay,新增五语言 PAYMENT_METHOD_INVALID,禁止客户端 OMG 原始参数
  • T107 [US1] 在用户端 App 增加信用卡/Apple Pay i18n 选择,并让首次支付与重新支付分别提交本次选择;当前工作区未包含 App 源码,需提供用户端仓库后实施
  • T108 [US1] 全部 OMG 计划功能调整完成后,使用 JDK 21 统一运行渠道定向测试、OMG 回归和模块构建;核对最终 diff、暂存范围及无 SQL 变更
  • T109 [US1] 在 OMG stage 分别验收信用卡和 Apple Pay 直接流程,确认不出现超商快付、AFTEE、银联或其他渠道选择项

Phase 19: 外送订单支付后开放骑手

  • T110 更新 OMG 规格,允许首次成功结算在不推进订单/配送状态的前提下触发外送骑手开放推送
  • T111 在 OmgPaymentNotifyService 首次更新订单支付状态后加载业务订单,并复用配送推送服务按统一条件开放给骑手
  • T112 补充 OMG 首次成功结算触发骑手开放推送测试,并复用统一开放条件拦截未支付或非待接单状态

Dependencies & Execution Order

  • Phase 1 → Phase 2 → Phase 3 → Phase 4 → Phase 5 → Phase 6 → Phase 7 → Phase 8 → Phase 9 → Phase 10 → Phase 11 → Phase 12 → Phase 13 → Phase 14 → Phase 15 → Phase 16 → Phase 17 → Phase 18。
  • T008 与 T011/T012 可独立写测试,但实施时顺序执行以维持清晰 TDD 证据。
  • T031 必须早于任何脏文件修改;T041 必须在旧代码退役完成后执行。
  • 手动 stage 验收依赖开发者执行 DDL,自动测试和构建不依赖数据库变更。

Completion Definition

  • POST /pay/omg/create 首次返回可提交的 stage 表单。
  • POST /pay/omg/notify 对所有实际字段验签,并幂等同步成功/失败支付事实。
  • 每次回调完整保存到现有 ipn_log;不新增该表字段。
  • 成功仅修改订单 payStatus,不推进业务状态或触发退款;外送订单首次支付成功可触发骑手开放推送,其他通用支付推送不触发。
  • 同订单重复/并发创建最多一条 CREATED,后续请求为 PAYMENT_ATTEMPT_EXISTS
  • 官方检查码向量一致,实际发送字段无遗漏。
  • App 只提交 CREDIT/APPLE_PAY;新支付表单分别固定为 ChoosePayment=Credit + UnionPay=2ChoosePayment=ApplePay,不发送 ChoosePayment=ALLIgnorePayment
  • 新代码全在 omgpay 包,不引用旧 OMG 支付实现。
  • 旧 Controller、回调、查询、补单、退款、任务及旧表运行时引用为零。
  • pos_store_omg 凭证表、持久化和管理能力保留;联网探测只使用新 omgpay 实现。
  • 日志足以定位问题且无敏感信息;非预期异常保留堆栈。
  • JDK 21 定向测试与构建通过,最终 diff 无无关改动。
  • iPhone 中 omgCheckout 监听当前页面 WebView,精确结果 URL 单次触发交接;后端现有结果页、按钮和 Scheme 兜底保持兼容。