bmc_hub/app/dashboard/backend/router.py

224 lines
7.6 KiB
Python
Raw Permalink Normal View History

from fastapi import APIRouter, HTTPException
from app.core.database import execute_query
from typing import Dict, Any, List
import logging
logger = logging.getLogger(__name__)
router = APIRouter()
@router.get("/stats", response_model=Dict[str, Any])
async def get_dashboard_stats():
"""
Get aggregated statistics for the dashboard
"""
try:
logger.info("📊 Fetching dashboard stats...")
# 1. Customer Counts
logger.info("Fetching customer count...")
customer_res = execute_query("SELECT COUNT(*) as count FROM customers WHERE deleted_at IS NULL", fetchone=True)
customer_count = customer_res['count'] if customer_res else 0
# 2. Contact Counts
logger.info("Fetching contact count...")
contact_res = execute_query("SELECT COUNT(*) as count FROM contacts", fetchone=True)
contact_count = contact_res['count'] if contact_res else 0
# 3. Vendor Counts
logger.info("Fetching vendor count...")
vendor_res = execute_query("SELECT COUNT(*) as count FROM vendors", fetchone=True)
vendor_count = vendor_res['count'] if vendor_res else 0
# 4. Recent Customers (Real "Activity")
logger.info("Fetching recent customers...")
recent_customers = execute_query("""
SELECT id, name, created_at, 'customer' as type
FROM customers
WHERE deleted_at IS NULL
ORDER BY created_at DESC
LIMIT 5
""")
# 5. Vendor Categories Distribution
logger.info("Fetching vendor distribution...")
vendor_categories = execute_query("""
SELECT category, COUNT(*) as count
FROM vendors
GROUP BY category
""")
logger.info("✅ Dashboard stats fetched successfully")
return {
"counts": {
"customers": customer_count,
"contacts": contact_count,
"vendors": vendor_count
},
"recent_activity": recent_customers or [],
"vendor_distribution": vendor_categories or [],
"system_status": "online"
}
except Exception as e:
logger.error(f"❌ Error fetching dashboard stats: {e}", exc_info=True)
raise HTTPException(status_code=500, detail=str(e))
@router.get("/search", response_model=Dict[str, List[Any]])
async def global_search(q: str):
"""
Global search across customers, contacts, and vendors
"""
if not q or len(q) < 2:
return {"customers": [], "contacts": [], "vendors": []}
search_term = f"%{q}%"
try:
# Search Customers
customers = execute_query("""
SELECT id, name, email, 'Kunde' as type
FROM customers
WHERE deleted_at IS NULL AND (
name ILIKE %s OR
email ILIKE %s OR
cvr_number ILIKE %s OR
phone ILIKE %s OR
mobile_phone ILIKE %s
)
LIMIT 5
""", (search_term, search_term, search_term, search_term, search_term))
# Search Contacts
contacts = execute_query("""
SELECT id, first_name || ' ' || last_name as name, email, 'Kontakt' as type
FROM contacts
WHERE first_name ILIKE %s OR
last_name ILIKE %s OR
email ILIKE %s OR
phone ILIKE %s OR
mobile ILIKE %s
LIMIT 5
""", (search_term, search_term, search_term, search_term, search_term))
# Search Vendors
vendors = execute_query("""
SELECT id, name, email, 'Leverandør' as type
FROM vendors
WHERE is_active = true AND (
name ILIKE %s OR
email ILIKE %s OR
cvr_number ILIKE %s OR
phone ILIKE %s
)
LIMIT 5
""", (search_term, search_term, search_term, search_term))
return {
"customers": customers or [],
"contacts": contacts or [],
"vendors": vendors or []
}
except Exception as e:
logger.error(f"❌ Error performing global search: {e}", exc_info=True)
return {"customers": [], "contacts": [], "vendors": []}
@router.get("/live-stats", response_model=Dict[str, Any])
async def get_live_stats():
"""
Get live statistics for the three live boxes: Sales, Support, Økonomi
"""
try:
# Sales Stats (placeholder - replace with real data when tables exist)
sales_stats = {
"active_orders": 0,
"monthly_sales": 0,
"open_quotes": 0
}
# Support Stats (placeholder)
support_stats = {
"open_tickets": 0,
"avg_response_time": 0,
"today_tickets": 0
}
# Finance Stats (placeholder)
finance_stats = {
"unpaid_invoices_count": 0,
"unpaid_invoices_amount": 0,
"overdue_invoices": 0,
"today_payments": 0
}
# Try to get real customer count as a demo
try:
customer_count = execute_query("SELECT COUNT(*) as count FROM customers WHERE deleted_at IS NULL", fetchone=True)
sales_stats["active_orders"] = customer_count.get('count', 0) if customer_count else 0
except:
pass
return {
"sales": sales_stats,
"support": support_stats,
"finance": finance_stats
}
except Exception as e:
logger.error(f"❌ Error fetching live stats: {e}", exc_info=True)
return {
"sales": {"active_orders": 0, "monthly_sales": 0, "open_quotes": 0},
"support": {"open_tickets": 0, "avg_response_time": 0, "today_tickets": 0},
"finance": {"unpaid_invoices_count": 0, "unpaid_invoices_amount": 0, "overdue_invoices": 0, "today_payments": 0}
}
@router.get("/recent-activity", response_model=List[Dict[str, Any]])
async def get_recent_activity():
"""
Get recent activity across the system for the sidebar
"""
try:
activities = []
# Recent customers
recent_customers = execute_query("""
SELECT id, name, created_at, 'customer' as activity_type, 'bi-building' as icon, 'primary' as color
FROM customers
WHERE deleted_at IS NULL
ORDER BY created_at DESC
LIMIT 3
""")
# Recent contacts
recent_contacts = execute_query("""
SELECT id, first_name || ' ' || last_name as name, created_at, 'contact' as activity_type, 'bi-person' as icon, 'success' as color
FROM contacts
ORDER BY created_at DESC
LIMIT 3
""")
# Recent vendors
recent_vendors = execute_query("""
SELECT id, name, created_at, 'vendor' as activity_type, 'bi-shop' as icon, 'info' as color
FROM vendors
ORDER BY created_at DESC
LIMIT 2
""")
# Combine all activities
if recent_customers:
activities.extend(recent_customers)
if recent_contacts:
activities.extend(recent_contacts)
if recent_vendors:
activities.extend(recent_vendors)
# Sort by created_at and limit
activities.sort(key=lambda x: x.get('created_at', ''), reverse=True)
return activities[:10]
except Exception as e:
logger.error(f"❌ Error fetching recent activity: {e}", exc_info=True)
return []