miaoguo_virtual_payment.md 4.5 KB

秒过小程序虚拟支付接入

本模块与原有 src/api/pay 并行,旧支付接口保持不变。新模块继续使用 ProductPayInfoMiaoguoWXUsersMiaoguoCoupon,订单状态、金额单位及秒过 PayType=7/9 的业务含义与旧代码兼容。

环境配置

服务端启动前配置以下环境变量:

WX_VIRTUAL_PAY_OFFER_ID=微信虚拟支付OfferId
WX_VIRTUAL_PAY_APP_KEY=正式环境AppKey
WX_VIRTUAL_PAY_SANDBOX_APP_KEY=沙箱环境AppKey
WX_VIRTUAL_PAY_ENV=1
WX_MIAOGUO_MESSAGE_TOKEN=秒过小程序消息推送Token
WX_VIRTUAL_PAY_PRODUCTS_JSON='[
  {"productId":"后台正式商品ID","payType":7,"price":19900,"goodsPrice":36500,"env":0},
  {"productId":"后台正式试用商品ID","payType":9,"price":100,"env":0},
  {"productId":"后台沙箱商品ID","payType":7,"price":19900,"goodsPrice":36500,"env":1},
  {"productId":"后台沙箱试用商品ID","payType":9,"price":100,"env":1}
]'
  • price 是用户实际支付金额,单位为分;goodsPrice 是小程序后台已发布商品原价。两者不同时,服务端会把 price 作为 activitySellingPrice 签名。
  • 省略 goodsPrice 时默认与 price 相同。
  • WX_VIRTUAL_PAY_PRODUCTS_JSON 可以省略。没有匹配配置时,服务端按“内部产品编号_实际金额(元)”生成微信道具 ID。秒过当前对应关系为:1 元使用 166_1、199 元使用 166_199、258 元使用 166_258。以后其他小程序也采用相同规则,例如内部产品编号 205 的 199 元道具为 205_199
  • 秒过服务端会校验业务金额:试用 PayType=9 只允许 1 元,购买 PayType=7 通常只允许 199 元或 258 元。服务端通过 OpenID 查到的真实 UserID < 8UserID=3089 可用 1 元测试购买;不能依赖客户端自行传入的 UserID,以免普通用户篡改金额后低价开通权益。
  • 如果微信后台商品原价与实际支付价不同,需要在配置表中加入对应售价,服务端才能正确传入 activitySellingPrice
  • WX_VIRTUAL_PAY_ENV=1 为沙箱,0 为正式环境。iOS 没有沙箱,服务端会强制使用正式环境商品和正式 AppKey。
  • AppKey 只放在服务端环境变量中,不能写入小程序代码或接口响应。

新接口

接口 用途
GET /api/MiaoguoVirtualPayLogin500 换取登录态、创建兼容订单并返回虚拟支付签名
GET /api/MiaoguoVirtualPayOrderStatus500 主动查询微信订单并在漏回调时补发货
POST /api/MiaoguoVirtualPayNotify500 接收 xpay_goods_deliver_notify 并发放权益

微信公众平台的秒过小程序消息推送地址应指向:

https://www.kylx365.com/api/MiaoguoVirtualPayNotify500

当前代码按明文 XML/JSON 消息接收;Token 必须与 WX_MIAOGUO_MESSAGE_TOKEN 一致。 同一路径的 GET 请求已实现公众平台首次保存地址时的签名校验与 echostr 回显。 若公众平台启用了安全模式(AES 加密消息),需先切换为明文模式,或后续增加消息解密。

客户端与业务处理

  • 小程序新增 main.virtualPayMoney,原 main.payMoney 保留。
  • Android、鸿蒙和 Windows 在测试环境使用沙箱;iOS 自动使用 Apple 支付正式环境。
  • iOS 要求 iOS 15 及以上、微信 8.0.68 及以上,单笔最低 1 元,并受中国大陆 App Store 账号条件限制。
  • 微信重复推送不会重复增加会员有效期:订单和用户更新在同一数据库事务中完成,订单行加锁并以 Status=1 判定幂等。
  • 支付消息漏推时,小程序会轮询查单;查到状态为已支付后,服务端发放权益并调用 /xpay/notify_provide_goods

本次没有实现退款、iOS 退款询问事件和投诉处理。

本地测试支付完成逻辑

支付完成后的核心逻辑由发货通知和主动查单共同调用 fulfillOrder。该函数支持在测试中注入假数据库,因此以下命令不会连接或修改真实数据库,也不会调用微信接口:

npm run test:virtual-pay:completion

测试覆盖:正常购买完成、测试用户 1 元购买、1 元试用、重复发货幂等、金额不一致回滚,以及模拟微信 xpay_goods_deliver_notify 发货通知。完整虚拟支付测试可运行:

npm run test:virtual-pay

只有最终的微信客户端拉起支付、微信真实扣款和公网消息推送需要做少量线上联调;会员更新、优惠券消耗、订单完成与异常回滚都可先在本地自动测试。