package billing import ( "context" "errors" ) var ( ErrDisabled = errors.New("billing is not configured") ErrInvalidPlan = errors.New("invalid billing plan") ErrInvalidRequest = errors.New("invalid billing request") ErrNotFound = errors.New("billing record not found") ErrConflict = errors.New("billing request is already being created") ErrInvalidSignature = errors.New("invalid stripe signature") ErrCustomerRequired = errors.New("stripe customer is not available") ) const ( PlanFree = "free" PlanStarter = "starter" PlanPro = "pro" ) type CheckoutAttempt struct { ID string `bson:"_id"` UID int64 `bson:"uid"` RequestID string `bson:"request_id"` PlanID string `bson:"plan_id"` PriceID string `bson:"price_id"` SessionID string `bson:"session_id,omitempty"` URL string `bson:"url,omitempty"` ExpiresAt int64 `bson:"expires_at,omitempty"` Status string `bson:"status"` PaymentStatus string `bson:"payment_status,omitempty"` FulfillmentStatus string `bson:"fulfillment_status"` CustomerID string `bson:"customer_id,omitempty"` SubscriptionID string `bson:"subscription_id,omitempty"` Error string `bson:"error,omitempty"` CreatedAt int64 `bson:"created_at"` UpdatedAt int64 `bson:"updated_at"` } type SubscriptionState struct { UID int64 PlanID string PaidPlanID string Status string CustomerID string SubscriptionID string CurrentPeriodStart int64 CurrentPeriodEnd int64 CancelAtPeriodEnd bool AdminOverride bool } type ProviderCheckout struct { SessionID string URL string ExpiresAt int64 Status string PaymentStatus string PriceID string CustomerID string SubscriptionID string } type CheckoutParams struct { UID int64 AttemptID string PlanID string PriceID string CustomerID string SuccessURL string CancelURL string IdempotencyKey string } type ProviderSubscription struct { ID string CustomerID string Status string PriceID string CurrentPeriodStart int64 CurrentPeriodEnd int64 CancelAtPeriodEnd bool } type Event struct { ID string Type string Created int64 ObjectID string SubscriptionID string CustomerID string PriceID string Status string PeriodStart int64 PeriodEnd int64 CancelAtPeriodEnd bool } type EntitlementUpdate struct { EventID string EventCreatedAt int64 UID int64 PlanID string PaidPlanID string Status string CustomerID string SubscriptionID string CurrentPeriodStart int64 CurrentPeriodEnd int64 CancelAtPeriodEnd bool } type PurchaseAudit struct { ID string `bson:"_id"` UID int64 `bson:"uid"` PlanID string `bson:"plan_id"` StripeEventID string `bson:"stripe_event_id"` StripeSessionID string `bson:"stripe_session_id,omitempty"` StripeCustomerID string `bson:"stripe_customer_id,omitempty"` StripeSubscriptionID string `bson:"stripe_subscription_id,omitempty"` Status string `bson:"status"` CreatedAt int64 `bson:"created_at"` } type Provider interface { CreateCheckout(context.Context, CheckoutParams) (*ProviderCheckout, error) GetCheckout(context.Context, string) (*ProviderCheckout, error) GetSubscription(context.Context, string) (*ProviderSubscription, error) CreatePortal(context.Context, string, string) (string, error) VerifyEvent([]byte, string, string) (*Event, error) } type Repository interface { InsertCheckout(context.Context, *CheckoutAttempt) (bool, error) GetCheckoutByRequest(context.Context, int64, string) (*CheckoutAttempt, error) GetCheckout(context.Context, int64, string) (*CheckoutAttempt, error) GetCheckoutBySession(context.Context, string) (*CheckoutAttempt, error) UpdateCheckout(context.Context, *CheckoutAttempt) error GetSubscription(context.Context, int64) (*SubscriptionState, error) FindUIDByCustomer(context.Context, string) (int64, error) ApplyEntitlement(context.Context, EntitlementUpdate) (bool, error) WebhookProcessed(context.Context, string) (bool, error) MarkWebhookProcessed(context.Context, string, string, int64) error UpsertPurchase(context.Context, *PurchaseAudit) error }