Files
roacont/docs/design-alegere-partener-anaf.md
Marius Mutu 5b0a3321db Verificare ANAF la alegerea partenerului: opt-in pe introducerea de documente
Cablarea din ROACONT pentru verificarea ANAF implementata in COMUN (ocautare.prg):

- ointroduceri_cont.vc2: 6 apeluri de cautare partener trec lVerificaANAF=1
  (frm_introd_compact, frm_introd_compact2007, frm_note, frm_note2007), plus
  frm_plati_impozite prin caut_parteneri. Raman fara verificare cautarile de
  responsabili, achizitor, casa si creditor.
- cont2000.mn2: punct de meniu Initializari > Optiuni utilizator >
  "Verificare ANAF la alegerea partenerului" (DO ANAF_ComutaVerificare IN ocautare.prg).
- roacont.prg: incarcarea procedurilor necesare verificarii.
- oproceduri_import.prg: la importul cu cod fiscal discordant se cere confirmare
  in loc sa se aleaga tacit.
- changelog 2.11.65 si documentul de design al functionalitatii.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019H3r66sVojGhgaKq5niu1u
2026-07-27 01:29:20 +03:00

49 KiB

Design: Asistenta alegere partener corect la introducere (verificare ANAF automata)

Generat de /office-hours pe 24.07.2026 Branch: main (implementarea va merge pe claude/) Repo: romfast/roacont (mirror git al SVN ^/ROACONT/Trunk) Status: APPROVED (24.07.2026, D7) Mode: Startup (intraprenoriat — produs intern ROA)

Problema

La introducerea facturilor de achizitie/vanzare (si la incasari/plati) utilizatorul alege partenerul dintr-un dialog de cautare. Cand un partener isi schimba calitatea de platitor TVA, conventia ROA cere ALT partener (alt nom_parteneri.id_par) cu acelasi nume si cod fiscal cu/fara RO; cel vechi se marcheaza de regula INACTIV. Probleme concrete:

  1. Utilizatorul nu are nicio informatie, la selectie, despre situatia ANAF curenta a partenerului (platitor TVA sau nu, activ/radiat) — statutul se poate schimba oricand, chiar daca partenerul nu are inca o "pereche".
  2. Perechea inactiva e complet invizibila (filtru hardcodat STERS=0 AND INACTIV=0), deci la o noua schimbare de calitate utilizatorul creeaza al TREILEA duplicat in loc sa reactiveze partenerul vechi.
  3. Alegerea gresita din pereche rupe imperecherea plati/incasari cu facturi (aceeasi cheie id_part), producand solduri fantoma pe doi parteneri.
  4. Importurile (eFactura, extrase) compara codul fiscal doar cu UPPER+ALLTRIM, deci RO12345 si 12345 sunt terti diferiti — fabrica de duplicate noi.

Evidenta cererii

  • Situatie recurenta la clientii ROACONT: parteneri care comuta calitatea de platitor TVA de mai multe ori; utilizatori care aleg din greseala membrul gresit al perechii; corectii manuale costisitoare la imperecherea plati-facturi.
  • Butonul de verificare ANAF exista deja in nomenclator si e folosit — dar e in alt flux decat introducerea, unde se ia de fapt decizia.

Status quo (fluxul actual, mapat in cod)

  • Nucleu selectie: CautPartenerContabilitate()COMUN\programe\ocautare.prg:56 (SELECT ID_PART, DENUMIRE, COD_FISCAL din NOM_PARTENERI, filtru inactivi :117-121), varianta casa/banca caut_parteneri() :161 (param tlInactiv :175-177), selectie multipla caut_parteneri_xml() :199.
  • Dialog: cauta_alfa_form(_plus)COMUN\clase\cauta_alfa_forms.vc2 (do_cauta, do_alege, do_adauga/buton Nou).
  • Puncte de apel: note contabile/facturi (Clase\ointroduceri_cont.vc2, verific_partener :1542/:4769 → do_cauta_partener :921/:3848), casa/banca (COMUN\clase\ocasabanca.vc2:1788,1823), stornare (Ferestre\frm_stornare_plinc.sc2:368), importuri (frm_import_extrase_banca.sc2, frm_import_note_a4200.sc2, oproceduri_import.prg:364/:746).
  • Verificare ANAF existenta: clasa VerificareANAF cu ANAF_SincronWebService_PlatitorTvaCOMUN\programe\validare.prg:1552,1603 (endpoint v9 PlatitorTvaRest, loturi max 100 CUI, pauza 1s; intoarce scpTVA, statusInactivi, statusTvaIncasare, denumire/adresa); buton but_verifica (COMUN\clase\cmd_butoane.vc2:427) doar pe nomenclator/formular verificare.
  • Statutul TVA NU e stocat pe partener: se deduce din prefixul RO al COD_FISCAL (ex. saft_d406.prg:1066). Rezultatele verificarii merg doar in istoric (pack_parteneri.save_istoric_cod_fiscal, validare.prg:757).

Utilizator tinta si pana cea mai ingusta

Operatorul de contabilitate care introduce zilnic facturi si incasari/plati. Pana cea mai ingusta: in momentul alegerii partenerului, sa i se spuna automat "ANAF zice altceva decat codul fiscal al partenerului ales" si sa i se ofere perechea corecta (inclusiv cea inactiva) sau crearea unui partener nou.

Constrangeri

  • 80/20: modificari minime cu efect maxim; fara refactorizari; fara schimbare de schema Oracle (fara coloana "platitor TVA" pe nom_parteneri).
  • VFP9 legacy, fara teste automate; comentarii in cod max o linie *!*.
  • Conventia ROA ramane: partener nou la schimbare de calitate TVA; regula se documenteaza (nu era scrisa nicaieri pana la acest document).
  • Fara commit (git/SVN) fara review pe diff in docs/.

Premise agreate

  1. Modelul de date ramane neschimbat; statutul TVA se deduce din prefixul RO.
  2. (revizuita) Durerea are DOUA surse: lipsa de vizibilitate la selectie SI duplicatele nascute la import din compararea nenormalizata a codului fiscal.
  3. Punctul de interventie cu efect maxim e nucleul de selectie din ocautare.prg (+ dialogul cauta_alfa_form), mostenit de toate punctele de apel.
  4. (decizie utilizator, D5) Verificarea ANAF se face AUTOMAT la fiecare alegere de partener, nu doar cand exista pereche — statutul se poate schimba intre timp.

Perspectiva cross-model (subagent independent)

  • Steelman: dialogul de selectie devine "ghid de decizie" — o singura interventie in nucleu, mostenita de toate formularele, fara schimbare de model de date.
  • Insight-cheie: criteriul de "partener corect" nu e doar ANAF, ci SI "pe ce id_part sunt documentele existente" → fereastra de decizie afiseaza data ultimului document per membru al perechii.
  • Premisa contestata (acceptata): duplicatele se nasc si la import → fixul de potrivire normalizata intra in pachet.
  • Idee laterala retinuta ca transa viitoare: raport pasiv de discordante "prefix RO vs ultimul istoric ANAF" peste datele deja colectate.

Abordari considerate

A: Doar buton manual "Verificare ANAF" in dialogul de selectie

Refolosire but_verifica; zero latenta automata. Respinsa ca insuficienta: protectia depinde de disciplina utilizatorului.

B (ALEASA): Verificare ANAF automata la alegere + fereastra de decizie + fix import

Detalii mai jos. Completeness 9/10 pe durerea descrisa.

C: B + raport pasiv discordante ANAF din istoric

Amanata ca transa separata (depinde de cat de des ruleaza clientii verificarea in lot; decuplata de hot path — se poate adauga oricand).

Abordarea recomandata (aprobata: B)

Interventie intr-un singur punct comun + doua completari mici:

  1. Functie noua VerificaPartenerLaSelectie(toPartener) in COMUN\programe\ocautare.prg, apelata din CautPartenerContabilitate() inainte de blocul ADAUGA_CORESP_TIP_PART (ocautare.prg:148-150) — daca utilizatorul comuta pe pereche, corespondentele tip-partener se adauga pe id_part-ul FINAL, nu pe cel initial. Acopera note/facturi, stornare, importuri fara sa atinga cele ~10 puncte de apel.
    • Contract: functia primeste si poate REESCRIE obiectul de retur (id_part, nume/denumire, cod_fiscal, tip); daca loCauta e NULL/gol (utilizatorul a renuntat la cautare), verificarea se sare complet.
    • Politica de activare (decizie eng review D1, apelanti triati in cod): hibrid explicit. CautPartenerContabilitate: hook ON implicit (apelantii sunt fluxuri de introducere), cu opt-out DOAR la orap_terti.prg:1019 (raport). caut_parteneri: hook OFF implicit, activat EXPLICIT (parametru nou tlVerificaANAF) la cele 4 puncte de introducere: ocasabanca.vc2 (:1823), frm_import_extrase_banca.sc2 (:2211, :2616), ointroduceri_cont.vc2 (:9665, :9704). Fluxurile de consultare (fisa cont fisa_cont_noua.sc2:459, orap_trezorerie.prg:31/:229, orap_terti.prg:826/:1794/:1986) raman NEATINSE, fara nicio modificare.
    • Apel ANAF pentru CUI-ul partenerului ales: wrapper nou single-CUI peste VerificareANAF (functia de lot ANAF_SincronWebService_PlatitorTva e construita pentru loturi de 100 cu logging intens — nu se cheama direct in hot path); timeout-ul se seteaza pe obiectul WinHTTP cu SetTimeouts.
    • Cache pe sesiune — proprietate pe un obiect global existent (ex. goApp) sau colectie publica declarata in roacont.prg, cheie = CUI normalizat (fara RO), valoare = rezultat+timestamp; se goleste la schimbarea firmei. Un CUI verificat o data pe sesiune nu mai genereaza apel — limiteaza si presiunea pe serviciul ANAF (mai multi operatori simultan raman fiecare cu 1 apel/CUI/sesiune).
    • Degradare tacuta: fara internet / ANAF cazut / timeout ⇒ comportament identic cu azi (fara mesaje de eroare in hot path).
    • Guard obligatoriu de mediu partajat: ocautare.prg e inclus si de alte produse ROA — hook-ul verifica intai existenta clasei (TYPE("goApp")/ALINES+SET("PROCEDURE") sau try CREATEOBJECT cu fallback) si degradeaza tacut daca validare.prg/VerificareANAF nu sunt incarcate in acel produs. Fara guard, orice selectie de partener din produsele-frate ar crapa la runtime.
    • Excluderi: persoane fizice (TIP_PERSOANA=2 / CNP 13 cifre), coduri nenumerice dupa eliminarea RO, parteneri externi (COD_TARA<>RO).
  2. La discordanta (ANAF scpTVA ≠ prefixul RO al partenerului ales, sau statusInactivi = inactiv/radiat) — fereastra compacta de decizie (forma noua mica in COMUN\ferestre\, pe stilul dialogurilor existente; nu AMESSAGEBOX — are grid cu membrii perechii si 3-4 butoane):
    • Cauta perechea dupa CUI normalizat (fara RO), INCLUSIV INACTIV=1 (interogare Oracle ieftina; filtrul gridului principal NU se schimba).
    • Afiseaza toti membrii: ID, denumire, cod fiscal, activ/inactiv, data ultimului document per id_part (MAX peste jurnal cumparari, jurnal vanzari si casa/banca — lista exacta a tabelelor se confirma la implementare; atentie la lipsa indexului pe id_part pe baze mari — se ruleaza DOAR in fereastra de discordanta, nu in hot path).
    • Actiuni: (a) alege perechea concordanta cu ANAF; (b) swap ghidat cu confirmare: reactiveaza perechea + inactiveaza partenerul curent (evita al treilea duplicat); dupa swap se face refresh pe cursorul de selectie (cel vechi dispare, cel reactivat apare); (c) fara pereche: propune buton "Nou" cu CUI-ul corect precompletat; (d) continua oricum (utilizatorul decide, nimic blocant).
    • Guvernarea swap-ului (decizie CEO review D2): swap-ul se executa prin calea EXISTENTA de modificare nomenclator (nom_parteneri_modifica / pachetul Oracle aferent), NU prin UPDATE ad-hoc in ocautare.prg — o singura cale de scriere in nom_parteneri. Gating cu dreptul EXISTENT de modificare nomenclator parteneri (verifica_drepturi): fara drept, butonul de swap e dezactivat cu tooltip explicativ, dar perechea poate fi in continuare ALEASA.
    • Kill-switch (decizie CEO review D4): optiune noua in settings.ini, sectiunea [anaf], verificare_selectie=1 implicit (citita cu getini). Cu 0, verificarea automata la selectie e oprita complet (comportament identic cu azi) — rollback chirurgical per statie/client fara downgrade de exe.
    • Concordanta ⇒ nicio fereastra, flux identic cu azi.
  3. Fix import (Programe\oproceduri_import.prg, potrivirea GetPartenerByCodFiscal :449 / dedup :4479-4495, citare verificata): cand potrivirea exacta esueaza, se incearca potrivirea pe CUI normalizat (fara RO); la gasire NU se alege automat — se cere confirmare ("exista partener cu acelasi CUI fara/cu RO — folosesti acela sau creezi unul nou?"). Pe loturi (zip eFactura): confirmarile NU se pun una cate una in mijlocul importului — discordantele se colecteaza si se prezinta o singura data, la final, intr-o lista cu optiune per rand + "aplica la toate". Opreste fabrica de duplicate fara sa blocheze importul.
  4. Optional (redundant partial cu verificarea automata — se taie daca diff-ul creste): buton but_verifica si in cauta_alfa_form, pentru verificare manuala INAINTE de alegere.

Ce NU facem (explicit)

  • Nu adaugam coloana TVA / data verificare pe nom_parteneri.
  • Nu facem merge/reasignare de documente intre id_part-uri.
  • Nu schimbam filtrul STERS=0 AND INACTIV=0 al gridului de selectie.
  • Nu blocam alegerea: toate avertismentele sunt informative, cu "continua oricum".

Intrebari deschise

  1. Drepturile swap — REZOLVAT (CEO review D2): dreptul existent de modificare nomenclator parteneri; executie prin calea existenta de modificare, nu UPDATE ad-hoc.
  2. TTL cache: pe sesiune (propus) sau pe zi (persistat)? Propunerea: sesiune.
  3. caut_parteneri_xml (selectie multipla) intra in scope sau ramane pe fluxul vechi? Propunerea: ramane pe fluxul vechi (volum mare de CUI-uri per apel).
  4. Latenta reala ANAF in orele de varf — de masurat inainte de a decide timeout-ul.
  5. Sursa tip la comutare — REZOLVAT (eng review D2): la comutarea pe pereche, tip se recalculeaza pentru id-ul perechii cu acelasi criteriu ca in SELECT-ul gridului (apartenenta la coresp_tip_part pentru tipurile contului); hook-ul fiind inainte de blocul ocautare.prg:148-150, blocul existent adauga natural corespondenta lipsa pe id-ul FINAL. Nota de implementare: wrapper-ul single-CUI sta in validare.prg, langa clasa VerificareANAF (coeziune).

Criterii de succes

  • La alegerea unui partener discordant cu ANAF, utilizatorul vede fereastra de decizie intr-un timp acceptabil (tinta orientativa <3s; pragul final se fixeaza dupa masuratorile de latenta din Tema) si poate ajunge la perechea inactiva fara sa iasa din fluxul de introducere.
  • Zero regresie de viteza cand ANAF nu raspunde (degradare tacuta).
  • Importul eFactura nu mai creeaza partener nou fara confirmare cand exista pereche pe CUI normalizat.
  • Niciun duplicat nou "al treilea" la clientii-pilot dupa o luna de folosire.

Plan de distributie

Livrare in roacont.exe prin fluxul existent: build din VFP IDE (roacont.PJX), revizie in pj2, intrare in changelog_roacont.txt (tag :nou:), commit SVN de catre Marius dupa aprobarea diff-ului. Nu necesita migrare Oracle (fara DDL).

Dependinte

  • Serviciul ANAF PlatitorTvaRest v9 (deja folosit in verificarea din nomenclator).
  • COMUN\programe\validare.prg si ocautare.prg sunt partajate cu alte produse ROA care le includ — de verificat la implementare cine mai apeleaza caut_parteneri/CautPartenerContabilitate din alte produse (blast radius COMUN vs COMUNROA).

Anexa: harta erorilor, edge-case-uri si teste (CEO review D3)

Harta erorilor (regula-cheie: verificarea esueaza TACUT, swap-ul esueaza ZGOMOTOS)

Cale Ce poate merge prost Actiune Utilizatorul vede
Apel ANAF (wrapper) timeout / DNS / HTTP 5xx / 429 degradare tacuta + UN log pe sesiune (nu per apel) nimic (flux ca azi)
Raspuns ANAF JSON malformat / CUI negasit / refuz tratat ca "fara informatie" → degradare tacuta nimic
Query pereche Oracle eroare goExecutor degradare tacuta + log nimic
MAX(data doc) per id_part lent / eroare fereastra se deschide FARA coloana "ultim doc" fereastra fara acea coloana
Swap (via nom_parteneri_modifica) eroare Oracle / lock / drept lipsa mesaj de EROARE vizibil; partenerul ramane neschimbat AMESSAGEBOX cu cauza
Anulare fereastra (ESC/inchidere) selectia ORIGINALA ramane valabila revine in formular cu partenerul ales initial
Dublu-click / reintrare apel dublu in curs guard de reintrare (flag "verificare in curs") un singur apel, o singura fereastra

Ordinea operatiilor (performanta)

  1. Alege partener → 2. cache lookup CUI → 3. apel ANAF (doar daca nu e in cache) → 4. concordant ⇒ STOP (zero query suplimentar pe selectiile normale) → 5. DOAR la discordanta: query pereche pe CUI normalizat (inclusiv inactivi)
  • MAX(data doc) per membru → 6. fereastra de decizie.

Reguli de implementare

  • NormalizeazaCUI() — functie UNICA in COMUN (strip RO doar daca restul e numeric, UPPER, fara spatii), folosita de wrapper, de query-ul de pereche si de fixul de import. Fara logica duplicata in 3 locuri.
  • Indicator vizual: wait cursor + text scurt "Verificare ANAF..." pe durata apelului (hot path-ul devine perceptibil doar cand chiar se apeleaza ANAF).
  • Logging: fiecare discordanta gasita se logheaza in goLog (CUI, id_part ales, ce a zis ANAF, ce a decis utilizatorul) — diagnosticabil ulterior.
  • Kill-switch: settings.ini [anaf] verificare_selectie=0 dezactiveaza complet hook-ul (verificat la intrare in functie, inainte de orice).

Lista de teste (manual / harness headless — test_init_env_auto)

  1. Partener concordant (RO + ANAF platitor) → niciun mesaj, flux identic.
  2. Discordant cu pereche ACTIVA → fereastra, alegerea perechii scrie id-ul corect.
  3. Discordant cu pereche INACTIVA → fereastra o arata; swap reactiveaza/inactiveaza
    • refresh cursor; fara drept de nomenclator → buton dezactivat, alegerea merge.
  4. Discordant FARA pereche → propunere "Nou" cu CUI precompletat.
  5. Fara internet / ANAF cazut → zero mesaje, flux identic cu azi, un log.
  6. Persoana fizica (CNP) / partener extern (COD_TARA<>RO) / CUI gol → skip total.
  7. Import lot eFactura cu discordante → confirmarile apar O DATA la final, "aplica la toate" functioneaza, niciun partener creat fara confirmare.
  8. Dublu-click rapid pe rand → un singur apel ANAF, o singura fereastra.
  9. Kill-switch 0 → comportament identic cu versiunea anterioara.
  10. Cache: al doilea document pe acelasi partener in aceeasi sesiune → zero apel ANAF nou.
  11. REGRESIE (eng review D1): fisa de cont si rapoartele terti/trezorerie NU declanseaza verificarea ANAF — comportament identic cu versiunea anterioara.

Specificatia vizuala a ferestrei de decizie (design review D2-D3)

+--- Verificare partener ANAF ------------------------------------+
| ANAF: NEPLATITOR TVA (din 01.03.2026). Partenerul ales are      |
| codul fiscal RO12345678 — nu corespunde.                        |  <- verdictul, PRIMUL
+------------------------------------------------------------------+
| ID    | Denumire       | Cod fiscal  | Stare    | Ultim document |
| 1234  | FIRMA SRL      | RO12345678  | Activ    | 15.06.2026     |  <- alegerea initiala
|>5678  | FIRMA SRL      | 12345678    | INACTIV  | 20.02.2026     |  <- PERECHEA, preselectata
+------------------------------------------------------------------+
| [Alege selectat]  [Reactiveaza+inactiveaza]  [Nou]  [Continua]  |
+------------------------------------------------------------------+
  • Ierarhie: 1) verdictul intr-o propozitie (status ANAF + data + de ce nu corespunde), 2) gridul cu toti membrii, randul CONCORDANT cu ANAF preselectat, 3) butoanele. Ton utilitar, fara alarmism — o singura decizie pe ecran.
  • Tastatura (decizie D2): Enter = alege randul selectat (preselectat: perechea concordanta); sageti = schimba selectia; ESC = pastreaza alegerea originala (inchide fara nicio actiune); swap DOAR pe butonul dedicat, cu confirmare suplimentara — niciodata pe Enter. Hotkey-uri pe butoane (VFP <).
  • Conventii existente refolosite: randul INACTIV colorat gri RGB(225,225,225) + tooltip — aceeasi conventie pe care utilizatorii o stiu din cauta_alfa_form ("partenerii de alt tip sunt colorati gri", ocautare.prg:136-137); butoane din cmd_butoane.vcx; erori prin AMESSAGEBOX; fereastra pe clasele de baza cont2000 (stil identic cu dialogurile existente).
  • Starea "fara pereche": fereastra FARA grid — doar verdictul + butoanele [Nou (CUI precompletat)] si [Continua]; Enter = Continua (aici NU exista alternativa corecta de preselectat, deci implicitul ramane conservator).
  • Butonul de swap fara drept de nomenclator: dezactivat (nu ascuns), cu tooltip "Necesita drept de modificare nomenclator parteneri".
  • Indicator in dialogul de selectie: pe durata apelului ANAF — wait cursor
    • WAIT WINDOW "Verificare ANAF..." NOWAIT, sters imediat dupa raspuns; vizibil doar cand apelul chiar are loc (cache miss).

Regula de lucru documentata (nota ceruta — nu era scrisa nicaieri)

Conventie ROA — schimbarea calitatii de platitor TVA a unui partener:

  1. NU se modifica codul fiscal al partenerului existent (istoricul documentelor ramane legat de id_part-ul vechi si de statutul TVA de la acea data).
  2. Se foloseste ALT partener cu acelasi nume si codul fiscal cu/fara RO dupa noua calitate. Daca perechea EXISTA deja (chiar inactiva), se REACTIVEAZA aceea — nu se creeaza al treilea duplicat.
  3. De regula, membrul care nu mai corespunde se marcheaza INACTIV ca sa nu mai apara la introducere. Daca ambii raman activi (situatii tranzitorii), utilizatorul alege dupa situatia ANAF si dupa documentul introdus.
  4. La incasari/plati se alege ACELASI id_part ca pe facturile pe care le stinge — altfel imperecherea plati-facturi se rupe.

(La implementare, acest text se muta/copiaza si in COMUN\docs\ daca vrem sa fie vizibil si celorlalte produse ROA.)

Tema (assignment)

Inainte de implementare, ruleaza pe o baza reala de client doua masuratori:

  1. SELECT de numarare: cate grupuri de CUI normalizat (fara RO) au >1 partener si cati dintre ei au membri inactivi — dimensioneaza problema reala.
  2. 10 apeluri ANAF PlatitorTvaRest la ore diferite — masoara latenta reala pentru alegerea timeout-ului. Rezultatele decid timeout-ul si daca fereastra de decizie are nevoie de pre-incarcare asincrona.

Ce am observat la felul in care gandesti

  • Ai respins ambele extreme si ai corectat exact pe mecanism: "chiar daca nu exista o pereche, tot trebuie facuta verificarea automata pe ANAF, pentru ca intre timp partenerul isi poate fi schimbat calitatea" — ai vazut ca riscul e in timp, nu in structura datelor.
  • Ai adus singur cazul-limita care omoara solutiile naive: "partenerul anterior este marcat inactiv... si exista situatii in care isi schimba calitatea de mai multe ori" — perechea invizibila din cauza filtrului INACTIV=0.
  • "80/20 minim de modificari cu maxim de efecte" — ai cerut explicit constrangerea de cost inainte de solutii, nu dupa.

GSTACK REVIEW REPORT

Review Trigger Why Runs Status Findings
CEO Review /plan-ceo-review Scope & strategy 1 CLEAR mode: HOLD_SCOPE, 3 constatari decise (swap guvernat, anexa spec, kill-switch), 0 critical gaps
Codex Review /codex review Independent 2nd opinion 0 sarit (2 verificari independente rulate azi la office-hours)
Eng Review /plan-eng-review Architecture & tests (required) 1 CLEAR 2 issues (politica hook hibrid D1, recalc tip D2), 13/13 cai cu test, 0 critical gaps
Design Review /plan-design-review UI/UX gaps 1 CLEAR score: 5/10 → 9/10, 3 decizii (focus, Enter=perechea, spec vizuala)
DX Review /plan-devex-review Developer experience gaps 0 n/a (nu e produs developer-facing)
  • UNRESOLVED: 0 — toate deciziile CEO (D1-D6), eng (D1-D2) si design (D1-D3) au raspuns.
  • VERDICT: CEO + ENG + DESIGN CLEARED — planul e complet, gata de implementare pe branch claude/partener-anaf.

REVIZIA 2 (25.07.2026) — V2': verdict ANAF in formularul de cautare

Status: APPROVED (25.07.2026, feedback live Marius + D1a/D2 confirmate). Aceasta revizie INLOCUIESTE sectiunile "fereastra de decizie" si "Specificatia vizuala a ferestrei de decizie" din designul initial. Restul (hook, wrapper single-CUI, NormalizeazaCUI, cache, kill-switch, excluderi, degradare tacuta, fix import, politica de activare pe apelanti) RAMANE VALABIL.

Motivatia (test live 25.07, ROMFAST 1879855)

Fereastra de decizie implementata in rundele 1-8 s-a dovedit confuza in uz real:

  1. Utilizatorul nu intelege de ce a aparut fereastra; mesajul de sus e insuficient (fara numele partenerului, fara ce inseamna verdictul, fara ce are de facut).
  2. Gridul arata TOT grupul de CUI, inclusiv membrii cu aceeasi problema — nu ghideaza.
  3. Butonul Inactiveaza/Activeaza cere o operatiune de nomenclator ambigua (pe care rand? in pereche cu cine?) in mijlocul fluxului de introducere.
  4. Verificarea ANAF e invizibila cand totul corespunde (WAIT WINDOW NOWAIT dispare la orice miscare de mouse) — utilizatorul nu stie ca protectia exista.
  5. Butonul "Nou" din fereastra dubleaza butonul Nou al cautarii.

Solutia revizuita

1. Label ANAF in cauta_alfa_form (COMUN\clase\cauta_alfa_forms.vc2) — verdictul pentru RANDUL CURENT din grid, vizibil INAINTE de alegere:

+--- Cautare partener --------------------------------------------+
| Cautare: ROMFAST_                                         [Nou] |
| | Denumire               | Cod fiscal | ...                    ||
| |>ROMFAST CONSTANTA SRL  | 1879855    |                        ||
| ANAF: PLATITOR TVA — codul 1879855 (fara RO) NU corespunde.     |  <- label
+------------------------------------------------------------------+

Starile labelului (texte finale, spec Marius 25.07):

  • gol — persoana fizica / partener extern / CUI nenumeric / kill-switch 0 / eroare-timeout ANAF (degradare tacuta);
  • "Verificare ANAF..." — pe durata apelului (persistent, nu WAIT WINDOW);
  • concordant (VERDE): "ANAF: Platitor TVA (RO1879855 FAGA SRL)" — cod fiscal + denumirea ANAF;
  • discordant (ROSU, bold): "(!) ANAF: Platitor TVA (1879855 ROMFAST CONSTANTA SRL) » detalii" — marcaj (!) si sageata » (chr 187, cp1252) care indica apasarea pentru detalii; cursor mana pe label (clickabil).

Declansare: AfterRowColChange reporneste un timer debounce (~400ms); apelul se face doar daca utilizatorul ramane pe rand (cache per CUI pe sesiune → un singur apel real per partener). Navigarea rapida nu declanseaza nimic.

Blast radius: label + timer + proprietate de activare intra in clasa comuna, dar INERTE implicit (proprietate .F.); se activeaza doar din cautarile de parteneri cu verificare ANAF (tlVerificaANAF / CautPartenerContabilitate), cu guard-urile existente pentru produsele-frate. Celelalte nomenclatoare nu vad nicio diferenta.

2. Dublu-click pe label → AMESSAGEBOX cu detaliile complete: nume + cod ales, verdict ANAF, codul fiscal corect, perechea existenta (cautata pe CUI normalizat, INCLUSIV inactiva) sau indrumarea catre butonul Nou al cautarii daca nu exista.

3. La alegerea unui partener discordant (D1a) — plasa de siguranta: apare automat dialogul de decizie (formularul de cautare ramane deschis). Format final (spec Marius, 25.07) — lista numerotata + butoane care spun exact ce aleg:

1. ROMFAST CONSTANTA SRL (CUI: 1879855, ID: 108)  ANAF: PLATITOR TVA
2. FAGA SRL (CUI: RO1879855, ID: 200140)  inactiv

  [Alege FAGA SRL]   [Alege ROMFAST CONSTANTA SRL]   [Renunta]
  • Butonul perechii alege perechea; butonul alesului pastreaza alegerea; Renunta (si ESC) = ramai in cautare. Fara linie de mapare Da/Nu.
  • Fara pereche: randul 1 + "Nu exista partener cu CUI RO1879855 (il puteti crea cu butonul Nou)." — butoane [Continua] [Renunta].
  • Mai multi candidati: lista numerotata a candidatilor + "Alegeti manual." — buton unic, ramai in cautare.
  • Implementare: AMESSAGEBOX nu suporta etichete custom pe butoane — dialogul e o clasa mica DEFINE CLASS ... AS Form definita IN COD in ocautare.prg (fara .scx, fara binar), 2-3 butoane cu Caption dinamic (denumiri trunchiate rezonabil). Detaliile de la dublu-click pe label folosesc acelasi format numerotat, pur informativ.

FARA activare/reactivare (decizie Marius, 25.07): alegerea unei perechi inactive doar FOLOSESTE acel id_part pe document — partenerul ramane inactiv, "inactiv" apare pur informativ. Motivatie: pe incasari/plati utilizatorul vrea partenerul cu facturile/soldul, indiferent de TVA; nu toti utilizatorii au drepturi de modificare nomenclator; orice operatiune de nomenclator in fluxul de introducere incurca. Activarea/inactivarea raman exclusiv operatiuni manuale in nomenclatorul de parteneri.

4. Alegere rapida (D2): daca utilizatorul alege inainte ca timerul sa fi verificat randul, verificarea se face PE LOC la selectie (alegerile rapide nu ocolesc protectia).

Ce se ELIMINA din implementarea rundelor 1-8

  • COMUN\ferestre\frm_verif_partener_anaf (.sc2/.scx/.sct) — fereastra dispare.
  • But_swap / ActualizeazaCaptionSwap / apelul PACK_PARTENERI.MODIFICA_INACTIV.
  • Migrarea ff_2026_07_24_01_COMUN_PACK_PARTENERI.sql — NU se mai ruleaza pe productie; versiune_db.txt revine la valoarea anterioara. (Procedura ramane aplicata pe schema de test — inofensiva, se poate drop-ui separat.)
  • Deschiderea ferestrei din hook (Do Form ... frm_verif_partener_anaf).

Ce se PASTREAZA neschimbat

NormalizeazaCUI, wrapper single-CUI ANAF_VerificaCuiSingle, cache-ul pe sesiune + golirea la schimbarea firmei, kill-switch [anaf] verificare_selectie, excluderile (PF/extern/nenumeric), degradarea tacuta, fixul de import (oproceduri_import.prg), politica de activare pe apelanti (tlVerificaANAF, opt-out orap_terti), regula de lucru documentata, harta erorilor (mai putin randul de swap — eliminat).

Teste afectate

Suita COMUN\utile\Teste\partener_anaf\ se rescrie pe noul flux: label (stari, debounce, dublu-click), D1a (cele 3 butoane), D2 (alegere rapida), reactivare single-row, regresie nomenclatoare non-partener (label inert).


REVIZIA 3 (25.07.2026) — verdict la data documentului + texte finale

Status: APPROVED (25.07.2026, feedback live Marius pe screenshot-ul din productie). Aceasta revizie ajusteaza doar textele si adauga data documentului; restul REVIZIEI 2 ramane valabil.

1. Textul labelului

Denumirea si codul fiscal afisate sunt cele de la ANAF (nu cele ale randului ales), in ordinea NUME apoi COD, plus data la care s-a cerut starea:

  • concordant (verde): ANAF: Platitor TVA (ROMFAST SRL RO1879855) la 15.06.2026
  • discordant (rosu, bold): (!) ANAF: Platitor TVA (ROMFAST SRL RO1879855) la 15.06.2026 >> click detalii

Sageata » (Chr(187)) se inlocuieste cu >> ASCII (fara risc de encoding cp1252), iar textul devine click detalii. Marcajul (!) se pastreaza la discordanta.

2. Dialogurile (detalii la dublu-click + confirmarea la alegere)

Format aerisit, cu antet comun (metodele AntetDialog / ListaCorecti din anaf_verif_cautare):

ROMFAST CONSTANTA SRL  (CUI: 1879855, ID: 108)

! ANAF: Platitor TVA (ROMFAST SRL, RO1879855) la 15.06.2026

Parteneri ROA cu CUI RO1879855:
  1. ABSOLUT SRL (ID: 598)  inactiv
  2. ROMFAST S.R.L. (ID: 614)
  • lista contine DOAR partenerii cu codul fiscal corect (fara cel deja ales), ordonati alfabetic (ORDER BY UPPER(DENUMIRE) in ANAF_CautaPereche);
  • fara candidati: Nu exista partener cu CUI RO1879855 (il puteti crea cu butonul Nou).;
  • la alegere, ultimul rand ramane maparea butoanelor: Da = alege 1. <denumire> Nu = pastreaza selectia Abandon = inapoi la cautare.

3. Starea ANAF la data documentului

Serviciul PlatitorTvaRest v9 primea deja o data (era Date()); acum primeste data documentului, cand exista:

  • ANAF_VerificaCuiSingle(tcCui, tdData) si ANAF_StarePartener(tcCodFiscal, tdData); data goala/lipsa => data curenta (comportament identic cu inainte);
  • cheia de cache pe sesiune devine CUI + data (acelasi CUI la doua date = doua apeluri);
  • transport: cheia de hash dDataDoc pentru CautPartenerContabilitate, parametrul 7 tdDataDoc pentru caut_parteneri; proprietatea dDataDoc pe anaf_verif_cautare;
  • sursele datei in apelanti: poAct.dataact (introduceri note/facturi, ointroduceri_cont.vc2: do_cauta_partener x2, gridurile de partener din frm_note/frm_note2007, frm_plati_impozite) si poDate.dataact (facturare, ofacturare.vc2: do_cauta_client, do_cauta_furnizor); toate cu guard Type(...)='D'.

4. Casa/banca — verificare scoasa

Punctul activat in runda 1 (ocasabanca.vc2, Ck_bancasa.InteractiveChange) NU e introducere de document: e checkbox-ul de filtrare care alege casa/banca proprie (filtru = ' AND id_bancasa = ...'), fara data de document. Verificarea ANAF se dezactiveaza acolo (revenire la apelul fara tlVerificaANAF).

5. Comentarii in cod

Regula de lucru confirmata de Marius (25.07): fara comentarii in corpul codului; o singura linie scurta in antetul fisierului, fara autor "claude". Comentariile inline adaugate in rundele 1-11 pentru aceasta functionalitate se elimina.

6. Import din extras de cont — corectie de abordare (decizie Marius, 25.07)

La importul din extras e vorba de PLATI/INCASARI, nu de facturi: statutul ANAF (platitor/neplatitor) nu ajuta cu nimic acolo. Singurul criteriu care conteaza e "partenerul pe care stau facturile", pentru ca GetDocumentByContPartenerAct (COMUN\programe\oproceduri_comune.prg:6942) cauta documentul strict pe id_part (ireg_parteneri, an/luna curente), iar GetPartenerByCodFiscal (:6557) normalizeaza CUI-ul si ia orbeste MAX(id_part) din grup.

Prin urmare:

  • verificarea ANAF se scoate din formularul de import extrase (cele doua pickere manuale de partener din configurari);
  • confirmarea pe loturi pentru discordantele de CUI (adaugata in runda 1) se ELIMINA — importul nu mai intreaba nimic;
  • cand exista mai multi parteneri cu acelasi CUI normalizat, alegerea se face dupa documente, nu dupa MAX(id_part):
    1. daca linia de extras are numar de document si optiunea "Asociaza facturi" e bifata, documentul se cauta pe TOTI membrii grupului, iar nota merge pe partenerul pe care s-a gasit factura (se muta si id_partd/id_partc);
    2. altfel, se alege membrul cu documente in perioada curenta (ireg_parteneri, numar de randuri, la egalitate soldul cel mai mare in modul);
    3. daca niciun membru nu are documente, ramane alegerea de azi.
  • la initializare facturi din balanta (CompleteazaParteneriROA) confirmarea per partener se elimina: se foloseste tacut partenerul existent cu acelasi CUI normalizat, iar cursorul de parteneri primeste coloana normalizata calculata o singura data (fara Locate cu apel de functie per partener).

REVIZIA 4 (26.07.2026) — verificare neintruziva la alegerea partenerului

Status: APROBATA CU MODIFICARI dupa review /autoplan (26.07.2026, 3 lentile: CEO / design / inginerie, Codex indisponibil pe masina). Aceasta revizie inlocuieste punctul 3 al REVIZIEI 2 ("La alegerea unui partener discordant") si punctul 2 al REVIZIEI 3 (maparea butoanelor la alegere).

Motivatia (Marius, 26.07): formularul de avertizare de la alegerea partenerului e intruziv si confuz, mai ales pe incasari/plati, unde partenerul NU e o alegere libera — e determinat de facturile de imperecheat, iar o propunere de schimbare a partenerului exact in acel punct sparge imperecherea (GetDocumentByContPartenerAct cauta documentul strict pe id_part).

Decizii de poarta (review /autoplan, 26.07)

# Decizie Continut
D1 / UC1 Marcajul colorat pe toate randurile NU intra in aceasta transa Implicit ramane nivelul 1 (verdict pe randul curent). Ghidarea o preia, in Detalii, semnul "are documente in perioada" pe fiecare candidat. Marcajul in grid devine transa separata, dupa masuratori (vezi "Transa viitoare")
UC2 Polaritate inversata CautPartenerContabilitate devine OFF implicit + opt-in explicit lVerificaANAF=>1 pe 8 apeluri. Simetric cu caut_parteneri
UC3 Detalii ramane AMESSAGEBOX Fara formular nou definit in cod. Optiunea per utilizator se comuta dintr-un punct de meniu, dupa modelul RC_REGCUMP_LISTARE_BUG

1. Ce se scoate din calea de alegere

VerificaAlegere (ocautare.prg:428) nu mai deschide nimic pe comportamentul implicit: cand nivelul de confirmare e 0 face Return .T. imediat, fara apel sincron la ANAF.

La nivelul 3 (opt-in) comportamentul ramane exact cel de azi: verificare sincrona

  • Amessagebox(...,3+48) cu lista numerotata + aInputBox pentru varianta. ATENTIE (eroare factuala corectata): clasa anaf_dialog nu exista — a fost eliminata la runda 11, iar confirmarea de azi e AMESSAGEBOX. Nicio parte a acestei revizii nu se sprijina pe ea.

Chiar cand nu se afiseaza nimic, alegerea unui partener discordant se logheaza in goLog (CUI, id_part ales, verdict) — e singura sursa de date despre frecventa reala a problemei, si conditia de intrare pentru transa viitoare.

2. Detalii (click pe label) — decizia, la cererea utilizatorului

Ramane AMESSAGEBOX, cu formatul din REVIZIA 3, plus doua schimbari:

  1. Discriminatorul pe documente langa fiecare candidat — criteriul care conteaza efectiv la imperechere, nu statutul TVA:
    ROMFAST CONSTANTA SRL  (CUI: 1879855, ID: 108)
    
    ! ANAF: Platitor TVA (ROMFAST SRL, RO1879855) la 15.06.2026
    
    Parteneri ROA cu CUI RO1879855:
      1. ABSOLUT SRL (ID: 598)  inactiv
      2. ROMFAST S.R.L. (ID: 614)  are documente in perioada
    
    Sursa: ireg_parteneri pe anul/luna curente, un singur SELECT, doar la deschiderea Detalii (niciodata in calea de navigare prin grid).
  2. Alegerea variantei se face de aici (butoanele AMESSAGEBOX + aInputBox cand sunt mai multi candidati), adica exact mecanismul existent, mutat de pe calea impusa pe calea ceruta de utilizator. Foloseste poANAFInlocuire + AplicaInlocuirePartenerANAF, cu guardul obligatoriu de la punctul 5 (C2).

Detalii se deschide si cand oStare e .Null. (ANAF picat, cod fiscal invalid): afiseaza antetul si o linie explicita ("ANAF nu a raspuns — verificarea a fost sarita"), nu returneaza mut ca azi (ocautare.prg:411).

Labelul devine clickabil pe ambele stari (verde si rosu) si primeste F4 ca echivalent de tastatura (utilizatorii lucreaza fara mouse); textul labelului spune F4 = detalii. Codul de tasta pentru F4 se confirma la implementare — ramura OTHERWISE din cauta_alfa_forms.vc2:715 nu intra in conflict cu redirectarea literelor catre caseta de cautare.

3. Cascada de optiuni — o singura scara

O singura optiune, RC_ANAF_VERIF_SELECTIE, cu valori cumulative:

Valoare Comportament
0 oprit (nicio verificare)
1 verdict pe randul curent (implicit)
2 rezervat pentru marcajul in grid (transa viitoare)
3 verdict + confirmare la alegerea unui partener discordant (opt-in)

Rezolvare, prima valoare gasita castiga:

  1. settings.ini [anaf] verificare_selectiedoar kill-switch pe valoarea 0, nu sursa de nivel (altfel bifa/optiunea utilizatorului devine silentios inoperanta si nimeni nu poate explica de ce);
  2. citeste_optiune_utilizator('RC_ANAF_VERIF_SELECTIE') — per utilizator;
  3. citeste_optiune('RC_ANAF_VERIF_SELECTIE') — per firma;
  4. hardcodat: 1.

Comutarea per utilizator: punct de meniu, dupa modelul RC_REGCUMP_LISTARE_BUG (citeste valoarea, arata starea, scrie noua valoare cu scrie_optiune_utilizator). Etichete fara ambiguitate: Arata starea ANAF in cautarea de partener / Intreaba la alegerea unui partener discordant.

Seed-ul per firma se amana: cascada cade oricum pe implicitul hardcodat, iar un INSERT in optiuni e citit de COMUN in toate produsele — nu e "discoverabilitate", e comutator suite-wide.

4. Politica de activare (inversata, UC2)

CautPartenerContabilitate (ocautare.prg:507) devine OFF implicit, cu opt-in explicit lVerificaANAF=>1. Motivul, verificat: exista ~68 de apelanti, dintre care lista de opt-out acoperea ~20, toti din ROACONT; ar fi ramas ON prin omisiune COMUN\clase\baza.vc2:10400 (clasa de baza UI, deci toate produsele), orapoarte_cont.vc2:3843 (filtru de raport), ofacturare.vc2:20946 ("Alegeti Banca"), :20957 ("casa in lei"), :19441 (Agenti), :7160/:7997/:9257 (Responsabili), :13793/:17826 (Partener rezervare), plus oinventar, omodificari, onomenclatoare, ferestre_cere_date, ooperatii_comune.prg. ROAGEST si ROAAUTO incarca validare.prg (roagest.prg:234, roaauto.prg:198), deci toate guardurile existente trec si la ele.

Lista ON (singurele locuri cu lVerificaANAF=>1):

  • Clase\ointroduceri_cont.vc2do_cauta_partener (x2, :921, :3850);
  • Clase\ointroduceri_cont.vc2 — gridurile de partener din frm_note (:7096, :7120) si frm_note2007 (:8943, :8984);
  • COMUN\clase\ofacturare.vc2do_cauta_client, do_cauta_furnizor.

Parametrul lNuVerificaANAF dispare. Consecinta de curatat: dupa inversare, niciun apelant nu mai trimite tlVerificaANAF la caut_parteneri — se decide explicit daca parametrii tlVerificaANAF/tdDataDoc si ramura ANAF din caut_parteneri (ocautare.prg:625) raman sau se scot ca ei cod mort.

5. Reguli obligatorii de implementare (constatari verificate in cod)

# Regula Ancoraj
C2 AplicaInlocuirePartenerANAF se apeleaza doar cand gnButon = 1; poANAFInlocuire se reseteaza la intrarea in Detalii si pe ramura de abandon. Altfel: utilizatorul alege varianta in Detalii, apoi anuleaza cautarea, iar Scatter ... Blank (cauta_alfa.prg:243) + guardul slab Type('toPartener.id_part')='N' fac ca apelantul sa primeasca totusi partenerul — pe incasari rupe imperecherea ocautare.prg:165, :609, :666
C3 do_termin pe formularul de cautare se apeleaza dupa ce AMESSAGEBOX-ul a returnat, niciodata din interiorul unui dialog modal copil (do_termin face this.Release) _frm_base.vc2:363-371
H2 Eroarea de SELECT din ANAF_CautaPereche nu mai are voie sa apara ca "Nu exista partener cu CUI ... (il puteti crea cu butonul Nou)" — asta indruma activ spre al treilea duplicat. ListaCorecti primeste un parametru de eroare; la eroare mesajul devine "Nu s-a putut citi lista de parteneri" si sugestia "Nou" dispare. Cursorul se inchide si pe ramura de eroare ocautare.prg:154-157, :389-405, :423, :455
H6 Cascada se citeste o singura data, la intrarea in CautPartenerContabilitate/caut_parteneri, cu lcSel = Select() / Select(m.lcSel) in jur. Niciodata din Activeaza, VerificaRand sau dintr-un handler de UI. citeste_optiune_utilizator nu restaureaza zona de lucru, iar scrie_optiune_utilizator da AMESSAGEBOX la eroare si face TABLEUPDATE in afara ramurii de succes oinit_optiuni.prg:731-740, :770-778
H7 Cascada testeaza !Empty(Alltrim(valoare)) pe fiecare nivel. Patternul existent Int(Val(Nvl(citeste_optiune_utilizator(...), '0'))) mapeaza absent -> 0 = OPRIT si ar opri verificarea la primul nivel gol Clase\ovanzcump.vc2 (pattern), oinit_optiuni.prg:730, :808
M9 Citirea getini iese de pe calea per-rand: azi ANAF_StarePartener o face la fiecare verificare, cu FOPEN/scan/FCLOSE pe DIRGEN\settings.ini, care e de regula pe share de retea. Kill-switch-ul se citeste odata cu cascada ocautare.prg:59, ini.prg:288, roacont.prg:441
M2 Se foloseste This.oForm.crs_cursor, nu _GRID1.RecordSource: SAVE_GRID goleste RecordSource pe toata durata repopularii, care include un round-trip Oracle oproceduri_comune.prg:1387, ocautare.prg:303, :414, :443
M5 Valorile de cascada cache-uite pe sesiune se invalideaza la schimbarea firmei sau a utilizatorului (ca si cache-ul ANAF)
A2 Guard suplimentar 'OINIT_OPTIUNI' $ Upper(Set('Procedure')) inainte de orice apel la cascada: ROACASA incarca ocautare fara oinit_optiuni ocautare.prg:63 (modelul existent)
B1 Bug in codul de azi: VerificaRand iese pe Reccount = 0 fara sa goleasca labelul, deci verdictul precedent ramane pe ecran atribuit unei liste goale ocautare.prg:304-306
B2 Spec vs implementare: SeteazaLabel forteaza FontBold = .F., desi REVIZIA 2/3 cere discordanta in rosu bold. Se aliniaza (bold la discordanta) ocautare.prg:353
B3 Anchor al labelului devine 14 (Left+Bottom+Right) — cu 6 textul se taie la redimensionare; labelul urca deasupra cmd_select (invizibil pe fluxul de partener), fara sa mai creasca inaltimea formei cauta_alfa_forms.vc2:47, :269-279, ocautare.prg:245-257
B4 Denumirea ANAF se trunchiaza la ~24 caractere in label (cea completa apare in Detalii): textul discordant la lungime maxima depaseste 2 randuri de Arial 10 in ~487x30px si se taie fara elipsa ocautare.prg:367
B5 SET STEP ON viu la validare.prg:1841 (preexistent, nu din aceasta lucrare) — in IDE deschide debuggerul. De scos validare.prg:1841

Wrapperul batch ANAF nu se scrie in aceasta transa: fara marcaj in grid nu are consumator (YAGNI).

6. Ce se pastreaza neschimbat

Textele si culorile labelului (REVIZIA 3 pt. 1, cu corectia B2), starea la data documentului (REVIZIA 3 pt. 3), dDataDoc/tdDataDoc, NormalizeazaCUI, ANAF_VerificaCuiSingle, cache-ul pe sesiune + golirea la schimbarea firmei, excluderile (PF/extern/nenumeric), degradarea tacuta, ANAF_CautaPereche, AplicaInlocuirePartenerANAF, fixul de import (REVIZIA 3 pt. 6), regula "fara comentarii in corpul codului" (REVIZIA 3 pt. 5), hook-ul generic din cauta_alfa.prg si cele 8 linii din cauta_alfa_forms.vc2.

7. Teste (toate fezabile in harnessul headless)

  1. Cascada: ini 0 bate tot; utilizator bate firma; firma bate hardcodatul; absent != 0 (H7); lipsa crsOptiuni/crsOptiuniUtilizator/goExecutor.
  2. Nivel 1 (implicit): label prezent; VerificaAlegere nu deschide nimic si nu face niciun apel HTTP la alegere (contorul de apeluri exista deja in suita).
  3. Nivel 0: poVerifAlegere neinstantiat, zero apeluri, label absent.
  4. Nivel 3: dialogul existent, cele 3 rezultate — testele actuale, rulate cu optiunea pe 3.
  5. C2 (testul cel mai important, lipsa azi): poANAFInlocuire setat + gnButon = 2 (Renunta) => obiectul returnat ramane blank, id_part = 0.
  6. H2: ANAF_CautaPereche esuat (mock pe goExecutor) => mesaj de eroare, fara sugestia "Nou".
  7. Detalii cu oStare .Null. => se deschide, cu linia explicativa.
  8. Discriminatorul "are documente in perioada" (mock pe goExecutor, cu si fara randuri).
  9. Bug-ul B1: cautare fara rezultate => labelul se goleste.
  10. Zona de lucru: Alias() identic inainte si dupa citirea/scrierea optiunilor (H6).
  11. Punctul de meniu scrie valoarea corecta si are efect imediat (M6: la trecerea pe 0 se opreste si timerul si se goleste labelul pe cautarea deschisa).
  12. Regresie: apelantii care NU au lVerificaANAF=>1 nu instantiaza poVerifAlegere.

8. Transa viitoare — marcaj in grid (nivelul 2), cu conditii de intrare

Nu se implementeaza pana nu exista, in aceasta ordine:

  1. Masuratori (Tema din planul initial, inca nefacuta): latenta reala a unui apel ANAF la ore diferite; comportamentul la rafale (30 loturi de 20 CUI la interval scurt — de la al catelea vine 429); numarul real de perechi de CUI duplicat la un client real.
  2. Date din loguri: cate discordante apar efectiv la pilot si in ce flux.

Cerinte tehnice de respectat atunci (toate verificate acum, ca sa nu se piarda):

# Cerinta
UC1 Criteriul de colorare corect pe trezorerie e "are documente in perioada" (SELECT local), nu statutul ANAF: pe o incasare, verdele dupa ANAF indruma spre partenerul fara facturi
D-F2 DynamicForeColor e invizibil pe randul selectat (_baza.vc2:200-201: highlight bleumarin cu text alb). Semnalul are nevoie de al doilea canal: DynamicFontBold, care supravietuieste highlight-ului. Verde+bold pentru randul confirmat, restul normal; rosul dispare de pe randuri (are 3 sensuri distincte: prefix gresit, radiat la ANAF, CIF invalid)
C4 Un singur anaf_timer cu doua consumatoare = nedeterminism: do_cauta face Go Top + SetFocus dupa actualizeaza_grid1, deci AfterRowColChange rearmeaza acelasi timer. Necesar: doua flag-uri (sau doua timere) + flag de suprimare lInBatch, GO pe Recno() salvat, colectarea CUI-urilor fara SELECT-SQL pe cursorul legat de grid
H1 CUI-urile din notfound sunt inserate ca randuri blank (scpTVA = .F., denumire goala) — fara filtru !Empty(denumire) orice partener cu prefix RO negasit la ANAF ar aparea marcat gresit
H4 Collection.GetKey e supraincarcat: cu argument numeric intoarce cheia de la index, nu indexul. Cheile se construiesc string: 'P' + Transform(id_part), si Item() doar dupa GetKey(...) <> 0
H5 Expresia Dynamic* se evalueaza in context de pictare: referinta necalificata (ANAF_CuloareRand(id_part)), corp intreg in TRY/CATCH cu Return Rgb(0,0,0), Nvl(id_part,0) (randul <TOATE INREGISTRARILE> de pe ramura lAllInList are id_part blank), zero apeluri care schimba zona de lucru. O eroare aici se repeta la fiecare repaint
H8 Curatarea binding-ului pe metoda: Unbindevents(form, 'actualizeaza_grid1', This, 'DupaGrid') cu 4 argumente — varianta cu 1 argument sterge si BINDEVENT(Thisform,"lAles",...) din Init si rupe selectia multipla
H9 Codul ROA impune >= 1s intre interogarile ANAF (validare.prg:1777, INKEY(1)); un debounce de 400ms il incalca. Necesare: interval minim global pe sesiune + circuit-breaker la 3 esecuri + log per cod HTTP distinct (azi gvANAF_EroareLogataSesiune amuteste toata sesiunea dupa prima eroare, iar 429/5xx sunt indistinguibile de "fara informatie")
M1 Delegatul DupaGrid trebuie sa aiba semnatura metodei delegate (Lparameters pcFiltru), altfel eroare 1229
M7 Codul fiscal invalid nu are stare in schema de culori — se decide explicit sau se documenteaza omisiunea
Test Partile netestabile in harnessul actual: ordinea actiunilor sub timer, reentranta pe cursorul gridului, culorile efectiv randate. Daca intra, intra cu risc de regresie permanent
Invariant Intreg mecanismul depinde de PRIVATE poVerifAlegere/poANAFInlocuire vizibile prin domeniu dinamic, ceea ce functioneaza doar pentru ca formularul de cautare e WindowType = 1 (modal). Orice trecere la modeless rupe atribuirea fara eroare