This commit is contained in:
@@ -490,6 +490,91 @@ components:
|
||||
description: 总记录数
|
||||
type: integer
|
||||
type: object
|
||||
DtoAgentRechargeOnlineResponse:
|
||||
properties:
|
||||
amount:
|
||||
description: 在线充值金额(分),范围10000分~100000000分
|
||||
type: integer
|
||||
payment_method:
|
||||
description: 支付方式 (wechat:微信, alipay:支付宝)
|
||||
type: string
|
||||
payment_no:
|
||||
description: 支付单号(PAY前缀)
|
||||
type: string
|
||||
qr_content:
|
||||
description: 支付渠道原始扫码付款内容,由前端渲染二维码
|
||||
type: string
|
||||
recharge_id:
|
||||
description: 充值记录ID
|
||||
minimum: 0
|
||||
type: integer
|
||||
recharge_no:
|
||||
description: 充值单号(ARCH前缀)
|
||||
type: string
|
||||
recharge_source:
|
||||
description: 充值来源 (agent_online:代理在线自充)
|
||||
type: string
|
||||
recharge_source_name:
|
||||
description: 充值来源名称(中文)
|
||||
type: string
|
||||
status:
|
||||
description: 状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款, 6:已驳回)
|
||||
type: integer
|
||||
status_name:
|
||||
description: 状态名称(中文)
|
||||
type: string
|
||||
type: object
|
||||
DtoAgentRechargePaymentMethodsResponse:
|
||||
properties:
|
||||
max_amount:
|
||||
description: 在线充值最大金额(分),固定为100000000
|
||||
type: integer
|
||||
methods:
|
||||
description: 可用支付方式,固定顺序 (wechat:微信, alipay:支付宝)
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
type: array
|
||||
min_amount:
|
||||
description: 在线充值最小金额(分),固定为10000
|
||||
type: integer
|
||||
type: object
|
||||
DtoAgentRechargePaymentStatusResponse:
|
||||
properties:
|
||||
completed_at:
|
||||
description: 钱包入账完成时间
|
||||
nullable: true
|
||||
type: string
|
||||
paid_at:
|
||||
description: 第三方支付确认时间
|
||||
nullable: true
|
||||
type: string
|
||||
payment_status:
|
||||
description: 支付状态 (0:待支付, 1:已支付, 2:已失败, 3:已退款)
|
||||
type: integer
|
||||
payment_status_name:
|
||||
description: 支付状态名称(中文)
|
||||
type: string
|
||||
recharge_id:
|
||||
description: 充值记录ID
|
||||
minimum: 0
|
||||
type: integer
|
||||
recharge_no:
|
||||
description: 充值单号(ARCH前缀)
|
||||
type: string
|
||||
recharge_source:
|
||||
description: 充值来源 (platform_offline:平台线下代充, agent_online:代理在线自充)
|
||||
type: string
|
||||
recharge_source_name:
|
||||
description: 充值来源名称(中文)
|
||||
type: string
|
||||
status:
|
||||
description: 充值状态 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款, 6:已驳回)
|
||||
type: integer
|
||||
status_name:
|
||||
description: 充值状态名称(中文)
|
||||
type: string
|
||||
type: object
|
||||
DtoAgentRechargeRejectParams:
|
||||
properties:
|
||||
rejection_reason:
|
||||
@@ -546,7 +631,7 @@ components:
|
||||
nullable: true
|
||||
type: integer
|
||||
payment_method:
|
||||
description: 支付方式 (wechat:微信在线支付, offline:线下转账)
|
||||
description: 支付方式 (wechat:微信在线支付, alipay:支付宝在线支付, offline:线下转账)
|
||||
type: string
|
||||
payment_transaction_id:
|
||||
description: 第三方支付流水号
|
||||
@@ -560,6 +645,12 @@ components:
|
||||
recharge_no:
|
||||
description: 充值单号(ARCH前缀)
|
||||
type: string
|
||||
recharge_source:
|
||||
description: 充值来源 (platform_offline:平台线下代充, agent_online:代理在线自充)
|
||||
type: string
|
||||
recharge_source_name:
|
||||
description: 充值来源名称(中文)
|
||||
type: string
|
||||
rejection_reason:
|
||||
description: 驳回原因,仅 status=6 时有值
|
||||
nullable: true
|
||||
@@ -3580,7 +3671,7 @@ components:
|
||||
minimum: 1
|
||||
type: integer
|
||||
payment_method:
|
||||
description: 支付方式 (wechat:微信在线支付, offline:线下转账仅平台可用)
|
||||
description: 支付方式 (wechat:微信在线支付, alipay:支付宝在线支付, offline:线下转账仅平台可用)
|
||||
type: string
|
||||
payment_voucher_key:
|
||||
description: 支付凭证对象存储Key列表(payment_method=offline 时至少1个,最多5个,微信支付时忽略)
|
||||
@@ -3593,12 +3684,16 @@ components:
|
||||
description: 运营备注(可选,创建后只读)
|
||||
maxLength: 1000
|
||||
type: string
|
||||
request_id:
|
||||
description: 在线充值幂等请求标识,微信或支付宝支付时必填
|
||||
maxLength: 64
|
||||
type: string
|
||||
shop_id:
|
||||
description: 目标店铺ID,代理只能填自己店铺
|
||||
description: 目标店铺ID,仅平台线下代充可填;代理在线充值禁止传入
|
||||
minimum: 0
|
||||
nullable: true
|
||||
type: integer
|
||||
required:
|
||||
- shop_id
|
||||
- amount
|
||||
- payment_method
|
||||
type: object
|
||||
@@ -12194,6 +12289,12 @@ paths:
|
||||
description: 按状态过滤 (1:待支付, 2:已支付, 3:已完成, 4:已关闭, 5:已退款, 6:已驳回)
|
||||
nullable: true
|
||||
type: integer
|
||||
- description: 按充值来源过滤 (platform_offline:平台线下代充, agent_online:代理在线自充)
|
||||
in: query
|
||||
name: recharge_source
|
||||
schema:
|
||||
description: 按充值来源过滤 (platform_offline:平台线下代充, agent_online:代理在线自充)
|
||||
type: string
|
||||
- description: 创建时间起始日期(YYYY-MM-DD)
|
||||
in: query
|
||||
name: start_date
|
||||
@@ -12279,7 +12380,7 @@ paths:
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/components/schemas/DtoAgentRechargeResponse'
|
||||
$ref: '#/components/schemas/DtoAgentRechargeOnlineResponse'
|
||||
msg:
|
||||
description: 响应消息
|
||||
example: success
|
||||
@@ -12463,6 +12564,73 @@ paths:
|
||||
summary: 确认线下充值
|
||||
tags:
|
||||
- 代理预充值
|
||||
/api/admin/agent-recharges/{id}/payment-status:
|
||||
get:
|
||||
parameters:
|
||||
- description: ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
schema:
|
||||
description: ID
|
||||
minimum: 0
|
||||
type: integer
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
code:
|
||||
description: 响应码
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/components/schemas/DtoAgentRechargePaymentStatusResponse'
|
||||
msg:
|
||||
description: 响应消息
|
||||
example: success
|
||||
type: string
|
||||
timestamp:
|
||||
description: 时间戳
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- code
|
||||
- msg
|
||||
- data
|
||||
- timestamp
|
||||
type: object
|
||||
description: 成功
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 请求参数错误
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 未认证或认证已过期
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 无权访问
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 服务器内部错误
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 查询代理充值本地支付与到账状态
|
||||
tags:
|
||||
- 代理预充值
|
||||
/api/admin/agent-recharges/{id}/reject:
|
||||
post:
|
||||
parameters:
|
||||
@@ -12509,6 +12677,64 @@ paths:
|
||||
summary: 驳回代理充值订单
|
||||
tags:
|
||||
- 代理预充值
|
||||
/api/admin/agent-recharges/payment-methods:
|
||||
get:
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
code:
|
||||
description: 响应码
|
||||
example: 0
|
||||
type: integer
|
||||
data:
|
||||
$ref: '#/components/schemas/DtoAgentRechargePaymentMethodsResponse'
|
||||
msg:
|
||||
description: 响应消息
|
||||
example: success
|
||||
type: string
|
||||
timestamp:
|
||||
description: 时间戳
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- code
|
||||
- msg
|
||||
- data
|
||||
- timestamp
|
||||
type: object
|
||||
description: 成功
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 请求参数错误
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 未认证或认证已过期
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 无权访问
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
description: 服务器内部错误
|
||||
security:
|
||||
- BearerAuth: []
|
||||
summary: 查询代理在线充值可用支付方式
|
||||
tags:
|
||||
- 代理预充值
|
||||
/api/admin/asset-allocation-records:
|
||||
get:
|
||||
parameters:
|
||||
|
||||
327
docs/feature-034-agent-wallet-qr-recharge/代理钱包扫码充值接口对接说明.md
Normal file
327
docs/feature-034-agent-wallet-qr-recharge/代理钱包扫码充值接口对接说明.md
Normal file
@@ -0,0 +1,327 @@
|
||||
# 代理钱包扫码充值实现与接口对接说明
|
||||
|
||||
> 面向:产品、前端和联调人员
|
||||
> 范围:代理微信/支付宝桌面扫码自充、平台线下代充来源区分、支付状态轮询
|
||||
> 接口细节:以 [`docs/admin-openapi.yaml`](../../admin-openapi.yaml) 为准,本文说明前端调用顺序、字段口径和页面状态。
|
||||
|
||||
## 一、先看这几个关键结论
|
||||
|
||||
1. **同一个创建接口有两条业务路径**:代理账号使用 `wechat|alipay` 在线自充;平台或超级管理员使用 `offline` 线下代充。
|
||||
2. **前端必须使用 `recharge_source` 区分来源**:`platform_offline` 是平台线下代充,`agent_online` 是代理在线自充;不要根据账号名称、备注或审批字段猜测。
|
||||
3. **代理不能选择充值店铺**:在线充值的店铺和主钱包由登录上下文确定,请求不得发送 `shop_id`、支付凭证或备注。
|
||||
4. **二维码由前端渲染**:后端返回支付渠道原始 `qr_content`,不返回二维码图片。
|
||||
5. **网络重试不能创建新请求 ID**:同一次提交重试复用原 `request_id`;用户主动发起下一笔充值时生成新的 `request_id`。
|
||||
6. **支付和钱包到账是两个阶段**:`status=2` 表示第三方已收款、钱包入账处理中;只有 `status=3` 才表示钱包到账完成。
|
||||
7. **页面轮询只调用本地状态接口**:前端不得直接调用微信、支付宝查单,也不要反复调用创建接口查询状态。
|
||||
8. **在线金额单位为分**:最低 `10000` 分(100 元),最高 `100000000` 分(100 万元);不要提交浮点元金额。
|
||||
|
||||
## 二、本次需求怎么实现
|
||||
|
||||
| 能力 | 后端实现 | 前端要做什么 |
|
||||
| --- | --- | --- |
|
||||
| 可用支付方式 | 根据当前有效支付配置返回真正可用的 `wechat`、`alipay` | 打开充值弹窗时先查询;只展示返回数组中的方式 |
|
||||
| 代理在线自充 | 从登录账号取得当前店铺和主钱包,创建充值单、支付单并向第三方预下单 | 只提交金额、支付方式和请求 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": "weixin://wxpay/bizpayurl?pr=...",
|
||||
"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` | 充值状态 `1~6` |
|
||||
| `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`。
|
||||
- 后端已完成微信 Native、支付宝 PreCreate、支付确认、异步钱包入账和回调丢失恢复的代码装配。
|
||||
- 当前交付已通过 `go build ./...`、`go vet ./...` 和 OpenSpec 严格校验。
|
||||
- 按需求方要求,本次未启动 API/Worker,未连接 PostgreSQL/Redis,未调用真实支付渠道,未发送真实回调,也未运行自动化测试。
|
||||
- 前端联调环境需具备完整支付配置;至少确认微信和支付宝创建响应分别返回非空 `qr_content`。
|
||||
- 本需求不支持 JSAPI、H5、WAP、同设备拉起支付、主动取消、支付方式切换、二维码图片接口或在线退款。
|
||||
85
docs/feature-034-agent-wallet-qr-recharge/功能总结.md
Normal file
85
docs/feature-034-agent-wallet-qr-recharge/功能总结.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# 代理钱包桌面扫码充值
|
||||
|
||||
前端调用顺序、请求示例和页面状态详见 [`代理钱包扫码充值接口对接说明.md`](代理钱包扫码充值接口对接说明.md)。
|
||||
|
||||
## 功能范围
|
||||
|
||||
代理账号可在后台为当前所属店铺主钱包创建微信 Native 或支付宝当面付扫码充值。平台与超级管理员继续使用既有线下代充和企业微信审批,两个创建路径不共用权限。
|
||||
|
||||
充值订单相关响应统一返回:
|
||||
|
||||
- `recharge_source=platform_offline`、`recharge_source_name=平台线下代充`
|
||||
- `recharge_source=agent_online`、`recharge_source_name=代理在线自充`
|
||||
|
||||
来源由受控支付方式推导:`offline` 为平台线下代充,`wechat|alipay` 为代理在线自充。列表支持 `recharge_source` 筛选,不新增重复数据库列。
|
||||
|
||||
## API 对接
|
||||
|
||||
### 查询可用支付方式
|
||||
|
||||
`GET /api/admin/agent-recharges/payment-methods`
|
||||
|
||||
仅代理账号可用,返回当前真正可预下单、验签和查单的 `wechat`、`alipay`,以及在线充值金额范围 `10000~100000000` 分。
|
||||
|
||||
### 创建充值订单
|
||||
|
||||
`POST /api/admin/agent-recharges`
|
||||
|
||||
代理在线自充请求仅允许:
|
||||
|
||||
```json
|
||||
{
|
||||
"amount": 10000,
|
||||
"payment_method": "wechat",
|
||||
"request_id": "客户端生成的唯一请求标识"
|
||||
}
|
||||
```
|
||||
|
||||
响应包含 `recharge_id`、`payment_no`、`qr_content`、`recharge_source` 和充值状态。前端直接使用 `qr_content` 渲染二维码,不展示或记录支付配置、商户身份和密钥。
|
||||
|
||||
平台线下代充使用 `payment_method=offline`,并按既有契约提交目标 `shop_id`、支付凭证和备注;响应来源为 `platform_offline`。
|
||||
|
||||
### 列表、详情与支付状态
|
||||
|
||||
- `GET /api/admin/agent-recharges?recharge_source=agent_online`
|
||||
- `GET /api/admin/agent-recharges/:id`
|
||||
- `GET /api/admin/agent-recharges/:id/payment-status`
|
||||
|
||||
列表和详情均返回充值来源。支付状态接口仅用于在线充值,只读取本地充值单和支付单,返回支付确认时间与钱包完成时间,不返回 `qr_content`、内部重试错误或其他钱包余额,也不调用第三方渠道。
|
||||
|
||||
前端在页面可见时可每 3 秒轮询;进入已完成、已关闭、已退款或已驳回终态后停止轮询。
|
||||
|
||||
## 支付与到账
|
||||
|
||||
第三方收款成功后,回调只确认支付事实并写入 `agent_recharge.payment_confirmed.v1` Outbox。Worker 在独立事务中复用主钱包入账能力,以充值记录 ID 的唯一流水保证最多入账一次,并将充值状态从已支付推进为已完成。
|
||||
|
||||
支付单保存创建时的 `payment_config_id` 和 `merchant_identity`:微信记录商户号,支付宝记录应用 ID,供未来导出按实际收款身份核对。该内部字段不在创建、列表、详情或支付状态响应中暴露。
|
||||
|
||||
## 异常恢复
|
||||
|
||||
Worker 每分钟调度一次恢复任务,并使用唯一任务约束避免并发重复扫描。任务固定扫描最多 50 张创建超过 2 分钟的代理在线待支付单:
|
||||
|
||||
- 尚无付款内容:使用原 `payment_no` 重试预下单。
|
||||
- 已有付款内容:按创建时的支付方式与配置主动查单。
|
||||
- 渠道确认成功:复用统一支付确认用例。
|
||||
- 渠道明确关闭:条件关闭仍待支付的本地单。
|
||||
- 超时、未知或渠道异常:保持原状态,等待后续重试。
|
||||
|
||||
微信、支付宝每次预下单和查单均写 Integration Log,其中包含耗时和安全摘要,不保存密钥或完整二维码内容。
|
||||
|
||||
## 部署与回滚
|
||||
|
||||
推荐顺序:
|
||||
|
||||
1. 执行 `000197`、`000198` 数据库迁移。
|
||||
2. 确认微信商户号、证书、APIv3 Key、回调地址,或支付宝应用 ID、私钥、公钥、回调地址完整。
|
||||
3. 同时发布 API 与 Worker,确认回调路由、Outbox Relay、代理充值消费者和恢复任务均已装配。
|
||||
4. 最后开放前端扫码充值入口。
|
||||
|
||||
回滚时先关闭前端入口和在线支付方式,停止创建新单;回调、恢复任务、Outbox Relay 和钱包消费者必须继续处理已收款订单。不得删除待支付、已支付或待入账的支付事实。确认资金单全部收敛后,才可回滚应用与数据库迁移。
|
||||
|
||||
## 静态验收与未验证边界
|
||||
|
||||
本次按用户要求不启动 API/Worker,不连接 PostgreSQL/Redis,不调用真实支付,不发送回调,也不运行自动化测试。交付仅执行格式化、差异检查、编译、静态分析、OpenAPI 生成和 OpenSpec 严格校验。
|
||||
|
||||
上线前由发布方核对支付配置与回调公网可达性,并使用一笔微信和一笔支付宝订单确认渠道能返回非空 `qr_content`。回调丢失、重复回调与 Worker 重放可在需要时按上述状态和唯一流水口径人工核对。
|
||||
Reference in New Issue
Block a user