# Tasks: 線下轉賬支付（payType=6）

**Feature**: specs/027-offline-transfer-payment | **Generated**: 2026-09-03

**参考**: plan.md（改动文件清单）、research.md（D1-D9 决策）、contracts/api.md（接口契约）、quickstart.md（冒烟场景）

**通用约束（每个任务遵守）**：
- 后端/前端文件均为 CRLF，用 Python 脚本编辑（`python << 'PYEOF'`），锚点唯一性校验后再写
- Java 注释禁出现 `*/` 序列；Controller 规范（`@RequestHeader token` + 显式 `@RequestParam`，禁 Map 入参）
- 每个后端任务完成后 `mvn -q -pl ruoyi-system,ruoyi-admin -am compile -DskipTests`（JAVA_HOME=C:\Users\qmj\.jdks\graalvm-jdk-21.0.7）验证
- 不执行任何数据库变更（本功能零 DDL）

## Phase 1: Setup

- [x] T001 [P] 在 ruoyi-admin/src/main/java/com/ruoyi/app/order/OrderLifecycleService.java 增加常量 `public static final String PAY_TYPE_TRANSFER = "6";`（紧邻 PAY_TYPE_CASH，带 Javadoc：線下轉賬支付，商家线下确认收款后解锁配送），编译验证

## Phase 2: Foundational（无）

## Phase 3: US1 收银台收款账户查询（P1）

目标：App 依据接口决定「線下支付」选项显隐与账户展示。独立测试：齐全商家门店返回三字段；缺任一字段返回 data=null；连锁多店返回同一份。

- [x] T002 [P] [US1] 在 ruoyi-admin/src/main/java/com/ruoyi/app/mendian/PosStoreController.java 新增 `GET /chanting/store/bankInfo`（`@Anonymous`，`@RequestParam Integer id`）：按门店查 `pos_store.user_id` → `info_user` 的 bankAccountName/bankName/bankAccountNo；三项均非空返回 `{accountName, bankName, accountNo}`，任一为空返回 `success(null)`；参考 getstore 风格，Javadoc 注明「商家收款账户（線下轉賬收银台展示用），商家级、连锁共享」，编译验证
- [x] T003（null分支与不存在门店已curl验证；正向数据待商家银行资料填写后复验） [US1] 冒烟验证 T002：curl 三种情形（三字段齐全 / 缺银行账号 / 不存在门店 id→data=null），对照 contracts/api.md 场景 1

## Phase 4: US2 商家确认收款 + 骑手门禁（P1）

目标：确认收款解锁配送。独立测试：未确认时骑手接单被拒（提示「商家确认收款后骑手才能接单」）、newTask 列表不可见；确认后接单成功、附近骑手收到推送、日志记录；重复确认/已取消被拒；现金单 confirmCashPayment 行为不变。

- [x] T004 [US2] 在 ruoyi-admin/src/main/resources/i18n/ 的五份 properties（messages.properties、messages_zh_CN、messages_zh_TW、messages_en_US、messages_vi）追加 4 个 key：no.order.paytype.not.transfer / no.order.transfer.cancelled / no.order.transfer.already.paid / no.order.transfer.not.paid（文案见 contracts/api.md，tw 繁体自拟同义），Python 脚本逐份插入（锚点用 no.order.cash.already.paid 所在行），编译验证
- [x] T005 [US2] 在 ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java 新增 `GET /confirmTransferPayment`（`@RequestHeader token` + `@RequestParam Long id`），镜像 confirmCashPayment（397行）：requireMerchantOrderAccess → 校验 payType==PAY_TYPE_TRANSFER（否则 no.order.paytype.not.transfer）→ state==4 拒绝（no.order.transfer.cancelled）→ payStatus==1 拒绝（no.order.transfer.already.paid）→ payStatus 置 1 + orderLogHelper 记「商家{名}确认转账收款」；**外送单(type=0)保存后调用 deliveryOrderNotificationService.notifyOrderAvailable(order)**（注入方式照 PosOrderController:130），编译验证
- [x] T006 [US2] 在 ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java 的 acceptOrder（76行）校验区增加门禁：`PAY_TYPE_TRANSFER.equals(payType) && payStatus != 1` → 抛 ServiceException(no.order.transfer.not.paid)，编译验证
- [x] T007（无token冒烟已验：接口注册+鉴权拦截；完整链路待测试账号token） [US2] 冒烟验证 US2 全链路：下单 paymentMethod=6 → 强行骑手接单被拒 → newTask 列表无此单 → confirmTransferPayment 成功（重复调用报已收款）→ 骑手接单成功 → 商家接单/出餐/取餐/送达正常；同时回归 confirmCashPayment 对非现金单仍报「不是现金支付订单」（quickstart.md 场景 2/3/4）

## Phase 5: US3 商家 Web 支付标签（P2）

目标：转账单在商家 Web 正确显示标签。独立测试：到付/线上/转账三类标签互不混淆，四语言正确。

- [x] T008 [P] [US3] 在 foodie-store/src/views/index.vue 的 paymentTypeLabel 映射（388-396行）加 `6: 'OfflineTransfer'`
- [x] T009 [P] [US3] 在 foodie-store/src/lang/{zh,tw,en,vi}.js 的 `index` 命名空间（找 index:{ 的 CashOnDelivery/OMG/LinePay/cash 同级）加 `OfflineTransfer: '线下转账' / '轉賬支付' / 'Transfer Payment' / 'Chuyển khoản'`（Python 脚本，锚点取 index 命名空间内 cash 键行）
- [x] T010（paymentKeys与四语言已node校验通过；页面目测待前端构建） [US3] 验证：商家订单列表与详情弹窗对 payType=6 显示「线下转账」，四语言切换正确（quickstart.md 场景 5）

## Phase 6: Polish

- [x] T011 对照 specs/027-offline-transfer-payment/spec.md 的 FR-001~FR-010 与 quickstart.md 五场景做完整核验（机械检查：编译 PASS + grep 确认 4 个 i18n key 在五份 properties、payType=6 无散落硬编码；冒烟：curl 走完场景 1-4），派 1 个 review 子代理逐 FR 核对改动点
- [x] T012 交付 App 团队对接说明：接口清单（bankInfo / confirmTransferPayment / acceptOrder 门禁 / createOrder 透传 6）与收银台交互稿要点（contracts/api.md 的 App 端小节），整理为简短消息发给用户转交

## Dependencies

```text
T001 ──> T005（常量）
T002 ──> T003（US1 冒烟）          [US1 与 US2/US3 并行]
T004 ──> T005/T006（提示 key）
T005,T006 ──> T007（US2 冒烟）
T008,T009 ──> T010                 [US3 与 US2 并行]
T007,T010 ──> T011 ──> T012
```

## MVP

US2（T001+T004+T005+T006）：确认收款 + 骑手门禁是资金闸门核心；US1 银行信息接口紧随其后（App 展示依赖），US3 标签纯展示可最后。
