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 []