修复:套餐耗尽后流量详单断档问题
问题:套餐 status=Depleted 后,queryActivePackages 查不到套餐, DeductDataUsage 直接 return CodeNoAvailablePackage,导致上游 仍有真实流量时,tb_package_usage_daily_record 不再写入,详单断档。 修复:无 Active 套餐时,找最近一条 Depleted 套餐,将溢出流量 累加到 data_usage_mb 并写入当日 daily_record,保持详单连续性。 status 不变,不重复触发停机。
This commit is contained in:
@@ -88,13 +88,22 @@ func (s *UsageService) DeductDataUsage(ctx context.Context, carrierType string,
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
today := time.Now().Format("2006-01-02")
|
||||||
|
|
||||||
if len(packages) == 0 {
|
if len(packages) == 0 {
|
||||||
|
// 无生效套餐:尝试找 Depleted 套餐记录溢出流量详单,避免详单断档
|
||||||
|
if recordErr := s.recordOverflowToDepletedPackage(ctx, tx, targetCarrierType, targetCarrierID, deductUsageMB, today); recordErr != nil {
|
||||||
|
s.logger.Warn("记录溢出流量到已耗尽套餐失败",
|
||||||
|
zap.String("carrier_type", targetCarrierType),
|
||||||
|
zap.Uint("carrier_id", targetCarrierID),
|
||||||
|
zap.Int64("usage_mb", deductUsageMB),
|
||||||
|
zap.Error(recordErr))
|
||||||
|
}
|
||||||
return errors.New(errors.CodeNoAvailablePackage, "没有可用套餐")
|
return errors.New(errors.CodeNoAvailablePackage, "没有可用套餐")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按优先级扣减流量
|
// 按优先级扣减流量
|
||||||
remainingUsage := deductUsageMB
|
remainingUsage := deductUsageMB
|
||||||
today := time.Now().Format("2006-01-02")
|
|
||||||
|
|
||||||
for index, pkg := range packages {
|
for index, pkg := range packages {
|
||||||
if remainingUsage <= 0 {
|
if remainingUsage <= 0 {
|
||||||
@@ -446,3 +455,40 @@ func (s *UsageService) triggerSuspensionAfterCommit(carrierType string, carrierI
|
|||||||
}(cardID)
|
}(cardID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// recordOverflowToDepletedPackage 在所有套餐已耗尽时,将溢出流量写入最近的 Depleted 套餐日记录。
|
||||||
|
// 目的:保持流量详单连续性,即便套餐用完期间上游仍有流量使用,详单不会断档。
|
||||||
|
// 只写日记录和累加 data_usage_mb,不改变套餐 status,不触发停机。
|
||||||
|
func (s *UsageService) recordOverflowToDepletedPackage(ctx context.Context, tx *gorm.DB, carrierType string, carrierID uint, overflowMB int64, today string) error {
|
||||||
|
query := tx.Where("status = ?", constants.PackageUsageStatusDepleted)
|
||||||
|
switch carrierType {
|
||||||
|
case constants.AssetTypeIotCard:
|
||||||
|
query = query.Where("iot_card_id = ?", carrierID)
|
||||||
|
case constants.AssetTypeDevice:
|
||||||
|
query = query.Where("device_id = ?", carrierID)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var pkg model.PackageUsage
|
||||||
|
if err := query.Order("id DESC").First(&pkg).Error; err != nil {
|
||||||
|
// 找不到 Depleted 套餐,静默忽略
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
newUsage := pkg.DataUsageMB + overflowMB
|
||||||
|
if err := tx.Model(&pkg).Update("data_usage_mb", newUsage).Error; err != nil {
|
||||||
|
return errors.Wrap(errors.CodeDatabaseError, err, "更新溢出流量失败")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.updateDailyRecord(ctx, tx, pkg.ID, today, overflowMB, newUsage); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info("记录溢出流量到已耗尽套餐",
|
||||||
|
zap.Uint("package_usage_id", pkg.ID),
|
||||||
|
zap.Int64("overflow_mb", overflowMB),
|
||||||
|
zap.Int64("new_usage_mb", newUsage))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user