From 6c78fec8a7eb73436e598ca615ccc186e9be91b4 Mon Sep 17 00:00:00 2001 From: Claude Agent Date: Mon, 23 Feb 2026 15:05:41 +0000 Subject: [PATCH] feat(dashboard): add datorat/achitat/sold breakdown for budget debts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces "luna prec / luna curentă" columns with a clearer accounting reconciliation flow: Datorat (owed) → Achitat (paid) → Sold (remaining). Backend models gain 3 new fields per sub-account and group. Frontend shows ✓ when a debt is fully cleared. Mobile TVA card now shows both total and remaining sold. SwipeableCards gains fixedDots/fillHeight props for better layout above MobileBottomNav. Telegram formatter updated to use new fields and drops redundant RON suffix from amounts. Co-Authored-By: Claude Sonnet 4.6 --- backend/modules/reports/models/dashboard.py | 9 +- .../reports/services/dashboard_service.py | 42 ++- backend/modules/telegram/bot/formatters.py | 71 +++-- .../cards/FinancialIndicatorsCard.vue | 49 ++-- .../dashboard/cards/IndicatorItem.vue | 2 +- .../components/solduri/SolduriCompactCard.vue | 146 +++++++++- src/modules/reports/views/DashboardView.vue | 267 ++++++++++++++++-- .../components/mobile/SwipeableCards.vue | 143 ++++++++-- 8 files changed, 606 insertions(+), 123 deletions(-) diff --git a/backend/modules/reports/models/dashboard.py b/backend/modules/reports/models/dashboard.py index 649e99b..3413a21 100644 --- a/backend/modules/reports/models/dashboard.py +++ b/backend/modules/reports/models/dashboard.py @@ -9,6 +9,9 @@ class BudgetDebtSubAccount(BaseModel): label: str # ex: "4311 - CAS angajat" precedent: Decimal # sold luna precedentă (pozitiv=datorie, negativ=creanță) curent: Decimal # sold luna curentă (pozitiv=datorie, negativ=creanță) + datorat: Decimal = Decimal('0') # datorie din luna precedentă (= preccred - precdeb) + achitat: Decimal = Decimal('0') # plăți efectuate luna curentă (= ruldeb) + sold: Decimal = Decimal('0') # sold final real (= soldcred - solddeb) class BudgetDebtGroup(BaseModel): """Grup de datorii la buget (TVA / BASS / CAM)""" @@ -17,6 +20,9 @@ class BudgetDebtGroup(BaseModel): precedent: Decimal # total grup luna prec (semn ±) curent: Decimal # total grup luna crt (semn ±) sub_accounts: List[BudgetDebtSubAccount] = [] + datorat: Decimal = Decimal('0') # total datorie grup luna precedentă + achitat: Decimal = Decimal('0') # total plăți grup luna curentă + sold: Decimal = Decimal('0') # sold final real al grupului class TreasuryAccount(BaseModel): """Cont de trezorerie (bancă/casă)""" @@ -146,4 +152,5 @@ class DashboardSummary(BaseModel): # DATORII LA BUGET - breakdown pe grupe (TVA / BASS / CAM) cu sub-conturi budget_debt_breakdown: List[BudgetDebtGroup] = [] - budget_debt_total_precedent: Decimal = Decimal('0') # suma tuturor grupurilor luna prec \ No newline at end of file + budget_debt_total_precedent: Decimal = Decimal('0') # suma tuturor grupurilor luna prec + budget_debt_total_sold: Decimal = Decimal('0') # sold final total (cât mai rămâne de plată) \ No newline at end of file diff --git a/backend/modules/reports/services/dashboard_service.py b/backend/modules/reports/services/dashboard_service.py index 8fa6680..cbb54aa 100644 --- a/backend/modules/reports/services/dashboard_service.py +++ b/backend/modules/reports/services/dashboard_service.py @@ -555,6 +555,9 @@ class DashboardService: sub_accounts = [] group_prec = Decimal('0') group_cur = Decimal('0') + group_datorat = Decimal('0') + group_achitat = Decimal('0') + group_sold = Decimal('0') if group_def['key'] == 'TVA': # TVA special: valorile deja calculate (semn ±) @@ -562,22 +565,39 @@ class DashboardService: tva_cur = tva_plata_curent - tva_recuperat_curent group_prec = tva_prec group_cur = tva_cur + + # Achitat TVA = plăți efective din luna curentă (ruldeb pe contul de TVA plată) + if sold_4423 > 0: + tva_achitat_prec = tva_data['4423']['ruldeb'] + else: + tva_achitat_prec = tva_data['4427']['ruldeb'] + group_datorat = tva_prec + group_achitat = tva_achitat_prec + group_sold = max(Decimal('0'), tva_prec - tva_achitat_prec) + # Sub-conturi TVA (doar cele cu sold non-zero) for cont in ['4423', '4424', '4426', '4427']: if cont in all_budget_data: d = all_budget_data[cont] if cont == '4424': # creanță → semn negativ val_prec = -(d['precdeb'] - d['preccred']) - val_cur = -(d['ruldeb'] - d['rulcred']) - else: # 4423, 4426, 4427: rulcred - ruldeb (lunar, nu cumulat) + val_cur = -(d['rulcred']) + val_sold = Decimal('0') # creanță: nu are sold de plată + else: # 4423, 4426, 4427 val_prec = d['preccred'] - d['precdeb'] - val_cur = d['rulcred'] - d['ruldeb'] + val_cur = d['rulcred'] # obligații noi luna curentă + val_sold = max(Decimal('0'), val_prec - d['ruldeb']) + val_datorat = val_prec + val_achitat = d['ruldeb'] if val_prec != 0 or val_cur != 0: sub_accounts.append(BudgetDebtSubAccount( cont=cont, label=ACCOUNT_LABELS[cont], precedent=val_prec, curent=val_cur, + datorat=val_datorat, + achitat=val_achitat, + sold=val_sold, )) else: # BASS și CAM: matching exact pe codul contului @@ -585,16 +605,25 @@ class DashboardService: if account_code in all_budget_data: d = all_budget_data[account_code] val_prec = d['preccred'] - d['precdeb'] # pozitiv = datorie - val_cur = d['rulcred'] - d['ruldeb'] # rulaj luna curentă (consistent cu TVA) + val_cur = d['rulcred'] # obligații noi luna curentă + val_datorat = val_prec + val_achitat = d['ruldeb'] # plăți directe (debit) + val_sold = max(Decimal('0'), val_datorat - val_achitat) # datorat - achitat if val_prec != 0 or val_cur != 0: sub_accounts.append(BudgetDebtSubAccount( cont=account_code, label=ACCOUNT_LABELS.get(account_code, account_code), precedent=val_prec, curent=val_cur, + datorat=val_datorat, + achitat=val_achitat, + sold=val_sold, )) group_prec += val_prec group_cur += val_cur + group_datorat += val_datorat + group_achitat += val_achitat + group_sold += val_sold if group_prec != 0 or group_cur != 0 or sub_accounts: budget_debt_breakdown.append(BudgetDebtGroup( @@ -603,9 +632,13 @@ class DashboardService: precedent=group_prec, curent=group_cur, sub_accounts=sub_accounts, + datorat=group_datorat, + achitat=group_achitat, + sold=group_sold, )) budget_debt_total_precedent = sum(g.precedent for g in budget_debt_breakdown) + budget_debt_total_sold = sum(g.sold for g in budget_debt_breakdown) # Procesare trezorerie treasury_accounts = [] @@ -697,6 +730,7 @@ class DashboardService: # Datorii la buget pe grupe cu sub-conturi budget_debt_breakdown=budget_debt_breakdown, budget_debt_total_precedent=budget_debt_total_precedent, + budget_debt_total_sold=budget_debt_total_sold, ) @staticmethod diff --git a/backend/modules/telegram/bot/formatters.py b/backend/modules/telegram/bot/formatters.py index 0333e03..1e890ac 100644 --- a/backend/modules/telegram/bot/formatters.py +++ b/backend/modules/telegram/bot/formatters.py @@ -18,16 +18,16 @@ def format_dashboard_response(data: Dict[str, Any], company_name: str = None) -> # Sold total trezorerie (casa + banca) - rotunjit la leu treasury_totals = data.get('treasury_totals_by_currency', {}) sold_trezorerie = round(float(treasury_totals.get('RON', 0))) - text += f"**Sold Trezorerie:** {sold_trezorerie:,} RON\n\n" + text += f"**Sold Trezorerie:** {sold_trezorerie:,}\n\n" # Sold Clienți - rotunjit la leu clienti_sold = round(float(data.get('clienti_sold_total', 0))) clienti_in_termen = round(float(data.get('clienti_sold_in_termen', 0))) clienti_restant = round(float(data.get('clienti_sold_restant', 0))) - text += f"**Sold Clienți:** {clienti_sold:,} RON\n" - text += f" - În termen: {clienti_in_termen:,} RON\n" - text += f" - Restanță: {clienti_restant:,} RON\n\n" + text += f"**Sold Clienți:** {clienti_sold:,}\n" + text += f" - În termen: {clienti_in_termen:,}\n" + text += f" - Restanță: {clienti_restant:,}\n\n" # Sold Furnizori BRUT (pentru consistență cu detaliile) - rotunjit la leu furnizori_in_termen = round(float(data.get('furnizori_sold_in_termen', 0))) @@ -36,47 +36,40 @@ def format_dashboard_response(data: Dict[str, Any], company_name: str = None) -> furnizori_avansuri = round(float(data.get('furnizori_avansuri', 0))) furnizori_sold_net = round(float(data.get('furnizori_sold_total', 0))) - text += f"**Sold Furnizori:** {furnizori_sold_brut:,} RON\n" - text += f" - În termen: {furnizori_in_termen:,} RON\n" - text += f" - Restanță: {furnizori_restant:,} RON\n" + text += f"**Sold Furnizori:** {furnizori_sold_brut:,}\n" + text += f" - În termen: {furnizori_in_termen:,}\n" + text += f" - Restanță: {furnizori_restant:,}\n" if furnizori_avansuri != 0: - text += f" - Avansuri: {furnizori_avansuri:,} RON\n" - text += f" - Net (după avansuri): {furnizori_sold_net:,} RON" + text += f" - Avansuri: {furnizori_avansuri:,}\n" + text += f" - Net (după avansuri): {furnizori_sold_net:,}" else: - text += f" - Net: {furnizori_sold_net:,} RON" + text += f" - Net: {furnizori_sold_net:,}" - # Solduri TVA - rotunjit la leu - tva_plata_prec = round(float(data.get('tva_plata_precedent', 0))) - tva_recup_prec = round(float(data.get('tva_recuperat_precedent', 0))) - tva_plata_cur = round(float(data.get('tva_plata_curent', 0))) - tva_recup_cur = round(float(data.get('tva_recuperat_curent', 0))) - - # Afișează secțiunea doar dacă există cel puțin o valoare > 0 - if tva_plata_prec > 0 or tva_recup_prec > 0 or tva_plata_cur > 0 or tva_recup_cur > 0: - text += "\n\n**Solduri TVA:**\n" - if tva_plata_prec > 0: - text += f" - TVA de plată precedent: {tva_plata_prec:,} RON\n" - if tva_recup_prec > 0: - text += f" - TVA de recuperat precedent: {tva_recup_prec:,} RON\n" - if tva_plata_cur > 0: - text += f" - TVA de plată curent: {tva_plata_cur:,} RON\n" - if tva_recup_cur > 0: - text += f" - TVA de recuperat curent: {tva_recup_cur:,} RON\n" - - # Datorii la Buget - breakdown pe grupe (TVA / BASS / CAM), valori luna precedentă + # Datorii la Buget - două secțiuni: luna precedentă și luna curentă budget_breakdown = data.get('budget_debt_breakdown', []) if budget_breakdown: - grupe_cu_datorie = [ - g for g in budget_breakdown - if round(float(g.get('precedent', 0))) > 0 - ] - if grupe_cu_datorie: - total_buget = sum(round(float(g.get('precedent', 0))) for g in grupe_cu_datorie) + grupe_prec = [g for g in budget_breakdown if round(float(g.get('datorat', g.get('precedent', 0)))) > 0] + grupe_crt = [g for g in budget_breakdown if round(float(g.get('curent', 0))) > 0] + + if grupe_prec or grupe_crt: text += "\n\n**Datorii la Buget:**\n" - for grupa in grupe_cu_datorie: - val = round(float(grupa.get('precedent', 0))) - text += f" - {grupa.get('label', '')}: {val:,} RON\n" - text += f" Total: {total_buget:,} RON\n" + + if grupe_prec: + total_sold = sum(round(float(g.get('sold', 0))) for g in grupe_prec) + total_dat = sum(round(float(g.get('datorat', g.get('precedent', 0)))) for g in grupe_prec) + sold_total_str = f"{total_sold:,}" if total_sold > 0 else "0 \u2713" + text += f"\n _Precedent: dat: {total_dat:,}, sold: {sold_total_str}_\n" + for g in grupe_prec: + datorat = round(float(g.get('datorat', g.get('precedent', 0)))) + sold = round(float(g.get('sold', 0))) + label = g.get('label', '') + sold_str = f"{sold:,}" if sold > 0 else "0 \u2713" + text += f" {label:<6} {datorat:,} · {sold_str}\n" + + if grupe_crt: + items = [f"{g.get('label', '')} {round(float(g.get('curent', 0))):,}" for g in grupe_crt] + total_crt = sum(round(float(g.get('curent', 0))) for g in grupe_crt) + text += f"\n _Curent: {' \u00b7 '.join(items)} = {total_crt:,}_\n" return text diff --git a/src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue b/src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue index 72770b8..27b34b2 100644 --- a/src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue +++ b/src/modules/reports/components/dashboard/cards/FinancialIndicatorsCard.vue @@ -3,7 +3,6 @@

- Indicatori Financiari

@@ -102,7 +101,7 @@

- 💧 Lichiditate + Lichiditate

@@ -178,7 +177,7 @@

- ⚡ Eficiență + Eficiență

@@ -290,7 +289,7 @@

- ⚠️ Risc + Risc

@@ -393,7 +392,7 @@

- 💰 Cash Flow + Cash Flow

@@ -478,7 +477,7 @@

- 📈 Dinamică + Dinamică

@@ -554,7 +553,7 @@

- 💹 Profitabilitate + Profitabilitate

@@ -666,7 +665,7 @@

- 🎯 Altman Z-Score + Altman Z-Score

@@ -738,7 +737,7 @@

- 🏛️ Solvabilitate + Solvabilitate

@@ -830,7 +829,7 @@

- 💧 Lichiditate + Lichiditate

@@ -898,7 +897,7 @@

- ⚡ Eficiență + Eficiență

@@ -998,7 +997,7 @@

- ⚠️ Risc + Risc

@@ -1089,7 +1088,7 @@

- 💰 Cash Flow + Cash Flow

@@ -1166,7 +1165,7 @@

- 📈 Dinamică + Dinamică

@@ -1234,7 +1233,7 @@

- 🎯 Altman Z-Score + Altman Z-Score

@@ -1305,7 +1304,7 @@

- 💰 Profitabilitate + Profitabilitate

@@ -1400,7 +1399,7 @@

- 🏛️ Solvabilitate + Solvabilitate

@@ -1712,7 +1711,7 @@ const formatCurrency = (value) => { maximumFractionDigits: 0 }) const sign = num < 0 ? '-' : num > 0 ? '+' : '' - return `${sign}${formatted} RON` + return `${sign}${formatted}` } // Normalize status for consistent styling @@ -1823,8 +1822,8 @@ const handlePeriodChange = () => {