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
6.5 KiB
Raport lane citire-fdb - cititorul Firebird (SAGA noua)
Lane: citire-fdb, etapa 2. Data: 21.09.2026. Director: D:\ROA\IMPORT2ROA\solduri2roa.
1. Facut (livrabile)
| fisier | ce |
|---|---|
citire_fdb.py |
cititorul: balanta + parteneri + facturi din copia unei baze CONT_BAZA.FDB |
tests/test_citire_fdb.py |
5 teste unittest (poarta + scadent + SUM(REGISTRU) + % + parteneri/facturi) |
docs/procedura_copie_fdb_client.md |
cum isi face clientul copia bazei (backup/gbak/fisier brut) |
Puncte cheie in citire_fdb.py:
_SQL_BALANTA(:54) - agregareaREGISTRUpe trei intervale si pe doua laturi, cu rollup la sintetic (SUBSTRINGpana la punct), excluderea randului%si filtruDATA < inceputul lunii urmatoare(nu apar conturi cu activitate doar dupa luna ceruta)._conecteaza(:92) - embedded,fbclient.dll, SYSDBA/masterkey, charsetWIN1250,no_gc=True, tranzactieaccess_mode=READ; apelantul facerollback+close.citeste_balanta(:154) - neteaza precedentul (preluare + an) pe latura, da total = prec + rulaj si sold pe net; denumire/tip dinCONTURI.citeste_parteneri(:200) -FURNIZORI+CLIENTI; cod fiscal lipsa -> codul analitic.citeste_facturi(:243) -INTRD(+INTRARI, dedup peID_INTRARE) siIESIRI;SCADENTNULL -> ultima zi a lunii cerute.produce(:287) - scrie cele trei CSV-uri;main(:303) - CLIpy citire_fdb.py "<baza.fdb>" "<FIRMA>" <an> <luna> [dir].- Docstring-ul (vizibil la
--help) declara explicit ca cititorul e verificat doar pe cazul sintetic si nu se foloseste la un client fara rerularea portii pe datele lui.
Doar creari de fisiere noi. Nu s-a modificat genereaza_xlsx.py, citire_xlsx.py,
mapare.py, extract_balanta.py, config/*, tests/golden/*, tests/test_regresie.py,
tests/anonimizeaza_etalon.py, init_facturi_balanta_note.xlsx. Nu s-a scris nimic in
D:\SAGA250909 (doar copie citita in temporar).
2. Verificari
Poarta (criteriul de terminare)
Comanda de test:
py -m unittest discover -s tests -v
Rezultat (exact):
Ran 23 tests in 1.271s
OK
23 = cele 18 existente + 5 noi. EXIT=0. (Warnings: openpyxl fara stil implicit pe
exportul de joaca si WARNING *** OLE2 inconsistency de la xlrd pe .xls - preexistente,
nu esecuri.)
Poarta propriu-zisa (test_poarta_identica_cu_xlsx): balanta produsa de citire_fdb din
copia CONT_BAZA.FDB este identica cu cea produsa de citire_xlsx.py din
exemple\saga-sqlite-balanta-09-2026.xlsx, pentru luna 09/2026. Verificat pe randuri
(assertEqual) si la nivel de octet pe CSV-ul scris de ambii (878 octeti, identici).
Verificare manuala suplimentara (aceeasi concluzie):
nr xlsx 10 nr fdb 10
identice
Inlocuitorul verificarii "Totaluri:"
test_sum_registru_egal_netul_balantei: SUM(REGISTRU) pe debit si pe credit (fara
%/gol) la data ceruta; laturile sunt egale (8774.15 = 8774.15), iar
(debit - credit) = netul balantei generate (0.00). OK.
Restul garzilor
SCADENTNULL (singurul randINTRD) ->2026-09-30(ultima zi a lunii cerute). OK.- Contul colector
%nu apare in iesire; niciun rand fara cont. OK. - Parteneri: 2 randuri (
ROMFASTfara cod fiscal -> provizoriu401.00001;TRANSPORT->1879855). Facturi: 1 rand (401.00001,123,2026-07-02,2026-09-30,0.0). - Cod mod: fisier ASCII, LF (ca
citire_xlsx.py), 0 octeti > 127.
Nu s-a atins D:\SAGA250909: poarta si testele deschid o copie in
C:\Users\mmari\AppData\Local\Temp\opencode (facuta si stearsa de test); originalul nu a
fost deschis.
3. Nefacut / blocat / intrebari deschise
3.1 Analiticele din balanta - conflict plan vs poarta (de decis)
Planul si sarcina spun: "Agregarea grupeaza pe partea din stanga punctului si emite si
randul analitic, si sinteticul". Poarta spune: balanta FDB trebuie sa fie identica
cu cea din .xlsx.
Cele doua nu pot fi satisfacute simultan pe firma de joaca: REGISTRU are miscare pe
analiticul 401.00002, dar exportul .xlsx are doar randul sintetic 401 (10
randuri, niciunul cu punct). Daca as emite si analiticul, as obtine 11 randuri si poarta
pica. Am respectat poarta (criteriul explicit de terminare): citire_balanta ruleaza
analiticele in sintetic si emite un singur rand per sintetic.
Consecinta, de stiut: pentru un client real, balanta_<FIRMA>.csv produs de acest cititor
nu contine conturile analitice. In aval, genereaza_xlsx.py (pct. :236-305) asteapta
pentru conturile cu parteneri si randul sintetic (by[p]) si randurile analitice
(children[p]); cu iesirea doar-sintetic, 401 ar fi tratat ca partener fara analitice,
iar analiticele nepartenere ar disparea complet. Planul insusi scrie ca acest cititor e
"verificat partial ... nimic despre analitice - exact partea grea".
Nu am ghicit: am ales poarta. Ramane de decis una din variantele:
(a) balanta FDB e prin definitie doar-sintetic, iar analiticele se rezolva in alt pas
(nu exista azi); sau
(b) cititorul primeste un mod/flag (ex. --analitice) si poarta se defineste pe proiectia
sintetica, nu pe "identic".
3.2 rulaj brut vs net (asumare)
DEB_PREC == SOLD_IN_D in export (ex. 421: debit 1476, credit 4050, export
0 / 2574), deci precedentul e netat per cont - implementat asa. Pentru RULAJ_D/_C
nu exista nicio miscare in luna 09/2026, deci poarta nu poate decide daca SAGA da rulajul
brut sau netat. Am ales brut (pastreaza distinctia planului total = prec + rulaj,
altfel total ar deveni identic cu soldul). De reverificat pe primul client real.
3.3 Surse de facturi
INTRARI si IES_DET sunt goale pe firma de joaca, iar IES_DET/INTRD_DET sunt tabele
de linii (nu au CONT_CLI/DATA/SCADENT), deci nu pot da randul de factura.
Implementat: furnizori din INTRD (+ INTRARI daca are randuri, dedup pe ID_INTRARE),
clienti din IESIRI. Daca pe un client real facturile stau altfel, se ajusteaza dupa ce se
vede baza.
3.4 Altele
data/scadentse scriu ISO (YYYY-MM-DD); contractul nu fixeaza formatul..gitignore: planul (sectiunea Git) cereparteneri_*.csv/facturi_*.csv/*.fdb; nu le-am adaugat (in afara livrabilului lane-ului).- Ordinea balantei: crescator lexicografic pe
cont; coincide cu ordinea din exportul de joaca. Daca SAGA real ordoneaza altfel, poarta pe client va arata.
4. Stare periculoasa
Niciuna. Fara procese lasate pornite, fara .vc2/.sc2 editate, fara date de test
consumate, fara commit (git status: doar cele 3 fisiere noi, netracked). Copiile
temporare ale bazei au fost sterse.