Lane integrare: extrage.py si genereaza.py cu parametri, maparea legata

Firmele si lunile nu mai sunt hardcodate. extrage.py dispecerizeaza catre cele
trei cititoare (pdf / xlsx / fdb, dedus din extensie, extensie necunoscuta =
eroare) si scrie contractul intern; genereaza.py aplica maparea si scrie
init_<FIRMA>_<an>_<luna>.xlsx plus mapare_<FIRMA>.xlsx.

genereaza_xlsx.py devine biblioteca: an/luna parametri, data si scadenta
calculate din ele, sablonul cautat langa script. Cand exista parteneri_ si
facturi_ (drumul FDB) se emite cate un FACTURA per document, cu cod fiscal real,
si numai daca suma documentelor da netul contului; altfel ramane comportamentul
de azi, un FACTURA agregat.

Corectat in orchestrare: la redenumirea unui cont cu parteneri, generatorul lua
primul analitic ca sa afle contul sintetic. Daca analiticele erau mapate pe
conturi diferite, BALANTA agregat si randurile FACTURA cadeau pe conturi
diferite, tacut. Acum se opreste cu eroare; colapsarea pe acelasi cont ramane
legala. Doua teste acopera ambele cazuri.

29 de teste trec, inclusiv regresia pe etalon cu generatorul modificat.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
This commit is contained in:
2026-09-21 16:23:45 +03:00
parent 6b37d370d7
commit 82511c8adb
5 changed files with 630 additions and 70 deletions

164
tests/test_integrare.py Normal file
View File

@@ -0,0 +1,164 @@
"""Test de integrare: capat-la-capat pe firma de joaca, din ambele surse.
Ruleaza `extrage.py` apoi `genereaza.py` in directoare temporare (nu scrie nimic in
radacina proiectului), din:
- exportul de foaie de calcul SAGA (exemple/saga-sqlite-balanta-09-2026.xlsx);
- copia bazei Firebird D:\\SAGA250909\\0001\\CONT_BAZA.FDB.
Verifica: xlsx-ul de import exista, are randuri de date si SUM(totdeb) = SUM(totcred).
Pe o masina fara baza / fbclient.dll / driver, teste FDB se sar, nu esueaza.
Rulare: py -m unittest discover -s tests -v
"""
import os
import pathlib
import shutil
import subprocess
import sys
import tempfile
import unittest
import openpyxl
RADACINA = pathlib.Path(__file__).resolve().parent.parent
if str(RADACINA) not in sys.path:
sys.path.insert(0, str(RADACINA))
import extrage
import genereaza_xlsx
EXTRAGE = RADACINA / "extrage.py"
GENEREAZA = RADACINA / "genereaza.py"
XLSX_EXEMPLU = RADACINA / "exemple" / "saga-sqlite-balanta-09-2026.xlsx"
FBCLIENT = pathlib.Path(r"C:\Program Files\Firebird\Firebird30_Saga\fbclient.dll")
BAZA = pathlib.Path(r"D:\SAGA250909\0001\CONT_BAZA.FDB")
FIRMA = "JOACA"
AN, LUNA = 2026, 9
TOL = 0.01
def _driver_disponibil():
try:
import firebird.driver # noqa: F401
return True
except Exception:
return False
def _ruleaza(script, arg, dir_iesire):
"""Ruleaza un punct de intrare cu `--dir` in directorul temporar si verificat."""
return subprocess.run(
[sys.executable, str(script), "--firma", FIRMA,
"--an", str(AN), "--luna", str(LUNA), "--dir", str(dir_iesire)] + arg,
cwd=str(dir_iesire), capture_output=True, text=True)
def _sume_xlsx(cale):
wb = openpyxl.load_workbook(cale)
try:
ws = wb.active
header = [c.value for c in ws[1]]
i_deb = header.index("totdeb")
i_cred = header.index("totcred")
deb = cred = 0.0
if ws.max_row > 1:
for row in ws.iter_rows(min_row=2, values_only=True):
deb += row[i_deb] or 0
cred += row[i_cred] or 0
return ws.max_row, deb, cred
finally:
wb.close()
class TestIntegrare(unittest.TestCase):
def setUp(self):
self._tmp = tempfile.TemporaryDirectory(prefix="integrare_")
self.dir = pathlib.Path(self._tmp.name)
def tearDown(self):
self._tmp.cleanup()
def _flux(self, sursa, fisier):
r = _ruleaza(EXTRAGE, ["--sursa", sursa, "--fisier", str(fisier)], self.dir)
self.assertEqual(r.returncode, 0, "extrage.py a picat:\n%s\n%s"
% (r.stdout, r.stderr))
self.assertTrue((self.dir / ("balanta_%s.csv" % FIRMA)).exists(),
"extrage.py nu a scris balanta")
r = _ruleaza(GENEREAZA, [], self.dir)
self.assertEqual(r.returncode, 0, "genereaza.py a picat:\n%s\n%s"
% (r.stdout, r.stderr))
xlsx = self.dir / ("init_%s_%d_%d.xlsx" % (FIRMA, AN, LUNA))
self.assertTrue(xlsx.exists(), "lipseste xlsx-ul de import: %s" % xlsx)
n, deb, cred = _sume_xlsx(xlsx)
self.assertGreater(n, 1, "xlsx-ul de import nu are randuri de date")
self.assertAlmostEqual(deb, cred, delta=TOL,
msg="SUM(totdeb)=%s != SUM(totcred)=%s" % (deb, cred))
return xlsx
def test_capat_la_capat_xlsx(self):
if not XLSX_EXEMPLU.exists():
self.skipTest("lipseste exportul %s" % XLSX_EXEMPLU)
self._flux("xlsx", XLSX_EXEMPLU)
def test_capat_la_capat_fdb(self):
if not FBCLIENT.exists():
self.skipTest("lipseste fbclient.dll: %s" % FBCLIENT)
if not BAZA.exists():
self.skipTest("lipseste baza Firebird: %s" % BAZA)
if not _driver_disponibil():
self.skipTest("lipseste pachetul firebird-driver")
copie = self.dir / "CONT_BAZA.FDB"
shutil.copy2(str(BAZA), str(copie))
self._flux("fdb", copie)
class TestDispecerSursa(unittest.TestCase):
def test_deducere_din_extensie(self):
self.assertEqual(extrage.deduce_sursa("balanta.pdf"), "pdf")
self.assertEqual(extrage.deduce_sursa("balanta.xls"), "xlsx")
self.assertEqual(extrage.deduce_sursa("balanta.XLSX"), "xlsx")
self.assertEqual(extrage.deduce_sursa("CONT_BAZA.FDB"), "fdb")
def test_extensie_necunoscuta_da_eroare(self):
with self.assertRaises(SystemExit):
extrage.deduce_sursa("balanta.csv")
if __name__ == "__main__":
unittest.main()
class TestMapareSinteticPartener(unittest.TestCase):
"""Analiticele unui cont cu parteneri nu au voie sa cada pe conturi diferite:
BALANTA e agregat pe sintetic, FACTURA e per analitic, iar o redenumire
partiala ar rupe tacit corespondenta dintre ele."""
ROWS = [
{"cont": "401", "denumire": "FURNIZORI", "total_d": 0.0, "total_c": 300.0},
{"cont": "401.0001", "denumire": "A", "total_d": 0.0, "total_c": 100.0},
{"cont": "401.0002", "denumire": "B", "total_d": 0.0, "total_c": 200.0},
]
def setUp(self):
self.header = genereaza_xlsx.citeste_header()
def test_conturi_diferite_dau_eroare(self):
mapare = {"401.0001": {"cont": "4011", "acont": None},
"401.0002": {"cont": "4012", "acont": None}}
with self.assertRaises(genereaza_xlsx.Stop) as ctx:
genereaza_xlsx.genereaza(self.ROWS, self.header, 2025, 12, mapare=mapare)
self.assertIn("conturi diferite", str(ctx.exception))
def test_acelasi_cont_pe_toate_analiticele_e_legal(self):
mapare = {"401.0001": {"cont": "4011", "acont": None},
"401.0002": {"cont": "4011", "acont": None}}
out, _, _, _, _ = genereaza_xlsx.genereaza(self.ROWS, self.header, 2025, 12,
mapare=mapare)
conturi = {r["cont"] for r in out}
self.assertEqual({"4011"}, conturi)