refactor: 一次性佣金配置从套餐级别提升到系列级别
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m29s

主要变更:
- 新增 tb_shop_series_allocation 表,存储系列级别的一次性佣金配置
- ShopPackageAllocation 移除 one_time_commission_amount 字段
- PackageSeries 新增 enable_one_time_commission 字段控制是否启用一次性佣金
- 新增 /api/admin/shop-series-allocations CRUD 接口
- 佣金计算逻辑改为从 ShopSeriesAllocation 获取一次性佣金金额
- 删除废弃的 ShopSeriesOneTimeCommissionTier 模型
- OpenAPI Tag '系列分配' 和 '单套餐分配' 合并为 '套餐分配'

迁移脚本:
- 000042: 重构佣金套餐模型
- 000043: 简化佣金分配
- 000044: 一次性佣金分配重构
- 000045: PackageSeries 添加 enable_one_time_commission 字段

测试:
- 新增验收测试 (shop_series_allocation, commission_calculation)
- 新增流程测试 (one_time_commission_chain)
- 删除过时的单元测试(已被验收测试覆盖)
This commit is contained in:
2026-02-04 14:28:44 +08:00
parent fba8e9e76b
commit b18ecfeb55
106 changed files with 9899 additions and 6608 deletions

View File

@@ -0,0 +1,99 @@
## Why
当前套餐与佣金系统存在**概念模型与实现错位**的问题:套餐价格字段过多且语义不清(`Price``SuggestedCostPrice``SuggestedRetailPrice` 三个字段用途混乱),流量字段设计不支持真流量/虚流量共存机制,一次性佣金缺少链式分配能力(无法设置"给下级多少"),套餐分配与系列分配的关系不清晰。这导致接口入参混乱、不同模块的一致性被破坏、操作流程不是线性的。需要基于梳理清楚的业务模型进行系统性重构。
## What Changes
### 套餐模型简化
- **BREAKING** 移除 `Package.Price` 字段,只保留 `cost_price`(成本价)和 `suggested_retail_price`(建议售价)
- **BREAKING** 重构流量字段:`real_data_mb`(必填)+ `enable_virtual_data`(开关)+ `virtual_data_mb`(可选,≤真流量)
- 移除 `data_type` 字段(不再是二选一)
- 移除 `data_amount_mb` 字段(语义不清)
### 一次性佣金重构
- **BREAKING** 修改触发条件命名:`single_recharge``first_recharge`(首充)
- **BREAKING** 新增链式分配能力:套餐分配时设置"给下级的一次性佣金金额"
- 新增一次性佣金时效配置(永久/固定日期/相对时长)
- 优化强充金额计算:首充时 `max(首充要求, 套餐售价)`;累计充值时支持固定/动态差额两种模式
- 新增梯度佣金统计范围开关(仅自己/自己+下级)
### 套餐分配统一
- **BREAKING** 统一套餐分配模型:将一次性佣金额度配置移入套餐分配
- 套餐系列仅定义一次性佣金"规则",分配时设置"给谁多少"
- 代理只能看到自己能拿到的一次性佣金额度,不能看到总规则
### 累计充值机制完善
- 明确累计范围:按卡/设备在该套餐系列下累计
- 明确累计操作:只有"充值"操作累计,"直接购买套餐"不累计
- 一次性佣金每张卡/设备只触发一次
### 代理视角优化
- 不同用户调用同一套餐列表接口,看到不同的成本价(自己的成本价)
- 不同用户看到不同的一次性佣金额度(自己能拿到的)
## Capabilities
### New Capabilities
- `commission-chain-distribution`: 一次性佣金链式分配能力,支持在套餐分配时设置给下级的佣金金额,自动计算各级代理分得的佣金
- `package-virtual-data`: 套餐真流量/虚流量共存机制,支持开关控制虚流量,停机判断基于配置选择使用哪个流量值
- `one-time-commission-validity`: 一次性佣金时效管理,支持永久、固定到期日期、相对时长三种时效类型
- `accumulated-recharge-tracking`: 累计充值追踪,按卡/设备在套餐系列下累计充值金额,只统计充值操作
### Modified Capabilities
- `package-management`: 移除 `Price``data_type``data_amount_mb` 字段,简化为 `cost_price` + `suggested_retail_price` + 真流量/虚流量共存
- `package-series-management`: 一次性佣金规则仅在系列层面定义,分配时不再复制完整配置
- `shop-series-allocation`: 移除完整的一次性佣金配置,改为引用系列规则 + 设置给下级的金额
- `one-time-commission-trigger`: 触发条件从 `single_recharge` 改为 `first_recharge`,首充定义为该卡/设备在该系列下的第一次充值
- `commission-calculation`: 适配链式分配逻辑,上级佣金 = 自己能拿的 - 给下级的
- `force-recharge-check`: 首充强充金额改为 `max(首充要求, 套餐售价)`,累计充值强充支持固定/动态两种计算方式
- `agent-available-packages`: 返回代理视角的成本价和一次性佣金额度,而非原始配置
- `shop-commission-tier`: 新增统计范围开关(仅自己/自己+下级),统计周期与一次性佣金时效一致
## Impact
### 数据库变更
- `tb_package`: 移除 `price``data_type``data_amount_mb` 字段,新增 `enable_virtual_data` 字段
- `tb_package_series`: 新增一次性佣金时效字段(`validity_type``validity_value`
- `tb_shop_series_allocation`: 移除大部分一次性佣金配置字段,仅保留 `one_time_commission_amount`(给下级的金额)
- `tb_shop_package_allocation`: 新增 `one_time_commission_amount` 字段
- `tb_iot_card` / `tb_device`: 新增 `accumulated_recharge_amount`(累计充值)、`first_recharge_triggered`(首充已触发)字段
- `tb_shop_series_one_time_commission_tier`: 新增 `stat_scope` 字段
### API 变更BREAKING
- `POST /api/admin/packages`: 移除 `price``data_type``data_amount_mb` 参数
- `PUT /api/admin/packages/:id`: 同上
- `POST /api/admin/shop-series-allocations`: 移除 `one_time_commission_type/trigger/threshold/mode/value` 等字段,新增 `one_time_commission_amount`
- `POST /api/admin/shop-package-allocations`: 新增 `one_time_commission_amount` 字段
- `GET /api/admin/packages`: 返回结构变化,成本价和一次性佣金按用户视角返回
### 代码变更
- `internal/model/package.go`: Package 结构体字段调整
- `internal/model/shop_series_allocation.go`: 移除一次性佣金配置字段
- `internal/model/shop_package_allocation.go`: 新增一次性佣金金额字段
- `internal/model/dto/package_dto.go`: 请求/响应 DTO 调整
- `internal/model/dto/shop_series_allocation.go`: DTO 简化
- `internal/service/commission/`: 佣金计算逻辑适配链式分配
- `internal/handler/admin/package.go`: 套餐列表按用户视角返回
- `internal/task/commission_calculation.go`: 异步任务适配新逻辑
### 前端影响
- 套餐管理页面:移除价格字段,调整流量配置 UI
- 套餐分配页面:简化一次性佣金配置,改为只设置"给下级多少"
- 套餐列表页面:显示的成本价和一次性佣金需要理解为"自己视角"
### 数据迁移
- 需要迁移脚本处理历史数据:
- `Package.SuggestedCostPrice``Package.cost_price`(如果 `Price` 有值需要决定保留哪个)
- 已有的 `ShopSeriesAllocation` 一次性佣金配置需要迁移到新结构