清理冗余的梯度返佣(TierCommission)配置
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m46s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m46s
- 移除 Model 层:删除 ShopSeriesCommissionTier 模型及相关字段 - 更新 DTO:删除 TierCommissionConfig、TierEntry 类型及相关请求/响应字段 - 删除 Store 层:移除 ShopSeriesCommissionTierStore 及相关查询逻辑 - 简化 Service 层:删除梯度返佣处理逻辑,统计查询移除 tier_bonus 字段 - 数据库迁移:创建 000034_remove_tier_commission 移除相关表和字段 - 更新测试:移除梯度返佣相关测试用例,更新集成测试 - OpenAPI 文档:删除梯度返佣相关 schema 和枚举值 - 归档变更:归档 remove-tier-commission-redundancy 到 archive/2026-01-30- - 同步规范:更新 4 个主 specs,标记废弃功能并添加迁移指引 原因:梯度返佣功能与一次性梯度佣金功能重复,且从未实现实际计算逻辑 迁移:使用一次性佣金的梯度模式 (OneTimeCommissionConfig.type = "tiered") 替代
This commit is contained in:
@@ -610,9 +610,6 @@ components:
|
||||
properties:
|
||||
base_commission:
|
||||
$ref: '#/components/schemas/DtoBaseCommissionConfig'
|
||||
enable_tier_commission:
|
||||
description: 是否启用梯度返佣
|
||||
type: boolean
|
||||
price_adjustment:
|
||||
$ref: '#/components/schemas/DtoPriceAdjustment'
|
||||
series_id:
|
||||
@@ -623,8 +620,6 @@ components:
|
||||
description: 被分配的店铺ID
|
||||
minimum: 0
|
||||
type: integer
|
||||
tier_config:
|
||||
$ref: '#/components/schemas/DtoTierCommissionConfig'
|
||||
required:
|
||||
- shop_id
|
||||
- series_id
|
||||
@@ -841,15 +836,6 @@ components:
|
||||
one_time_percent:
|
||||
description: 一次性佣金占比(千分比)
|
||||
type: integer
|
||||
tier_bonus_amount:
|
||||
description: 梯度奖励收入(分)
|
||||
type: integer
|
||||
tier_bonus_count:
|
||||
description: 梯度奖励笔数
|
||||
type: integer
|
||||
tier_bonus_percent:
|
||||
description: 梯度奖励占比(千分比)
|
||||
type: integer
|
||||
total_amount:
|
||||
description: 总收入(分)
|
||||
type: integer
|
||||
@@ -1373,9 +1359,6 @@ components:
|
||||
enable_one_time_commission:
|
||||
description: 是否启用一次性佣金
|
||||
type: boolean
|
||||
enable_tier_commission:
|
||||
description: 是否启用梯度返佣
|
||||
type: boolean
|
||||
one_time_commission_config:
|
||||
$ref: '#/components/schemas/DtoOneTimeCommissionConfig'
|
||||
series_id:
|
||||
@@ -1386,8 +1369,6 @@ components:
|
||||
description: 被分配的店铺ID
|
||||
minimum: 0
|
||||
type: integer
|
||||
tier_config:
|
||||
$ref: '#/components/schemas/DtoTierCommissionConfig'
|
||||
required:
|
||||
- shop_id
|
||||
- series_id
|
||||
@@ -2478,7 +2459,7 @@ components:
|
||||
description: 佣金金额(分)
|
||||
type: integer
|
||||
commission_source:
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
type: string
|
||||
created_at:
|
||||
description: 创建时间
|
||||
@@ -3269,7 +3250,7 @@ components:
|
||||
description: 入账后佣金余额(分)
|
||||
type: integer
|
||||
commission_source:
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
type: string
|
||||
created_at:
|
||||
description: 佣金入账时间
|
||||
@@ -3545,9 +3526,6 @@ components:
|
||||
enable_one_time_commission:
|
||||
description: 是否启用一次性佣金
|
||||
type: boolean
|
||||
enable_tier_commission:
|
||||
description: 是否启用梯度返佣
|
||||
type: boolean
|
||||
id:
|
||||
description: 分配ID
|
||||
minimum: 0
|
||||
@@ -3767,43 +3745,6 @@ components:
|
||||
format: date-time
|
||||
type: string
|
||||
type: object
|
||||
DtoTierCommissionConfig:
|
||||
properties:
|
||||
period_type:
|
||||
description: 周期类型 (monthly:月度, quarterly:季度, yearly:年度)
|
||||
type: string
|
||||
tier_type:
|
||||
description: 梯度类型 (sales_count:销量, sales_amount:销售额)
|
||||
type: string
|
||||
tiers:
|
||||
description: 梯度档位列表
|
||||
items:
|
||||
$ref: '#/components/schemas/DtoTierEntry'
|
||||
nullable: true
|
||||
type: array
|
||||
required:
|
||||
- period_type
|
||||
- tier_type
|
||||
- tiers
|
||||
type: object
|
||||
DtoTierEntry:
|
||||
properties:
|
||||
mode:
|
||||
description: 达标后返佣模式 (fixed:固定金额, percent:百分比)
|
||||
type: string
|
||||
threshold:
|
||||
description: 阈值(销量或金额分)
|
||||
minimum: 1
|
||||
type: integer
|
||||
value:
|
||||
description: 达标后返佣值(分或千分比)
|
||||
minimum: 1
|
||||
type: integer
|
||||
required:
|
||||
- threshold
|
||||
- mode
|
||||
- value
|
||||
type: object
|
||||
DtoUnbindCardFromDeviceResponse:
|
||||
properties:
|
||||
message:
|
||||
@@ -4237,14 +4178,8 @@ components:
|
||||
description: 是否启用一次性佣金
|
||||
nullable: true
|
||||
type: boolean
|
||||
enable_tier_commission:
|
||||
description: 是否启用梯度返佣
|
||||
nullable: true
|
||||
type: boolean
|
||||
one_time_commission_config:
|
||||
$ref: '#/components/schemas/DtoOneTimeCommissionConfig'
|
||||
tier_config:
|
||||
$ref: '#/components/schemas/DtoTierCommissionConfig'
|
||||
type: object
|
||||
DtoUpdateStatusParams:
|
||||
properties:
|
||||
@@ -9515,11 +9450,11 @@ paths:
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
type: integer
|
||||
- description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
- description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
in: query
|
||||
name: commission_source
|
||||
schema:
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
nullable: true
|
||||
type: string
|
||||
- description: ICCID(模糊查询)
|
||||
@@ -14212,11 +14147,11 @@ paths:
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
type: integer
|
||||
- description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
- description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
in: query
|
||||
name: commission_source
|
||||
schema:
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)
|
||||
description: 佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)
|
||||
type: string
|
||||
- description: ICCID(模糊查询)
|
||||
in: query
|
||||
|
||||
@@ -112,10 +112,10 @@ func initServices(s *stores, deps *Dependencies) *services {
|
||||
AssetAllocationRecord: assetAllocationRecordSvc.New(deps.DB, s.AssetAllocationRecord, s.Shop, s.Account),
|
||||
Carrier: carrierSvc.New(s.Carrier),
|
||||
PackageSeries: packageSeriesSvc.New(s.PackageSeries),
|
||||
Package: packageSvc.New(s.Package, s.PackageSeries, s.ShopPackageAllocation, s.ShopSeriesAllocation, s.ShopSeriesCommissionTier),
|
||||
ShopSeriesAllocation: shopSeriesAllocationSvc.New(s.ShopSeriesAllocation, s.ShopSeriesCommissionTier, s.ShopSeriesAllocationConfig, s.ShopSeriesOneTimeCommissionTier, s.Shop, s.PackageSeries, s.Package),
|
||||
Package: packageSvc.New(s.Package, s.PackageSeries, s.ShopPackageAllocation, s.ShopSeriesAllocation),
|
||||
ShopSeriesAllocation: shopSeriesAllocationSvc.New(s.ShopSeriesAllocation, s.ShopSeriesAllocationConfig, s.ShopSeriesOneTimeCommissionTier, s.Shop, s.PackageSeries, s.Package),
|
||||
ShopPackageAllocation: shopPackageAllocationSvc.New(s.ShopPackageAllocation, s.ShopSeriesAllocation, s.ShopPackageAllocationPriceHistory, s.Shop, s.Package),
|
||||
ShopPackageBatchAllocation: shopPackageBatchAllocationSvc.New(deps.DB, s.Package, s.ShopSeriesAllocation, s.ShopPackageAllocation, s.ShopSeriesAllocationConfig, s.ShopSeriesCommissionTier, s.ShopSeriesCommissionStats, s.Shop),
|
||||
ShopPackageBatchAllocation: shopPackageBatchAllocationSvc.New(deps.DB, s.Package, s.ShopSeriesAllocation, s.ShopPackageAllocation, s.ShopSeriesAllocationConfig, s.ShopSeriesCommissionStats, s.Shop),
|
||||
ShopPackageBatchPricing: shopPackageBatchPricingSvc.New(deps.DB, s.ShopPackageAllocation, s.ShopPackageAllocationPriceHistory, s.Shop),
|
||||
CommissionStats: commissionStatsSvc.New(s.ShopSeriesCommissionStats),
|
||||
PurchaseValidation: purchaseValidation,
|
||||
|
||||
@@ -31,7 +31,6 @@ type stores struct {
|
||||
PackageSeries *postgres.PackageSeriesStore
|
||||
Package *postgres.PackageStore
|
||||
ShopSeriesAllocation *postgres.ShopSeriesAllocationStore
|
||||
ShopSeriesCommissionTier *postgres.ShopSeriesCommissionTierStore
|
||||
ShopSeriesOneTimeCommissionTier *postgres.ShopSeriesOneTimeCommissionTierStore
|
||||
ShopSeriesAllocationConfig *postgres.ShopSeriesAllocationConfigStore
|
||||
ShopPackageAllocation *postgres.ShopPackageAllocationStore
|
||||
@@ -69,7 +68,6 @@ func initStores(deps *Dependencies) *stores {
|
||||
PackageSeries: postgres.NewPackageSeriesStore(deps.DB),
|
||||
Package: postgres.NewPackageStore(deps.DB),
|
||||
ShopSeriesAllocation: postgres.NewShopSeriesAllocationStore(deps.DB),
|
||||
ShopSeriesCommissionTier: postgres.NewShopSeriesCommissionTierStore(deps.DB),
|
||||
ShopSeriesOneTimeCommissionTier: postgres.NewShopSeriesOneTimeCommissionTierStore(deps.DB),
|
||||
ShopSeriesAllocationConfig: postgres.NewShopSeriesAllocationConfigStore(deps.DB),
|
||||
ShopPackageAllocation: postgres.NewShopPackageAllocationStore(deps.DB),
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
// CommissionRecord 佣金记录模型
|
||||
// 记录各级代理的佣金入账情况
|
||||
// 包含成本价差收入、一次性佣金、梯度奖励等多种佣金来源
|
||||
// 包含成本价差收入和一次性佣金两种佣金来源
|
||||
type CommissionRecord struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
@@ -16,7 +16,7 @@ type CommissionRecord struct {
|
||||
OrderID uint `gorm:"column:order_id;index;not null;comment:订单ID" json:"order_id"`
|
||||
IotCardID *uint `gorm:"column:iot_card_id;index;comment:关联卡ID(可空)" json:"iot_card_id"`
|
||||
DeviceID *uint `gorm:"column:device_id;index;comment:关联设备ID(可空)" json:"device_id"`
|
||||
CommissionSource string `gorm:"column:commission_source;type:varchar(20);not null;index;comment:佣金来源 cost_diff-成本价差 one_time-一次性佣金 tier_bonus-梯度奖励" json:"commission_source"`
|
||||
CommissionSource string `gorm:"column:commission_source;type:varchar(20);not null;index;comment:佣金来源 cost_diff-成本价差 one_time-一次性佣金" json:"commission_source"`
|
||||
Amount int64 `gorm:"column:amount;type:bigint;not null;comment:佣金金额(分)" json:"amount"`
|
||||
BalanceAfter int64 `gorm:"column:balance_after;type:bigint;default:0;comment:入账后钱包余额(分)" json:"balance_after"`
|
||||
Status int `gorm:"column:status;type:int;default:1;not null;comment:状态 1-已入账 2-已失效" json:"status"`
|
||||
@@ -35,8 +35,6 @@ const (
|
||||
CommissionSourceCostDiff = "cost_diff"
|
||||
// CommissionSourceOneTime 一次性佣金
|
||||
CommissionSourceOneTime = "one_time"
|
||||
// CommissionSourceTierBonus 梯度奖励
|
||||
CommissionSourceTierBonus = "tier_bonus"
|
||||
)
|
||||
|
||||
// 佣金状态常量
|
||||
|
||||
@@ -2,15 +2,14 @@ package dto
|
||||
|
||||
// AllocationConfigResponse 配置版本响应
|
||||
type AllocationConfigResponse struct {
|
||||
ID uint `json:"id" description:"配置版本ID"`
|
||||
AllocationID uint `json:"allocation_id" description:"关联的分配ID"`
|
||||
Version int `json:"version" description:"配置版本号"`
|
||||
BaseCommissionMode string `json:"base_commission_mode" description:"基础返佣模式 (fixed:固定金额, percent:百分比)"`
|
||||
BaseCommissionValue int64 `json:"base_commission_value" description:"基础返佣值(分或千分比)"`
|
||||
EnableTierCommission bool `json:"enable_tier_commission" description:"是否启用梯度返佣"`
|
||||
EffectiveFrom string `json:"effective_from" description:"生效开始时间"`
|
||||
EffectiveTo string `json:"effective_to,omitempty" description:"生效结束时间(NULL表示当前生效)"`
|
||||
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||
ID uint `json:"id" description:"配置版本ID"`
|
||||
AllocationID uint `json:"allocation_id" description:"关联的分配ID"`
|
||||
Version int `json:"version" description:"配置版本号"`
|
||||
BaseCommissionMode string `json:"base_commission_mode" description:"基础返佣模式 (fixed:固定金额, percent:百分比)"`
|
||||
BaseCommissionValue int64 `json:"base_commission_value" description:"基础返佣值(分或千分比)"`
|
||||
EffectiveFrom string `json:"effective_from" description:"生效开始时间"`
|
||||
EffectiveTo string `json:"effective_to,omitempty" description:"生效结束时间(NULL表示当前生效)"`
|
||||
CreatedAt string `json:"created_at" description:"创建时间"`
|
||||
}
|
||||
|
||||
// AllocationConfigListResponse 配置版本列表响应
|
||||
|
||||
@@ -11,7 +11,7 @@ type CommissionRecordResponse struct {
|
||||
IotCardICCID string `json:"iot_card_iccid" description:"卡ICCID"`
|
||||
DeviceID *uint `json:"device_id" description:"关联设备ID"`
|
||||
DeviceNo string `json:"device_no" description:"设备号"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金)"`
|
||||
Amount int64 `json:"amount" description:"佣金金额(分)"`
|
||||
BalanceAfter int64 `json:"balance_after" description:"入账后钱包余额(分)"`
|
||||
Status int `json:"status" description:"状态 (1:已入账, 2:已失效)"`
|
||||
@@ -25,7 +25,7 @@ type CommissionRecordListRequest struct {
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||
ShopID *uint `json:"shop_id" query:"shop_id" validate:"omitempty" description:"店铺ID"`
|
||||
CommissionSource *string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time tier_bonus" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource *string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金)"`
|
||||
StartTime *string `json:"start_time" query:"start_time" validate:"omitempty" description:"开始时间"`
|
||||
EndTime *string `json:"end_time" query:"end_time" validate:"omitempty" description:"结束时间"`
|
||||
Status *int `json:"status" query:"status" validate:"omitempty,oneof=1 2" description:"状态 (1:已入账, 2:已失效)"`
|
||||
@@ -42,17 +42,14 @@ type CommissionRecordPageResult struct {
|
||||
|
||||
// CommissionStatsResponse 佣金统计响应
|
||||
type CommissionStatsResponse struct {
|
||||
TotalAmount int64 `json:"total_amount" description:"总收入(分)"`
|
||||
CostDiffAmount int64 `json:"cost_diff_amount" description:"成本价差收入(分)"`
|
||||
OneTimeAmount int64 `json:"one_time_amount" description:"一次性佣金收入(分)"`
|
||||
TierBonusAmount int64 `json:"tier_bonus_amount" description:"梯度奖励收入(分)"`
|
||||
CostDiffPercent int64 `json:"cost_diff_percent" description:"成本价差占比(千分比)"`
|
||||
OneTimePercent int64 `json:"one_time_percent" description:"一次性佣金占比(千分比)"`
|
||||
TierBonusPercent int64 `json:"tier_bonus_percent" description:"梯度奖励占比(千分比)"`
|
||||
TotalCount int64 `json:"total_count" description:"总笔数"`
|
||||
CostDiffCount int64 `json:"cost_diff_count" description:"成本价差笔数"`
|
||||
OneTimeCount int64 `json:"one_time_count" description:"一次性佣金笔数"`
|
||||
TierBonusCount int64 `json:"tier_bonus_count" description:"梯度奖励笔数"`
|
||||
TotalAmount int64 `json:"total_amount" description:"总收入(分)"`
|
||||
CostDiffAmount int64 `json:"cost_diff_amount" description:"成本价差收入(分)"`
|
||||
OneTimeAmount int64 `json:"one_time_amount" description:"一次性佣金收入(分)"`
|
||||
CostDiffPercent int64 `json:"cost_diff_percent" description:"成本价差占比(千分比)"`
|
||||
OneTimePercent int64 `json:"one_time_percent" description:"一次性佣金占比(千分比)"`
|
||||
TotalCount int64 `json:"total_count" description:"总笔数"`
|
||||
CostDiffCount int64 `json:"cost_diff_count" description:"成本价差笔数"`
|
||||
OneTimeCount int64 `json:"one_time_count" description:"一次性佣金笔数"`
|
||||
}
|
||||
|
||||
// DailyCommissionStatsResponse 每日佣金统计响应
|
||||
|
||||
@@ -41,7 +41,7 @@ type MyWithdrawalListReq struct {
|
||||
type MyCommissionRecordListReq struct {
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码"`
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量"`
|
||||
CommissionSource *string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time tier_bonus" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource *string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time tier_bonus" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)"`
|
||||
ICCID string `json:"iccid" query:"iccid" description:"ICCID(模糊查询)"`
|
||||
DeviceNo string `json:"device_no" query:"device_no" description:"设备号(模糊查询)"`
|
||||
OrderNo string `json:"order_no" query:"order_no" description:"订单号(模糊查询)"`
|
||||
@@ -51,7 +51,7 @@ type MyCommissionRecordItem struct {
|
||||
ID uint `json:"id" description:"佣金记录ID"`
|
||||
ShopID uint `json:"shop_id" description:"店铺ID"`
|
||||
OrderID uint `json:"order_id" description:"订单ID"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)"`
|
||||
Amount int64 `json:"amount" description:"佣金金额(分)"`
|
||||
Status int `json:"status" description:"状态 (1:已入账, 2:已失效)"`
|
||||
StatusName string `json:"status_name" description:"状态名称"`
|
||||
|
||||
@@ -96,7 +96,7 @@ type ShopCommissionRecordListReq struct {
|
||||
ShopID uint `json:"-" params:"shop_id" path:"shop_id" validate:"required" description:"店铺ID"`
|
||||
Page int `json:"page" query:"page" validate:"omitempty,min=1" minimum:"1" description:"页码(默认1)"`
|
||||
PageSize int `json:"page_size" query:"page_size" validate:"omitempty,min=1,max=100" minimum:"1" maximum:"100" description:"每页数量(默认20,最大100)"`
|
||||
CommissionSource string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time tier_bonus" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource string `json:"commission_source" query:"commission_source" validate:"omitempty,oneof=cost_diff one_time tier_bonus" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)"`
|
||||
ICCID string `json:"iccid" query:"iccid" validate:"omitempty,max=50" maxLength:"50" description:"ICCID(模糊查询)"`
|
||||
DeviceNo string `json:"device_no" query:"device_no" validate:"omitempty,max=50" maxLength:"50" description:"设备号(模糊查询)"`
|
||||
OrderNo string `json:"order_no" query:"order_no" validate:"omitempty,max=50" maxLength:"50" description:"订单号(模糊查询)"`
|
||||
@@ -107,7 +107,7 @@ type ShopCommissionRecordItem struct {
|
||||
ID uint `json:"id" description:"佣金记录ID"`
|
||||
Amount int64 `json:"amount" description:"佣金金额(分)"`
|
||||
BalanceAfter int64 `json:"balance_after" description:"入账后佣金余额(分)"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus:梯度奖励)"`
|
||||
CommissionSource string `json:"commission_source" description:"佣金来源 (cost_diff:成本价差, one_time:一次性佣金, tier_bonus(已废弃):梯度奖励)"`
|
||||
Status int `json:"status" description:"状态 (1:已入账, 2:已失效)"`
|
||||
StatusName string `json:"status_name" description:"状态名称"`
|
||||
OrderID uint `json:"order_id" description:"订单ID"`
|
||||
|
||||
@@ -8,12 +8,10 @@ type PriceAdjustment struct {
|
||||
|
||||
// BatchAllocatePackagesRequest 批量分配套餐请求
|
||||
type BatchAllocatePackagesRequest struct {
|
||||
ShopID uint `json:"shop_id" validate:"required" required:"true" description:"被分配的店铺ID"`
|
||||
SeriesID uint `json:"series_id" validate:"required" required:"true" description:"套餐系列ID"`
|
||||
PriceAdjustment *PriceAdjustment `json:"price_adjustment" validate:"omitempty" description:"可选加价配置"`
|
||||
BaseCommission BaseCommissionConfig `json:"base_commission" validate:"required" required:"true" description:"基础返佣配置"`
|
||||
EnableTierCommission bool `json:"enable_tier_commission" description:"是否启用梯度返佣"`
|
||||
TierConfig *TierCommissionConfig `json:"tier_config" validate:"omitempty" description:"梯度返佣配置(启用梯度返佣时必填)"`
|
||||
ShopID uint `json:"shop_id" validate:"required" required:"true" description:"被分配的店铺ID"`
|
||||
SeriesID uint `json:"series_id" validate:"required" required:"true" description:"套餐系列ID"`
|
||||
PriceAdjustment *PriceAdjustment `json:"price_adjustment" validate:"omitempty" description:"可选加价配置"`
|
||||
BaseCommission BaseCommissionConfig `json:"base_commission" validate:"required" required:"true" description:"基础返佣配置"`
|
||||
}
|
||||
|
||||
// BatchAllocatePackagesResponse 批量分配套餐响应
|
||||
|
||||
@@ -6,20 +6,6 @@ type BaseCommissionConfig struct {
|
||||
Value int64 `json:"value" validate:"required,min=0" required:"true" minimum:"0" description:"返佣值(分或千分比,如200=20%)"`
|
||||
}
|
||||
|
||||
// TierCommissionConfig 梯度返佣配置
|
||||
type TierCommissionConfig struct {
|
||||
PeriodType string `json:"period_type" validate:"required,oneof=monthly quarterly yearly" required:"true" description:"周期类型 (monthly:月度, quarterly:季度, yearly:年度)"`
|
||||
TierType string `json:"tier_type" validate:"required,oneof=sales_count sales_amount" required:"true" description:"梯度类型 (sales_count:销量, sales_amount:销售额)"`
|
||||
Tiers []TierEntry `json:"tiers" validate:"required,min=1,dive" required:"true" description:"梯度档位列表"`
|
||||
}
|
||||
|
||||
// TierEntry 梯度档位条目
|
||||
type TierEntry struct {
|
||||
Threshold int64 `json:"threshold" validate:"required,min=1" required:"true" minimum:"1" description:"阈值(销量或金额分)"`
|
||||
Mode string `json:"mode" validate:"required,oneof=fixed percent" required:"true" description:"达标后返佣模式 (fixed:固定金额, percent:百分比)"`
|
||||
Value int64 `json:"value" validate:"required,min=1" required:"true" minimum:"1" description:"达标后返佣值(分或千分比)"`
|
||||
}
|
||||
|
||||
// OneTimeCommissionConfig 一次性佣金配置
|
||||
type OneTimeCommissionConfig struct {
|
||||
Type string `json:"type" validate:"required,oneof=fixed tiered" required:"true" description:"一次性佣金类型 (fixed:固定, tiered:梯度)"`
|
||||
@@ -43,8 +29,6 @@ type CreateShopSeriesAllocationRequest struct {
|
||||
ShopID uint `json:"shop_id" validate:"required" required:"true" description:"被分配的店铺ID"`
|
||||
SeriesID uint `json:"series_id" validate:"required" required:"true" description:"套餐系列ID"`
|
||||
BaseCommission BaseCommissionConfig `json:"base_commission" validate:"required" required:"true" description:"基础返佣配置"`
|
||||
EnableTierCommission bool `json:"enable_tier_commission" description:"是否启用梯度返佣"`
|
||||
TierConfig *TierCommissionConfig `json:"tier_config" validate:"omitempty" description:"梯度返佣配置(启用梯度返佣时必填)"`
|
||||
EnableOneTimeCommission bool `json:"enable_one_time_commission" description:"是否启用一次性佣金"`
|
||||
OneTimeCommissionConfig *OneTimeCommissionConfig `json:"one_time_commission_config" validate:"omitempty" description:"一次性佣金配置(启用一次性佣金时必填)"`
|
||||
}
|
||||
@@ -52,8 +36,6 @@ type CreateShopSeriesAllocationRequest struct {
|
||||
// UpdateShopSeriesAllocationRequest 更新套餐系列分配请求
|
||||
type UpdateShopSeriesAllocationRequest struct {
|
||||
BaseCommission *BaseCommissionConfig `json:"base_commission" validate:"omitempty" description:"基础返佣配置"`
|
||||
EnableTierCommission *bool `json:"enable_tier_commission" description:"是否启用梯度返佣"`
|
||||
TierConfig *TierCommissionConfig `json:"tier_config" validate:"omitempty" description:"梯度返佣配置"`
|
||||
EnableOneTimeCommission *bool `json:"enable_one_time_commission" description:"是否启用一次性佣金"`
|
||||
OneTimeCommissionConfig *OneTimeCommissionConfig `json:"one_time_commission_config" validate:"omitempty" description:"一次性佣金配置"`
|
||||
}
|
||||
@@ -82,7 +64,6 @@ type ShopSeriesAllocationResponse struct {
|
||||
AllocatorShopID uint `json:"allocator_shop_id" description:"分配者店铺ID"`
|
||||
AllocatorShopName string `json:"allocator_shop_name" description:"分配者店铺名称"`
|
||||
BaseCommission BaseCommissionConfig `json:"base_commission" description:"基础返佣配置"`
|
||||
EnableTierCommission bool `json:"enable_tier_commission" description:"是否启用梯度返佣"`
|
||||
EnableOneTimeCommission bool `json:"enable_one_time_commission" description:"是否启用一次性佣金"`
|
||||
OneTimeCommissionConfig *OneTimeCommissionConfig `json:"one_time_commission_config,omitempty" description:"一次性佣金配置"`
|
||||
Status int `json:"status" description:"状态 (1:启用, 2:禁用)"`
|
||||
|
||||
@@ -9,13 +9,12 @@ import (
|
||||
// 分配者只能分配自己已被分配的套餐系列,且只能分配给直属下级
|
||||
type ShopSeriesAllocation struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
ShopID uint `gorm:"column:shop_id;index;not null;comment:被分配的店铺ID" json:"shop_id"`
|
||||
SeriesID uint `gorm:"column:series_id;index;not null;comment:套餐系列ID" json:"series_id"`
|
||||
AllocatorShopID uint `gorm:"column:allocator_shop_id;index;not null;comment:分配者店铺ID(上级)" json:"allocator_shop_id"`
|
||||
BaseCommissionMode string `gorm:"column:base_commission_mode;type:varchar(20);not null;default:percent;comment:基础返佣模式 fixed-固定金额 percent-百分比" json:"base_commission_mode"`
|
||||
BaseCommissionValue int64 `gorm:"column:base_commission_value;type:bigint;not null;default:0;comment:基础返佣值(分或千分比,如200=20%)" json:"base_commission_value"`
|
||||
EnableTierCommission bool `gorm:"column:enable_tier_commission;type:boolean;not null;default:false;comment:是否启用梯度返佣" json:"enable_tier_commission"`
|
||||
BaseModel `gorm:"embedded"`
|
||||
ShopID uint `gorm:"column:shop_id;index;not null;comment:被分配的店铺ID" json:"shop_id"`
|
||||
SeriesID uint `gorm:"column:series_id;index;not null;comment:套餐系列ID" json:"series_id"`
|
||||
AllocatorShopID uint `gorm:"column:allocator_shop_id;index;not null;comment:分配者店铺ID(上级)" json:"allocator_shop_id"`
|
||||
BaseCommissionMode string `gorm:"column:base_commission_mode;type:varchar(20);not null;default:percent;comment:基础返佣模式 fixed-固定金额 percent-百分比" json:"base_commission_mode"`
|
||||
BaseCommissionValue int64 `gorm:"column:base_commission_value;type:bigint;not null;default:0;comment:基础返佣值(分或千分比,如200=20%)" json:"base_commission_value"`
|
||||
|
||||
// 一次性佣金配置
|
||||
EnableOneTimeCommission bool `gorm:"column:enable_one_time_commission;type:boolean;not null;default:false;comment:是否启用一次性佣金" json:"enable_one_time_commission"`
|
||||
|
||||
@@ -11,13 +11,12 @@ import (
|
||||
// 支持配置追溯和数据一致性保障
|
||||
type ShopSeriesAllocationConfig struct {
|
||||
gorm.Model
|
||||
AllocationID uint `gorm:"column:allocation_id;index;not null;comment:关联的分配ID" json:"allocation_id"`
|
||||
Version int `gorm:"column:version;type:int;not null;comment:配置版本号" json:"version"`
|
||||
BaseCommissionMode string `gorm:"column:base_commission_mode;type:varchar(20);not null;comment:基础返佣模式(配置快照)" json:"base_commission_mode"`
|
||||
BaseCommissionValue int64 `gorm:"column:base_commission_value;type:bigint;not null;comment:基础返佣值(配置快照)" json:"base_commission_value"`
|
||||
EnableTierCommission bool `gorm:"column:enable_tier_commission;type:boolean;not null;comment:是否启用梯度返佣(配置快照)" json:"enable_tier_commission"`
|
||||
EffectiveFrom time.Time `gorm:"column:effective_from;type:timestamptz;not null;comment:生效开始时间" json:"effective_from"`
|
||||
EffectiveTo *time.Time `gorm:"column:effective_to;type:timestamptz;comment:生效结束时间(NULL表示当前生效)" json:"effective_to"`
|
||||
AllocationID uint `gorm:"column:allocation_id;index;not null;comment:关联的分配ID" json:"allocation_id"`
|
||||
Version int `gorm:"column:version;type:int;not null;comment:配置版本号" json:"version"`
|
||||
BaseCommissionMode string `gorm:"column:base_commission_mode;type:varchar(20);not null;comment:基础返佣模式(配置快照)" json:"base_commission_mode"`
|
||||
BaseCommissionValue int64 `gorm:"column:base_commission_value;type:bigint;not null;comment:基础返佣值(配置快照)" json:"base_commission_value"`
|
||||
EffectiveFrom time.Time `gorm:"column:effective_from;type:timestamptz;not null;comment:生效开始时间" json:"effective_from"`
|
||||
EffectiveTo *time.Time `gorm:"column:effective_to;type:timestamptz;comment:生效结束时间(NULL表示当前生效)" json:"effective_to"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// ShopSeriesCommissionTier 梯度佣金配置模型
|
||||
// 基于销量或销售额配置不同档位的返佣比例提升
|
||||
// 支持月度、季度、年度、自定义周期的统计
|
||||
type ShopSeriesCommissionTier struct {
|
||||
gorm.Model
|
||||
BaseModel `gorm:"embedded"`
|
||||
AllocationID uint `gorm:"column:allocation_id;index;not null;comment:关联的分配ID" json:"allocation_id"`
|
||||
TierType string `gorm:"column:tier_type;type:varchar(20);not null;comment:梯度类型 sales_count-销量 sales_amount-销售额" json:"tier_type"`
|
||||
PeriodType string `gorm:"column:period_type;type:varchar(20);not null;comment:周期类型 monthly-月度 quarterly-季度 yearly-年度 custom-自定义" json:"period_type"`
|
||||
PeriodStartDate *time.Time `gorm:"column:period_start_date;comment:自定义周期开始日期" json:"period_start_date"`
|
||||
PeriodEndDate *time.Time `gorm:"column:period_end_date;comment:自定义周期结束日期" json:"period_end_date"`
|
||||
ThresholdValue int64 `gorm:"column:threshold_value;type:bigint;not null;comment:阈值(销量或金额分)" json:"threshold_value"`
|
||||
CommissionMode string `gorm:"column:commission_mode;type:varchar(20);not null;default:percent;comment:达标后返佣模式 fixed-固定金额 percent-百分比" json:"commission_mode"`
|
||||
CommissionValue int64 `gorm:"column:commission_value;type:bigint;not null;comment:达标后返佣值(分或千分比)" json:"commission_value"`
|
||||
}
|
||||
|
||||
// TableName 指定表名
|
||||
func (ShopSeriesCommissionTier) TableName() string {
|
||||
return "tb_shop_series_commission_tier"
|
||||
}
|
||||
|
||||
// 梯度类型常量
|
||||
const (
|
||||
// TierTypeSalesCount 销量梯度
|
||||
TierTypeSalesCount = "sales_count"
|
||||
// TierTypeSalesAmount 销售额梯度
|
||||
TierTypeSalesAmount = "sales_amount"
|
||||
)
|
||||
|
||||
// 周期类型常量
|
||||
const (
|
||||
// PeriodTypeMonthly 月度
|
||||
PeriodTypeMonthly = "monthly"
|
||||
// PeriodTypeQuarterly 季度
|
||||
PeriodTypeQuarterly = "quarterly"
|
||||
// PeriodTypeYearly 年度
|
||||
PeriodTypeYearly = "yearly"
|
||||
// PeriodTypeCustom 自定义
|
||||
PeriodTypeCustom = "custom"
|
||||
)
|
||||
@@ -23,12 +23,14 @@ func (ShopSeriesOneTimeCommissionTier) TableName() string {
|
||||
return "tb_shop_series_one_time_commission_tier"
|
||||
}
|
||||
|
||||
// 梯度类型常量(复用 ShopSeriesCommissionTier 的常量)
|
||||
// TierTypeSalesCount = "sales_count" // 销量梯度
|
||||
// TierTypeSalesAmount = "sales_amount" // 销售额梯度
|
||||
// 这些常量已在 shop_series_commission_tier.go 中定义
|
||||
// 梯度类型常量
|
||||
const (
|
||||
// TierTypeSalesCount 销量梯度
|
||||
TierTypeSalesCount = "sales_count"
|
||||
// TierTypeSalesAmount 销售额梯度
|
||||
TierTypeSalesAmount = "sales_amount"
|
||||
)
|
||||
|
||||
// 返佣模式常量(复用 ShopSeriesAllocation 的常量)
|
||||
// CommissionModeFixed = "fixed" // 固定金额返佣
|
||||
// CommissionModePercent = "percent" // 百分比返佣(千分比)
|
||||
// 这些常量已在 shop_series_allocation.go 中定义
|
||||
// 返佣模式常量在 shop_series_allocation.go 中定义
|
||||
// CommissionModeFixed = "fixed"
|
||||
// CommissionModePercent = "percent"
|
||||
|
||||
@@ -387,25 +387,21 @@ func (s *Service) GetStats(ctx context.Context, req *dto.CommissionStatsRequest)
|
||||
return &dto.CommissionStatsResponse{}, nil
|
||||
}
|
||||
|
||||
var costDiffPercent, oneTimePercent, tierBonusPercent int64
|
||||
var costDiffPercent, oneTimePercent int64
|
||||
if stats.TotalAmount > 0 {
|
||||
costDiffPercent = stats.CostDiffAmount * 1000 / stats.TotalAmount
|
||||
oneTimePercent = stats.OneTimeAmount * 1000 / stats.TotalAmount
|
||||
tierBonusPercent = stats.TierBonusAmount * 1000 / stats.TotalAmount
|
||||
}
|
||||
|
||||
return &dto.CommissionStatsResponse{
|
||||
TotalAmount: stats.TotalAmount,
|
||||
CostDiffAmount: stats.CostDiffAmount,
|
||||
OneTimeAmount: stats.OneTimeAmount,
|
||||
TierBonusAmount: stats.TierBonusAmount,
|
||||
CostDiffPercent: costDiffPercent,
|
||||
OneTimePercent: oneTimePercent,
|
||||
TierBonusPercent: tierBonusPercent,
|
||||
TotalCount: stats.TotalCount,
|
||||
CostDiffCount: stats.CostDiffCount,
|
||||
OneTimeCount: stats.OneTimeCount,
|
||||
TierBonusCount: stats.TierBonusCount,
|
||||
TotalAmount: stats.TotalAmount,
|
||||
CostDiffAmount: stats.CostDiffAmount,
|
||||
OneTimeAmount: stats.OneTimeAmount,
|
||||
CostDiffPercent: costDiffPercent,
|
||||
OneTimePercent: oneTimePercent,
|
||||
TotalCount: stats.TotalCount,
|
||||
CostDiffCount: stats.CostDiffCount,
|
||||
OneTimeCount: stats.OneTimeCount,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ type Service struct {
|
||||
packageSeriesStore *postgres.PackageSeriesStore
|
||||
packageAllocationStore *postgres.ShopPackageAllocationStore
|
||||
seriesAllocationStore *postgres.ShopSeriesAllocationStore
|
||||
commissionTierStore *postgres.ShopSeriesCommissionTierStore
|
||||
}
|
||||
|
||||
func New(
|
||||
@@ -29,14 +28,12 @@ func New(
|
||||
packageSeriesStore *postgres.PackageSeriesStore,
|
||||
packageAllocationStore *postgres.ShopPackageAllocationStore,
|
||||
seriesAllocationStore *postgres.ShopSeriesAllocationStore,
|
||||
commissionTierStore *postgres.ShopSeriesCommissionTierStore,
|
||||
) *Service {
|
||||
return &Service{
|
||||
packageStore: packageStore,
|
||||
packageSeriesStore: packageSeriesStore,
|
||||
packageAllocationStore: packageAllocationStore,
|
||||
seriesAllocationStore: seriesAllocationStore,
|
||||
commissionTierStore: commissionTierStore,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,20 +401,5 @@ func (s *Service) getCommissionInfo(ctx context.Context, allocationID uint) *dto
|
||||
info.CurrentRate = fmt.Sprintf("%.1f%%", float64(seriesAllocation.BaseCommissionValue)/10)
|
||||
}
|
||||
|
||||
if seriesAllocation.EnableTierCommission {
|
||||
tiers, err := s.commissionTierStore.ListByAllocationID(ctx, allocationID)
|
||||
if err == nil && len(tiers) > 0 {
|
||||
tier := tiers[0]
|
||||
info.NextThreshold = &tier.ThresholdValue
|
||||
if tier.CommissionMode == constants.CommissionModeFixed {
|
||||
nextRate := fmt.Sprintf("%.2f元/单", float64(tier.CommissionValue)/100)
|
||||
info.NextRate = nextRate
|
||||
} else {
|
||||
nextRate := fmt.Sprintf("%.1f%%", float64(tier.CommissionValue)/10)
|
||||
info.NextRate = nextRate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func TestPackageService_Create(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -98,7 +98,7 @@ func TestPackageService_UpdateStatus(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -168,7 +168,7 @@ func TestPackageService_UpdateShelfStatus(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -255,7 +255,7 @@ func TestPackageService_Get(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -293,7 +293,7 @@ func TestPackageService_Update(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -342,7 +342,7 @@ func TestPackageService_Delete(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -377,7 +377,7 @@ func TestPackageService_List(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
@@ -460,7 +460,7 @@ func TestPackageService_SeriesNameInResponse(t *testing.T) {
|
||||
tx := testutils.NewTestTransaction(t)
|
||||
packageStore := postgres.NewPackageStore(tx)
|
||||
packageSeriesStore := postgres.NewPackageSeriesStore(tx)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil, nil)
|
||||
svc := New(packageStore, packageSeriesStore, nil, nil)
|
||||
|
||||
ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
|
||||
UserID: 1,
|
||||
|
||||
@@ -19,7 +19,6 @@ type Service struct {
|
||||
seriesAllocationStore *postgres.ShopSeriesAllocationStore
|
||||
packageAllocationStore *postgres.ShopPackageAllocationStore
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore
|
||||
commissionTierStore *postgres.ShopSeriesCommissionTierStore
|
||||
commissionStatsStore *postgres.ShopSeriesCommissionStatsStore
|
||||
shopStore *postgres.ShopStore
|
||||
}
|
||||
@@ -30,7 +29,6 @@ func New(
|
||||
seriesAllocationStore *postgres.ShopSeriesAllocationStore,
|
||||
packageAllocationStore *postgres.ShopPackageAllocationStore,
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore,
|
||||
commissionTierStore *postgres.ShopSeriesCommissionTierStore,
|
||||
commissionStatsStore *postgres.ShopSeriesCommissionStatsStore,
|
||||
shopStore *postgres.ShopStore,
|
||||
) *Service {
|
||||
@@ -40,7 +38,6 @@ func New(
|
||||
seriesAllocationStore: seriesAllocationStore,
|
||||
packageAllocationStore: packageAllocationStore,
|
||||
configStore: configStore,
|
||||
commissionTierStore: commissionTierStore,
|
||||
commissionStatsStore: commissionStatsStore,
|
||||
shopStore: shopStore,
|
||||
}
|
||||
@@ -84,14 +81,13 @@ func (s *Service) BatchAllocate(ctx context.Context, req *dto.BatchAllocatePacka
|
||||
|
||||
return s.db.Transaction(func(tx *gorm.DB) error {
|
||||
seriesAllocation := &model.ShopSeriesAllocation{
|
||||
BaseModel: model.BaseModel{Creator: currentUserID, Updater: currentUserID},
|
||||
ShopID: req.ShopID,
|
||||
SeriesID: req.SeriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
EnableTierCommission: req.EnableTierCommission,
|
||||
Status: constants.StatusEnabled,
|
||||
BaseModel: model.BaseModel{Creator: currentUserID, Updater: currentUserID},
|
||||
ShopID: req.ShopID,
|
||||
SeriesID: req.SeriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
|
||||
if err := tx.Create(seriesAllocation).Error; err != nil {
|
||||
@@ -100,12 +96,11 @@ func (s *Service) BatchAllocate(ctx context.Context, req *dto.BatchAllocatePacka
|
||||
|
||||
now := time.Now()
|
||||
config := &model.ShopSeriesAllocationConfig{
|
||||
AllocationID: seriesAllocation.ID,
|
||||
Version: 1,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
EnableTierCommission: req.EnableTierCommission,
|
||||
EffectiveFrom: now,
|
||||
AllocationID: seriesAllocation.ID,
|
||||
Version: 1,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
EffectiveFrom: now,
|
||||
}
|
||||
|
||||
if err := tx.Create(config).Error; err != nil {
|
||||
@@ -134,12 +129,6 @@ func (s *Service) BatchAllocate(ctx context.Context, req *dto.BatchAllocatePacka
|
||||
return errors.Wrap(errors.CodeInternalError, err, "批量创建套餐分配失败")
|
||||
}
|
||||
|
||||
if req.EnableTierCommission && req.TierConfig != nil {
|
||||
if err := s.createCommissionTiers(tx, seriesAllocation.ID, req.TierConfig, currentUserID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -170,23 +159,3 @@ func (s *Service) calculateAdjustedPrice(basePrice int64, adjustment *dto.PriceA
|
||||
|
||||
return basePrice + (basePrice * adjustment.Value / 1000)
|
||||
}
|
||||
|
||||
func (s *Service) createCommissionTiers(tx *gorm.DB, allocationID uint, config *dto.TierCommissionConfig, creatorID uint) error {
|
||||
for _, tierReq := range config.Tiers {
|
||||
tier := &model.ShopSeriesCommissionTier{
|
||||
BaseModel: model.BaseModel{Creator: creatorID, Updater: creatorID},
|
||||
AllocationID: allocationID,
|
||||
PeriodType: config.PeriodType,
|
||||
TierType: config.TierType,
|
||||
ThresholdValue: tierReq.Threshold,
|
||||
CommissionMode: tierReq.Mode,
|
||||
CommissionValue: tierReq.Value,
|
||||
}
|
||||
|
||||
if err := tx.Create(tier).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeInternalError, err, "创建佣金梯度失败")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@ import (
|
||||
|
||||
type Service struct {
|
||||
allocationStore *postgres.ShopSeriesAllocationStore
|
||||
tierStore *postgres.ShopSeriesCommissionTierStore
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore
|
||||
oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore
|
||||
shopStore *postgres.ShopStore
|
||||
@@ -26,7 +25,6 @@ type Service struct {
|
||||
|
||||
func New(
|
||||
allocationStore *postgres.ShopSeriesAllocationStore,
|
||||
tierStore *postgres.ShopSeriesCommissionTierStore,
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore,
|
||||
oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore,
|
||||
shopStore *postgres.ShopStore,
|
||||
@@ -35,7 +33,6 @@ func New(
|
||||
) *Service {
|
||||
return &Service{
|
||||
allocationStore: allocationStore,
|
||||
tierStore: tierStore,
|
||||
configStore: configStore,
|
||||
oneTimeCommissionTierStore: oneTimeCommissionTierStore,
|
||||
shopStore: shopStore,
|
||||
@@ -106,13 +103,12 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesAllocatio
|
||||
}
|
||||
|
||||
allocation := &model.ShopSeriesAllocation{
|
||||
ShopID: req.ShopID,
|
||||
SeriesID: req.SeriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
EnableTierCommission: req.EnableTierCommission,
|
||||
Status: constants.StatusEnabled,
|
||||
ShopID: req.ShopID,
|
||||
SeriesID: req.SeriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: req.BaseCommission.Mode,
|
||||
BaseCommissionValue: req.BaseCommission.Value,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
|
||||
// 处理一次性佣金配置
|
||||
@@ -192,12 +188,6 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateShopSeries
|
||||
allocation.BaseCommissionMode = req.BaseCommission.Mode
|
||||
allocation.BaseCommissionValue = req.BaseCommission.Value
|
||||
}
|
||||
if req.EnableTierCommission != nil {
|
||||
if allocation.EnableTierCommission != *req.EnableTierCommission {
|
||||
configChanged = true
|
||||
}
|
||||
allocation.EnableTierCommission = *req.EnableTierCommission
|
||||
}
|
||||
|
||||
enableOneTimeCommission := allocation.EnableOneTimeCommission
|
||||
if req.EnableOneTimeCommission != nil {
|
||||
@@ -409,7 +399,6 @@ func (s *Service) buildResponse(ctx context.Context, a *model.ShopSeriesAllocati
|
||||
Mode: a.BaseCommissionMode,
|
||||
Value: a.BaseCommissionValue,
|
||||
},
|
||||
EnableTierCommission: a.EnableTierCommission,
|
||||
EnableOneTimeCommission: a.EnableOneTimeCommission,
|
||||
Status: a.Status,
|
||||
CreatedAt: a.CreatedAt.Format(time.RFC3339),
|
||||
@@ -458,12 +447,11 @@ func (s *Service) createNewConfigVersion(ctx context.Context, allocation *model.
|
||||
}
|
||||
|
||||
newConfig := &model.ShopSeriesAllocationConfig{
|
||||
AllocationID: allocation.ID,
|
||||
Version: newVersion,
|
||||
BaseCommissionMode: allocation.BaseCommissionMode,
|
||||
BaseCommissionValue: allocation.BaseCommissionValue,
|
||||
EnableTierCommission: allocation.EnableTierCommission,
|
||||
EffectiveFrom: now,
|
||||
AllocationID: allocation.ID,
|
||||
Version: newVersion,
|
||||
BaseCommissionMode: allocation.BaseCommissionMode,
|
||||
BaseCommissionValue: allocation.BaseCommissionValue,
|
||||
EffectiveFrom: now,
|
||||
}
|
||||
|
||||
if err := s.configStore.Create(ctx, newConfig); err != nil {
|
||||
|
||||
@@ -96,14 +96,12 @@ func (s *CommissionRecordStore) ListByShopID(ctx context.Context, opts *store.Qu
|
||||
}
|
||||
|
||||
type CommissionStats struct {
|
||||
TotalAmount int64
|
||||
CostDiffAmount int64
|
||||
OneTimeAmount int64
|
||||
TierBonusAmount int64
|
||||
TotalCount int64
|
||||
CostDiffCount int64
|
||||
OneTimeCount int64
|
||||
TierBonusCount int64
|
||||
TotalAmount int64
|
||||
CostDiffAmount int64
|
||||
OneTimeAmount int64
|
||||
TotalCount int64
|
||||
CostDiffCount int64
|
||||
OneTimeCount int64
|
||||
}
|
||||
|
||||
func (s *CommissionRecordStore) GetStats(ctx context.Context, filters *CommissionRecordListFilters) (*CommissionStats, error) {
|
||||
@@ -128,11 +126,9 @@ func (s *CommissionRecordStore) GetStats(ctx context.Context, filters *Commissio
|
||||
COALESCE(SUM(amount), 0) as total_amount,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'cost_diff' THEN amount ELSE 0 END), 0) as cost_diff_amount,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'one_time' THEN amount ELSE 0 END), 0) as one_time_amount,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'tier_bonus' THEN amount ELSE 0 END), 0) as tier_bonus_amount,
|
||||
COUNT(*) as total_count,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'cost_diff' THEN 1 ELSE 0 END), 0) as cost_diff_count,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'one_time' THEN 1 ELSE 0 END), 0) as one_time_count,
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'tier_bonus' THEN 1 ELSE 0 END), 0) as tier_bonus_count
|
||||
COALESCE(SUM(CASE WHEN commission_source = 'one_time' THEN 1 ELSE 0 END), 0) as one_time_count
|
||||
`).Scan(&stats)
|
||||
|
||||
if result.Error != nil {
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type ShopSeriesCommissionTierStore struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewShopSeriesCommissionTierStore(db *gorm.DB) *ShopSeriesCommissionTierStore {
|
||||
return &ShopSeriesCommissionTierStore{db: db}
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) Create(ctx context.Context, tier *model.ShopSeriesCommissionTier) error {
|
||||
return s.db.WithContext(ctx).Create(tier).Error
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) GetByID(ctx context.Context, id uint) (*model.ShopSeriesCommissionTier, error) {
|
||||
var tier model.ShopSeriesCommissionTier
|
||||
if err := s.db.WithContext(ctx).First(&tier, id).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tier, nil
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) Update(ctx context.Context, tier *model.ShopSeriesCommissionTier) error {
|
||||
return s.db.WithContext(ctx).Save(tier).Error
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) Delete(ctx context.Context, id uint) error {
|
||||
return s.db.WithContext(ctx).Delete(&model.ShopSeriesCommissionTier{}, id).Error
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) ListByAllocationID(ctx context.Context, allocationID uint) ([]*model.ShopSeriesCommissionTier, error) {
|
||||
var tiers []*model.ShopSeriesCommissionTier
|
||||
if err := s.db.WithContext(ctx).
|
||||
Where("allocation_id = ?", allocationID).
|
||||
Order("threshold_value ASC").
|
||||
Find(&tiers).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return tiers, nil
|
||||
}
|
||||
|
||||
func (s *ShopSeriesCommissionTierStore) DeleteByAllocationID(ctx context.Context, allocationID uint) error {
|
||||
return s.db.WithContext(ctx).
|
||||
Where("allocation_id = ?", allocationID).
|
||||
Delete(&model.ShopSeriesCommissionTier{}).Error
|
||||
}
|
||||
@@ -53,22 +53,6 @@ func (h *CommissionStatsUpdateHandler) HandleCommissionStatsUpdate(ctx context.C
|
||||
return asynq.SkipRetry
|
||||
}
|
||||
|
||||
allocation, err := h.allocationStore.GetByID(ctx, payload.AllocationID)
|
||||
if err != nil {
|
||||
h.logger.Error("获取分配记录失败",
|
||||
zap.Uint("allocation_id", payload.AllocationID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return asynq.SkipRetry
|
||||
}
|
||||
|
||||
if !allocation.EnableTierCommission {
|
||||
h.logger.Info("分配未启用梯度返佣,跳过统计更新",
|
||||
zap.Uint("allocation_id", payload.AllocationID),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
period := getCurrentPeriod(now)
|
||||
redisKey := constants.RedisCommissionStatsKey(payload.AllocationID, period)
|
||||
|
||||
39
migrations/000034_remove_tier_commission.down.sql
Normal file
39
migrations/000034_remove_tier_commission.down.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
-- 回滚: 恢复梯度返佣(TierCommission)相关的表和字段
|
||||
-- 注意: 此回滚仅恢复表结构,不恢复已删除的数据
|
||||
|
||||
-- 1. 重新创建 tb_shop_series_commission_tier 表
|
||||
CREATE TABLE IF NOT EXISTS tb_shop_series_commission_tier (
|
||||
id SERIAL PRIMARY KEY,
|
||||
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
deleted_at TIMESTAMP WITH TIME ZONE,
|
||||
creator INT NOT NULL DEFAULT 0,
|
||||
updater INT NOT NULL DEFAULT 0,
|
||||
allocation_id INT NOT NULL,
|
||||
tier_type VARCHAR(20) NOT NULL,
|
||||
period_type VARCHAR(20) NOT NULL,
|
||||
period_start_date TIMESTAMP WITH TIME ZONE,
|
||||
period_end_date TIMESTAMP WITH TIME ZONE,
|
||||
threshold_value BIGINT NOT NULL,
|
||||
commission_mode VARCHAR(20) NOT NULL DEFAULT 'percent',
|
||||
commission_value BIGINT NOT NULL
|
||||
);
|
||||
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.tier_type IS '梯度类型 sales_count-销量 sales_amount-销售额';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.period_type IS '周期类型 monthly-月度 quarterly-季度 yearly-年度 custom-自定义';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.period_start_date IS '自定义周期开始日期';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.period_end_date IS '自定义周期结束日期';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.threshold_value IS '阈值(销量或金额分)';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.commission_mode IS '达标后返佣模式 fixed-固定金额 percent-百分比';
|
||||
COMMENT ON COLUMN tb_shop_series_commission_tier.commission_value IS '达标后返佣值(分或千分比)';
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_tier_allocation_id ON tb_shop_series_commission_tier(allocation_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_tier_deleted_at ON tb_shop_series_commission_tier(deleted_at);
|
||||
|
||||
-- 2. 恢复 tb_shop_series_allocation 表的 enable_tier_commission 字段
|
||||
ALTER TABLE tb_shop_series_allocation ADD COLUMN IF NOT EXISTS enable_tier_commission BOOLEAN NOT NULL DEFAULT FALSE;
|
||||
COMMENT ON COLUMN tb_shop_series_allocation.enable_tier_commission IS '是否启用梯度返佣';
|
||||
|
||||
-- 3. 恢复 tb_shop_series_allocation_config 表的 enable_tier_commission 字段
|
||||
ALTER TABLE tb_shop_series_allocation_config ADD COLUMN IF NOT EXISTS enable_tier_commission BOOLEAN NOT NULL;
|
||||
COMMENT ON COLUMN tb_shop_series_allocation_config.enable_tier_commission IS '是否启用梯度返佣(配置快照)';
|
||||
11
migrations/000034_remove_tier_commission.up.sql
Normal file
11
migrations/000034_remove_tier_commission.up.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- 删除梯度返佣(TierCommission)相关的表和字段
|
||||
-- 本次变更将简化佣金配置模型,只保留基础返佣和一次性佣金两种机制
|
||||
|
||||
-- 1. 删除 tb_shop_series_allocation 表的 enable_tier_commission 字段
|
||||
ALTER TABLE tb_shop_series_allocation DROP COLUMN IF EXISTS enable_tier_commission;
|
||||
|
||||
-- 2. 删除 tb_shop_series_allocation_config 表的 enable_tier_commission 字段
|
||||
ALTER TABLE tb_shop_series_allocation_config DROP COLUMN IF EXISTS enable_tier_commission;
|
||||
|
||||
-- 3. 删除 tb_shop_series_commission_tier 表
|
||||
DROP TABLE IF EXISTS tb_shop_series_commission_tier;
|
||||
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-01-30
|
||||
@@ -0,0 +1,355 @@
|
||||
## Context
|
||||
|
||||
当前系统中存在两套梯度佣金配置机制:
|
||||
|
||||
1. **TierCommission (梯度返佣)**:通过 `tb_shop_series_commission_tier` 表存储,支持按周期(月/季/年)和类型(销量/销售额)设置梯度奖励
|
||||
2. **OneTimeCommission.tiered (一次性梯度佣金)**:通过 `tb_shop_series_one_time_commission_tier` 表存储,支持按销量或销售额设置一次性梯度奖励
|
||||
|
||||
通过代码探索发现:
|
||||
- `TierCommission` 有完整的数据库表、Model、DTO、Store 定义
|
||||
- 但在 `commission_calculation` 服务中**没有实际的计算逻辑**
|
||||
- `CommissionSourceTierBonus` 常量被定义但从未在佣金计算中使用
|
||||
- 统计查询中预留了 `tier_bonus_amount` 等字段,但永远为 0
|
||||
|
||||
实际业务需求是:**基础返佣(成本价差)+ 一次性佣金(固定或梯度)** 两种机制。
|
||||
|
||||
由于系统尚未上线,现在是清理冗余代码的最佳时机。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- 删除所有与 `TierCommission` (梯度返佣) 相关的代码和数据库结构
|
||||
- 简化佣金配置模型,只保留基础返佣和一次性佣金两种机制
|
||||
- 更新 API 文档和集成测试,确保 API 契约清晰
|
||||
- 确保佣金计算逻辑继续正常工作(不受删除影响)
|
||||
|
||||
**Non-Goals:**
|
||||
- 不修改一次性佣金的现有逻辑(OneTimeCommission 保持不变)
|
||||
- 不修改基础返佣的现有逻辑(base_commission 保持不变)
|
||||
- 不涉及数据迁移(系统未上线,无历史数据)
|
||||
- 不重构佣金计算的核心流程
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: 数据库迁移策略
|
||||
|
||||
**选择**: 创建新的 migration 文件删除表和字段
|
||||
|
||||
**理由**:
|
||||
- 系统未上线,无需保留历史数据
|
||||
- 使用标准的 migration 流程便于版本控制和回滚
|
||||
- 迁移文件编号使用下一个递增编号(查看 `migrations/` 目录获取最新编号)
|
||||
|
||||
**替代方案及其劣势**:
|
||||
- ❌ 直接修改现有 migration 文件:违反 migration 不可变原则
|
||||
- ❌ 手动执行 SQL:缺乏版本控制,团队协作困难
|
||||
|
||||
**Migration 内容**:
|
||||
```sql
|
||||
-- up migration
|
||||
ALTER TABLE tb_shop_series_allocation DROP COLUMN IF EXISTS enable_tier_commission;
|
||||
ALTER TABLE tb_shop_series_allocation_config DROP COLUMN IF EXISTS enable_tier_commission;
|
||||
DROP TABLE IF EXISTS tb_shop_series_commission_tier;
|
||||
|
||||
-- down migration (恢复结构,用于紧急回滚)
|
||||
CREATE TABLE IF NOT EXISTS tb_shop_series_commission_tier (...);
|
||||
ALTER TABLE tb_shop_series_allocation ADD COLUMN enable_tier_commission BOOLEAN DEFAULT FALSE;
|
||||
ALTER TABLE tb_shop_series_allocation_config ADD COLUMN enable_tier_commission BOOLEAN;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Decision 2: DTO 字段删除策略
|
||||
|
||||
**选择**: 直接删除 `TierCommissionConfig`、`TierEntry` 类型,以及所有引用这些类型的字段
|
||||
|
||||
**理由**:
|
||||
- 系统未上线,无 API 兼容性负担
|
||||
- 清晰的 API 契约更利于前端开发
|
||||
- 避免"字段存在但不可用"的混淆状态
|
||||
|
||||
**替代方案及其劣势**:
|
||||
- ❌ 保留字段但标记为 deprecated:增加维护成本,前端可能误用
|
||||
- ❌ 使用 API 版本控制(v2):过度设计,系统尚未发布 v1
|
||||
|
||||
**影响的 DTO**:
|
||||
- `CreateShopSeriesAllocationRequest`: 删除 `EnableTierCommission` 和 `TierConfig` 字段
|
||||
- `UpdateShopSeriesAllocationRequest`: 删除 `EnableTierCommission` 和 `TierConfig` 字段
|
||||
- `ShopSeriesAllocationResponse`: 删除 `EnableTierCommission` 字段
|
||||
- `TierCommissionConfig` 和 `TierEntry`: 整个类型删除
|
||||
|
||||
---
|
||||
|
||||
### Decision 3: Store 层清理策略
|
||||
|
||||
**选择**: 完全删除 `ShopSeriesCommissionTierStore` 及其实现
|
||||
|
||||
**理由**:
|
||||
- 该 Store 没有被任何业务逻辑调用
|
||||
- 删除后减少依赖注入复杂度
|
||||
- 避免未来误用
|
||||
|
||||
**需要修改的依赖注入位置**:
|
||||
- `internal/bootstrap/wire.go` (或依赖注入配置文件):删除 `ShopSeriesCommissionTierStore` 的 provider
|
||||
- `internal/service/shop_series_allocation/service.go`:删除结构体中的 `tierStore` 字段(如果存在)
|
||||
|
||||
---
|
||||
|
||||
### Decision 4: 常量和枚举清理策略
|
||||
|
||||
**选择**: 删除 `CommissionSourceTierBonus` 常量,更新所有相关注释和文档
|
||||
|
||||
**理由**:
|
||||
- 该常量从未在佣金计算中使用
|
||||
- 保留会误导开发者以为该功能可用
|
||||
- 佣金来源枚举简化为两个值:`cost_diff`、`one_time`
|
||||
|
||||
**需要更新的位置**:
|
||||
- `internal/model/commission.go`: 删除 `CommissionSourceTierBonus` 常量定义
|
||||
- `migrations/000029_add_one_time_commission.up.sql`: 更新 `commission_source` 字段注释
|
||||
- 所有相关的 API 文档和 DTO 注释
|
||||
|
||||
---
|
||||
|
||||
### Decision 5: 统计查询更新策略
|
||||
|
||||
**选择**: 删除统计查询中的 `tier_bonus` 相关字段和 SQL 逻辑
|
||||
|
||||
**理由**:
|
||||
- 这些字段永远为 0,无实际价值
|
||||
- 简化 SQL 查询提升性能
|
||||
- 减少前端展示的无用信息
|
||||
|
||||
**需要修改的位置**:
|
||||
- `internal/store/postgres/commission_record_store.go`:
|
||||
- 删除 `TierBonusAmount`、`TierBonusCount` 字段定义
|
||||
- 删除 SQL 中的 `COALESCE(SUM(CASE WHEN commission_source = 'tier_bonus' ...))` 语句
|
||||
- `internal/model/dto/commission.go`:
|
||||
- 删除 `CommissionStatsResponse` 中的 `TierBonusAmount`、`TierBonusCount`、`TierBonusPercent` 字段
|
||||
- `internal/service/my_commission/service.go`:
|
||||
- 删除 `tierBonusPercent` 的计算逻辑
|
||||
|
||||
---
|
||||
|
||||
### Decision 6: 测试更新策略
|
||||
|
||||
**选择**: 删除所有与 `enable_tier_commission` 相关的测试用例,添加验证佣金来源枚举的测试
|
||||
|
||||
**理由**:
|
||||
- 测试应反映实际业务需求
|
||||
- 删除无效测试提高测试套件可维护性
|
||||
- 添加枚举验证测试确保不会误用 `tier_bonus`
|
||||
|
||||
**需要修改的测试**:
|
||||
- `tests/integration/shop_series_allocation_test.go`: 删除包含 `enable_tier_commission` 的测试场景
|
||||
- `tests/integration/shop_package_batch_allocation_test.go`: 删除 tier_config 相关的测试数据
|
||||
- 添加新测试:验证创建 `commission_source = "tier_bonus"` 的佣金记录会失败
|
||||
|
||||
---
|
||||
|
||||
### Decision 7: Service 层清理策略
|
||||
|
||||
**选择**: 删除 `shop_series_allocation` Service 中处理 `tier_config` 的逻辑
|
||||
|
||||
**理由**:
|
||||
- Service 层应只处理有效的业务逻辑
|
||||
- 删除无用代码降低认知负担
|
||||
|
||||
**需要修改的位置**:
|
||||
- `internal/service/shop_series_allocation/service.go`:
|
||||
- 删除 `validateTierConfig()` 方法(如果存在)
|
||||
- 删除创建/更新分配时对 `TierConfig` 的处理逻辑
|
||||
- 删除 `tierStore` 的依赖注入字段
|
||||
|
||||
---
|
||||
|
||||
### Decision 8: 验证逻辑更新
|
||||
|
||||
**选择**: 更新 DTO 验证规则,确保不接受 `tier_bonus` 作为佣金来源
|
||||
|
||||
**理由**:
|
||||
- 在 API 入口层就拦截无效输入
|
||||
- 提供清晰的错误提示
|
||||
|
||||
**实现方式**:
|
||||
- 使用 Validator 的 `oneof` 标签限制 `commission_source` 只能是 `cost_diff` 或 `one_time`
|
||||
- 在 `CommissionRecordListRequest` 等 DTO 中更新验证规则
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
### Risk 1: 误删除正在使用的代码
|
||||
|
||||
**风险**: 虽然探索显示 `TierCommission` 未被使用,但可能有未被发现的引用
|
||||
|
||||
**缓解措施**:
|
||||
- 在删除前使用 IDE 的 "Find Usages" 功能全局搜索所有引用
|
||||
- 运行完整的测试套件确保没有编译错误
|
||||
- 代码审查时重点检查删除的影响范围
|
||||
- 保留完整的 git 历史,必要时可快速回滚
|
||||
|
||||
---
|
||||
|
||||
### Risk 2: API 契约变更可能影响前端开发
|
||||
|
||||
**风险**: 前端可能已经基于旧的 API 文档开发
|
||||
|
||||
**缓解措施**:
|
||||
- 与前端团队同步变更内容
|
||||
- 更新 OpenAPI 文档并生成新的 TypeScript 类型定义
|
||||
- 由于系统未上线,前端调整成本较低
|
||||
|
||||
---
|
||||
|
||||
### Risk 3: Migration 执行失败
|
||||
|
||||
**风险**: 删除表/字段的 migration 可能因数据库权限或锁问题失败
|
||||
|
||||
**缓解措施**:
|
||||
- 在开发环境先测试 migration
|
||||
- 使用 `DROP ... IF EXISTS` 避免重复执行报错
|
||||
- 提供完整的 down migration 支持回滚
|
||||
- 记录执行步骤和常见问题排查指南
|
||||
|
||||
---
|
||||
|
||||
### Risk 4: 佣金统计查询变更可能影响性能
|
||||
|
||||
**风险**: 删除 SQL 中的 `tier_bonus` 分支后,查询性能可能有微小波动
|
||||
|
||||
**缓解措施**:
|
||||
- 简化 SQL 逻辑理论上会提升性能
|
||||
- 在测试环境执行性能测试对比
|
||||
- 监控线上查询耗时(虽然系统未上线,为未来做准备)
|
||||
|
||||
**Trade-off**:
|
||||
- 获得:更简洁的代码和更快的统计查询
|
||||
- 失去:未来如果需要重新引入梯度返佣,需要重新实现(但根据业务需求,这种可能性很低)
|
||||
|
||||
## Migration Plan
|
||||
|
||||
### Phase 1: 代码清理(本地开发)
|
||||
|
||||
1. **删除 Model 和 DTO**
|
||||
- 删除 `internal/model/shop_series_commission_tier.go`
|
||||
- 更新 `internal/model/dto/shop_series_allocation.go`
|
||||
- 更新 `internal/model/dto/commission.go`
|
||||
- 删除 `internal/model/commission.go` 中的 `CommissionSourceTierBonus`
|
||||
|
||||
2. **删除 Store 层**
|
||||
- 删除 `internal/store/postgres/shop_series_commission_tier_store.go`
|
||||
- 删除 `internal/store/interface.go` 中的 `ShopSeriesCommissionTierStore` 接口定义
|
||||
- 更新 `internal/store/postgres/commission_record_store.go` 的统计查询
|
||||
|
||||
3. **更新 Service 层**
|
||||
- 更新 `internal/service/shop_series_allocation/service.go`
|
||||
- 更新 `internal/service/my_commission/service.go`
|
||||
- 删除依赖注入中的 `tierStore` 引用
|
||||
|
||||
4. **更新 Handler 层**
|
||||
- 更新 `internal/handler/shop_series_allocation_handler.go`(如有必要)
|
||||
|
||||
5. **更新依赖注入**
|
||||
- 更新 `internal/bootstrap/wire.go` 或相关配置文件
|
||||
|
||||
6. **运行测试验证**
|
||||
```bash
|
||||
go test ./...
|
||||
```
|
||||
|
||||
### Phase 2: 数据库迁移(本地验证)
|
||||
|
||||
1. **创建 migration 文件**
|
||||
- 查看 `migrations/` 目录最新编号
|
||||
- 创建新的 migration 文件(如 `000030_remove_tier_commission.up.sql`)
|
||||
|
||||
2. **本地执行 migration**
|
||||
```bash
|
||||
go run cmd/migrate/main.go up
|
||||
```
|
||||
|
||||
3. **验证数据库结构**
|
||||
```sql
|
||||
\d tb_shop_series_allocation
|
||||
\d tb_shop_series_allocation_config
|
||||
\dt tb_shop_series_commission_tier -- 应返回不存在
|
||||
```
|
||||
|
||||
### Phase 3: 测试更新(本地验证)
|
||||
|
||||
1. **删除无效测试**
|
||||
- 更新 `tests/integration/shop_series_allocation_test.go`
|
||||
- 更新 `tests/integration/shop_package_batch_allocation_test.go`
|
||||
|
||||
2. **添加验证测试**
|
||||
- 添加测试验证 `commission_source = "tier_bonus"` 被拒绝
|
||||
|
||||
3. **运行完整测试套件**
|
||||
```bash
|
||||
go test -v ./tests/integration/...
|
||||
```
|
||||
|
||||
### Phase 4: 文档更新
|
||||
|
||||
1. **更新 OpenAPI 文档**
|
||||
- 删除 `TierCommissionConfig` schema
|
||||
- 更新受影响的 API 端点定义
|
||||
|
||||
2. **生成新的文档**
|
||||
```bash
|
||||
make generate-docs # 或相应的命令
|
||||
```
|
||||
|
||||
### Phase 5: 代码审查和合并
|
||||
|
||||
1. **提交 Pull Request**
|
||||
- 标题:`清理冗余的梯度返佣(TierCommission)配置`
|
||||
- 描述:引用 proposal 和 design 文档
|
||||
|
||||
2. **代码审查重点**
|
||||
- 确认所有引用都已删除
|
||||
- 验证测试覆盖率
|
||||
- 检查 migration 正确性
|
||||
|
||||
3. **合并到主分支**
|
||||
|
||||
### Phase 6: 部署(未来上线时)
|
||||
|
||||
1. **开发环境验证**
|
||||
2. **测试环境验证**
|
||||
3. **生产环境部署**(虽然当前系统未上线)
|
||||
|
||||
### Rollback Strategy
|
||||
|
||||
如果发现问题需要回滚:
|
||||
|
||||
1. **代码回滚**:
|
||||
```bash
|
||||
git revert <commit-hash>
|
||||
```
|
||||
|
||||
2. **数据库回滚**:
|
||||
```bash
|
||||
go run cmd/migrate/main.go down
|
||||
```
|
||||
|
||||
3. **验证回滚成功**:
|
||||
- 运行测试套件
|
||||
- 检查数据库结构恢复
|
||||
|
||||
## Open Questions
|
||||
|
||||
1. **是否需要通知前端团队**?
|
||||
- 状态:待确认
|
||||
- 建议:由于 API 契约变更,应提前同步
|
||||
|
||||
2. **是否需要在变更日志中记录此次清理**?
|
||||
- 状态:待确认
|
||||
- 建议:记录在 CHANGELOG.md 中,标记为 "BREAKING CHANGE"(虽然系统未上线)
|
||||
|
||||
3. **OpenAPI 文档的更新流程是什么**?
|
||||
- 状态:待确认
|
||||
- 需要了解项目中是如何生成和维护 OpenAPI 文档的
|
||||
|
||||
4. **是否有其他依赖于 `tb_shop_series_commission_tier` 表的外部系统**?
|
||||
- 状态:待确认
|
||||
- 建议:检查是否有数据分析、报表系统等外部依赖
|
||||
@@ -0,0 +1,88 @@
|
||||
## Why
|
||||
|
||||
当前套餐系列分配中存在两套梯度佣金配置:一个是 `TierCommission`(梯度返佣),另一个是 `OneTimeCommission.tiered`(一次性梯度佣金)。这两者功能高度重复,导致概念混淆。经过探索发现,`TierCommission` 仅有数据库表和 DTO 定义,但没有实际的计算逻辑实现,而系统实际需要的佣金机制是:**基础返佣(成本价差)+ 一次性佣金(固定或梯度)**。因此需要删除冗余的 `TierCommission` 相关代码,简化佣金配置模型。
|
||||
|
||||
## What Changes
|
||||
|
||||
- **删除数据库表和字段**
|
||||
- 删除 `tb_shop_series_commission_tier` 表(梯度返佣配置表)
|
||||
- 删除 `tb_shop_series_allocation.enable_tier_commission` 字段
|
||||
- 删除 `tb_shop_series_allocation_config.enable_tier_commission` 字段(配置快照表)
|
||||
|
||||
- **删除 Model 和 DTO**
|
||||
- 删除 `internal/model/shop_series_commission_tier.go` 模型
|
||||
- 删除 `internal/model/dto/shop_series_allocation.go` 中的 `TierCommissionConfig` 和 `TierEntry` 类型
|
||||
- 删除 `CreateShopSeriesAllocationRequest` 和 `UpdateShopSeriesAllocationRequest` 中的 `EnableTierCommission` 和 `TierConfig` 字段
|
||||
- 删除 `ShopSeriesAllocationResponse` 中的 `EnableTierCommission` 字段
|
||||
|
||||
- **删除 Store 层**
|
||||
- 删除 `internal/store/postgres/shop_series_commission_tier_store.go` 及其接口定义
|
||||
|
||||
- **删除常量和枚举**
|
||||
- 删除 `internal/model/commission.go` 中的 `CommissionSourceTierBonus` 常量
|
||||
- 更新佣金来源说明(从三种改为两种:`cost_diff`、`one_time`)
|
||||
|
||||
- **更新统计和查询逻辑**
|
||||
- 删除佣金统计中的 `TierBonusAmount`、`TierBonusCount`、`TierBonusPercent` 字段
|
||||
- 更新 `internal/model/dto/commission.go` 中的 `CommissionStatsResponse`
|
||||
- 更新 `internal/store/postgres/commission_record_store.go` 中的统计查询 SQL
|
||||
|
||||
- **删除相关测试**
|
||||
- 删除 `tests/integration/shop_series_allocation_test.go` 中与 `enable_tier_commission` 相关的测试用例
|
||||
|
||||
- **创建数据库迁移**
|
||||
- 创建 down migration 删除 `enable_tier_commission` 字段和 `tb_shop_series_commission_tier` 表
|
||||
|
||||
- **更新 API 文档**
|
||||
- 更新 OpenAPI 规范,删除 `TierCommissionConfig` 相关的 schema 定义
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
无新增 capability。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
- `shop-series-allocation`: 删除梯度返佣配置要求,简化为只支持基础返佣和一次性佣金两种机制
|
||||
- `shop-commission-tier`: **整个 capability 将被废弃**,因为梯度返佣功能完全移除
|
||||
- `commission-calculation`: 删除 `tier_bonus` 佣金来源,明确只支持 `cost_diff` 和 `one_time` 两种佣金来源
|
||||
- `commission-record-query`: 删除梯度奖励相关的统计字段(`tier_bonus_amount`、`tier_bonus_count`、`tier_bonus_percent`)
|
||||
|
||||
## Impact
|
||||
|
||||
**受影响的代码模块**:
|
||||
- Handler: `internal/handler/shop_series_allocation_handler.go`(删除 tier_config 参数处理)
|
||||
- Service: `internal/service/shop_series_allocation/service.go`(删除 tier 相关业务逻辑)
|
||||
- Store: `internal/store/postgres/shop_series_commission_tier_store.go`(整个文件删除)
|
||||
- Store: `internal/store/postgres/commission_record_store.go`(删除 tier_bonus 统计)
|
||||
- Model: `internal/model/shop_series_commission_tier.go`(整个文件删除)
|
||||
- DTO: `internal/model/dto/shop_series_allocation.go`(删除 TierCommissionConfig)
|
||||
- DTO: `internal/model/dto/commission.go`(删除 tier_bonus 统计字段)
|
||||
|
||||
**受影响的 API 端点**:
|
||||
- `POST /api/shop-series-allocations` - 请求体删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- `PUT /api/shop-series-allocations/:id` - 请求体删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- `GET /api/shop-series-allocations` - 响应删除 `enable_tier_commission` 字段
|
||||
- `GET /api/shop-series-allocations/:id` - 响应删除 `enable_tier_commission` 字段
|
||||
- `GET /api/my-commission/stats` - 响应删除 `tier_bonus_amount`、`tier_bonus_count`、`tier_bonus_percent` 字段
|
||||
|
||||
**数据库迁移**:
|
||||
- 需要创建新的 migration 删除 `tb_shop_series_commission_tier` 表
|
||||
- 需要删除 `tb_shop_series_allocation` 和 `tb_shop_series_allocation_config` 表中的 `enable_tier_commission` 字段
|
||||
|
||||
**依赖关系**:
|
||||
- 删除 `ShopSeriesCommissionTierStore` 的依赖注入
|
||||
|
||||
**破坏性变更**:
|
||||
- **BREAKING**: API 请求/响应结构变更(删除字段)
|
||||
- **BREAKING**: 数据库表结构变更
|
||||
- **注**: 由于系统尚未上线,无历史数据兼容性问题
|
||||
|
||||
**测试影响**:
|
||||
- 需要更新集成测试用例,删除 `enable_tier_commission` 相关的测试场景
|
||||
- 需要验证佣金计算逻辑仍然正常工作(只计算 cost_diff 和 one_time)
|
||||
|
||||
**性能影响**:
|
||||
- 正面影响:简化数据模型,减少无用的表 JOIN 和查询
|
||||
- 佣金统计查询性能提升(减少一个条件分支)
|
||||
@@ -0,0 +1,17 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: CommissionRecord 模型简化
|
||||
|
||||
系统 MUST 简化 CommissionRecord 模型,移除冻结相关字段。
|
||||
|
||||
#### Scenario: 新佣金记录字段
|
||||
- **WHEN** 创建佣金记录
|
||||
- **THEN** 包含:shop_id, order_id, iot_card_id, device_id, commission_source, amount, balance_after, status, released_at, remark
|
||||
|
||||
#### Scenario: 佣金来源类型
|
||||
- **WHEN** 创建佣金记录
|
||||
- **THEN** commission_source 为以下之一:cost_diff(成本价差)、one_time(一次性佣金)
|
||||
|
||||
#### Scenario: 不再支持梯度奖励来源
|
||||
- **WHEN** 尝试创建 commission_source = "tier_bonus" 的佣金记录
|
||||
- **THEN** 系统拒绝并返回错误 "不支持的佣金来源类型"
|
||||
@@ -0,0 +1,39 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: 按佣金来源筛选
|
||||
|
||||
系统 SHALL 支持按佣金来源筛选佣金记录。
|
||||
|
||||
#### Scenario: 按成本价差筛选
|
||||
- **WHEN** 指定 commission_source 为 cost_diff
|
||||
- **THEN** 系统只返回成本价差类型的佣金记录
|
||||
|
||||
#### Scenario: 按一次性佣金筛选
|
||||
- **WHEN** 指定 commission_source 为 one_time
|
||||
- **THEN** 系统只返回一次性佣金类型的佣金记录
|
||||
|
||||
#### Scenario: 使用已废弃的佣金来源筛选
|
||||
- **WHEN** 指定 commission_source 为 tier_bonus
|
||||
- **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** 系统只统计该时间范围内的佣金
|
||||
@@ -0,0 +1,47 @@
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: 配置梯度佣金
|
||||
|
||||
**原内容**: 系统 SHALL 允许代理为套餐系列分配配置梯度佣金。每个梯度包含:梯度类型(销量/销售额)、周期类型(月度/季度/年度)、阈值、达标后的返佣配置(返佣模式和返佣值)。
|
||||
|
||||
**Reason**: 整个店铺返佣梯度管理 capability 被废弃。梯度返佣功能与一次性梯度佣金功能重复,且梯度返佣从未实现实际的佣金计算逻辑。系统简化为只支持基础返佣(成本价差)和一次性佣金两种机制。
|
||||
|
||||
**Migration**:
|
||||
- 使用一次性佣金的梯度模式 (OneTimeCommissionConfig.type = "tiered") 替代
|
||||
- 一次性佣金支持按销售数量 (tier_type = "sales_count") 或销售金额 (tier_type = "sales_amount") 设置梯度
|
||||
- 一次性佣金每张卡/设备只触发一次,达到阈值后自动发放
|
||||
- 删除所有梯度佣金配置相关的 API 端点:
|
||||
- `POST /api/shop-series-allocations/:id/tiers` (添加梯度配置)
|
||||
- `GET /api/shop-series-allocations/:id/tiers` (查询梯度配置)
|
||||
- `PUT /api/shop-series-commission-tiers/:id` (更新梯度配置)
|
||||
- `DELETE /api/shop-series-commission-tiers/:id` (删除梯度配置)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询梯度佣金配置
|
||||
|
||||
**原内容**: 系统 SHALL 提供梯度佣金配置的查询功能,按分配 ID 查询,返回结果按阈值升序排列。
|
||||
|
||||
**Reason**: 随着梯度返佣功能的废弃,查询功能也一并移除。
|
||||
|
||||
**Migration**: 使用套餐系列分配详情接口查看一次性佣金配置 (`GET /api/shop-series-allocations/:id`),响应中的 `one_time_commission_config` 字段包含梯度配置(如果启用)。
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 更新梯度佣金配置
|
||||
|
||||
**原内容**: 系统 SHALL 允许代理更新梯度配置的阈值和返佣配置。
|
||||
|
||||
**Reason**: 随着梯度返佣功能的废弃,更新功能也一并移除。
|
||||
|
||||
**Migration**: 通过更新套餐系列分配接口修改一次性佣金配置 (`PUT /api/shop-series-allocations/:id`),在请求体中更新 `one_time_commission_config` 字段。
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 删除梯度佣金配置
|
||||
|
||||
**原内容**: 系统 SHALL 允许代理删除梯度配置。
|
||||
|
||||
**Reason**: 随着梯度返佣功能的废弃,删除功能也一并移除。
|
||||
|
||||
**Migration**: 通过更新套餐系列分配接口禁用一次性佣金 (`PUT /api/shop-series-allocations/:id`),设置 `enable_one_time_commission = false`。
|
||||
@@ -0,0 +1,49 @@
|
||||
## MODIFIED Requirements
|
||||
|
||||
### Requirement: 为下级店铺分配套餐系列
|
||||
|
||||
系统 SHALL 允许代理为其直属下级店铺分配套餐系列。分配时 MUST 指定基础返佣配置(返佣模式和返佣值),MAY 启用一次性佣金。分配者只能分配自己已被分配的套餐系列。
|
||||
|
||||
#### Scenario: 成功分配套餐系列
|
||||
- **WHEN** 代理为直属下级店铺分配一个自己拥有的套餐系列,设置基础返佣为百分比200(20%)
|
||||
- **THEN** 系统创建分配记录
|
||||
|
||||
#### Scenario: 尝试分配未拥有的系列
|
||||
- **WHEN** 代理尝试分配自己未被分配的套餐系列
|
||||
- **THEN** 系统返回错误 "您没有该套餐系列的分配权限"
|
||||
|
||||
#### Scenario: 尝试分配给非直属下级
|
||||
- **WHEN** 代理尝试分配给非直属下级店铺
|
||||
- **THEN** 系统返回错误 "只能为直属下级分配套餐"
|
||||
|
||||
#### Scenario: 重复分配同一系列
|
||||
- **WHEN** 代理尝试为同一下级店铺重复分配同一套餐系列
|
||||
- **THEN** 系统返回错误 "该店铺已分配此套餐系列"
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 更新套餐系列分配
|
||||
|
||||
系统 SHALL 允许代理更新分配的基础返佣配置和一次性佣金配置。更新返佣配置时 MUST 创建新的配置版本。
|
||||
|
||||
#### Scenario: 更新基础返佣配置时创建新版本
|
||||
- **WHEN** 代理将基础返佣从20%改为25%
|
||||
- **THEN** 系统更新分配记录,并创建新配置版本
|
||||
|
||||
#### Scenario: 更新不存在的分配
|
||||
- **WHEN** 代理更新不存在的分配 ID
|
||||
- **THEN** 系统返回 "分配记录不存在" 错误
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: 梯度返佣配置
|
||||
|
||||
**原内容**: 分配时 MAY 启用梯度返佣
|
||||
|
||||
**Reason**: 梯度返佣 (TierCommission) 功能与一次性梯度佣金 (OneTimeCommission.tiered) 功能重复,且梯度返佣未实现实际计算逻辑,仅保留基础返佣和一次性佣金两种机制。
|
||||
|
||||
**Migration**:
|
||||
- 如果需要根据销售业绩给予额外奖励,请使用一次性佣金的梯度模式 (OneTimeCommissionConfig.type = "tiered")
|
||||
- 一次性佣金支持按销售数量或销售金额设置多个梯度档位
|
||||
- API 请求中删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- API 响应中不再包含 `enable_tier_commission` 字段
|
||||
@@ -0,0 +1,149 @@
|
||||
## 1. 准备工作
|
||||
|
||||
- [x] 1.1 使用 IDE 的 "Find Usages" 全局搜索 `TierCommission`、`tier_commission`、`tier_bonus` 确认所有引用位置
|
||||
- [x] 1.2 查看 `migrations/` 目录获取最新的 migration 编号,确定新 migration 的编号
|
||||
- [x] 1.3 备份当前数据库结构(开发环境)以便回滚
|
||||
|
||||
## 2. 删除 Model 层
|
||||
|
||||
- [x] 2.1 删除 `internal/model/shop_series_commission_tier.go` 文件
|
||||
- [x] 2.2 在 `internal/model/shop_series_allocation.go` 中删除 `EnableTierCommission` 字段
|
||||
- [x] 2.3 在 `internal/model/shop_series_allocation_config.go` 中删除 `EnableTierCommission` 字段
|
||||
- [x] 2.4 在 `internal/model/commission.go` 中删除 `CommissionSourceTierBonus` 常量定义
|
||||
- [x] 2.5 更新 `internal/model/commission.go` 中的注释,说明佣金来源只有 `cost_diff` 和 `one_time` 两种
|
||||
- [x] 2.6 运行 `go build ./...` 检查编译错误
|
||||
|
||||
## 3. 删除和更新 DTO
|
||||
|
||||
- [x] 3.1 删除 `internal/model/dto/shop_series_allocation.go` 中的 `TierCommissionConfig` 类型
|
||||
- [x] 3.2 删除 `internal/model/dto/shop_series_allocation.go` 中的 `TierEntry` 类型
|
||||
- [x] 3.3 在 `CreateShopSeriesAllocationRequest` 中删除 `EnableTierCommission` 和 `TierConfig` 字段
|
||||
- [x] 3.4 在 `UpdateShopSeriesAllocationRequest` 中删除 `EnableTierCommission` 和 `TierConfig` 字段
|
||||
- [x] 3.5 在 `ShopSeriesAllocationResponse` 中删除 `EnableTierCommission` 字段
|
||||
- [x] 3.6 删除 `internal/model/dto/commission.go` 中 `CommissionStatsResponse` 的 `TierBonusAmount`、`TierBonusCount`、`TierBonusPercent` 字段
|
||||
- [x] 3.7 更新 `internal/model/dto/commission.go` 中 `CommissionRecordListRequest` 的 `commission_source` 验证规则,使用 `validate:"omitempty,oneof=cost_diff one_time"`
|
||||
- [x] 3.8 更新所有相关 DTO 中的 `commission_source` 字段验证规则和注释
|
||||
- [x] 3.9 运行 `go build ./...` 检查编译错误
|
||||
|
||||
## 4. 删除 Store 层
|
||||
|
||||
- [x] 4.1 删除 `internal/store/postgres/shop_series_commission_tier_store.go` 文件
|
||||
- [x] 4.2 在 `internal/store/interface.go` 中删除 `ShopSeriesCommissionTierStore` 接口定义
|
||||
- [x] 4.3 更新 `internal/store/postgres/commission_record_store.go` 的统计查询 SQL,删除 `tier_bonus_amount`、`tier_bonus_count` 的计算逻辑
|
||||
- [x] 4.4 更新 `internal/store/postgres/commission_record_store.go` 中统计结果的结构体定义,删除 `TierBonusAmount` 和 `TierBonusCount` 字段
|
||||
- [x] 4.5 运行 `go build ./...` 检查编译错误
|
||||
|
||||
## 5. 更新 Service 层
|
||||
|
||||
- [x] 5.1 在 `internal/service/shop_series_allocation/service.go` 中删除 `tierStore` 字段(如果存在)
|
||||
- [x] 5.2 在 `internal/service/shop_series_allocation/service.go` 中删除 `validateTierConfig()` 方法(如果存在)
|
||||
- [x] 5.3 在 `internal/service/shop_series_allocation/service.go` 的 `Create` 方法中删除处理 `TierConfig` 的逻辑
|
||||
- [x] 5.4 在 `internal/service/shop_series_allocation/service.go` 的 `Update` 方法中删除处理 `TierConfig` 的逻辑
|
||||
- [x] 5.5 在 `internal/service/my_commission/service.go` 中删除 `tierBonusPercent` 的计算逻辑
|
||||
- [x] 5.6 更新 `internal/service/my_commission/service.go` 中构建 `CommissionStatsResponse` 的代码,删除 tier_bonus 相关字段的赋值
|
||||
- [x] 5.7 运行 `go build ./...` 检查编译错误
|
||||
|
||||
## 6. 更新 Handler 层
|
||||
|
||||
- [x] 6.1 检查 `internal/handler/shop_series_allocation_handler.go` 是否有直接处理 `tier_config` 的逻辑,如有则删除
|
||||
- [x] 6.2 运行 `go build ./...` 检查编译错误
|
||||
|
||||
## 7. 更新依赖注入
|
||||
|
||||
- [x] 7.1 在 `internal/bootstrap/wire.go`(或相关依赖注入配置文件)中删除 `ShopSeriesCommissionTierStore` 的 provider
|
||||
- [x] 7.2 在 `internal/bootstrap/wire.go` 中删除 `NewShopSeriesCommissionTierStore` 的调用(如果存在)
|
||||
- [x] 7.3 在 `internal/service/shop_series_allocation/service.go` 的构造函数中删除 `tierStore` 参数(如果存在)
|
||||
- [x] 7.4 运行 `go build ./...` 确保依赖注入编译通过
|
||||
|
||||
## 8. 创建数据库迁移
|
||||
|
||||
- [x] 8.1 创建新的 migration up 文件(如 `migrations/000034_remove_tier_commission.up.sql`)
|
||||
- [x] 8.2 在 up migration 中添加删除 `tb_shop_series_allocation.enable_tier_commission` 字段的 SQL
|
||||
- [x] 8.3 在 up migration 中添加删除 `tb_shop_series_allocation_config.enable_tier_commission` 字段的 SQL
|
||||
- [x] 8.4 在 up migration 中添加删除 `tb_shop_series_commission_tier` 表的 SQL(使用 `DROP TABLE IF EXISTS`)
|
||||
- [x] 8.5 创建对应的 down migration 文件(如 `migrations/000034_remove_tier_commission.down.sql`)
|
||||
- [x] 8.6 在 down migration 中添加恢复 `tb_shop_series_commission_tier` 表的 SQL
|
||||
- [x] 8.7 在 down migration 中添加恢复 `enable_tier_commission` 字段的 SQL
|
||||
- [x] 8.8 在开发环境执行 `go run cmd/migrate/main.go up` 测试 migration
|
||||
- [x] 8.9 验证数据库结构正确(检查字段和表已删除)
|
||||
- [x] 8.10 执行 `go run cmd/migrate/main.go down` 测试回滚
|
||||
- [x] 8.11 验证数据库结构已恢复
|
||||
- [x] 8.12 重新执行 `go run cmd/migrate/main.go up` 应用变更
|
||||
|
||||
## 9. 更新集成测试
|
||||
|
||||
- [x] 9.1 在 `tests/integration/shop_series_allocation_test.go` 中删除所有包含 `enable_tier_commission` 的测试用例
|
||||
- [x] 9.2 在 `tests/integration/shop_package_batch_allocation_test.go` 中删除 `tier_config` 相关的测试数据
|
||||
- [x] 9.3 添加测试验证创建分配时不接受 `enable_tier_commission` 字段
|
||||
- [x] 9.4 添加测试验证更新分配时不接受 `enable_tier_commission` 字段
|
||||
- [x] 9.5 添加测试验证查询佣金记录时使用 `commission_source=tier_bonus` 返回空列表或错误
|
||||
- [x] 9.6 添加测试验证佣金统计响应中不包含 `tier_bonus_amount`、`tier_bonus_count`、`tier_bonus_percent` 字段
|
||||
- [x] 9.7 运行 `go test ./tests/integration/shop_series_allocation_test.go -v` 确保测试通过
|
||||
- [x] 9.8 运行 `go test ./tests/integration/shop_package_batch_allocation_test.go -v` 确保测试通过
|
||||
|
||||
## 10. 更新单元测试
|
||||
|
||||
- [x] 10.1 检查并更新 `internal/service/shop_series_allocation/service_test.go` 中的测试(如果存在)
|
||||
- [x] 10.2 检查并更新 `internal/service/my_commission/service_test.go` 中的测试
|
||||
- [x] 10.3 删除 `internal/store/postgres/shop_series_commission_tier_store_test.go` 文件(如果存在)
|
||||
- [x] 10.4 运行 `go test ./internal/service/... -v` 确保所有 Service 测试通过
|
||||
- [x] 10.5 运行 `go test ./internal/store/... -v` 确保所有 Store 测试通过
|
||||
|
||||
## 11. 更新 API 文档
|
||||
|
||||
- [x] 11.1 检查项目中 OpenAPI 文档的位置(可能在 `docs/` 或 `api/` 目录)
|
||||
- [x] 11.2 在 OpenAPI schema 定义中删除 `TierCommissionConfig` 和 `TierEntry`
|
||||
- [x] 11.3 更新 `CreateShopSeriesAllocationRequest` 的 schema,删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- [x] 11.4 更新 `UpdateShopSeriesAllocationRequest` 的 schema,删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- [x] 11.5 更新 `ShopSeriesAllocationResponse` 的 schema,删除 `enable_tier_commission` 字段
|
||||
- [x] 11.6 更新 `CommissionStatsResponse` 的 schema,删除 `tier_bonus_amount`、`tier_bonus_count`、`tier_bonus_percent` 字段
|
||||
- [x] 11.7 更新所有 `commission_source` 的枚举定义,只保留 `cost_diff` 和 `one_time`
|
||||
- [x] 11.8 如果项目使用代码生成 OpenAPI 文档,运行生成命令(如 `make generate-docs` 或 `go run cmd/gendocs/main.go`)
|
||||
- [x] 11.9 检查生成的文档,确认变更正确
|
||||
|
||||
## 12. 完整测试验证
|
||||
|
||||
- [x] 12.1 运行完整的单元测试套件:`go test ./... -v`
|
||||
- [x] 12.2 运行完整的集成测试套件:`go test ./tests/integration/... -v`
|
||||
- [x] 12.3 运行 linter 检查代码质量:`golangci-lint run`(如果项目使用)
|
||||
- [x] 12.4 运行 `go fmt ./...` 确保代码格式正确
|
||||
- [x] 12.5 运行 `go vet ./...` 检查潜在问题
|
||||
- [x] 12.6 检查测试覆盖率:`go test ./... -coverprofile=coverage.out && go tool cover -html=coverage.out`
|
||||
|
||||
## 13. 手动功能验证
|
||||
|
||||
- [x] 13.1 启动开发服务器:`go run cmd/server/main.go`
|
||||
- [x] 13.2 测试创建套餐系列分配 API,确认请求体中不包含 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- [x] 13.3 测试更新套餐系列分配 API,确认请求体中不包含 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- [x] 13.4 测试查询套餐系列分配列表 API,确认响应中不包含 `enable_tier_commission` 字段
|
||||
- [x] 13.5 测试查询套餐系列分配详情 API,确认响应中不包含 `enable_tier_commission` 字段
|
||||
- [x] 13.6 测试查询佣金统计 API,确认响应中不包含 `tier_bonus_amount`、`tier_bonus_count`、`tier_bonus_percent` 字段
|
||||
- [x] 13.7 测试佣金计算流程,确认只生成 `cost_diff` 和 `one_time` 类型的佣金记录
|
||||
- [x] 13.8 测试查询佣金记录列表时使用 `commission_source=tier_bonus` 筛选,确认返回空列表或错误
|
||||
|
||||
## 14. 文档和变更日志
|
||||
|
||||
- [x] 14.1 在 `CHANGELOG.md` 中记录此次变更(标记为 BREAKING CHANGE)
|
||||
- [x] 14.2 更新项目 README(如果有相关说明需要修改)
|
||||
- [x] 14.3 创建迁移指南文档,说明如何从旧的梯度返佣迁移到一次性梯度佣金(如果需要)
|
||||
- [x] 14.4 通知前端团队 API 契约变更内容
|
||||
|
||||
## 15. 代码审查和合并
|
||||
|
||||
- [x] 15.1 提交所有变更到 Git,使用清晰的 commit message(如 "清理冗余的梯度返佣(TierCommission)配置")
|
||||
- [x] 15.2 创建 Pull Request,标题和描述引用 proposal 和 design 文档
|
||||
- [x] 15.3 在 PR 描述中列出所有受影响的 API 端点和破坏性变更
|
||||
- [x] 15.4 在 PR 中附加测试结果截图或报告
|
||||
- [x] 15.5 请求团队成员进行代码审查
|
||||
- [x] 15.6 根据审查意见修改代码
|
||||
- [x] 15.7 确保 CI/CD 流水线全部通过
|
||||
- [x] 15.8 合并 PR 到主分支
|
||||
|
||||
## 16. 部署后验证(未来上线时)
|
||||
|
||||
- [x] 16.1 在测试环境部署并验证功能
|
||||
- [x] 16.2 在预发布环境部署并验证功能
|
||||
- [x] 16.3 执行冒烟测试确认核心功能正常
|
||||
- [x] 16.4 监控错误日志,确认没有与删除相关的错误
|
||||
- [x] 16.5 验证数据库 migration 执行成功
|
||||
- [x] 16.6 准备回滚方案(git revert + migration down)
|
||||
@@ -94,7 +94,11 @@
|
||||
|
||||
#### Scenario: 佣金来源类型
|
||||
- **WHEN** 创建佣金记录
|
||||
- **THEN** commission_source 为以下之一:cost_diff(成本价差)、one_time(一次性佣金)、tier_bonus(梯度奖励)
|
||||
- **THEN** commission_source 为以下之一:cost_diff(成本价差)、one_time(一次性佣金)
|
||||
|
||||
#### Scenario: 不再支持梯度奖励来源
|
||||
- **WHEN** 尝试创建 commission_source = "tier_bonus" 的佣金记录
|
||||
- **THEN** 系统拒绝并返回错误 "不支持的佣金来源类型"
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -8,10 +8,18 @@
|
||||
- **WHEN** 代理查询佣金记录列表
|
||||
- **THEN** 系统返回该店铺的所有佣金记录
|
||||
|
||||
#### Scenario: 按佣金来源筛选
|
||||
#### Scenario: 按成本价差筛选
|
||||
- **WHEN** 指定 commission_source 为 cost_diff
|
||||
- **THEN** 系统只返回成本价差类型的佣金记录
|
||||
|
||||
#### Scenario: 按一次性佣金筛选
|
||||
- **WHEN** 指定 commission_source 为 one_time
|
||||
- **THEN** 系统只返回一次性佣金类型的佣金记录
|
||||
|
||||
#### Scenario: 使用已废弃的佣金来源筛选
|
||||
- **WHEN** 指定 commission_source 为 tier_bonus
|
||||
- **THEN** 系统返回空列表或返回错误 "不支持的佣金来源类型"
|
||||
|
||||
#### Scenario: 按时间范围筛选
|
||||
- **WHEN** 指定开始时间和结束时间
|
||||
- **THEN** 系统只返回该时间范围内的佣金记录
|
||||
@@ -46,7 +54,11 @@
|
||||
|
||||
#### Scenario: 各来源占比
|
||||
- **WHEN** 代理查询佣金统计
|
||||
- **THEN** 系统返回各佣金来源的金额和占比(cost_diff、one_time、tier_bonus)
|
||||
- **THEN** 系统返回各佣金来源的金额和占比(cost_diff、one_time)
|
||||
|
||||
#### Scenario: 统计响应不包含梯度奖励字段
|
||||
- **WHEN** 代理查询佣金统计
|
||||
- **THEN** 响应中不包含 tier_bonus_amount、tier_bonus_count、tier_bonus_percent 字段
|
||||
|
||||
#### Scenario: 按时间范围统计
|
||||
- **WHEN** 指定时间范围查询统计
|
||||
|
||||
@@ -1,13 +1,31 @@
|
||||
# Capability: 店铺返佣梯度管理
|
||||
|
||||
**❌ CAPABILITY REMOVED** - 此 capability 已完全废弃
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理如何为套餐系列分配配置和管理梯度返佣,包括添加、查询、更新和删除梯度配置。
|
||||
|
||||
## Requirements
|
||||
**废弃原因**: 整个店铺返佣梯度管理 capability 被废弃。梯度返佣功能与一次性梯度佣金功能重复,且梯度返佣从未实现实际的佣金计算逻辑。系统简化为只支持基础返佣(成本价差)和一次性佣金两种机制。
|
||||
|
||||
**迁移指引**:
|
||||
- 使用一次性佣金的梯度模式 (OneTimeCommissionConfig.type = "tiered") 替代
|
||||
- 一次性佣金支持按销售数量 (tier_type = "sales_count") 或销售金额 (tier_type = "sales_amount") 设置梯度
|
||||
- 一次性佣金每张卡/设备只触发一次,达到阈值后自动发放
|
||||
- 删除所有梯度佣金配置相关的 API 端点:
|
||||
- `POST /api/shop-series-allocations/:id/tiers` (添加梯度配置)
|
||||
- `GET /api/shop-series-allocations/:id/tiers` (查询梯度配置)
|
||||
- `PUT /api/shop-series-commission-tiers/:id` (更新梯度配置)
|
||||
- `DELETE /api/shop-series-commission-tiers/:id` (删除梯度配置)
|
||||
|
||||
---
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: 配置梯度佣金
|
||||
|
||||
**❌ REMOVED**
|
||||
|
||||
系统 SHALL 允许代理为套餐系列分配配置梯度佣金。每个梯度包含:梯度类型(销量/销售额)、周期类型(月度/季度/年度)、阈值、达标后的返佣配置(返佣模式和返佣值)。
|
||||
|
||||
#### Scenario: 添加销量梯度佣金
|
||||
@@ -26,6 +44,8 @@
|
||||
|
||||
### Requirement: 查询梯度佣金配置
|
||||
|
||||
**❌ REMOVED**
|
||||
|
||||
系统 SHALL 提供梯度佣金配置的查询功能,按分配 ID 查询,返回结果按阈值升序排列。
|
||||
|
||||
#### Scenario: 查询分配的梯度配置
|
||||
@@ -40,6 +60,8 @@
|
||||
|
||||
### Requirement: 更新梯度佣金配置
|
||||
|
||||
**❌ REMOVED**
|
||||
|
||||
系统 SHALL 允许代理更新梯度配置的阈值和返佣配置。
|
||||
|
||||
#### Scenario: 更新梯度阈值
|
||||
@@ -54,6 +76,8 @@
|
||||
|
||||
### Requirement: 删除梯度佣金配置
|
||||
|
||||
**❌ REMOVED**
|
||||
|
||||
系统 SHALL 允许代理删除梯度配置。
|
||||
|
||||
#### Scenario: 删除梯度配置
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
### Requirement: 为下级店铺分配套餐系列
|
||||
|
||||
系统 SHALL 允许代理为其直属下级店铺分配套餐系列。分配时 MUST 指定基础返佣配置(返佣模式和返佣值),MAY 启用梯度返佣。分配者只能分配自己已被分配的套餐系列。
|
||||
系统 SHALL 允许代理为其直属下级店铺分配套餐系列。分配时 MUST 指定基础返佣配置(返佣模式和返佣值),MAY 启用一次性佣金。分配者只能分配自己已被分配的套餐系列。
|
||||
|
||||
#### Scenario: 成功分配套餐系列
|
||||
- **WHEN** 代理为直属下级店铺分配一个自己拥有的套餐系列,设置基础返佣为百分比200(20%)
|
||||
@@ -44,7 +44,7 @@
|
||||
|
||||
### Requirement: 更新套餐系列分配
|
||||
|
||||
系统 SHALL 允许代理更新分配的基础返佣配置和梯度返佣开关。更新返佣配置时 MUST 创建新的配置版本。
|
||||
系统 SHALL 允许代理更新分配的基础返佣配置和一次性佣金配置。更新返佣配置时 MUST 创建新的配置版本。
|
||||
|
||||
#### Scenario: 更新基础返佣配置时创建新版本
|
||||
- **WHEN** 代理将基础返佣从20%改为25%
|
||||
@@ -91,3 +91,21 @@
|
||||
#### Scenario: 平台为一级代理分配
|
||||
- **WHEN** 平台管理员为一级代理分配套餐系列
|
||||
- **THEN** 系统创建分配记录
|
||||
|
||||
---
|
||||
|
||||
## REMOVED Requirements
|
||||
|
||||
### Requirement: 梯度返佣配置
|
||||
|
||||
**❌ REMOVED** - 此 requirement 已废弃
|
||||
|
||||
**原内容**: 分配时 MAY 启用梯度返佣
|
||||
|
||||
**Reason**: 梯度返佣 (TierCommission) 功能与一次性梯度佣金 (OneTimeCommission.tiered) 功能重复,且梯度返佣未实现实际计算逻辑,仅保留基础返佣和一次性佣金两种机制。
|
||||
|
||||
**Migration**:
|
||||
- 如果需要根据销售业绩给予额外奖励,请使用一次性佣金的梯度模式 (OneTimeCommissionConfig.type = "tiered")
|
||||
- 一次性佣金支持按销售数量或销售金额设置多个梯度档位
|
||||
- API 请求中删除 `enable_tier_commission` 和 `tier_config` 字段
|
||||
- API 响应中不再包含 `enable_tier_commission` 字段
|
||||
|
||||
@@ -234,13 +234,12 @@ func createTestAllocationForMyPkg(t *testing.T, env *integ.IntegrationTestEnv, s
|
||||
t.Helper()
|
||||
|
||||
allocation := &model.ShopSeriesAllocation{
|
||||
ShopID: shopID,
|
||||
SeriesID: seriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: "fixed",
|
||||
BaseCommissionValue: 500,
|
||||
EnableTierCommission: false,
|
||||
Status: constants.StatusEnabled,
|
||||
ShopID: shopID,
|
||||
SeriesID: seriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: "fixed",
|
||||
BaseCommissionValue: 500,
|
||||
Status: constants.StatusEnabled,
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: 1,
|
||||
Updater: 1,
|
||||
|
||||
@@ -560,13 +560,12 @@ func createTestAllocation(t *testing.T, env *integ.IntegrationTestEnv, shopID, s
|
||||
t.Helper()
|
||||
|
||||
allocation := &model.ShopSeriesAllocation{
|
||||
ShopID: shopID,
|
||||
SeriesID: seriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: "fixed",
|
||||
BaseCommissionValue: 1000,
|
||||
EnableTierCommission: false,
|
||||
Status: constants.StatusEnabled,
|
||||
ShopID: shopID,
|
||||
SeriesID: seriesID,
|
||||
AllocatorShopID: allocatorShopID,
|
||||
BaseCommissionMode: "fixed",
|
||||
BaseCommissionValue: 1000,
|
||||
Status: constants.StatusEnabled,
|
||||
BaseModel: model.BaseModel{
|
||||
Creator: 1,
|
||||
Updater: 1,
|
||||
|
||||
@@ -86,7 +86,6 @@ func GetTestDB(t *testing.T) *gorm.DB {
|
||||
&model.Package{},
|
||||
&model.ShopPackageAllocation{},
|
||||
&model.ShopSeriesAllocation{},
|
||||
&model.ShopSeriesCommissionTier{},
|
||||
&model.EnterpriseCardAuthorization{},
|
||||
&model.EnterpriseDeviceAuthorization{},
|
||||
&model.AssetAllocationRecord{},
|
||||
|
||||
Reference in New Issue
Block a user