# 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`) - agregarea `REGISTRU` pe trei intervale si pe doua laturi, cu rollup la sintetic (`SUBSTRING` pana la punct), excluderea randului `%` si filtru `DATA < inceputul lunii urmatoare` (nu apar conturi cu activitate doar dupa luna ceruta). - `_conecteaza` (`:92`) - embedded, `fbclient.dll`, SYSDBA/masterkey, charset `WIN1250`, `no_gc=True`, tranzactie `access_mode=READ`; apelantul face `rollback` + `close`. - `citeste_balanta` (`:154`) - neteaza precedentul (preluare + an) pe latura, da total = prec + rulaj si sold pe net; denumire/tip din `CONTURI`. - `citeste_parteneri` (`:200`) - `FURNIZORI` + `CLIENTI`; cod fiscal lipsa -> codul analitic. - `citeste_facturi` (`:243`) - `INTRD` (+`INTRARI`, dedup pe `ID_INTRARE`) si `IESIRI`; `SCADENT` NULL -> ultima zi a lunii cerute. - `produce` (`:287`) - scrie cele trei CSV-uri; `main` (`:303`) - CLI `py citire_fdb.py "" "" [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 - `SCADENT` NULL (singurul rand `INTRD`) -> `2026-09-30` (ultima zi a lunii cerute). OK. - Contul colector `%` nu apare in iesire; niciun rand fara cont. OK. - Parteneri: 2 randuri (`ROMFAST` fara cod fiscal -> provizoriu `401.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_.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`/`scadent` se scriu ISO (`YYYY-MM-DD`); contractul nu fixeaza formatul. - `.gitignore`: planul (sectiunea Git) cere `parteneri_*.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.