Lane citire-fdb: cititorul Firebird, cu poarta pe firma de joaca
citire_fdb.py produce balanta, parteneri si facturi din CONT_BAZA.FDB. Soldurile stocate in CONTURI sunt 0, deci balanta se obtine agregand REGISTRU pe cele trei intervale de data; analiticul se ruleaza in sintetic si se emit ambele randuri; contul colector % se exclude. Conexiune embedded, READ, doar SELECT, rollback. Garzi pe NULL: scadenta lipsa cade pe ultima zi a lunii, codul fiscal lipsa pe codul provizoriu, partenerul intrand in lista pentru cautarea ANAF. Poarta: CSV-ul din FDB e identic la octet cu cel produs de citire_xlsx.py din exportul firmei de joaca (09/2026), iar SUM(REGISTRU) pe fiecare latura da netul balantei. Verificat independent: 10 conturi, 7298.15 pe ambele laturi. Limita, scrisa si in cod si in raport: firma de joaca nu are niciun analitic, deci cititorul e verificat DOAR pe cazul sintetic si nu se foloseste la un client fara rerularea portii pe datele lui. docs/procedura_copie_fdb_client.md: cum isi face clientul copia bazei. 23 de teste trec, fara skip. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
This commit is contained in:
129
tests/test_citire_fdb.py
Normal file
129
tests/test_citire_fdb.py
Normal file
@@ -0,0 +1,129 @@
|
||||
"""Teste pentru citire_fdb: balanta din Firebird identica cu exportul .xlsx.
|
||||
|
||||
Poarta: `balanta` produsa din copia unei baze `CONT_BAZA.FDB` trebuie sa fie
|
||||
identica (pana la octet) cu cea produsa de `citire_xlsx.py` din exportul de foaie
|
||||
de calcul, pe firma de joaca, luna 09/2026. Baza originala NU se deschide: se
|
||||
copiaza intr-un director temporar.
|
||||
|
||||
Pe o masina fara SAGA (fara fbclient.dll, baza, driver sau export) testele se
|
||||
sar, nu esueaza.
|
||||
|
||||
Rulare: py -m unittest discover -s tests -v
|
||||
"""
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import sys
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
RADACINA = pathlib.Path(__file__).resolve().parent.parent
|
||||
if str(RADACINA) not in sys.path:
|
||||
sys.path.insert(0, str(RADACINA))
|
||||
|
||||
import citire_fdb
|
||||
import citire_xlsx
|
||||
|
||||
FBCLIENT = pathlib.Path(r"C:\Program Files\Firebird\Firebird30_Saga\fbclient.dll")
|
||||
BAZA = pathlib.Path(r"D:\SAGA250909\0001\CONT_BAZA.FDB")
|
||||
XLSX = RADACINA / "exemple" / "saga-sqlite-balanta-09-2026.xlsx"
|
||||
|
||||
AN, LUNA = 2026, 9
|
||||
TOL = 0.01
|
||||
|
||||
|
||||
def _driver_disponibil():
|
||||
try:
|
||||
import firebird.driver # noqa: F401
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class TestCitireFdb(unittest.TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
if not FBCLIENT.exists():
|
||||
raise unittest.SkipTest("lipseste fbclient.dll: %s" % FBCLIENT)
|
||||
if not BAZA.exists():
|
||||
raise unittest.SkipTest("lipseste baza Firebird: %s" % BAZA)
|
||||
if not _driver_disponibil():
|
||||
raise unittest.SkipTest("lipseste pachetul firebird-driver")
|
||||
cls._tmp = tempfile.TemporaryDirectory(prefix="citire_fdb_")
|
||||
cls.baza = os.path.join(cls._tmp.name, "CONT_BAZA.FDB")
|
||||
shutil.copy2(str(BAZA), cls.baza)
|
||||
cls.dir = cls._tmp.name
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls._tmp.cleanup()
|
||||
|
||||
def test_poarta_identica_cu_xlsx(self):
|
||||
if not XLSX.exists():
|
||||
self.skipTest("lipseste exportul %s" % XLSX)
|
||||
rows_xlsx = citire_xlsx.citeste_balanta(str(XLSX))
|
||||
rows_fdb = citire_fdb.citeste_balanta(self.baza, AN, LUNA)
|
||||
self.assertTrue(rows_xlsx, "exportul xlsx nu are randuri")
|
||||
self.assertEqual(rows_xlsx, rows_fdb,
|
||||
"balanta din FDB difera de exportul xlsx")
|
||||
|
||||
# comparatie stricta: acelasi fisier CSV, la octet
|
||||
cale_xlsx = os.path.join(self.dir, "din_xlsx.csv")
|
||||
cale_fdb = os.path.join(self.dir, "din_fdb.csv")
|
||||
citire_xlsx.scrie_csv(rows_xlsx, cale_xlsx)
|
||||
citire_fdb.scrie_csv(rows_fdb, cale_fdb, citire_fdb.COLOANE_BALANTA)
|
||||
with open(cale_xlsx, "rb") as f:
|
||||
a = f.read()
|
||||
with open(cale_fdb, "rb") as f:
|
||||
b = f.read()
|
||||
self.assertEqual(a, b, "CSV-urile difera la nivel de octet")
|
||||
|
||||
def test_sum_registru_egal_netul_balantei(self):
|
||||
d_an, d_luna, d_urm = citire_fdb._limite(AN, LUNA)
|
||||
con = citire_fdb._conecteaza(self.baza)
|
||||
try:
|
||||
deb, cred = citire_fdb._select(
|
||||
con,
|
||||
"SELECT "
|
||||
"SUM(CASE WHEN TRIM(CONT_D) NOT IN ('', '%') THEN SUMA ELSE 0 END), "
|
||||
"SUM(CASE WHEN TRIM(CONT_C) NOT IN ('', '%') THEN SUMA ELSE 0 END) "
|
||||
"FROM REGISTRU WHERE DATA < ?", (d_urm,))[0]
|
||||
finally:
|
||||
con.rollback()
|
||||
con.close()
|
||||
self.assertAlmostEqual(float(deb), float(cred), delta=TOL,
|
||||
msg="SUM(REGISTRU) nu e echilibrat pe laturi")
|
||||
|
||||
rows = citire_fdb.citeste_balanta(self.baza, AN, LUNA)
|
||||
net_balanta = sum(r["total_d"] - r["total_c"] for r in rows)
|
||||
self.assertAlmostEqual(float(deb) - float(cred), net_balanta, delta=TOL,
|
||||
msg="netul din REGISTRU != netul balantei")
|
||||
|
||||
def test_scadent_null_cade_pe_ultima_zi_a_lunii(self):
|
||||
rows = citire_fdb.citeste_facturi(self.baza, AN, LUNA)
|
||||
self.assertTrue(rows, "nu s-au citit facturi")
|
||||
asteptat = citire_fdb._ultima_zi(AN, LUNA).isoformat()
|
||||
# singura factura din firma de joaca are SCADENT NULL in INTRD
|
||||
self.assertEqual(rows[0]["scadent"], asteptat)
|
||||
|
||||
def test_cont_colector_exclus(self):
|
||||
rows = citire_fdb.citeste_balanta(self.baza, AN, LUNA)
|
||||
self.assertNotIn("%", [r["cont"] for r in rows])
|
||||
self.assertTrue(all(r["cont"] for r in rows), "rand fara cont")
|
||||
|
||||
def test_parteneri_si_facturi(self):
|
||||
parteneri = citire_fdb.citeste_parteneri(self.baza)
|
||||
self.assertTrue(parteneri, "nu s-au citit parteneri")
|
||||
for r in parteneri:
|
||||
self.assertTrue(r["cont_analitic"])
|
||||
self.assertTrue(r["cod_fiscal"],
|
||||
"cod fiscal gol pentru %s" % r["cont_analitic"])
|
||||
facturi = citire_fdb.citeste_facturi(self.baza, AN, LUNA)
|
||||
for r in facturi:
|
||||
self.assertTrue(r["cont_analitic"])
|
||||
self.assertTrue(r["scadent"])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user