from fastapi import APIRouter, Depends, HTTPException, Query from typing import Optional import sys import os sys.path.append(os.path.join(os.path.dirname(__file__), '../../../../shared')) from auth.dependencies import get_current_user from auth.models import CurrentUser import logging logger = logging.getLogger(__name__) from ..models.dashboard import DashboardSummary, TrendsResponse, TrendData from ..services.dashboard_service import DashboardService router = APIRouter() @router.get("/summary", response_model=DashboardSummary) async def get_dashboard_summary( company: str = Query(description="Codul firmei"), current_user: CurrentUser = Depends(get_current_user) ): """ Obține toate datele pentru dashboard într-un singur apel - Necesită autentificare JWT - Returnează statistici clienți/furnizori și trezorerie """ try: # Verifică dacă utilizatorul are acces la firma specificată if company not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_complete_summary(company, current_user.username) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: raise HTTPException(status_code=500, detail=f"Eroare la obținerea datelor dashboard: {str(e)}") @router.get("/trends", response_model=TrendsResponse) async def get_dashboard_trends( company: str = Query(description="Codul firmei"), period: str = Query(default="30d", description="Perioada pentru trends: 7d, 30d, ytd, 12m"), compare_previous: bool = Query(default=True, description="Compară cu perioada anterioară"), current_user: CurrentUser = Depends(get_current_user) ): """ Obține trenduri pentru indicatorii principali (clienți/furnizori) - period: "7d" (7 zile), "30d" (30 zile), "ytd" (year to date), "12m" (12 luni) - compare_previous: dacă să compare cu perioada anterioară - Necesită autentificare JWT - Returnează date pentru grafice de trenduri """ try: # Verifică dacă utilizatorul are acces la firma specificată if company not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") # Validează perioada valid_periods = ["7d", "30d", "ytd", "12m"] if period not in valid_periods: raise HTTPException( status_code=400, detail=f"Perioadă nevalidă: {period}. Valori permise: {', '.join(valid_periods)}" ) # Obține datele de trenduri result = await DashboardService.get_trends(int(company), period) # The service now returns the data in the correct format # Return it directly as TrendsResponse return TrendsResponse(**result) except ValueError as e: logger.error(f"Value error in trends endpoint: {str(e)}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea trendurilor: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea trendurilor: {str(e)}") @router.get("/detailed-data") async def get_detailed_data( company: str = Query(description="Codul firmei"), data_type: str = Query(description="Tipul de date: clients, suppliers, treasury"), page: int = Query(default=1, ge=1), page_size: int = Query(default=25, ge=1, le=100), search: str = Query(default="", description="Termen de căutare"), current_user: CurrentUser = Depends(get_current_user) ): """ Obține date detaliate pentru tabelele din dashboard """ logger.info(f"[ROUTER] detailed-data called: company={company}, data_type={data_type}") try: if company not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") logger.info(f"[ROUTER] Calling DashboardService.get_detailed_data") result = await DashboardService.get_detailed_data( company=company, data_type=data_type, page=page, page_size=page_size, search=search ) logger.info(f"[ROUTER] Service returned: {len(result.get('data', []))} rows") return result except Exception as e: logger.error(f"Eroare la obținerea datelor detaliate: {str(e)}") raise HTTPException(status_code=500, detail=str(e)) @router.get("/performance") async def get_performance( company: int = Query(..., description="ID-ul firmei"), period: str = Query("7d", regex="^(7d|1m|3m|6m|ytd|12m)$", description="Perioada pentru analiză"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează date performanță pentru perioada selectată - Necesită autentificare JWT - Returnează grafice încasări vs plăți pentru perioada selectată - Calculează indicatori: rata încasării, cash conversion, working capital """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_performance_data(company, period) # Convert to Chart.js compatible format return { "labels": result.get("labels", []), "datasets": [{ "data": result.get("data", []), "label": result.get("label", "Performance"), "borderColor": result.get("borderColor", "#3B82F6"), "backgroundColor": result.get("backgroundColor", "rgba(59, 130, 246, 0.1)"), "tension": 0.4 }] } except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea datelor de performanță: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea datelor de performanță: {str(e)}") @router.get("/cashflow") async def get_cashflow( company: int = Query(..., description="ID-ul firmei"), period: str = Query("7d", regex="^(7d|1m|3m|6m)$", description="Perioada pentru previziune"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează previziune cash flow pentru perioada selectată - Necesită autentificare JWT - Analizează scadențele viitoare pentru calculul cash flow-ului - Identifică zilele critice cu deficit de cash """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_cashflow_forecast(company, period) # Convert to Chart.js compatible format return { "labels": result.get("labels", []), "datasets": [{ "data": result.get("data", []), "label": result.get("label", "Cash Flow"), "borderColor": result.get("borderColor", "#10B981"), "backgroundColor": result.get("backgroundColor", "rgba(16, 185, 129, 0.1)"), "tension": 0.4 }] } except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea previziunii cash flow: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea previziunii cash flow: {str(e)}") @router.get("/maturity") async def get_maturity_analysis( company: int = Query(..., description="ID-ul firmei"), period: str = Query("7d", regex="^(7d|1m|3m|6m|12m|all)$", description="Orizont de planificare pentru analiza scadențelor"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează analiza scadențelor pentru orizontul de planificare selectat - Necesită autentificare JWT - Logică: Include TOATE restanțele + scadențele viitoare din perioada selectată - Perioade disponibile: * 7d: Toate restanțele + scadențe următoarelor 7 zile * 1m: Toate restanțele + scadențe următoarelor 30 zile * 3m: Toate restanțele + scadențe următoarelor 90 zile * 6m: Toate restanțele + scadențe următoarelor 180 zile * 12m: Toate restanțele + scadențe următoarelor 365 zile * all: Toate soldurile (fără filtru) - Compară scadențele clienți vs furnizori - Calculează balanța și oferă recomandări - Returnează metadate cu statistici complete """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_maturity_analysis(company, period) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea analizei scadențelor: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea analizei scadențelor: {str(e)}") @router.get("/monthly-flows") async def get_monthly_flows( company: int = Query(..., description="ID-ul firmei"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează fluxurile lunare pentru firma selectată - Necesită autentificare JWT - Returnează date pentru analiza fluxurilor lunare """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_monthly_flows(company) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea fluxurilor lunare: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea fluxurilor lunare: {str(e)}") @router.get("/treasury-breakdown") async def get_treasury_breakdown( company: int = Query(..., description="ID-ul firmei"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează defalcarea trezoreriei pentru firma selectată - Necesită autentificare JWT - Returnează distribuția soldurilor pe conturi și tipuri """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_treasury_breakdown(company) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea defalcării trezoreriei: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea defalcării trezoreriei: {str(e)}") @router.get("/net-balance-breakdown") async def get_net_balance_breakdown( company: int = Query(..., description="ID-ul firmei"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează defalcarea balanței nete pentru firma selectată - Necesită autentificare JWT - Returnează analiza detaliată a balanței nete """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_net_balance_breakdown(company) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea defalcării balanței nete: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea defalcării balanței nete: {str(e)}") @router.get("/current-period") async def get_current_period( company: int = Query(..., description="ID-ul firmei"), current_user: CurrentUser = Depends(get_current_user) ): """ Returnează perioada curentă (an și lună) din calendarul Oracle - Necesită autentificare JWT - Returnează anul, luna și perioada curentă în format YYYY-MM - Folosit pentru afișarea lunii curente în dashboard """ try: # Verifică dacă utilizatorul are acces la firma specificată if str(company) not in current_user.companies: raise HTTPException(status_code=403, detail=f"Nu aveți acces la firma {company}") result = await DashboardService.get_current_period(company) return result except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error(f"Eroare la obținerea perioadei curente: {str(e)}") raise HTTPException(status_code=500, detail=f"Eroare la obținerea perioadei curente: {str(e)}")