diff --git a/README.md b/README.md index fd8907f..9da4c8c 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/citire_fdb.py b/citire_fdb.py index 15eb343..89f9b74 100644 --- a/citire_fdb.py +++ b/citire_fdb.py @@ -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, diff --git a/config/conturi_parteneri.csv b/config/conturi_parteneri.csv index 67db95a..e5e61c8 100644 --- a/config/conturi_parteneri.csv +++ b/config/conturi_parteneri.csv @@ -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. diff --git a/docs/analiza_lacerta_fdb.md b/docs/analiza_lacerta_fdb.md index 14486b8..960049f 100644 --- a/docs/analiza_lacerta_fdb.md +++ b/docs/analiza_lacerta_fdb.md @@ -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. diff --git a/docs/decizii_import.md b/docs/decizii_import.md index 8743c60..a05dfd6 100644 --- a/docs/decizii_import.md +++ b/docs/decizii_import.md @@ -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: diff --git a/extrage.py b/extrage.py index ee3b17c..23b4ace 100644 --- a/extrage.py +++ b/extrage.py @@ -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 diff --git a/genereaza_xlsx.py b/genereaza_xlsx.py index 5f1cb75..fc07c95 100644 --- a/genereaza_xlsx.py +++ b/genereaza_xlsx.py @@ -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), diff --git a/tests/golden/golden_FUNDATIA_2025_12.xlsx b/tests/golden/golden_FUNDATIA_2025_12.xlsx index 9bc7f96..3942651 100644 Binary files a/tests/golden/golden_FUNDATIA_2025_12.xlsx and b/tests/golden/golden_FUNDATIA_2025_12.xlsx differ diff --git a/tests/golden/golden_MASTER_2025_12.xlsx b/tests/golden/golden_MASTER_2025_12.xlsx index 37d93cd..6ad489d 100644 Binary files a/tests/golden/golden_MASTER_2025_12.xlsx and b/tests/golden/golden_MASTER_2025_12.xlsx differ diff --git a/tests/test_citire_fdb.py b/tests/test_citire_fdb.py index 54b0da0..04bfd6d 100644 --- a/tests/test_citire_fdb.py +++ b/tests/test_citire_fdb.py @@ -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]) diff --git a/tests/test_lacerta.py b/tests/test_lacerta.py index 168286f..5fd2d02 100644 --- a/tests/test_lacerta.py +++ b/tests/test_lacerta.py @@ -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__":