All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m27s
存量中套餐本身购买即生效、店铺分配覆盖为实名即生效的正式套餐,购买后同样等实名, 但原口径只看套餐本身:无法配置默认沉默期、不进未配置清单与打开前检查, 待实名记录无法回填导致总开关打不开,新购买也绕过沉默期。 - 未配置清单与打开前检查纳入存在实名即生效分配覆盖的套餐 - 购买即生效正式套餐允许选填默认沉默期,加油包仍禁止 - 分配覆盖购买即生效 → 实名即生效在套餐已配置默认沉默期时放行 - 同步 OpenSpec design D11、spec、tasks 3.4/3.5 与前端说明 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
110 lines
5.0 KiB
Go
110 lines
5.0 KiB
Go
package packagepkg
|
||
|
||
import (
|
||
"github.com/break/junhong_cmp_fiber/internal/model"
|
||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
)
|
||
|
||
// ValidateExpiryBaseOverride 校验显式提交的分配生效条件覆盖。
|
||
func ValidateExpiryBaseOverride(value *string, submitted bool) (*string, error) {
|
||
if !submitted {
|
||
return nil, errors.New(errors.CodeInvalidParam, "生效条件覆盖字段未提交,须显式传值(null 或合法枚举)")
|
||
}
|
||
if value == nil {
|
||
return nil, nil
|
||
}
|
||
if *value != constants.PackageExpiryBaseFromActivation && *value != constants.PackageExpiryBaseFromPurchase {
|
||
return nil, errors.New(errors.CodeInvalidParam, "生效条件覆盖值非法,合法值为:购买即生效、实名激活时生效")
|
||
}
|
||
return value, nil
|
||
}
|
||
|
||
// EffectiveExpiryBase 返回套餐分配最终采用的生效条件。
|
||
func EffectiveExpiryBase(pkg *model.Package, allocation *model.ShopPackageAllocation) string {
|
||
if allocation != nil && allocation.ExpiryBaseOverride != nil {
|
||
return *allocation.ExpiryBaseOverride
|
||
}
|
||
return pkg.ExpiryBase
|
||
}
|
||
|
||
// ExpiryBaseName 返回生效条件中文名称。
|
||
func ExpiryBaseName(value string) string {
|
||
switch value {
|
||
case constants.PackageExpiryBaseFromActivation:
|
||
return "实名激活时生效"
|
||
case constants.PackageExpiryBaseFromPurchase:
|
||
return "购买即生效"
|
||
default:
|
||
return "未知"
|
||
}
|
||
}
|
||
|
||
// ExpiryBaseOverrideName 返回覆盖值中文名称,空值表示跟随套餐默认。
|
||
func ExpiryBaseOverrideName(value *string) string {
|
||
if value == nil {
|
||
return "跟随套餐默认"
|
||
}
|
||
return ExpiryBaseName(*value)
|
||
}
|
||
|
||
// ValidateAllocationExpiryBaseOverride 校验分配覆盖不得改变套餐生效条件(add-package-silence-period §3.3)。
|
||
// 套餐服务与店铺分配(单个、批量、系列授权)写入路径共用:
|
||
// 覆盖把实名即生效套餐改成购买即生效会绕过沉默期,阻断;把购买即生效套餐改成实名即生效时,
|
||
// 套餐已配置默认沉默期才放行(design D11)。覆盖为空(跟随套餐默认)或与套餐一致时放行;加油包不进入沉默期,不受此约束。
|
||
func ValidateAllocationExpiryBaseOverride(pkg *model.Package, override *string) error {
|
||
if pkg == nil || override == nil || pkg.PackageType == constants.PackageTypeAddon || *override == pkg.ExpiryBase {
|
||
return nil
|
||
}
|
||
if *override == constants.PackageExpiryBaseFromActivation && pkg.SilencePeriodDays != nil {
|
||
return nil
|
||
}
|
||
if *override == constants.PackageExpiryBaseFromActivation {
|
||
return errors.New(errors.CodePackageExpiryBaseChangeForbidden,
|
||
"套餐「"+pkg.PackageName+"」未配置默认沉默期,不允许通过分配覆盖改为实名即生效")
|
||
}
|
||
return errors.New(errors.CodePackageExpiryBaseChangeForbidden,
|
||
"套餐「"+pkg.PackageName+"」不允许通过分配覆盖从实名即生效改为购买即生效")
|
||
}
|
||
|
||
// ValidatePackageExpiryBaseChange 校验套餐自身生效条件变更(§3.3):实名即生效改为购买即生效阻断;
|
||
// 购买即生效改为实名即生效时,同一请求必须提供默认沉默期。
|
||
func ValidatePackageExpiryBaseChange(pkg *model.Package, before, after string, silenceDaysSubmitted bool) error {
|
||
if pkg == nil || pkg.PackageType == constants.PackageTypeAddon || before == after {
|
||
return nil
|
||
}
|
||
if before == constants.PackageExpiryBaseFromActivation && after == constants.PackageExpiryBaseFromPurchase {
|
||
return errors.New(errors.CodePackageExpiryBaseChangeForbidden, "实名即生效套餐不允许改为购买即生效")
|
||
}
|
||
if before == constants.PackageExpiryBaseFromPurchase && after == constants.PackageExpiryBaseFromActivation && !silenceDaysSubmitted {
|
||
return errors.New(errors.CodeSilencePeriodOutOfRange, "改为实名即生效时必须同时设置默认沉默期(1~90 天)")
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// RequiresSilencePeriod 判断套餐是否必须配置默认沉默期:实名即生效的正式套餐。
|
||
func RequiresSilencePeriod(pkg *model.Package) bool {
|
||
return pkg != nil && pkg.PackageType != constants.PackageTypeAddon && pkg.ExpiryBase == constants.PackageExpiryBaseFromActivation
|
||
}
|
||
|
||
// ValidatePackageSilenceConfig 校验套餐最终的沉默期配置:实名即生效正式套餐必填 1~90 天;
|
||
// 购买即生效正式套餐可选填 1~90 天(只在店铺分配覆盖为实名即生效时使用,design D11);加油包不得填写。
|
||
func ValidatePackageSilenceConfig(pkg *model.Package) error {
|
||
if pkg == nil {
|
||
return nil
|
||
}
|
||
if pkg.SilencePeriodDays == nil {
|
||
if RequiresSilencePeriod(pkg) {
|
||
return errors.New(errors.CodeSilencePeriodOutOfRange, "实名即生效套餐必须配置默认沉默期(1~90 天)")
|
||
}
|
||
return nil
|
||
}
|
||
if pkg.PackageType == constants.PackageTypeAddon {
|
||
return errors.New(errors.CodeInvalidParam, "加油包不能配置沉默期")
|
||
}
|
||
if *pkg.SilencePeriodDays < constants.SilencePackageDaysMin || *pkg.SilencePeriodDays > constants.SilencePackageDaysMax {
|
||
return errors.New(errors.CodeSilencePeriodOutOfRange, "默认沉默期须为 1~90 天")
|
||
}
|
||
return nil
|
||
}
|