package models import ( "time" ) // SubscriptionTier represents the subscription tier type SubscriptionTier string const ( TierFree SubscriptionTier = "free" TierPro SubscriptionTier = "pro" ) // SubscriptionPlatform constants const ( PlatformIOS = "ios" PlatformAndroid = "android" PlatformStripe = "stripe" ) // SubscriptionSettings represents the subscription_subscriptionsettings table (singleton) type SubscriptionSettings struct { ID uint `gorm:"primaryKey" json:"id"` EnableLimitations bool `gorm:"column:enable_limitations;default:false" json:"enable_limitations"` EnableMonitoring bool `gorm:"column:enable_monitoring;default:true" json:"enable_monitoring"` TrialEnabled bool `gorm:"column:trial_enabled;default:true" json:"trial_enabled"` TrialDurationDays int `gorm:"column:trial_duration_days;default:14" json:"trial_duration_days"` } // TableName returns the table name for GORM func (SubscriptionSettings) TableName() string { return "subscription_subscriptionsettings" } // UserSubscription represents the subscription_usersubscription table type UserSubscription struct { BaseModel UserID uint `gorm:"column:user_id;uniqueIndex;not null" json:"user_id"` User User `gorm:"foreignKey:UserID" json:"-"` Tier SubscriptionTier `gorm:"column:tier;size:10;default:'free'" json:"tier"` // In-App Purchase data (Apple / Google) AppleReceiptData *string `gorm:"column:apple_receipt_data;type:text" json:"-"` GooglePurchaseToken *string `gorm:"column:google_purchase_token;type:text" json:"-"` // Stripe data (web subscriptions) StripeCustomerID *string `gorm:"column:stripe_customer_id;size:255" json:"-"` StripeSubscriptionID *string `gorm:"column:stripe_subscription_id;size:255" json:"-"` StripePriceID *string `gorm:"column:stripe_price_id;size:255" json:"-"` // Subscription dates SubscribedAt *time.Time `gorm:"column:subscribed_at" json:"subscribed_at"` ExpiresAt *time.Time `gorm:"column:expires_at" json:"expires_at"` AutoRenew bool `gorm:"column:auto_renew;default:true" json:"auto_renew"` // Trial TrialStart *time.Time `gorm:"column:trial_start" json:"trial_start"` TrialEnd *time.Time `gorm:"column:trial_end" json:"trial_end"` TrialUsed bool `gorm:"column:trial_used;default:false" json:"trial_used"` // Tracking CancelledAt *time.Time `gorm:"column:cancelled_at" json:"cancelled_at"` Platform string `gorm:"column:platform;size:10" json:"platform"` // ios, android, stripe // Admin override - bypasses all limitations regardless of global settings IsFree bool `gorm:"column:is_free;default:false" json:"is_free"` } // TableName returns the table name for GORM func (UserSubscription) TableName() string { return "subscription_usersubscription" } // IsActive returns true if the subscription is active (pro tier and not expired, or trial active) func (s *UserSubscription) IsActive() bool { if s.IsTrialActive() { return true } if s.Tier != TierPro { return false } if s.ExpiresAt != nil && time.Now().UTC().After(*s.ExpiresAt) { return false } return true } // IsPro returns true if the user has a pro subscription or active trial func (s *UserSubscription) IsPro() bool { return s.IsActive() } // IsTrialActive returns true if the user has an active, unexpired trial func (s *UserSubscription) IsTrialActive() bool { if s.TrialEnd == nil { return false } return time.Now().UTC().Before(*s.TrialEnd) } // HasStripeSubscription returns true if the user has Stripe subscription data func (s *UserSubscription) HasStripeSubscription() bool { return s.StripeSubscriptionID != nil && *s.StripeSubscriptionID != "" } // HasAppleSubscription returns true if the user has Apple receipt data func (s *UserSubscription) HasAppleSubscription() bool { return s.AppleReceiptData != nil && *s.AppleReceiptData != "" } // HasGoogleSubscription returns true if the user has Google purchase token func (s *UserSubscription) HasGoogleSubscription() bool { return s.GooglePurchaseToken != nil && *s.GooglePurchaseToken != "" } // SubscriptionSource returns the platform that the active subscription came from func (s *UserSubscription) SubscriptionSource() string { return s.Platform } // UpgradeTrigger represents the subscription_upgradetrigger table type UpgradeTrigger struct { BaseModel TriggerKey string `gorm:"column:trigger_key;uniqueIndex;size:50;not null" json:"trigger_key"` Title string `gorm:"column:title;size:200;not null" json:"title"` Message string `gorm:"column:message;type:text;not null" json:"message"` PromoHTML string `gorm:"column:promo_html;type:text" json:"promo_html"` ButtonText string `gorm:"column:button_text;size:50;default:'Upgrade to Pro'" json:"button_text"` IsActive bool `gorm:"column:is_active;default:true" json:"is_active"` } // TableName returns the table name for GORM func (UpgradeTrigger) TableName() string { return "subscription_upgradetrigger" } // FeatureBenefit represents the subscription_featurebenefit table type FeatureBenefit struct { BaseModel FeatureName string `gorm:"column:feature_name;size:200;not null" json:"feature_name"` FreeTierText string `gorm:"column:free_tier_text;size:200;not null" json:"free_tier_text"` ProTierText string `gorm:"column:pro_tier_text;size:200;not null" json:"pro_tier_text"` DisplayOrder int `gorm:"column:display_order;default:0" json:"display_order"` IsActive bool `gorm:"column:is_active;default:true" json:"is_active"` } // TableName returns the table name for GORM func (FeatureBenefit) TableName() string { return "subscription_featurebenefit" } // Promotion represents the subscription_promotion table type Promotion struct { BaseModel PromotionID string `gorm:"column:promotion_id;uniqueIndex;size:50;not null" json:"promotion_id"` Title string `gorm:"column:title;size:200;not null" json:"title"` Message string `gorm:"column:message;type:text;not null" json:"message"` Link *string `gorm:"column:link;size:200" json:"link"` StartDate time.Time `gorm:"column:start_date;not null" json:"start_date"` EndDate time.Time `gorm:"column:end_date;not null" json:"end_date"` TargetTier SubscriptionTier `gorm:"column:target_tier;size:10;default:'free'" json:"target_tier"` IsActive bool `gorm:"column:is_active;default:true" json:"is_active"` } // TableName returns the table name for GORM func (Promotion) TableName() string { return "subscription_promotion" } // IsCurrentlyActive returns true if the promotion is currently active func (p *Promotion) IsCurrentlyActive() bool { if !p.IsActive { return false } now := time.Now().UTC() return now.After(p.StartDate) && now.Before(p.EndDate) } // TierLimits represents the subscription_tierlimits table type TierLimits struct { BaseModel Tier SubscriptionTier `gorm:"column:tier;uniqueIndex;size:10;not null" json:"tier"` PropertiesLimit *int `gorm:"column:properties_limit" json:"properties_limit"` TasksLimit *int `gorm:"column:tasks_limit" json:"tasks_limit"` ContractorsLimit *int `gorm:"column:contractors_limit" json:"contractors_limit"` DocumentsLimit *int `gorm:"column:documents_limit" json:"documents_limit"` } // TableName returns the table name for GORM func (TierLimits) TableName() string { return "subscription_tierlimits" } // GetDefaultFreeLimits returns the default limits for the free tier func GetDefaultFreeLimits() TierLimits { one := 1 ten := 10 zero := 0 return TierLimits{ Tier: TierFree, PropertiesLimit: &one, TasksLimit: &ten, ContractorsLimit: &zero, DocumentsLimit: &zero, } } // GetDefaultProLimits returns the default limits for the pro tier (unlimited) func GetDefaultProLimits() TierLimits { return TierLimits{ Tier: TierPro, PropertiesLimit: nil, // nil = unlimited TasksLimit: nil, ContractorsLimit: nil, DocumentsLimit: nil, } }