Files
frontend-app/docs/douyin-pay-integration.md
T

82 lines
5.2 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.
# 抖音 App 支付接入与打包
2026-09-09,基于 develop / b350f1c 修复。
## 本次故障
普通 uni-app App 中调用 uni.requestPayment({ provider: "toutiao" }) 无法找到该通道,
会报 requestPayment:fail service not found。配置 Scheme 白名单不会注册支付 SDK。
后端 prepayId 不能由前端直接当成 pay_token 拼接收银台 URL。
## 统一调用
订单页、订单补付、充值使用 utils/douyin-pay.js 的 appDypayFun(payment),传入
/order/payment 等接口的 data 对象(含 orderNum、douyin),不要传整个 HTTP response。
utils/payUtils.js 保留 douyinPayFun(douyin, orderId, orderNum) 兼容入口,
也委托给同一原生调用与查单逻辑。
适配器支持 douyin 的旧扁平字段以及新 orderInfo 对象/JSON,
最终传给 SDK 的字段为 appid、partnerid、prepayid、package、noncestr、timestamp、sign。
签名仍由服务端产生,前端不自行签名或改写签名字段。
uni_modules/tb-douyin-pay 是本地源码 UTS 插件,不是 uni.requestPayment provider;
无需将它添加成 manifest 的 toutiao 支付通道。
Android 原生依赖由 utssdk/app-android/config.json 声明;
iOS SDK 位于 utssdk/app-ios/Frameworks/DypaySDK.xcframework。
需要将整个插件目录纳入版本控制,不能只提交 utils 和页面。
## 打包与验收
1. 在支持插件配置的 HBuilderX(插件声明最低 4.36)打开 frontend-app。
2. 安装对应 UTS 编译与 App 打包扩展,Android 打包需能解析插件 Maven 依赖。
3. 制作包含本插件的自定义调试基座或完整 Android/iOS 安装包,使用平台登记的包名和签名。
4. 安装新的原生包。单独更新 WGT 或服务器部署无法给旧安装包加入 SDK。
5. 从真实订单调用支付;测试页也可粘贴 /order/payment 成功返回 JSON。
6. 覆盖成功、取消、网络失败、重复点击、回前台、冷启动恢复场景。
仅服务端 /payment/queryResult 返回 state=2 才提示支付成功。
SDK 成功或跳回 App 本身不作为到账依据。结果未知时保留待查订单并阻止重复发起。
人工续付接口返回 paid 时仍走原查单接口,以便补同步业务订单;closed 只解除本地待查记录,不标记成功。
测试页不再提供模拟 pay_token 链接,不在页面日志输出完整签名。
H5/小程序不会调用原生 App SDK。
## 验证边界
2026-09-09 实测:14 项自动化测试通过,6 个 Vue 文件的 SFC/脚本/模板检查通过。
HBuilderX 5.24 执行 App appResource 导出成功,产物位于 unpackage/resources,
包含 tb-douyin-pay 的 Android 原生源码/配置和 iOS SDK 源码/框架。
编译有既有 CSS Autoprefixer 注释警告,不影响此次资源导出。
这次没有构建、安装完整 APK/IPA,也没有进行真机交易。
npm run test:douyin 覆盖参数适配、旧调用入口、服务端确认、重复支付及异常恢复。
这些自动化测试使用模拟 SDK/接口,不会产生真实交易,不能替代完整原生包与真机验收。
## 关闭 App 后继续未支付订单(2026-09-09 补丁)
旧实现把保存的订单一直当作“结果未知”,只查单不允许重新打开收银台。
现在冷启动仍然只查单;用户再次点击抖音支付时,调用
`POST /payment/douyin/resume`(表单参数 `orderNum`),由当前登录身份校验订单归属。
- 服务端确认 `NOTPAY` 且本地订单仍可支付、未过期:复用原支付订单号、金额、到期时间,
获取新的 SDK 签名参数;用户确认“继续上一笔支付”后打开收银台。
- 返回 `paid` 或 `closed`:不调 SDK,只清理该账户对应的本地待查记录。
- `USERPAYING`、未知渠道状态、查单失败、续付接口不可用:仍保留记录,不创建新支付。
- 取消弹窗、账号切换、重复点击:不会发起第二笔支付。
- 只保存原订单号,不缓存签名;兼容修复前已保存的订单号,覆盖购物及充值。
接口返回 `data = { state, orderNum, payment }`,其中 state 为 unpaid/paid/closed/pending,
只有 unpaid 才含 payment(与原 /order/payment 的 SDK 参数结构一致)。
续付接口不创建支付订单、不重新扣抵扣券,也不会自动取消、退款或更改订单到期时间。
**发布顺序:先部署后端续付接口,再更新 App。只更新 App 无法解除旧后端的锁定。**
本次无 SQL、无新增密钥配置。现有原生插件未变化,但仍需使用已包含 SDK 的安装包。
本补丁涉及 App 的 `utils/douyin-pay.js`、`tests/douyin-integration.test.cjs` 及本文档;
后端涉及 `DouyinPaymentResumeService`、`DouyinPayResumeDto`、`DouyinPayService`、
`QueryOrderResult`、`PayController` 和 `DouyinPaymentResumeServiceTest`。
本地验证:`npm run test:douyin` 的 22 项测试通过;后端
`mvn -o -pl hashmall-frontend -am test -Dtest=DouyinPaymentResumeServiceTest,DouyinPayInfoDtoTest,DouyinAppPaySignerTest -Dsurefire.failIfNoSpecifiedTests=false`
编译成功,所选 10 项测试通过(含新增 7 项续付测试)。
提交目标:后端 hashmall/hashmall 的 dev_douyin_tmp,App 为 charles/frontend-app 的 dev_codex。
尚未部署或进行真机实付;以上测试均使用模拟渠道,不产生真实交易。