from fastapi import APIRouter, Depends, HTTPException from decimal import Decimal from pydantic import BaseModel from ..auth import get_current_user from ..models import User from ..billing.models import PricingConfig, Invoice, SubscriptionPlan from ..billing.invoice_generator import InvoiceGenerator def require_superuser(current_user: User = Depends(get_current_user)): if not current_user.is_superuser: raise HTTPException(status_code=403, detail="Superuser privileges required") return current_user router = APIRouter( prefix="/api/admin/billing", tags=["admin", "billing"], dependencies=[Depends(require_superuser)], ) class PricingConfigUpdate(BaseModel): config_key: str config_value: float class PlanCreate(BaseModel): name: str display_name: str description: str storage_gb: int bandwidth_gb: int price_monthly: float price_yearly: float = None @router.get("/pricing") async def get_all_pricing(current_user: User = Depends(require_superuser)): configs = await PricingConfig.all() return [ { "id": c.id, "config_key": c.config_key, "config_value": float(c.config_value), "description": c.description, "unit": c.unit, "updated_at": c.updated_at, } for c in configs ] @router.put("/pricing/{config_id}") async def update_pricing( config_id: int, update: PricingConfigUpdate, current_user: User = Depends(require_superuser), ): config = await PricingConfig.get_or_none(id=config_id) if not config: raise HTTPException(status_code=404, detail="Config not found") config.config_value = Decimal(str(update.config_value)) config.updated_by = current_user await config.save() return {"message": "Pricing updated successfully"} @router.post("/generate-invoices/{year}/{month}") async def generate_all_invoices( year: int, month: int, current_user: User = Depends(require_superuser) ): users = await User.filter(is_active=True).all() generated = [] skipped = [] for user in users: invoice = await InvoiceGenerator.generate_monthly_invoice(user, year, month) if invoice: generated.append( { "user_id": user.id, "invoice_id": invoice.id, "total": float(invoice.total), } ) else: skipped.append(user.id) return {"generated": len(generated), "skipped": len(skipped), "invoices": generated} @router.post("/plans") async def create_plan( plan_data: PlanCreate, current_user: User = Depends(require_superuser) ): plan = await SubscriptionPlan.create(**plan_data.dict()) return {"id": plan.id, "message": "Plan created successfully"} @router.get("/stats") async def get_billing_stats(current_user: User = Depends(require_superuser)): from tortoise.functions import Sum total_revenue = ( await Invoice.filter(status="paid") .annotate(total_sum=Sum("total")) .values("total_sum") ) invoice_count = await Invoice.all().count() pending_invoices = await Invoice.filter(status="open").count() return { "total_revenue": float(total_revenue[0]["total_sum"] or 0), "total_invoices": invoice_count, "pending_invoices": pending_invoices, }