Files
solduri2roa/docs/raport_lane_citire_xlsx.md
Marius Mutu ba4cbbf62c Lane-urile citire-xlsx si mapare: cititorul de foaie SAGA si pasul de mapare
citire_xlsx.py citeste .xlsx (openpyxl) si .xls (xlrd) in acelasi contract intern
ca extract_balanta.py. Prima foaie, nu dupa nume; potrivire exacta a coloanelor,
niciodata pe substring (TOTAL_DEB vs TOTAL_DEB_1); CONT ramane text.

mapare.py: propunere automata, corectii_<FIRMA>.xlsx detinut de utilizator si
mapare_<FIRMA>.xlsx regenerat de unealta, .TOATE/.RESTUL in ordinea exact ->
RESTUL -> TOATE, redenumirea sinteticului. Se opreste cu eroare la cont/acont
peste 4 caractere, coliziune accidentala si cont_saga inexistent in corectii.

Corectat in orchestrare: .xls-ul SAGA nu are inregistrare CODEPAGE, deci xlrd
cadea pe iso-8859-1 si strica denumirile ("FURNIZORI \x97 DEBITORI"). Citirea se
face cu encoding_override="cp1250", cu o verificare in test care pica daca revine.

18 teste trec, inclusiv poarta de regresie pe etalon.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
2026-09-21 15:59:56 +03:00

5.7 KiB

Raport lane citire-xlsx - cititorul de foaie de calcul SAGA

Data: 21.09.2026. Lane: citire-xlsx, in paralel cu mapare.

1. Facut

Livrabil nou: citire_xlsx.py

Cititor pentru balantele SAGA .xls / .xlsx, scrie balanta_<FIRMA>.csv cu contractul intern (13 coloane). Puncte:

  • citire_xlsx.py:24 - COLOANE = contractul intern, identic cu extract_balanta.py plus tip.
  • citire_xlsx.py:27 - MAPARE_SUME: DEB_PREC/CRED_PREC -> prec_d/prec_c, RULAJ_D/RULAJ_C -> rulaj_d/rulaj_c, TOTAL_DEB/TOTAL_CRED -> total_d/total_c, FIN_D/FIN_C -> sold_d/sold_c.
  • citire_xlsx.py:41 _index_antet - potrivire exacta, case-insensitive (strip().upper()), niciodata pe substring; coloana ceruta lipsa sau duplicata -> ValueError cu numele coloanei.
  • citire_xlsx.py:57 _randuri_xlsx - openpyxl, data_only=True, read_only=True.
  • citire_xlsx.py:72 _randuri_xls - xlrd 2.0.2.
  • citire_xlsx.py:83 _randuri - alege dupa extensie; alta extensie -> ValueError. Ambele iau prima foaie (sheetnames[0] / sheet_by_index(0)), fara cautare dupa nume.
  • citire_xlsx.py:104 _cont - CONT ramane text; un float intreg (401.0) devine "401", unul cu zecimale (401.00002) devine "401.00002", niciodata numar.
  • citire_xlsx.py:117 _num - None/gol -> 0.0; alt text neconvertibil -> ValueError.
  • citire_xlsx.py:132 citeste_balanta - produce randurile; pagina si este_total raman goale (exportul nu are rand de totaluri); sare doar peste randurile complet goale.
  • citire_xlsx.py:152 scrie_csv - utf-8-sig, newline="", exact ca extract_balanta.py.
  • citire_xlsx.py:159 main - CLI: py citire_xlsx.py <sursa> <iesire.csv>.

Test nou: tests/test_citire_xlsx.py

unittest din stdlib, fara dependinte noi. Cazuri:

  • :85 test_xlsx_si_xls_identice - .xlsx (openpyxl) si .xls (xlrd) produc acelasi rezultat.
  • :102 test_relatii_si_frunze - pe ambele fisiere: total_d = prec_d + rulaj_d, total_c = prec_c + rulaj_c, sold_d - sold_c = total_d - total_c pe toate randurile, plus SUM(sold_d) = SUM(sold_c) pe frunze. Toleranta 0.01.
  • :110 test_cont_ramane_text - toate valorile cont sunt str.
  • :116 test_danube_analitice - saga2roa_danube\balanta.xls (341 randuri, 263 analitice); daca lipseste, skipTest. Verifica explicit ca 105.10 ramane text, nu numar.
  • :133 test_cont_numeric_devine_text - celula CONT scrisa ca numar (401.00002) iese text.
  • :148 test_coloana_lipsa_si_fara_substring - antet cu TOTAL_DEB_1 dar fara TOTAL_DEB da ValueError care numeste TOTAL_DEB: nici coloana lipsa nu trece tacut, nici _1 nu se confunda cu coloana principala.

2. Verificari

Comanda: py -m unittest discover -s tests -v (din radacina proiectului). Iesire exacta:

test_coloana_lipsa_si_fara_substring (test_citire_xlsx.TestCitireXlsx.test_coloana_lipsa_si_fara_substring) ... ok
test_cont_numeric_devine_text (test_citire_xlsx.TestCitireXlsx.test_cont_numeric_devine_text) ... ok
test_cont_ramane_text (test_citire_xlsx.TestCitireXlsx.test_cont_ramane_text) ... ok
test_danube_analitice (test_citire_xlsx.TestCitireXlsx.test_danube_analitice) ... ok
test_relatii_si_frunze (test_citire_xlsx.TestCitireXlsx.test_relatii_si_frunze) ... ok
test_xlsx_si_xls_identice (test_citire_xlsx.TestCitireXlsx.test_xlsx_si_xls_identice) ... ok
test_fundatia (test_regresie.TestRegresieEtalon.test_fundatia) ... ok
test_master (test_regresie.TestRegresieEtalon.test_master) ... ok

----------------------------------------------------------------------
Ran 8 tests in 0.542s

OK

test_regresie.py existent trece neatinse. (Pe stderr apar avertismentele cunoscute ale xlrd OLE2 inconsistency / No CODEPAGE si cel al openpyxl despre stil - nu afecteaza rezultatul.)

Verificare CLI capat-la-capat, iesire in director temporar:

py citire_xlsx.py "exemple/saga-sqlite-balanta-09-2026.xlsx" "$TEMP/out_test.csv"
  -> scris ...out_test.csv: 10 randuri
  -> pagina,cont,denumire,prec_d,prec_c,rulaj_d,rulaj_c,total_d,total_c,sold_d,sold_c,este_total,tip
     ,371,MARFURI,2615.0,0.0,0.0,0.0,2615.0,0.0,2615.0,0.0,,A

Cifre pe cele trei fisiere (relatii de sume, frunze): xlsx 10 randuri / 0 esec / 10 frunze; xls identic; DANUBE 341 randuri / 0 esec / 320 frunze, balanta frunzelor 19018742.48 = 19018742.48.

Fisiere noi: citire_xlsx.py (170 linii) si tests/test_citire_xlsx.py (137 linii), ambele ASCII curat (0 octeti > 0x7F) si LF (conventia fisierelor .py din proiect). Nu sunt .vc2 / .sc2 / .prg, deci regula de cens cp1250 nu se aplica.

git status: doar ?? citire_xlsx.py si ?? tests/test_citire_xlsx.py. Nimic altceva atins.

3. Nefacut / blocat

  • Interfata catre genereaza_xlsx.py (maparea) nu e atinsa: lane-ul mapare face asta. genereaza_xlsx.citeste_balanta foloseste csv.DictReader si citeste doar cont/denumire/total_d/total_c/este_total, deci coloana noua tip nu il deranjeaza.
  • extract_balanta.py nu a fost atins (interzis), deci CSV-ul de PDF are inca 12 coloane, fara tip. Contractul din plan cere 13 coloane pentru toate cele 3 cititoare; alinierea PDF-ului ramane de facut intr-un alt lane, cand se decide forma lui tip pe drumul PDF.
  • Intersectia cu citire-fdb (CSV identic xlsx/FDB pe firma de joaca) ramane pe lane-ul citire-fdb.
  • Nu am adaugat xlrd in CLAUDE.md la Mediu (il cere planul, dar e in afara scopului acestui lane; xlrd era deja instalat si documentat in docs/raport_sursa_saga_xlsx.md).

4. Stare periculoasa

Niciuna. Fara .vc2/.sc2 editat fara write-back, fara procese lasate pornite, fara date de test consumate (iesirile de test au mers in %TEMP%). Fara commit, fara git add, fara sed -i. Nu s-a modificat nimic sub D:\ROA\ROACONT, D:\SAGA250909 sau saga2roa*.