# 服务号网页 1 元支付
本模块用于 `public/wcs/pay.html` 的微信公众号网页支付,与原有 `src/api/pay`
并行。原 `ProductPayLoginWeb`、`ProductPayNotifyWebchatService` 等接口继续保留,网页入口
改用 `src/api/wechatServicePay` 下的新接口。
该页面在微信内置浏览器中使用普通 JSAPI 支付。Android 和 iOS 使用相同服务端接口,
不使用小程序虚拟支付 `requestVirtualPayment`。
## 兼容数据规则
- 金额由服务端固定为 100 分,客户端不能指定价格。
- `ProductPayInfo.ProductID=167`。
- `PayType=8`,`BuyType=131`,订单初始 `Status=0`。
- 支付成功后 `Status=1`,同时写入 `PayEndTime`、`XMLPay`、
`ProductServiceTime` 和服务号 `UserID`。
- `WechatServiceWXUsers` 写入 `IsProbation=1` 和 `ProbationPayTime`。
- 如果服务号用户的 UnionID 已关联 `MiaoguoWXUsers`,秒过有效期更新为支付时间后 16 天。
- 微信重复通知或“通知与主动查单同时到达”不会重复发放权益,完成逻辑使用数据库事务、
行锁和 `Status=1` 幂等判断。
## 新接口
| 接口 | 方法 | 用途 |
| --- | --- | --- |
| `/api/MiaoguoWechatServicePayLogin500` | POST | OAuth code 换 OpenID、固定 1 元统一下单、返回 JSAPI 参数 |
| `/api/MiaoguoWechatServicePayOrderStatus500` | POST | 主动向微信查单,必要时补发权益 |
| `/api/MiaoguoWechatServicePayNotify500` | POST XML | 微信 APIv2 支付结果通知 |
下单响应、查单响应和支付成功通知均校验 APIv2 签名、AppID 和商户号;完成订单前还会
校验 OpenID、交易单号与 100 分金额。微信通知地址默认是:
```text
https://www.kylx365.com/api/MiaoguoWechatServicePayNotify500
```
如部署域名变化,可配置:
```bash
WX_WECHAT_SERVICE_PAY_NOTIFY_URL=https://域名/api/MiaoguoWechatServicePayNotify500
WX_WECHAT_SERVICE_PAY_TIMEOUT_MS=10000
```
微信商户平台 APIv2 密钥仍读取现有 `config.wx.payapisecret`,服务号 AppID、AppSecret 和
商户号也沿用现有配置,因此数据库及部署配置与旧模块兼容。
## 支付完成确认
网页不会再把微信前端 `getBrandWCPayRequest:ok` 当作最终成功。它会把服务端生成的
`TradeNo` 提交到新查单接口,只有服务端向微信确认 `trade_state=SUCCESS` 且事务完成后
才跳转成功页。支付按钮在整个流程中防重复点击;如果微信已受理但查单暂时失败,页面会
保持禁用并提醒不要重复支付。
本地自动测试不会访问微信或修改真实数据库:
```bash
npm run test:wechat-service-pay
```
测试包含固定服务端金额、APIv2 签名/XML、伪造通知拦截、事务完成、重复通知幂等、
金额不一致回滚、主动查单补完成,以及网页支付后确认逻辑。