Files
huang b18ecfeb55
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m29s
refactor: 一次性佣金配置从套餐级别提升到系列级别
主要变更:
- 新增 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)
- 删除过时的单元测试(已被验收测试覆盖)
2026-02-04 14:28:44 +08:00

6.0 KiB
Raw Permalink Blame History

Why

当前套餐与佣金系统存在概念模型与实现错位的问题:套餐价格字段过多且语义不清(PriceSuggestedCostPriceSuggestedRetailPrice 三个字段用途混乱),流量字段设计不支持真流量/虚流量共存机制,一次性佣金缺少链式分配能力(无法设置"给下级多少"),套餐分配与系列分配的关系不清晰。这导致接口入参混乱、不同模块的一致性被破坏、操作流程不是线性的。需要基于梳理清楚的业务模型进行系统性重构。

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_rechargefirst_recharge(首充)
  • BREAKING 新增链式分配能力:套餐分配时设置"给下级的一次性佣金金额"
  • 新增一次性佣金时效配置(永久/固定日期/相对时长)
  • 优化强充金额计算:首充时 max(首充要求, 套餐售价);累计充值时支持固定/动态差额两种模式
  • 新增梯度佣金统计范围开关(仅自己/自己+下级)

套餐分配统一

  • BREAKING 统一套餐分配模型:将一次性佣金额度配置移入套餐分配
  • 套餐系列仅定义一次性佣金"规则",分配时设置"给谁多少"
  • 代理只能看到自己能拿到的一次性佣金额度,不能看到总规则

累计充值机制完善

  • 明确累计范围:按卡/设备在该套餐系列下累计
  • 明确累计操作:只有"充值"操作累计,"直接购买套餐"不累计
  • 一次性佣金每张卡/设备只触发一次

代理视角优化

  • 不同用户调用同一套餐列表接口,看到不同的成本价(自己的成本价)
  • 不同用户看到不同的一次性佣金额度(自己能拿到的)

Capabilities

New Capabilities

  • commission-chain-distribution: 一次性佣金链式分配能力,支持在套餐分配时设置给下级的佣金金额,自动计算各级代理分得的佣金
  • package-virtual-data: 套餐真流量/虚流量共存机制,支持开关控制虚流量,停机判断基于配置选择使用哪个流量值
  • one-time-commission-validity: 一次性佣金时效管理,支持永久、固定到期日期、相对时长三种时效类型
  • accumulated-recharge-tracking: 累计充值追踪,按卡/设备在套餐系列下累计充值金额,只统计充值操作

Modified Capabilities

  • package-management: 移除 Pricedata_typedata_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: 移除 pricedata_typedata_amount_mb 字段,新增 enable_virtual_data 字段
  • tb_package_series: 新增一次性佣金时效字段(validity_typevalidity_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: 移除 pricedata_typedata_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.SuggestedCostPricePackage.cost_price(如果 Price 有值需要决定保留哪个)
    • 已有的 ShopSeriesAllocation 一次性佣金配置需要迁移到新结构