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

6.9 KiB
Raw Blame History

退款时代理处理逻辑分析

当前流程分析

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行

  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

// 检查订单状态
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.goalipayrefundcallbacklogic.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)后订单退款的情况
  • 需要在退款回调和管理员退款中添加撤销代理收益的逻辑