From 4c59a103c91d113fd4adbf197dfbf6cab024eb04 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Mon, 21 Sep 2026 00:14:07 +0300 Subject: [PATCH] Analitic cu sold pe latura opusa: FACTURA cu suma negativa Analiticul unui cont cu parteneri al carui sold e pe latura opusa laturii fixate in cod primeste rand FACTURA, cu suma negativa pe latura formularului (BALANTA si sold). Nu mai ramane nimic pe NEREPARTIZAT. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01BdA5a3ECKFD6Citf1ptPZu --- docs/decizii_import.md | 8 +- docs/raport_genxlsx.md | 66 +++++++-------- docs/verificare_FUNDATIA.md | 28 +++---- docs/verificare_MASTER.md | 40 +++++----- genereaza_xlsx.py | 155 ++++++++++++++++++++---------------- init_FUNDATIA_2025_12.xlsx | Bin 11192 -> 11196 bytes init_MASTER_2025_12.xlsx | Bin 11299 -> 11351 bytes 7 files changed, 158 insertions(+), 139 deletions(-) diff --git a/docs/decizii_import.md b/docs/decizii_import.md index f548a2d..a8e7266 100644 --- a/docs/decizii_import.md +++ b/docs/decizii_import.md @@ -95,8 +95,12 @@ Revizuit 20.09.2026 (inlocuieste forma din pct. 11 si 14 pentru aceste conturi). - **`5311`** (casa, fara analitice): rand `BALANTA` pe `5311` (acont gol) + rand `FACTURA` pe `5311` (acont gol), partener `CENTRALA`. - **`5125`**: **doar analitice**, fara parteneri. Se trateaza ca orice cont obisnuit cu analitice. -- Un analitic cu soldul pe latura opusa laturii fixate in cod (`:379`, trezoreria merge pe debit) - nu primeste rand FACTURA; ramane doar randul BALANTA si formularul ii pune `NEREPARTIZAT`. +- Un analitic cu soldul pe **latura opusa** laturii fixate in cod (`:379` - trezoreria merge pe + debit) primeste totusi rand FACTURA: suma se scrie **cu semn negativ pe latura formularului**, + atat in randul `BALANTA` (`totdeb = -20,80`, `totcred` gol) cat si in `sold`-ul randului + `FACTURA` (`-20,80`). Soldul ramane pe latura corecta, balanta ramane inchisa + (`SUM(totdeb) = SUM(totcred)`), randul FACTURA consuma exact randul BALANTA si nu mai ramane + nimic pe `NEREPARTIZAT`. Pretul: nota contine o suma negativa - acceptat (decis 20.09.2026). Caz gasit: MASTER `5121.01 PIRAEUS BANK - RON`, sold creditor 20,80. ## 16. Regula generala: randul FACTURA trebuie sa aiba acelasi `acont` ca randul BALANTA pe care il consuma diff --git a/docs/raport_genxlsx.md b/docs/raport_genxlsx.md index 23e2338..352ea87 100644 --- a/docs/raport_genxlsx.md +++ b/docs/raport_genxlsx.md @@ -1,4 +1,4 @@ -# Raport lane `genxlsx` (v2) +# Raport lane `genxlsx` (v3) Script: `genereaza_xlsx.py`. Produce pentru fiecare firma xlsx-ul de initializare (`init__2025_12.xlsx`, un sheet, randul 1 = capul de tabel, fara instructiuni/exemple) @@ -6,7 +6,7 @@ si raportul de verificare (`docs/verificare_.md`). ## Livrabile - `init_FUNDATIA_2025_12.xlsx` - 75 randuri (47 BALANTA, 28 FACTURA) -- `init_MASTER_2025_12.xlsx` - 79 randuri (46 BALANTA, 33 FACTURA) +- `init_MASTER_2025_12.xlsx` - 80 randuri (46 BALANTA, 34 FACTURA) - `docs/verificare_FUNDATIA.md`, `docs/verificare_MASTER.md` - `genereaza_xlsx.py` @@ -14,44 +14,43 @@ si raportul de verificare (`docs/verificare_.md`). | Firma | SUM(totdeb)=SUM(totcred) | frunze pierdute | parteneri | lungimi/dubluri | |---|---|---|---|---| | FUNDATIA | 7068369.50 = 7068369.50 (net 0.00) | 0 | OK | OK | -| MASTER | 2318592.91 = 2318592.91 (net 0.00) | 0 | OK | OK | +| MASTER | 2318572.11 = 2318572.11 (net 0.00) | 0 | OK | OK | -## Corectii v2 (fata de v1) -1. **Randul FACTURA `DIFERENTA SINTETIC ` a fost eliminat** de pe conturile cu parteneri. - Formularul scade singur suma randurilor FACTURA din randul BALANTA de pe acelasi - `(cont, acont, latura)` si pune restul pe partenerul `NEREPARTIZAT` pe care il creeaza el - (`frm..sc2:415-431`). Diferenta nu se mai inventa de noi. -2. **Analitice cu sold pe latura opusa nu mai primesc FACTURA.** Latura FACTURA e fixa in cod - (`frm..sc2:379`/'383'): `401,404,462,419,408,4551` -> CREDIT, orice alt cont -> DEBIT. - Analiticul sarit ramane doar in randul BALANTA (pe latura lui corecta) si formularul ii pune - `NEREPARTIZAT`. Fiecare caz e listat in raport (sectiunea 4). -3. **Randul BALANTA reprezinta contul sintetic intreg.** La partenerii cu un singur BALANTA - agregat, `totdeb` = suma `total_d` a tuturor analiticelor + postarea directa pe sintetic - (idem `totcred`), nu doar analiticele pentru care s-a emis FACTURA. -4. **pct. 15 (revizuit 20.09.2026):** - - `5121`/`5124`: analiticele **raman analitice** si in plus primesc partener. Pentru fiecare - analitic se scriu **doua randuri pe acelasi `(cont, acont)`**: un `BALANTA` cu acont si - `totdeb`/`totcred` ale analiticului, si un `FACTURA` cu **acelasi acont**, `cod_fiscal` = - codul SAGA, `sold` = soldul analiticului. Acelasi `acont` e obligatoriu, altfel scaderea din - cod nu se potriveste si suma se dubleaza. - - `5125`: NU mai e cont cu parteneri - doar randuri BALANTA cu acont, fara FACTURA. - - `5311`: BALANTA (acont gol) + FACTURA (acont gol), partener `CENTRALA`. - - `401, 4092, 4111, 461, 462, 4551`: neschimbate - un BALANTA agregat pe sintetic (acont gol) - + cate un FACTURA per analitic (acont gol). +## Corectia v3 (fata de v2) +**Analiticul cu sold pe latura opusa laturii fixate de formular (`frm..sc2:379`) NU mai este +sarit.** Primeste rand `FACTURA`, iar suma se scrie cu **semn negativ pe latura formularului**: +- randul `BALANTA` al analiticului: `totdeb = -|sold|` (daca latura formularului e D) sau + `totcred = -|sold|` (daca e C), cealalta latura goala; +- randul `FACTURA`: `sold = -|sold|`, pe aceeasi latura si cu **acelasi `acont`** ca BALANTA. + +Soldul ramane pe latura corecta, `SUM(totdeb) = SUM(totcred)` se pastreaza (ambele laturi scad +cu aceeasi suma), randul FACTURA consuma exact randul BALANTA si nu mai ramane nimic pe +`NEREPARTIZAT`. Regula se aplica general, la orice cont cu parteneri. Pretul acceptat: nota +contine o suma negativa. + +Efecte pe MASTER: +1 rand (FACTURA pentru `5121.01`), iar `SUM(totdeb)`/`SUM(totcred)` scad +cu 20.80 si ajung exact peste `Totaluri.total_d`/`total_c` din PDF (diferenta 0.00, fata de +20.80 in v2). ## Ce ramane pe `NEREPARTIZAT`, per cont (sectiunea 3 din verificari) -`net sintetic - SUM(sold FACTURA cu semn) = analitice sarite + postare directa pe sintetic`. +`net sintetic - SUM(sold FACTURA cu semn) = postare directa pe sintetic`. Rezultat: toate conturile ies 0, mai putin MASTER `5121`: -| cont | SUM FACTURA | net sintetic | sarite | postare directa | NEREPARTIZAT asteptat | diferenta | -|---|---|---|---|---|---|---| -| MASTER 5121 | 15599.25 | 15730.61 | -20.80 (`5121.01` creditor) | +152.16 | 131.36 | 131.36 | +| cont | SUM FACTURA | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | +|---|---|---|---|---|---| +| MASTER 5121 | 15578.45 | 15730.61 | +152.16 | 152.16 | 152.16 | -- MASTER `5121.01 PIRAEUS BANK - RON` (sold creditor 20,80): fara FACTURA, doar - `BALANTA 5121 acont 01` pe credit -> formularul ii pune `NEREPARTIZAT`. +- MASTER `5121.01 PIRAEUS BANK - RON` (sold creditor 20,80): `BALANTA acont 01 totdeb=-20.80` + + `FACTURA acont 01 sold=-20.80` -> se consuma exact, fara `NEREPARTIZAT`. - MASTER `5121` postare directa +152.16: rand `BALANTA 5121 acont 99` `DIFERENTA SINTETIC SAGA` (fara FACTURA) -> `NEREPARTIZAT`. +## Analitice cu semn negativ (sectiunea 4 din verificari) +| Firma | cont | analitic | sold (semnat) | latura formularului | +|---|---|---|---|---| +| MASTER | 5121 | 5121.01 | -20.8 | D | +| FUNDATIA | - | niciunul | - | - | + ## Randuri de diferenta (pct. 13-15) generate - MASTER `117` (nepartener): +2635.87 -> rand `BALANTA` cont 117, acont `99`, nume `DIFERENTA SINTETIC SAGA`. @@ -59,7 +58,8 @@ Rezultat: toate conturile ies 0, mai putin MASTER `5121`: - FUNDATIA: niciunul (1171.01 are diferenta net zero - doar netare SAGA). ## Observatii -- SUM(totdeb) difera de `Totaluri.total_d` din PDF (FUNDATIA +739831.67, MASTER +20.80): - gross-ul sinteticelor netate de SAGA nu se poate reconstrui din frunze; netul coincide exact. +- FUNDATIA: SUM(totdeb) difera de `Totaluri.total_d` din PDF cu +739831.67 (gross-ul + sinteticelor netate de SAGA nu se poate reconstrui din frunze); netul coincide exact. +- MASTER: dupa corectia v3, SUM(totdeb) = `Totaluri.total_d` = 2318572.11 (diferenta 0.00). - Coloana `explicatia` (control D/C) este goala in xlsx-ul final. - Nu s-a facut niciun commit. diff --git a/docs/verificare_FUNDATIA.md b/docs/verificare_FUNDATIA.md index e0323eb..633c5e0 100644 --- a/docs/verificare_FUNDATIA.md +++ b/docs/verificare_FUNDATIA.md @@ -20,25 +20,25 @@ Generat de `genereaza_xlsx.py` din `balanta_FUNDATIA.csv`. Randuri de date: 75 ( ## 3. Conturi partener: FACTURA + NEREPARTIZAT = net sintetic -Formularul scade din randul BALANTA suma randurilor FACTURA de pe acelasi `(cont, acont, latura)` si lasa restul pe partenerul `NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = analitice sarite + postare directa pe sintetic`. +Formularul scade din randul BALANTA suma randurilor FACTURA de pe acelasi `(cont, acont, latura)` si lasa restul pe partenerul `NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = postare directa pe sintetic`. -| cont | SUM(sold FACTURA) | net sintetic | analitice sarite | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat | -|---|---|---|---|---|---|---|---| -| 401 | -314703.58 | -314703.58 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4092 | 809.33 | 809.33 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4111 | 15126.48 | 15126.48 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4551 | -1571531.33 | -1571531.33 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 461 | 477938.37 | 477938.37 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 462 | -3400771.0 | -3400771.0 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 5121 | 81966.8 | 81966.8 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 5124 | 2492540.28 | 2492540.28 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 5311 | 72433.56 | 72433.56 | 0.0 | 0.0 | 0.0 | 0.0 | OK | +| cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat | +|---|---|---|---|---|---|---| +| 401 | -314703.58 | -314703.58 | 0.0 | 0.0 | 0.0 | OK | +| 4092 | 809.33 | 809.33 | 0.0 | 0.0 | 0.0 | OK | +| 4111 | 15126.48 | 15126.48 | 0.0 | 0.0 | 0.0 | OK | +| 4551 | -1571531.33 | -1571531.33 | 0.0 | 0.0 | 0.0 | OK | +| 461 | 477938.37 | 477938.37 | 0.0 | 0.0 | 0.0 | OK | +| 462 | -3400771.0 | -3400771.0 | 0.0 | 0.0 | 0.0 | OK | +| 5121 | 81966.8 | 81966.8 | 0.0 | 0.0 | 0.0 | OK | +| 5124 | 2492540.28 | 2492540.28 | 0.0 | 0.0 | 0.0 | OK | +| 5311 | 72433.56 | 72433.56 | 0.0 | 0.0 | 0.0 | OK | Rezultat: OK -## 4. Analitice sarite (sold pe latura opusa formularului) +## 4. Analitice cu semn negativ (sold pe latura opusa formularului) -Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa nu primeste rand FACTURA; ramane in BALANTA si formularul ii pune `NEREPARTIZAT`. +Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa primeste totusi rand FACTURA, iar suma se scrie cu **semn negativ pe latura formularului**, atat in randul BALANTA cat si in `sold`-ul randului FACTURA. Soldul ramane pe latura corecta, balanta ramane inchisa, iar randul FACTURA consuma exact randul BALANTA (fara `NEREPARTIZAT`). Niciunul. diff --git a/docs/verificare_MASTER.md b/docs/verificare_MASTER.md index 5f5b4d4..e8602c6 100644 --- a/docs/verificare_MASTER.md +++ b/docs/verificare_MASTER.md @@ -1,15 +1,15 @@ # Verificare `init_MASTER_2025_12.xlsx` -Generat de `genereaza_xlsx.py` din `balanta_MASTERJOB.csv`. Randuri de date: 79 (46 BALANTA, 33 FACTURA). +Generat de `genereaza_xlsx.py` din `balanta_MASTERJOB.csv`. Randuri de date: 80 (46 BALANTA, 34 FACTURA). ## 1. Balanta generala (SUM totdeb = SUM totcred) -- SUM(totdeb) = 2318592.91 -- SUM(totcred) = 2318592.91 +- SUM(totdeb) = 2318572.11 +- SUM(totcred) = 2318572.11 - diferenta (totdeb - totcred) = 0.0 -> OK - Totaluri balanta: total_d=2318572.11 total_c=2318572.11 net=0.0 - NET xlsx (0.0) vs NET Totaluri (0.0) -> OK -- Nota: SUM(totdeb)=2318592.91 difera de Totaluri.total_d=2318572.11 cu 20.8; suma pe laturi a PDF-ului nu se poate reconstrui din frunze acolo unde SAGA a netat sinteticul (gross-ul parintelui e netat). Netul se pastreaza exact. +- Nota: SUM(totdeb)=2318572.11 difera de Totaluri.total_d=2318572.11 cu 0.0; suma pe laturi a PDF-ului nu se poate reconstrui din frunze acolo unde SAGA a netat sinteticul (gross-ul parintelui e netat). Netul se pastreaza exact. ## 2. Conturi frunza din CSV, reprezentate o singura data @@ -20,29 +20,29 @@ Generat de `genereaza_xlsx.py` din `balanta_MASTERJOB.csv`. Randuri de date: 79 ## 3. Conturi partener: FACTURA + NEREPARTIZAT = net sintetic -Formularul scade din randul BALANTA suma randurilor FACTURA de pe acelasi `(cont, acont, latura)` si lasa restul pe partenerul `NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = analitice sarite + postare directa pe sintetic`. +Formularul scade din randul BALANTA suma randurilor FACTURA de pe acelasi `(cont, acont, latura)` si lasa restul pe partenerul `NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = postare directa pe sintetic`. -| cont | SUM(sold FACTURA) | net sintetic | analitice sarite | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat | -|---|---|---|---|---|---|---|---| -| 401 | -547108.99 | -547108.99 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4092 | 4.0 | 4.0 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4111 | 12000.0 | 12000.0 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 4551 | -751724.61 | -751724.61 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 461 | 69289.0 | 69289.0 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 462 | -9810.0 | -9810.0 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 5121 | 15599.25 | 15730.61 | -20.8 | 152.16 | 131.36 | 131.36 | OK | -| 5124 | 1060090.96 | 1060090.96 | 0.0 | 0.0 | 0.0 | 0.0 | OK | -| 5311 | 98460.87 | 98460.87 | 0.0 | 0.0 | 0.0 | 0.0 | OK | +| cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat | +|---|---|---|---|---|---|---| +| 401 | -547108.99 | -547108.99 | 0.0 | 0.0 | 0.0 | OK | +| 4092 | 4.0 | 4.0 | 0.0 | 0.0 | 0.0 | OK | +| 4111 | 12000.0 | 12000.0 | 0.0 | 0.0 | 0.0 | OK | +| 4551 | -751724.61 | -751724.61 | 0.0 | 0.0 | 0.0 | OK | +| 461 | 69289.0 | 69289.0 | 0.0 | 0.0 | 0.0 | OK | +| 462 | -9810.0 | -9810.0 | 0.0 | 0.0 | 0.0 | OK | +| 5121 | 15578.45 | 15730.61 | 152.16 | 152.16 | 152.16 | OK | +| 5124 | 1060090.96 | 1060090.96 | 0.0 | 0.0 | 0.0 | OK | +| 5311 | 98460.87 | 98460.87 | 0.0 | 0.0 | 0.0 | OK | Rezultat: OK -## 4. Analitice sarite (sold pe latura opusa formularului) +## 4. Analitice cu semn negativ (sold pe latura opusa formularului) -Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa nu primeste rand FACTURA; ramane in BALANTA si formularul ii pune `NEREPARTIZAT`. +Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa primeste totusi rand FACTURA, iar suma se scrie cu **semn negativ pe latura formularului**, atat in randul BALANTA cat si in `sold`-ul randului FACTURA. Soldul ramane pe latura corecta, balanta ramane inchisa, iar randul FACTURA consuma exact randul BALANTA (fara `NEREPARTIZAT`). -| cont | analitic | sold (semnat) | motiv | +| cont | analitic | sold (semnat) | latura formularului | |---|---|---|---| -| 5121 | 5121.01 | -20.8 | sold creditor vs latura D a formularului | +| 5121 | 5121.01 | -20.8 | D | ## 5. Lungimi si dubluri diff --git a/genereaza_xlsx.py b/genereaza_xlsx.py index 355d3b3..7fb410d 100644 --- a/genereaza_xlsx.py +++ b/genereaza_xlsx.py @@ -19,8 +19,9 @@ Forma randurilor (revizuit 20.09.2026, vezi pct. 14-15): 5121/5124 devine rand BALANTA de diferenta (analitic nou, fara FACTURA); la ceilalti parteneri se include in BALANTA agregat. NU se mai emite FACTURA de diferenta (o rezolva formularul, prin NEREPARTIZAT). -- analiticul cu sold pe latura opusa celei fixate de formular (':379') nu primeste - FACTURA; ramane doar in BALANTA si apare ca NEREPARTIZAT. +- analiticul cu sold pe latura opusa celei fixate de formular (':379') primeste + FACTURA, cu suma scrisa cu semn negativ pe latura formularului (atat in BALANTA + cat si in sold-ul FACTURA); soldul ramane pe latura corecta si nu apare NEREPARTIZAT. """ import csv @@ -155,8 +156,8 @@ def rand(header, **kw): return r -def _semn_sold(net): - return "creditor" if net < 0 else "debitor" +def este_latura_formular(net, side): + return (net > 0) == (side == "D") def genereaza(rows, header): @@ -183,7 +184,7 @@ def genereaza(rows, header): out = [] leaf_map = {} # frunza -> randurile dedicate (folosite la dubluri) leaf_rep = set() # toate frunzele reprezentate (inclusiv in BALANTA agregat) - sarite = [] # (cont, analitic, sold_semnat, motiv) + negative = [] # (cont, analitic, sold_semnat, latura_formular) def add(r, leaf=None): out.append(r) @@ -220,21 +221,25 @@ def genereaza(rows, header): for k in direct: kd = by[k] kac = split_cont(k)[1] - add(rand(header, TIP="BALANTA", cont=p, acont=kac, numar=1, - nume=kd["denumire"], totdeb=round(kd["total_d"], 2), - totcred=round(kd["total_c"], 2)), leaf=k) net = round(kd["total_d"] - kd["total_c"], 2) + if net != 0 and not este_latura_formular(net, side): + neg = -abs(net) + negative.append((p, k, neg, side)) + if side == "D": + td, tc = neg, None + else: + td, tc = None, neg + else: + td, tc = round(kd["total_d"], 2), round(kd["total_c"], 2) + add(rand(header, TIP="BALANTA", cont=p, acont=kac, numar=1, + nume=kd["denumire"], totdeb=td, totcred=tc), leaf=k) if net == 0: continue - if (net > 0) == (side == "D"): - add(rand(header, TIP="FACTURA", cont=p, acont=kac, - numar=k.replace(".", ""), - nume=kd["denumire"] or f"FURNIZOR {k}", - cod_fiscal=k, sold=abs(net), explicatia=side)) - else: - sarite.append((p, k, net, - f"sold {_semn_sold(net)} vs latura {side} " - f"a formularului")) + sold = abs(net) if este_latura_formular(net, side) else -abs(net) + add(rand(header, TIP="FACTURA", cont=p, acont=kac, + numar=k.replace(".", ""), + nume=kd["denumire"] or f"FURNIZOR {k}", + cod_fiscal=k, sold=sold, explicatia=side)) if p in diff_by_parent: d = diff_by_parent[p] ac = acont_diferenta(p, direct) @@ -246,8 +251,20 @@ def genereaza(rows, header): # 401/4092/4111/461/462/4551 si 5311 if direct: - base_d = sum(by[k]["total_d"] for k in direct) - base_c = sum(by[k]["total_c"] for k in direct) + base_d = 0.0 + base_c = 0.0 + for k in direct: + net = round(by[k]["total_d"] - by[k]["total_c"], 2) + if net != 0 and not este_latura_formular(net, side): + neg = -abs(net) + negative.append((p, k, neg, side)) + if side == "D": + base_d += neg + else: + base_c += neg + else: + base_d += by[k]["total_d"] + base_c += by[k]["total_c"] d = diff_by_parent.get(p, 0.0) add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1, nume=by[p]["denumire"], @@ -258,33 +275,33 @@ def genereaza(rows, header): if net == 0: leaf_rep.add(k) continue - if (net > 0) == (side == "D"): - add(rand(header, TIP="FACTURA", cont=p, acont=None, - numar=k.replace(".", ""), - nume=by[k]["denumire"] or f"FURNIZOR {k}", - cod_fiscal=k, sold=abs(net), explicatia=side), - leaf=k) - else: - sarite.append((p, k, net, - f"sold {_semn_sold(net)} vs latura {side} " - f"a formularului")) - leaf_rep.add(k) + sold = abs(net) if este_latura_formular(net, side) else -abs(net) + add(rand(header, TIP="FACTURA", cont=p, acont=None, + numar=k.replace(".", ""), + nume=by[k]["denumire"] or f"FURNIZOR {k}", + cod_fiscal=k, sold=sold, explicatia=side), + leaf=k) else: net = round(by[p]["total_d"] - by[p]["total_c"], 2) - add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1, - nume=by[p]["denumire"], totdeb=round(by[p]["total_d"], 2), - totcred=round(by[p]["total_c"], 2)), leaf=p) - if net != 0: - if (net > 0) == (side == "D"): - nume = "CENTRALA" if p == "5311" else by[p]["denumire"] - add(rand(header, TIP="FACTURA", cont=p, acont=None, - numar=p, nume=nume, cod_fiscal=p, sold=abs(net), - explicatia=side)) + if net != 0 and not este_latura_formular(net, side): + neg = -abs(net) + negative.append((p, p, neg, side)) + if side == "D": + td, tc = neg, None else: - sarite.append((p, p, net, - f"sold {_semn_sold(net)} vs latura {side} " - f"a formularului")) - return out, diffs, leaf_map, leaf_rep, sarite + td, tc = None, neg + else: + td = round(by[p]["total_d"], 2) + tc = round(by[p]["total_c"], 2) + add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1, + nume=by[p]["denumire"], totdeb=td, totcred=tc), leaf=p) + if net != 0: + nume = "CENTRALA" if p == "5311" else by[p]["denumire"] + sold = abs(net) if este_latura_formular(net, side) else -abs(net) + add(rand(header, TIP="FACTURA", cont=p, acont=None, + numar=p, nume=nume, cod_fiscal=p, sold=sold, + explicatia=side)) + return out, diffs, leaf_map, leaf_rep, negative def scrie_xlsx(header, rows, path): @@ -302,7 +319,7 @@ def scrie_xlsx(header, rows, path): def verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, leaf_rep, - sarite, header): + negative, header): by, children = arbore(rows) leaves = [c for c in by if c not in children] diff_by_parent = dict(diffs) @@ -334,24 +351,19 @@ def verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, leaf_rep, semn = 1 if latura_factura(r["cont"]) == "D" else -1 part_rows[r["cont"]] = part_rows.get(r["cont"], 0.0) + semn * (r["sold"] or 0) - sarite_by_cont = {} - for cont, _k, s, _motiv in sarite: - sarite_by_cont[cont] = round(sarite_by_cont.get(cont, 0.0) + s, 2) - part_verif = [] for p in sorted({c.split(".")[0] for c in by if este_partener(c)}): net_sint = round(by[p]["total_d"] - by[p]["total_c"], 2) suma = round(part_rows.get(p, 0.0), 2) - sarit = round(sarite_by_cont.get(p, 0.0), 2) direct = round(diff_by_parent.get(p, 0.0), 2) - asteptat = round(sarit + direct, 2) + asteptat = direct diferenta = round(net_sint - suma, 2) ok = abs(diferenta - asteptat) <= 0.005 - part_verif.append((p, suma, net_sint, sarit, direct, asteptat, diferenta, ok)) + part_verif.append((p, suma, net_sint, direct, asteptat, diferenta, ok)) ok_bal = abs(net) <= 0.005 ok_leaves = not pierdute and not duplicate_leaf - ok_part = all(x[7] for x in part_verif) + ok_part = all(x[6] for x in part_verif) ok_lung = not lungimi and not dubluri_bal L = [] @@ -392,30 +404,33 @@ def verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, leaf_rep, L.append("Formularul scade din randul BALANTA suma randurilor FACTURA de pe " "acelasi `(cont, acont, latura)` si lasa restul pe partenerul " "`NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = " - "analitice sarite + postare directa pe sintetic`.") + "postare directa pe sintetic`.") L.append("") - L.append("| cont | SUM(sold FACTURA) | net sintetic | analitice sarite | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |") - L.append("|---|---|---|---|---|---|---|---|") - for p, suma, net_sint, sarit, direct, asteptat, diferenta, ok in part_verif: - L.append(f"| {p} | {suma} | {net_sint} | {sarit} | {direct} | {asteptat} " + L.append("| cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |") + L.append("|---|---|---|---|---|---|---|") + for p, suma, net_sint, direct, asteptat, diferenta, ok in part_verif: + L.append(f"| {p} | {suma} | {net_sint} | {direct} | {asteptat} " f"| {diferenta} | {'OK' if ok else '**ESEC**'} |") L.append("") L.append(f"Rezultat: {'OK' if ok_part else '**ESEC**'}") L.append("") - L.append("## 4. Analitice sarite (sold pe latura opusa formularului)") + L.append("## 4. Analitice cu semn negativ (sold pe latura opusa formularului)") L.append("") L.append("Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> " - "CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa nu " - "primeste rand FACTURA; ramane in BALANTA si formularul ii pune " - "`NEREPARTIZAT`.") + "CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa " + "primeste totusi rand FACTURA, iar suma se scrie cu **semn negativ pe " + "latura formularului**, atat in randul BALANTA cat si in `sold`-ul " + "randului FACTURA. Soldul ramane pe latura corecta, balanta ramane " + "inchisa, iar randul FACTURA consuma exact randul BALANTA (fara " + "`NEREPARTIZAT`).") L.append("") - if not sarite: + if not negative: L.append("Niciunul.") else: - L.append("| cont | analitic | sold (semnat) | motiv |") + L.append("| cont | analitic | sold (semnat) | latura formularului |") L.append("|---|---|---|---|") - for cont, k, s, motiv in sarite: - L.append(f"| {cont} | {k} | {s} | {motiv} |") + for cont, k, s, side in negative: + L.append(f"| {cont} | {k} | {s} | {side} |") L.append("") L.append("## 5. Lungimi si dubluri") L.append("") @@ -459,7 +474,7 @@ def verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, leaf_rep, "totdeb": totdeb, "totcred": totcred, "net": net, "pierdute": pierdute, "dubluri_leaf": duplicate_leaf, "dubluri_bal": list(dubluri_bal), "lungimi": lungimi, - "part_verif": part_verif, "sarite": sarite} + "part_verif": part_verif, "negative": negative} def main(): @@ -467,11 +482,11 @@ def main(): assert len(header) == 39, f"cap de tabel neasteptat: {len(header)} coloane" for firma, csv_path in FIRME: rows = citeste_balanta(csv_path) - out, diffs, leaf_map, leaf_rep, sarite = genereaza(rows, header) + out, diffs, leaf_map, leaf_rep, negative = genereaza(rows, header) xlsx_path = f"init_{firma}_2025_12.xlsx" scrie_xlsx(header, out, xlsx_path) rez = verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, - leaf_rep, sarite, header) + leaf_rep, negative, header) print(f"=== {firma} ===") print(f" rows: {len(out)} totdeb={rez['totdeb']} totcred={rez['totcred']} net={rez['net']}") print(f" balanta={'OK' if rez['bal'] else 'ESEC'} " @@ -479,8 +494,8 @@ def main(): f"parteneri={'OK' if rez['part'] else 'ESEC'} " f"lungimi={'OK' if rez['lung'] else 'ESEC'}") print(f" scris {xlsx_path} si docs/verificare_{firma}.md") - if rez["sarite"]: - print(f" analitice sarite: {rez['sarite']}") + if rez["negative"]: + print(f" analitice cu semn negativ: {rez['negative']}") if rez["pierdute"] or rez["dubluri_leaf"] or rez["dubluri_bal"] or rez["lungimi"]: print(" ATENTIE:", rez["pierdute"], rez["dubluri_leaf"], rez["dubluri_bal"], rez["lungimi"]) diff --git a/init_FUNDATIA_2025_12.xlsx b/init_FUNDATIA_2025_12.xlsx index 7a4555b213d960ea252dfbf731fcb4433e90a333..d9aa688cb001a4462ffa593b1171ece580e6a5ac 100644 GIT binary patch delta 9190 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

y0HG^CEbs z=}PwfnIb>rcRpk0dQV6D$5?)5FvfBIW<_rX%}!oeEWwx+7pY2A)`OR|uvQ=VjLpVB zw%7Tc^)N@Vo49~LeA%0UPS4M6XmE+!I&6pac`oftLZc~>mW^?Jk%W-PbDM`>Nj}KkiN-v}m&G!W@Ho_N zNaWpgv5TN3h~DqhRR{W&QtcY);QfB4GuOsW<_|1MZ~GsV#LA|ZiC}UaY!V?I#GGLm zK!u5XjUkb}T3xD*i?NhnGwT0t z76N+8r8Yp=#?-7ma9U)v=K?q+R%#nMu73JW8zhI_YTg>7+M^Qs+}?&`b>p;;!6dhc zReOOyL`I*EWw*3sT)e>!4*{dq-uTnXe(G|5`}zJ9tzyH38{*>*nQmKLn~lgs zKmcemrLK<1X_2|99ewrH%6m)Scu^!|D#%>ZNmH&A5?Ffsb?vJb53Ty(^st1y>_A zZ%HiBCfA=$9Y;%BXH1+?tmwoMAAK<_1GbsdDHqwT(b<{B7bmR{1Z54!Ojvi;Mcdv6 z0ITvQUWc*RiU zV_5TGqZG`ATY*Fe)Xyq7QsML0rOXq25fHj9{S?yxNn@DI5lpku`~$%{wCv^k>46I= z($2cSaPXnX2$+>Bwq1)?K)?(ZKcNNOjl1Pau#7XZCfIcpm_bO_7a2No9Sj5Gg+ejI zY$l6>70iKc50klzED?s>Z?`FVC7MJRiWhCN9D%+Ui@D9|iX)VG0HBkCHxtBA#KCO~ zf&Y#rDVef6D*b3E){NmbCH(q1VuW^dvJ0k-cogOV# zKB#!NfWLJE*|f?s2CHDVU>=pX$@OW}h3vfgnm^AKd>7>t*SAzj#R_t+Y&XfJs&U?F z_2T&(J*C%WmKH6awhrH}XDac;9(wcMmBq|0%b_s1G&~^ud#gbd%jEIUhW8Y7tC-NO zLJ8Z)#ofWe#l_(t%1%hxP}_Zn6=6ybcKEo1IwxON{1F!=gdoWqz|Ptst0rnE|Ch0; zqV(cMm28gvCu!Xu9^62WeZiBdhs-%hCdj4*$XXB=S!rBmS4r}YJGX;??cV+%fi5E` zwX<^=mBYA|&y0Dpd|vKYN=4d6Cd>&7?o^~^#xIG57Y1|_%#Bmav{cgUUr;&(?(7w# z@%&|4lKF!bkxi4fdyi(5FM6<0F6_L}oeN*d*2w2nv`0kcgM{{`U0&Sk%qMtty%*h} zL*PrgRdo6WuEAcX5t+^ESH;ac_YAJyxMLK2zUNza@vY@LfB_6Z04w#oB*$o~J^EA#$a?tQOe?Led zX`?|T2mRI^1%gY&lW7&C5(pO9!+NUJ@2=GhJ+8h9Fscv}RTxw52!0l@)nIOTIoz?m z@VK#b7tg9?IOt_ubBELl`)+dJvIrcl?IRFU~?kceQrKV z1^bmrL>aH2>O%OY6*_9Ew{K2%(Eg1+CsI0`6k2-Asa#BC;Aypicj&{WWyfCjJc6#0 zCmivtfBMkE2aQYi3oKkbT|TchDHk>Z(^X1_@9sUG>8sl<;U|P`#B_Y2VTq7j3{KUH zM9!!6QdGlvE6raK>&mP3}^H(ldsuH_=?d)oAk( z5t6By-YHH-kfwcOM)o=UT{LiUTuX3ALKb6 zRmY7=Cyg2j{SF76t}=#ix&a?`1l9l2mU>^n4>e3MQ(pTNFuoX)_+l2lock};m!%G? z1EYV5)k^?0Q~Np)uy{h#rS|D9J!?PBJJtpKE+Gm`CSy%KtjN{Tl?I@qcsV|Cy$zPO*^u4}||Fm;ciV zN=0I&p!x^G|JE?H5=j1|0F}W20Y+#8mW=hk9sh6Hz`?-a{>y+YHJ+6L(U$q2m;VpC CW=YBb delta 9217 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 JIpd$X{|92*P|*MY diff --git a/init_MASTER_2025_12.xlsx b/init_MASTER_2025_12.xlsx index ee919b24fb19244b009a21d1cf81184c4b8d3d61..8c471c0c25ef4620840a3fbce7736a9196697a0a 100644 GIT binary patch delta 9381 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

  • 8lL52w2lN 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 delta 9269 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