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

@@ -74,6 +74,9 @@ components:
minimum: 0
nullable: true
type: integer
enterprise_name:
description: 企业名称
type: string
id:
description: 账号ID
minimum: 0
@@ -86,6 +89,9 @@ components:
minimum: 0
nullable: true
type: integer
shop_name:
description: 店铺名称
type: string
status:
description: 状态 (0:禁用, 1:启用)
type: integer
@@ -632,23 +638,13 @@ components:
description: 设备号
type: string
type: object
DtoBaseCommissionConfig:
properties:
mode:
description: 返佣模式 (fixed:固定金额, percent:百分比)
type: string
value:
description: 返佣值分或千分比如200=20%
minimum: 0
type: integer
required:
- mode
- value
type: object
DtoBatchAllocatePackagesRequest:
properties:
base_commission:
$ref: '#/components/schemas/DtoBaseCommissionConfig'
one_time_commission_amount:
description: 该代理能拿到的一次性佣金(分)
minimum: 0
nullable: true
type: integer
price_adjustment:
$ref: '#/components/schemas/DtoPriceAdjustment'
series_id:
@@ -662,7 +658,6 @@ components:
required:
- shop_id
- series_id
- base_commission
type: object
DtoBatchSetCardSeriesBindngRequest:
properties:
@@ -1119,20 +1114,18 @@ components:
type: object
DtoCreatePackageRequest:
properties:
data_amount_mb:
description: 总流量额度(MB)
cost_price:
description: 成本价(分)
minimum: 0
nullable: true
type: integer
data_type:
description: 流量类型 (real:真流量, virtual:虚流量)
nullable: true
type: string
duration_months:
description: 套餐时长(月数)
maximum: 120
minimum: 1
type: integer
enable_virtual_data:
description: 是否启用虚流量
type: boolean
package_code:
description: 套餐编码
maxLength: 100
@@ -1146,10 +1139,6 @@ components:
package_type:
description: 套餐类型 (formal:正式套餐, addon:附加套餐)
type: string
price:
description: 套餐价格(分)
minimum: 0
type: integer
real_data_mb:
description: 真流量额度(MB)
minimum: 0
@@ -1160,11 +1149,6 @@ components:
minimum: 0
nullable: true
type: integer
suggested_cost_price:
description: 建议成本价(分)
minimum: 0
nullable: true
type: integer
suggested_retail_price:
description: 建议售价(分)
minimum: 0
@@ -1180,7 +1164,7 @@ components:
- package_name
- package_type
- duration_months
- price
- cost_price
type: object
DtoCreatePackageSeriesRequest:
properties:
@@ -1188,6 +1172,8 @@ components:
description: 描述
maxLength: 500
type: string
one_time_commission_config:
$ref: '#/components/schemas/DtoSeriesOneTimeCommissionConfigDTO'
series_code:
description: 系列编码
maxLength: 100
@@ -1279,7 +1265,7 @@ components:
DtoCreateShopPackageAllocationRequest:
properties:
cost_price:
description: 覆盖的成本价(分)
description: 该代理的成本价(分)
minimum: 0
type: integer
package_id:
@@ -1361,25 +1347,35 @@ components:
type: object
DtoCreateShopSeriesAllocationRequest:
properties:
base_commission:
$ref: '#/components/schemas/DtoBaseCommissionConfig'
enable_force_recharge:
description: 是否启用强充(累计充值强充)
description: 是否启用强制充值
nullable: true
type: boolean
enable_one_time_commission:
description: 是否启用一次性佣金
nullable: true
type: boolean
force_recharge_amount:
description: 充金额(分,0表示使用阈值金额)
description: 制充值金额(分)
minimum: 0
nullable: true
type: integer
force_recharge_trigger_type:
description: 强充触发类型(1:单次充值, 2:累计充值)
description: 强充触发类型 (1:单次充值, 2:累计充值)
nullable: true
type: integer
one_time_commission_config:
$ref: '#/components/schemas/DtoOneTimeCommissionConfig'
one_time_commission_amount:
description: 该代理能拿的一次性佣金金额上限(分)
minimum: 0
type: integer
one_time_commission_threshold:
description: 一次性佣金触发阈值(分)
minimum: 0
nullable: true
type: integer
one_time_commission_trigger:
description: 一次性佣金触发类型 (first_recharge:首次充值, accumulated_recharge:累计充值)
type: string
series_id:
description: 套餐系列ID
minimum: 0
@@ -1391,7 +1387,7 @@ components:
required:
- shop_id
- series_id
- base_commission
- one_time_commission_amount
type: object
DtoCreateWithdrawalSettingReq:
properties:
@@ -2205,9 +2201,6 @@ components:
card_category:
description: 卡业务类型 (normal:普通卡, industry:行业卡)
type: string
card_type:
description: 卡类型
type: string
carrier_id:
description: 运营商ID
minimum: 0
@@ -2530,57 +2523,26 @@ components:
description: 已提现佣金(分)
type: integer
type: object
DtoOneTimeCommissionConfig:
DtoOneTimeCommissionTierDTO:
properties:
mode:
description: 返佣模式 (fixed:固定金额, percent:百分比) - 固定类型时必填
amount:
description: 佣金金额(分)
minimum: 0
type: integer
dimension:
description: 统计维度 (sales_count:销量, sales_amount:销售额)
type: string
stat_scope:
description: 统计范围 (self:仅自己, self_and_sub:自己+下级)
type: string
threshold:
description: 最低阈值(分)
minimum: 1
type: integer
tiers:
description: 梯度档位列表 - 梯度类型时必填
items:
$ref: '#/components/schemas/DtoOneTimeCommissionTierEntry'
nullable: true
type: array
trigger:
description: 触发条件 (single_recharge:单次充值, accumulated_recharge:累计充值)
type: string
type:
description: 一次性佣金类型 (fixed:固定, tiered:梯度)
type: string
value:
description: 佣金金额(分)或比例(千分比)- 固定类型时必填
minimum: 1
description: 达标阈值
minimum: 0
type: integer
required:
- type
- trigger
- dimension
- threshold
type: object
DtoOneTimeCommissionTierEntry:
properties:
mode:
description: 返佣模式 (fixed:固定金额, percent:百分比)
type: string
threshold:
description: 梯度阈值(销量或销售额分)
minimum: 1
type: integer
tier_type:
description: 梯度类型 (sales_count:销量, sales_amount:销售额)
type: string
value:
description: 返佣值(分或千分比)
minimum: 1
type: integer
required:
- tier_type
- threshold
- mode
- value
- amount
type: object
DtoOrderItemResponse:
properties:
@@ -2720,8 +2682,7 @@ components:
DtoPackageResponse:
properties:
cost_price:
description: 成本价(分,仅代理用户可见)
nullable: true
description: 成本价(分)
type: integer
created_at:
description: 创建时间
@@ -2729,19 +2690,20 @@ components:
current_commission_rate:
description: 当前返佣比例(仅代理用户可见)
type: string
data_amount_mb:
description: 总流量额度(MB)
type: integer
data_type:
description: 流量类型 (real:真流量, virtual:虚流量)
type: string
duration_months:
description: 套餐时长(月数)
type: integer
enable_virtual_data:
description: 是否启用虚流量
type: boolean
id:
description: 套餐ID
minimum: 0
type: integer
one_time_commission_amount:
description: 一次性佣金金额(分,代理视角)
nullable: true
type: integer
package_code:
description: 套餐编码
type: string
@@ -2751,9 +2713,6 @@ components:
package_type:
description: 套餐类型 (formal:正式套餐, addon:附加套餐)
type: string
price:
description: 套餐价格(分)
type: integer
profit_margin:
description: 利润空间(分,仅代理用户可见)
nullable: true
@@ -2776,9 +2735,6 @@ components:
status:
description: 状态 (1:启用, 2:禁用)
type: integer
suggested_cost_price:
description: 建议成本价(分)
type: integer
suggested_retail_price:
description: 建议售价(分)
type: integer
@@ -2820,10 +2776,15 @@ components:
description:
description: 描述
type: string
enable_one_time_commission:
description: 是否启用一次性佣金
type: boolean
id:
description: 系列ID
minimum: 0
type: integer
one_time_commission_config:
$ref: '#/components/schemas/DtoSeriesOneTimeCommissionConfigDTO'
series_code:
description: 系列编码
type: string
@@ -3380,6 +3341,48 @@ components:
minimum: 0
type: integer
type: object
DtoSeriesOneTimeCommissionConfigDTO:
properties:
commission_amount:
description: 固定佣金金额commission_type=fixed时使用
minimum: 0
type: integer
commission_type:
description: 佣金类型 (fixed:固定, tiered:梯度)
type: string
enable:
description: 是否启用一次性佣金
type: boolean
enable_force_recharge:
description: 是否启用强充
type: boolean
force_amount:
description: 强充金额(分)
minimum: 0
type: integer
force_calc_type:
description: 强充计算类型 (fixed:固定, dynamic:动态)
type: string
threshold:
description: 触发阈值(分)
minimum: 0
type: integer
tiers:
description: 梯度配置列表commission_type=tiered时使用
items:
$ref: '#/components/schemas/DtoOneTimeCommissionTierDTO'
nullable: true
type: array
trigger_type:
description: 触发类型 (first_recharge:首充, accumulated_recharge:累计充值)
type: string
validity_type:
description: 时效类型 (permanent:永久, fixed_date:固定日期, relative:相对时长)
type: string
validity_value:
description: 时效值(日期或月数)
type: string
type: object
DtoSetSpeedLimitRequest:
properties:
download_speed:
@@ -3554,15 +3557,15 @@ components:
type: object
DtoShopPackageAllocationResponse:
properties:
allocation_id:
description: 关联的系列分配ID
allocator_shop_id:
description: 分配者店铺ID0表示平台分配
minimum: 0
type: integer
calculated_cost_price:
description: 原计算成本价(分),供参考
type: integer
allocator_shop_name:
description: 分配者店铺名称
type: string
cost_price:
description: 覆盖的成本价(分)
description: 该代理的成本价(分)
type: integer
created_at:
description: 创建时间
@@ -3581,6 +3584,18 @@ components:
package_name:
description: 套餐名称
type: string
series_allocation_id:
description: 关联的系列分配ID
minimum: 0
nullable: true
type: integer
series_id:
description: 套餐系列ID
minimum: 0
type: integer
series_name:
description: 套餐系列名称
type: string
shop_id:
description: 被分配的店铺ID
minimum: 0
@@ -3718,35 +3733,43 @@ components:
DtoShopSeriesAllocationResponse:
properties:
allocator_shop_id:
description: 分配者店铺ID
description: 分配者店铺ID0表示平台分配
minimum: 0
type: integer
allocator_shop_name:
description: 分配者店铺名称
type: string
base_commission:
$ref: '#/components/schemas/DtoBaseCommissionConfig'
created_at:
description: 创建时间
type: string
enable_force_recharge:
description: 是否启用强
description: 是否启用强制充值
type: boolean
enable_one_time_commission:
description: 是否启用一次性佣金
type: boolean
force_recharge_amount:
description: 充金额(分)
description: 制充值金额(分)
type: integer
force_recharge_trigger_type:
description: 强充触发类型(1:单次充值, 2:累计充值)
description: 强充触发类型 (1:单次充值, 2:累计充值)
type: integer
id:
description: 分配ID
minimum: 0
type: integer
one_time_commission_config:
$ref: '#/components/schemas/DtoOneTimeCommissionConfig'
one_time_commission_amount:
description: 该代理能拿的一次性佣金金额上限(分)
type: integer
one_time_commission_threshold:
description: 一次性佣金触发阈值(分)
type: integer
one_time_commission_trigger:
description: 一次性佣金触发类型
type: string
series_code:
description: 套餐系列编码
type: string
series_id:
description: 套餐系列ID
minimum: 0
@@ -3888,9 +3911,6 @@ components:
card_category:
description: 卡业务类型 (normal:普通卡, industry:行业卡)
type: string
card_type:
description: 卡类型
type: string
carrier_id:
description: 运营商ID
minimum: 0
@@ -4110,21 +4130,21 @@ components:
type: object
DtoUpdatePackageParams:
properties:
data_amount_mb:
description: 总流量额度(MB)
cost_price:
description: 成本价(分)
minimum: 0
nullable: true
type: integer
data_type:
description: 流量类型 (real:真流量, virtual:虚流量)
nullable: true
type: string
duration_months:
description: 套餐时长(月数)
maximum: 120
minimum: 1
nullable: true
type: integer
enable_virtual_data:
description: 是否启用虚流量
nullable: true
type: boolean
package_name:
description: 套餐名称
maxLength: 255
@@ -4135,11 +4155,6 @@ components:
description: 套餐类型 (formal:正式套餐, addon:附加套餐)
nullable: true
type: string
price:
description: 套餐价格(分)
minimum: 0
nullable: true
type: integer
real_data_mb:
description: 真流量额度(MB)
minimum: 0
@@ -4150,11 +4165,6 @@ components:
minimum: 0
nullable: true
type: integer
suggested_cost_price:
description: 建议成本价(分)
minimum: 0
nullable: true
type: integer
suggested_retail_price:
description: 建议售价(分)
minimum: 0
@@ -4173,6 +4183,8 @@ components:
maxLength: 500
nullable: true
type: string
one_time_commission_config:
$ref: '#/components/schemas/DtoSeriesOneTimeCommissionConfigDTO'
series_name:
description: 系列名称
maxLength: 255
@@ -4278,16 +4290,13 @@ components:
properties:
status:
description: 状态 (0:禁用, 1:启用)
maximum: 1
minimum: 0
nullable: true
type: integer
required:
- status
type: object
DtoUpdateShopPackageAllocationParams:
properties:
cost_price:
description: 覆盖的成本价(分)
description: 该代理的成本价(分)
minimum: 0
nullable: true
type: integer
@@ -4333,10 +4342,8 @@ components:
type: object
DtoUpdateShopSeriesAllocationParams:
properties:
base_commission:
$ref: '#/components/schemas/DtoBaseCommissionConfig'
enable_force_recharge:
description: 是否启用强充(累计充值强充)
description: 是否启用强制充值
nullable: true
type: boolean
enable_one_time_commission:
@@ -4344,15 +4351,32 @@ components:
nullable: true
type: boolean
force_recharge_amount:
description: 充金额(分,0表示使用阈值金额)
description: 制充值金额(分)
minimum: 0
nullable: true
type: integer
force_recharge_trigger_type:
description: 强充触发类型(1:单次充值, 2:累计充值)
description: 强充触发类型 (1:单次充值, 2:累计充值)
nullable: true
type: integer
one_time_commission_amount:
description: 该代理能拿的一次性佣金金额上限(分)
minimum: 0
nullable: true
type: integer
one_time_commission_threshold:
description: 一次性佣金触发阈值(分)
minimum: 0
nullable: true
type: integer
one_time_commission_trigger:
description: 一次性佣金触发类型
nullable: true
type: string
status:
description: 状态 (1:启用, 2:禁用)
nullable: true
type: integer
one_time_commission_config:
$ref: '#/components/schemas/DtoOneTimeCommissionConfig'
type: object
DtoUpdateStatusParams:
properties:
@@ -4853,6 +4877,22 @@ paths:
minimum: 0
nullable: true
type: integer
- description: 店铺ID筛选
in: query
name: shop_id
schema:
description: 店铺ID筛选
minimum: 1
nullable: true
type: integer
- description: 企业ID筛选
in: query
name: enterprise_id
schema:
description: 企业ID筛选
minimum: 1
nullable: true
type: integer
responses:
"200":
content:
@@ -11008,6 +11048,13 @@ paths:
description: 状态 (1:启用, 2:禁用)
nullable: true
type: integer
- description: 是否启用一次性佣金
in: query
name: enable_one_time_commission
schema:
description: 是否启用一次性佣金
nullable: true
type: boolean
responses:
"200":
content:
@@ -12823,6 +12870,22 @@ paths:
minimum: 0
nullable: true
type: integer
- description: 系列分配ID
in: query
name: series_allocation_id
schema:
description: 系列分配ID
minimum: 0
nullable: true
type: integer
- description: 分配者店铺ID
in: query
name: allocator_shop_id
schema:
description: 分配者店铺ID
minimum: 0
nullable: true
type: integer
- description: 状态 (1:启用, 2:禁用)
in: query
name: status
@@ -12885,7 +12948,7 @@ paths:
- BearerAuth: []
summary: 单套餐分配列表
tags:
- 套餐分配
- 套餐分配
post:
requestBody:
content:
@@ -12947,7 +13010,7 @@ paths:
- BearerAuth: []
summary: 创建单套餐分配
tags:
- 套餐分配
- 套餐分配
/api/admin/shop-package-allocations/{id}:
delete:
parameters:
@@ -12988,7 +13051,7 @@ paths:
- BearerAuth: []
summary: 删除单套餐分配
tags:
- 套餐分配
- 套餐分配
get:
parameters:
- description: ID
@@ -13054,7 +13117,7 @@ paths:
- BearerAuth: []
summary: 获取单套餐分配详情
tags:
- 套餐分配
- 套餐分配
put:
parameters:
- description: ID
@@ -13125,7 +13188,7 @@ paths:
- BearerAuth: []
summary: 更新单套餐分配
tags:
- 套餐分配
- 套餐分配
/api/admin/shop-package-allocations/{id}/cost-price:
put:
parameters:
@@ -13192,7 +13255,7 @@ paths:
- BearerAuth: []
summary: 更新单套餐分配成本价
tags:
- 套餐分配
- 套餐分配
/api/admin/shop-package-allocations/{id}/status:
put:
parameters:
@@ -13238,7 +13301,7 @@ paths:
- BearerAuth: []
summary: 更新单套餐分配状态
tags:
- 套餐分配
- 套餐分配
/api/admin/shop-package-batch-allocations:
post:
requestBody:
@@ -13373,6 +13436,14 @@ paths:
minimum: 0
nullable: true
type: integer
- description: 分配者店铺ID
in: query
name: allocator_shop_id
schema:
description: 分配者店铺ID
minimum: 0
nullable: true
type: integer
- description: 状态 (1:启用, 2:禁用)
in: query
name: status
@@ -13433,9 +13504,9 @@ paths:
description: 服务器内部错误
security:
- BearerAuth: []
summary: 套餐系列分配列表
summary: 系列分配列表
tags:
- 套餐系列分配
- 套餐分配
post:
requestBody:
content:
@@ -13495,9 +13566,9 @@ paths:
description: 服务器内部错误
security:
- BearerAuth: []
summary: 创建套餐系列分配
summary: 创建系列分配
tags:
- 套餐系列分配
- 套餐分配
/api/admin/shop-series-allocations/{id}:
delete:
parameters:
@@ -13536,9 +13607,9 @@ paths:
description: 服务器内部错误
security:
- BearerAuth: []
summary: 删除套餐系列分配
summary: 删除系列分配
tags:
- 套餐系列分配
- 套餐分配
get:
parameters:
- description: ID
@@ -13602,9 +13673,9 @@ paths:
description: 服务器内部错误
security:
- BearerAuth: []
summary: 获取套餐系列分配详情
summary: 获取系列分配详情
tags:
- 套餐系列分配
- 套餐分配
put:
parameters:
- description: ID
@@ -13673,55 +13744,9 @@ paths:
description: 服务器内部错误
security:
- BearerAuth: []
summary: 更新套餐系列分配
summary: 更新系列分配
tags:
- 套餐系列分配
/api/admin/shop-series-allocations/{id}/status:
put:
parameters:
- description: ID
in: path
name: id
required: true
schema:
description: ID
minimum: 0
type: integer
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/DtoUpdateStatusParams'
responses:
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 请求参数错误
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 未认证或认证已过期
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 无权访问
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 服务器内部错误
security:
- BearerAuth: []
summary: 更新套餐系列分配状态
tags:
- 套餐系列分配
- 套餐分配
/api/admin/shops:
get:
parameters: