feat(dashboard): Complete dashboard desktop cleanup and improvements
User Stories Completed: - US-001: Eliminare SolduriCompactCard de pe Desktop - US-002: Eliminare Icoane din Header-ul CollapsibleCard - US-003: Reorganizare TreasuryDualCard - Text Înainte de Grafice - US-004: Reorganizare ClientiBalanceCard - Text Înainte de Grafice - US-005: Reorganizare FurnizoriBalanceCard - Text Înainte de Grafice - US-006: Grafice Colapsabile în TreasuryDualCard - US-007: Grafice Colapsabile în ClientiBalanceCard - US-008: Grafice Colapsabile în FurnizoriBalanceCard - US-009: Grafice Colapsabile în CashFlowMetricCard Additional Improvements: - Add cache metadata display (CacheFooter component) for all dashboard cards - Add @cached decorators to get_monthly_flows and get_indicators_with_sparklines - Fix financial indicators calculations and sparkline sync - Add state reset on company change to prevent stale data - New shared components: CacheFooter.vue, authRedirect.js - Enhanced FinancialIndicatorsCard with sparklines and period selection Squashed from branch: ralph/dashboard-desktop-cleanup (11 commits) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Request
|
||||
from typing import Optional
|
||||
# import sys # Removed - no longer needed
|
||||
import os
|
||||
|
||||
from shared.auth.dependencies import get_current_user
|
||||
@@ -290,6 +289,7 @@ async def get_maturity_analysis(
|
||||
|
||||
@router.get("/monthly-flows")
|
||||
async def get_monthly_flows(
|
||||
request: Request,
|
||||
company: int = Query(..., description="ID-ul firmei"),
|
||||
luna: Optional[int] = Query(None, ge=1, le=12, description="Luna contabilă (1-12)"),
|
||||
an: Optional[int] = Query(None, ge=2000, le=2100, description="Anul contabil"),
|
||||
@@ -301,15 +301,31 @@ async def get_monthly_flows(
|
||||
- Necesită autentificare JWT
|
||||
- Returnează date pentru analiza fluxurilor lunare
|
||||
- luna/an: perioada contabilă de referință (dacă nu sunt specificate, folosește ultima perioadă)
|
||||
- Include metadata cache pentru Telegram Bot (X-Include-Cache-Metadata header)
|
||||
"""
|
||||
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, luna=luna, an=an)
|
||||
return result
|
||||
|
||||
# Apelăm serviciul cu request pentru cache metadata
|
||||
result = await DashboardService.get_monthly_flows(company, luna=luna, an=an, request=request)
|
||||
|
||||
# Convert to dict if needed
|
||||
result_dict = result.dict() if hasattr(result, 'dict') else result
|
||||
|
||||
# Add cache metadata if requested (for Telegram Bot / Dashboard)
|
||||
include_metadata = request.headers.get('X-Include-Cache-Metadata', '').lower() == 'true'
|
||||
if include_metadata:
|
||||
cache_hit = getattr(request.state, 'cache_hit', False)
|
||||
response_time = getattr(request.state, 'response_time_ms', 0)
|
||||
cache_source = getattr(request.state, 'cache_source', None)
|
||||
result_dict['cache_hit'] = cache_hit
|
||||
result_dict['response_time_ms'] = response_time
|
||||
result_dict['cache_source'] = cache_source
|
||||
|
||||
return result_dict
|
||||
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
except Exception as e:
|
||||
@@ -435,7 +451,6 @@ async def get_current_period(
|
||||
|
||||
@router.get(
|
||||
"/financial-indicators",
|
||||
response_model=FinancialIndicatorsResponse,
|
||||
tags=["dashboard"]
|
||||
)
|
||||
async def get_financial_indicators(
|
||||
@@ -445,7 +460,7 @@ async def get_financial_indicators(
|
||||
an: Optional[int] = Query(None, ge=2000, le=2100, description="Anul contabil"),
|
||||
include_sparklines: bool = Query(True, description="Include date istorice pentru sparklines (12 luni)"),
|
||||
current_user: CurrentUser = Depends(get_current_user)
|
||||
) -> FinancialIndicatorsResponse:
|
||||
):
|
||||
"""
|
||||
Returnează toți indicatorii financiari calculați pentru firma selectată.
|
||||
|
||||
@@ -504,15 +519,25 @@ async def get_financial_indicators(
|
||||
# Dacă include_sparklines este True, folosim metoda care include datele istorice
|
||||
if include_sparklines:
|
||||
response = await FinancialIndicatorsService.get_indicators_with_sparklines(
|
||||
company, resolved_luna, resolved_an, months=12
|
||||
company, resolved_luna, resolved_an, months=12, request=request
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Financial indicators with sparklines for company {company}, "
|
||||
f"luna={resolved_luna}, an={resolved_an}: "
|
||||
f"Z-Score={response.altman_zscore.zscore.value} ({response.altman_zscore.zscore.status})"
|
||||
f"Z-Score={response.altman_zscore.zscore.value} ({response.altman_zscore.zscore.status}), "
|
||||
f"cache_hit={getattr(request.state, 'cache_hit', False)}, "
|
||||
f"response_time={getattr(request.state, 'response_time_ms', 0):.1f}ms"
|
||||
)
|
||||
|
||||
# Add cache metadata if requested (for Telegram Bot / Dashboard)
|
||||
include_metadata = request.headers.get('X-Include-Cache-Metadata', '').lower() == 'true'
|
||||
if include_metadata:
|
||||
result_dict = response.dict() if hasattr(response, 'dict') else response
|
||||
result_dict['cache_hit'] = getattr(request.state, 'cache_hit', False)
|
||||
result_dict['response_time_ms'] = getattr(request.state, 'response_time_ms', 0)
|
||||
result_dict['cache_source'] = getattr(request.state, 'cache_source', None)
|
||||
return result_dict
|
||||
return response
|
||||
|
||||
# Dacă include_sparklines este False, calculăm doar indicatorii curenți
|
||||
@@ -537,6 +562,12 @@ async def get_financial_indicators(
|
||||
altman_task = FinancialIndicatorsService.calculate_altman_zscore(
|
||||
company, resolved_luna, resolved_an
|
||||
)
|
||||
profitabilitate_task = FinancialIndicatorsService.calculate_profitability_indicators(
|
||||
company, resolved_luna, resolved_an
|
||||
)
|
||||
solvabilitate_task = FinancialIndicatorsService.calculate_solvability_indicators(
|
||||
company, resolved_luna, resolved_an
|
||||
)
|
||||
|
||||
# Executăm toate calculele în paralel pentru performanță
|
||||
(
|
||||
@@ -545,14 +576,18 @@ async def get_financial_indicators(
|
||||
risc,
|
||||
cash_flow,
|
||||
dinamica,
|
||||
altman_zscore
|
||||
altman_zscore,
|
||||
profitabilitate,
|
||||
solvabilitate
|
||||
) = await asyncio.gather(
|
||||
lichiditate_task,
|
||||
eficienta_task,
|
||||
risc_task,
|
||||
cash_flow_task,
|
||||
dinamica_task,
|
||||
altman_task
|
||||
altman_task,
|
||||
profitabilitate_task,
|
||||
solvabilitate_task
|
||||
)
|
||||
|
||||
# Construim răspunsul
|
||||
@@ -562,7 +597,9 @@ async def get_financial_indicators(
|
||||
risc=risc,
|
||||
cash_flow=cash_flow,
|
||||
dinamica=dinamica,
|
||||
altman_zscore=altman_zscore
|
||||
altman_zscore=altman_zscore,
|
||||
profitabilitate=profitabilitate,
|
||||
solvabilitate=solvabilitate
|
||||
)
|
||||
|
||||
logger.info(
|
||||
@@ -570,6 +607,14 @@ async def get_financial_indicators(
|
||||
f"Z-Score={altman_zscore.zscore.value} ({altman_zscore.zscore.status})"
|
||||
)
|
||||
|
||||
# Add cache metadata if requested (for Telegram Bot / Dashboard)
|
||||
include_metadata = request.headers.get('X-Include-Cache-Metadata', '').lower() == 'true'
|
||||
if include_metadata:
|
||||
result_dict = response.dict() if hasattr(response, 'dict') else response
|
||||
result_dict['cache_hit'] = getattr(request.state, 'cache_hit', False)
|
||||
result_dict['response_time_ms'] = getattr(request.state, 'response_time_ms', 0)
|
||||
result_dict['cache_source'] = getattr(request.state, 'cache_source', None)
|
||||
return result_dict
|
||||
return response
|
||||
|
||||
except ValueError as e:
|
||||
|
||||
Reference in New Issue
Block a user