diff --git a/internal/service/shop_series_grant/service.go b/internal/service/shop_series_grant/service.go index c6d289d..dc5b031 100644 --- a/internal/service/shop_series_grant/service.go +++ b/internal/service/shop_series_grant/service.go @@ -202,15 +202,13 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesGrantRequ operatorShopID := middleware.GetShopIDFromContext(ctx) operatorType := middleware.GetUserTypeFromContext(ctx) - // 1. 查询套餐系列,确认佣金类型 + // 1. 查询套餐系列,解析一次性佣金配置(可选) + // 系列授权同时作为套餐销售权限的入口记录,未启用一次性佣金的系列也可创建授权,佣金金额默认为 0 series, err := s.packageSeriesStore.GetByID(ctx, req.SeriesID) if err != nil { return nil, errors.New(errors.CodeNotFound, "套餐系列不存在") } - config, err := series.GetOneTimeCommissionConfig() - if err != nil || config == nil || !config.Enable { - return nil, errors.New(errors.CodeInvalidParam, "该系列未启用一次性佣金,无法创建授权") - } + config, _ := series.GetOneTimeCommissionConfig() // 1.5 校验目标店铺是否存在 _, err = s.shopStore.GetByID(ctx, req.ShopID) @@ -238,7 +236,7 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesGrantRequ } // 平台/超管 allocatorShopID = 0 - // 4. 参数验证:固定模式 or 梯度模式 + // 4. 参数验证:仅启用一次性佣金的系列才需要配置佣金金额 allocation := &model.ShopSeriesAllocation{ ShopID: req.ShopID, SeriesID: req.SeriesID, @@ -249,59 +247,61 @@ func (s *Service) Create(ctx context.Context, req *dto.CreateShopSeriesGrantRequ allocation.Creator = operatorID allocation.Updater = operatorID - if config.CommissionType == "fixed" { - if req.OneTimeCommissionAmount == nil { - return nil, errors.New(errors.CodeInvalidParam, "固定模式必须填写佣金金额") - } - ceiling, ceilErr := s.getParentCeilingFixed(ctx, allocatorShopID, req.SeriesID, config) - if ceilErr != nil { - return nil, ceilErr - } - if *req.OneTimeCommissionAmount > ceiling { - return nil, errors.New(errors.CodeInvalidParam, "佣金金额不能超过上级天花板") - } - allocation.OneTimeCommissionAmount = *req.OneTimeCommissionAmount - } else { - // 梯度模式 - if len(req.CommissionTiers) == 0 { - return nil, errors.New(errors.CodeInvalidParam, "梯度模式必须填写阶梯配置") - } - // 阶梯数量和 threshold 必须与全局完全一致 - if len(req.CommissionTiers) != len(config.Tiers) { - return nil, errors.New(errors.CodeInvalidParam, "梯度阶梯数量与系列配置不一致") - } - ceilingMap, ceilErr := s.getParentCeilingTiered(ctx, allocatorShopID, req.SeriesID, config.Tiers) - if ceilErr != nil { - return nil, ceilErr - } - agentTiers := make([]model.AllocationCommissionTier, 0, len(req.CommissionTiers)) - for i, tier := range req.CommissionTiers { - if tier.Threshold != config.Tiers[i].Threshold { - return nil, errors.New(errors.CodeInvalidParam, "梯度阶梯 threshold 与系列配置不匹配") + if config != nil && config.Enable { + if config.CommissionType == "fixed" { + if req.OneTimeCommissionAmount == nil { + return nil, errors.New(errors.CodeInvalidParam, "固定模式必须填写佣金金额") } - ceiling, ok := ceilingMap[tier.Threshold] - if !ok { - ceiling = 0 + ceiling, ceilErr := s.getParentCeilingFixed(ctx, allocatorShopID, req.SeriesID, config) + if ceilErr != nil { + return nil, ceilErr } - if tier.Amount > ceiling { - return nil, errors.New(errors.CodeInvalidParam, "某档位佣金金额超过上级天花板") + if *req.OneTimeCommissionAmount > ceiling { + return nil, errors.New(errors.CodeInvalidParam, "佣金金额不能超过上级天花板") + } + allocation.OneTimeCommissionAmount = *req.OneTimeCommissionAmount + } else { + // 梯度模式 + if len(req.CommissionTiers) == 0 { + return nil, errors.New(errors.CodeInvalidParam, "梯度模式必须填写阶梯配置") + } + // 阶梯数量和 threshold 必须与全局完全一致 + if len(req.CommissionTiers) != len(config.Tiers) { + return nil, errors.New(errors.CodeInvalidParam, "梯度阶梯数量与系列配置不一致") + } + ceilingMap, ceilErr := s.getParentCeilingTiered(ctx, allocatorShopID, req.SeriesID, config.Tiers) + if ceilErr != nil { + return nil, ceilErr + } + agentTiers := make([]model.AllocationCommissionTier, 0, len(req.CommissionTiers)) + for i, tier := range req.CommissionTiers { + if tier.Threshold != config.Tiers[i].Threshold { + return nil, errors.New(errors.CodeInvalidParam, "梯度阶梯 threshold 与系列配置不匹配") + } + ceiling, ok := ceilingMap[tier.Threshold] + if !ok { + ceiling = 0 + } + if tier.Amount > ceiling { + return nil, errors.New(errors.CodeInvalidParam, "某档位佣金金额超过上级天花板") + } + agentTiers = append(agentTiers, model.AllocationCommissionTier{ + Threshold: tier.Threshold, + Amount: tier.Amount, + }) + } + if err := allocation.SetCommissionTiers(agentTiers); err != nil { + return nil, errors.Wrap(errors.CodeInternalError, err, "序列化阶梯佣金失败") } - agentTiers = append(agentTiers, model.AllocationCommissionTier{ - Threshold: tier.Threshold, - Amount: tier.Amount, - }) } - if err := allocation.SetCommissionTiers(agentTiers); err != nil { - return nil, errors.Wrap(errors.CodeInternalError, err, "序列化阶梯佣金失败") - } - } - // 5. 强充配置:first_recharge 或平台已开强充 → locked,忽略代理传入 - forceRechargeLocked := config.TriggerType == model.OneTimeCommissionTriggerFirstRecharge || config.EnableForceRecharge - if !forceRechargeLocked && req.EnableForceRecharge != nil && *req.EnableForceRecharge { - allocation.EnableForceRecharge = true - if req.ForceRechargeAmount != nil { - allocation.ForceRechargeAmount = *req.ForceRechargeAmount + // 5. 强充配置:first_recharge 或平台已开强充 → locked,忽略代理传入 + forceRechargeLocked := config.TriggerType == model.OneTimeCommissionTriggerFirstRecharge || config.EnableForceRecharge + if !forceRechargeLocked && req.EnableForceRecharge != nil && *req.EnableForceRecharge { + allocation.EnableForceRecharge = true + if req.ForceRechargeAmount != nil { + allocation.ForceRechargeAmount = *req.ForceRechargeAmount + } } }