Cercetare: ambele formate SAGA (VFP xls/xlsx si Firebird .FDB), cu dovezi fisier:linie in docs/raport_sursa_saga_xlsx.md si raport_exporturi_saga_noua.md. Plan v3 dupa review de strategie si arhitectura: contract intern + trei cititoare, mapare in doua fisiere cu proprietari diferiti, lane-uri. Etalon de regresie anonimizat in tests/golden/ (sume si structura neatinse, zero IBAN si zero cod fiscal real). Tabela de corespondenta ramane ignorata. Iesirile de productie ies din git (raman pe disc); .gitignore acopera si copiile de baze de client si iesirile intermediare ale convertorului. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
18 KiB
Raport exporturi SAGA noua (Firebird) - cercetare read-only
Lane: exporturi-saga-noua. Sarcina de cercetare, fara modificari de cod.
Fisiere analizate in D:\ROA\IMPORT2ROA\solduri2roa\exemple\:
saga-sqlite-balanta-09-2026.xlsx, saga-sqlite-balanta-09-2026.xls,
saga-sqlite-furnizori-09-2026.xlsx, saga-sqlite-furnizori-facturi-un-furnizor-09-2026.xlsx.
Baza explorata: D:\SAGA250909\0001\CONT_BAZA.FDB (Firebird, NU SQLite).
Temporarele de lucru: C:\Users\mmari\AppData\Local\Temp\opencode. Nu s-a modificat nimic in
D:\SAGA250909 (doar SELECT, tranzactie read-only). Fisierele nu sunt SQLite; numele contin
"sqlite" dar continutul sunt foi de calcul obisnuite (vezi mai jos).
PARTEA A - structura celor 4 exporturi
A.1 saga-sqlite-balanta-09-2026.xlsx
- O singura foaie:
Sheet1. DimensiuneA1:AI11= 11 randuri x 35 coloane (1 antet + 10 randuri de date). Fara foi ascunse, fara celule fuzionate. - Antetul este pe randul 1. Datele incep la randul 2 si se termina la randul 11.
- NU exista rand de totaluri (ultimul rand este o data: contul
6461).
Coloanele, in ordine (litera = nume):
| Lit | Nume | Lit | Nume | Lit | Nume |
|---|---|---|---|---|---|
| A | CONT | M | RULAJT_D | Y | RULAJ_D_1 |
| B | DENUMIRE | N | RULAJT_C | Z | RULAJ_C_1 |
| C | CATEGORIE | O | TOTAL_DEB | AA | RULAJT_D_1 |
| D | TIP | P | TOTAL_CRED | AB | RULAJT_C_1 |
| E | DEB_INIT | Q | FIN_D | AC | TOTAL_DEB_1 |
| F | CRED_INIT | R | FIN_C | AD | TOTAL_CRED_1 |
| G | DEB_PREC | S | DEB_INIT_1 | AE | FIN_D_1 |
| H | CRED_PREC | T | CRED_INIT_1 | AF | FIN_C_1 |
| I | SOLD_IN_D | U | DEB_PREC_1 | AG | ANALITIC |
| J | SOLD_IN_C | V | CRED_PREC_1 | AH | VALIDAT |
| K | RULAJ_D | W | SOLD_IN_D_1 | AI | LINIE |
| L | RULAJ_C | X | SOLD_IN_C_1 |
Primele 8 randuri de date (rand Excel 2..9; sumele relevante, D/C separate):
| Rand | A cont | B denumire | D tip | E/F init | G/H prec | K/L rulaj | O/P total | Q/R fin | AG | AH | AI |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 2 | 371 | MARFURI | A | 0 / 0 | 2615 / 0 | 0 / 0 | 2615 / 0 | 2615 / 0 | 0 | 1 | 1 |
| 3 | 401 | FURNIZORI | P | 0 / 0 | 0 / 3164.15 | 0 / 0 | 0 / 3164.15 | 0 / 3164.15 | 0 | 1 | 2 |
| 4 | 421 | PERSONAL - SALARII DATORATE | P | 0 / 2574 | 0 / 2574 | 0 / 0 | 0 / 2574 | 0 / 2574 | 0 | 0 | 3 |
| 5 | 4315 | CONTR. DE ASIGURARI SOCIALE | P | 0 / 938 | 0 / 938 | 0 / 0 | 0 / 938 | 0 / 938 | 0 | 0 | 4 |
| 6 | 4316 | CONTR. DE ASIGURARI SOCIALE DE SANATATE | P | 0 / 375 | 0 / 375 | 0 / 0 | 0 / 375 | 0 / 375 | 0 | 0 | 5 |
| 7 | 436 | CONTR. ASIGURATORIE DE MUNCA | P | 0 / 84 | 0 / 84 | 0 / 0 | 0 / 84 | 0 / 84 | 0 | 0 | 6 |
| 8 | 4426 | TVA DEDUCTIBILA | A | 0 / 0 | 549.15 / 0 | 0 / 0 | 549.15 / 0 | 549.15 / 0 | 0 | 1 | 7 |
| 9 | 444 | IMPOZITUL PE VENITURI DE NATURA SALARIILOR | P | 0 / 163 | 0 / 163 | 0 / 0 | 0 / 163 | 0 / 163 | 0 | 0 | 8 |
Ultimele 3 randuri (rand Excel 9..11):
| Rand | A cont | B denumire | D tip | E/F init | G/H prec | O/P total | Q/R fin | AG | AH | AI |
|---|---|---|---|---|---|---|---|---|---|---|
| 9 | 444 | IMPOZIT... SALARIILOR | P | 0 / 163 | 0 / 163 | 0 / 163 | 0 / 163 | 0 | 0 | 8 |
| 10 | 641 | CHELT. CU SALARIILE PERSONALULUI | A | 4050 / 0 | 4050 / 0 | 4050 / 0 | 4050 / 0 | 0 | 0 | 9 |
| 11 | 6461 | CHELT. CU CONTRIB. ASIGURATORIE PT. MUNCA A SALARIATILOR | A | 84 / 0 | 84 / 0 | 84 / 0 | 84 / 0 | 0 | 0 | 10 |
Tipuri reale de valori (openpyxl):
CONT(A) = text (str), ex.Sheet1!A2='371'. Nu e numar.DENUMIRE(B) = text.TIP(D) = text ('A'sau'P');CATEGORIE(C) = gol pe toate randurile.- Sumele (E..R si
_1) = numerice (float la citire, dar stocate ca numar). ANALITIC(AG) = boolean (Falsepe toate randurile);VALIDAT(AH),LINIE(AI) = intregi.
Cont sintetic vs analitic: in acest fisier nu exista niciun cont analitic - toate cele 10
coduri sunt fara punct (371, 401, 421, 4315, 4316, 436, 4426, 444, 641, 6461), iar ANALITIC
(AG) este 0/False pe toate randurile. Deci din acest fisier singur nu se poate arata cum arata un
rand analitic. Formatul analitic se vede in schimb in exportul de furnizori:
saga-sqlite-furnizori-09-2026.xlsx!H2 = 401.00002 (text). Rezulta: sintetic = cod fara punct
(401), analitic = sintetic.cod (401.00002). Daca si coloana ANALITIC distinge ceva ramane
neclar (aici e 0 pe toate randurile, inclusiv pe cele care in vechiul export VFP aveau 1 - vezi B).
Coloane de sume (maparea ceruta):
| Rol | Coloane |
|---|---|
| precedent D / C | DEB_PREC (G) / CRED_PREC (H) |
| rulaj D / C | RULAJ_D (K) / RULAJ_C (L) |
| total D / C | TOTAL_DEB (O) / TOTAL_CRED (P) |
| sold D / C | FIN_D (Q) / FIN_C (R) |
TOTAL_* sunt sume cumulative (precedent + rulaj), NU solduri; soldul final este FIN_*.
Exista in plus: DEB_INIT/CRED_INIT (E/F) = sold la inceputul anului, SOLD_IN_D/SOLD_IN_C
(I/J) = sold la inceput de perioada, RULAJT_D/RULAJT_C (M/N) = rulaj total cumulat.
Relatiile cerute, verificate pe toate cele 10 randuri (toleranta 0.005):
| Verificare | Rezultat |
|---|---|
TOTAL_DEB = DEB_PREC + RULAJ_D |
10/10 OK |
TOTAL_CRED = CRED_PREC + RULAJ_C |
10/10 OK |
FIN_D - FIN_C = TOTAL_DEB - TOTAL_CRED |
10/10 OK |
(suplimentar) SOLD_IN_D - SOLD_IN_C = DEB_PREC - CRED_PREC |
10/10 OK |
(suplimentar) acelasi set _1 (S..AF) identic cu setul principal |
10/10 OK |
Nu exista rand care sa pice. Setul _1 (S..AF) este identic cu setul principal pe toate
randurile - consecvent cu observatia din raport_sursa_saga_xlsx.md (pe conturile sintetice _1
este copia setului principal).
A.2 saga-sqlite-balanta-09-2026.xls vs .xlsx
Fisierele au acelasi continut (aceleasi 35 coloane in aceeasi ordine si aceleasi 10 randuri de
date, cu aceleasi valori). Semnaturi: .xls = OLE2/BIFF8 (d0cf11e0a1b11ae1...), .xlsx =
OOXML/ZIP (PK..). Diferente constatate:
| Aspect | .xls |
.xlsx |
|---|---|---|
| Nume foaie | xl |
Sheet1 |
| Antet | litere mici (cont, denumire, ...) |
litere mari (CONT, DENUMIRE, ...) |
CATEGORIE goala |
sir vid '' |
celula None |
| Restul valorilor | identice | identice |
Comparatia programatica (valori numerice + text case-insensitive) a dat 0 diferente in afara celor de mai sus. Deci: acelasi export, doar alt format si alta conventie de nume/case.
A.3 saga-sqlite-furnizori-09-2026.xlsx
- O foaie
Sheet1,A1:J2= 2 randuri x 10 coloane (1 antet + 1 rand de date). - Antet pe randul 1; datele pe randul 2. Nu exista rand de totaluri.
- Coloane: A
COD, BDENUMIRE, CNE_INIT, DTOTAL, EINCASARI, FNE_FIN, GNEACHITAT, HANALITIC, ISOLD, JGRUPA.
Randul de date (rand 2): A2='00002', B2='TRANSPORT', C2=3164.15, D2=0, E2=0,
F2=3164.15, G2=3164.15, H2='401.00002', I2=3164.15, J2 gol.
Tipuri: COD (A) si ANALITIC (H) = text; DENUMIRE (B) = text; sumele C..G, I numerice;
GRUPA (J) gol.
Ce identifica partenerul: in acest export partenerul este identificat prin:
COD= codul SAGA al tertului (00002), text;ANALITIC= contul analitic401.00002(text) - da, apare codul contului analitic;DENUMIRE=TRANSPORT. Exportul NU contine codul fiscal (desi tabelulFURNIZORIdin baza il are - vezi Partea C). Deci legatura cu partenerul se face peCODsi/sau peANALITIC, nu pe cod fiscal.
A.4 saga-sqlite-furnizori-facturi-un-furnizor-09-2026.xlsx
- O foaie
Sheet1,A1:J2= 2 randuri x 10 coloane (1 antet + 1 rand de date). - Antet pe randul 1; datele pe randul 2. Nu exista rand de totaluri.
- Coloane: A
DATA, BNR, CCONT_FUR, DNE_INIT, ETOTAL, FPLATI, GNE_FIN, HNEACHITAT, IINF_SUPLM, JDATA_DOC.
Randul de date (rand 2): A2=2026-07-02 (datetime), B2='123' (text), C2='401.00002' (text),
D2=3164.15, E2=0, F2=0, G2=3164.15, H2=3164.15, I2 gol, J2 gol.
Campuri de factura prezente: numar (NR), data operare (DATA), cont furnizor (CONT_FUR),
sold initial neachitat (NE_INIT), total factura (TOTAL), plati (PLATI), neachitat final
(NE_FIN), neachitat (NEACHITAT), informatii suplimentare (INF_SUPLM), data document
(DATA_DOC).
Lipsesc: data scadenta si valuta (desi in baza, tabelul de intrari, are SCADENT si
COD_VALUTA - exportul nu le include). Nu exista nici o coloana de serie.
Legatura de furnizor: prin CONT_FUR = 401.00002 (acelasi analitic ca in A.3) - nu exista
COD de tert in acest export.
PARTEA B - comparatie cu ce stim deja
B.1 Cu CSV-ul din PDF (extract_balanta.py)
CSV-ul din PDF are coloanele:
pagina, cont, denumire, prec_d, prec_c, rulaj_d, rulaj_c, total_d, total_c, sold_d, sold_c, este_total.
Corespondenta cu exportul nou:
| CSV (PDF) | Export nou (balanta) |
|---|---|
cont |
CONT (A) |
denumire |
DENUMIRE (B) |
prec_d / prec_c |
DEB_PREC (G) / CRED_PREC (H) |
rulaj_d / rulaj_c |
RULAJ_D (K) / RULAJ_C (L) |
total_d / total_c |
TOTAL_DEB (O) / TOTAL_CRED (P) |
sold_d / sold_c |
FIN_D (Q) / FIN_C (R) |
pagina |
lipseste |
este_total |
lipseste |
Se poate produce acelasi CSV din exportul SAGA nou? Pentru partea de conturi + cele 8 sume: da, maparea e 1:1 si relatiile sunt aceleasi (verificate 10/10 la A.1). Ce lipseste:
pagina- proprie PDF-ului, depinde de paginare, nu are echivalent in export;este_total- exportul nu are deloc randuri de totaluri; in CSV-ul din PDF acest marker distinge randurile "Total sume clasa N" si randul "Totaluri:", care in export nu exista (ar trebui calculate, nu citite);- setul de conturi poate diferi: in exemplul nou apar doar conturile cu miscare, la nivel sintetic.
B.2 Cu vechiul export SAGA-pe-VFP (raport_sursa_saga_xlsx.md, sectiunea 1)
Structura este identica cu cea documentata acolo pentru balanta.xls (VFP): aceleasi 35 de
coloane, in aceeasi ordine, cu aceleasi nume (cont..fin_c, _1, analitic, validat,
linie). Singurele diferente observate:
- numele foii:
xl/Sheet1(nou) vsbalanta(VFP); - case-ul antetului (mic in
.xls, mare in.xlsx) - in raportul VFP antetul era cu litere mici; - valoarea coloanei
analitic: in fisierul VFP vechi era 1 pe toate randurile, in exportul nou este 0/False pe toate randurile (dar aici toate randurile sunt sintetice - nu se poate decide daca diferenta e de semantica sau doar de firma/perioada).
Concluzie: un convertor care stie deja sa citeasca exportul VFP (conturi.dbf / balanta.xls)
poate citi neschimbat si exportul SAGA nou Firebird - layout-ul de coloane este acelasi.
Observatie importanta (dovada in Partea C): desi layout-ul e identic cu tabelul CONTURI,
valorile din export nu sunt un dump brut al tabelului - soldurile stocate in CONTURI sunt 0,
iar cifrele din export corespund agregarii registrului de note (REGISTRU). Deci exportul e un
raport calculat, nu o citire directa de tabel.
PARTEA C - baza Firebird CONT_BAZA.FDB (explorare, NUMAI CITIRE)
C.1 Ce client/server exista pe masina
- Server Firebird instalat si pornit: serviciul
FirebirdServerFirebird30_Saga("C:\Program Files\Firebird\Firebird30_Saga\firebird.exe" -s Firebird30_Saga, LocalSystem). C:\Program Files\Firebird\Firebird30_Saga\contine:isql.exe,fbclient.dll,firebird.exe,gsec.exe,gbak.exe,gfix.exe,fbsvcmgr.exe, plusplugins\engine12.dll(Firebird 3.0). In plus SAGA are clientul inD:\SAGA250909\FbClient\(fbclient.dll,plugins\engine12.dll,legacy_auth.dll, etc.).- Versiunea raportata de baza: 3.0.7 (via
rdb$get_context('SYSTEM','ENGINE_VERSION')). - Port de ascultare: doar 3060 (
RemoteServicePort = 3060infirebird.conf; pe 3050 nu asculta nimic). O conexiune TCP lalocalhost/3060ajunge la baza dar raspunde cu eroare de autentificare (Your user name and password are not defined) - deci parola SYSDBA nu emasterkey/masterkela server.
C.2 Cum s-a reusit conectarea (read-only)
- S-a instalat
firebird-driver(py -m pip install firebird-driver-> 2.0.3) si s-a indicat explicit clientul:fdb.load_api(r"C:\Program Files\Firebird\Firebird30_Saga\fbclient.dll"). - Conexiunea embedded la fisier a functionat:
fdb.connect(database=r"D:\SAGA250909\0001\CONT_BAZA.FDB", user="SYSDBA", password="masterkey", charset="WIN1250", no_gc=True)-> OK, versiune 3.0.7. Embedded acceptamasterkey/masterke(autentificare locala/trusted); TCP la 3060 nu. - Respectarea "NUMAI CITIRE": s-a folosit o tranzactie read-only
(
fdb.tpb(Isolation.READ_COMMITTED, access_mode=TraAccessMode.READ)) sino_gc=True; s-au rulat doar SELECT-uri, apoirollback. Nu s-a scris, nu s-a facut ALTER, nu s-a copiat baza.
C.3 Ce contine baza
191 de tabele, 0 view-uri. Cele relevante pentru conversie:
| Tabel | Randuri | Ce este |
|---|---|---|
CONTURI |
586 | planul de conturi + solduri stocate |
FURNIZORI |
2 | furnizori |
CLIENTI |
0 | clienti |
INTRARI / INTRD |
0 / 1 | intrari = facturi furnizori (antet / detaliat) |
IESIRI / IES_DET |
0 / - | iesiri = facturi clienti |
REGISTRU |
8 | registru de note contabile (miscarile pe conturi) |
FFACT |
5 | NU e tabel de facturi - e tabela de formulare/layout de tiparire |
Structuri (campurile cheie; tipurile sunt cele din rdb$relation_fields/rdb$fields):
CONTURI (586 randuri) - plan de conturi:
CONT VARCHAR(20) NOT NULL, DENUMIRE VARCHAR(64), TIP CHAR(1),
DEB_INIT/CRED_INIT/DEB_PREC/CRED_PREC NUMERIC(15,2),
CONT_INCH VARCHAR(20), DEB_INIT_V/CRED_INIT_V/DEB_PREC_V/CRED_PREC_V NUMERIC(14,2),
COD_VALUTA VARCHAR(3), BLOCAT SMALLINT.
Exemplu de rand: ('1012', 'CAPITAL SUBSCRIS VARSAT', 'P', 0.00, 0.00, 0.00, 0.00, ...).
Atentie: CONT e text (se citeste ca sir, deci 401.00002 nu se strica);
in acest exemplu toate soldurile stocate sunt 0 - vezi C.4.
FURNIZORI (2 randuri):
COD VARCHAR(8) NOT NULL, DENUMIRE VARCHAR(64), COD_FISCAL VARCHAR(20), REG_COM VARCHAR(16),
ANALITIC VARCHAR(20), GRUPA VARCHAR(16), plus adresa/IBAN/agent/etc.
Randuri: ('00001','ROMFAST','','401.00001'), ('00002','TRANSPORT','1879855','401.00002').
CLIENTI (0 randuri): aceeasi structura de tert ca FURNIZORI
(COD, DENUMIRE, COD_FISCAL, ANALITIC, GRUPA, adresa, agent, limita credit, e-Factura...).
INTRARI (0) / INTRD (1 rand) - facturi furnizori:
ID_INTRARE, NR_NIR, NR_INTRARE, COD, DENUMIRE, CONT_FUR, DATA, SCADENT,
NEACHITAT NUMERIC(15,2), NEACHITAT_VAL, COD_VALUTA, CURS, VAL_VAL, VAL_LEI,
BAZA_TVA, TOTAL, TVA, TRANSP_VAL/LEI, VALIDAT, DATA_DOC, INF_SUPLM, ...
Randul existent: ID_INTRARE=24, NR_INTRARE='123', COD='00001', CONT_FUR='401.00001', DATA=2026-07-02, SCADENT=NULL, TOTAL=0, NEACHITAT=0, COD_VALUTA='EUR'.
IESIRI (0) - facturi clienti:
NR_IESIRE, ID_IESIRE, COD, DENUMIRE, CONT_CLI, DATA, SCADENT, TOTAL,
NEACHITAT, BAZA_TVA, TVA, COMANDA, DATA_DOC, INF_SUPLM, IS_EF, ...
REGISTRU (8 randuri) - notele contabile (sursa miscarilor):
ID_NOTA, CONT_D VARCHAR(20), CONT_C VARCHAR(20), SUMA NUMERIC(15,2), DATA,
EXPLICATIE, VALIDAT, COD, TIP_O, PK. Aici se vede cheia: contul analitic apare in
CONT_D/CONT_C ca text (401.00002), iar % este un cont colector.
Deci: planul de conturi cu solduri = CONTURI; furnizorii = FURNIZORI; clientii = CLIENTI;
facturile furnizorilor = INTRARI/INTRD; facturile clientilor = IESIRI/IES_DET.
C.4 Dovada ca exporturile sunt rapoarte calculate, nu dump de tabel
CONTURIare 585 randuri utile (fara randul%) si 0 randuri cu sold stocat nenul (deb_prec/cred_prec/deb_init/cred_init= 0 pentru toti), si totusi exportul de balanta are cifre. Deci cifrele vin din agregareaREGISTRUla data raportului.- Potriviri exacte:
REGISTRUare pe371debit2615.00-> exportul are371DEB_PREC=2615; pe401.00002credit2615.00 + 549.15 = 3164.15-> exportul are401CRED_PREC=3164.15si exportul de furnizoriSOLD=3164.15. In plus, miscarea veche pe641este din 2025-11-30 -> exportul areDEB_INIT=4050(sold la inceput de an), ceea ce confirma semanticaDEB_INIT/CRED_INIT= inceput de an siDEB_PREC/CRED_PREC= inceput de perioada. - In exportul de balanta contul apare ca
401(sintetic), iar401.00002(analitic) nu apare ca rand separat -> exportul ruleaza analiticele in sinteticul lor (sau a fost cerut la nivel sintetic). Regula exacta de includere sintetic/analitic nu se poate stabili din acest singur exemplu.
C.5 Ce NU se poate stabili
- Nu se poate confirma exact din ce tabel/se selecteaza randul de factura din exportul
saga-sqlite-furnizori-facturi-un-furnizor: exportul areCONT_FUR='401.00002'siNR='123', dar singurul rand dinINTRDareCONT_FUR='401.00001'(ROMFAST), tot cuNR_INTRARE='123'. ColoaneleDATA/NR/CONT_FUR/TOTAL/NEACHITAT/INF_SUPLM/DATA_DOCexista inINTRD, darNE_INIT,PLATI,NE_FINnu exista ca si coloane in baza - sunt calculate (sold initial, plati, sold final). Potrivirea exacta a randului nu se poate face cu datele disponibile. - Semnificatia coloanei
ANALITICdin balanta (0/False la toate randurile) nu se poate stabili.
Stare si verificari
- Nu s-a modificat niciun fisier din proiect sau din
D:\SAGA250909; nu s-a facut write-back; nu s-a comis nimic (git/svn). Baza Firebird a fost accesata doar cu SELECT, in tranzactie read-only,no_gc=True, fara copiere. - Verificari rulate: relatiile de sume pe balanta (10/10 OK pentru toate cele trei relatii cerute);
comparatia
.xlsvs.xlsx(0 diferente reale); listarea tabelelor (191 tabele, 0 view-uri) si a structurilor cheie; potrivirea soldurilor export vsREGISTRU. - Temporare:
C:\Users\mmari\AppData\Local\Temp\opencode\(analiza.py,verif.py,fbtest*.py,fblist.py,fbcols.py,fbdata.py,fbsearch.py+ dump-uri txt). Nu sunt in proiect. - Fara stare periculoasa: niciun
.vc2editat fara write-back, niciun proces lasat pornit, fara date de test consumate.