# models/schema/subscription.py """ Pydantic schemas for subscription operations. Supports subscription management and tier limit checks. """ from datetime import datetime from pydantic import BaseModel, ConfigDict, Field # ============================================================================ # Tier Information Schemas # ============================================================================ class TierFeatures(BaseModel): """Features included in a tier.""" letzshop_sync: bool = True inventory_basic: bool = True inventory_locations: bool = False inventory_purchase_orders: bool = False invoice_lu: bool = True invoice_eu_vat: bool = False invoice_bulk: bool = False customer_view: bool = True customer_export: bool = False analytics_dashboard: bool = False accounting_export: bool = False api_access: bool = False automation_rules: bool = False team_roles: bool = False white_label: bool = False multi_vendor: bool = False custom_integrations: bool = False sla_guarantee: bool = False dedicated_support: bool = False class TierLimits(BaseModel): """Limits for a subscription tier.""" orders_per_month: int | None = Field(None, description="None = unlimited") products_limit: int | None = Field(None, description="None = unlimited") team_members: int | None = Field(None, description="None = unlimited") order_history_months: int | None = Field(None, description="None = unlimited") class TierInfo(BaseModel): """Full tier information.""" code: str name: str price_monthly_cents: int price_annual_cents: int | None limits: TierLimits features: list[str] # ============================================================================ # Subscription Schemas # ============================================================================ class SubscriptionCreate(BaseModel): """Schema for creating a subscription (admin/internal use).""" tier: str = Field(default="essential", pattern="^(essential|professional|business|enterprise)$") is_annual: bool = False trial_days: int = Field(default=14, ge=0, le=30) class SubscriptionUpdate(BaseModel): """Schema for updating a subscription.""" tier: str | None = Field(None, pattern="^(essential|professional|business|enterprise)$") status: str | None = Field(None, pattern="^(trial|active|past_due|cancelled|expired)$") is_annual: bool | None = None custom_orders_limit: int | None = None custom_products_limit: int | None = None custom_team_limit: int | None = None class SubscriptionResponse(BaseModel): """Schema for subscription response.""" model_config = ConfigDict(from_attributes=True) id: int vendor_id: int tier: str status: str period_start: datetime period_end: datetime is_annual: bool trial_ends_at: datetime | None orders_this_period: int orders_limit_reached_at: datetime | None # Effective limits (with custom overrides applied) orders_limit: int | None products_limit: int | None team_members_limit: int | None # Computed properties is_active: bool is_trial: bool trial_days_remaining: int | None created_at: datetime updated_at: datetime class SubscriptionUsage(BaseModel): """Current subscription usage statistics.""" orders_used: int orders_limit: int | None orders_remaining: int | None orders_percent_used: float | None products_used: int products_limit: int | None products_remaining: int | None products_percent_used: float | None team_members_used: int team_members_limit: int | None team_members_remaining: int | None team_members_percent_used: float | None class UsageSummary(BaseModel): """Usage summary for billing page display.""" orders_this_period: int orders_limit: int | None orders_remaining: int | None products_count: int products_limit: int | None products_remaining: int | None team_count: int team_limit: int | None team_remaining: int | None class SubscriptionStatusResponse(BaseModel): """Subscription status with usage and limits.""" subscription: SubscriptionResponse usage: SubscriptionUsage tier_info: TierInfo # ============================================================================ # Limit Check Schemas # ============================================================================ class LimitCheckResult(BaseModel): """Result of a limit check.""" allowed: bool limit: int | None current: int remaining: int | None message: str | None = None class CanCreateOrderResponse(BaseModel): """Response for order creation check.""" allowed: bool orders_this_period: int orders_limit: int | None message: str | None = None class CanAddProductResponse(BaseModel): """Response for product addition check.""" allowed: bool products_count: int products_limit: int | None message: str | None = None class CanAddTeamMemberResponse(BaseModel): """Response for team member addition check.""" allowed: bool team_count: int team_limit: int | None message: str | None = None class FeatureCheckResponse(BaseModel): """Response for feature check.""" feature: str enabled: bool tier_required: str | None = None message: str | None = None