package models import ( "time" "gorm.io/datatypes" "rocketgit.ru/rsmon/worker/app/models/concerns" ) const ( SubscriptionStatusTrialing = "trialing" SubscriptionStatusActive = "active" SubscriptionStatusPastDue = "past_due" SubscriptionStatusPaused = "paused" SubscriptionStatusCanceled = "canceled" SubscriptionStatusExpired = "expired" ) // Subscription is the current billable entitlement for one account. M0 only // writes manual subscriptions; provider flows are deliberately deferred. type Subscription struct { concerns.Model AccountID int64 `gorm:"not null;index" json:"account_id"` Account *Account `json:"-"` PlanID int64 `gorm:"not null;index" json:"plan_id"` Plan *Plan `json:"plan,omitempty"` Provider string `gorm:"size:16;not null;default:'manual'" json:"provider"` ProviderSubscriptionID *string `gorm:"size:128" json:"provider_subscription_id,omitempty"` ProviderCustomerID *string `gorm:"size:128" json:"provider_customer_id,omitempty"` Status string `gorm:"size:24;not null;default:'active';index" json:"status"` BillingCycle string `gorm:"size:8;not null;default:'monthly'" json:"billing_cycle"` CurrentPeriodStart *time.Time `json:"current_period_start,omitempty"` CurrentPeriodEnd *time.Time `gorm:"index" json:"current_period_end,omitempty"` TrialEndsAt *time.Time `json:"trial_ends_at,omitempty"` CancelAtPeriodEnd bool `gorm:"not null;default:false" json:"cancel_at_period_end"` CanceledAt *time.Time `json:"canceled_at,omitempty"` Currency string `gorm:"size:3;not null" json:"currency"` AmountMinor int64 `gorm:"not null;default:0" json:"amount_minor"` MetadataJSON datatypes.JSON `gorm:"type:jsonb;not null;default:'{}'" json:"metadata_json"` concerns.Timestamped } // SubscriptionEvent is an append-only audit record for entitlement changes // and provider deliveries. ProviderEventID makes future webhook processing // idempotent without coupling the ledger to a specific PSP. type SubscriptionEvent struct { concerns.Model SubscriptionID int64 `gorm:"not null;index" json:"subscription_id"` AccountID int64 `gorm:"not null;index" json:"account_id"` Provider string `gorm:"size:16;not null;default:'manual';uniqueIndex:idx_subscription_events_provider_event,priority:1" json:"provider"` Kind string `gorm:"size:32;not null" json:"kind"` FromPlanID *int64 `json:"from_plan_id,omitempty"` ToPlanID *int64 `json:"to_plan_id,omitempty"` AmountMinor *int64 `json:"amount_minor,omitempty"` Currency string `gorm:"size:3" json:"currency,omitempty"` ActorUserID *int64 `json:"actor_user_id,omitempty"` ProviderEventID *string `gorm:"size:128;uniqueIndex:idx_subscription_events_provider_event,priority:2" json:"provider_event_id,omitempty"` PayloadJSON datatypes.JSON `gorm:"type:jsonb;not null;default:'{}'" json:"payload_json"` CreatedAt time.Time `json:"created_at"` }