Decizii LACERTA: data = ultima zi, 542 cu parteneri, 4428/01, backup .fbk

- genereaza_xlsx: coloana data = ultima zi a lunii; etalonul de regresie
  actualizat doar pe aceasta coloana (verificat celula cu celula).
- config: 542 cont cu parteneri (acum identic cu REF); descrierea lui 4092
  corectata.
- extrage/citire_fdb: .fbk se restaureaza cu gbak -c in temporar; test ca
  da aceleasi fisiere ca FDB-ul.
- test_lacerta: 49/53 frunze identice cu REF, 4428.TOATE -> 4428/01.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
This commit is contained in:
2026-09-27 16:43:54 +03:00
parent 99d9cf0aff
commit b5773c9822
11 changed files with 71 additions and 35 deletions

View File

@@ -16,14 +16,14 @@ Rezultatul este `iesiri/init_FIRMA_2026_6.xlsx`, care se importa in ROACONT.
| sursa | fisier | ce se obtine |
|---|---|---|
| SAGA noua (Firebird) | `CONT_BAZA.FDB` (o **copie**, nu baza vie) | balanta + parteneri cu CUI + facturi per document |
| SAGA noua (Firebird) | `CONT_BAZA.FDB` (o **copie**, nu baza vie) sau backup `.fbk` | balanta + parteneri cu CUI + facturi per document |
| export SAGA | `.xls` / `.xlsx` | doar balanta |
| balanta tiparita | `.pdf` | doar balanta |
Tipul se deduce din extensie. **FDB-ul e sursa recomandata.** Clientul face copia dupa
`docs/procedura_copie_fdb_client.md`. Poate fi si oprita (`shutdown`): unealta
lucreaza pe o copie a ei si nu atinge fisierul primit. Backupul `.fbk` nu e acceptat
inca.
lucreaza pe o copie a ei si nu atinge fisierul primit. Un `.fbk` se restaureaza
automat in temporar.
## Pasii
@@ -54,7 +54,8 @@ Coloane: `cont_saga`, `cont`, `acont`, `exclus`, `motiv`. `cont` are maxim 4 car
| `4428.TOATE` | toate analiticele lui 4428 |
| `4428.RESTUL` | analiticele lui 4428 fara corectie exacta |
Exemple: `419.NETOPIA -> 419 / 2`, `4428.TOATE -> 4428 / (gol)` = strange tot pe sintetic.
Exemple: `419.NETOPIA -> 419 / 2`, `4428.TOATE -> 4428 / 01` = strange toate analiticele
pe unul singur (lasa `acont` gol doar daca sinteticul nu are si postari directe).
Cand un analitic nu incape in 4 caractere, genereaza se opreste si iti cere corectia.
## Reguli de stiut
@@ -62,6 +63,7 @@ Cand un analitic nu incape in 4 caractere, genereaza se opreste si iti cere core
- Conturile cu parteneri sunt in `config/conturi_parteneri.csv` (autoritatea).
Primesc un rand `BALANTA` pe sintetic si randuri `FACTURA` per partener sau document.
- In xlsx intra doar frunzele (ultimul nivel de analitic).
- Data soldurilor este ultima zi a lunii (`30.06.2026` pentru `--luna 6`).
- Diferenta dintre sintetic si suma analiticelor (note puse direct pe sintetic) iese
pe un analitic de diferenta (`9999`, `99`) sau, la parteneri, pe `NEREPARTIZAT` in ROA.
- Nu ajusta cifre ca sa treaca o verificare. Raporteaza.

View File

@@ -22,7 +22,7 @@ colector `%` se exclude.
Baza primita se copiaza in temporar si copia se repune online (clientul o poate opri
cu `full shutdown` inainte de copiere); fisierul primit nu se atinge.
VERIFICARI: firma de joaca din `D:\SAGA250909\0001` (sinteticele = exportul .xlsx,
VERIFICARI: firma de joaca din `D:/SAGA250909/0001` (sinteticele = exportul .xlsx,
la octet) si LACERTA 06/2026 (tests/test_lacerta.py: 48 din 53 de frunze identice cu
importul facut din exportul SAGA, restul explicate in docs/analiza_lacerta_fdb.md;
facturile per document insumeaza netul fiecarui partener). La un client nou se
@@ -43,6 +43,7 @@ from datetime import date
FBCLIENT = r"C:\Program Files\Firebird\Firebird30_Saga\fbclient.dll"
GFIX = os.path.join(os.path.dirname(FBCLIENT), "gfix.exe")
GBAK = os.path.join(os.path.dirname(FBCLIENT), "gbak.exe")
UTILIZATOR = "SYSDBA"
PAROLA = "masterkey"
CHARSET = "WIN1250"
@@ -292,12 +293,20 @@ def scrie_csv(rows, cale, coloane):
def copie_online(cale_fdb, dir_tmp):
"""Copiaza baza in dir_tmp si o repune online, daca clientul a oprit-o inainte de
copiere (`full shutdown`). Fisierul primit nu se atinge. Pe o baza deja online
gfix raspunde cu eroare, inofensiva: daca repunerea chiar esueaza, conectarea
urmatoare pica cu mesajul real (`database ... shutdown`)."""
copiere (`full shutdown`). Un backup `.fbk` se restaureaza cu gbak in dir_tmp.
Fisierul primit nu se atinge. Pe o baza deja online gfix raspunde cu eroare,
inofensiva: daca repunerea chiar esueaza, conectarea urmatoare pica cu mesajul
real (`database ... shutdown`)."""
if not os.path.exists(cale_fdb):
raise FileNotFoundError("lipseste baza Firebird: %s" % cale_fdb)
copie = os.path.join(dir_tmp, "CONT_BAZA.FDB")
if cale_fdb.lower().endswith(".fbk"):
rez = subprocess.run([GBAK, "-c", cale_fdb, copie, "-user", UTILIZATOR,
"-password", PAROLA], capture_output=True, text=True)
if rez.returncode != 0:
raise RuntimeError("restaurarea %s a esuat: %s"
% (cale_fdb, (rez.stderr or rez.stdout).strip()))
return copie
shutil.copyfile(cale_fdb, copie)
if os.path.exists(GFIX):
subprocess.run([GFIX, "-online", "normal", copie, "-user", UTILIZATOR,

View File

@@ -2,9 +2,10 @@ cont,categorie,motiv
5121,BANCA,Cont bancar in lei: analiticele raman analitice si primesc partener.
5124,BANCA,Cont bancar in valuta: analiticele raman analitice si primesc partener.
401,SINTETIC,Furnizori: BALANTA agregat pe sintetic plus cate un FACTURA per analitic.
4092,SINTETIC,Furnizori de imobilizari: BALANTA agregat plus FACTURA per analitic.
4092,SINTETIC,Furnizori-debitori pt. prestari de servicii: BALANTA agregat plus FACTURA per analitic.
4111,SINTETIC,Clienti: BALANTA agregat plus FACTURA per analitic.
461,SINTETIC,Debitori diversi: BALANTA agregat plus FACTURA per analitic.
462,SINTETIC,Creditori diversi: BALANTA agregat plus FACTURA per analitic.
4551,SINTETIC,Actionari: BALANTA agregat plus FACTURA per analitic.
542,SINTETIC,Avansuri de trezorerie: BALANTA agregat plus FACTURA per persoana (analitic).
5311,FARA_ANALITICE,Casa in lei: BALANTA plus FACTURA pe sintetic cu partener CENTRALA.
1 cont categorie motiv
2 5121 BANCA Cont bancar in lei: analiticele raman analitice si primesc partener.
3 5124 BANCA Cont bancar in valuta: analiticele raman analitice si primesc partener.
4 401 SINTETIC Furnizori: BALANTA agregat pe sintetic plus cate un FACTURA per analitic.
5 4092 SINTETIC Furnizori de imobilizari: BALANTA agregat plus FACTURA per analitic. Furnizori-debitori pt. prestari de servicii: BALANTA agregat plus FACTURA per analitic.
6 4111 SINTETIC Clienti: BALANTA agregat plus FACTURA per analitic.
7 461 SINTETIC Debitori diversi: BALANTA agregat plus FACTURA per analitic.
8 462 SINTETIC Creditori diversi: BALANTA agregat plus FACTURA per analitic.
9 4551 SINTETIC Actionari: BALANTA agregat plus FACTURA per analitic.
10 542 SINTETIC Avansuri de trezorerie: BALANTA agregat plus FACTURA per persoana (analitic).
11 5311 FARA_ANALITICE Casa in lei: BALANTA plus FACTURA pe sintetic cu partener CENTRALA.

View File

@@ -118,18 +118,22 @@ P1-P5 sunt facute. Rulare pe LACERTA dupa ele (`tests/test_lacerta.py`):
Corectiile folosite (in test, ca in REF): `419.NETOPIA -> 419 / 2`, `4428.TOATE -> 4428`.
## Intrebari deschise
## Intrebari - raspunse 26.09.2026
1. **4428 iese pe doua randuri**: `4428` fara acont (373,14, analiticele M/TI/TP stranse
prin `.TOATE`) si `4428 / 99` (1.376,54, postarile direct pe sintetic). Nu stiu cum
trateaza importul un cont cu rand si fara acont, si cu acont. Varianta sigura:
corectia `4428.TOATE -> 4428 / 01`, ca sa iasa doua frunze curate. Decizia e a ta.
2. `.fbk`: procedura clientului recomanda backupul `.fbk` ca varianta preferata, dar
`extrage.py` nu il accepta (nu il restaureaza cu `gbak -c`). Deocamdata clientul
trebuie sa trimita `.FDB`.
3. Deciziile de config de mai sus (`542`, `461`, `4092`) si coloana `data`.
1. 4428 -> corectia `4428.TOATE -> 4428 / 01`; doua frunze curate, `01` si `99`.
2. `.fbk` e acceptat: `extrage.py` il restaureaza cu `gbak -c` in temporar
(`tests/test_citire_fdb.py::test_fbk_identic_cu_fdb`).
3. `542` e adaugat in config (acum identic cu REF: BALANTA 2.243,57 / 1.824,07 si 2 FACTURA
care insumeaza 129,44). Descrierea lui `4092` e corectata.
4. Coloana `data` = ultima zi a lunii.
Frunze BALANTA identice cu REF dupa aceste decizii: **49 din 53**.
**Ramas deschis:** `461` si `4092` sunt conturi cu parteneri, dar pot avea analitice
functionale sau geografice (`461.SGR` "AMBALAJE SGR", `4092.1`). Azi un astfel de analitic
devine un pseudo-partener cu cod fiscal provizoriu (`461.SGR`).
## Starea pe disc
Cod: `citire_fdb.py` (P1-P3), `tests/test_citire_fdb.py` (poarta restransa la sintetice),
`tests/test_lacerta.py` (P4), `.gitignore` (P5). Suita: `py -m unittest discover -s tests`,
37 de teste, toate trec. Fisierele LACERTA din `exemple/` sunt ignorate de git.
38 de teste, toate trec. Fisierele LACERTA din `exemple/` sunt ignorate de git.

View File

@@ -119,9 +119,20 @@ Consecinte:
ambele randuri cu acelasi `acont`.
- Latura conteaza si ea: un rand FACTURA pe debit nu atinge randul BALANTA de pe credit.
## 17. Decizii din proba LACERTA (26.09.2026)
- Coloana `data` = **ultima zi a lunii** (inainte, prima zi). Etalonul de regresie a fost
actualizat doar pe aceasta coloana.
- `542` (avansuri de trezorerie) este cont cu parteneri: BALANTA pe sintetic + FACTURA per
persoana.
- Analitice nenumerice stranse pe sintetic (`4428.M/TI/TP` prin `.TOATE`) primesc un acont
(`01`), ca sa nu stea langa analiticul de diferenta (`99`) un rand fara acont.
- `461` si `4092` raman conturi cu parteneri, desi pot avea si analitice functionale sau
geografice (`461.SGR`, `4092.1`). Tratarea acestora e deschisa (docs/analiza_lacerta_fdb.md).
## Divergenta fata de CONFIG_CONT_IREG (constatata 21.09.2026)
Setul operational de conturi cu parteneri este `config/conturi_parteneri.csv` (9 conturi), validat
Setul operational de conturi cu parteneri este `config/conturi_parteneri.csv` (10 conturi; `542` adaugat 26.09.2026), validat
in productie. `CONFIG_CONT_IREG` din Oracle este doar **consultativ**; divergentele se raporteaza,
nu se aplica. Comparatia se reface oricand cu:

View File

@@ -27,6 +27,7 @@ SURSE_DUPA_EXTENSIE = {
".xls": "xlsx",
".xlsx": "xlsx",
".fdb": "fdb",
".fbk": "fdb", # backup gbak; se restaureaza in temporar (citire_fdb.copie_online)
}
@@ -35,7 +36,7 @@ def deduce_sursa(fisier):
sursa = SURSE_DUPA_EXTENSIE.get(ext)
if sursa is None:
raise SystemExit(
"extensie necunoscuta pentru %s: %r (astept .pdf, .xls/.xlsx sau .fdb)"
"extensie necunoscuta pentru %s: %r (astept .pdf, .xls/.xlsx, .fdb sau .fbk)"
% (fisier, ext))
return sursa

View File

@@ -166,17 +166,16 @@ def acont_diferenta(parent, kids):
return ac
def _data(an, luna):
"""Prima zi a lunii, in formatul din sablon (DD.MM.YYYY)."""
return "01.%02d.%04d" % (int(luna), int(an))
def _datascad(an, luna):
"""Ultima zi a lunii, in formatul din sablon (DD.MM.YYYY)."""
return "%02d.%02d.%04d" % (monthrange(int(an), int(luna))[1],
int(luna), int(an))
# data soldului = ultima zi a lunii (decizie 27.09.2026; inainte, prima zi)
_data = _datascad
def rand(header, an, luna, **kw):
r = {h: None for h in header}
r.update(an=an, luna=luna, data=_data(an, luna), datascad=_datascad(an, luna),

View File

@@ -11,6 +11,7 @@ sar, nu esueaza.
Rulare: py -m unittest discover -s tests -v
"""
import os
import subprocess
import pathlib
import shutil
import sys
@@ -110,6 +111,15 @@ class TestCitireFdb(unittest.TestCase):
# singura factura din firma de joaca are SCADENT NULL in INTRD
self.assertEqual(rows[0]["scadent"], asteptat)
def test_fbk_identic_cu_fdb(self):
"""Backupul gbak (.fbk) se restaureaza in temporar si da aceleasi fisiere."""
fbk = os.path.join(self.dir, "firma.fbk")
subprocess.run([citire_fdb.GBAK, "-b", self.baza, fbk, "-user",
citire_fdb.UTILIZATOR, "-password", citire_fdb.PAROLA], check=True)
a = citire_fdb.produce(self.baza, "A", AN, LUNA, os.path.join(self.dir, "a"))
b = citire_fdb.produce(fbk, "B", AN, LUNA, os.path.join(self.dir, "b"))
self.assertEqual(a, b)
def test_cont_colector_exclus(self):
rows = citire_fdb.citeste_balanta(self.baza, AN, LUNA)
self.assertNotIn("%", [r["cont"] for r in rows])

View File

@@ -37,7 +37,8 @@ AN, LUNA = 2026, 6
# deciziile de mapare din REF, pentru analiticele care nu intra in acont
CORECTII = [
["419.NETOPIA", "419", "2", None, "ca in REF"],
["4428.TOATE", "4428", None, None, "ca in REF"],
# REF are un singur rand 4428; 01 ca sa iasa frunze curate langa diferenta 4428/99
["4428.TOATE", "4428", "01", None, "decizie 26.09.2026"],
]
# frunza -> (REF, NOI), cu (totdeb, totcred); None = frunza lipseste
@@ -49,18 +50,15 @@ DIFERENTE_ASTEPTATE = {
("4092", "1"): ((2606.86, 0.0), None),
# nota de 900 direct pe 419: analitic de diferenta; REF a pierdut-o
("419", "9999"): (None, (0.0, 900.0)),
# 4428: postarile direct pe sintetic -> analitic de diferenta; totalul coincide
("4428", ""): ((1749.68, 0.0), (373.14, 0.0)),
# 4428: analiticele M/TI/TP pe 01 (corectie), postarile direct pe sintetic pe 99;
# totalul coincide cu randul unic din REF
("4428", ""): ((1749.68, 0.0), None),
("4428", "01"): (None, (373.14, 0.0)),
("4428", "99"): (None, (1376.54, 0.0)),
# 5121: regula de banca (BALANTA cu acont per cont bancar), validata la MASTER
("5121", ""): ((40801.41, 35876.25), None),
("5121", "1"): (None, (40601.41, 35876.25)),
("5121", "2"): (None, (200.0, 0.0)),
# 542 nu e cont cu parteneri in config: analitice + diferenta
("542", ""): ((2243.57, 1824.07), None),
("542", "01"): (None, (1828.77, 1824.07)),
("542", "02"): (None, (124.74, 0.0)),
("542", "99"): (None, (290.06, 0.0)),
# 891 are rulaj zero; REF nu-l scrie
("891", ""): (None, (0.0, 0.0)),
}
@@ -148,7 +146,8 @@ class TestLacerta(unittest.TestCase):
s[str(r["cont"])] += _v(r["sold"])
self.assertEqual({k: (c[k], round(s[k], 2)) for k in c}, {
"401": (12, 9220.75), "4092": (1, 2606.86), "4111": (1, 90.0),
"4551": (3, 3023583.0), "461": (1, 2250.0), "5121": (2, 4925.16)})
"4551": (3, 3023583.0), "461": (1, 2250.0), "5121": (2, 4925.16),
"542": (2, 129.44)})
if __name__ == "__main__":