修复错误购买报错的问题,修复接口返回虚流量启动错误的问题
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m48s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m48s
This commit is contained in:
@@ -2227,13 +2227,10 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
return err
|
||||
}
|
||||
|
||||
hasBlockingMain, err := packagepkg.HasBlockingMainPackageForFormal(tx.WithContext(ctx), carrierType, carrierID, now)
|
||||
hasCurrentMain, err := packagepkg.HasCurrentMainPackageForQueue(tx.WithContext(ctx), carrierType, carrierID, now)
|
||||
if err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐失败")
|
||||
}
|
||||
if hasBlockingMain {
|
||||
return errors.New(errors.CodeMainPackageExists)
|
||||
}
|
||||
|
||||
var status int
|
||||
var priority int
|
||||
@@ -2242,62 +2239,73 @@ func (s *Service) activateMainPackage(ctx context.Context, tx *gorm.DB, order *m
|
||||
var nextResetAt *time.Time
|
||||
var pendingRealnameActivation bool
|
||||
|
||||
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)
|
||||
if hasCurrentMain {
|
||||
// 当前仍有在用主套餐时,新主套餐进入待生效队列,后续由过期/退款等流程接续激活。
|
||||
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)
|
||||
|
||||
// REALNAME-02: 后台囤货场景三维决策(卡类型 + 购买路径 + expiry_base + 实名状态)
|
||||
// 查询卡类型(行业卡永远直接激活,不等实名)
|
||||
// 同时查询载体当前实名状态:已实名则跳过 pending,直接激活
|
||||
var cardCategory string
|
||||
var currentlyRealnamed bool
|
||||
if carrierType == "iot_card" {
|
||||
var card model.IotCard
|
||||
if err := tx.Select("card_category", "real_name_status").First(&card, carrierID).Error; err == nil {
|
||||
cardCategory = card.CardCategory
|
||||
currentlyRealnamed = card.RealNameStatus == constants.RealNameStatusVerified
|
||||
}
|
||||
// err != nil 时 currentlyRealnamed 保守默认 false,不阻断购买流程
|
||||
} else if carrierType == "device" {
|
||||
// 子查询:统计该设备绑定的已实名卡数量(GORM 自动注入 deleted_at IS NULL)
|
||||
var count int64
|
||||
subQuery := tx.Model(&model.DeviceSimBinding{}).
|
||||
Select("iot_card_id").
|
||||
Where("device_id = ? AND bind_status = 1", carrierID)
|
||||
if err := tx.Model(&model.IotCard{}).
|
||||
Where("id IN (?) AND real_name_status = 1", subQuery).
|
||||
Count(&count).Error; err == nil {
|
||||
currentlyRealnamed = count > 0
|
||||
}
|
||||
// err != nil 时保守默认 false,不阻断购买流程
|
||||
}
|
||||
|
||||
// 判断是否 C 端购买(C 端购买前已做实名前置检查,直接激活)
|
||||
isCEndPurchase := order.BuyerType == model.BuyerTypePersonal
|
||||
|
||||
if cardCategory != "industry" && !isCEndPurchase {
|
||||
// 后台囤货路径:按 expiry_base 决定是否等实名
|
||||
if pkg.ExpiryBase != "from_purchase" {
|
||||
if currentlyRealnamed {
|
||||
s.logger.Info("购买时载体已实名,直接激活套餐",
|
||||
zap.String("carrier_type", carrierType),
|
||||
zap.Uint("carrier_id", carrierID))
|
||||
} else {
|
||||
// from_activation(默认):未实名,等实名后激活
|
||||
status = constants.PackageUsageStatusPending
|
||||
pendingRealnameActivation = true
|
||||
activatedAt = time.Time{}
|
||||
expiresAt = time.Time{}
|
||||
nextResetAt = nil
|
||||
// REALNAME-02: 后台囤货场景三维决策(卡类型 + 购买路径 + expiry_base + 实名状态)
|
||||
// 查询卡类型(行业卡永远直接激活,不等实名)
|
||||
// 同时查询载体当前实名状态:已实名则跳过 pending,直接激活
|
||||
var cardCategory string
|
||||
var currentlyRealnamed bool
|
||||
if carrierType == "iot_card" {
|
||||
var card model.IotCard
|
||||
if err := tx.Select("card_category", "real_name_status").First(&card, carrierID).Error; err == nil {
|
||||
cardCategory = card.CardCategory
|
||||
currentlyRealnamed = card.RealNameStatus == constants.RealNameStatusVerified
|
||||
}
|
||||
// err != nil 时 currentlyRealnamed 保守默认 false,不阻断购买流程
|
||||
} else if carrierType == "device" {
|
||||
// 子查询:统计该设备绑定的已实名卡数量(GORM 自动注入 deleted_at IS NULL)
|
||||
var count int64
|
||||
subQuery := tx.Model(&model.DeviceSimBinding{}).
|
||||
Select("iot_card_id").
|
||||
Where("device_id = ? AND bind_status = 1", carrierID)
|
||||
if err := tx.Model(&model.IotCard{}).
|
||||
Where("id IN (?) AND real_name_status = 1", subQuery).
|
||||
Count(&count).Error; err == nil {
|
||||
currentlyRealnamed = count > 0
|
||||
}
|
||||
// err != nil 时保守默认 false,不阻断购买流程
|
||||
}
|
||||
// from_purchase:立即激活,status 已为 Active,保持不变
|
||||
|
||||
// 判断是否 C 端购买(C 端购买前已做实名前置检查,直接激活)
|
||||
isCEndPurchase := order.BuyerType == model.BuyerTypePersonal
|
||||
|
||||
if cardCategory != "industry" && !isCEndPurchase {
|
||||
// 后台囤货路径:按 expiry_base 决定是否等实名
|
||||
if pkg.ExpiryBase != "from_purchase" {
|
||||
if currentlyRealnamed {
|
||||
s.logger.Info("购买时载体已实名,直接激活套餐",
|
||||
zap.String("carrier_type", carrierType),
|
||||
zap.Uint("carrier_id", carrierID))
|
||||
} else {
|
||||
// from_activation(默认):未实名,等实名后激活
|
||||
status = constants.PackageUsageStatusPending
|
||||
pendingRealnameActivation = true
|
||||
activatedAt = time.Time{}
|
||||
expiresAt = time.Time{}
|
||||
nextResetAt = nil
|
||||
}
|
||||
}
|
||||
// from_purchase:立即激活,status 已为 Active,保持不变
|
||||
}
|
||||
// 行业卡或 C 端购买:直接激活,status 已为 Active,保持不变
|
||||
}
|
||||
// 行业卡或 C 端购买:直接激活,status 已为 Active,保持不变
|
||||
|
||||
// 创建套餐使用记录
|
||||
virtualTotalMBSnapshot, displayGainRatioSnapshot, enableVirtualDataSnapshot := model.BuildPackageUsageSnapshotValues(pkg)
|
||||
|
||||
Reference in New Issue
Block a user