归档一次性佣金配置落库与累计触发修复,同步规范文档到主 specs
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m45s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m45s
- 归档 fix-one-time-commission-config-and-accumulation 到 archive/2026-01-29-* - 同步 delta specs 到主规范(one-time-commission-trigger、commission-calculation) - 新增累计触发逻辑文档和测试用例 - 修复一次性佣金配置落库和累计充值更新逻辑
This commit is contained in:
@@ -16,29 +16,32 @@ import (
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
allocationStore *postgres.ShopSeriesAllocationStore
|
||||
tierStore *postgres.ShopSeriesCommissionTierStore
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore
|
||||
shopStore *postgres.ShopStore
|
||||
packageSeriesStore *postgres.PackageSeriesStore
|
||||
packageStore *postgres.PackageStore
|
||||
allocationStore *postgres.ShopSeriesAllocationStore
|
||||
tierStore *postgres.ShopSeriesCommissionTierStore
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore
|
||||
oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore
|
||||
shopStore *postgres.ShopStore
|
||||
packageSeriesStore *postgres.PackageSeriesStore
|
||||
packageStore *postgres.PackageStore
|
||||
}
|
||||
|
||||
func New(
|
||||
allocationStore *postgres.ShopSeriesAllocationStore,
|
||||
tierStore *postgres.ShopSeriesCommissionTierStore,
|
||||
configStore *postgres.ShopSeriesAllocationConfigStore,
|
||||
oneTimeCommissionTierStore *postgres.ShopSeriesOneTimeCommissionTierStore,
|
||||
shopStore *postgres.ShopStore,
|
||||
packageSeriesStore *postgres.PackageSeriesStore,
|
||||
packageStore *postgres.PackageStore,
|
||||
) *Service {
|
||||
return &Service{
|
||||
allocationStore: allocationStore,
|
||||
tierStore: tierStore,
|
||||
configStore: configStore,
|
||||
shopStore: shopStore,
|
||||
packageSeriesStore: packageSeriesStore,
|
||||
packageStore: packageStore,
|
||||
allocationStore: allocationStore,
|
||||
tierStore: tierStore,
|
||||
configStore: configStore,
|
||||
oneTimeCommissionTierStore: oneTimeCommissionTierStore,
|
||||
shopStore: shopStore,
|
||||
packageSeriesStore: packageSeriesStore,
|
||||
packageStore: packageStore,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +102,10 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesAllocatio
|
||||
return nil, errors.New(errors.CodeConflict, "该店铺已分配此套餐系列")
|
||||
}
|
||||
|
||||
if err := s.validateOneTimeCommissionConfig(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
allocation := &model.ShopSeriesAllocation{
|
||||
ShopID: req.ShopID,
|
||||
SeriesID: req.SeriesID,
|
||||
@@ -108,12 +115,34 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesAllocatio
|
||||
EnableTierCommission: req.EnableTierCommission,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
|
||||
// 处理一次性佣金配置
|
||||
allocation.EnableOneTimeCommission = req.EnableOneTimeCommission
|
||||
if req.EnableOneTimeCommission && req.OneTimeCommissionConfig != nil {
|
||||
cfg := req.OneTimeCommissionConfig
|
||||
allocation.OneTimeCommissionType = cfg.Type
|
||||
allocation.OneTimeCommissionTrigger = cfg.Trigger
|
||||
allocation.OneTimeCommissionThreshold = cfg.Threshold
|
||||
// fixed 类型需要保存 mode 和 value
|
||||
if cfg.Type == model.OneTimeCommissionTypeFixed {
|
||||
allocation.OneTimeCommissionMode = cfg.Mode
|
||||
allocation.OneTimeCommissionValue = cfg.Value
|
||||
}
|
||||
}
|
||||
allocation.Creator = currentUserID
|
||||
|
||||
if err := s.allocationStore.Create(ctx, allocation); err != nil {
|
||||
return nil, fmt.Errorf("创建分配失败: %w", err)
|
||||
}
|
||||
|
||||
// 如果是梯度类型,保存梯度配置
|
||||
if req.EnableOneTimeCommission && req.OneTimeCommissionConfig != nil &&
|
||||
req.OneTimeCommissionConfig.Type == model.OneTimeCommissionTypeTiered {
|
||||
if err := s.saveOneTimeCommissionTiers(ctx, allocation.ID, req.OneTimeCommissionConfig.Tiers, currentUserID); err != nil {
|
||||
return nil, fmt.Errorf("创建一次性佣金梯度配置失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return s.buildResponse(ctx, allocation, targetShop.ShopName, series.SeriesName)
|
||||
}
|
||||
|
||||
@@ -170,6 +199,42 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateShopSeries
|
||||
}
|
||||
allocation.EnableTierCommission = *req.EnableTierCommission
|
||||
}
|
||||
|
||||
enableOneTimeCommission := allocation.EnableOneTimeCommission
|
||||
if req.EnableOneTimeCommission != nil {
|
||||
enableOneTimeCommission = *req.EnableOneTimeCommission
|
||||
}
|
||||
if err := s.validateOneTimeCommissionConfigForUpdate(enableOneTimeCommission, req.OneTimeCommissionConfig); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oneTimeCommissionChanged := false
|
||||
if req.EnableOneTimeCommission != nil {
|
||||
if allocation.EnableOneTimeCommission != *req.EnableOneTimeCommission {
|
||||
oneTimeCommissionChanged = true
|
||||
}
|
||||
allocation.EnableOneTimeCommission = *req.EnableOneTimeCommission
|
||||
}
|
||||
if req.OneTimeCommissionConfig != nil && allocation.EnableOneTimeCommission {
|
||||
cfg := req.OneTimeCommissionConfig
|
||||
if allocation.OneTimeCommissionType != cfg.Type ||
|
||||
allocation.OneTimeCommissionTrigger != cfg.Trigger ||
|
||||
allocation.OneTimeCommissionThreshold != cfg.Threshold ||
|
||||
allocation.OneTimeCommissionMode != cfg.Mode ||
|
||||
allocation.OneTimeCommissionValue != cfg.Value {
|
||||
oneTimeCommissionChanged = true
|
||||
}
|
||||
allocation.OneTimeCommissionType = cfg.Type
|
||||
allocation.OneTimeCommissionTrigger = cfg.Trigger
|
||||
allocation.OneTimeCommissionThreshold = cfg.Threshold
|
||||
if cfg.Type == model.OneTimeCommissionTypeFixed {
|
||||
allocation.OneTimeCommissionMode = cfg.Mode
|
||||
allocation.OneTimeCommissionValue = cfg.Value
|
||||
} else {
|
||||
allocation.OneTimeCommissionMode = ""
|
||||
allocation.OneTimeCommissionValue = 0
|
||||
}
|
||||
}
|
||||
allocation.Updater = currentUserID
|
||||
|
||||
if configChanged {
|
||||
@@ -182,6 +247,16 @@ func (s *Service) Update(ctx context.Context, id uint, req *dto.UpdateShopSeries
|
||||
return nil, fmt.Errorf("更新分配失败: %w", err)
|
||||
}
|
||||
|
||||
if oneTimeCommissionChanged && req.OneTimeCommissionConfig != nil &&
|
||||
req.OneTimeCommissionConfig.Type == model.OneTimeCommissionTypeTiered {
|
||||
if err := s.oneTimeCommissionTierStore.DeleteByAllocationID(ctx, allocation.ID); err != nil {
|
||||
return nil, fmt.Errorf("清理旧梯度配置失败: %w", err)
|
||||
}
|
||||
if err := s.saveOneTimeCommissionTiers(ctx, allocation.ID, req.OneTimeCommissionConfig.Tiers, currentUserID); err != nil {
|
||||
return nil, fmt.Errorf("更新一次性佣金梯度配置失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
shop, _ := s.shopStore.GetByID(ctx, allocation.ShopID)
|
||||
series, _ := s.packageSeriesStore.GetByID(ctx, allocation.SeriesID)
|
||||
|
||||
@@ -323,7 +398,7 @@ func (s *Service) buildResponse(ctx context.Context, a *model.ShopSeriesAllocati
|
||||
allocatorShopName = allocatorShop.ShopName
|
||||
}
|
||||
|
||||
return &dto.ShopSeriesAllocationResponse{
|
||||
resp := &dto.ShopSeriesAllocationResponse{
|
||||
ID: a.ID,
|
||||
ShopID: a.ShopID,
|
||||
ShopName: shopName,
|
||||
@@ -335,11 +410,39 @@ func (s *Service) buildResponse(ctx context.Context, a *model.ShopSeriesAllocati
|
||||
Mode: a.BaseCommissionMode,
|
||||
Value: a.BaseCommissionValue,
|
||||
},
|
||||
EnableTierCommission: a.EnableTierCommission,
|
||||
Status: a.Status,
|
||||
CreatedAt: a.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: a.UpdatedAt.Format(time.RFC3339),
|
||||
}, nil
|
||||
EnableTierCommission: a.EnableTierCommission,
|
||||
EnableOneTimeCommission: a.EnableOneTimeCommission,
|
||||
Status: a.Status,
|
||||
CreatedAt: a.CreatedAt.Format(time.RFC3339),
|
||||
UpdatedAt: a.UpdatedAt.Format(time.RFC3339),
|
||||
}
|
||||
|
||||
if a.EnableOneTimeCommission {
|
||||
cfg := &dto.OneTimeCommissionConfig{
|
||||
Type: a.OneTimeCommissionType,
|
||||
Trigger: a.OneTimeCommissionTrigger,
|
||||
Threshold: a.OneTimeCommissionThreshold,
|
||||
Mode: a.OneTimeCommissionMode,
|
||||
Value: a.OneTimeCommissionValue,
|
||||
}
|
||||
if a.OneTimeCommissionType == model.OneTimeCommissionTypeTiered {
|
||||
tiers, err := s.oneTimeCommissionTierStore.ListByAllocationID(ctx, a.ID)
|
||||
if err == nil && len(tiers) > 0 {
|
||||
cfg.Tiers = make([]dto.OneTimeCommissionTierEntry, len(tiers))
|
||||
for i, t := range tiers {
|
||||
cfg.Tiers[i] = dto.OneTimeCommissionTierEntry{
|
||||
TierType: t.TierType,
|
||||
Threshold: t.ThresholdValue,
|
||||
Mode: t.CommissionMode,
|
||||
Value: t.CommissionValue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
resp.OneTimeCommissionConfig = cfg
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (s *Service) createNewConfigVersion(ctx context.Context, allocation *model.ShopSeriesAllocation) error {
|
||||
@@ -371,6 +474,72 @@ func (s *Service) createNewConfigVersion(ctx context.Context, allocation *model.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) validateOneTimeCommissionConfig(req *dto.CreateShopSeriesAllocationRequest) error {
|
||||
if !req.EnableOneTimeCommission {
|
||||
return nil
|
||||
}
|
||||
if req.OneTimeCommissionConfig == nil {
|
||||
return errors.New(errors.CodeInvalidParam, "启用一次性佣金时必须提供配置")
|
||||
}
|
||||
cfg := req.OneTimeCommissionConfig
|
||||
if cfg.Type == model.OneTimeCommissionTypeFixed {
|
||||
if cfg.Mode == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣模式")
|
||||
}
|
||||
if cfg.Value <= 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣金额")
|
||||
}
|
||||
} else if cfg.Type == model.OneTimeCommissionTypeTiered {
|
||||
if len(cfg.Tiers) == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "梯度类型一次性佣金必须提供梯度档位")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) validateOneTimeCommissionConfigForUpdate(enableOneTimeCommission bool, cfg *dto.OneTimeCommissionConfig) error {
|
||||
if !enableOneTimeCommission {
|
||||
return nil
|
||||
}
|
||||
if cfg == nil {
|
||||
return nil
|
||||
}
|
||||
if cfg.Type == model.OneTimeCommissionTypeFixed {
|
||||
if cfg.Mode == "" {
|
||||
return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣模式")
|
||||
}
|
||||
if cfg.Value <= 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "固定类型一次性佣金必须指定返佣金额")
|
||||
}
|
||||
} else if cfg.Type == model.OneTimeCommissionTypeTiered {
|
||||
if len(cfg.Tiers) == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "梯度类型一次性佣金必须提供梯度档位")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) saveOneTimeCommissionTiers(ctx context.Context, allocationID uint, tiers []dto.OneTimeCommissionTierEntry, userID uint) error {
|
||||
if len(tiers) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
tierModels := make([]*model.ShopSeriesOneTimeCommissionTier, len(tiers))
|
||||
for i, t := range tiers {
|
||||
tierModels[i] = &model.ShopSeriesOneTimeCommissionTier{
|
||||
AllocationID: allocationID,
|
||||
TierType: t.TierType,
|
||||
ThresholdValue: t.Threshold,
|
||||
CommissionMode: t.Mode,
|
||||
CommissionValue: t.Value,
|
||||
Status: constants.StatusEnabled,
|
||||
}
|
||||
tierModels[i].Creator = userID
|
||||
}
|
||||
|
||||
return s.oneTimeCommissionTierStore.BatchCreate(ctx, tierModels)
|
||||
}
|
||||
|
||||
func (s *Service) GetEffectiveConfig(ctx context.Context, allocationID uint, at time.Time) (*model.ShopSeriesAllocationConfig, error) {
|
||||
config, err := s.configStore.GetEffective(ctx, allocationID, at)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user