|
|
@@ -0,0 +1,217 @@
|
|
|
+---
|
|
|
+description: "Task list for OMG(歐買尬/FunPoint)AIO 支付接入"
|
|
|
+---
|
|
|
+
|
|
|
+# Tasks: OMG(歐買尬/FunPoint)AIO 支付接入
|
|
|
+
|
|
|
+**Input**: Design documents from `/specs/016-omg-payment/`
|
|
|
+
|
|
|
+**Prerequisites**: plan.md, spec.md, research.md(D1–D13), data-model.md, contracts/api.md(A1–A5/B1–B7/§C), quickstart.md(均已就绪)
|
|
|
+
|
|
|
+**Tests**: 未要求 TDD;验证以 `OmgCheckMacValue.main` 自测(官方示例值)+ quickstart.md 场景 A–E 端到端为准。
|
|
|
+
|
|
|
+**Organization**: 按 user story 组织,每个 story 可独立实现与验证。**MVP = US1 + US2**(支付闭环)。
|
|
|
+
|
|
|
+**⚠️ 硬约束(research §0)**:OMG 全部代码独立新建,**零 `newebpay` 依赖**(不得 import `com.ruoyi.app.utils.newebpay.*`、`NewebPayEncryptUtil`、`NewebPay`、`NewebpayPayController`、`PosStoreNewebpay*`,不复用 `pos_order_payment` 表)。仅复用平台共享基础设施:`PosOrder`/`IPosOrderService`、`PayPush`/`PushEventService`、`OrderLogHelper`、`IpnLog`、`OrderPushBodyDto`、`sendAcceptRiderPush`/`sendHdfkMessage` 链路、`InfoUser`、`@Anonymous`。
|
|
|
+
|
|
|
+## Format: `[ID] [P?] [Story] Description`
|
|
|
+
|
|
|
+- **[P]**: 可并行(不同文件、无依赖)
|
|
|
+- **[Story]**: 归属 user story(US1~US5)
|
|
|
+- 描述含精确文件路径;前端 CRLF 文件用 Python 脚本编辑
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 1: Setup(基础设施)
|
|
|
+
|
|
|
+**Purpose**: 数据库 DDL 与配置就位
|
|
|
+
|
|
|
+- [ ] T001 追加三表建表 DDL 到 `updatesql/sql.md`(`pos_store_omg`、`pos_order_omg_payment`、`pos_order_omg_refund`,取自 data-model.md,标注 2026-07-29 OMG 支付接入;不直接执行)
|
|
|
+- [ ] T002 [P] 在 `ruoyi-admin/src/main/resources/application.yml`(及 `application-dev.yml`)新增 `omg` 配置段(见 research D8/contracts B1):`base-url=https://payment-stage.funpoint.com.tw`(正式 `payment.funpoint.com.tw`)、`return-url`、`order-result-url`、`payment-info-url`、`client-redirect-url`;`InvoiceMark=N`、`EncryptType=1` 在代码固定,不入配置
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 2: Foundational(阻塞前置,所有 story 依赖)
|
|
|
+
|
|
|
+**Purpose**: 签名工具、HTTP 客户端、三实体、Mapper——所有 story 的公共地基
|
|
|
+
|
|
|
+**⚠️ CRITICAL**: 本阶段完成前(尤其 `OmgCheckMacValue` 自测通过)不得开始任何 user story
|
|
|
+
|
|
|
+- [ ] T003 [P] 创建 `ruoyi-admin/src/main/java/com/ruoyi/app/utils/omg/OmgPayConfig.java`(merchantId/hashKey/hashIv,构造器+getter,仿 `NewebPayConfig` 结构但独立包)
|
|
|
+- [ ] T004 创建 `ruoyi-admin/src/main/java/com/ruoyi/app/utils/omg/OmgCheckMacValue.java`:静态 `generate(Map params, hashKey, hashIv)` 与 `verify(Map params, hashKey, hashIv)`。算法(contracts §C4 / research D1):去 CheckMacValue → key 字母序 → `k=v&...` → 包夹 `HashKey={k}&..&HashIV={iv}` → `URLEncoder.encode(s,UTF_8)` → 替换 `%2d→- %5f→_ %2e→. %21→! %2a→* %28→( %29→)` → 转小写 → SHA256 → hex 大写。含 `main` 自测:用官方示例 HashKey=`5294y06JbISpM5x9`/HashIV=`v77hoKGq4kWxNNIS` 复算应得 `AA5842FDA7E55ACEB7118D6353E9822CA6D6FF09A0D1FC129A879DD5CAF93266`
|
|
|
+- [ ] T005 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PosStoreOmg.java`(`@TableName("pos_store_omg")`,字段见 data-model.md §1)
|
|
|
+- [ ] T006 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderOmgPayment.java`(`@TableName("pos_order_omg_payment")`,字段见 data-model.md §2)
|
|
|
+- [ ] T007 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrderOmgRefund.java`(`@TableName("pos_order_omg_refund")`,字段见 data-model.md §3)
|
|
|
+- [ ] T008 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosStoreOmgMapper.java` + `ruoyi-system/src/main/resources/mapper/chanting/PosStoreOmgMapper.xml`(基础 CRUD + selectStoreList/selectStoreDetail VO 查询,仿 PosStoreEzpayMapper)
|
|
|
+- [ ] T009 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosOrderOmgPaymentMapper.java` + `.../mapper/chanting/PosOrderOmgPaymentMapper.xml`(insert、selectByTradeNo、selectByMerchantTradeNo、selectLatestByDdId、updateById)
|
|
|
+- [ ] T010 [P] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/mapper/PosOrderOmgRefundMapper.java` + `.../mapper/chanting/PosOrderOmgRefundMapper.xml`(insert、selectByPaymentId、selectByDdId)
|
|
|
+- [ ] T011 [P] 创建 `ruoyi-admin/src/main/java/com/ruoyi/app/utils/omg/OmgPay.java`(`@Component`,HTTP 客户端,httpclient4+fastjson2):端点常量 `URL_AIO_CHECKOUT=/Cashier/AioCheckOut/V5`、`URL_QUERY_TRADE_INFO=/Cashier/QueryTradeInfo/V5`、`URL_DO_ACTION=/CreditDetail/DoAction`;`createAioForm(baseUrl,cfg,params)`→对全部参数生成 CheckMacValue 后返回 form 字段 Map(含 gatewayUrl);`queryTrade(baseUrl,cfg,merchantTradeNo)`→响应 k=v 解析为 Map;`doAction(baseUrl,cfg,merchantTradeNo,tradeNo,action,totalAmount)`→响应 Map;私有 `postForm`
|
|
|
+
|
|
|
+**Checkpoint**:`OmgCheckMacValue.main` 自测通过、三表可建、实体/Mapper 就绪 → 可开始 user story
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 3: User Story 1 - 发起 OMG 支付 (Priority: P1) 🎯 MVP part 1
|
|
|
+
|
|
|
+**Goal**: C 端用户下单后调发起接口拿到 form 参数,前端 Form Post 跳转 OMG 收银台(ChoosePayment=ALL)
|
|
|
+
|
|
|
+**Independent Test**: 对已开通 OMG 的门店下单 → 调 `/pay/omg/create` → 返回 `gatewayUrl` + 全参数(含 CheckMacValue) → 前端跳转 OMG 页出现支付方式;`pos_order_omg_payment` 落一行(pay_status=0)、`pos_order.pay_type="7"`
|
|
|
+
|
|
|
+- [ ] T012 [P] [US1] 创建 `ruoyi-system/src/main/java/com/ruoyi/system/domain/dto/StoreOmgCredentialDto.java`(storeId/merchantId/hashKey/hashIv/enabledPayments,`@Valid`)与 `ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/PosStoreOmgVo.java`(列表/详情 VO)
|
|
|
+- [ ] T013 [US1] 实现 `ruoyi-system/.../service/IPosStoreOmgService.java` + `impl/PosStoreOmgServiceImpl.java`(纯 DB:`getOrCreateByStoreId`、`getEnabledConfig(storeId)` 返回已开通且启用的凭证或 null、`getEnabledByMerchantId(merchantId)` 回调按商店代号反查凭证),仿 PosStoreEzpayServiceImpl
|
|
|
+- [ ] T014 [US1] 实现 `ruoyi-system/.../service/IPosOrderOmgPaymentService.java` + `impl/PosOrderOmgPaymentServiceImpl.java`:`createPayment(ddId,merchantTradeNo,storeId,merchantId,amount,choosePayment)`、`getByTradeNo`、`getByMerchantTradeNo`、`getLatestByDdId`、`markSuccess(...payType,rtnCode,rtnMsg,authCode,payTime,callbackRaw)`(幂等:tradeNo 已 pay_status=1 返回 0)、`markFail`、`markRefunded`
|
|
|
+- [ ] T015 [US1] 在 `ruoyi-system/.../domain/PosOrder.java` 附近或新建常量类定义 `PAY_TYPE_OMG="7"`(OMG 在线支付),不改表结构
|
|
|
+- [ ] T016 [US1] 创建 `ruoyi-admin/src/main/java/com/ruoyi/app/pay/OmgPayController.java` 实现 `POST /pay/omg/create`(`@Anonymous`+`@Auth`,Header token):校验订单存在/未支付/属当前用户/金额>0 → `getEnabledConfig(mdId)`(无则 `error("该门店暂不支持线上支付")`)→ `MerchantTradeNo="OMG"+清洗(ddId)` → 组参(MerchantID/MerchantTradeNo/MerchantTradeDate=yyyy/MM/dd HH:mm:ss/PaymentType=aio/TotalAmount=amount/ReturnURL/ChoosePayment=ALL/EncryptType=1/ItemName/InvoiceMark=N)→ `OmgPay.createAioForm` 生成 CheckMacValue 与 form 字段 → `createPayment` 落流水(pay_status=0) → 更新 `pos_order.pay_type="7"`/`pay_url=gatewayUrl` → 返回 form 字段(见 contracts/api.md B1)
|
|
|
+- [ ] T017 [US1] 前端 `E:\QtwCode\foodie\foodie-store\` 新增「OMG 支付」入口:下单后调 `/pay/omg/create`,用返回字段构建隐藏 form 自动 submit 到 `gatewayUrl`;支付相关文案用 `$t()` 四语 i18n(zh/tw/en/vi,key 加到对应对象层级,有意义命名)
|
|
|
+
|
|
|
+**Checkpoint**: 发起支付链路通,可跳转 OMG 测试收银台(此时回调未接,订单状态待 US2 更新)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 4: User Story 2 - 支付回调核销与履约触发 (Priority: P2) 🎯 MVP part 2
|
|
|
+
|
|
|
+**Goal**: OMG `ReturnURL` 回调到达后,验签 CheckMacValue + 幂等 + 金额 + RtnCode/SimulatePaid 校验,更新订单 payStatus=1 并触发推送(含可接单骑手);`/pay/omg/return` 仅引导
|
|
|
+
|
|
|
+**Independent Test**: US1 发起并跳转后用测试卡付款 → OMG 回调 `/pay/omg/notify` → 订单 payStatus=1、`pos_order_omg_payment` 写 trade_no/pay_type=`Credit_CreditCard`/rtn_code=1、用户/商家/骑手收到推送;重复回调不变;金额不符/伪造签名拒绝
|
|
|
+
|
|
|
+- [ ] T018 [US2] 在 `OmgPayController.java` 实现 `POST /pay/omg/notify`(`@Anonymous`):collectForm 收参 → 记 IpnLog → 由 `MerchantID` 调 `getEnabledByMerchantId` → 无凭证记录并返回
|
|
|
+- [ ] T019 [US2] notify 验签:`OmgCheckMacValue.verify(全部回调参, hashKey, hashIv)`,与回传 `CheckMacValue` 不符 → 拒绝并记录(绝不变更订单),仍回 `1|OK`
|
|
|
+- [ ] T020 [US2] notify 幂等+金额+状态校验:按 `TradeNo` 查 `pos_order_omg_payment`(已 pay_status=1 → 直接返回 `1|OK`);`TradeAmt==订单 amount`(不符→拒绝核销、告警);由 `MerchantTradeNo` 反查流水与订单(不存在→记录待查返回);判 `RtnCode==1 且 SimulatePaid!=1`(模拟支付 `SimulatePaid=1` → 不发货、记录)
|
|
|
+- [ ] T021 [US2] notify 成功业务链路:`markSuccess`(pay_type=回覆 PaymentType 如 `Credit_CreditCard`、rtn_code、pay_time=PaymentDate、callback_raw)→ 更新 `pos_order`(state=0, payStatus=1) → `orderLogHelper.logSync` 记日志 → `PayPush`+`pushEventService.PublisherEvent` 推送用户/商家(参照 `PosOrderController.sendHdfkMessage` 货到付款同款 `OrderPushBodyDto.getJson`)→ **补全可接单骑手推送**:在 `OmgPayController` 内独立实现(复用 `PayPush.sendAcceptRiderPush` / 货到付款链路调用方式,**不复用 NewebPay 代码**,见 CLAUDE.md「sendAcceptRiderPush 迁移」)→ 回应**纯字符串 `1|OK`**(注意:非 JSON,与蓝新不同)
|
|
|
+- [ ] T022 [US2] notify 失败处理(`RtnCode!=1`):`markFail` 写流水(pay_status=2)、订单保持未支付、记 `rtn_code`+`rtn_msg`(不硬编码错误码分支,见 contracts §C3)、回 `1|OK`
|
|
|
+- [ ] T023 [US2] 在 `OmgPayController.java` 实现 `GET|POST /pay/omg/return`(`@Anonymous`):仅 302 重定向前端结果页(带 ddId),**不改订单状态**(以 notify 为准)
|
|
|
+- [ ] T024 [US2] 前端 `E:\QtwCode\foodie\foodie-store\` 支付结果页:展示支付状态、轮询订单 payStatus(ReturnURL 不改状态,以轮询/回调后状态为准);文案四语 i18n
|
|
|
+
|
|
|
+**Checkpoint**: US1+US2 构成完整 MVP——下单→付款→订单已支付→推送,可端到端验证(quickstart 场景 B、C)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 5: User Story 5 - 门店 OMG 凭证开通管理 (Priority: P2)
|
|
|
+
|
|
|
+**Goal**: 运营在平台后台录入/验证/启停门店 OMG 凭证(独立于蓝新凭证表)
|
|
|
+
|
|
|
+**Independent Test**: 后台为门店录入测试凭证 → 调 `QueryTradeInfo/V5` 验证通过 → 状态已开通 → 该门店可发起支付;停用后不可
|
|
|
+
|
|
|
+- [ ] T025 [US5] 创建 `ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosStoreOmgController.java`(`/system/storeOmg`,`@PreAuthorize("chanting:storeOmg:*")`):`list`/`{storeId}`/`apply/{storeId}`/`saveCredentials`/`toggleEnable/{storeId}`/`reset/{storeId}`/`enabledPayments/{storeId}`,仿 `PosStoreEzpayController` 模式
|
|
|
+- [ ] T026 [US5] `saveCredentials` 凭证验证:Controller 调 `OmgPay.queryTrade(fictitious MerchantTradeNo)` 探测;响应提示金钥/商店错误 → 视为无效拒绝、状态不变、记 `last_verify_result`;否则 `enableWithCredentials`(omg_status=2/is_enabled=1)
|
|
|
+- [ ] T027 [US5] 扩展 `PosStoreOmgServiceImpl`:`apply`(0→1)、`enableWithCredentials`、`toggleEnable`、`reset`、`setEnabledPayments`、`recordVerifyResult`(仿 PosStoreEzpayServiceImpl 状态机)
|
|
|
+- [ ] T028 [US5] 平台后台 `E:\QtwCode\foodie\foodie-admin-vue\` 新增门店 OMG 凭证管理页(列表分页/详情/录入凭证/启停/重置/设置方式),文案四语 i18n
|
|
|
+- [ ] T029 [US5] 菜单与权限:新增菜单项 + 权限标识 `chanting:storeOmg:list/query/apply/saveCredentials/toggleEnable`,`sys_menu` 插入 SQL 写入 `updatesql/sql.md`(仿 storeEzpay 菜单,不直接执行)
|
|
|
+
|
|
|
+**Checkpoint**: 凭证可全流程管理,US1 发起支付有真实凭证来源(不必手插数据)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 6: User Story 3 - ATM / 超商 非即时支付 (Priority: P3)
|
|
|
+
|
|
|
+**Goal**: `ChoosePayment=ALL` 下消费者选 ATM/超商时,平台展示 OMG 虚帐/缴费码,消费者期限内付款后回调核销
|
|
|
+
|
|
|
+**Independent Test**: 选 ATM/超商 → OMG 回调 `/pay/omg/paymentInfo` 带虚帐/缴费码 → 平台展示 + 期限 → 消费者付款 → `/pay/omg/notify`(RtnCode=1) → 订单核销(quickstart 场景 D)
|
|
|
+
|
|
|
+- [ ] T030 [US3] 在 `OmgPayController.java` 实现 `POST /pay/omg/paymentInfo`(`@Anonymous`):`OmgCheckMacValue.verify` → 解析 BankCode/vAccount/ExpireDate 或 PaymentNo/ExpireDate → 落 `pos_order_omg_payment.callback_raw`(并可用专用字段/`pay_url` 存取号码供前端读)→ 回 `1|OK`
|
|
|
+- [ ] T031 [US3] 暴露取号信息给前端:`GET /pay/omg/paymentInfo/{orderid}`(或复用订单查询)返回虚帐/缴费码 + 期限;前端 `E:\QtwCode\foodie\foodie-store\` ATM/超商结果页展示 + 倒计时;文案四语 i18n
|
|
|
+- [ ] T032 [US3] 延期付款最终核销:消费者实际付款后 OMG 回调 `/pay/omg/notify`(RtnCode=1)→ 复用 US2 的 `markSuccess` + 推送链路(pay_type=`ATM_*`/`CVS_*`)→ 订单已支付
|
|
|
+
|
|
|
+**Checkpoint**: ATM/超商 全链路(取号→展示→付款→核销)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 7: User Story 4 - 订单取消与退款 (Priority: P3)
|
|
|
+
|
|
|
+**Goal**: 订单取消时,信用卡订单调 OMG `DoAction` 退款并同步状态;ATM/超商记录待人工
|
|
|
+
|
|
|
+**Independent Test**: 对一笔 OMG 已支付信用卡订单发起取消 → 调 `DoAction`(Action=R) → `pos_order_omg_refund` 记录、`pos_order_omg_payment.pay_status=3`、`pos_order.pay_status=2`;失败→记 `rtn_msg` 可重试(quickstart 场景 E)
|
|
|
+
|
|
|
+- [ ] T033 [US4] 实现 `ruoyi-system/.../service/IPosOrderOmgRefundService.java` + `impl`(`record(paymentId,ddId,tradeNo,action,amount,rtnCode,rtnMsg,callbackRaw)`、`listByPayment`、`listByDdId`)
|
|
|
+- [ ] T034 [US4] 在 `OmgPayController.java` 实现退款(`POST /pay/omg/refund?orderid=` 或由取消链路调用):查 OMG 已支付订单 → 信用卡(pay_type=`Credit_CreditCard`) → `OmgPay.doAction(Action=R, TotalAmount=amount)` → 写 `pos_order_omg_refund` → `RtnCode==1` 则 `markRefunded`(pay_status=3) + `pos_order.pay_status=2`;`ATM_*/CVS_*/BarcodeATM_*` 无 API → 记录待人工处理
|
|
|
+- [ ] T035 [US4](可选/增强)状态化 Action:下单时 `NeedExtraPaidInfo=Y` 取 `gwsr`,退款前查 `CreditDetail/QueryTrade/V2`(需盘合后台 `CreditCheckCode`) 决定 `N(已授權)/E(要關帳)/R(已關帳)`;MVP 可先统一 `R`,失败再分支
|
|
|
+- [ ] T036 [US4] 接入订单取消链路:`PosOrderShOprateController`(商家取消) / `UserOrderController`(用户取消) 取消 OMG 已支付订单时触发退款;相关提示文案四语 i18n
|
|
|
+
|
|
|
+**Checkpoint**: 信用卡退款闭环(stage `DoAction` 不可用,退款须正式小额或 mock 验证)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Phase 8: Polish & Cross-Cutting
|
|
|
+
|
|
|
+**Purpose**: 多 story 共享的收尾与护栏
|
|
|
+
|
|
|
+- [ ] T037 [P] 四语 i18n 统一校验:foodie-store 与 foodie-admin-vue 的 zh.js/tw.js/en.js/vi.js 中 OMG 支付相关 key 四文件齐全、命名有意义、位于正确对象层级(用 i18n-consistency-checker 或人工核)
|
|
|
+- [ ] T038 [P] 安全复核:`/pay/omg/notify`、`/pay/omg/paymentInfo`、`/pay/omg/return` 确为 `@Anonymous` 且仅这些匿名;HashKey/HashIV 不出现在任何前端响应/日志明文;CheckMacValue 验签为强制前置;金额校验与 `SimulatePaid` 守卫不可绕过
|
|
|
+- [ ] T039 [P] **零蓝新依赖复核**:grep `com.ruoyi.app.utils.omg` 及 `OmgPayController`/`PosStoreOmg*`/`PosOrderOmg*` 全部 OMG 新建类,确认无任何 `newebpay` import(必须为 0,违反硬约束)
|
|
|
+- [ ] T040 运行 `specs/016-omg-payment/quickstart.md` 全部场景 A–E 端到端验证(stage + 测试卡 + 内网穿透),记录结果(退款场景 E 因 stage 不可用需正式小额/mock)
|
|
|
+- [ ] T041 文档一致性:确认 spec.md/plan.md/tasks.md 描述一致;`updatesql/sql.md` 中 SQL 齐全(三建表 + OMG 菜单权限)
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Dependencies & Execution Order
|
|
|
+
|
|
|
+### Phase 依赖
|
|
|
+- **Phase 1 Setup**: 无依赖,立即开始
|
|
|
+- **Phase 2 Foundational**: 依赖 Phase 1 —— **阻塞所有 user story**(`OmgCheckMacValue` 自测必须先过)
|
|
|
+- **Phase 3 US1**: 依赖 Phase 2
|
|
|
+- **Phase 4 US2**: 依赖 US1(回调处理依赖发起产生的流水与订单关联)
|
|
|
+- **Phase 5 US5(凭证管理)**: 依赖 Phase 2(凭证表/Mapper);**可与 US1/US2 并行**(US1 测试可临时手插凭证数据)
|
|
|
+- **Phase 6 US3(ATM/超商)**: 依赖 US1+US2(复用发起+回调主链路,增量在取号回调与展示)
|
|
|
+- **Phase 7 US4(退款)**: 依赖 US1+US2(依赖已支付流水与 trade_no)
|
|
|
+- **Phase 8 Polish**: 依赖所有欲交付的 story 完成
|
|
|
+
|
|
|
+### User Story 独立性
|
|
|
+- **US1**: 依赖 Foundational,无跨 story 依赖
|
|
|
+- **US2**: 依赖 US1(闭环下半段)
|
|
|
+- **US3**: 依赖 US1+US2,增量在 PaymentInfoURL 取号与展示
|
|
|
+- **US4**: 依赖 US1+US2
|
|
|
+- **US5**: 依赖 Foundational,可与 US1/US2 并行
|
|
|
+
|
|
|
+### 并行机会
|
|
|
+- Phase 2 的 T003/T005/T006/T007/T008/T009/T010/T011 互不冲突,可全部并行(T004 CheckMacValue 优先跑通自测)
|
|
|
+- US5(Phase 5)可与 US1/US2(Phase 3/4)并行(不同文件、不同端)
|
|
|
+- Phase 8 的 T037/T038/T039 可并行
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Parallel Example: Foundational
|
|
|
+
|
|
|
+```bash
|
|
|
+# 以下任务文件互不冲突,可并行:
|
|
|
+Task: "OmgPayConfig in ruoyi-admin/.../utils/omg/OmgPayConfig.java"
|
|
|
+Task: "PosStoreOmg in ruoyi-system/.../domain/PosStoreOmg.java"
|
|
|
+Task: "PosOrderOmgPayment in ruoyi-system/.../domain/PosOrderOmgPayment.java"
|
|
|
+Task: "PosOrderOmgRefund in ruoyi-system/.../domain/PosOrderOmgRefund.java"
|
|
|
+Task: "PosStoreOmgMapper + XML"
|
|
|
+Task: "PosOrderOmgPaymentMapper + XML"
|
|
|
+Task: "PosOrderOmgRefundMapper + XML"
|
|
|
+Task: "OmgPay HTTP 客户端骨架 in ruoyi-admin/.../utils/omg/OmgPay.java"
|
|
|
+# OmgCheckMacValue(T004) 含被他人依赖的签名契约,建议优先完成并跑通自测
|
|
|
+```
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Implementation Strategy
|
|
|
+
|
|
|
+### MVP First(US1 + US2)
|
|
|
+1. Phase 1 Setup + Phase 2 Foundational(**`OmgCheckMacValue` 自测必须先过**)
|
|
|
+2. Phase 3 US1(发起支付)+ Phase 4 US2(回调处理)→ 端到端验证(quickstart 场景 B、C)
|
|
|
+3. **STOP and VALIDATE**: 下单→信用卡付款→订单已支付→推送(含可接单骑手),全链路通
|
|
|
+4. 此时已是最小可用产品
|
|
|
+
|
|
|
+### 增量交付
|
|
|
+1. MVP(US1+US2)→ 验证 → 可上测试环境
|
|
|
+2. + US5(凭证管理)→ 去除手插数据、运营自助
|
|
|
+3. + US3(ATM/超商)→ 覆盖延期方式
|
|
|
+4. + US4(退款)→ 售后资金闭环
|
|
|
+5. Polish(i18n/安全/零蓝新复核/全场景验证)→ 可转正式
|
|
|
+
|
|
|
+### 并行策略
|
|
|
+- Foundational 完成后:开发者 A 做 US1+US2(主链路),开发者 B 做 US5(凭证管理前后端),互不阻塞
|
|
|
+- US3/US4 待主链路稳定后接力
|
|
|
+
|
|
|
+---
|
|
|
+
|
|
|
+## Notes
|
|
|
+
|
|
|
+- [P] 任务 = 不同文件、无依赖;同文件多改动须串行
|
|
|
+- 前端 CRLF 文件(foodie-store/foodie-admin-vue)用 Python 脚本编辑,避免 Edit 匹配失败
|
|
|
+- 所有数据库变更写 `updatesql/sql.md`,不直接执行
|
|
|
+- 每个任务或逻辑组完成后提交(按用户指示);在 test 分支开发,不新建分支
|
|
|
+- HashKey/HashIV 为敏感凭证:仅后端持有,日志脱敏,不下发前端
|
|
|
+- **硬约束**:全程零 `newebpay` 依赖(T039 复核);Apple Pay 归在 Credit 下,回覆 PaymentType=`Credit_CreditCard`
|