quickstart.md 5.1 KB

Quickstart: OMG AIO 创建支付订单验证

Prerequisites

  1. 使用 JDK 21:C:\Users\qmj\.jdks\graalvm-jdk-21.0.7
  2. 开发者已手动执行 updatesql/sql.mdpos_order_omg_attempt DDL。
  3. 测试门店在可信 pos_store_omg 中录入并启用 OMG stage 凭证。
  4. 准备该用户自己的单门店订单:dd_id = parent_dd_idpay_type='2'pay_status=0state IN (0,1,2)amount>0
  5. omgpay.return-url 是受控 HTTPS 地址,路径精确为 /pay/omg/notify

Automated verification

$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

$headers = @{ token = '<USER_TOKEN>' }
$body = @{ orderId = '<SINGLE_STORE_DD_ID>'; paymentMethod = 'CREDIT' } | ConvertTo-Json
$response = Invoke-RestMethod -Method Post `
  -Uri 'https://<API_HOST>/pay/omg/create' `
  -Headers $headers -ContentType 'application/json' -Body $body
$response.data

Expected:

  • status=CREATED
  • gatewayUrl 精确等于 stage AioCheckOut V5 地址。
  • CREDIT 响应包含 ChoosePayment=CreditUnionPay=2,且不包含 IgnorePayment
  • paymentMethod 改为 APPLE_PAY 后,新响应包含 ChoosePayment=ApplePay,且不包含 UnionPayIgnorePayment
  • 两种响应都不包含 ChoosePayment=ALL
  • CheckMacValue 是 64 位大写十六进制。
  • 响应不含 HashKey 或 HashIV。

Current-page form POST

在客户端当前页面创建 <form method="post">,action 设置为 gatewayUrl,逐一把 formFields 的键和值创建为 hidden input,然后调用 form.submit()。不要设置 iframe target,也不要 window.open()

Expected: 分别提交 CREDITAPPLE_PAY 表单时,浏览器直接进入对应 OMG stage 付款流程并显示正确金额;不得出现超商快付、AFTEE 或其他渠道选择项。Apple Pay 仍需门店已开通且设备环境支持。

Duplicate request

对同一 orderId 再调用创建接口。

Expected:

  • 返回 PAYMENT_ATTEMPT_EXISTS
  • 没有 formFields
  • 数据库没有第二条该 dd_idCREATED 行。
  • 不生成或返回新的 MerchantTradeNo。

Concurrent request

用两个 PowerShell 作业同时提交同一订单:

$uri = 'https://<API_HOST>/pay/omg/create'
$tokenValue = '<USER_TOKEN>'
$json = (@{ orderId = '<SINGLE_STORE_DD_ID>' } | 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。手动查询:

SELECT dd_id, COUNT(*) AS active_count
FROM pos_order_omg_attempt
WHERE active_dd_id = '<SINGLE_STORE_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 内容重放;不要自行删除空值字段或额外字段:

$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 回调或旧查询结果作为新流程证据。