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:
164
tests/test_integrare.py
Normal file
164
tests/test_integrare.py
Normal 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)
|
||||
Reference in New Issue
Block a user