## ADDED Requirements

### Requirement: 迁移接口的越权校验（通用要求）

本规范下所有 `/shops/:shop_id/...` 迁移/新增接口，Service 层方法入口 SHALL 调用 `middleware.CanManageShop(ctx, shopID)` 做显式越权校验。Handler 层只做参数解析，不承担权限逻辑。该要求同时追溯适用于已有但缺少校验的 `ListShopWithdrawalRequests`、`ListShopCommissionRecords` 两个方法（回归漏洞修复）。

统一错误返回：`errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")`。

#### Scenario: 代理传非自己管辖店铺 ID 被 Service 层拦截

- **WHEN** 代理 A（shopID=10）请求本规范任意一个 `/shops/:shop_id/...` 接口，传入代理 B（shopID=20）的 shopID
- **THEN** Service 层入口的 `middleware.CanManageShop(ctx, 20)` 返回 error，接口返回 403，消息 "无权限操作该资源或资源不存在"

#### Scenario: 平台人员不受 CanManageShop 限制

- **WHEN** 平台人员请求任意 `/shops/:shop_id/...` 接口
- **THEN** `middleware.CanManageShop` 直接放行，接口正常返回数据

#### Scenario: 已有方法 ListShopCommissionRecords / ListShopWithdrawalRequests 补齐校验

- **WHEN** 代理账号请求 `/shops/{非自己管辖shopID}/commission-records` 或 `/withdrawal-requests`
- **THEN** 实现后返回 403（回归漏洞修复前这两个方法会返回数据）

---

### Requirement: 查询佣金记录列表

系统 SHALL 提供佣金记录列表查询，支持按店铺、佣金来源、时间范围、状态筛选。

#### Scenario: 代理查询自己店铺的佣金
- **WHEN** 代理查询佣金记录列表
- **THEN** 系统返回该店铺的所有佣金记录

#### Scenario: 按成本价差筛选
- **WHEN** 指定 commission_source 为 cost_diff
- **THEN** 系统只返回成本价差类型的佣金记录

#### Scenario: 按一次性佣金筛选
- **WHEN** 指定 commission_source 为 one_time
- **THEN** 系统只返回一次性佣金类型的佣金记录

#### Scenario: 使用已废弃的佣金来源筛选
- **WHEN** 指定 commission_source 为 tier_bonus
- **THEN** 系统返回空列表或返回错误 "不支持的佣金来源类型"

#### Scenario: 按时间范围筛选
- **WHEN** 指定开始时间和结束时间
- **THEN** 系统只返回该时间范围内的佣金记录

#### Scenario: 响应包含关联信息
- **WHEN** 查询佣金记录列表
- **THEN** 每条记录包含：
  - 佣金记录 ID、金额、状态、状态名称
  - 订单号（order_no）、订单创建时间（order_created_at）
  - ICCID（当订单类型为单卡时）
  - 设备虚拟号（当订单类型为设备时）
  - 销售来源店铺 ID 和名称（seller_shop_id, seller_shop_name）
  - 佣金入账时间

---

### Requirement: 查询佣金记录详情

系统 SHALL 允许查询单条佣金记录的详细信息。

#### Scenario: 查询佣金详情
- **WHEN** 代理查询指定佣金记录详情
- **THEN** 系统返回完整的佣金信息和关联的订单、卡/设备信息

#### Scenario: 查询他人佣金
- **WHEN** 代理尝试查询其他店铺的佣金记录
- **THEN** 系统返回 "记录不存在" 错误

---

### Requirement: 佣金统计

系统 SHALL 提供佣金统计功能，包含总收入和各来源占比。

#### Scenario: 查询总收入
- **WHEN** 代理查询佣金统计
- **THEN** 系统返回总收入金额（所有已入账佣金之和）

#### Scenario: 各来源占比
- **WHEN** 代理查询佣金统计
- **THEN** 系统返回各佣金来源的金额和占比（cost_diff、one_time）

#### Scenario: 统计响应不包含梯度奖励字段
- **WHEN** 代理查询佣金统计
- **THEN** 响应中不包含 tier_bonus_amount、tier_bonus_count、tier_bonus_percent 字段

#### Scenario: 按时间范围统计
- **WHEN** 指定时间范围查询统计
- **THEN** 系统只统计该时间范围内的佣金

---

### Requirement: 每日佣金统计

系统 SHALL 提供每日佣金统计查询。

#### Scenario: 查询每日统计
- **WHEN** 代理查询指定日期范围的每日统计
- **THEN** 系统返回每天的佣金总额和笔数

#### Scenario: 默认最近30天
- **WHEN** 代理查询每日统计不指定日期范围
- **THEN** 系统返回最近 30 天的数据

---

## MODIFIED Requirements

### Requirement: 佣金状态定义

**原内容**：

佣金记录状态为二态：1=已入账，2=已失效

**修改为**：

佣金记录状态为四态：
- 1 = 已冻结：佣金已计算但暂不可提现
- 2 = 解冻中：满足解冻条件，正在等待发放
- 3 = 已发放：佣金已入账可提现
- 4 = 已失效：佣金核验失败或订单退款导致失效

#### Scenario: 差价佣金创建时状态
- **WHEN** 差价佣金计算完成并创建记录
- **THEN** 记录状态为 3（已发放）

#### Scenario: 链路断裂时状态
- **WHEN** 佣金链路断裂（上级代理未分配套餐）
- **THEN** 记录状态为 99（待人工修正）

#### Scenario: 订单退款时状态
- **WHEN** 关联订单发生退款
- **THEN** 佣金记录状态更新为 4（已失效）

---

### Requirement: 佣金状态常量一致性

系统 SHALL 使用统一的状态值和状态名称映射，确保佣金状态显示正确。

#### Scenario: 已发放状态正确显示
- **WHEN** 佣金记录 status = 3
- **THEN** 状态名称返回 "已发放"

#### Scenario: 已冻结状态正确显示
- **WHEN** 佣金记录 status = 1
- **THEN** 状态名称返回 "已冻结"

#### Scenario: 解冻中状态正确显示
- **WHEN** 佣金记录 status = 2
- **THEN** 状态名称返回 "解冻中"

#### Scenario: 已失效状态正确显示
- **WHEN** 佣金记录 status = 4
- **THEN** 状态名称返回 "已失效"
