不允许购买第二个主套餐
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m50s

This commit is contained in:
Break
2026-06-10 15:24:26 +08:00
parent 32c9859b38
commit 5c779cb6e0
7 changed files with 314 additions and 108 deletions

View File

@@ -10,6 +10,7 @@ import (
"github.com/redis/go-redis/v9"
"go.uber.org/zap"
"gorm.io/gorm"
"gorm.io/gorm/clause"
"github.com/break/junhong_cmp_fiber/internal/model"
packagepkg "github.com/break/junhong_cmp_fiber/internal/service/package"
@@ -496,14 +497,17 @@ func (h *AutoPurchaseHandler) activateMainPackage(
now time.Time,
) error {
_ = ctx
var activeMainPackage model.PackageUsage
err := tx.Where("status = ?", constants.PackageUsageStatusActive).
Where("master_usage_id IS NULL").
Where(carrierType+"_id = ?", carrierID).
Order("priority ASC").
First(&activeMainPackage).Error
if err := h.lockPackageCarrier(ctx, tx, carrierType, carrierID); err != nil {
return err
}
hasActiveMain := err == nil
hasBlockingMain, err := packagepkg.HasBlockingMainPackageForFormal(tx.WithContext(ctx), carrierType, carrierID, now)
if err != nil {
return err
}
if hasBlockingMain {
return errors.New("已有主套餐,不能重复购买主套餐")
}
var status int
var priority int
@@ -512,21 +516,11 @@ func (h *AutoPurchaseHandler) activateMainPackage(
var nextResetAt *time.Time
var pendingRealnameActivation bool
if hasActiveMain {
status = constants.PackageUsageStatusPending
var maxPriority int
tx.Model(&model.PackageUsage{}).
Where(carrierType+"_id = ?", carrierID).
Select("COALESCE(MAX(priority), 0)").
Scan(&maxPriority)
priority = maxPriority + 1
} else {
status = constants.PackageUsageStatusActive
priority = 1
activatedAt = now
expiresAt = packagepkg.CalculateExpiryTime(pkg.CalendarType, activatedAt, pkg.DurationMonths, pkg.DurationDays)
nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, pkg.CalendarType, now, activatedAt)
}
status = constants.PackageUsageStatusActive
priority = 1
activatedAt = now
expiresAt = packagepkg.CalculateExpiryTime(pkg.CalendarType, activatedAt, pkg.DurationMonths, pkg.DurationDays)
nextResetAt = packagepkg.CalculateNextResetTime(pkg.DataResetCycle, pkg.CalendarType, now, activatedAt)
// REALNAME-02: 自动购包属于 C 端充值触发不需要等实名C 端已做前置实名检查)
// ExpiryBase 仅影响后台囤货路径,此处无需判断
@@ -580,6 +574,19 @@ func (h *AutoPurchaseHandler) activateMainPackage(
}).Error
}
func (h *AutoPurchaseHandler) lockPackageCarrier(ctx context.Context, tx *gorm.DB, carrierType string, carrierID uint) error {
switch carrierType {
case constants.AssetWalletResourceTypeIotCard, "card":
var card model.IotCard
return tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&card, carrierID).Error
case constants.AssetWalletResourceTypeDevice:
var device model.Device
return tx.WithContext(ctx).Clauses(clause.Locking{Strength: "UPDATE"}).First(&device, carrierID).Error
default:
return errors.New("无效的套餐载体类型")
}
}
func (h *AutoPurchaseHandler) activateAddonPackage(
ctx context.Context,
tx *gorm.DB,