Files
ycc-proxy-server/退款时代理处理逻辑分析.md
2025-12-02 19:57:10 +08:00

233 lines
6.9 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.

# 退款时代理处理逻辑分析
## 当前流程分析
### 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`)后订单退款的情况
- 需要在退款回调和管理员退款中添加撤销代理收益的逻辑