80 lines
7.9 KiB
Markdown
80 lines
7.9 KiB
Markdown
# 黄金矿工旧 iOS 客服支付接入
|
||
|
||
本分支基于现有 `wx/KeFuInfo`、`wx/checkIos` 和提供的 `order3.html` 扩展。未改动游戏前端仓库,未部署或调用真实支付。下载目录中的原文件未修改,可部署副本为 [web/order3.html](web/order3.html)。
|
||
|
||
## 客户端和客服入口
|
||
|
||
1. 游戏客户端先以登录态请求 `POST /goldMiner/index`:
|
||
|
||
```json
|
||
{
|
||
"action": "create_order",
|
||
"channel": "legacy_ios",
|
||
"uid": "玩家ID",
|
||
"token": "登录token",
|
||
"itemid": "当期配置的gold_miner商品ID",
|
||
"createRequestId": "本次购买请求ID"
|
||
}
|
||
```
|
||
|
||
成功外壳为 `{code:1,data,msg}`,data 包含 `outTradeNo, periodId, priceFen, productId, quantity:1, channel, expiresAt, sessionFrom`。价格、用户、期和数量均来自服务端。重复请求复用该玩家该期的订单;原生和客服渠道不允许同一期分别开单。过期或已关闭订单不能继续付款。
|
||
|
||
2. 保存返回的 `outTradeNo`,将 `data.sessionFrom` **原样**传入微信 `openCustomerServiceConversation` 的 `sessionFrom`。不能继续沿用旧客户端自己生成订单号、拼接价格的黄金矿工路径。票据有效期最多 15 分钟且不超过活动截止;过期后重新预下单取得新票据,不生成另一笔订单。
|
||
3. 现有客服网关将 `FromUserName`、`SessionFrom` 转发到 `wx/KeFuInfo`。黄金矿工要求票据签名、归属 openid、商品和环境全部匹配;无需给未知网关新增验签参数。此票据授权向订单本人发送链接,**不是付款凭据**。普通商品保留现有流程。
|
||
4. 支付链接参数携带该订单专用 `time` 票据,替代黄金矿工依赖全局 `iosTime` 的做法;页面把它原样提交 `wx/checkIos`。也支持游戏内以 `uid/token/outTradeNo` 调用该接口。返回严格布尔值 `true/false`。
|
||
5. `checkIos` 只校验和关联订单。`order` 在预下单时就是主记录,`iosOrder` 保留完整兼容副本;主记录存在时不覆盖支付状态,不丢失 goldMiner 快照。主记录缺失时只从已验证的服务端副本恢复。同一操作可重试,付款早于转单也不会回退订单。
|
||
6. 支付成功后,用已有 `wx/getPayInfo`、`wx/iosgetPayInfo` 或 `wx/getOrderReward` 携带 `uid/token/outTradeNo` 查询。这些接口可触发商户主动查单。返回 `rewardDelivery=goldMiner.claim` 时进入活动领奖协议;禁止套用普通金币商品的通用补发。
|
||
|
||
客户端预下单调用是必需接入点,本提交提供后端和页面,未修改 MatchMaster 游戏代码。现有客服网关需原样转发 `SessionFrom`;仍需微信实际会话联调确认网关没有截断或改写票据。
|
||
|
||
## 支付确认与恢复
|
||
|
||
- `/goldMiner/merchantNotify` 是新的 POST 商户通知地址。验证微信支付 RSA 签名和 5 分钟时间窗,AES-256-GCM 解密,再核对 appid、mchid、openid、订单号、CNY 金额、JSAPI 类型和支付时间。
|
||
- 优先读取 `ctx.request.rawBody` 或 `ctx.rawBody`。部署必须检查 Laf 网关实际传入的原始体;缺少时只对 `JSON.stringify(ctx.body)` 的字节尝试验签,若序列化与原消息不同则失败,不绕过验签。主动查单负责恢复遗漏支付。不能仅以接口可访问判定通知已接通。
|
||
- 微信商户查单响应同样需要签名验证。只有可信成功结果能写 `confirmedAt/transactionId/paidAt`;先持久化支付事实,再授予活动权益。通知只在持久化成功后应答,权益失败交给查单、登录或任务重试。
|
||
- 登录最多查 2 笔待处理订单,任务每轮最多查 5 笔;30 秒订单租约避免重复并发请求,失败退避从 10 秒到最多 5 分钟。网络超时和验签失败保留订单。接口的 `PAYMENT_PENDING` 不能被当作金币补发授权。
|
||
- 未支付旧期订单经可信查单后关闭;关单与付款竞态会重新查单,成功付款走原活动履约。签名确认延迟时,有达标奖励补发原期,无奖励顺延紧接下一期;重复回调和查询不会重复发资格。冲突保留 `manual_review`,不自动顺延第三期。
|
||
- `goldMiner.paymentChannel` 标识 `legacy_ios/native`,历史缺失该字段的活动订单按原生处理。新增商户快照、预支付状态、租约、重试和支付确认字段均放在原有 `goldMiner` 对象内,无新增通关事件集合。主订单保留完整原有活动快照。
|
||
|
||
## 环境配置和发布
|
||
|
||
| 环境变量 | 内容 |
|
||
| --- | --- |
|
||
| `PAYMENT_APP_ENV` | `test` 或 `production`,与所在后端和订单一致 |
|
||
| `GOLD_MINER_LEGACY_ENABLED` | 仅字符串 `true` 开放旧渠道预下单和发支付链接,默认关闭;关闭后仍处理已付款订单 |
|
||
| `WX_MCH_ID` | 微信支付商户号 |
|
||
| `WX_MINIGAME_APP_ID` | 支付 appid,必须与玩家 openid 和商户绑定关系相符 |
|
||
| `WX_MCH_CERT_SERIAL_NO` | 商户 API 证书序列号,用于请求签名 |
|
||
| `WX_PAY_PRIVATE_KEY_BUCKET` | 私有存储桶,内含 `apiclient_key.pem`,沿用现有商户签名配置 |
|
||
| `GOLD_MINER_WECHATPAY_PUBLIC_KEYS` | JSON 对象:微信支付公钥 ID/平台证书序列号 → 对应 PEM 公钥或证书;与商户私钥不同,支持并存轮换 |
|
||
| `GOLD_MINER_WECHATPAY_API_V3_KEY` | 32 字节 API v3 密钥,用于通知解密 |
|
||
| `GOLD_MINER_ORDER_TICKET_SECRET` | 随机生成至少 32 字节的服务端票据密钥,测试/正式独立;轮换会使未过期链接失效 |
|
||
| `GOLD_MINER_MERCHANT_NOTIFY_URL` | 当前环境的 HTTPS `/goldMiner/merchantNotify` 完整 URL |
|
||
| `GOLD_MINER_PAY_PAGE_URL` | 实际部署的 HTTPS `order3.html` 地址,不带 hash |
|
||
| `GOLD_MINER_CHECK_IOS_URL` | 当前环境的 HTTPS `/wx/checkIos` 完整 URL |
|
||
|
||
依赖已有 `cloud.shared` 中的 `wxaccess_token` 和微信有效客服会话;失效时接口返回 `CUSTOMER_SERVICE_UNAVAILABLE`,复用原订单重试,不递归开单。环境密钥不得放进客户端、Postman 或 Git。
|
||
|
||
先按 [总部署清单](README.md#8-管理配置与部署) 发布依赖和入口,再运行 `setup_indexes`(包含商户流水唯一索引和查单索引)、绑定每分钟任务、部署支付页,最后启用开关。除 goldMiner 目录外,本次需更新:
|
||
|
||
- `login.ts`
|
||
- `wx/KeFuInfo.ts`、`wx/checkIos.ts`
|
||
- `wx/getPayInfo.ts`、`wx/iosgetPayInfo.ts`、`wx/getOrderReward.ts`
|
||
|
||
如果测试服尚未部署上一版黄金矿工,还必须同步总部署清单中的 `userLevel`、原生下单、原生回调等文件。现有 YAML 方法未变;专属通知新增 YAML 必须一起发布。
|
||
|
||
支付页优先使用后端签入链接的 `checkUrl`,普通旧链接未提供时保留原生产地址。必须部署本仓库副本后才可用测试服链接;Downloads 原页硬编码生产地址。支付页只接受转单接口明确返回 true,并等待 WeixinJSBridge 就绪。小游戏支付参数继续由后端签名。
|
||
|
||
`PAYMENT_APP_ENV=test` 只隔离应用和订单,不是微信商户免扣款沙箱;新商户请求仍到微信正式 API。上线前需要实际微信账号验证 appid/openid、客服转发、支付目录/域名、CORS、证书和通知原始体配置,仓库测试无法替代这些部署条件。测试及正式订单的通知地址各自保存在订单快照,不走原生测试回调转发。
|
||
|
||
## 验证
|
||
|
||
```powershell
|
||
node --test laf-cloud/functions/goldMiner/tests/*.test.mjs
|
||
node --test --test-name-pattern='gold miner' laf-cloud/tests/login-wucai-state.test.mjs
|
||
```
|
||
|
||
本地使用模拟数据库、RSA 签名响应和加密通知,未真实支付或发送客服消息。覆盖鉴权/票据、价格、重复预下单、转单快照、付款先于转单、通知验签/解密、查询租约、超时重试、期末关单竞态、跨期履约、支付页及 Postman 链路。Postman 共 42 个请求,新第 07 组测试旧渠道。
|
||
|
||
参考协议:[微信 JSAPI 下单](https://pay.wechatpay.cn/doc/v3/merchant/4012791870)、[微信支付通知](https://pay.wechatpay.cn/doc/v3/merchant/4012791861)、[Laf 请求上下文](https://doc.laf.run/zh/cloud-function/request.html)。
|