同步相关内容
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
# 新增需求 05:代理钱包扫码充值
|
||||
|
||||
> 状态:已合并至标准评审稿,本文保留为实施明细。
|
||||
> 状态:已冻结,本文保留为实施明细;如有冲突,以标准评审稿和 UR#34 PRD 为准。
|
||||
> 评审主文档:`../../7月迭代技术方案-标准评审稿.md`
|
||||
> 实施 PRD:`../../../../.scratch/ur34-agent-recharge/PRD.md`
|
||||
> 范围:代理在后台使用微信或支付宝扫码充值代理主钱包。
|
||||
|
||||
## 一、已确认决策
|
||||
@@ -9,7 +10,7 @@
|
||||
1. 代理在后台为自己的店铺主钱包充值。
|
||||
2. 支付方式支持微信扫码和支付宝扫码。
|
||||
3. 单笔最低充值金额为 100 元,即 `10000` 分。
|
||||
4. 代理在线充值不进入企业微信审批,支付成功后直接幂等增加代理主钱包余额。
|
||||
4. 代理在线充值不进入企业微信审批;支付成功事实先落库,再由可靠 Worker 幂等增加代理主钱包余额。
|
||||
5. 平台员工线下代充值仍按 `02-企业微信审批接入.md` 走企微审批,与本方案隔离。
|
||||
6. 后端返回支付二维码内容,前端使用现有二维码组件渲染,不由后端生成或保存二维码图片文件。
|
||||
7. 微信使用 Native 支付,支付宝使用 `alipay.trade.precreate` 当面付预创建。
|
||||
@@ -26,7 +27,7 @@
|
||||
- 微信支付仅保存当前生效支付配置,响应中没有 `code_url`。
|
||||
- 支付宝回调只分发套餐订单和客户资产钱包充值,没有代理充值订单类型。
|
||||
- `HandlePaymentCallback` 在旧 Service 中直接更新充值单、钱包和流水,业务状态和幂等边界没有收口为独立用例。
|
||||
- 前端技术方案只写了“保留收款码和支付状态页面”,没有支付方式选择、最低金额、二维码过期和支付成功状态细节。
|
||||
- 前端技术方案只写了“保留收款码和支付状态页面”,没有支付方式选择、最低金额、第三方状态收敛和支付/入账状态细节。
|
||||
|
||||
现有评审中“代理在线充值不审批”的结论保持不变,本次补齐的是扫码支付和最低金额的完整技术方案。
|
||||
|
||||
@@ -47,15 +48,15 @@ sequenceDiagram
|
||||
API->>DB: 创建充值单和支付单
|
||||
API->>Pay: Native/PreCreate 预下单
|
||||
Pay-->>API: 二维码内容
|
||||
API-->>Web: 返回二维码和过期时间
|
||||
API-->>Web: 原样返回 qr_content
|
||||
Web-->>Agent: 展示二维码并轮询支付状态
|
||||
Agent->>Pay: 扫码完成支付
|
||||
Pay->>Callback: 异步支付通知
|
||||
Callback->>API: ConfirmAgentRechargePayment
|
||||
API->>DB: 校验支付单、金额和状态
|
||||
API->>Wallet: CreditRecharge
|
||||
Wallet->>DB: 同事务增加余额、写流水、完成充值单
|
||||
API->>DB: 固化支付成功并写入账 Outbox
|
||||
API-->>Pay: 返回成功
|
||||
DB-->>Wallet: Worker 消费入账任务
|
||||
Wallet->>DB: 独立事务增加余额、写流水、完成充值单
|
||||
Web->>API: 查询到已完成
|
||||
Web-->>Agent: 展示最新钱包余额
|
||||
```
|
||||
@@ -82,8 +83,9 @@ internal/
|
||||
│ └── repository.go 钱包与充值聚合仓储接口
|
||||
├── application/agentrecharge/
|
||||
│ ├── create_qr_recharge.go 创建充值单和扫码支付
|
||||
│ ├── confirm_payment.go 支付回调确认并入账
|
||||
│ ├── close_expired.go 关闭过期未支付充值单
|
||||
│ ├── confirm_payment.go 支付回调或查单确认支付事实
|
||||
│ ├── post_wallet.go 可靠任务执行钱包入账
|
||||
│ ├── sync_pending.go 受控查询待支付第三方订单
|
||||
│ └── get_payment_status.go 轻量支付状态查询
|
||||
├── infrastructure/adapter/payment/
|
||||
│ ├── wechat_native.go 微信 Native 预下单
|
||||
@@ -104,11 +106,11 @@ internal/
|
||||
| 1 | 待支付 | 已创建二维码,等待扫码 |
|
||||
| 2 | 已支付 | 支付已确认,钱包入账事务处理中 |
|
||||
| 3 | 已完成 | 钱包余额和流水已完成 |
|
||||
| 4 | 已关闭 | 超时未支付或主动取消 |
|
||||
| 4 | 已关闭 | 第三方明确未支付且已关闭/失效,或线下审批撤销/删除 |
|
||||
| 5 | 已退款 | 历史或后续人工退款结果 |
|
||||
| 6 | 已驳回 | 仅旧数据或线下审批兼容,在线充值不产生 |
|
||||
|
||||
`status=2` 是短暂业务处理状态。支付回调事务正常完成时直接推进到 `3`;若钱包入账发生可恢复错误,则保持 `2` 并由可靠任务继续处理。
|
||||
`status=2` 是支付事实或审批通过已经固化、钱包正在处理的业务状态。只有独立钱包入账事务成功后才推进到 `3`;发生可恢复错误时保持 `2`,使用 `processing_status=3`表达失败并由可靠任务继续处理。
|
||||
|
||||
### 4.3 钱包入账不变量
|
||||
|
||||
@@ -117,7 +119,7 @@ internal/
|
||||
- 只允许向目标店铺的 `wallet_type=main` 钱包入账。
|
||||
- 入账金额必须等于充值单金额和支付单金额。
|
||||
- 同一充值单只能生成一条成功钱包流水。
|
||||
- 钱包余额、`version`、充值单状态和钱包流水在同一数据库事务更新。
|
||||
- Worker 在同一数据库事务中更新钱包余额、`version`、充值单状态和钱包流水;支付事实由更早的独立事务固化,钱包失败不得回滚真实收款。
|
||||
- 钱包乐观锁冲突时由 Application 重新加载后有限重试,不能重复创建流水。
|
||||
- 支付渠道成功不等于业务已经完成;只有钱包事务成功后充值单才变为已完成。
|
||||
|
||||
@@ -196,15 +198,20 @@ ali_notify_url
|
||||
"payment_method": "wechat",
|
||||
"amount": 10000,
|
||||
"qr_content": "weixin://wxpay/bizpayurl?...",
|
||||
"expires_at": "2026-07-15T15:00:00+08:00",
|
||||
"status": 1,
|
||||
"status_name": "待支付"
|
||||
"status_name": "待支付",
|
||||
"payment_status": 0,
|
||||
"payment_status_name": "待支付",
|
||||
"processing_status": 0,
|
||||
"processing_status_name": "未触发"
|
||||
}
|
||||
```
|
||||
|
||||
微信返回 `code_url`、支付宝返回 `qr_code`,Application 统一映射为 `qr_content`。
|
||||
|
||||
## 六、支付回调与直接入账
|
||||
本地无法准确知道第三方订单的真实失效时间,因此接口不返回 `expires_at`,前端不展示本地推算的精确倒计时。第三方支付成功或关闭以回调和后端受控查单为准。
|
||||
|
||||
## 六、支付确认与可靠入账
|
||||
|
||||
### 6.1 回调校验
|
||||
|
||||
@@ -225,16 +232,20 @@ payment.order_type = agent_recharge
|
||||
|
||||
### 6.2 回调事务
|
||||
|
||||
```text
|
||||
1. 按 payment_no 加载支付单
|
||||
2. 支付单 pending -> paid 条件更新
|
||||
3. 充值单 1 -> 2 条件更新
|
||||
4. 加载代理主钱包并执行 CreditRecharge
|
||||
5. 钱包余额和 version 更新
|
||||
6. 创建唯一钱包流水
|
||||
7. 充值单 2 -> 3,写 paid_at/completed_at
|
||||
8. 写 Audit Event
|
||||
```
|
||||
支付事实事务:
|
||||
|
||||
1. 按 `payment_no` 加载并核验支付单。
|
||||
2. 支付单从待支付条件更新为已支付。
|
||||
3. 充值单从 `1=待支付` 更新为 `2=已支付`,`processing_status=1`。
|
||||
4. 可靠写入钱包入账 Outbox 后向支付渠道返回成功。
|
||||
|
||||
钱包入账 Worker 的独立事务:
|
||||
|
||||
1. 加载代理主钱包并执行 `CreditRecharge`。
|
||||
2. 更新钱包余额和 `version`。
|
||||
3. 创建唯一钱包流水。
|
||||
4. 充值单从 `2=已支付` 更新为 `3=已完成`,`processing_status=2`。
|
||||
5. 写资金 Audit Event 和到账通知事件。
|
||||
|
||||
幂等键:
|
||||
|
||||
@@ -247,7 +258,7 @@ agent_recharge:{recharge_id}:credit
|
||||
### 6.3 回调失败恢复
|
||||
|
||||
- 第三方校验失败:拒绝回调,不改变业务状态。
|
||||
- 支付状态已成功、钱包事务失败:充值单保持已支付,写 Outbox/恢复任务继续入账。
|
||||
- 支付状态已成功、钱包事务失败:充值单保持已支付,`processing_status=3`,由可靠任务继续入账。
|
||||
- 钱包流水已存在但充值单未完成:恢复任务只补齐充值单状态。
|
||||
- 重复回调:查询到支付单或充值单已完成后直接返回渠道成功报文。
|
||||
- 本功能不引入审批,也不会因为支付金额较大转入审批。
|
||||
@@ -263,16 +274,16 @@ const AgentRechargeMinAmount int64 = 10000
|
||||
- 单位固定为分。
|
||||
- DTO 使用 `min=10000`,Service/Application 必须再次校验。
|
||||
- 前端输入单位为元,提交前转换为分。
|
||||
- 最大金额继续沿用现有系统上限,后续调整单独配置。
|
||||
- 最大金额固定为 `100000000` 分。
|
||||
- 禁止前端通过浮点数直接计算金额,元转分使用字符串或十进制定点处理。
|
||||
|
||||
### 7.2 权限
|
||||
|
||||
- 代理只能为当前登录账号所属店铺的主钱包充值。
|
||||
- 后端从登录上下文校验 `shop_id`,不能只相信请求参数。
|
||||
- 平台和超级管理员可以查看全部充值记录;是否允许代代理发起在线扫码充值保持现有权限。
|
||||
- 后端从登录上下文确定当前代理店铺,在线请求不接受 `shop_id`。
|
||||
- 平台和超级管理员不能替代理发起在线扫码充值,只能为明确的目标 `shop_id` 发起 `offline` 线下代充值。
|
||||
- 企业账号无权访问代理充值接口。
|
||||
- 代理不能查看其他店铺的充值单、支付状态或二维码。
|
||||
- 创建权限与查看权限分离。代理在具备充值查看权限时,按既有店铺层级数据范围查看本店及有权管理的下级店铺充值;列表、详情和支付状态使用同一范围。
|
||||
|
||||
## 八、API 设计
|
||||
|
||||
@@ -307,7 +318,6 @@ POST /api/admin/agent-recharges
|
||||
|
||||
```json
|
||||
{
|
||||
"shop_id": 101,
|
||||
"amount": 10000,
|
||||
"payment_method": "wechat",
|
||||
"request_id": "01J2RECHARGE..."
|
||||
@@ -322,7 +332,7 @@ wechat / alipay / offline
|
||||
|
||||
其中 `offline` 仅平台员工线下代充值使用,并继续走企微审批;代理用户只能选择 `wechat/alipay`。
|
||||
|
||||
`request_id` 用于防止前端重复点击创建多个二维码订单,同一店铺下建立业务唯一约束或 Redis 防重键。
|
||||
`request_id` 只用于防止同一次提交的重试重复创建。代理每次主动创建或再次拉起支付都必须使用新的 `request_id`,并创建新的充值单和支付单;此前未付款订单继续等待第三方自然收敛,不按金额复用旧单。
|
||||
|
||||
### 8.3 查询支付状态
|
||||
|
||||
@@ -338,7 +348,8 @@ GET /api/admin/agent-recharges/{id}/payment-status
|
||||
"payment_status_name": "已支付",
|
||||
"paid_at": "2026-07-15T14:35:00+08:00",
|
||||
"completed_at": "2026-07-15T14:35:01+08:00",
|
||||
"wallet_balance": 510000
|
||||
"processing_status": 2,
|
||||
"processing_status_name": "处理成功"
|
||||
}
|
||||
```
|
||||
|
||||
@@ -355,7 +366,7 @@ GET /api/admin/agent-recharges/{id}/payment-status
|
||||
- 金额使用数字输入框,单位为元,明确最低 100 元。
|
||||
- 支付方式使用微信/支付宝分段控件,带对应图标。
|
||||
- 不可用渠道禁用并显示简短原因。
|
||||
- 主按钮为“生成支付二维码”。
|
||||
- 主按钮为“立即充值”。按钮提交创建充值请求,后端不提供独立的二维码生成接口。
|
||||
|
||||
### 9.2 二维码状态
|
||||
|
||||
@@ -365,16 +376,15 @@ GET /api/admin/agent-recharges/{id}/payment-status
|
||||
充值金额
|
||||
支付方式
|
||||
二维码
|
||||
二维码剩余有效时间
|
||||
支付状态
|
||||
取消/重新生成
|
||||
钱包入账状态
|
||||
```
|
||||
|
||||
- 前端使用 `qr_content` 生成二维码,不请求后端图片文件。
|
||||
- 页面可见时每 3 秒查询一次轻量支付状态。
|
||||
- 页面隐藏时暂停轮询,恢复可见时立即查询。
|
||||
- 状态变为已完成、已关闭或离开页面时停止轮询。
|
||||
- 二维码过期后禁用原二维码,提供“重新生成”命令,重新创建充值单和支付单。
|
||||
- 不显示本地推算的精确过期时间,也不提供后端“取消/重新生成二维码”接口;用户再次主动拉起时按一次全新的充值创建处理。
|
||||
- 支付完成后关闭二维码区域,刷新钱包余额并展示充值成功结果。
|
||||
- 全流程不展示审批状态或企微审批区块。
|
||||
|
||||
@@ -398,12 +408,12 @@ GET /api/admin/agent-recharges/{id}/payment-status
|
||||
微信/支付宝支付回调成功/失败
|
||||
钱包入账成功/失败
|
||||
重复回调被幂等忽略
|
||||
充值单超时关闭
|
||||
第三方查单确认支付关闭或失效
|
||||
```
|
||||
|
||||
支付渠道交互写 `tb_integration_log`,钱包余额变化写关键 `Audit Event`,并关联充值单、支付单、代理钱包和钱包流水。
|
||||
|
||||
在线充值不产生审批通知。充值成功后可以生成普通资金结果站内通知,但不能显示“审批通过”。
|
||||
在线充值不产生审批通知。目标代理主钱包实际入账后必须生成“充值到账”站内通知;在线实际提交账号与目标代理主账号不同时,两者分别通知并按充值单与接收人防重。平台线下代充值的真实提交人只接收 UR#37 的审批结果通知,除非其本身也是到账通知接收人。
|
||||
|
||||
## 十一、代码迁移范围
|
||||
|
||||
@@ -438,9 +448,9 @@ GET /api/admin/agent-recharges/{id}/payment-status
|
||||
4. 验证支付宝 PreCreate 返回有效 `qr_code`,前端能够扫码支付。
|
||||
5. 验证支付回调通过支付单类型分发到代理充值用例。
|
||||
6. 验证微信、支付宝回调金额不一致时不会增加钱包余额。
|
||||
7. 验证支付成功后不创建企微审批实例,直接完成钱包入账。
|
||||
7. 验证支付成功后不创建企微审批实例,先固化支付事实,再由可靠 Worker 完成钱包入账。
|
||||
8. 验证重复回调只产生一条钱包流水,余额只增加一次。
|
||||
9. 验证支付成功但钱包事务暂时失败时能够恢复完成,不需要代理重复支付。
|
||||
10. 验证二维码过期后充值单关闭,旧二维码不能继续显示为有效。
|
||||
10. 验证接口不返回 `expires_at`,前端不展示本地倒计时;第三方明确关闭后充值单才关闭,迟到成功回调仍能幂等入账。
|
||||
11. 验证代理充值详情固定返回 `approval_source=none`,不展示审批区域。
|
||||
12. 验证平台员工线下代充值仍按原企微审批方案执行,不受在线充值改造影响。
|
||||
|
||||
Reference in New Issue
Block a user