# 差价佣金计算和分配逻辑搜索结果

## 一、差价佣金的计算方式

### 1.1 计算公式

差价佣金 = 下级成本价 - 自己成本价

### 1.2 计算流程

**文件位置**: `internal/service/commission_calculation/service.go:121-225`

```go
func (s *Service) CalculateCostDiffCommission(ctx context.Context, order *model.Order) ([]*model.CommissionRecord, error)
```

**核心逻辑**:

1. **销售端利润计算** (第138-153行)
   - 销售利润 = 订单总金额 - 销售成本价
   - 如果销售利润 > 0，为销售店铺创建一条佣金记录

2. **链式向上计算** (第163-222行)
   - 从销售店铺开始，逐级向上遍历代理链
   - 对于每一级代理：
     - 获取该代理的成本价（从 ShopPackageAllocation 表）
     - 计算差价：childCostPrice - myCostPrice
     - 如果差价 > 0，创建佣金记录

3. **链路断裂处理** (第173-200行)
   - 如果上级代理未分配该套餐，创建待审佣金记录（status=99）
   - 记录备注：套餐系列未分配给该代理，需人工核查

### 1.3 示例

```
平台基础成本价: 100元
  ↓
分配给代理A，成本价: 120元
  ├─ A的利润: 120 - 100 = 20元
  ↓
分配给代理A1，成本价: 130元
  ├─ A1的利润: 130 - 120 = 10元
  ├─ A的差价佣金: 130 - 120 = 10元
  ↓
A1销售给客户，售价: 200元
  ├─ A1的销售利润: 200 - 130 = 70元
  ├─ A的差价佣金: 130 - 120 = 10元
  ├─ 平台收入: 120元
```

---

## 二、差价佣金的发放条件

### 2.1 触发条件

**文件位置**: `internal/service/order/service.go:1621` 和 `internal/task/commission_calculation.go`

差价佣金在以下情况触发：

1. **订单支付成功** 
   - 支付状态从 `PaymentStatusPending` (1) 变为 `PaymentStatusPaid` (2)
   - 触发点：`WalletPay()` 方法完成后调用 `enqueueCommissionCalculation()`

2. **异步任务处理**
   - 任务类型: `commission:calculate`
   - 处理器: `CommissionCalculationHandler.HandleCommissionCalculation()`
   - 队列: Asynq 异步任务队列

### 2.2 发放流程

**文件位置**: `internal/service/commission_calculation/service.go:74-119`

```go
func (s *Service) CalculateCommission(ctx context.Context, orderID uint) error
```

**步骤**:

1. **检查订单佣金状态** (第81-84行)
   - 如果 `commission_status == 2` (已计算)，跳过
   - 防止重复计算

2. **计算成本价差佣金** (第86-98行)
   - 调用 `CalculateCostDiffCommission()` 获取佣金记录列表
   - 逐条创建佣金记录到 `tb_commission_record` 表
   - 调用 `creditCommissionInTx()` 入账到代理钱包

3. **触发一次性佣金** (第100-111行)
   - 仅非代购订单触发
   - 根据订单类型（单卡/设备）调用对应方法

4. **更新订单佣金状态** (第113-115行)
   - 将 `commission_status` 更新为 `2` (已计算)

### 2.3 佣金入账

**文件位置**: `internal/service/commission_calculation/service.go:641-687`

```go
func (s *Service) creditCommissionInTx(ctx context.Context, tx *gorm.DB, record *model.CommissionRecord) error
```

**入账步骤**:

1. 获取店铺的分佣钱包 (wallet_type = 'commission')
2. 增加钱包余额
3. 更新佣金记录状态为 `CommissionStatusReleased` (3)
4. 记录入账时间 `released_at`
5. 创建钱包交易记录 (transaction_type = 'commission')

---

## 三、差价佣金与订单状态的关系

### 3.1 订单状态定义

**文件位置**: `internal/model/order.go:106-110`

```go
// 佣金状态常量
const (
    CommissionStatusPending    = 1 // 待计算
    CommissionStatusCalculated = 2 // 已计算
)
```

### 3.2 订单支付状态

**文件位置**: `internal/model/order.go:98-104`

```go
// 支付状态常量
const (
    PaymentStatusPending   = 1 // 待支付
    PaymentStatusPaid      = 2 // 已支付
    PaymentStatusCancelled = 3 // 已取消
    PaymentStatusRefunded  = 4 // 已退款
)
```

### 3.3 状态转换关系

```
订单创建
  ↓
commission_status = 1 (待计算)
payment_status = 1 (待支付)
  ↓
用户支付
  ↓
payment_status = 2 (已支付)
  ↓
触发佣金计算任务
  ↓
异步处理：CalculateCommission()
  ↓
commission_status = 2 (已计算)
佣金入账到代理钱包
```

### 3.4 佣金记录状态

**文件位置**: `internal/model/commission.go:40-46` 和 `pkg/constants/iot.go:180-187`

```go
// 佣金记录状态（tb_commission_record.status）
const (
    CommissionStatusReleased      = 3  // 已发放
    CommissionStatusInvalid       = 4  // 已失效
    CommissionStatusPendingReview = 99 // 待人工修正（链路断裂）
)

// 代理钱包交易状态（tb_agent_wallet_transaction.status）
const (
    CommissionStatusFrozen        = 1  // 已冻结
    CommissionStatusUnfreezing    = 2  // 解冻中
    CommissionStatusReleased      = 3  // 已发放
    CommissionStatusInvalid       = 4  // 已失效
    CommissionStatusPendingReview = 99 // 待人工修正
)
```

### 3.5 关键字段

**订单表 (tb_order)**:
- `commission_status`: 佣金计算状态
- `commission_config_version`: 佣金配置版本快照
- `seller_shop_id`: 销售店铺ID（用于成本价差佣金）
- `seller_cost_price`: 销售成本价（用于计算利润）
- `series_id`: 系列ID（用于查询分配配置）

**佣金记录表 (tb_commission_record)**:
- `shop_id`: 佣金归属店铺
- `order_id`: 关联订单
- `commission_source`: 佣金来源 (cost_diff/one_time)
- `amount`: 佣金金额
- `status`: 佣金状态
- `released_at`: 入账时间
- `balance_after`: 入账后钱包余额

---

## 四、关键代码位置总结

| 功能 | 文件位置 | 方法 |
|------|---------|------|
| 差价佣金计算 | `internal/service/commission_calculation/service.go` | `CalculateCostDiffCommission()` |
| 佣金入账 | `internal/service/commission_calculation/service.go` | `creditCommissionInTx()` |
| 佣金计算触发 | `internal/service/order/service.go` | `enqueueCommissionCalculation()` |
| 异步任务处理 | `internal/task/commission_calculation.go` | `HandleCommissionCalculation()` |
| 订单支付完成 | `internal/service/order/service.go` | `WalletPay()` |
| 模型定义 | `internal/model/commission.go` | `CommissionRecord` |
| 模型定义 | `internal/model/order.go` | `Order` |
| 业务文档 | `docs/commission-package-model.md` | 完整的佣金业务模型说明 |

---

## 五、相关常量

**文件位置**: `pkg/constants/constants.go` 和 `pkg/constants/iot.go`

```go
// 任务类型
TaskTypeCommission = "commission:calculate"

// 佣金来源
CommissionSourceCostDiff = "cost_diff"    // 成本价差
CommissionSourceOneTime  = "one_time"     // 一次性佣金

// 佣金状态
CommissionStatusReleased      = 3  // 已发放
CommissionStatusInvalid       = 4  // 已失效
CommissionStatusPendingReview = 99 // 待人工修正
```

