6.9 KiB
6.9 KiB
退款时代理处理逻辑分析
当前流程分析
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):
// 报告生成成功后,发送代理处理异步任务(不阻塞报告流程)
if asyncErr := l.svcCtx.AsynqService.SendAgentProcessTask(order.Id); asyncErr != nil {
// 代理处理任务发送失败,只记录日志,不影响报告流程
logx.Errorf("发送代理处理任务失败,订单ID: %d, 错误: %v", order.Id, asyncErr)
}
4. API调用失败时的处理(第164-167行)
combinedResponse, err := l.svcCtx.ApiRequestService.ProcessRequests(decryptData, product.Id)
if err != nil {
return l.handleError(ctx, err, order, query)
}
handleError 的处理(第206-257行):
- 删除Redis缓存
- 更新查询状态为
failed - 退款
- 更新订单状态为
refunded
关键点:此时代理处理任务还没有发送(因为查询还没成功)
问题分析
✅ 情况1:API调用失败,退款(正常情况)
流程:
- 支付成功,创建代理订单(
ProcessStatus = 0) - 调用API失败(第164-167行)
- 进入
handleError,退款 - 更新订单状态为
refunded - 代理处理任务还没发送(查询未成功)
代理状态:
- ✅ 代理订单
ProcessStatus = 0(未处理) - ✅ 代理没有收到佣金
- ✅ 代理没有收到返佣
- ✅ 处理正确
⚠️ 情况2:查询成功但订单被退款(边界情况)
可能的场景:
- 支付成功,创建代理订单(
ProcessStatus = 0) - 调用API成功,查询状态更新为
success - 发送代理处理任务(第192行)
- 但在代理处理任务执行前,订单被退款(比如管理员手动退款)
代理处理任务的保护机制(agentProcess.go:43-46):
// 检查订单状态
if order.Status != "paid" {
logx.Infof("代理处理任务跳过,订单未支付: orderID=%d, status=%s", payload.OrderID, order.Status)
return nil // 订单未支付,不处理,不重试
}
代理状态:
- ✅ 如果订单状态是
refunded,代理处理任务会跳过 - ✅ 代理订单
ProcessStatus仍然是 0 - ✅ 代理没有收到佣金和返佣
- ✅ 处理正确
⚠️ 情况3:代理已处理但订单被退款(需要处理)
可能的场景:
- 支付成功,创建代理订单(
ProcessStatus = 0) - 调用API成功,查询状态更新为
success - 发送代理处理任务
- 代理处理任务执行,发放佣金和返佣(
ProcessStatus = 1) - 之后订单被退款(比如管理员手动退款)
当前问题:
- ❌ 代理已经收到佣金和返佣
- ❌ 没有撤销代理收益的逻辑
- ❌ 退款回调中也没有处理代理订单的逻辑
发现的问题
问题1:退款回调中缺少代理订单处理
当前退款回调逻辑(wechatpayrefundcallbacklogic.go 和 alipayrefundcallbacklogic.go):
- ✅ 只更新订单状态和退款记录
- ❌ 没有检查代理订单
- ❌ 没有撤销代理收益
问题2:管理员手动退款时缺少代理订单处理
当前管理员退款逻辑(adminrefundorderlogic.go):
- ✅ 创建退款记录,更新订单状态
- ❌ 没有检查代理订单
- ❌ 没有撤销代理收益
建议的解决方案
方案1:在退款回调中处理代理订单(推荐)
在退款成功回调中,检查代理订单并撤销收益:
// 在 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. 创建撤销代理收益的方法
// CancelAgentCommission 撤销代理收益(订单退款时调用)
func (s *AgentService) CancelAgentCommission(ctx context.Context, orderId int64) error {
// 1. 查找代理订单
// 2. 检查是否已处理
// 3. 撤销佣金(从钱包扣除)
// 4. 撤销返佣(从上级钱包扣除)
// 5. 更新代理订单状态
// 6. 创建撤销记录
}
总结
当前情况(API调用失败退款)
✅ 处理正确:
- API调用失败时,代理处理任务还没发送
- 代理订单未处理,代理没有收益
- 无需修改
需要补充的场景
⚠️ 需要处理:
- 代理订单已处理(
ProcessStatus = 1)后订单退款的情况 - 需要在退款回调和管理员退款中添加撤销代理收益的逻辑