# Quickstart: OMG（歐買尬/FunPoint）AIO 支付接入

**Feature**: specs/016-omg-payment/spec.md
**Date**: 2026-07-29

端到端验证 OMG 支付可用性的可运行场景。实现细节见 `tasks.md`（待生成），接口字段见 `contracts/api.md`，表结构见 `data-model.md`。

---

## 前置准备

1. **DB**：执行 `updatesql/sql.md` 中 2026-07-29 的三张表 DDL（`pos_store_omg` / `pos_order_omg_payment` / `pos_order_omg_refund`）。
2. **配置**（`application.yml`）填入测试值：
   - `omg.base-url=https://payment-stage.funpoint.com.tw`
   - `omg.return-url` / `omg.payment-info-url` 指向**公网可达**的本服务地址（本地用 ngrok/frp 穿透到 8082）。
3. **凭证**：在盘合测试后台申请测试商店号，拿到 `MerchantID` / `HashKey` / `HashIV`。
4. **签名自测**：运行 `OmgCheckMacValue.main`，应 PASS（ECPay 官方 MD5 向量锁定编码流水线）；OMG SHA256 需使用实际商户凭证联调验签。

---

## 场景 A：门店录入并验证 OMG 凭证（US5）

1. 平台后台对一个门店「发起申请」→「录入凭证」(`MerchantID/HashKey/HashIV`)。
2. 系统调 OMG `QueryTradeInfo/V5` 查虚构单号探测金钥。
3. **预期**：金钥正确 → 提示「凭证验证通过，已开通」，`pos_store_omg.omg_status=2, is_enabled=1`；金钥错误 → 拒绝、状态不变、`last_verify_result` 记失败原因。

---

## 场景 B：消费者在线支付（信用卡，US1 + US2）

1. 消费者下一笔餐饮订单（`pos_order.pay_status=0`）。
2. 调 `POST /pay/omg/create?orderid=...` → 返回 form 字段（`gatewayUrl` + `MerchantID/MerchantTradeNo/.../CheckMacValue`）。
3. 前端 Form Post 到 OMG 收银台 → 用文档附录**测试卡**完成付款。
4. OMG 服务端 POST 回 `/pay/omg/notify`。
5. **预期**：
   - `/pay/omg/notify` 验签 CheckMacValue 通过、`RtnCode=1`、`SimulatePaid=0` → 回 `1|OK`；
   - `pos_order_omg_payment.pay_status=1`、`trade_no` 写入、`pay_type=Credit`；
   - `pos_order.pay_status=1`（state 不变）、订单日志记录、用户/商家/骑手收到推送（含 `sendAcceptRiderPush`）。

---

## 场景 C：回调健壮性（US2 边界）

1. **重复回调**：对同一 `trade_no` 再发一次 notify → 不重复更新订单、不重复推送，仍回 `1|OK`。
2. **伪造回调**：篡改金额或 CheckMacValue → 验签失败、拒绝、订单状态不变、记日志。
3. **金额不符**：`TradeAmt` ≠ 订单 amount → 拒绝核销、记日志。
4. **测试模拟**：`SimulatePaid=1` → 不核销发货、记日志。

---

## 场景 D：支付方式范围（P0）

1. 创建新 OMG 支付表单。
2. 核对 `ChoosePayment=Credit`、`UnionPay=2`，且两字段都已参加 CheckMacValue。
3. 核对不存在 `ClientRedirectURL`、`ExpireDate`、`StoreExpireDate`、`BarcodeATMExpireDate`。
4. 打开 stage 收银台，确认只显示信用卡与 Apple Pay，不显示银联、ATM、CVS、BarcodeATM 或 AFTEE。

---

## 场景 E：订单取消退款（US4，仅信用卡）

1. 对一笔已支付信用卡订单发起取消。
2. 系统调 `/CreditDetail/DoAction`（Action 按状态，默认 `R` 退刷）→ 写 `pos_order_omg_refund`。
3. **预期**：成功 → `pos_order_omg_payment.pay_status=3(已退款)`、`pos_order.pay_status=2`、`pos_order_omg_refund.rtn_code=1`；失败 → 记 `rtn_msg` 可重试、不误标已退款。
4. ⚠️ **stage 环境 `DoAction` 不可用**，退款须在正式环境做小额验证或 mock 测试。

---

## 完成判据

- 场景 A/B 全绿；C 的伪造/重复/金额不符/模拟均被正确拦截；D 的收银台只显示信用卡与 Apple Pay；E 的信用卡退款状态与资金同步。
- 全程 OMG 代码无任何 `newebpay` 依赖（grep 验证）。
