sub2api/backend/internal/service/user_subscription.go
benjamin a4884b4e75 fix(subscription): 将日卡改为一次性每日配额
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-05-18 21:09:11 +08:00

143 lines
3.3 KiB
Go

package service
import "time"
type UserSubscription struct {
ID int64
UserID int64
GroupID int64
StartsAt time.Time
ExpiresAt time.Time
Status string
DailyWindowStart *time.Time
WeeklyWindowStart *time.Time
MonthlyWindowStart *time.Time
DailyUsageUSD float64
WeeklyUsageUSD float64
MonthlyUsageUSD float64
AssignedBy *int64
AssignedAt time.Time
Notes string
CreatedAt time.Time
UpdatedAt time.Time
User *User
Group *Group
AssignedByUser *User
}
func (s *UserSubscription) IsActive() bool {
return s.Status == SubscriptionStatusActive && time.Now().Before(s.ExpiresAt)
}
func (s *UserSubscription) IsExpired() bool {
return time.Now().After(s.ExpiresAt)
}
func (s *UserSubscription) DaysRemaining() int {
if s.IsExpired() {
return 0
}
return int(time.Until(s.ExpiresAt).Hours() / 24)
}
func (s *UserSubscription) IsWindowActivated() bool {
return s.DailyWindowStart != nil || s.WeeklyWindowStart != nil || s.MonthlyWindowStart != nil
}
func (s *UserSubscription) HasOneTimeDailyQuota() bool {
if s == nil || s.StartsAt.IsZero() || s.ExpiresAt.IsZero() {
return false
}
return !s.ExpiresAt.After(s.StartsAt.AddDate(0, 0, 1))
}
func (s *UserSubscription) NeedsDailyReset() bool {
return s.NeedsDailyResetAt(time.Now())
}
func (s *UserSubscription) NeedsDailyResetAt(now time.Time) bool {
if s.DailyWindowStart == nil {
return false
}
if s.HasOneTimeDailyQuota() {
return false
}
return !now.Before(s.DailyWindowStart.Add(24 * time.Hour))
}
func (s *UserSubscription) NeedsWeeklyReset() bool {
if s.WeeklyWindowStart == nil {
return false
}
return time.Since(*s.WeeklyWindowStart) >= 7*24*time.Hour
}
func (s *UserSubscription) NeedsMonthlyReset() bool {
if s.MonthlyWindowStart == nil {
return false
}
return time.Since(*s.MonthlyWindowStart) >= 30*24*time.Hour
}
func (s *UserSubscription) DailyResetTime() *time.Time {
if s.DailyWindowStart == nil {
return nil
}
if s.HasOneTimeDailyQuota() {
t := s.ExpiresAt
return &t
}
t := s.DailyWindowStart.Add(24 * time.Hour)
return &t
}
func (s *UserSubscription) WeeklyResetTime() *time.Time {
if s.WeeklyWindowStart == nil {
return nil
}
t := s.WeeklyWindowStart.Add(7 * 24 * time.Hour)
return &t
}
func (s *UserSubscription) MonthlyResetTime() *time.Time {
if s.MonthlyWindowStart == nil {
return nil
}
t := s.MonthlyWindowStart.Add(30 * 24 * time.Hour)
return &t
}
func (s *UserSubscription) CheckDailyLimit(group *Group, additionalCost float64) bool {
if !group.HasDailyLimit() {
return true
}
return s.DailyUsageUSD+additionalCost <= *group.DailyLimitUSD
}
func (s *UserSubscription) CheckWeeklyLimit(group *Group, additionalCost float64) bool {
if !group.HasWeeklyLimit() {
return true
}
return s.WeeklyUsageUSD+additionalCost <= *group.WeeklyLimitUSD
}
func (s *UserSubscription) CheckMonthlyLimit(group *Group, additionalCost float64) bool {
if !group.HasMonthlyLimit() {
return true
}
return s.MonthlyUsageUSD+additionalCost <= *group.MonthlyLimitUSD
}
func (s *UserSubscription) CheckAllLimits(group *Group, additionalCost float64) (daily, weekly, monthly bool) {
daily = s.CheckDailyLimit(group, additionalCost)
weekly = s.CheckWeeklyLimit(group, additionalCost)
monthly = s.CheckMonthlyLimit(group, additionalCost)
return
}