Lane contract: config/conturi_parteneri.csv, divergenta Oracle, poarta de regresie

Setul de conturi cu parteneri iese din literali si trece in
config/conturi_parteneri.csv, cu categorie si motiv. Comportamentul e neschimbat;
lipsa fisierului opreste cu eroare, nu cade pe set gol.

CONFIG_CONT_IREG ramane consultativ: tools/divergenta_parteneri.py raporteaza
divergenta, nu o aplica. Constatarea (27 conturi in Oracle si nu la noi, 3 la noi
si nu in Oracle - 5121, 5124, 5311) e scrisa in docs/decizii_import.md.

tests/test_regresie.py compara iesirea codului de azi cu tests/golden/ pe valori
de celula, prin anonimizatorul refolosit ca functie. Trece pe FUNDATIA si MASTER;
verificat ca pica la o schimbare reala de set de conturi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EYeAtVxeS8m4oXekjX8Am2
This commit is contained in:
2026-09-21 15:53:00 +03:00
parent 15bb26ac15
commit f23b3367d8
9 changed files with 477 additions and 49 deletions

View File

@@ -46,6 +46,69 @@ COL_TIP = 5
IBAN = re.compile(r"RO\s?\d{2}(?:\s?[A-Z0-9]{4}){5}", re.IGNORECASE)
def citeste_corespondenta(cale=CORESP):
"""Tabela real -> fals folosita la construirea etalonului. NU se regenereaza."""
return json.loads(pathlib.Path(cale).read_text(encoding="utf-8"))
def anonimizeaza_foaie(ws, coresp):
"""Anonimizeaza foaia `ws` in loc, completand tabela `coresp`. NU salveaza.
Intoarce (randuri FACTURA atinse, celule cu IBAN inlocuite).
"""
schimbate = 0
for rand in range(2, ws.max_row + 1):
if (ws.cell(rand, COL_TIP).value or "").strip().upper() != "FACTURA":
continue
schimbate += 1
nume = ws.cell(rand, COL_NUME).value
if nume:
if nume not in coresp["nume"]:
coresp["nume"][nume] = "PARTENER %03d" % (len(coresp["nume"]) + 1)
ws.cell(rand, COL_NUME).value = coresp["nume"][nume]
cf = ws.cell(rand, COL_COD_FISCAL).value
if cf:
cf = str(cf)
if cf not in coresp["cod_fiscal"]:
coresp["cod_fiscal"][cf] = "CF%06d" % (len(coresp["cod_fiscal"]) + 1)
ws.cell(rand, COL_COD_FISCAL).value = coresp["cod_fiscal"][cf]
for col in (COL_REG_COM, COL_ADRESA, COL_EXPLICATIA):
if ws.cell(rand, col).value:
ws.cell(rand, col).value = None
# IBAN-urile apar si in afara randurilor FACTURA (denumirea analiticului de banca)
ibanuri = 0
for rand in ws.iter_rows():
for celula in rand:
if not isinstance(celula.value, str) or not IBAN.search(celula.value):
continue
def fals(m, _c=coresp):
real = m.group(0)
if real not in _c["iban"]:
_c["iban"][real] = "RO00 IBAN %04d" % (len(_c["iban"]) + 1)
return _c["iban"][real]
celula.value = IBAN.sub(fals, celula.value)
ibanuri += 1
return schimbate, ibanuri
def anonimizeaza_fisier(sursa, tinta, coresp=None):
"""Scrie in `tinta` o copie anonimizata a lui `sursa`, cu aceleasi reguli.
Tabela implicita e cea comisa (CORESP); nu o regenereaza, doar o citeste.
"""
if coresp is None:
coresp = citeste_corespondenta()
wb = openpyxl.load_workbook(sursa)
schimbate, ibanuri = anonimizeaza_foaie(wb.active, coresp)
wb.save(tinta)
return schimbate, ibanuri
def anonimizeaza():
GOLDEN.mkdir(parents=True, exist_ok=True)
coresp = {"nume": {}, "cod_fiscal": {}, "iban": {}}
@@ -61,44 +124,7 @@ def anonimizeaza():
shutil.copy(cale, GOLDEN / tinta)
wb = openpyxl.load_workbook(GOLDEN / tinta)
ws = wb.active
schimbate = 0
for rand in range(2, ws.max_row + 1):
if (ws.cell(rand, COL_TIP).value or "").strip().upper() != "FACTURA":
continue
schimbate += 1
nume = ws.cell(rand, COL_NUME).value
if nume:
if nume not in coresp["nume"]:
coresp["nume"][nume] = "PARTENER %03d" % (len(coresp["nume"]) + 1)
ws.cell(rand, COL_NUME).value = coresp["nume"][nume]
cf = ws.cell(rand, COL_COD_FISCAL).value
if cf:
cf = str(cf)
if cf not in coresp["cod_fiscal"]:
coresp["cod_fiscal"][cf] = "CF%06d" % (len(coresp["cod_fiscal"]) + 1)
ws.cell(rand, COL_COD_FISCAL).value = coresp["cod_fiscal"][cf]
for col in (COL_REG_COM, COL_ADRESA, COL_EXPLICATIA):
if ws.cell(rand, col).value:
ws.cell(rand, col).value = None
# IBAN-urile apar si in afara randurilor FACTURA (denumirea analiticului de banca)
ibanuri = 0
for rand in ws.iter_rows():
for celula in rand:
if not isinstance(celula.value, str) or not IBAN.search(celula.value):
continue
def fals(m, _c=coresp):
real = m.group(0)
if real not in _c["iban"]:
_c["iban"][real] = "RO00 IBAN %04d" % (len(_c["iban"]) + 1)
return _c["iban"][real]
celula.value = IBAN.sub(fals, celula.value)
ibanuri += 1
schimbate, ibanuri = anonimizeaza_foaie(ws, coresp)
wb.save(GOLDEN / tinta)
raport.append((tinta, ws.max_row - 1, schimbate, ibanuri))