# app/modules/billing/routes/pages/platform.py """ Billing Platform Page Routes (HTML rendering). Platform (unauthenticated) pages for pricing and signup: - Pricing page - Signup wizard - Signup success """ from fastapi import APIRouter, Depends, HTTPException, Request from fastapi.responses import HTMLResponse from sqlalchemy.orm import Session from app.core.database import get_db from app.modules.core.utils.page_context import get_platform_context from app.templates_config import templates def _require_platform(request: Request): """Get the current platform or raise 404. Platform must always be known.""" platform = getattr(request.state, "platform", None) if not platform: raise HTTPException( status_code=404, detail="Platform not detected. Pricing and signup require a known platform.", ) return platform router = APIRouter() def _get_tiers_data(db: Session, platform_id: int) -> list[dict]: """Build tier data for display in templates from database.""" from app.modules.billing.models import SubscriptionTier, TierCode query = db.query(SubscriptionTier).filter( SubscriptionTier.is_active == True, SubscriptionTier.is_public == True, SubscriptionTier.platform_id == platform_id, ) tiers_db = query.order_by(SubscriptionTier.display_order).all() tiers = [] for tier in tiers_db: feature_codes = sorted(tier.get_feature_codes()) tiers.append({ "code": tier.code, "name": tier.name, "price_monthly": tier.price_monthly_cents / 100, "price_annual": (tier.price_annual_cents / 100) if tier.price_annual_cents else None, "feature_codes": feature_codes, "products_limit": tier.get_limit_for_feature("products_limit"), "orders_per_month": tier.get_limit_for_feature("orders_per_month"), "team_members": tier.get_limit_for_feature("team_members"), "is_popular": tier.code == TierCode.PROFESSIONAL.value, "is_enterprise": tier.code == TierCode.ENTERPRISE.value, }) return tiers # ============================================================================ # PRICING PAGE # ============================================================================ @router.get("/pricing", response_class=HTMLResponse, name="platform_pricing") async def pricing_page( request: Request, db: Session = Depends(get_db), ): """ Standalone pricing page with detailed tier comparison. Tiers are filtered by the current platform (detected from domain/path). """ platform = _require_platform(request) context = get_platform_context(request, db) context["tiers"] = _get_tiers_data(db, platform_id=platform.id) context["page_title"] = "Pricing" return templates.TemplateResponse( "billing/platform/pricing.html", context, ) # ============================================================================ # SIGNUP WIZARD # ============================================================================ @router.get("/signup", response_class=HTMLResponse, name="platform_signup") async def signup_page( request: Request, tier: str | None = None, annual: bool = False, db: Session = Depends(get_db), ): """ Multi-step signup wizard. Routes to platform-specific signup templates. Each platform defines its own signup flow (different steps, different UI). Query params: - tier: Pre-selected tier code - annual: Pre-select annual billing """ platform = _require_platform(request) context = get_platform_context(request, db) context["page_title"] = "Start Your Free Trial" context["selected_tier"] = tier context["is_annual"] = annual context["tiers"] = _get_tiers_data(db, platform_id=platform.id) return templates.TemplateResponse( "billing/platform/signup.html", context, ) @router.get( "/signup/success", response_class=HTMLResponse, name="platform_signup_success" ) async def signup_success_page( request: Request, store_code: str | None = None, db: Session = Depends(get_db), ): """ Signup success page. Shown after successful account creation. """ context = get_platform_context(request, db) context["page_title"] = "Welcome to Orion!" context["store_code"] = store_code return templates.TemplateResponse( "billing/platform/signup-success.html", context, )