Compare commits

...

1 Commits

Author SHA1 Message Date
shanshanzhong147 0a897419a5 修复(#86): 排除永久订阅回归促销误判
Co-authored-by: multica-agent <github@multica.ai>
2026-05-27 01:44:11 -07:00
2 changed files with 71 additions and 2 deletions
+20 -2
View File
@@ -11,6 +11,7 @@ import (
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type PromoResult struct {
@@ -148,6 +149,12 @@ func evaluateInactiveUserPromo(
err := db.WithContext(ctx).
Model(&user.Subscribe{}).
Where("user_id = ?", userID).
Order(clause.OrderBy{
Expression: clause.Expr{
SQL: "CASE WHEN expire_time = ? THEN 0 ELSE 1 END",
Vars: []interface{}{permanentSubscribeExpireTime()},
},
}).
Order("expire_time DESC").
Limit(1).
Take(&lastSub).Error
@@ -158,8 +165,19 @@ func evaluateInactiveUserPromo(
return false, time.Time{}, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query promo inactive user subscription failed")
}
threshold := now.AddDate(0, -params.InactiveMonths, 0)
return lastSub.ExpireTime.Before(threshold) || lastSub.ExpireTime.Equal(threshold), ruleExpiresAt, nil
return isInactivePromoEligible(lastSub.ExpireTime, now, params.InactiveMonths), ruleExpiresAt, nil
}
func isInactivePromoEligible(expireTime time.Time, now time.Time, inactiveMonths int) bool {
if expireTime.Equal(permanentSubscribeExpireTime()) {
return false
}
threshold := now.AddDate(0, -inactiveMonths, 0)
return expireTime.Before(threshold) || expireTime.Equal(threshold)
}
func permanentSubscribeExpireTime() time.Time {
return time.UnixMilli(0)
}
func promoRuleExpiresAt(rule *promo.RuleWithPrice) time.Time {
@@ -0,0 +1,51 @@
package common
import (
"testing"
"time"
)
func TestIsInactivePromoEligible(t *testing.T) {
now := time.Date(2026, time.May, 27, 12, 0, 0, 0, time.UTC)
tests := []struct {
name string
expireAt time.Time
want bool
}{
{
name: "expired before inactive threshold is eligible",
expireAt: now.AddDate(0, -4, 0),
want: true,
},
{
name: "expired exactly at inactive threshold is eligible",
expireAt: now.AddDate(0, -3, 0),
want: true,
},
{
name: "recently expired subscription is not eligible",
expireAt: now.AddDate(0, -2, 0),
want: false,
},
{
name: "active future subscription is not eligible",
expireAt: now.Add(time.Hour),
want: false,
},
{
name: "permanent subscription marker is not eligible",
expireAt: time.UnixMilli(0),
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := isInactivePromoEligible(tt.expireAt, now, 3)
if got != tt.want {
t.Fatalf("isInactivePromoEligible() = %v, want %v", got, tt.want)
}
})
}
}