Files
ycc-proxy-server/退款时代理处理逻辑分析.md

233 lines
6.9 KiB
Markdown
Raw Normal View History

2025-12-02 19:57:10 +08:00
# 退款时代理处理逻辑分析
## 当前流程分析
### 1. 订单支付成功后的流程
```
支付成功
支付回调(支付宝/微信)
更新订单状态为 "paid"
发送异步任务 SendQueryTask(order.Id)
PaySuccessNotifyUserHandler.ProcessTask
├─ 创建查询记录query表状态为 "pending"
├─ 生成授权书
├─ 调用API请求服务第164行← 可能失败
├─ 如果API成功
│ ├─ 更新查询状态为 "success"
│ └─ 发送代理处理任务 SendAgentProcessTask第192行
└─ 如果API失败
└─ handleError → 退款 → 更新订单状态为 "refunded"
```
### 2. 代理订单创建时机
**在支付时创建**`paymentlogic.go:316-327`
- 代理订单在用户支付时创建
- `ProcessStatus = 0`(待处理)
- 此时还没有发放佣金和返佣
### 3. 代理处理任务执行时机
**只在查询成功后发送**`paySuccessNotify.go:192`
```go
// 报告生成成功后,发送代理处理异步任务(不阻塞报告流程)
if asyncErr := l.svcCtx.AsynqService.SendAgentProcessTask(order.Id); asyncErr != nil {
// 代理处理任务发送失败,只记录日志,不影响报告流程
logx.Errorf("发送代理处理任务失败订单ID: %d, 错误: %v", order.Id, asyncErr)
}
```
### 4. API调用失败时的处理第164-167行
```go
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(decryptData, product.Id)
if err != nil {
return l.handleError(ctx, err, order, query)
}
```
**handleError 的处理**第206-257行
1. 删除Redis缓存
2. 更新查询状态为 `failed`
3. **退款**
4. 更新订单状态为 `refunded`
**关键点**:此时代理处理任务**还没有发送**(因为查询还没成功)
---
## 问题分析
### ✅ 情况1API调用失败退款正常情况
**流程**
1. 支付成功,创建代理订单(`ProcessStatus = 0`
2. 调用API失败第164-167行
3. 进入 `handleError`,退款
4. 更新订单状态为 `refunded`
5. **代理处理任务还没发送**(查询未成功)
**代理状态**
- ✅ 代理订单 `ProcessStatus = 0`(未处理)
- ✅ 代理**没有收到**佣金
- ✅ 代理**没有收到**返佣
-**处理正确**
### ⚠️ 情况2查询成功但订单被退款边界情况
**可能的场景**
1. 支付成功,创建代理订单(`ProcessStatus = 0`
2. 调用API成功查询状态更新为 `success`
3. 发送代理处理任务第192行
4. **但在代理处理任务执行前**,订单被退款(比如管理员手动退款)
**代理处理任务的保护机制**`agentProcess.go:43-46`
```go
// 检查订单状态
if order.Status != "paid" {
logx.Infof("代理处理任务跳过,订单未支付: orderID=%d, status=%s", payload.OrderID, order.Status)
return nil // 订单未支付,不处理,不重试
}
```
**代理状态**
- ✅ 如果订单状态是 `refunded`,代理处理任务会跳过
- ✅ 代理订单 `ProcessStatus` 仍然是 0
- ✅ 代理**没有收到**佣金和返佣
-**处理正确**
### ⚠️ 情况3代理已处理但订单被退款需要处理
**可能的场景**
1. 支付成功,创建代理订单(`ProcessStatus = 0`
2. 调用API成功查询状态更新为 `success`
3. 发送代理处理任务
4. 代理处理任务执行,发放佣金和返佣(`ProcessStatus = 1`
5. **之后**订单被退款(比如管理员手动退款)
**当前问题**
-**代理已经收到佣金和返佣**
-**没有撤销代理收益的逻辑**
-**退款回调中也没有处理代理订单的逻辑**
---
## 发现的问题
### 问题1退款回调中缺少代理订单处理
**当前退款回调逻辑**`wechatpayrefundcallbacklogic.go``alipayrefundcallbacklogic.go`
- ✅ 只更新订单状态和退款记录
-**没有检查代理订单**
-**没有撤销代理收益**
### 问题2管理员手动退款时缺少代理订单处理
**当前管理员退款逻辑**`adminrefundorderlogic.go`
- ✅ 创建退款记录,更新订单状态
-**没有检查代理订单**
-**没有撤销代理收益**
---
## 建议的解决方案
### 方案1在退款回调中处理代理订单推荐
在退款成功回调中,检查代理订单并撤销收益:
```go
// 在 handleQueryOrderRefund 中添加代理订单处理
if status == refunddomestic.STATUS_SUCCESS {
// 更新订单状态
order.Status = orderStatus
// ...
// 检查并处理代理订单
agentOrder, err := l.svcCtx.AgentOrderModel.FindOneByOrderId(ctx, order.Id)
if err == nil && agentOrder.ProcessStatus == 1 {
// 代理订单已处理,需要撤销收益
err = l.svcCtx.AgentService.CancelAgentCommission(ctx, order.Id)
if err != nil {
logx.Errorf("撤销代理收益失败订单ID: %d, 错误: %v", order.Id, err)
// 不阻断退款流程,只记录日志
}
}
}
```
### 方案2在管理员退款时处理代理订单
`AdminRefundOrderLogic` 中添加代理订单检查和处理。
### 方案3在代理处理任务中增加订单状态检查已有保护
当前已有保护机制(`agentProcess.go:43-46`),如果订单状态不是 `paid`,会跳过处理。
---
## 当前处理是否正确?
### ✅ 对于 API 调用失败的情况
**完全正确**
- 如果API调用失败第164-167行会进入退款流程
- 此时代理处理任务还没发送(因为查询未成功)
- 代理订单 `ProcessStatus = 0`,代理没有收到收益
- **处理正确,无需修改**
### ⚠️ 对于已处理代理订单的退款情况
**存在问题**
- 如果代理订单已经处理(`ProcessStatus = 1`),代理已收到佣金和返佣
- 此时订单退款,**没有撤销代理收益的逻辑**
- 这会导致:
- 用户收到退款
- 但代理仍然保留佣金和返佣
- **资金不一致**
---
## 建议修改
### 1. 在退款回调中添加代理订单检查
### 2. 在管理员退款中添加代理订单检查
### 3. 创建撤销代理收益的方法
```go
// CancelAgentCommission 撤销代理收益(订单退款时调用)
func (s *AgentService) CancelAgentCommission(ctx context.Context, orderId int64) error {
// 1. 查找代理订单
// 2. 检查是否已处理
// 3. 撤销佣金(从钱包扣除)
// 4. 撤销返佣(从上级钱包扣除)
// 5. 更新代理订单状态
// 6. 创建撤销记录
}
```
---
## 总结
### 当前情况API调用失败退款
**处理正确**
- API调用失败时代理处理任务还没发送
- 代理订单未处理,代理没有收益
- **无需修改**
### 需要补充的场景
⚠️ **需要处理**
- 代理订单已处理(`ProcessStatus = 1`)后订单退款的情况
- 需要在退款回调和管理员退款中添加撤销代理收益的逻辑