spec.md 13 KB

Feature Specification: OMG 支付接入(订单在线支付)

Feature Branch: (待创建,暂未建分支/未提交)

Created: 2026-07-29

Status: Draft —— 关键决策已定(D1–D6,见「已定决策」)

Input: 接入台湾 OMG(歐買尬 / 金流引擎 FunPoint)AIO 幕前支付(https://developers.omg.com.tw/payment/aio/api/01_order.html)用于订单在线支付。替代已就绪未启用的蓝新 NewebPay(011,不再启用);OMG 独立实现、不复用蓝新代码,仅复用平台共享订单/推送链路。


集成背景(已确认,来自 OMG AIO 文档)

  • 网关端点
    • 测试:https://payment-stage.funpoint.com.tw/Cashier/AioCheckOut/V5
    • 生产:https://payment.funpoint.com.tw/Cashier/AioCheckOut/V5
    • POSTapplication/x-www-form-urlencoded
  • 签名模型(关键差异):OMG 用 CheckMacValue(SHA256,EncryptType=1 单字段签名;这与蓝新 NewebPay 的 TradeInfo(AES) + TradeSha(SHA256) 双层模型不同。结论:需独立的 OMG 签名工具,不能复用 NewebPayEncryptUtil。具体算法(参数排序、URI 编码、HashKey/HashIV 包夹、SHA256 大写)在文档附錄 07_appendices / 范例 06_check-value-sample,留待 plan/research 落地。
  • 支持的支付方式ChoosePayment):Credit(信用卡)、ApplePayATMCVS(超商代码)、BarcodeATMAFTEEALL
    • ⚠️ 文档未把「LINE Pay」列为独立 ChoosePayment —— 用户提及 LINE Pay,需确认其接入方式(可能走 Credit 子支付或独立通道),见 D4。
  • 幕前流程:商户组参 + 计算 CheckMacValue → POST 到 AioCheckOut/V5 → 消费者在 OMG 收银台支付 → OMG 服务端 POST 回 ReturnURL(商户须回 1|OK)→ 可选 OrderResultURL 客户端跳转(仅即时支付方式支持)。
  • 非即时支付(ATM/超商/BarcodeATM):OMG 生成虚帐/缴费码 → 回调 PaymentInfoURL(服务端 POST)+ 可选 ClientRedirectURL(客户端展示)。
  • 退款05_refund API;订单查询04_order_query付款结果通知03_payment_notify
  • 发票InvoiceMark 必须 N —— 电子发票仍走本项目 ezPay 链路(010/014),与支付解耦。
  • 约束:不可用 iframe;iOS 下不可另开新窗口;MerchantTradeNo 全平台唯一;ReturnURLOrderResultURL 不可相同。

与本项目现有支付的关系

  • 本功能把 OMG 启用为订单在线支付。蓝新 NewebPay(011)代码就绪未启用;VNPay/ZaloPay 已废弃(见 project-deprecated-code 记忆)。
  • 复用现有链路:订单状态流转入口(PosOrderShOprate/PosOrderQsOprate/UserOrderController/PosOrderController)、PayPush(iOS uni 云函数 msduser/msdrider/msdstore + PushEventpush_message)、以及 sendAcceptRiderPush(迁移契机,见 CLAUDE.md「当前在用的订单操作入口」)。
  • 凭证门店级:每门店独立 OMG 凭证(MerchantID/HashKey/HashIV),存于门店维度配置表 pos_store_omg
  • 不复用蓝新代码(用户硬约束):OMG 全部代码(工具类/客户端/实体/Service/Controller)与表(凭证/流水/退款)独立新建、零 newebpay 依赖,不复用蓝新的 pos_store_newebpay / pos_order_payment;仅复用平台共享基础设施(订单状态机、推送、订单日志)。

已定决策(D1–D6,2026-07-29 确认)

  • D1 — 支付方式范围:支持 OMG 全部支付方式(ChoosePayment=ALL:信用卡 Credit / Apple Pay / ATM / 超商 CVS / BarcodeATM / AFTEE)。
  • D2 — 与 NewebPay(011) 的关系OMG 替代蓝新金流,作为订单在线支付启用;NewebPay 不再启用。
  • D3 — 退款/取消本期范围,订单取消走 OMG 退款 API(05_refund)。
  • D4 — LINE Pay本期不做(文档未列为独立 ChoosePayment,后续再议)。
  • D5 — 覆盖订单范围本期仅餐饮订单;旅游·机票订单(015)后续衔接,不在本期。
  • D6 — 凭证粒度门店级(每门店独立 MerchantID / HashKey / HashIV,启用开关,同 011 模式)。

说明:OMG 文档可正常获取(与 015 的 iFlight 不同),无硬阻塞。决策已定,可直接进 /speckit-plan


User Scenarios & Testing (mandatory)

User Story 1 - 消费者在线支付订单(Priority: P1)

消费者下单后选择在线支付,选定方式(如信用卡/Apple Pay),跳转 OMG 收银台完成付款;付款成功后订单变为已支付并进入履约。

Why this priority:在线支付是订单交易闭环的核心,没有它订单无法在线收款。

Independent Test:从一笔待支付订单出发,能跳转 OMG、用测试卡完成支付,订单状态变为已支付。

Acceptance Scenarios:

  1. Given 一笔待支付订单,When 消费者发起支付并选择支付方式,Then 跳转 OMG 收银台且金额/订单号正确。
  2. Given 消费者在 OMG 完成付款,When OMG 回调平台,Then 订单核销为已支付,消费者看到支付成功。
  3. Given 消费者取消或关闭支付页未付款,When 超时,Then 订单保持未支付并可重试,不误判为已付。

User Story 2 - 支付回调核销与履约触发(Priority: P2)

OMG 服务端回调(ReturnURL)到达后,验签 + 幂等更新订单,并触发后续履约(状态流转、商家/骑手推送)。

Why this priority:支付成功必须可靠地驱动订单履约,否则「付了钱却没人接单」。

Independent Test:模拟 OMG 回调(合法/伪造/重复),合法回调能更新订单并触发推送,伪造被拒、重复不重复发货。

Acceptance Scenarios:

  1. Given OMG 合法回调到达,When 平台验签通过,Then 订单更新为已支付并回 1|OK,履约链路(含 sendAcceptRiderPush 推送)被触发。
  2. Given 同一订单的重复回调,When 再次到达,Then 幂等处理,不重复更新/不重复推送。
  3. Given 伪造或验签失败的回调,When 到达,Then 拒绝并记录,订单状态不变。

User Story 3 - 非即时支付(ATM / 超商)(Priority: P3)

消费者选择 ATM 转账或超商缴费时,平台展示 OMG 生成的虚帐/缴费码,消费者在期限内完成后由 OMG 回调核销。

Why this priority:扩大支付覆盖面,但非即时到账,可晚于信用卡 MVP。

Independent Test:选择 ATM/超商,能拿到虚帐/缴费码并展示;模拟付款完成回调能核销订单。

Acceptance Scenarios:

  1. Given 消费者选 ATM/超商,When OMG 生成虚帐/缴费码回调 PaymentInfoURLThen 平台展示付款信息与期限。
  2. Given 消费者在期限内完成付款,When OMG 回调 ReturnURLThen 订单核销为已支付并触发履约。
  3. Given 超过付款期限未付,When 逾期,Then 订单按规则失效/可重试。

User Story 4 - 订单取消与退款(Priority: P3)

订单取消(用户取消/商家取消/超时退款)时,通过 OMG 退款 API(05_refund)原路退款,并同步状态。

Why this priority:售后资金闭环,依赖 D3 是否本期。

Independent Test:对一笔已支付订单发起取消,能调用 OMG 退款并同步为已退款。

Acceptance Scenarios:

  1. Given 一笔已支付订单可退款,When 发起取消,Then 调 OMG 退款 API 并将订单标记为退款中/已退款。
  2. Given 退款失败,When OMG 返回失败,Then 记录原因并可重试,不误标已退款。

User Story 5 - 商家/平台配置 OMG 凭证(Priority: P2)

商家或平台在后台维护 OMG 凭证(MerchantID/HashKey/HashIV),支持测试/生产切换与启用开关。

Why this priority:支付前提是凭证可用,属 P2 基础设施。

Independent Test:在后台录入门店 OMG 凭证,能用于发起支付与验签。

Acceptance Scenarios:

  1. Given 已授权运营,When 录入门店 OMG 凭证并启用,Then 该门店订单可发起 OMG 支付。
  2. Given 未配置或未启用凭证的门店,When 尝试在线支付,Then 不展示/不可用在线支付(可降级货到付款)。

Edge Cases

  • 回调签名验证失败(伪造/篡改)—— 必须拒绝并记录。
  • 重复回调(网络重试)—— 按 MerchantTradeNo 幂等,不重复发货/推送。
  • 消费者支付页关闭/超时未付 —— 订单不误判,可重试或按规则失效。
  • 金额不一致(下单价 vs 支付价,如改了单/用了券)—— 以平台实际应收金额为准。
  • 回调与「用户取消」并发 —— 明确最终状态优先级,避免已付款却被取消。
  • 退款失败 / 部分退款 / 跨日退款。
  • 多门店凭证:A 门店凭证不可用于 B 门店订单。
  • 测试凭证误用到生产、或反之。

Requirements (mandatory)

Functional Requirements

  • FR-001:系统 MUST 支持消费者对未支付订单发起 OMG 幕前在线支付,跳转 OMG 收银台(金额、订单号、商品描述正确)。
  • FR-002:系统 MUST 支持 OMG 全部支付方式(ChoosePayment=ALL:信用卡 / Apple Pay / ATM / 超商 / BarcodeATM / AFTEE);LINE Pay 本期不做(D4)。
  • FR-003:系统 MUST 使用 OMG CheckMacValue(SHA256,EncryptType=1)对请求签名、对回调验签;签名工具独立于现有 NewebPay 工具。
  • FR-004:系统 MUST 在 OMG ReturnURL 回调时验签 + 按 MerchantTradeNo 幂等更新订单为已支付,并回 1|OK
  • FR-005:系统 MUST 在支付成功后触发现有订单履约链路(状态流转 + iOS 推送 + sendAcceptRiderPush)。
  • FR-006:系统 MUST 支持非即时支付(ATM/超商)的虚帐/缴费码生成、展示与期限管理(PaymentInfoURL 回调)。
  • FR-007:系统 MUST 支持订单取消时经 OMG 退款 API(05_refund)退款并同步状态(本期范围,D3)。
  • FR-008:系统 MUST 支持门店级 OMG 凭证配置(MerchantID/HashKey/HashIV,启用开关,测试/生产切换)。
  • FR-009:本期功能覆盖范围仅餐饮订单的在线支付;旅游·机票订单(015)后续衔接,不在本期(D5)。
  • FR-010:系统 MUST 持久化支付流水(MerchantTradeNo、金额、方式、时间、回调原始报文、退款记录),支持对账。
  • FR-011:系统 MUST 在 InvoiceMark=N 下与 ezPay 电子发票链路解耦,支付不干涉开票。
  • FR-012:OMG 替代蓝新 NewebPay(011) 作为订单在线支付启用,NewebPay 不再启用(D2)。
  • FR-013:系统 MUST NOT 复用或依赖任何蓝新 NewebPay 代码/表;OMG 凭证、流水、退款表与工具类/Controller 全部独立新建,仅可使用平台共享基础设施(订单状态机、推送、订单日志)。

Key Entities (include if feature involves data)

  • 门店 OMG 凭证(StoreOmgCredential):门店关联、MerchantID、HashKey、HashIV、环境(测试/生产)、启用开关。
  • 支付请求(OmgPaymentRequest)MerchantTradeNo(幂等键)、订单、金额、ChoosePayment、ReturnURL/NotifyURL、生成的 CheckMacValue
  • 支付流水(OrderPayment)MerchantTradeNo、关联订单、金额、支付方式、状态(待付/已付/失败/退款)、OMG 交易号、回调原始报文、时间。
  • 退款记录(OmgRefund):关联支付流水、退款金额、退款状态、OMG 回应、时间。

Success Criteria (mandatory)

Measurable Outcomes

  • SC-001:消费者从下单到完成在线支付(即时方式)端到端时长满足体验预期(如主流在数分钟内)。
  • SC-002:支付回调核销成功率达标;重复回调 100% 幂等,不重复发货/推送。
  • SC-003:支付成功后订单履约(状态流转 + 推送)100% 被触发,无「已付款未接单」。
  • SC-004:伪造/验签失败的回调 100% 被拒绝,资金安全零失误。
  • SC-005:退款(若本期)在目标时长内完成且订单状态与资金同步。

Assumptions

  • 平台已/将向 OMG 申请商店号与 HashKey/HashIV(测试 + 生产)。
  • 复用现有订单状态机、PayPush 推送链路、用户体系,不为此功能重建。
  • OMG AIO CheckMacValue 算法与 ECPay 同源(业界标准),具体实现留待 plan/research。
  • 电子发票仍走 ezPay(010/014),与 OMG 支付解耦(InvoiceMark=N)。
  • 测试先用 payment-stage.funpoint.com.tw 测试端点与测试凭证,生产环境与凭证后续切换。
  • 凭证签名等敏感操作在服务端完成,HashKey/HashIV 不下发前端。
  • 在线支付与现有「货到付款」并存,由门店配置决定是否提供在线支付。