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

**日期**：2026-09-03 | **状态**：定稿（对话讨论 + 代码核实，无未决项）

## 决策清单

### D1 支付方式值 = 6
- **决策**：`PosOrder.payType = "6"` 表示線下轉賬。
- **依据**：现有值域 1=外送到付、2=信用卡(OMG)、3=LINE Pay、4=现金、5=Apple Pay（specs/023 已定）；6 为空闲新值。常量加 `OrderLifecycleService.PAY_TYPE_TRANSFER`（现有 `PAY_TYPE_CASH="4"` 同文件）。
- **备选**：复用 4（现金）加标记位——拒绝，语义混淆且破坏现金确认逻辑。

### D2 收款账户查询接口放门店控制器，商家级数据
- **决策**：`GET /chanting/store/bankInfo?id={storeId}`（匿名），路径：门店 → `pos_store.user_id`（商家主账号）→ `info_user` 三字段（bankAccountName/bankName/bankAccountNo，026 已加）；任一为空返回 `data=null`。
- **依据**：审核资料银行字段挂在商家主账号上，连锁店共用；App 拿 null 隐藏「線下支付」选项（spec FR-001）。
- **备选**：挂到订单接口按 orderId 查——拒绝，选项在选择支付方式时（下单前）就需要，只有 storeId 可用。

### D3 下单链路零改动
- **决策**：`UserOrderController.createOrder` 的 `paymentMethod` 直接透传为 `payType`（第259行），无白名单校验；6 天然可下单（state=0、payStatus=0、collectPayment 不设）。
- **依据**：代码核实；与线上支付单未付态完全同构。

### D4 确认收款镜像现金版 + 挂骑手通知钩子
- **决策**：新增 `GET /system/orderShOprate/confirmTransferPayment`，结构照抄 `confirmCashPayment`（PosOrderShOprateController:397）：校验 payType=6、state≠4（已取消拒绝）、payStatus 0→1、`orderLogHelper` 记「商家XX确认转账收款」；**外送单(type=0)确认后调用 `deliveryOrderNotificationService.notifyOrderAvailable(order)`** 通知附近骑手。
- **依据**：`notifyOrderAvailable` = "支付完成且仍待骑手接单时通知附近骑手"，OMG 支付成功后正是这样调（OmgPaymentNotifyService:189）；转账单确认收款 = 它的"支付完成"时刻，不挂钩子则订单进骑手池但无人被通知。
- **备选**：复用 confirmCashPayment 放宽校验到 4 和 6——拒绝，错误提示与日志语义会混（现金/转账），App 端也不好区分埋点。

### D5 骑手可见性：零改动（天然满足）
- **决策**：骑手抢单列表（`orderList` tab=newTask）现有查询已含 `eq(PosOrder::getPayStatus, 1L)`（PosOrderQsOprateController:347），payStatus=0 的转账单自动不可见。
- **依据**：代码核实；这也是线上未支付单不进骑手池的同一机制。
- **推送排除**：同样天然满足——骑手新单推送只由"支付完成"钩子触发（OMG/LINE 回调），下单时不推。

### D6 骑手接单门禁：防绕过的显式校验
- **决策**：`PosOrderQsOprateController.acceptOrder` 增加校验：`payType=6 && payStatus≠1` → 拒绝，提示 key `no.order.transfer.not.paid`（「商家确认收款后骑手才能接单」，五份 properties）。
- **依据**：列表过滤挡不住直接调接口（App 抢单页刷新时差、越权调用）；spec FR-004 要求接口级拒绝。
- **备选**：不加（信任列表过滤）——拒绝，spec 明确要求接口拒绝且成本一行。

### D7 后端国际化资源：五份 properties
- **决策**：新 key 加到 `ruoyi-admin/src/main/resources/i18n/` 下 messages.properties（默认，内容为 vi）、messages_zh_CN、messages_zh_TW、messages_en_US、messages_vi 全部五份。
- **依据**：现金单的 key（no.order.paytype.not.cash 等）在五份文件中均有先例，直接对齐。
- **新增 key**：`no.order.paytype.not.transfer`（非转账单）、`no.order.transfer.cancelled`（已取消不可确认）、`no.order.transfer.already.paid`（已收款）、`no.order.transfer.not.paid`（骑手门禁提示）。

### D8 商家 Web 标签
- **决策**：foodie-store `index.vue` 的 `paymentTypeLabel` 映射加 `6: 'OfflineTransfer'`；i18n key 加 `index` 命名空间四语言（zh 线下转账 / tw 轉賬支付 / en Transfer Payment / vi Chuyển khoản）。列表列与详情弹窗共用该函数，一处改两处生效。
- **依据**：现有 1-4 映射同型（index.vue:388-396）。

### D9 明确不做
- App 端 UI（客户收银台、商家 App 确认按钮、骑手 App）：不在工作区，交付接口+交互说明。
- Web 商家端「确认收款」按钮：本期只做接口，按钮后续按需。
- 运费代收/结算、凭证上传、转账单超时取消：纯线下，spec 已排除。
- 零 DDL：复用 payType/payStatus 现有字段。

## 风险与注意

- **confirmTransferPayment 需注入 DeliveryOrderNotificationService**：PosOrderShOprateController 目前未注入（PosOrderController 有），照 PosOrderController:130 的方式补。
- **notifyOrderAvailable 的时机**：其内部有事务同步（afterCommit）；确认收款方法不加 @Transactional（对齐现金版），保存后直接调用即可。
- **自取/堂食转账单**：完成时现有 completeOrder 自动置 payStatus=1（state 2→3 时），无需特殊处理；确认收款按钮同样可用。
