This commit is contained in:
@@ -491,6 +491,118 @@ func (s *ActivationService) syncCarrierStatusActivated(ctx context.Context, tx *
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidatePackagesForRefund 退款精准失效套餐
|
||||
// 规则:
|
||||
// 1. 优先按 packageUsageID 精准失效单条套餐(且必须属于当前退款订单)
|
||||
// 2. 未传 packageUsageID 时,按 orderID 失效该订单生成的套餐
|
||||
// 3. 若命中主套餐,级联失效其加油包,避免残留挂靠关系
|
||||
func (s *ActivationService) InvalidatePackagesForRefund(ctx context.Context, assetType string, assetID uint, orderID uint, packageUsageID *uint) error {
|
||||
if orderID == 0 {
|
||||
return errors.New(errors.CodeInvalidParam, "无效的订单ID")
|
||||
}
|
||||
|
||||
validStatuses := []int{
|
||||
constants.PackageUsageStatusPending,
|
||||
constants.PackageUsageStatusActive,
|
||||
constants.PackageUsageStatusDepleted,
|
||||
}
|
||||
|
||||
baseQuery := s.db.WithContext(ctx).Model(&model.PackageUsage{})
|
||||
switch assetType {
|
||||
case "iot_card":
|
||||
baseQuery = baseQuery.Where("iot_card_id = ?", assetID)
|
||||
case "device":
|
||||
baseQuery = baseQuery.Where("device_id = ?", assetID)
|
||||
default:
|
||||
return errors.New(errors.CodeInvalidParam, "无效的资产类型")
|
||||
}
|
||||
|
||||
var targets []model.PackageUsage
|
||||
if packageUsageID != nil && *packageUsageID > 0 {
|
||||
var usage model.PackageUsage
|
||||
err := baseQuery.
|
||||
Where("id = ? AND order_id = ?", *packageUsageID, orderID).
|
||||
Where("status IN ?", validStatuses).
|
||||
First(&usage).Error
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
s.logger.Info("退款精准失效:未命中可失效套餐",
|
||||
zap.String("asset_type", assetType),
|
||||
zap.Uint("asset_id", assetID),
|
||||
zap.Uint("order_id", orderID),
|
||||
zap.Uint("package_usage_id", *packageUsageID),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询退款关联套餐失败")
|
||||
}
|
||||
targets = append(targets, usage)
|
||||
} else {
|
||||
if err := baseQuery.
|
||||
Where("order_id = ?", orderID).
|
||||
Where("status IN ?", validStatuses).
|
||||
Find(&targets).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询退款订单套餐失败")
|
||||
}
|
||||
if len(targets) == 0 {
|
||||
s.logger.Info("退款精准失效:订单无可失效套餐",
|
||||
zap.String("asset_type", assetType),
|
||||
zap.Uint("asset_id", assetID),
|
||||
zap.Uint("order_id", orderID),
|
||||
)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
targetIDSet := make(map[uint]struct{}, len(targets))
|
||||
mainUsageIDs := make([]uint, 0, len(targets))
|
||||
for _, usage := range targets {
|
||||
targetIDSet[usage.ID] = struct{}{}
|
||||
if usage.MasterUsageID == nil {
|
||||
mainUsageIDs = append(mainUsageIDs, usage.ID)
|
||||
}
|
||||
}
|
||||
|
||||
if len(mainUsageIDs) > 0 {
|
||||
var addons []model.PackageUsage
|
||||
if err := baseQuery.
|
||||
Where("master_usage_id IN ?", mainUsageIDs).
|
||||
Where("status IN ?", validStatuses).
|
||||
Find(&addons).Error; err != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, err, "查询主套餐关联加油包失败")
|
||||
}
|
||||
for _, addon := range addons {
|
||||
targetIDSet[addon.ID] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
targetIDs := make([]uint, 0, len(targetIDSet))
|
||||
for id := range targetIDSet {
|
||||
targetIDs = append(targetIDs, id)
|
||||
}
|
||||
if len(targetIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
result := s.db.WithContext(ctx).
|
||||
Model(&model.PackageUsage{}).
|
||||
Where("id IN ?", targetIDs).
|
||||
Update("status", constants.PackageUsageStatusInvalidated)
|
||||
if result.Error != nil {
|
||||
return errors.Wrap(errors.CodeDatabaseError, result.Error, "退款失效套餐失败")
|
||||
}
|
||||
|
||||
s.logger.Info("退款精准失效套餐完成",
|
||||
zap.String("asset_type", assetType),
|
||||
zap.Uint("asset_id", assetID),
|
||||
zap.Uint("order_id", orderID),
|
||||
zap.Int("target_count", len(targetIDs)),
|
||||
zap.Int64("affected", result.RowsAffected),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InvalidateAllPackagesByAsset 批量失效资产关联的所有有效套餐
|
||||
// 退款时调用:将该资产下状态为待生效(0)、生效中(1)、已用完(2)的套餐全部标记为已失效(4)
|
||||
func (s *ActivationService) InvalidateAllPackagesByAsset(ctx context.Context, assetType string, assetID uint) error {
|
||||
|
||||
Reference in New Issue
Block a user