# Quickstart: OMG AIO 创建支付订单验证 ## Prerequisites 1. 使用 JDK 21:`C:\Users\qmj\.jdks\graalvm-jdk-21.0.7`。 2. 开发者已手动执行 `updatesql/sql.md` 中 `pos_order_omg_attempt` DDL。 3. 测试门店在可信 `pos_store_omg` 中录入并启用 OMG stage 凭证。 4. 准备该用户自己的单门店订单:`dd_id = parent_dd_id`、`pay_type='2'`、`pay_status=0`、`state IN (0,1,2)`、`amount>0`。 5. `omgpay.return-url` 是受控 HTTPS 地址,路径精确为 `/pay/omg/notify`。 ## Automated verification ```powershell $env:JAVA_HOME='C:\Users\qmj\.jdks\graalvm-jdk-21.0.7' $env:Path="$env:JAVA_HOME\bin;$env:Path" mvn -pl ruoyi-system -am -Dtest='OmgPaymentAttemptServiceTest,OmgIpnAuditServiceTest' -Dsurefire.failIfNoSpecifiedTests=false test mvn -pl ruoyi-admin -am -Dtest='OmgCheckMacSignerTest,OmgPaymentFormFactoryTest,OmgPaymentCreateServiceTest,OmgPaymentControllerTest,OmgNotifyFormParserTest,OmgNotifyRawBodyFilterTest,OmgPaymentNotifyServiceTest,OmgPaymentNotifyControllerTest' -Dsurefire.failIfNoSpecifiedTests=false test mvn -pl ruoyi-admin -am -DskipTests package ``` ## Create request ```powershell $headers = @{ token = '' } $body = @{ orderId = ''; paymentMethod = 'CREDIT' } | ConvertTo-Json $response = Invoke-RestMethod -Method Post ` -Uri 'https:///pay/omg/create' ` -Headers $headers -ContentType 'application/json' -Body $body $response.data ``` Expected: - `status=CREATED`。 - `gatewayUrl` 精确等于 stage AioCheckOut V5 地址。 - `CREDIT` 响应包含 `ChoosePayment=Credit`、`UnionPay=2`,且不包含 `IgnorePayment`。 - 将 `paymentMethod` 改为 `APPLE_PAY` 后,新响应包含 `ChoosePayment=ApplePay`,且不包含 `UnionPay` 或 `IgnorePayment`。 - 两种响应都不包含 `ChoosePayment=ALL`。 - `CheckMacValue` 是 64 位大写十六进制。 - 响应不含 HashKey 或 HashIV。 ## Current-page form POST 在客户端当前页面创建 `
`,action 设置为 `gatewayUrl`,逐一把 `formFields` 的键和值创建为 hidden input,然后调用 `form.submit()`。不要设置 iframe target,也不要 `window.open()`。 Expected: 分别提交 `CREDIT` 和 `APPLE_PAY` 表单时,浏览器直接进入对应 OMG stage 付款流程并显示正确金额;不得出现超商快付、AFTEE 或其他渠道选择项。Apple Pay 仍需门店已开通且设备环境支持。 ## Duplicate request 对同一 `orderId` 再调用创建接口。 Expected: - 返回 `PAYMENT_ATTEMPT_EXISTS`。 - 没有 `formFields`。 - 数据库没有第二条该 `dd_id` 的 `CREATED` 行。 - 不生成或返回新的 MerchantTradeNo。 ## Concurrent request 用两个 PowerShell 作业同时提交同一订单: ```powershell $uri = 'https:///pay/omg/create' $tokenValue = '' $json = (@{ orderId = '' } | ConvertTo-Json -Compress) $jobs = 1..2 | ForEach-Object { Start-Job -ScriptBlock { param($u, $t, $b) Invoke-RestMethod -Method Post -Uri $u -Headers @{ token = $t } ` -ContentType 'application/json' -Body $b } -ArgumentList $uri, $tokenValue, $json } $jobs | Wait-Job | Receive-Job $jobs | Remove-Job ``` Expected: 一个请求成功,一个请求返回 `PAYMENT_ATTEMPT_EXISTS`。手动查询: ```sql SELECT dd_id, COUNT(*) AS active_count FROM pos_order_omg_attempt WHERE active_dd_id = '' GROUP BY dd_id; ``` `active_count` 必须为 1。 ## Negative cases 分别验证无效 token、他人订单、多门店子订单、state=3/4、pay_status 非 0、amount<=0、pay_type 非 2、无启用凭证。每项都必须: - 返回国际化业务错误与稳定 status; - 不写新尝试; - 不泄露其他订单或门店凭证详情。 ## Log review 确认日志可按 orderId 定位创建开始、校验、成功或拒绝,异常路径含服务端堆栈。全文搜索不得出现: - 请求 token; - HashKey / HashIV 的值; - 完整 CheckMacValue; - 完整 `formFields` 或凭证对象序列化内容。 ## Callback expectation ## 付款结果回调重放 使用真实 OMG stage 回调日志中的完整 form-urlencoded 内容重放;不要自行删除空值字段或额外字段: ```powershell $body = '<从 ipn_log.ipn_log 或应用日志复制的完整回调内容>' Invoke-WebRequest -Method Post ` -Uri 'https://foodieapi.waimai-paotui.com/pay/omg/notify' ` -ContentType 'application/x-www-form-urlencoded' ` -Body $body ``` 预期: - 签名、商户、交易号和金额匹配时返回纯文本 `1|OK`。 - `RtnCode=1`(包括 `SimulatePaid=1`)后,尝试为 `PAID`、订单 `pay_status=1`,订单 `state/delivery_status` 不变。 - 验签通过且 `RtnCode!=1` 后,尝试为 `FAILED`、订单仍未付款,下一次 create 可生成新尝试。 - 相同通知重复重放仍返回 `1|OK`,不重复推进任何订单业务状态。 - 修改金额、商户号、检查码或删除任何实际字段后返回 `0|ERROR`,支付和订单事实不变。 - 每次请求都在 `ipn_log` 新增 `type=omg` 的完整原文,包括验签失败请求。 本阶段不验收查询、补单、取号、退款或推送;不得把旧 OMG 回调或旧查询结果作为新流程证据。