feat(dashboard): add datorat/achitat/sold breakdown for budget debts
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 <noreply@anthropic.com>
This commit is contained in:
@@ -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
|
||||
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ă)
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user