# app/modules/billing/routes/api/vendor_addons.py """ Vendor add-on management endpoints. Provides: - List available add-ons - Get vendor's purchased add-ons - Purchase add-on - Cancel add-on All routes require module access control for the 'billing' module. """ import logging from fastapi import APIRouter, Depends, Query from pydantic import BaseModel from sqlalchemy.orm import Session from app.api.deps import get_current_vendor_api, require_module_access from app.core.config import settings from app.core.database import get_db from app.modules.billing.services import billing_service from app.modules.enums import FrontendType from models.schema.auth import UserContext vendor_addons_router = APIRouter( prefix="/addons", dependencies=[Depends(require_module_access("billing", FrontendType.VENDOR))], ) logger = logging.getLogger(__name__) # ============================================================================ # Schemas # ============================================================================ class AddOnResponse(BaseModel): """Add-on product information.""" id: int code: str name: str description: str | None = None category: str price_cents: int billing_period: str quantity_unit: str | None = None quantity_value: int | None = None class VendorAddOnResponse(BaseModel): """Vendor's purchased add-on.""" id: int addon_code: str addon_name: str status: str domain_name: str | None = None quantity: int period_start: str | None = None period_end: str | None = None class AddOnPurchaseRequest(BaseModel): """Request to purchase an add-on.""" addon_code: str domain_name: str | None = None # For domain add-ons quantity: int = 1 class AddOnCancelResponse(BaseModel): """Response for add-on cancellation.""" message: str addon_code: str # ============================================================================ # Endpoints # ============================================================================ @vendor_addons_router.get("", response_model=list[AddOnResponse]) def get_available_addons( category: str | None = Query(None, description="Filter by category"), current_user: UserContext = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """Get available add-on products.""" addons = billing_service.get_available_addons(db, category=category) return [ AddOnResponse( id=addon.id, code=addon.code, name=addon.name, description=addon.description, category=addon.category, price_cents=addon.price_cents, billing_period=addon.billing_period, quantity_unit=addon.quantity_unit, quantity_value=addon.quantity_value, ) for addon in addons ] @vendor_addons_router.get("/my-addons", response_model=list[VendorAddOnResponse]) def get_vendor_addons( current_user: UserContext = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """Get vendor's purchased add-ons.""" vendor_id = current_user.token_vendor_id vendor_addons = billing_service.get_vendor_addons(db, vendor_id) return [ VendorAddOnResponse( id=va.id, addon_code=va.addon_product.code, addon_name=va.addon_product.name, status=va.status, domain_name=va.domain_name, quantity=va.quantity, period_start=va.period_start.isoformat() if va.period_start else None, period_end=va.period_end.isoformat() if va.period_end else None, ) for va in vendor_addons ] @vendor_addons_router.post("/purchase") def purchase_addon( request: AddOnPurchaseRequest, current_user: UserContext = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """Purchase an add-on product.""" vendor_id = current_user.token_vendor_id vendor = billing_service.get_vendor(db, vendor_id) # Build URLs base_url = f"https://{settings.platform_domain}" success_url = f"{base_url}/vendor/{vendor.vendor_code}/billing?addon_success=true" cancel_url = f"{base_url}/vendor/{vendor.vendor_code}/billing?addon_cancelled=true" result = billing_service.purchase_addon( db=db, vendor_id=vendor_id, addon_code=request.addon_code, domain_name=request.domain_name, quantity=request.quantity, success_url=success_url, cancel_url=cancel_url, ) db.commit() return result @vendor_addons_router.delete("/{addon_id}", response_model=AddOnCancelResponse) def cancel_addon( addon_id: int, current_user: UserContext = Depends(get_current_vendor_api), db: Session = Depends(get_db), ): """Cancel a purchased add-on.""" vendor_id = current_user.token_vendor_id result = billing_service.cancel_addon(db, vendor_id, addon_id) db.commit() return AddOnCancelResponse( message=result["message"], addon_code=result["addon_code"], )