mirror of
http://88.130.71.182:3000/BlitTech/badoHair_be.git
synced 2026-06-12 23:23:22 +00:00
Initial Commit
This commit is contained in:
114
app/routers/admin/dashboard.py
Normal file
114
app/routers/admin/dashboard.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
import asyncpg
|
||||
|
||||
from app.core.responses import ok
|
||||
from app.dependencies import get_db, require_admin
|
||||
|
||||
router = APIRouter(prefix="/stats", tags=["Admin — Dashboard"])
|
||||
|
||||
|
||||
@router.get("/overview")
|
||||
async def overview(
|
||||
db: asyncpg.Connection = Depends(get_db),
|
||||
_: dict = Depends(require_admin),
|
||||
):
|
||||
# Revenue
|
||||
revenue_today = float(await db.fetchval(
|
||||
"SELECT COALESCE(SUM(total_amount),0) FROM orders WHERE status IN ('paid','processing','shipped','delivered') AND DATE(created_at)=CURRENT_DATE"
|
||||
) or 0)
|
||||
revenue_week = float(await db.fetchval(
|
||||
"SELECT COALESCE(SUM(total_amount),0) FROM orders WHERE status IN ('paid','processing','shipped','delivered') AND created_at>=date_trunc('week',now())"
|
||||
) or 0)
|
||||
revenue_month = float(await db.fetchval(
|
||||
"SELECT COALESCE(SUM(total_amount),0) FROM orders WHERE status IN ('paid','processing','shipped','delivered') AND created_at>=date_trunc('month',now())"
|
||||
) or 0)
|
||||
|
||||
# Booking counts — what the frontend dashboard shows
|
||||
orders_pending = int(await db.fetchval("SELECT COUNT(*) FROM orders WHERE status='pending'") or 0)
|
||||
bookings_pending = int(await db.fetchval("SELECT COUNT(*) FROM bookings WHERE status='pending'") or 0)
|
||||
bookings_confirmed = int(await db.fetchval(
|
||||
"SELECT COUNT(*) FROM bookings b JOIN time_slots ts ON ts.id=b.slot_id WHERE b.status='confirmed' AND ts.date>=CURRENT_DATE"
|
||||
) or 0)
|
||||
|
||||
# Products
|
||||
products_count = int(await db.fetchval("SELECT COUNT(*) FROM products WHERE is_hidden=false") or 0)
|
||||
catalog_value = float(await db.fetchval(
|
||||
"SELECT COALESCE(SUM(price),0) FROM products WHERE is_hidden=false"
|
||||
) or 0)
|
||||
low_stock_count = int(await db.fetchval(
|
||||
"SELECT COUNT(*) FROM products WHERE stock_quantity<=5 AND is_hidden=false"
|
||||
) or 0)
|
||||
|
||||
new_customers_month = int(await db.fetchval(
|
||||
"SELECT COUNT(*) FROM profiles WHERE role='client' AND created_at>=date_trunc('month',now())"
|
||||
) or 0)
|
||||
|
||||
return ok({
|
||||
# Revenue stats
|
||||
"revenue_today": revenue_today,
|
||||
"revenue_week": revenue_week,
|
||||
"revenue_month": revenue_month,
|
||||
# Booking stats (matches frontend dashboard cards)
|
||||
"orders_pending": orders_pending,
|
||||
"bookings_pending": bookings_pending,
|
||||
"bookings_confirmed": bookings_confirmed,
|
||||
"bookings_upcoming": bookings_confirmed,
|
||||
# Product stats (matches frontend dashboard cards)
|
||||
"products_count": products_count,
|
||||
"catalog_value": catalog_value,
|
||||
"low_stock_count": low_stock_count,
|
||||
# Customer stats
|
||||
"new_customers_month": new_customers_month,
|
||||
})
|
||||
|
||||
|
||||
@router.get("/revenue")
|
||||
async def revenue(
|
||||
period: str = Query("month", pattern="^(today|week|month|year)$"),
|
||||
db: asyncpg.Connection = Depends(get_db),
|
||||
_: dict = Depends(require_admin),
|
||||
):
|
||||
trunc = {"today": "day", "week": "week", "month": "month", "year": "year"}[period]
|
||||
rows = await db.fetch(
|
||||
f"""
|
||||
SELECT date_trunc('{trunc}', created_at) AS period,
|
||||
COALESCE(SUM(total_amount), 0) AS revenue,
|
||||
COUNT(*) AS orders_count
|
||||
FROM orders
|
||||
WHERE status IN ('paid','processing','shipped','delivered')
|
||||
AND created_at >= date_trunc('{trunc}', now()) - interval '12 {trunc}s'
|
||||
GROUP BY 1 ORDER BY 1 DESC
|
||||
""",
|
||||
)
|
||||
booking_rows = await db.fetch(
|
||||
f"""
|
||||
SELECT date_trunc('{trunc}', b.created_at) AS period,
|
||||
COALESCE(SUM(b.amount_paid), 0) AS revenue,
|
||||
COUNT(*) AS bookings_count
|
||||
FROM bookings b
|
||||
WHERE b.status IN ('confirmed','completed')
|
||||
AND b.created_at >= date_trunc('{trunc}', now()) - interval '12 {trunc}s'
|
||||
GROUP BY 1 ORDER BY 1 DESC
|
||||
""",
|
||||
)
|
||||
return ok({"orders": [dict(r) for r in rows], "bookings": [dict(r) for r in booking_rows]})
|
||||
|
||||
|
||||
@router.get("/activity", tags=["Admin — Dashboard"])
|
||||
async def activity(
|
||||
limit: int = Query(20, ge=1, le=100),
|
||||
db: asyncpg.Connection = Depends(get_db),
|
||||
_: dict = Depends(require_admin),
|
||||
):
|
||||
rows = await db.fetch(
|
||||
"""
|
||||
SELECT al.id, p.full_name AS actor_name, al.action,
|
||||
al.entity_type, al.entity_id, al.metadata, al.created_at
|
||||
FROM activity_log al
|
||||
LEFT JOIN profiles p ON p.id = al.actor_id
|
||||
ORDER BY al.created_at DESC
|
||||
LIMIT $1
|
||||
""",
|
||||
limit,
|
||||
)
|
||||
return ok([dict(r) for r in rows])
|
||||
Reference in New Issue
Block a user