Feature Specification: 可配置支付方式(平台开关 × 商家选择 × 骑手闪送选择)
Feature Branch: 031-pay-method-config
Created: 2026-09-11
Status: Draft(设计决策已于 2026-09-09 对话定稿,本 spec 为落地成文)
Input: 平台能设置系统可用的支付方式(按"方式 × 维度"开关);商家能选择自己接受的支付方式;骑手能选择闪送收款方式;含银行卡列表化与 027 线下转账迁移。
背景与核心模型
支付方式目前在代码中为固定行为:用户下单传什么支付方式后端就接受什么(不校验该店是否可用,存在漏洞);闪送订单没有支付方式字段;线下转账的银行卡信息是 027 实现的固定三字段。
本功能建立三层闸门模型,某支付方式对一笔订单可用 = 平台开关(方式 × 维度) ∩ 收款方选择 ∩ 就绪度(支付凭证或启用银行卡)。
- 维度两个,独立开关、可交叉:商家餐饮单维度(用户向商家付款的订单)、骑手闪送维度(用户直接付骑手的闪送订单)。例如"线下转账"可以商家侧关、骑手侧开。
- 资金流不变:闪送款项用户直接付骑手(现金 / LINE Pay 好友转账 / 银行转账),平台不经手。
- 支付方式取值域(与现有系统一致):1=到付、2=信用卡(OMG)、3=LINE Pay、4=现金(仅商家建单场景)、5=Apple Pay(OMG)、6=线下转账。
User Scenarios & Testing (mandatory)
User Story 1 - 平台管理支付方式开关 (Priority: P1)
平台管理员在管理后台的"支付方式设置"页,看到每个支付方式在两个维度(商家餐饮单 / 骑手闪送)下的开关,可独立打开或关闭。所有开关默认开启,即平台不做任何设置时系统行为与现状完全一致。
Why this priority: 三层闸门的第一层,是整个功能的基础;没有平台开关,商家/骑手的选择无从谈起。
Independent Test: 平台关闭"线下转账-商家维度"后,所有商家的餐饮下单流程中该方式立即不可用;重新打开后恢复。仅实现本故事即拥有"平台一键下线某支付方式"的最小价值。
Acceptance Scenarios:
- Given 所有开关默认开启,When 管理员进入支付方式设置页,Then 每个支付方式展示两个维度开关且均为开启,现状不受影响。
- Given 管理员关闭"信用卡-商家维度",When 用户在该平台任意商家下单,Then 结算页不再出现信用卡支付(信用卡与 Apple Pay 同组联动)。
- Given 管理员关闭"LINE Pay-骑手闪送维度",When 闪送下单选择支付方式,Then LINE Pay 不出现,但商家餐饮单维度不受影响。
- Given 管理员误关某方式,When 重新开启,Then 该方式立即恢复可见可用,无需重启或发版。
User Story 2 - 商家选择接受的支付方式 (Priority: P1)
商家在商家端 PC(foodie-store)的支付设置页,勾选自己接受的支付方式,并可管理收款银行卡(增删、启用某一张)。选择在商家主账号级生效,连锁门店共享同一配置(与 027 银行信息语义一致)。商家从未设置(或清空)时默认接受全部启用方式,存量商家行为零变化。
Why this priority: 三层闸门的第二层,是商家侧的核心诉求;与平台开关同为基础能力。
Independent Test: 商家取消勾选"LINE Pay"后,用户在该商家下单时看不到 LINE Pay;仅实现本故事(配合 US1)即完成餐饮单维度闭环。
Acceptance Scenarios:
- Given 商家从未设置支付方式,When 用户在该商家下单,Then 可用支付方式 = 平台开启的方式 ∩ 就绪度(与现状一致,零变化)。
- Given 商家只勾选"到付、现金",When 用户下单,Then 结算页仅展示到付、现金(仍受平台开关约束)。
- Given 连锁商家主账号修改支付方式选择,When 任意门店视角查看,Then 配置一致(主账号级共享)。
- Given 平台后续关闭了商家已勾选的某方式,When 用户下单,Then 该方式仍不可见(平台开关优先)。
User Story 3 - 下单校验堵漏洞 (Priority: P1)
用户提交订单时,后端必须校验所传支付方式可用(∈ 平台开启 ∩ 商家接受 ∩ 就绪度),不可用时返回国际化错误提示。现状 createOrder 完全不校验,本故事补上。校验逻辑 MUST 收敛为一个独立的统一校验方法,所有下单入口在下单时调用该方法,禁止各入口自行实现校验(单一事实来源,闸门规则改动只改一处)。
Why this priority: 安全校验,防止绕过界面直接提交被禁方式(当前漏洞);统一方法保证餐饮单、商家建单、闪送单的闸门行为永远一致。
Independent Test: 用接口直接提交一个平台已关闭的支付方式创建订单,返回明确错误;前端展示被禁时后端同样拦截,双保险;各下单入口走的是同一个校验方法。
Acceptance Scenarios:
- Given "线下转账"平台已关或商家未选,When 客户端绕过界面直接以线下转账提交订单,Then 下单被拒绝并返回所使用语言的提示文案。
- Given 商家未配置 OMG 支付凭证(就绪度不满足),When 用户选择信用卡,Then 该方式不可用。
- Given 老版本 App 不感知新逻辑,When 其提交已下线的支付方式,Then 后端拒绝并返回国际化提示(不静默失败)。
User Story 4 - 骑手选择闪送收款方式与抢单过滤 (Priority: P2)
骑手设置自己接受的闪送收款方式;未设置时默认接受平台开放的全部方式(避免新单无人可见)。用户闪送下单时选择支付方式,订单记录该方式;骑手抢单列表只展示其接受该支付方式的订单。
Why this priority: 闪送资金直达骑手,骑手必须能控制自己接受哪种收款;依赖平台开关(US1)先行。
Independent Test: 骑手只选"现金",下单选"银行转账"的闪送订单不出现在其抢单列表;改选后恢复可见。
Acceptance Scenarios:
- Given 骑手未设置闪送收款方式,When 任意支付方式的闪送订单产生,Then 该订单对骑手可见(默认=平台开放全部)。
- Given 骑手仅接受"现金、LINE Pay",When 用户创建"银行转账"闪送订单,Then 该订单不进入此骑手的抢单列表,但进入接受银行转账的其他骑手列表。
- Given 用户闪送下单,When 选择支付方式,Then 可选项 = 平台闪送维度开启 ∩ 就绪度,选定后随订单固定记录。
- Given 平台关闭骑手维度某方式,When 用户闪送下单,Then 该方式不可选,骑手端相应配置项同步失效。
User Story 5 - 银行卡列表化与 027 迁移 (Priority: P2)
收款银行卡从 027 的固定三字段改为列表管理:商家与骑手通用,可维护多张卡、同时仅一张启用(启用新卡自动停旧卡);付款方(用户)仅看到收款方当前启用的卡。027 存量数据自动迁移为一张启用卡;现有银行信息查询接口保留、结构不变,改为读取启用卡并套用闸门,老客户端无感。
Why this priority: "就绪度"闸门与线下转账体验的基础;迁移保证存量商家转账展示不回退。
Independent Test: 迁移后原有填写过银行信息的商家,用户下单线下转账仍能看到转账信息(来自新列表的启用卡);商家新增第二张卡并启用,付款方看到新卡。
Acceptance Scenarios:
- Given 存量商家已有 027 银行三字段,When 升级后用户以线下转账下单,Then 转账信息正常展示(迁移自动完成,无人工操作)。
- Given 商家/骑手添加第二张银行卡并设为启用,When 付款方查看转账信息,Then 仅看到新启用的卡,旧卡自动停用。
- Given 收款方没有任何启用的卡,When 用户下单,Then 线下转账方式不满足就绪度、不可选。
- Given 027 原"三字段齐全才显示转账信息"规则,When 迁移后,Then 改为"存在启用卡即显示"。
User Story 6 - 骑手确认收款 (Priority: P3)
骑手送达并实际收到款后,在闪送订单上操作"确认收款";订单记录收款状态(未收→已收)与操作日志。确认收款不阻塞送达与完成流程(转账到账有时差,平台不经手资金不设硬闸门)。
Why this priority: 资金闭环的运营记录,优先级最低——不影响交易主流程。
Independent Test: 骑手送达后未确认收款,订单仍可正常完成;事后确认,状态与日志正确记录。
Acceptance Scenarios:
- Given 闪送订单已送达,When 骑手确认收款,Then 收款状态变为已收并记录操作人与时间。
- Given 骑手未确认收款,When 订单流转送达/完成,Then 流程不受任何阻塞,收款状态保持未收。
Edge Cases
- 平台关闭某方式时,已存在但未支付的旧订单如何处理?→ 下单校验(US3)在创建时点生效;已创建订单不追溯改动。
- 商家清空全部支付方式勾选?→ 视同未设置,回落为"全部启用"(与 NULL 语义一致,防止商家把自己锁死)。
- 骑手维度关闭平台某方式后,历史闪送订单的支付方式字段?→ 记录的是下单时点值,不追溯。
- 信用卡与 Apple Pay:作为同一组(OMG 渠道)一个开关,开关与商家勾选均同开同关。
- 现金(4)特殊:不纳入商家勾选管控(仅商家建单场景使用),平台开关也不覆盖它。
- 到付(1)纳入管控且默认开。
- 老客户端(不感知新字段/新逻辑):一律由后端校验拒绝并返回国际化提示;银行信息查询接口保持原结构兼容。
Requirements (mandatory)
Functional Requirements
- FR-001: 系统 MUST 提供平台级支付方式开关,按"支付方式 × 维度(商家餐饮单 / 骑手闪送)"独立控制,默认全部开启。
- FR-002: 某支付方式对一笔订单可用 MUST 满足三层闸门:平台开关开启 ∩ 收款方接受 ∩ 就绪度满足(线上渠道有凭证、线下转账有启用银行卡)。
- FR-003: 商家 MUST 能在商家端选择接受的支付方式,选择在主账号级生效(连锁共享);未设置或清空时 MUST 等同接受全部(存量行为零变化)。
- FR-004: 系统 MUST 在创建订单时校验支付方式满足闸门,不满足时以用户所用语言返回明确错误提示(兼容老 App,不静默失败)。该校验 MUST 封装为单一独立方法,作为唯一校验入口;所有下单路径(用户餐饮下单、商家建单、闪送下单)MUST 在下单时统一调用该方法,MUST NOT 在各入口重复实现校验逻辑。
- FR-005: 信用卡与 Apple Pay MUST 作为同一组方式展示与控制(同开同关)。
- FR-006: 到付(1)MUST 纳入平台开关管控且默认开;现金(4)MUST 不纳入本管控(仅商家建单场景)。
- FR-007: 用户闪送下单时 MUST 选择支付方式且被订单记录;可选项 = 闪送维度平台开关 ∩ 就绪度。
- FR-008: 骑手 MUST 能设置接受的闪送收款方式;未设置时 MUST 默认接受平台开放的全部方式。
- FR-009: 骑手抢单列表 MUST 只展示支付方式为其接受的闪送订单。
- FR-010: 商家与骑手 MUST 能维护收款银行卡列表(多卡、同时仅一张启用、启用新卡自动停旧卡);付款方仅能看到收款方启用的卡。
- FR-011: 027 存量银行三字段 MUST 自动迁移为一张启用卡,迁移不需人工操作;银行信息查询接口 MUST 保持原有结构返回启用卡并套用闸门。
- FR-012: 线下转账就绪度 MUST 由"三字段齐全"改为"存在启用银行卡"。
- FR-013: 骑手 MUST 能对闪送订单执行确认收款(未收→已收 + 操作日志);该操作 MUST NOT 阻塞送达/完成流程。
- FR-014: 平台端开关设置页 MUST 提供四语言界面;商家端 PC 设置页(方式勾选 + 银行卡管理)MUST 实现多语言。
- FR-015: 平台 MUST NOT 提供逐门店覆盖商家支付方式的能力(本期明确不做)。
- FR-016: 商家 App / 骑手 App 端界面本期 MUST NOT 开发(后端出接口,由 App 团队按 027 FR-010 模式另行接入)。
- FR-017: 所有数据库变更 MUST 记入
updatesql/sql.md 由开发者统一手动执行(项目惯例)。
Key Entities (include if feature involves data)
- 支付方式: 业务枚举(到付、信用卡、Apple Pay、LINE Pay、现金、线下转账),信用卡与 Apple Pay 同组。
- 平台支付方式开关: 方式 × 维度(商家餐饮单/骑手闪送)× 启停状态。
- 商家支付方式选择: 商家主账号 → 接受的方式集合;空=全部。
- 骑手闪送收款方式选择: 骑手 → 接受的方式集合;空=平台开放全部。
- 收款银行卡: 归属商家或骑手,多卡、单卡启用;含开户行(台湾银行清单)、账号、户名与审计信息。
- 闪送订单支付信息: 订单记录的支付方式与收款状态(未收/已收)。
Success Criteria (mandatory)
Measurable Outcomes
- SC-001: 平台切换任一开关后,该方式在全端的可见性立即(下一次查询)生效,无延迟、无重启。
- SC-002: 绕过界面直接提交被禁支付方式的下单请求,100% 被后端拒绝且返回所用语言的提示。
- SC-003: 升级上线后,未做任何设置的存量商家与骑手,其订单支付行为与升级前完全一致(零回归)。
- SC-004: 027 迁移完成后,全部存量有银行信息的商家线下转账展示不回退(迁移覆盖率 100%)。
- SC-005: 闪送抢单列表中不再出现骑手不接受支付方式的订单(过滤准确率 100%)。
- SC-006: 平台设置页与商家端设置页全部文案覆盖四语言(vi/zh/tw/en),无硬编码。
Assumptions
- 骑手"LINE Pay 收款信息"为文本字段(LINE ID/收款说明),骑手接单后展示给用户——具体展示位置与样式可在实现阶段调整。
- 银行卡暂不含"分行"栏位;如后续需要按增量补充。
- 普通付款用户(会员)不维护收款银行卡;收款方仅商家与骑手。
- 闪送资金流维持"用户直接付骑手、平台不经手"现状,本期不引入平台代收。
- 商家 App / 骑手 App 前端页面不在本期范围(仅后端接口);OMG / LINE Pay 凭证维持现有门店级平台管理模式。
- 骑手确认收款为运营记录性质,不与资金到账做系统核对。