122 lines
3.3 KiB
Python
Raw Normal View History

2025-11-10 15:46:40 +01:00
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
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
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
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
router = APIRouter(
prefix="/api/admin/billing",
tags=["admin", "billing"],
2025-11-13 23:22:05 +01:00
dependencies=[Depends(require_superuser)],
2025-11-10 15:46:40 +01:00
)
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
class PricingConfigUpdate(BaseModel):
config_key: str
config_value: float
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
class PlanCreate(BaseModel):
name: str
display_name: str
description: str
storage_gb: int
bandwidth_gb: int
price_monthly: float
price_yearly: float = None
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
@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,
2025-11-13 23:22:05 +01:00
"updated_at": c.updated_at,
2025-11-10 15:46:40 +01:00
}
for c in configs
]
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
@router.put("/pricing/{config_id}")
async def update_pricing(
config_id: int,
update: PricingConfigUpdate,
2025-11-13 23:22:05 +01:00
current_user: User = Depends(require_superuser),
2025-11-10 15:46:40 +01:00
):
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"}
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
@router.post("/generate-invoices/{year}/{month}")
async def generate_all_invoices(
2025-11-13 23:22:05 +01:00
year: int, month: int, current_user: User = Depends(require_superuser)
2025-11-10 15:46:40 +01:00
):
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:
2025-11-13 23:22:05 +01:00
generated.append(
{
"user_id": user.id,
"invoice_id": invoice.id,
"total": float(invoice.total),
}
)
2025-11-10 15:46:40 +01:00
else:
skipped.append(user.id)
2025-11-13 23:22:05 +01:00
return {"generated": len(generated), "skipped": len(skipped), "invoices": generated}
2025-11-10 15:46:40 +01:00
@router.post("/plans")
async def create_plan(
2025-11-13 23:22:05 +01:00
plan_data: PlanCreate, current_user: User = Depends(require_superuser)
2025-11-10 15:46:40 +01:00
):
plan = await SubscriptionPlan.create(**plan_data.dict())
return {"id": plan.id, "message": "Plan created successfully"}
2025-11-13 23:22:05 +01:00
2025-11-10 15:46:40 +01:00
@router.get("/stats")
async def get_billing_stats(current_user: User = Depends(require_superuser)):
2025-11-13 23:22:05 +01:00
from tortoise.functions import Sum
2025-11-10 15:46:40 +01:00
2025-11-13 23:22:05 +01:00
total_revenue = (
await Invoice.filter(status="paid")
.annotate(total_sum=Sum("total"))
.values("total_sum")
)
2025-11-10 15:46:40 +01:00
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,
2025-11-13 23:22:05 +01:00
"pending_invoices": pending_invoices,
2025-11-10 15:46:40 +01:00
}