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:
59
docs/procedura_copie_fdb_client.md
Normal file
59
docs/procedura_copie_fdb_client.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Copia bazei SAGA pentru conversie (pentru client)
|
||||
|
||||
Ca sa convertim soldurile avem nevoie de o **copie** a bazei SAGA, nu de baza pe
|
||||
care lucrezi zilnic. Copia se face asa incat sa fie `consistenta` (sa se poata
|
||||
deschide) si sa nu te deranjeze in lucru.
|
||||
|
||||
## Ce este baza
|
||||
|
||||
Baza este un fisier numit `CONT_BAZA.FDB`, intr-un subfolder al instalarii SAGA
|
||||
(de exemplu `C:\SAGA\0001\CONT_BAZA.FDB`; `0001` este firma). Dimensiunea creste in
|
||||
timp; la firmele mici ajunge la zeci de MB.
|
||||
|
||||
## Varianta recomandata - backup din SAGA (baza poate rula)
|
||||
|
||||
1. In SAGA, cauta functia de administrare / intretinere a bazei: ceva de forma
|
||||
"Backup baza de date" sau "Salvare baza de date".
|
||||
2. Salveaza fisierul rezultat (are de obicei extensia `.fbk`) intr-un folder obisnuit.
|
||||
3. Rezultatul este o copie **consistenta** si **mai mica** decat fisierul brut, si se
|
||||
face fara sa opresti SAGA.
|
||||
|
||||
Daca in SAGA nu gasesti functia, foloseste varianta urmatoare.
|
||||
|
||||
## Varianta cu gbak (daca ai acces la folderul SAGA)
|
||||
|
||||
Deschide o fereastra de comanda (Start -> scrie `cmd` -> Enter) si ruleaza, pe un
|
||||
singur rand:
|
||||
|
||||
"C:\Program Files\Firebird\Firebird30_Saga\gbak.exe" -b -v "C:\SAGA\0001\CONT_BAZA.FDB" "C:\temp\firma.fbk" -user SYSDBA -password PAROLA_SAGA
|
||||
|
||||
- inlocuieste `C:\SAGA\0001\CONT_BAZA.FDB` cu calea reala a bazei tale;
|
||||
- inlocuieste `C:\temp\firma.fbk` cu unde vrei sa iasa copia;
|
||||
- `PAROLA_SAGA` este parola pe care o foloseste SAGA pentru baza (daca nu o stii,
|
||||
foloseste varianta cu backupul din SAGA).
|
||||
|
||||
Fisierul `.fbk` rezultat este mai mic decat baza si se deschide la noi cu o comanda
|
||||
asemanatoare (`gbak -c`), fara sa atingem instalarea ta.
|
||||
|
||||
## Daca preferi sa trimiti fisierul brut `CONT_BAZA.FDB`
|
||||
|
||||
Atunci trebuie neaparat sa **inchizi SAGA inainte**:
|
||||
|
||||
1. Inchide SAGA complet (Fisier -> Iesire) si astepta sa se inchida.
|
||||
2. Asteapta cateva secunde.
|
||||
3. Copiaza `CONT_BAZA.FDB` intr-un folder obisnuit (Copy / Paste).
|
||||
|
||||
Daca SAGA este pornit in timpul copierii, copia poate iesi **stricata** si nu se mai
|
||||
poate deschide.
|
||||
|
||||
## Cum trimiti
|
||||
|
||||
- Pune fisierul (`.fbk` sau `.FDB`) intr-o arhiva ZIP, ca sa se trimita mai usor.
|
||||
- Trimite arhiva pe canalul obisnuit.
|
||||
- Nu modifica si nu redenumi baza.
|
||||
|
||||
## Ce facem noi cu ea
|
||||
|
||||
Deschidem doar copia, in mod **citire** (`read-only`), nu modificam si nu scriem
|
||||
nimic in ea, si extragem balanta, partenerii si facturile pentru conversie. Baza ta
|
||||
originala ramane neatinsa.
|
||||
141
docs/raport_lane_citire_fdb.md
Normal file
141
docs/raport_lane_citire_fdb.md
Normal file
@@ -0,0 +1,141 @@
|
||||
# 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 "<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
|
||||
|
||||
- `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_<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`/`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.
|
||||
Reference in New Issue
Block a user