From 9a83e367d8ac46f5d80b9cad95a1c89fc76017e4 Mon Sep 17 00:00:00 2001 From: Marius Mutu Date: Mon, 21 Sep 2026 16:42:25 +0300 Subject: [PATCH] Muta datele din radacina in date/, iesiri/ si sablon/ date/ - intrari de la client (PDF-urile, exportul SAGA) si balanta intermediara iesiri/ - xlsx-urile generate si verificare_.md (ignorat de git) sablon/ - sablonul ROA Punctele de intrare scriu acolo implicit: extrage.py --dir=date, genereaza.py citeste din date/ si scrie in iesiri/ (--dir-iesire), ca radacina sa nu se murdareasca la fiecare rulare. Sablonul e cautat langa script, in sablon/. Actualizate: TEMPLATE, cele trei teste care tin caile, .gitignore, CLAUDE.md si handoff-ul. Poarta capat-la-capat incepuse sa sara tacut dupa mutarea PDF-urilor (skipTest pe "lipsesc PDF-urile"); acum arata din nou catre date/ si ruleaza. 33 de teste trec, zero skip-uri. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2 --- .gitignore | 4 +++- CLAUDE.md | 3 +++ IBB 31.12.2025.pdf => date/IBB 31.12.2025.pdf | Bin MJC 31.12.2025.pdf => date/MJC 31.12.2025.pdf | Bin docs/handoff_etapa2_convertor.md | 15 ++++++++++++--- extrage.py | 3 ++- genereaza.py | 12 ++++++++---- genereaza_xlsx.py | 2 +- .../init_facturi_balanta_note.xlsx | Bin tests/anonimizeaza_etalon.py | 4 ++-- tests/test_integrare.py | 9 +++++++-- tests/test_regresie.py | 2 +- tests/test_regresie_capat_la_capat.py | 16 +++++++++------- 13 files changed, 48 insertions(+), 22 deletions(-) rename IBB 31.12.2025.pdf => date/IBB 31.12.2025.pdf (100%) rename MJC 31.12.2025.pdf => date/MJC 31.12.2025.pdf (100%) rename init_facturi_balanta_note.xlsx => sablon/init_facturi_balanta_note.xlsx (100%) diff --git a/.gitignore b/.gitignore index c1a441c..8140584 100644 --- a/.gitignore +++ b/.gitignore @@ -3,11 +3,13 @@ __pycache__/ .gstack/ # iesiri si date de firme de productie - raman pe disc, nu in git +# (docs/verificare_*.md raman in git: sunt dovada importurilor validate in productie) +iesiri/ init_*.xlsx export_*.xlsx mapare_*.xlsx balanta_*.csv -!init_facturi_balanta_note.xlsx +!sablon/init_facturi_balanta_note.xlsx # etalonul de regresie e anonimizat si se comite; tabela de corespondenta NU tests/_corespondenta_anonimizare.json diff --git a/CLAUDE.md b/CLAUDE.md index 1629fac..5ac6604 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -18,6 +18,9 @@ Convertor balante SAGA (PDF) -> xlsx de initializare solduri ROACONT. | `citire_fdb.py` | CONT_BAZA.FDB -> balanta + parteneri + facturi (verificat doar pe sintetic) | | `mapare.py` | propunere automata + `corectii_.xlsx`, .TOATE/.RESTUL | | `config/conturi_parteneri.csv` | **conturile cu parteneri** - autoritatea, nu CONFIG_CONT_IREG | +| `date/` | intrari de la client (PDF, export SAGA) + balanta intermediara | +| `iesiri/` | xlsx-urile generate + `verificare_.md` (ignorat de git) | +| `sablon/init_facturi_balanta_note.xlsx` | sablonul ROA (rand 1 = coloane) | | `genereaza_xlsx.py` | CSV -> `init___.xlsx` | | `init_facturi_balanta_note.xlsx` | sablonul ROA (rand 1 = coloane, 2-13 instructiuni, 20+ exemple) | | `docs/decizii_import.md` | **regulile de mapare - citeste intai** | diff --git a/IBB 31.12.2025.pdf b/date/IBB 31.12.2025.pdf similarity index 100% rename from IBB 31.12.2025.pdf rename to date/IBB 31.12.2025.pdf diff --git a/MJC 31.12.2025.pdf b/date/MJC 31.12.2025.pdf similarity index 100% rename from MJC 31.12.2025.pdf rename to date/MJC 31.12.2025.pdf diff --git a/docs/handoff_etapa2_convertor.md b/docs/handoff_etapa2_convertor.md index e01af52..b53a2b8 100644 --- a/docs/handoff_etapa2_convertor.md +++ b/docs/handoff_etapa2_convertor.md @@ -24,6 +24,7 @@ Actualizat 21.09.2026, la finalul executiei. Versiunea anterioara a acestui fisi | `tests/` | 33 de teste, `unittest` din stdlib | | `docs/procedura_copie_fdb_client.md` | cum isi face clientul copia bazei | | `docs/raport_lane_*.md` | raportul fiecarui lane | +| `date/`, `iesiri/`, `sablon/` | intrari de la client / xlsx-uri generate / sablonul ROA | Commit-uri: `15bb26a` (plan + etalon), `f23b336` (contract), `ba4cbbf` (citire-xlsx + mapare), `6b37d37` (citire-fdb), `82511c8` (integrare), plus commit-ul final de regresie. @@ -84,15 +85,23 @@ de pe 4296 a fost oprit), `D:\ROA\ROACONT`, `D:\SAGA250909` si `saga2roa*` neati joaca deschisa numai prin copie in temporar, `tests/_corespondenta_anonimizare.json` ramasa ignorata de git. -Fisierele `init_FUNDATIA_2025_12.xlsx` si `init_MASTER_2025_12.xlsx` sunt pe disc dar nu in git; -sunt necesare doar daca vrei sa **regenerezi** etalonul (`py tests\anonimizeaza_etalon.py`). +Fisierele `iesiri/init_FUNDATIA_2025_12.xlsx` si `iesiri/init_MASTER_2025_12.xlsx` sunt pe +disc dar nu in git; sunt necesare doar daca vrei sa **regenerezi** etalonul +(`py tests\anonimizeaza_etalon.py`, care le citeste din `iesiri/`). ## 8. Cum rulezi acum unealta ``` -py extrage.py --fisier "IBB 31.12.2025.pdf" --firma FUNDATIA --an 2025 --luna 12 +py extrage.py --fisier "date\IBB 31.12.2025.pdf" --firma FUNDATIA --an 2025 --luna 12 py genereaza.py --firma FUNDATIA --an 2025 --luna 12 ``` +Implicit `extrage.py` scrie in `date/`, iar `genereaza.py` citeste din `date/` si scrie in +`iesiri/` (`--dir` / `--dir-iesire` le schimba). Sablonul e in `sablon/`. + +**Capcana de nume**: balanta firmei MASTER se numeste `balanta_MASTERJOB.csv`, nu +`balanta_MASTER.csv`, deci pentru ea trebuie dat explicit +`--balanta date\balanta_MASTERJOB.csv`. Eroarea e clara, nu tacuta. + Sursa se deduce din extensie (`.pdf`, `.xls`/`.xlsx`, `.fdb`); o extensie necunoscuta da eroare. Pentru Firebird, da calea catre o **copie** a bazei, niciodata baza vie a clientului. diff --git a/extrage.py b/extrage.py index c6cbbc9..ee3b17c 100644 --- a/extrage.py +++ b/extrage.py @@ -67,7 +67,8 @@ def main(): parser.add_argument("--firma", required=True) parser.add_argument("--an", type=int) parser.add_argument("--luna", type=int) - parser.add_argument("--dir", default=".", help="directorul de iesire") + parser.add_argument("--dir", default="date", + help="unde se scrie contractul intern (implicit date/)") a = parser.parse_args() sursa = a.sursa or deduce_sursa(a.fisier) diff --git a/genereaza.py b/genereaza.py index 53379c1..bc46c31 100644 --- a/genereaza.py +++ b/genereaza.py @@ -66,10 +66,14 @@ def main(): parser.add_argument("--luna", type=int, required=True) parser.add_argument("--balanta", help="implicit balanta_.csv din --dir") - parser.add_argument("--dir", default=".", help="directorul de iesire") + parser.add_argument("--dir", default="date", + help="de unde se citeste balanta (implicit date/)") + parser.add_argument("--dir-iesire", dest="dir_iesire", default="iesiri", + help="unde se scriu xlsx-urile (implicit iesiri/)") a = parser.parse_args() os.makedirs(a.dir, exist_ok=True) + os.makedirs(a.dir_iesire, exist_ok=True) balanta = a.balanta or os.path.join(a.dir, "balanta_%s.csv" % a.firma) if not os.path.exists(balanta): raise SystemExit("lipseste balanta: %s" % balanta) @@ -90,12 +94,12 @@ def main(): rows, header, an=a.an, luna=a.luna, mapare=override, parteneri=parteneri, facturi=facturi) - xlsx_path = os.path.join(a.dir, "init_%s_%d_%d.xlsx" + xlsx_path = os.path.join(a.dir_iesire, "init_%s_%d_%d.xlsx" % (a.firma, a.an, a.luna)) generator.scrie_xlsx(header, out, xlsx_path) rez = generator.verifica(a.firma, balanta, xlsx_path, rows, out, diffs, leaf_map, leaf_rep, negative, header, - dir_verificare=os.path.join(a.dir, "docs")) + dir_verificare=a.dir_iesire) print("=== %s ===" % a.firma) print(" rows: %d totdeb=%s totcred=%s net=%s" @@ -106,7 +110,7 @@ def main(): "OK" if rez["part"] else "ESEC", "OK" if rez["lung"] else "ESEC")) print(" scris %s si %s" % (xlsx_path, - os.path.join(a.dir, "docs", + os.path.join(a.dir_iesire, "verificare_%s.md" % a.firma))) if rez["negative"]: print(" analitice cu semn negativ: %s" % (rez["negative"],)) diff --git a/genereaza_xlsx.py b/genereaza_xlsx.py index 82d1e73..5f1cb75 100644 --- a/genereaza_xlsx.py +++ b/genereaza_xlsx.py @@ -37,7 +37,7 @@ VALUTA = None # Sablonul sta langa script, nu langa directorul de lucru: iesirile pot merge in temp. TEMPLATE = os.path.join(os.path.dirname(os.path.abspath(__file__)), - "init_facturi_balanta_note.xlsx") + "sablon", "init_facturi_balanta_note.xlsx") # Latura pe care formularul pune randurile FACTURA (frm...sc2:379/'383'): # conturile din lista merg pe CREDIT, tot restul pe DEBIT. diff --git a/init_facturi_balanta_note.xlsx b/sablon/init_facturi_balanta_note.xlsx similarity index 100% rename from init_facturi_balanta_note.xlsx rename to sablon/init_facturi_balanta_note.xlsx diff --git a/tests/anonimizeaza_etalon.py b/tests/anonimizeaza_etalon.py index 640c29f..58c6303 100644 --- a/tests/anonimizeaza_etalon.py +++ b/tests/anonimizeaza_etalon.py @@ -115,10 +115,10 @@ def anonimizeaza(): raport = [] for sursa, tinta in SURSE: - cale = RADACINA / sursa + cale = RADACINA / "iesiri" / sursa if not cale.exists(): raise SystemExit( - "Lipseste %s. Etalonul nu se poate construi - vezi docs/handoff_etapa2_convertor.md" + "Lipseste iesiri/%s. Etalonul nu se poate construi - vezi docs/handoff_etapa2_convertor.md" % sursa ) shutil.copy(cale, GOLDEN / tinta) diff --git a/tests/test_integrare.py b/tests/test_integrare.py index 5080df2..f92da80 100644 --- a/tests/test_integrare.py +++ b/tests/test_integrare.py @@ -48,10 +48,15 @@ def _driver_disponibil(): def _ruleaza(script, arg, dir_iesire): - """Ruleaza un punct de intrare cu `--dir` in directorul temporar si verificat.""" + """Ruleaza un punct de intrare cu `--dir` in directorul temporar si verificat. + + genereaza.py scrie implicit in iesiri/; in test totul sta in acelasi temporar. + """ + iesire = ["--dir-iesire", str(dir_iesire)] if script.name == "genereaza.py" else [] return subprocess.run( [sys.executable, str(script), "--firma", FIRMA, - "--an", str(AN), "--luna", str(LUNA), "--dir", str(dir_iesire)] + arg, + "--an", str(AN), "--luna", str(LUNA), "--dir", str(dir_iesire)] + + iesire + arg, cwd=str(dir_iesire), capture_output=True, text=True) diff --git a/tests/test_regresie.py b/tests/test_regresie.py index 1a6a6e8..e08a8f9 100644 --- a/tests/test_regresie.py +++ b/tests/test_regresie.py @@ -58,7 +58,7 @@ class TestRegresieEtalon(unittest.TestCase): try: header = generator.citeste_header() for firma, csv_nume, golden_nume in FIRME: - rows = generator.citeste_balanta(str(RADACINA / csv_nume)) + rows = generator.citeste_balanta(str(RADACINA / "date" / csv_nume)) out, _, _, _, _ = generator.genereaza(rows, header) brut = tmpdir / ("init_%s_2025_12.xlsx" % firma) generator.scrie_xlsx(header, out, str(brut)) diff --git a/tests/test_regresie_capat_la_capat.py b/tests/test_regresie_capat_la_capat.py index e7ebfe7..5056333 100644 --- a/tests/test_regresie_capat_la_capat.py +++ b/tests/test_regresie_capat_la_capat.py @@ -12,7 +12,7 @@ reguli si ACEIASI tabela ca tests/anonimizeaza_etalon.py si se compara cu tests/golden/ pe VALORI DE CELULA, nu pe hash de fisier. Asocierea PDF -> firma nu se presupune: fiecare balanta extrasa se compara cu -balanta de referinta din radacina (balanta_FUNDATIA.csv / balanta_MASTERJOB.csv), +balanta de referinta din date/ (balanta_FUNDATIA.csv / balanta_MASTERJOB.csv), care e cea folosita la constructia etalonului. Daca iesirea difera de etalon, etalonul are dreptate: se raporteaza, nu se ajusteaza. @@ -39,13 +39,14 @@ import anonimizeaza_etalon as anonim CORESP = TESTS / "_corespondenta_anonimizare.json" GOLDEN = TESTS / "golden" +DATE = RADACINA / "date" EXTRAGE = RADACINA / "extrage.py" GENEREAZA = RADACINA / "genereaza.py" AN, LUNA = 2025, 12 MAX_DIFERENTE_RAPORTATE = 20 -# PDF din radacina -> firma -> balanta de referinta din radacina -> etalon. +# PDF din date/ -> firma -> balanta de referinta din date/ -> etalon. # Asocierea e verificata de test_pdf_corespunde_referintei, nu doar afirmata. FIRME = [ ("FUNDATIA", "IBB 31.12.2025.pdf", "balanta_FUNDATIA.csv", @@ -100,9 +101,9 @@ class TestRegresieCapatLaCapat(unittest.TestCase): @classmethod def setUpClass(cls): - lipsa = [pdf for _, pdf, _, _ in FIRME if not (RADACINA / pdf).exists()] + lipsa = [pdf for _, pdf, _, _ in FIRME if not (DATE / pdf).exists()] if lipsa: - raise unittest.SkipTest("lipsesc PDF-urile din radacina: %s" + raise unittest.SkipTest("lipsesc PDF-urile din date/: %s" % ", ".join(lipsa)) if not CORESP.exists(): raise unittest.SkipTest( @@ -116,14 +117,15 @@ class TestRegresieCapatLaCapat(unittest.TestCase): cls.iesiri = {} try: for firma, pdf, _, _ in FIRME: - _ruleaza(EXTRAGE, ["--sursa", "pdf", "--fisier", str(RADACINA / pdf), + _ruleaza(EXTRAGE, ["--sursa", "pdf", "--fisier", str(DATE / pdf), "--firma", firma, "--an", AN, "--luna", LUNA, "--dir", str(tmpdir)], tmpdir) cls.balante[firma] = tmpdir / ("balanta_%s.csv" % firma) for firma, _, _, _ in FIRME: _ruleaza(GENEREAZA, ["--firma", firma, "--an", AN, "--luna", LUNA, - "--dir", str(tmpdir)], tmpdir) + "--dir", str(tmpdir), + "--dir-iesire", str(tmpdir)], tmpdir) for firma, _, _, golden_nume in FIRME: brut = tmpdir / ("init_%s_%d_%d.xlsx" % (firma, AN, LUNA)) @@ -140,7 +142,7 @@ class TestRegresieCapatLaCapat(unittest.TestCase): def _verifica_referinta(self, firma): """Balanta extrasa din PDF = balanta de referinta (verifica asocierea PDF->firma).""" - referinta = RADACINA / dict( + referinta = DATE / dict( (f, r) for f, _, r, _ in FIRME)[firma] if not referinta.exists(): self.skipTest("lipseste referinta %s" % referinta)