Files
junhong_cmp_fiber/docs/feature-034-agent-wallet-qr-recharge/代理钱包扫码充值接口对接说明.md
break 8fc667daee
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m7s
让代理充值复用现有网页支付能力
微信按当前 v2/v3 配置分别生成 MWEB/H5 链接,支付宝复用 C 端 WAP 链接,并让可用支付方式基于生效配置判断。

Constraint: 支付链接统一通过 qr_content 返回,由前端渲染二维码;按要求不运行测试

Rejected: 微信 Native 与支付宝当面付 | 会引入非当前商户配置所需的额外产品开通

Confidence: high

Scope-risk: moderate

Directive: 微信 H5/MWEB 二维码仅承诺系统相机或外部浏览器扫码链路

Tested: 相关 Go 包编译通过;gofmt 与 git diff --check 通过

Not-tested: 按用户要求未运行自动化测试及真实支付联调
2026-07-30 11:41:50 +08:00

328 lines
13 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.
# 代理钱包扫码充值实现与接口对接说明
> 面向:产品、前端和联调人员
> 范围:代理微信/支付宝桌面扫码自充、平台线下代充来源区分、支付状态轮询
> 接口细节:以 [`docs/admin-openapi.yaml`](../../admin-openapi.yaml) 为准,本文说明前端调用顺序、字段口径和页面状态。
## 一、先看这几个关键结论
1. **同一个创建接口有两条业务路径**:代理账号使用 `wechat|alipay` 在线自充;平台或超级管理员使用 `offline` 线下代充。
2. **前端必须使用 `recharge_source` 区分来源**`platform_offline` 是平台线下代充,`agent_online` 是代理在线自充;不要根据账号名称、备注或审批字段猜测。
3. **代理不能选择充值店铺**:在线充值的店铺和主钱包由登录上下文确定,请求不得发送 `shop_id`、支付凭证或备注。
4. **二维码由前端渲染**:后端在 `qr_content` 返回支付 HTTPS URL不返回二维码图片。
5. **网络重试不能创建新请求 ID**:同一次提交重试复用原 `request_id`;用户主动发起下一笔充值时生成新的 `request_id`
6. **支付和钱包到账是两个阶段**`status=2` 表示第三方已收款、钱包入账处理中;只有 `status=3` 才表示钱包到账完成。
7. **页面轮询只调用本地状态接口**:前端不得直接调用微信、支付宝查单,也不要反复调用创建接口查询状态。
8. **在线金额单位为分**:最低 `10000`100 元),最高 `100000000`100 万元);不要提交浮点元金额。
## 二、本次需求怎么实现
| 能力 | 后端实现 | 前端要做什么 |
| --- | --- | --- |
| 可用支付方式 | 根据当前有效支付配置返回真正可用的 `wechat``alipay` | 打开充值弹窗时先查询;只展示返回数组中的方式 |
| 代理在线自充 | 从登录账号取得当前店铺和主钱包,创建充值单、支付单并按配置生成微信 v3 H5/v2 MWEB 或支付宝 WAP 支付 URL | 只提交金额、支付方式和请求 ID`qr_content` 渲染二维码 |
| 平台线下代充 | 保留既有目标店铺、凭证和企业微信审批流程 | 平台页面继续提交 `offline` 请求并只读展示审批状态 |
| 充值来源 | 根据受控创建方式返回稳定来源枚举 | 列表、详情和支付状态统一展示 `recharge_source_name` |
| 支付确认 | 微信/支付宝回调确认第三方收款事实 | 前端无需调用回调接口 |
| 钱包入账 | Outbox/Worker 幂等增加代理主钱包余额 | `status=2` 展示“入账处理中”,`status=3` 展示“已到账” |
| 回调丢失恢复 | Worker 使用原支付单号主动查单并收敛状态 | 页面继续轮询本地状态,无需提供“重新查单”按钮 |
## 三、接口对接表
| 页面动作 | 接口 | 前端调用说明 |
| --- | --- | --- |
| 打开代理在线充值弹窗 | `GET /api/admin/agent-recharges/payment-methods` | 仅代理账号调用;返回支付方式和金额上下限 |
| 创建在线扫码充值 | `POST /api/admin/agent-recharges` | 代理只传 `amount + payment_method + request_id` |
| 创建平台线下代充 | `POST /api/admin/agent-recharges` | 平台/超级管理员传 `shop_id + amount + payment_method=offline + payment_voucher_key + remark` |
| 查询充值列表 | `GET /api/admin/agent-recharges` | 支持 `recharge_source=platform_offline|agent_online` 筛选 |
| 查询充值详情 | `GET /api/admin/agent-recharges/:id` | 使用返回的来源、充值状态和审批状态展示 |
| 轮询在线支付状态 | `GET /api/admin/agent-recharges/:id/payment-status` | 仅在线单使用;页面可见时每 3 秒调用,终态停止 |
| 支付回调 | 微信/支付宝既有回调地址 | 只由支付渠道调用,前端禁止调用 |
所有接口都使用 Bearer Token成功响应统一为
```json
{
"code": 0,
"msg": "success",
"data": {},
"timestamp": "2026-07-27T16:00:00+08:00"
}
```
前端应同时检查 HTTP 状态和响应体 `code`,失败时优先展示后端返回的 `msg`
## 四、代理在线扫码充值调用流程
### 4.1 查询可用支付方式
```http
GET /api/admin/agent-recharges/payment-methods
Authorization: Bearer {token}
```
响应示例:
```json
{
"code": 0,
"msg": "success",
"data": {
"methods": ["wechat", "alipay"],
"min_amount": 10000,
"max_amount": 100000000
},
"timestamp": "2026-07-27T16:00:00+08:00"
}
```
前端处理规则:
- `methods=[]`:隐藏或禁用提交按钮,提示“当前暂无可用在线支付方式”。
- 只显示返回的支付方式,不自行补充微信或支付宝。
- 金额校验直接使用返回的 `min_amount``max_amount`,提交值仍为整数分。
- 平台、超级管理员和企业账号不调用此接口。
### 4.2 创建在线充值单
```http
POST /api/admin/agent-recharges
Authorization: Bearer {token}
Content-Type: application/json
```
微信请求示例:
```json
{
"amount": 10000,
"payment_method": "wechat",
"request_id": "recharge-20260727-8f73d95d"
}
```
支付宝只需将 `payment_method` 改为 `alipay`
在线请求禁止发送:
- `shop_id`
- `payment_voucher_key`
- `remark`
- 商户号、应用 ID、密钥、支付配置 ID
成功响应示例:
```json
{
"code": 0,
"msg": "success",
"data": {
"recharge_id": 101,
"recharge_no": "ARCH20260727160000123456",
"payment_no": "PAY20260727160000987654",
"payment_method": "wechat",
"recharge_source": "agent_online",
"recharge_source_name": "代理在线自充",
"amount": 10000,
"qr_content": "https://pay.example.com/...",
"status": 1,
"status_name": "待支付"
},
"timestamp": "2026-07-27T16:00:00+08:00"
}
```
前端处理规则:
1.`qr_content` 原样交给二维码组件,不解析、不改写、不拼接。
2. 二维码页面保存 `recharge_id`,后续轮询使用该 ID不使用 `payment_no` 查询。
3. 同一次请求超时或网络断开时,重试必须复用原 `request_id`;后端会返回原充值单和原二维码内容。
4. 用户关闭弹窗后重新点击“立即充值”,视为新一笔主动提交,必须生成新的 `request_id`
5. 相同 `request_id` 改变金额或支付方式会返回冲突,前端不得自动覆盖原请求。
### 4.3 轮询支付和到账状态
```http
GET /api/admin/agent-recharges/101/payment-status
Authorization: Bearer {token}
```
响应示例:
```json
{
"code": 0,
"msg": "success",
"data": {
"recharge_id": 101,
"recharge_no": "ARCH20260727160000123456",
"recharge_source": "agent_online",
"recharge_source_name": "代理在线自充",
"status": 2,
"status_name": "已支付",
"payment_status": 1,
"payment_status_name": "已支付",
"paid_at": "2026-07-27 16:01:20",
"completed_at": null
},
"timestamp": "2026-07-27T16:01:21+08:00"
}
```
页面建议每 3 秒轮询一次,仅在二维码弹窗可见时执行。按以下状态展示:
| `status` | 含义 | 页面展示 | 是否继续轮询 |
| --- | --- | --- | --- |
| `1` | 待支付 | 等待用户扫码付款 | 是 |
| `2` | 已支付 | 支付成功,钱包入账处理中 | 是 |
| `3` | 已完成 | 充值成功,钱包已到账 | 否 |
| `4` | 已关闭 | 订单已关闭,请重新发起充值 | 否 |
| `5` | 已退款 | 已退款 | 否 |
| `6` | 已驳回 | 已驳回 | 否 |
`payment_status` 的值为:`0=待支付``1=已支付``2=已失败``3=已退款`。页面主流程优先根据充值 `status` 判断;`payment_status` 用于补充支付阶段文案。
进入 `status=3` 后,前端刷新钱包余额和充值列表。不要在 `status=2` 时提前增加页面余额。
## 五、平台线下代充调用流程
平台或超级管理员继续调用同一个创建接口:
```json
{
"shop_id": 20,
"amount": 50000,
"payment_method": "offline",
"payment_voucher_key": ["recharge-voucher/20260727/abc.png"],
"remark": "银行转账"
}
```
线下代充响应和后续列表/详情会返回:
```json
{
"recharge_source": "platform_offline",
"recharge_source_name": "平台线下代充",
"approval_provider": "wecom",
"approval_status": 1,
"approval_status_name": "审批中"
}
```
前端处理规则:
- 代理账号不得展示线下代充表单。
- 平台线下单展示凭证、备注和企微审批状态,不展示扫码二维码。
- 存在 `approval_instance_id``approval_provider=wecom` 时,只读展示审批进度,不显示旧的本地确认/驳回按钮。
- 在线充值的 `approval_instance_id``null`,不要显示企微审批区域。
- `/:id/payment-status` 是在线支付状态接口,线下代充详情使用 `GET /:id`,不要轮询支付状态接口。
## 六、列表和详情对接
列表请求示例:
```http
GET /api/admin/agent-recharges?page=1&page_size=20&recharge_source=agent_online&status=1
```
可用筛选参数:
| 参数 | 说明 |
| --- | --- |
| `page` | 页码,默认 1 |
| `page_size` | 每页条数,默认 20最大 100 |
| `shop_id` | 店铺 ID按既有数据权限生效 |
| `status` | 充值状态 `16` |
| `recharge_source` | `platform_offline``agent_online` |
| `start_date` | 开始日期,格式 `YYYY-MM-DD` |
| `end_date` | 结束日期,格式 `YYYY-MM-DD` |
列表成功响应的分页数据位于:
```json
{
"data": {
"items": [],
"total": 0,
"page": 1,
"size": 20
}
}
```
建议列表至少展示:充值单号、店铺、金额、`recharge_source_name`、支付方式、`status_name`、提交人和创建时间。
详情接口:
```http
GET /api/admin/agent-recharges/{id}
```
页面分支必须以 `recharge_source` 为准:
- `agent_online`:展示支付方式、第三方流水号、支付时间、完成时间;隐藏凭证和企微审批操作。
- `platform_offline`:展示支付凭证、备注、提交人和企微审批状态;隐藏二维码和在线轮询区域。
## 七、充值来源与状态字段
### 7.1 充值来源
| 字段值 | 中文名 | 创建人和路径 |
| --- | --- | --- |
| `platform_offline` | 平台线下代充 | 平台/超级管理员提交 `payment_method=offline` |
| `agent_online` | 代理在线自充 | 代理提交 `payment_method=wechat|alipay` |
前端展示中文时优先使用后端返回的 `recharge_source_name`,业务分支使用稳定枚举 `recharge_source`
### 7.2 充值状态
| 状态 | 名称 | 说明 |
| --- | --- | --- |
| `1` | 待支付 | 在线单等待扫码;线下单等待审批 |
| `2` | 已支付 | 第三方收款已确认,钱包可能仍在入账 |
| `3` | 已完成 | 钱包余额和唯一流水已提交 |
| `4` | 已关闭 | 在线支付关闭或预下单失败 |
| `5` | 已退款 | 充值已退款 |
| `6` | 已驳回 | 线下代充审批驳回 |
## 八、权限和错误处理
| 操作 | 平台/超级管理员 | 代理账号 | 企业账号 |
| --- | --- | --- | --- |
| 创建在线扫码充值 | 禁止 | 仅当前店铺主钱包 | 禁止 |
| 创建线下代充 | 允许 | 禁止 | 禁止 |
| 查询在线支付方式 | 禁止 | 允许 | 禁止 |
| 查询列表/详情 | 按既有数据范围 | 按店铺层级数据范围 | 禁止 |
| 查询在线支付状态 | 按既有数据范围 | 按店铺层级数据范围 | 禁止 |
前端不要根据错误文案判断资源是否存在。无权限或资源不可见时,后端可能统一返回“无权限操作该资源或资源不存在”。常见处理:
- `400`:保留表单输入并展示参数错误,不自动重试。
- `401`:按现有登录失效流程处理。
- `403`:关闭无权限操作入口,不尝试换账号类型绕过。
- `409` 或业务冲突码:检查是否错误复用了 `request_id`
- `500`/超时:在线创建可使用原 `request_id` 重试一次;不要生成新 ID否则可能创建第二张充值单。
## 九、前端本期最容易漏掉的工作
- 在线充值表单不要复用线下表单对象后整体序列化,避免携带 `shop_id`、凭证或备注。
- 支付方式必须来自 `/payment-methods`,不要写死微信和支付宝都可用。
- 金额显示元、提交分;禁止使用浮点数直接乘除后提交。
- 二维码内容原样渲染,不记录到埋点、错误日志或浏览器持久化缓存。
- 同一次网络重试复用 `request_id`,新一笔主动充值换新 ID。
- `status=2` 只表示已收款、入账中,不能提前刷新成“钱包已到账”。
- 列表、详情的页面分支使用 `recharge_source`,不要用 `payment_method` 或审批字段猜来源。
- 线下单不调用支付状态接口;在线单不展示企微审批按钮。
- 页面隐藏或浏览器切到后台时停止轮询,恢复可见后再继续。
- 进入终态后停止轮询并刷新钱包余额、充值列表。
## 十、联调和验收边界
- OpenAPI 已包含 `/payment-methods`、在线创建、列表来源筛选、详情来源字段和 `/payment-status`
- 后端已完成微信 v3 H5/v2 MWEB、支付宝 WAP 支付 URL、支付确认、异步钱包入账和回调丢失恢复的代码装配。
- 当前交付已通过 `go build ./...``go vet ./...` 和 OpenSpec 严格校验。
- 按需求方要求,本次未启动 API/Worker未连接 PostgreSQL/Redis未调用真实支付渠道未发送真实回调也未运行自动化测试。
- 前端联调环境需具备完整支付配置;至少确认微信和支付宝创建响应分别返回非空 `qr_content`
- 本需求不支持 JSAPI、H5、WAP、同设备拉起支付、主动取消、支付方式切换、二维码图片接口或在线退款。