"""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. 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)] + 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) class TestAcontPeAnaliticePartener(unittest.TestCase): """Cont cu parteneri care are si analitice functionale (461.SGR) si parteneri (461.RESTUL -> 461/1): cate un BALANTA per (cont, acont), FACTURA cu acelasi acont (decizii_import.md pct. 16), postarea direct pe sintetic pe acontul de diferenta.""" ROWS = [ {"cont": "461", "denumire": "DEBITORI DIVERSI", "total_d": 350.0, "total_c": 0.0}, {"cont": "461.SGR", "denumire": "AMBALAJE SGR", "total_d": 100.0, "total_c": 0.0}, {"cont": "461.00001", "denumire": "PARTENER X", "total_d": 200.0, "total_c": 0.0}, ] MAPARE = {"461.SGR": {"cont": "461", "acont": "SGR"}, "461.00001": {"cont": "461", "acont": "1"}} def test_balanta_si_factura_pe_acelasi_acont(self): out, _, _, _, _ = genereaza_xlsx.genereaza( self.ROWS, genereaza_xlsx.citeste_header(), 2026, 6, mapare=self.MAPARE) bal = {(r["cont"], r["acont"]): r["totdeb"] for r in out if r["TIP"] == "BALANTA"} fac = {(r["cont"], r["acont"]): (r["nume"], r["sold"]) for r in out if r["TIP"] == "FACTURA"} self.assertEqual(bal, {("461", "SGR"): 100.0, ("461", "1"): 200.0, ("461", "9999"): 50.0}) self.assertEqual(fac, {("461", "SGR"): ("AMBALAJE SGR", 100.0), ("461", "1"): ("PARTENER X", 200.0)})