MatchMaster/server/laf-cloud/functions/goldMiner/LEGACY-PAYMENT.md

80 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 黄金矿工旧 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)。