支付服务 Runbook(微信 Native / 支付宝网站支付)¶
权威产品契约见 membership-agent-sales-guide.md。 范围:会员方案支付(微信 V3 Native 扫码 + 支付宝电脑/手机网站收银台);不含当面付扫码、日账单对账。
1. 本地联调(一分钱)¶
- 将商户证书放到
src/backend/cert/(已 gitignore),例如: apiclient_key.pem/pub_key.pem(微信)alipayPriveKey_RSA2.txt/alipayPublicKey_RSA2.txt(支付宝,密钥模式)- 在
src/backend/.env配置(对照.env.example): PAYMENT_ENABLED=truePAYMENT_TEST_AMOUNT_FEN=1(联调强制 0.01 元)WECHAT_*/ALIPAY_*与回调 URL- 微信商户平台「Native 支付回调」填:
https://<公网域名>/wepayapi/notify与WECHAT_NOTIFY_URL保持一致(后端wepay_router)。 - 支付宝异步通知填:
https://<公网域名>/api/payment/notify/alipay(或ALIPAY_NOTIFY_URL)。 - 支付宝同步回跳:
PAYMENT_RETURN_URL填前端落地页(如https://tuxianai.com/account?tab=ledger充值记录)。 不要把带?的前端地址直接当作支付宝return_url——官方禁止自定义 query, 会出现「付款成功,3 秒后自动返回商户」却永不跳转。 后端会按ALIPAY_NOTIFY_URL推导https://<公网域名>/api/payment/return传给支付宝, 再 302 到PAYMENT_RETURN_URL。 - 下单后前端应轮询
GET /api/billing/orders/{id},或调用POST /api/billing/orders/{id}/sync-pay(回调丢失时的标准兜底)。 - 上线前必须将
PAYMENT_TEST_AMOUNT_FEN=0;APP_ENV=production且该项 >0 时启动失败。
1.1 支付宝加签方式:密钥模式(本仓库唯一支持)¶
开放平台「开发设置 → 接口加签方式」须选 密钥(普遍适用),不要选「证书」。
| 开放平台操作 | 本地文件 / 配置 |
|---|---|
| 生成/上传「应用公钥」后得到「支付宝公钥」 | cert/alipayPublicKey_RSA2.txt(支付宝公钥,非应用公钥) |
| 应用私钥(仅本地保存,勿上传) | cert/alipayPriveKey_RSA2.txt |
| 应用 AppID | ALIPAY_APP_ID |
文件可为 PEM 全文,或仅 Base64 正文(启动时自动补 BEGIN/END)。后端用 RSA2:app_private_key_string + alipay_public_key_string,不使用应用公钥证书 / 支付宝根证书。
2. 证书与镜像¶
| 规则 | 说明 |
|---|---|
| 禁止进 Git | src/backend/cert/*(除 .gitkeep) |
| 禁止进镜像 | .dockerignore 已排除 src/backend/cert/** |
| 本地加载 | WECHAT_*_PATH / ALIPAY_*_PATH 相对 src/backend/ |
| 内联备选 | 也可把 PEM 全文写入 Secret / .env(勿提交) |
PAYMENT_ENABLED=true 时应用启动会校验:至少微信或支付宝凭证齐全,且存在回调 URL。
3. ACK Secret 挂载约定¶
3.1 推荐:Secret stringData 注入密钥(无文件)¶
deploy/ACK/secrets.example/backend-secrets.yaml 中预留支付相关键;make ack-secrets / create-secrets.ps1 可从 src/backend/.env 同步:
PAYMENT_ENABLED/PAYMENT_NOTIFY_URL/PAYMENT_RETURN_URL/PAYMENT_ORDER_EXPIRE_MINUTESPAYMENT_TEST_AMOUNT_FEN(生产必须0)WECHAT_*/ALIPAY_*(含内联 PEM 或 PATH)
若使用 PATH,须同时挂载证书文件(见下)。
3.2 可选:文件型 Secret 挂载到 /app/src/backend/cert¶
kubectl -n harness-app create secret generic harness-payment-certs \
--from-file=apiclient_key.pem=./apiclient_key.pem \
--from-file=pub_key.pem=./pub_key.pem \
--from-file=alipayPriveKey_RSA2.txt=./alipayPriveKey_RSA2.txt \
--from-file=alipayPublicKey_RSA2.txt=./alipayPublicKey_RSA2.txt
在 backend Deployment 增加(示例,勿把明文写进仓库):
volumeMounts:
- name: payment-certs
mountPath: /app/src/backend/cert
readOnly: true
volumes:
- name: payment-certs
secret:
secretName: harness-payment-certs
并保证 env 中:
WECHAT_MCH_PRIVATE_KEY_PATH=cert/apiclient_key.pem
WECHAT_PUBLIC_KEY_PATH=cert/pub_key.pem
ALIPAY_PRIVATE_KEY_PATH=cert/alipayPriveKey_RSA2.txt
ALIPAY_PUBLIC_KEY_PATH=cert/alipayPublicKey_RSA2.txt
4. 回调排查¶
| 现象 | 排查 |
|---|---|
| 通道反复通知 | 验签失败或履约失败返回 FAIL;查 backend 日志字段 order_no / transaction_id / error |
| 用户已付本地未开通 | 调 POST .../sync-pay;核对金额与 PAYMENT_TEST_AMOUNT_FEN |
| 订单变 cancelled | PAYMENT_ORDER_EXPIRE_MINUTES(默认 30)惰性关单;可重新下单 |
| Mock 不可用 | PAYMENT_ENABLED=true 时禁止 mock;开发期置 false |
支付宝跳转报 insufficient-isv-permissions |
不是代码签名错误。开放平台 AppID 未签约/未添加「电脑网站支付」或「手机网站支付」能力,或状态非「生效」。见下方 §4.1 |
| 付款成功显示 3 秒回商户但不跳转 | return_url 带了自定义 ? 参数(如 .../account?tab=ledger)。须走 /api/payment/return 中转;确认 ALIPAY_NOTIFY_URL 已配且 backend 已重启 |
日志关键字:支付回调、查单同步、支付退款、超时关单(无密钥原文)。
4.1 支付宝 insufficient-isv-permissions¶
本仓库默认调用 alipay.trade.page.pay(ALIPAY_PAY_MODE=page,产品码 FAST_INSTANT_TRADE_PAY)。
在 开放平台控制台 对 AppID ALIPAY_APP_ID 逐项确认:
- 应用已创建并上线/审核通过
- 「能力列表」中已添加 电脑网站支付,状态为 生效(没有则「添加能力」搜索添加)
- 商家中心「产品中心」对应产品已签约且生效
- 若只签约了手机网站支付:
.env设ALIPAY_PAY_MODE=wap后重启 backend - 当面付未签约时不要扫码;网站支付只能浏览器打开收银台
官方说明:ISV 权限不足
5. 退款¶
Admin:POST /api/admin/billing/orders/{id}/refund
通道侧使用订单实付作为微信 total,本次退款金额作为 refund;成功后 payment_records.status=refunded。