有效天数问题,充值单回调问题

This commit is contained in:
2026-05-08 11:46:34 +08:00
parent 7c85a8cf29
commit a93acc0784
12 changed files with 402 additions and 87 deletions

View File

@@ -278,8 +278,6 @@ func (s *Service) Renew(ctx context.Context, id uint) error {
if err = tx.Model(&model.IotCard{}).Where("id = ?", card.ID).Updates(map[string]any{
"generation": card.Generation + 1,
"asset_status": 1,
"accumulated_recharge": 0,
"first_commission_paid": false,
"accumulated_recharge_by_series": "{}",
"first_recharge_triggered_by_series": "{}",
"updater": middleware.GetUserIDFromContext(ctx),
@@ -320,8 +318,6 @@ func (s *Service) Renew(ctx context.Context, id uint) error {
if err = tx.Model(&model.Device{}).Where("id = ?", device.ID).Updates(map[string]any{
"generation": device.Generation + 1,
"asset_status": 1,
"accumulated_recharge": 0,
"first_commission_paid": false,
"accumulated_recharge_by_series": "{}",
"first_recharge_triggered_by_series": "{}",
"updater": middleware.GetUserIDFromContext(ctx),

View File

@@ -10,7 +10,7 @@ import (
// calendarType: 套餐周期类型natural_month=自然月by_day=按天)
// activatedAt: 激活时间
// durationMonths: 套餐时长月数calendar_type=natural_month 时使用)
// durationDays: 套餐天数calendar_type=by_day 时使用)
// durationDays: 套餐天数calendar_type=by_day 时使用,兼容每月折算天数
// 返回:过期时间(当天 23:59:59
func CalculateExpiryTime(calendarType string, activatedAt time.Time, durationMonths, durationDays int) time.Time {
var expiryDate time.Time
@@ -31,13 +31,53 @@ func CalculateExpiryTime(calendarType string, activatedAt time.Time, durationMon
expiryDate = time.Date(targetYear, targetMonth+1, 0, 23, 59, 59, 0, activatedAt.Location())
} else {
// 按天套餐activated_at + N 天23:59:59
expiryDate = activatedAt.AddDate(0, 0, durationDays)
effectiveDays := calculateByDayValidityDays(durationMonths, durationDays)
expiryDate = activatedAt.AddDate(0, 0, effectiveDays)
expiryDate = time.Date(expiryDate.Year(), expiryDate.Month(), expiryDate.Day(), 23, 59, 59, 0, expiryDate.Location())
}
return expiryDate
}
// CalculateValidityDays 计算套餐展示有效天数。
// 按天套餐优先返回折算后的总天数;自然月套餐按 baseTime 推算到目标月月末。
func CalculateValidityDays(calendarType string, baseTime time.Time, durationMonths, durationDays int) int {
if calendarType == constants.PackageCalendarTypeNaturalMonth {
return calculateNaturalMonthValidityDays(baseTime, durationMonths)
}
return calculateByDayValidityDays(durationMonths, durationDays)
}
func calculateByDayValidityDays(durationMonths, durationDays int) int {
if durationDays <= 0 {
if durationMonths <= 0 {
return 0
}
return durationMonths * 30
}
if durationMonths > 1 && durationDays <= 31 {
return durationMonths * durationDays
}
return durationDays
}
func calculateNaturalMonthValidityDays(baseTime time.Time, durationMonths int) int {
if baseTime.IsZero() || durationMonths <= 0 {
return 0
}
expiresAt := CalculateExpiryTime(constants.PackageCalendarTypeNaturalMonth, baseTime, durationMonths, 0)
startDate := time.Date(baseTime.Year(), baseTime.Month(), baseTime.Day(), 0, 0, 0, 0, baseTime.Location())
endDate := time.Date(expiresAt.Year(), expiresAt.Month(), expiresAt.Day(), 0, 0, 0, 0, expiresAt.Location())
days := int(endDate.Sub(startDate).Hours()/24) + 1
if days < 0 {
return 0
}
return days
}
// CalculateNextResetTime 计算下次流量重置时间
// dataResetCycle: 流量重置周期daily/monthly/yearly/none
// calendarType: 套餐周期类型natural_month/by_day影响月重置逻辑

View File

@@ -193,6 +193,3 @@ func (s *Service) checkForceRechargeRequirement(ctx context.Context, resourceTyp
return result, nil
}
// updateAccumulatedRechargeInTx 更新累计充值(事务内使用)
// 同时更新旧的 accumulated_recharge 字段和新的 accumulated_recharge_by_series JSON 字段

View File

@@ -204,7 +204,6 @@ func (s *Service) updateAccumulatedRechargeInTx(ctx context.Context, tx *gorm.DB
result := tx.Model(&model.IotCard{}).
Where("id = ?", resourceID).
Updates(map[string]any{
"accumulated_recharge": gorm.Expr("accumulated_recharge + ?", amount),
"accumulated_recharge_by_series": card.AccumulatedRechargeBySeriesJSON,
})
if result.Error != nil {
@@ -225,7 +224,6 @@ func (s *Service) updateAccumulatedRechargeInTx(ctx context.Context, tx *gorm.DB
result := tx.Model(&model.Device{}).
Where("id = ?", resourceID).
Updates(map[string]any{
"accumulated_recharge": gorm.Expr("accumulated_recharge + ?", amount),
"accumulated_recharge_by_series": device.AccumulatedRechargeBySeriesJSON,
})
if result.Error != nil {
@@ -400,7 +398,6 @@ func (s *Service) triggerOneTimeCommissionIfNeededInTx(ctx context.Context, tx *
}
if err := tx.Model(&model.IotCard{}).Where("id = ?", rechargeOrder.ResourceID).
Updates(map[string]any{
"first_commission_paid": true,
"first_recharge_triggered_by_series": card.FirstRechargeTriggeredBySeriesJSON,
}).Error; err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "更新卡佣金发放状态失败")
@@ -415,7 +412,6 @@ func (s *Service) triggerOneTimeCommissionIfNeededInTx(ctx context.Context, tx *
}
if err := tx.Model(&model.Device{}).Where("id = ?", rechargeOrder.ResourceID).
Updates(map[string]any{
"first_commission_paid": true,
"first_recharge_triggered_by_series": device.FirstRechargeTriggeredBySeriesJSON,
}).Error; err != nil {
return errors.Wrap(errors.CodeDatabaseError, err, "更新设备佣金发放状态失败")

View File

@@ -593,8 +593,6 @@ func (s *Service) resetAssetGeneration(ctx context.Context, assetType string, as
if err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).Updates(map[string]any{
"generation": card.Generation + 1,
"asset_status": 1,
"accumulated_recharge": 0,
"first_commission_paid": false,
"accumulated_recharge_by_series": "{}",
"first_recharge_triggered_by_series": "{}",
"updated_at": now,
@@ -644,8 +642,6 @@ func (s *Service) resetAssetGeneration(ctx context.Context, assetType string, as
if err := tx.Model(&model.Device{}).Where("id = ?", device.ID).Updates(map[string]any{
"generation": device.Generation + 1,
"asset_status": 1,
"accumulated_recharge": 0,
"first_commission_paid": false,
"accumulated_recharge_by_series": "{}",
"first_recharge_triggered_by_series": "{}",
"updated_at": now,