Implementare completă a card-ului Indicatori Financiari în Dashboard Solduri: Backend: - Model FinancialIndicators cu 22+ indicatori organizați pe categorii - Service cu calcule din VBAL (Lichiditate, Eficiență, Risc, Cash Flow, Dinamică) - Altman Z-Score cu toate componentele (X1-X4) și valori absolute - Profitabilitate cu ROA, ROE, Cifra Afaceri, Cheltuieli separate (operaționale/financiare) - Caching inteligent pe company_id, luna, an Frontend: - FinancialIndicatorsCard.vue cu 4 indicatori principali collapsed - Expanded view grupat pe categorii (desktop + mobile BottomSheet) - Subindicatori pentru verificare manuală în balanță - Traduceri complete în română - Dark mode support complet - Sparklines cu tooltips - Responsive design (desktop grid + mobile carousel) Documentație: - PRD complet cu specificații și formule - Descrieri cu conturi din planul contabil român (OMFP 1802/2014) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
312 lines
17 KiB
JSON
312 lines
17 KiB
JSON
{
|
|
"projectName": "financial-indicators-dashboard",
|
|
"branchName": "ralph/financial-indicators-dashboard",
|
|
"description": "Adaugare card indicatori financiari in dashboard solduri cu rate de lichiditate, eficienta, risc si Altman Z-Score pentru evaluare bancara/creditare",
|
|
"cssRules": {
|
|
"documentation": [
|
|
"docs/ONBOARDING_CSS.md",
|
|
"docs/DESIGN_TOKENS.md",
|
|
"docs/CSS_PATTERNS.md",
|
|
"docs/MOBILE_PATTERNS.md"
|
|
],
|
|
"goldenRules": [
|
|
"Foloseste DOAR design tokens - NICIODATA valori hardcodate",
|
|
"Testeaza in AMBELE teme (light + dark mode)",
|
|
"Mobile: touch targets minim 44x44px",
|
|
"Backend: foloseste decorator @cached pentru caching",
|
|
"Backend: urmeaza pattern-ul din dashboard_service.py"
|
|
]
|
|
},
|
|
"referenceFiles": {
|
|
"dashboardService": "backend/modules/reports/services/dashboard_service.py",
|
|
"dashboardRouter": "backend/modules/reports/routers/dashboard.py",
|
|
"dashboardView": "src/modules/reports/views/DashboardView.vue",
|
|
"dashboardStore": "src/modules/reports/stores/dashboard.js",
|
|
"existingCards": [
|
|
"src/modules/reports/components/dashboard/cards/TreasuryDualCard.vue",
|
|
"src/modules/reports/components/dashboard/cards/CashFlowMetricCard.vue",
|
|
"src/modules/reports/components/solduri/SolduriCompactCard.vue"
|
|
]
|
|
},
|
|
"userStories": [
|
|
{
|
|
"id": "US-001",
|
|
"title": "Backend - Serviciu Agregare Conturi Balanta",
|
|
"description": "Ca dezvoltator backend, vreau un serviciu care agregeaza soldurile din balanta de verificare (VBAL) pe clase de conturi, pentru ca am nevoie de date agregate pentru calculul indicatorilor de bilant si Altman Z-Score",
|
|
"priority": 1,
|
|
"acceptanceCriteria": [
|
|
"Creat backend/modules/reports/services/financial_indicators_service.py",
|
|
"Clasa FinancialIndicatorsService cu metodele statice necesare",
|
|
"Constanta ACCOUNT_GROUPS cu prefixele conturilor pentru fiecare categorie",
|
|
"Metoda get_balance_sheet_aggregates(company_id, luna, an) returneaza dict cu solduri agregate pentru: active_imobilizate, stocuri, creante, disponibilitati, capital_propriu, rezultat, datorii_termen_lung, datorii_curente, venituri, cheltuieli_operationale",
|
|
"Query-ul foloseste VBAL view cu LIKE pentru prefixe conturi (ex: cont LIKE '20%')",
|
|
"Cache implementat cu decorator @cached(cache_type='financial_indicators', key_params=['company_id', 'luna', 'an'])",
|
|
"Structura raspunsului documentata cu Pydantic model BalanceSheetAggregates"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 1"
|
|
},
|
|
{
|
|
"id": "US-002",
|
|
"title": "Backend - Calcul Indicatori Lichiditate",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad indicatorii de lichiditate calculati automat, pentru ca vreau sa stiu daca firma poate plati datoriile pe termen scurt",
|
|
"priority": 2,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_liquidity_indicators(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat lichiditate_curenta = active_curente / datorii_curente",
|
|
"Calculat lichiditate_imediata (Quick Ratio) = (disponibilitati + creante) / datorii_curente",
|
|
"Calculat lichiditate_vedere (Cash Ratio) = disponibilitati / datorii_curente",
|
|
"Fiecare indicator returneaza dict cu: value, status (good/warning/danger), threshold_min, threshold_max",
|
|
"Status: good pentru lichiditate_imediata >= 1.0, warning pentru 0.5-1.0, danger pentru < 0.5",
|
|
"Handle cazul cand datorii_curente = 0 (returneaza null sau infinit cu mesaj)"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 2"
|
|
},
|
|
{
|
|
"id": "US-003",
|
|
"title": "Backend - Calcul Indicatori Eficienta",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad indicatorii de eficienta (DSO, DPO, rate), pentru ca vreau sa stiu cat de repede convertesc resursele in bani",
|
|
"priority": 3,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_efficiency_indicators(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat dso (Durata Incasare) = (clienti_sold / facturari_lunare) * 30",
|
|
"Calculat dpo (Durata Plata) = (furnizori_sold / achizitii_lunare) * 30",
|
|
"Calculat cash_conversion_cycle = dso - dpo",
|
|
"Calculat rata_incasare = incasari / facturari * 100",
|
|
"Calculat rata_plata = plati / achizitii * 100",
|
|
"Status: good pentru DSO < 30, warning pentru 30-45, danger pentru > 45",
|
|
"Foloseste datele din summary si trends existente pentru facturari/incasari"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 3"
|
|
},
|
|
{
|
|
"id": "US-004",
|
|
"title": "Backend - Calcul Indicatori Risc si Aging",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad indicatorii de risc si aging creante/datorii, pentru ca vreau sa stiu cat de sanatos este portofoliul de creante",
|
|
"priority": 4,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_risk_indicators(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat creante_restante_pct = clienti_sold_restant / clienti_sold_total * 100",
|
|
"Calculat creante_90plus_pct = clienti_restant_90plus / clienti_sold_total * 100",
|
|
"Calculat datorii_restante_pct = furnizori_sold_restant / furnizori_sold_total * 100",
|
|
"Calculat raport_datorii_trezorerie = furnizori_sold_total / trezorerie",
|
|
"Status: good pentru creante_restante_pct < 20%, warning pentru 20-30%, danger pentru > 30%",
|
|
"Foloseste datele din summary existente pentru aging"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 4"
|
|
},
|
|
{
|
|
"id": "US-005",
|
|
"title": "Backend - Calcul Indicatori Cash Flow",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad indicatorii de cash flow, pentru ca vreau sa stiu daca firma genereaza sau consuma numerar",
|
|
"priority": 5,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_cashflow_indicators(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat flux_net_lunar = incasari_luna - plati_luna",
|
|
"Calculat cash_flow_ytd = suma fluxurilor de la ianuarie pana la luna curenta",
|
|
"Calculat flux_net_yoy_pct = (cf_curent - cf_anterior) / abs(cf_anterior) * 100",
|
|
"Calculat acoperire_cash_flow = cash_flow_ytd / datorii_restante",
|
|
"Status: good pentru flux_net > 0, danger pentru flux_net < 0",
|
|
"Foloseste datele din trends existente pentru incasari/plati istorice"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 5"
|
|
},
|
|
{
|
|
"id": "US-006",
|
|
"title": "Backend - Calcul Indicatori Dinamica",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad evolutia vanzarilor si achizitiilor, pentru ca vreau sa stiu daca afacerea creste sau scade",
|
|
"priority": 6,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_dynamics_indicators(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat crestere_vanzari_yoy = (facturari_curent - facturari_anterior) / facturari_anterior * 100",
|
|
"Calculat crestere_achizitii_yoy = (achizitii_curent - achizitii_anterior) / achizitii_anterior * 100",
|
|
"Calculat marja_implicita = (facturari - achizitii) / facturari * 100",
|
|
"Status: good pentru crestere_vanzari > 5%, warning pentru 0-5%, danger pentru < 0%",
|
|
"Foloseste datele din trends existente cu comparatie YoY"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 6"
|
|
},
|
|
{
|
|
"id": "US-007",
|
|
"title": "Backend - Calcul Altman Z-Score",
|
|
"description": "Ca utilizator al dashboard-ului, vreau sa vad scorul Altman Z-Score calculat automat, pentru ca vreau sa stiu riscul de faliment al firmei conform standardelor internationale",
|
|
"priority": 7,
|
|
"acceptanceCriteria": [
|
|
"Metoda calculate_altman_zscore(company_id, luna, an) in FinancialIndicatorsService",
|
|
"Calculat working_capital = active_curente - datorii_curente",
|
|
"Calculat total_assets = suma tuturor activelor din VBAL",
|
|
"Calculat X1 = working_capital / total_assets",
|
|
"Calculat X2 = rezultat_reportat (cont 117 + 121) / total_assets",
|
|
"Calculat X3 = ebit (venituri - cheltuieli_operationale) / total_assets",
|
|
"Calculat X4 = capital_propriu / (datorii_curente + datorii_termen_lung)",
|
|
"Calculat zscore = 6.56*X1 + 3.26*X2 + 6.72*X3 + 1.05*X4",
|
|
"Status: safe pentru zscore > 2.60, grey pentru 1.10-2.60, distress pentru < 1.10",
|
|
"Raspunsul include componentele individuale x1, x2, x3, x4 pentru transparenta"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 7"
|
|
},
|
|
{
|
|
"id": "US-008",
|
|
"title": "Backend - Endpoint API Financial Indicators",
|
|
"description": "Ca frontend developer, vreau un endpoint API care returneaza toti indicatorii calculati, pentru ca am nevoie sa afisez datele in UI",
|
|
"priority": 8,
|
|
"acceptanceCriteria": [
|
|
"Endpoint GET /api/reports/dashboard/financial-indicators in dashboard.py router",
|
|
"Parametri: company (required int), luna (optional int), an (optional int)",
|
|
"Apeleaza toate metodele calculate_* din FinancialIndicatorsService",
|
|
"Raspuns JSON cu structura: { lichiditate: {...}, eficienta: {...}, risc: {...}, cash_flow: {...}, dinamica: {...}, altman_zscore: {...} }",
|
|
"Fiecare indicator include: value, status, threshold_min, threshold_max",
|
|
"Cache 30 minute implementat cu decorator @cached",
|
|
"Response model Pydantic FinancialIndicatorsResponse definit",
|
|
"Endpoint documentat cu docstring si tags=['dashboard']"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 8"
|
|
},
|
|
{
|
|
"id": "US-009",
|
|
"title": "Backend - Date Istorice pentru Sparklines",
|
|
"description": "Ca utilizator, vreau sa vad evolutia fiecarui indicator pe 12 luni, pentru ca vreau sa inteleg trendul, nu doar valoarea curenta",
|
|
"priority": 9,
|
|
"acceptanceCriteria": [
|
|
"Metoda get_historical_indicators(company_id, months=12) in FinancialIndicatorsService",
|
|
"Calculeaza indicatorii pentru fiecare din ultimele 12 luni",
|
|
"Returneaza dict cu sparkline_data (array 12 valori) si sparkline_labels (array 12 etichete)",
|
|
"Etichete in format 'MMM YY' (ex: 'Feb 24', 'Mar 24')",
|
|
"Integreaza sparkline_data in raspunsul fiecarui indicator",
|
|
"Cache separat pentru date istorice (TTL 1 ora) pentru performanta"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 9"
|
|
},
|
|
{
|
|
"id": "US-010",
|
|
"title": "Frontend - Component FinancialIndicatorsCard",
|
|
"description": "Ca utilizator al dashboard-ului, vreau un card vizual care afiseaza indicatorii financiari, pentru ca vreau sa vad rapid starea financiara a firmei",
|
|
"priority": 10,
|
|
"acceptanceCriteria": [
|
|
"Creat src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue",
|
|
"Header cu titlu 'Indicatori Financiari' si selector perioada (dropdown luna/an)",
|
|
"TabView PrimeVue pentru categorii: Lichiditate, Eficienta, Risc, Z-Score",
|
|
"Grid 2x2 pentru indicatori in fiecare tab",
|
|
"Foloseste design tokens: var(--space-md), var(--surface-card), var(--text-color)",
|
|
"Props: loading (boolean), error (string), data (object din store)",
|
|
"npm run typecheck passes",
|
|
"Verify in browser that card-ul se afiseaza corect pe http://localhost:3000"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 10"
|
|
},
|
|
{
|
|
"id": "US-011",
|
|
"title": "Frontend - Component IndicatorItem cu Sparkline",
|
|
"description": "Ca utilizator, vreau fiecare indicator sa aiba o mini-diagrama de evolutie, pentru ca vreau sa vad trendul vizual",
|
|
"priority": 11,
|
|
"acceptanceCriteria": [
|
|
"Creat src/modules/reports/components/dashboard/cards/IndicatorItem.vue",
|
|
"Props: label (string), value (number), unit (string), status (good/warning/danger), sparklineData (array), thresholds (object)",
|
|
"Afiseaza: label sus, valoare mare centrata, sparkline jos, status icon dreapta",
|
|
"Cod culoare: verde var(--green-600), galben var(--yellow-600), rosu var(--red-600)",
|
|
"Sparkline implementat cu SVG polyline, responsive la container width",
|
|
"Tooltip la hover pe sparkline arata valoarea lunii",
|
|
"npm run typecheck passes",
|
|
"Verify in browser that sparkline-urile se afiseaza corect"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 11"
|
|
},
|
|
{
|
|
"id": "US-012",
|
|
"title": "Frontend - Expand pentru Detalii Complete",
|
|
"description": "Ca utilizator, vreau sa pot expanda cardul pentru a vedea toti indicatorii, pentru ca unii indicatori sunt mai putin importanti dar vreau acces la ei",
|
|
"priority": 12,
|
|
"acceptanceCriteria": [
|
|
"Buton chevron in footer-ul cardului pentru expand/collapse",
|
|
"State ref expanded = false, toggle la click",
|
|
"Starea collapsed arata 4 indicatori principali: Quick Ratio, DSO, Creante Restante %, Z-Score",
|
|
"Starea expanded arata toti indicatorii in DataTable PrimeVue cu coloane: Indicator, Valoare, Status, Trend",
|
|
"Animatie CSS transition pe max-height pentru smooth expand",
|
|
"npm run typecheck passes",
|
|
"Verify in browser that expand/collapse functioneaza fluid"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 12"
|
|
},
|
|
{
|
|
"id": "US-013",
|
|
"title": "Frontend - Store Integration",
|
|
"description": "Ca frontend developer, vreau sa integrez datele in Pinia store, pentru ca am nevoie de state management pentru indicatori",
|
|
"priority": 13,
|
|
"acceptanceCriteria": [
|
|
"In src/modules/reports/stores/dashboard.js adaugat state: financialIndicators: { loading: false, error: null, data: null }",
|
|
"Metoda async loadFinancialIndicators(companyId, luna, an) care face GET /api/reports/dashboard/financial-indicators",
|
|
"Seteaza loading=true la inceput, loading=false si data/error la final",
|
|
"Computed getters: lichiditate, eficienta, risc, cashFlow, dinamica, altmanZScore care extrag din data",
|
|
"Error handling cu try/catch si mesaj user-friendly",
|
|
"npm run typecheck passes"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 13"
|
|
},
|
|
{
|
|
"id": "US-014",
|
|
"title": "Frontend - Integrare in DashboardView Desktop",
|
|
"description": "Ca utilizator pe desktop, vreau sa vad cardul de indicatori in dashboard, pentru ca vreau acces rapid la informatii",
|
|
"priority": 14,
|
|
"acceptanceCriteria": [
|
|
"Import FinancialIndicatorsCard in DashboardView.vue",
|
|
"Adaugat in template pe desktop (v-if=!isMobile) dupa sectiunea metrics-cards-section",
|
|
"Div wrapper cu clasa financial-indicators-section, margin-top: var(--space-lg)",
|
|
"Card ocupa full width",
|
|
"In loadDashboardData() adaugat apel dashboardStore.loadFinancialIndicators(companyId, luna, an)",
|
|
"Paseaza props: :loading :error :data din store",
|
|
"npm run typecheck passes",
|
|
"Verify in browser (desktop 1200px+) that cardul apare corect sub grafice"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 14"
|
|
},
|
|
{
|
|
"id": "US-015",
|
|
"title": "Frontend - Integrare in DashboardView Mobile",
|
|
"description": "Ca utilizator pe mobil, vreau sa vad cardul de indicatori in carusel, pentru ca vreau acces la informatii si pe telefon",
|
|
"priority": 15,
|
|
"acceptanceCriteria": [
|
|
"In SwipeableCards din DashboardView adaugat pagina 6 (index 5)",
|
|
"Totalul de pagini devine 6 (era 5)",
|
|
"Pagina 6 contine FinancialIndicatorsCard adaptat pentru mobil",
|
|
"Layout single column pe mobil, tabs mai mici",
|
|
"Respecta padding: padding-top 0 (e in SwipeableCards), padding-bottom 0",
|
|
"Page indicator dots actualizeaza la 6 puncte",
|
|
"npm run typecheck passes",
|
|
"Verify in browser (mobile 375px) that swipe la pagina 6 arata cardul indicatori"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 15"
|
|
},
|
|
{
|
|
"id": "US-016",
|
|
"title": "Frontend - Dark Mode Support",
|
|
"description": "Ca utilizator, vreau cardul sa arate bine in dark mode, pentru ca folosesc aplicatia si seara",
|
|
"priority": 16,
|
|
"acceptanceCriteria": [
|
|
"Culorile status (verde/galben/rosu) vizibile pe fundal inchis - foloseste var(--green-400), var(--yellow-400), var(--red-400) in dark mode",
|
|
"Sparkline stroke color foloseste var(--primary-color) care se adapteaza la tema",
|
|
"Background card foloseste var(--surface-card) care se adapteaza",
|
|
"Text foloseste var(--text-color) care se adapteaza",
|
|
"NU sunt valori de culoare hardcodate (#fff, #000, etc)",
|
|
"npm run typecheck passes",
|
|
"Verify in browser cu toggle dark mode that totul e lizibil si contrastant"
|
|
],
|
|
"passes": true,
|
|
"notes": "Completed in iteration 16"
|
|
}
|
|
]
|
|
}
|