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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BdA5a3ECKFD6Citf1ptPZu
This commit is contained in:
2026-09-21 00:14:07 +03:00
parent 92dc8c7b32
commit 4c59a103c9
7 changed files with 158 additions and 139 deletions

View File

@@ -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`** (casa, fara analitice): rand `BALANTA` pe `5311` (acont gol) + rand `FACTURA` pe
`5311` (acont gol), partener `CENTRALA`. `5311` (acont gol), partener `CENTRALA`.
- **`5125`**: **doar analitice**, fara parteneri. Se trateaza ca orice cont obisnuit cu analitice. - **`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) - Un analitic cu soldul pe **latura opusa** laturii fixate in cod (`:379` - trezoreria merge pe
nu primeste rand FACTURA; ramane doar randul BALANTA si formularul ii pune `NEREPARTIZAT`. 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. 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 ## 16. Regula generala: randul FACTURA trebuie sa aiba acelasi `acont` ca randul BALANTA pe care il consuma

View File

@@ -1,4 +1,4 @@
# Raport lane `genxlsx` (v2) # Raport lane `genxlsx` (v3)
Script: `genereaza_xlsx.py`. Produce pentru fiecare firma xlsx-ul de initializare Script: `genereaza_xlsx.py`. Produce pentru fiecare firma xlsx-ul de initializare
(`init_<FIRMA>_2025_12.xlsx`, un sheet, randul 1 = capul de tabel, fara instructiuni/exemple) (`init_<FIRMA>_2025_12.xlsx`, un sheet, randul 1 = capul de tabel, fara instructiuni/exemple)
@@ -6,7 +6,7 @@ si raportul de verificare (`docs/verificare_<FIRMA>.md`).
## Livrabile ## Livrabile
- `init_FUNDATIA_2025_12.xlsx` - 75 randuri (47 BALANTA, 28 FACTURA) - `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` - `docs/verificare_FUNDATIA.md`, `docs/verificare_MASTER.md`
- `genereaza_xlsx.py` - `genereaza_xlsx.py`
@@ -14,44 +14,43 @@ si raportul de verificare (`docs/verificare_<FIRMA>.md`).
| Firma | SUM(totdeb)=SUM(totcred) | frunze pierdute | parteneri | lungimi/dubluri | | Firma | SUM(totdeb)=SUM(totcred) | frunze pierdute | parteneri | lungimi/dubluri |
|---|---|---|---|---| |---|---|---|---|---|
| FUNDATIA | 7068369.50 = 7068369.50 (net 0.00) | 0 | OK | OK | | 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) ## Corectia v3 (fata de v2)
1. **Randul FACTURA `DIFERENTA SINTETIC <cont>` a fost eliminat** de pe conturile cu parteneri. **Analiticul cu sold pe latura opusa laturii fixate de formular (`frm..sc2:379`) NU mai este
Formularul scade singur suma randurilor FACTURA din randul BALANTA de pe acelasi sarit.** Primeste rand `FACTURA`, iar suma se scrie cu **semn negativ pe latura formularului**:
`(cont, acont, latura)` si pune restul pe partenerul `NEREPARTIZAT` pe care il creeaza el - randul `BALANTA` al analiticului: `totdeb = -|sold|` (daca latura formularului e D) sau
(`frm..sc2:415-431`). Diferenta nu se mai inventa de noi. `totcred = -|sold|` (daca e C), cealalta latura goala;
2. **Analitice cu sold pe latura opusa nu mai primesc FACTURA.** Latura FACTURA e fixa in cod - randul `FACTURA`: `sold = -|sold|`, pe aceeasi latura si cu **acelasi `acont`** ca BALANTA.
(`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 Soldul ramane pe latura corecta, `SUM(totdeb) = SUM(totcred)` se pastreaza (ambele laturi scad
`NEREPARTIZAT`. Fiecare caz e listat in raport (sectiunea 4). cu aceeasi suma), randul FACTURA consuma exact randul BALANTA si nu mai ramane nimic pe
3. **Randul BALANTA reprezinta contul sintetic intreg.** La partenerii cu un singur BALANTA `NEREPARTIZAT`. Regula se aplica general, la orice cont cu parteneri. Pretul acceptat: nota
agregat, `totdeb` = suma `total_d` a tuturor analiticelor + postarea directa pe sintetic contine o suma negativa.
(idem `totcred`), nu doar analiticele pentru care s-a emis FACTURA.
4. **pct. 15 (revizuit 20.09.2026):** Efecte pe MASTER: +1 rand (FACTURA pentru `5121.01`), iar `SUM(totdeb)`/`SUM(totcred)` scad
- `5121`/`5124`: analiticele **raman analitice** si in plus primesc partener. Pentru fiecare cu 20.80 si ajung exact peste `Totaluri.total_d`/`total_c` din PDF (diferenta 0.00, fata de
analitic se scriu **doua randuri pe acelasi `(cont, acont)`**: un `BALANTA` cu acont si 20.80 in v2).
`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).
## Ce ramane pe `NEREPARTIZAT`, per cont (sectiunea 3 din verificari) ## 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`: Rezultat: toate conturile ies 0, mai putin MASTER `5121`:
| cont | SUM FACTURA | net sintetic | sarite | postare directa | NEREPARTIZAT asteptat | diferenta | | cont | SUM FACTURA | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta |
|---|---|---|---|---|---|---| |---|---|---|---|---|---|
| MASTER 5121 | 15599.25 | 15730.61 | -20.80 (`5121.01` creditor) | +152.16 | 131.36 | 131.36 | | 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 - MASTER `5121.01 PIRAEUS BANK - RON` (sold creditor 20,80): `BALANTA acont 01 totdeb=-20.80`
`BALANTA 5121 acont 01` pe credit -> formularul ii pune `NEREPARTIZAT`. + `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` - MASTER `5121` postare directa +152.16: rand `BALANTA 5121 acont 99` `DIFERENTA SINTETIC SAGA`
(fara FACTURA) -> `NEREPARTIZAT`. (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 ## Randuri de diferenta (pct. 13-15) generate
- MASTER `117` (nepartener): +2635.87 -> rand `BALANTA` cont 117, acont `99`, - MASTER `117` (nepartener): +2635.87 -> rand `BALANTA` cont 117, acont `99`,
nume `DIFERENTA SINTETIC SAGA`. 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). - FUNDATIA: niciunul (1171.01 are diferenta net zero - doar netare SAGA).
## Observatii ## Observatii
- SUM(totdeb) difera de `Totaluri.total_d` din PDF (FUNDATIA +739831.67, MASTER +20.80): - FUNDATIA: SUM(totdeb) difera de `Totaluri.total_d` din PDF cu +739831.67 (gross-ul
gross-ul sinteticelor netate de SAGA nu se poate reconstrui din frunze; netul coincide exact. 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. - Coloana `explicatia` (control D/C) este goala in xlsx-ul final.
- Nu s-a facut niciun commit. - Nu s-a facut niciun commit.

View File

@@ -20,25 +20,25 @@ Generat de `genereaza_xlsx.py` din `balanta_FUNDATIA.csv`. Randuri de date: 75 (
## 3. Conturi partener: FACTURA + NEREPARTIZAT = net sintetic ## 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 | | cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |
|---|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| 401 | -314703.58 | -314703.58 | 0.0 | 0.0 | 0.0 | 0.0 | OK | | 401 | -314703.58 | -314703.58 | 0.0 | 0.0 | 0.0 | OK |
| 4092 | 809.33 | 809.33 | 0.0 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 0.0 | OK | | 5311 | 72433.56 | 72433.56 | 0.0 | 0.0 | 0.0 | OK |
Rezultat: 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. Niciunul.

View File

@@ -1,15 +1,15 @@
# Verificare `init_MASTER_2025_12.xlsx` # 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) ## 1. Balanta generala (SUM totdeb = SUM totcred)
- SUM(totdeb) = 2318592.91 - SUM(totdeb) = 2318572.11
- SUM(totcred) = 2318592.91 - SUM(totcred) = 2318572.11
- diferenta (totdeb - totcred) = 0.0 -> OK - diferenta (totdeb - totcred) = 0.0 -> OK
- Totaluri balanta: total_d=2318572.11 total_c=2318572.11 net=0.0 - Totaluri balanta: total_d=2318572.11 total_c=2318572.11 net=0.0
- NET xlsx (0.0) vs NET Totaluri (0.0) -> OK - 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 ## 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 ## 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 | | cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |
|---|---|---|---|---|---|---|---| |---|---|---|---|---|---|---|
| 401 | -547108.99 | -547108.99 | 0.0 | 0.0 | 0.0 | 0.0 | OK | | 401 | -547108.99 | -547108.99 | 0.0 | 0.0 | 0.0 | OK |
| 4092 | 4.0 | 4.0 | 0.0 | 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 | 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 | 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 | 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 | 0.0 | OK | | 462 | -9810.0 | -9810.0 | 0.0 | 0.0 | 0.0 | OK |
| 5121 | 15599.25 | 15730.61 | -20.8 | 152.16 | 131.36 | 131.36 | OK | | 5121 | 15578.45 | 15730.61 | 152.16 | 152.16 | 152.16 | OK |
| 5124 | 1060090.96 | 1060090.96 | 0.0 | 0.0 | 0.0 | 0.0 | OK | | 5124 | 1060090.96 | 1060090.96 | 0.0 | 0.0 | 0.0 | OK |
| 5311 | 98460.87 | 98460.87 | 0.0 | 0.0 | 0.0 | 0.0 | OK | | 5311 | 98460.87 | 98460.87 | 0.0 | 0.0 | 0.0 | OK |
Rezultat: 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 ## 5. Lungimi si dubluri

View File

@@ -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 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 ceilalti parteneri se include in BALANTA agregat. NU se mai emite FACTURA de
diferenta (o rezolva formularul, prin NEREPARTIZAT). diferenta (o rezolva formularul, prin NEREPARTIZAT).
- analiticul cu sold pe latura opusa celei fixate de formular (':379') nu primeste - analiticul cu sold pe latura opusa celei fixate de formular (':379') primeste
FACTURA; ramane doar in BALANTA si apare ca NEREPARTIZAT. 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 import csv
@@ -155,8 +156,8 @@ def rand(header, **kw):
return r return r
def _semn_sold(net): def este_latura_formular(net, side):
return "creditor" if net < 0 else "debitor" return (net > 0) == (side == "D")
def genereaza(rows, header): def genereaza(rows, header):
@@ -183,7 +184,7 @@ def genereaza(rows, header):
out = [] out = []
leaf_map = {} # frunza -> randurile dedicate (folosite la dubluri) leaf_map = {} # frunza -> randurile dedicate (folosite la dubluri)
leaf_rep = set() # toate frunzele reprezentate (inclusiv in BALANTA agregat) 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): def add(r, leaf=None):
out.append(r) out.append(r)
@@ -220,21 +221,25 @@ def genereaza(rows, header):
for k in direct: for k in direct:
kd = by[k] kd = by[k]
kac = split_cont(k)[1] 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) 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: if net == 0:
continue continue
if (net > 0) == (side == "D"): sold = abs(net) if este_latura_formular(net, side) else -abs(net)
add(rand(header, TIP="FACTURA", cont=p, acont=kac, add(rand(header, TIP="FACTURA", cont=p, acont=kac,
numar=k.replace(".", ""), numar=k.replace(".", ""),
nume=kd["denumire"] or f"FURNIZOR {k}", nume=kd["denumire"] or f"FURNIZOR {k}",
cod_fiscal=k, sold=abs(net), explicatia=side)) cod_fiscal=k, sold=sold, explicatia=side))
else:
sarite.append((p, k, net,
f"sold {_semn_sold(net)} vs latura {side} "
f"a formularului"))
if p in diff_by_parent: if p in diff_by_parent:
d = diff_by_parent[p] d = diff_by_parent[p]
ac = acont_diferenta(p, direct) ac = acont_diferenta(p, direct)
@@ -246,8 +251,20 @@ def genereaza(rows, header):
# 401/4092/4111/461/462/4551 si 5311 # 401/4092/4111/461/462/4551 si 5311
if direct: if direct:
base_d = sum(by[k]["total_d"] for k in direct) base_d = 0.0
base_c = sum(by[k]["total_c"] for k in direct) 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) d = diff_by_parent.get(p, 0.0)
add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1, add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1,
nume=by[p]["denumire"], nume=by[p]["denumire"],
@@ -258,33 +275,33 @@ def genereaza(rows, header):
if net == 0: if net == 0:
leaf_rep.add(k) leaf_rep.add(k)
continue continue
if (net > 0) == (side == "D"): sold = abs(net) if este_latura_formular(net, side) else -abs(net)
add(rand(header, TIP="FACTURA", cont=p, acont=None, add(rand(header, TIP="FACTURA", cont=p, acont=None,
numar=k.replace(".", ""), numar=k.replace(".", ""),
nume=by[k]["denumire"] or f"FURNIZOR {k}", nume=by[k]["denumire"] or f"FURNIZOR {k}",
cod_fiscal=k, sold=abs(net), explicatia=side), cod_fiscal=k, sold=sold, explicatia=side),
leaf=k) leaf=k)
else:
sarite.append((p, k, net,
f"sold {_semn_sold(net)} vs latura {side} "
f"a formularului"))
leaf_rep.add(k)
else: else:
net = round(by[p]["total_d"] - by[p]["total_c"], 2) net = round(by[p]["total_d"] - by[p]["total_c"], 2)
add(rand(header, TIP="BALANTA", cont=p, acont=None, numar=1, if net != 0 and not este_latura_formular(net, side):
nume=by[p]["denumire"], totdeb=round(by[p]["total_d"], 2), neg = -abs(net)
totcred=round(by[p]["total_c"], 2)), leaf=p) negative.append((p, p, neg, side))
if net != 0: if side == "D":
if (net > 0) == (side == "D"): td, tc = neg, None
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))
else: else:
sarite.append((p, p, net, td, tc = None, neg
f"sold {_semn_sold(net)} vs latura {side} " else:
f"a formularului")) td = round(by[p]["total_d"], 2)
return out, diffs, leaf_map, leaf_rep, sarite 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): 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, def verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, leaf_rep,
sarite, header): negative, header):
by, children = arbore(rows) by, children = arbore(rows)
leaves = [c for c in by if c not in children] leaves = [c for c in by if c not in children]
diff_by_parent = dict(diffs) 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 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) 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 = [] part_verif = []
for p in sorted({c.split(".")[0] for c in by if este_partener(c)}): 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) net_sint = round(by[p]["total_d"] - by[p]["total_c"], 2)
suma = round(part_rows.get(p, 0.0), 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) direct = round(diff_by_parent.get(p, 0.0), 2)
asteptat = round(sarit + direct, 2) asteptat = direct
diferenta = round(net_sint - suma, 2) diferenta = round(net_sint - suma, 2)
ok = abs(diferenta - asteptat) <= 0.005 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_bal = abs(net) <= 0.005
ok_leaves = not pierdute and not duplicate_leaf 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 ok_lung = not lungimi and not dubluri_bal
L = [] 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 " L.append("Formularul scade din randul BALANTA suma randurilor FACTURA de pe "
"acelasi `(cont, acont, latura)` si lasa restul pe partenerul " "acelasi `(cont, acont, latura)` si lasa restul pe partenerul "
"`NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = " "`NEREPARTIZAT`. Deci: `net sintetic - SUM(sold FACTURA cu semn) = "
"analitice sarite + postare directa pe sintetic`.") "postare directa pe sintetic`.")
L.append("") L.append("")
L.append("| cont | SUM(sold FACTURA) | net sintetic | analitice sarite | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |") L.append("| cont | SUM(sold FACTURA) | net sintetic | postare directa | NEREPARTIZAT asteptat | diferenta | rezultat |")
L.append("|---|---|---|---|---|---|---|---|") L.append("|---|---|---|---|---|---|---|")
for p, suma, net_sint, sarit, direct, asteptat, diferenta, ok in part_verif: for p, suma, net_sint, direct, asteptat, diferenta, ok in part_verif:
L.append(f"| {p} | {suma} | {net_sint} | {sarit} | {direct} | {asteptat} " L.append(f"| {p} | {suma} | {net_sint} | {direct} | {asteptat} "
f"| {diferenta} | {'OK' if ok else '**ESEC**'} |") f"| {diferenta} | {'OK' if ok else '**ESEC**'} |")
L.append("") L.append("")
L.append(f"Rezultat: {'OK' if ok_part else '**ESEC**'}") L.append(f"Rezultat: {'OK' if ok_part else '**ESEC**'}")
L.append("") 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("")
L.append("Latura FACTURA e fixa in cod (`:379`): `401,404,462,419,408,4551` -> " 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 " "CREDIT, orice alt cont -> DEBIT. Un analitic cu sold pe latura opusa "
"primeste rand FACTURA; ramane in BALANTA si formularul ii pune " "primeste totusi rand FACTURA, iar suma se scrie cu **semn negativ pe "
"`NEREPARTIZAT`.") "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("") L.append("")
if not sarite: if not negative:
L.append("Niciunul.") L.append("Niciunul.")
else: else:
L.append("| cont | analitic | sold (semnat) | motiv |") L.append("| cont | analitic | sold (semnat) | latura formularului |")
L.append("|---|---|---|---|") L.append("|---|---|---|---|")
for cont, k, s, motiv in sarite: for cont, k, s, side in negative:
L.append(f"| {cont} | {k} | {s} | {motiv} |") L.append(f"| {cont} | {k} | {s} | {side} |")
L.append("") L.append("")
L.append("## 5. Lungimi si dubluri") L.append("## 5. Lungimi si dubluri")
L.append("") 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, "totdeb": totdeb, "totcred": totcred, "net": net,
"pierdute": pierdute, "dubluri_leaf": duplicate_leaf, "pierdute": pierdute, "dubluri_leaf": duplicate_leaf,
"dubluri_bal": list(dubluri_bal), "lungimi": lungimi, "dubluri_bal": list(dubluri_bal), "lungimi": lungimi,
"part_verif": part_verif, "sarite": sarite} "part_verif": part_verif, "negative": negative}
def main(): def main():
@@ -467,11 +482,11 @@ def main():
assert len(header) == 39, f"cap de tabel neasteptat: {len(header)} coloane" assert len(header) == 39, f"cap de tabel neasteptat: {len(header)} coloane"
for firma, csv_path in FIRME: for firma, csv_path in FIRME:
rows = citeste_balanta(csv_path) 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" xlsx_path = f"init_{firma}_2025_12.xlsx"
scrie_xlsx(header, out, xlsx_path) scrie_xlsx(header, out, xlsx_path)
rez = verifica(firma, csv_path, xlsx_path, rows, out, diffs, leaf_map, 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"=== {firma} ===")
print(f" rows: {len(out)} totdeb={rez['totdeb']} totcred={rez['totcred']} net={rez['net']}") print(f" rows: {len(out)} totdeb={rez['totdeb']} totcred={rez['totcred']} net={rez['net']}")
print(f" balanta={'OK' if rez['bal'] else 'ESEC'} " print(f" balanta={'OK' if rez['bal'] else 'ESEC'} "
@@ -479,8 +494,8 @@ def main():
f"parteneri={'OK' if rez['part'] else 'ESEC'} " f"parteneri={'OK' if rez['part'] else 'ESEC'} "
f"lungimi={'OK' if rez['lung'] else 'ESEC'}") f"lungimi={'OK' if rez['lung'] else 'ESEC'}")
print(f" scris {xlsx_path} si docs/verificare_{firma}.md") print(f" scris {xlsx_path} si docs/verificare_{firma}.md")
if rez["sarite"]: if rez["negative"]:
print(f" analitice sarite: {rez['sarite']}") print(f" analitice cu semn negativ: {rez['negative']}")
if rez["pierdute"] or rez["dubluri_leaf"] or rez["dubluri_bal"] or rez["lungimi"]: if rez["pierdute"] or rez["dubluri_leaf"] or rez["dubluri_bal"] or rez["lungimi"]:
print(" ATENTIE:", rez["pierdute"], rez["dubluri_leaf"], print(" ATENTIE:", rez["pierdute"], rez["dubluri_leaf"],
rez["dubluri_bal"], rez["lungimi"]) rez["dubluri_bal"], rez["lungimi"])

Binary file not shown.

Binary file not shown.