Files
junhong_cmp_fiber/internal/service/package/terms.go
邹进 af57de0d4d
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 9m27s
fix: 店铺分配覆盖为实名即生效的套餐纳入沉默期配置口径
存量中套餐本身购买即生效、店铺分配覆盖为实名即生效的正式套餐,购买后同样等实名,
但原口径只看套餐本身:无法配置默认沉默期、不进未配置清单与打开前检查,
待实名记录无法回填导致总开关打不开,新购买也绕过沉默期。

- 未配置清单与打开前检查纳入存在实名即生效分配覆盖的套餐
- 购买即生效正式套餐允许选填默认沉默期,加油包仍禁止
- 分配覆盖购买即生效 → 实名即生效在套餐已配置默认沉默期时放行
- 同步 OpenSpec design D11、spec、tasks 3.4/3.5 与前端说明

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 17:56:29 +09:00

110 lines
5.0 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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
}