# app/modules/billing/routes/api/store_usage.py """ Store usage and limits API endpoints. Provides endpoints for: - Current usage vs limits - Upgrade recommendations - Approaching limit warnings Migrated from app/api/v1/store/usage.py to billing module. """ import logging from fastapi import APIRouter, Depends from pydantic import BaseModel from sqlalchemy.orm import Session from app.api.deps import get_current_store_api, require_module_access from app.core.database import get_db from app.modules.billing.services.usage_service import usage_service from app.modules.enums import FrontendType from app.modules.tenancy.schemas.auth import UserContext store_usage_router = APIRouter( prefix="/usage", dependencies=[Depends(require_module_access("billing", FrontendType.STORE))], ) logger = logging.getLogger(__name__) # ============================================================================ # Response Schemas # ============================================================================ class UsageMetric(BaseModel): """Single usage metric.""" name: str current: int limit: int | None # None = unlimited percentage: float # 0-100, or 0 if unlimited is_unlimited: bool is_at_limit: bool is_approaching_limit: bool # >= 80% class TierInfo(BaseModel): """Current tier information.""" code: str name: str price_monthly_cents: int is_highest_tier: bool class UpgradeTierInfo(BaseModel): """Next tier upgrade information.""" code: str name: str price_monthly_cents: int price_increase_cents: int benefits: list[str] class UsageResponse(BaseModel): """Full usage response with limits and upgrade info.""" tier: TierInfo usage: list[UsageMetric] has_limits_approaching: bool has_limits_reached: bool upgrade_available: bool upgrade_tier: UpgradeTierInfo | None = None upgrade_reasons: list[str] class LimitCheckResponse(BaseModel): """Response for checking a specific limit.""" limit_type: str can_proceed: bool current: int limit: int | None percentage: float message: str | None = None upgrade_tier_code: str | None = None upgrade_tier_name: str | None = None # ============================================================================ # Endpoints # ============================================================================ @store_usage_router.get("", response_model=UsageResponse) def get_usage( current_user: UserContext = Depends(get_current_store_api), db: Session = Depends(get_db), ): """ Get current usage, limits, and upgrade recommendations. Returns comprehensive usage info for displaying in dashboard and determining when to show upgrade prompts. """ store_id = current_user.token_store_id # Get usage data from service usage_data = usage_service.get_store_usage(db, store_id) # Convert to response return UsageResponse( tier=TierInfo( code=usage_data.tier.code, name=usage_data.tier.name, price_monthly_cents=usage_data.tier.price_monthly_cents, is_highest_tier=usage_data.tier.is_highest_tier, ), usage=[ UsageMetric( name=m.name, current=m.current, limit=m.limit, percentage=m.percentage, is_unlimited=m.is_unlimited, is_at_limit=m.is_at_limit, is_approaching_limit=m.is_approaching_limit, ) for m in usage_data.usage ], has_limits_approaching=usage_data.has_limits_approaching, has_limits_reached=usage_data.has_limits_reached, upgrade_available=usage_data.upgrade_available, upgrade_tier=( UpgradeTierInfo( code=usage_data.upgrade_tier.code, name=usage_data.upgrade_tier.name, price_monthly_cents=usage_data.upgrade_tier.price_monthly_cents, price_increase_cents=usage_data.upgrade_tier.price_increase_cents, benefits=usage_data.upgrade_tier.benefits, ) if usage_data.upgrade_tier else None ), upgrade_reasons=usage_data.upgrade_reasons, ) @store_usage_router.get("/check/{limit_type}", response_model=LimitCheckResponse) def check_limit( limit_type: str, current_user: UserContext = Depends(get_current_store_api), db: Session = Depends(get_db), ): """ Check a specific limit before performing an action. Use this before creating orders, products, or inviting team members. Args: limit_type: One of "orders", "products", "team_members" Returns: Whether the action can proceed and upgrade info if not """ store_id = current_user.token_store_id # Check limit using service check_data = usage_service.check_limit(db, store_id, limit_type) return LimitCheckResponse( limit_type=check_data.limit_type, can_proceed=check_data.can_proceed, current=check_data.current, limit=check_data.limit, percentage=check_data.percentage, message=check_data.message, upgrade_tier_code=check_data.upgrade_tier_code, upgrade_tier_name=check_data.upgrade_tier_name, )