Plan corectat in patru puncte confirmate pe Oracle: - lista de coloane de taxare inversa are 13 termeni, nu 10 (TI19T/TI09T nu exista pe jc2007; expresia din oproceduri_decont.prg:8670 e scrisa peste view-ul VJC2025, cu aliasuri calculate) - tva_incasare nu exista pe jc2007/jv2007; interogarea transei 3 merge pe VJC2025/VJV2025 - kill-switch-ul nu se face in Optiuni_FIRMA/PROGRAM.dbf, ci pe modelul RC_ANAF_VERIF_SELECTIE (INI + optiuni Oracle + intrare de meniu) - oExecute deschide dialog de reconectare cu QUIT pe conexiune cazuta; apelul din transa 3 trebuie sa dezactiveze explicit reconectarea SVN r17910/r17911. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DhJwsrFFe1ZNAAtS8Twuti
39 KiB
Plan: 4 lucrari ROACONT (ANAF perioada TVA, validare CNP, avertizare exigibilizare, borderou eFactura)
Data: 27.07.2026. Autor livrare: marius.mutu. Versiune consolidata dupa runda 2 de review si poarta de decizie. Aceasta e versiunea de executat — incorporeaza toate deciziile. Istoricul review-ului e in Anexa, la final, si nu contine nimic de implementat.
Plan de test insotitor:
~/.gstack/projects/ROACONT/mmari-main-eng-review-test-plan-20260727-194744.md
Livrare in TREI TRANSE separate
Cele 4 lucrari nu au nicio dependenta functionala intre ele, dar au clase de risc si povesti de retragere incompatibile. Impachetate impreuna, o retragere pentru L3 ar lua cu ea si view-ul deja aplicat in schema clientului.
| Transa | Continut | Blast radius | Retragere | Blocata de |
|---|---|---|---|---|
| 1 | L1 + L2 | 2 fisiere .prg in COMUN |
un pas | nimic — se poate incepe |
| 2 | L4 | script DB + o expresie in client | doi pasi coordonati | 2 conditii de intrare |
| 3 | L3 | drumul de salvare al notelor, toata suita ROA | un pas, dar afecteaza tot | 1 conditie de intrare |
Fiecare transa se inchide in SVN inainte de a incepe urmatoarea.
TRANSA 1 — L1 + L2
Ambele in COMUN\programe\ocautare.prg + COMUN\programe\validare.prg. Lane secvential: L1 apoi L2.
Fara DB, fara drum de salvare. Reversibil prin revenire la binarul anterior.
L1 — de cand este platitor / neplatitor de TVA
Problema
Verificarea ANAF de la alegerea partenerului spune doar starea la data documentului ("ANAF: platitor TVA la 27.07.2026"). Pentru un cod fiscal care si-a schimbat atributul, utilizatorul nu vede DE CAND s-a schimbat.
Ce exista deja (verificat, nu se construieste)
ParseJsonANAFv8(validare.prg:2001-2114) pune DEJA in cursor toate campurile necesare:data_inceput_ScpTVA,data_sfarsit_ScpTVA,data_anul_imp_ScpTVA,mesaj_ScpTVA(citite dininregistrare_scop_tva.perioade_tva[1], liniile 2060-2072).- Cele trei coloane de data sunt DEJA de tip
DinCREATE CURSOR(validare.prg:2012). Nu e nevoie de normalizare, doar de garda pe gol. - Informatia se pierde in
ANAF_VerdictDinCursor(validare.prg:1657-1689), care ia din cursor doarcui,scpTVA,statusInactivi,denumire,mesaj(:1670-1675). - Cache-ul de sesiune
goCacheANAF_Sesiunepastreaza obiectul intreg (ocautare.prg:127.Add(m.loRezANAF, ...),:130.Item(...)). Proprietatile noi supravietuiesc. Nu se modifica. lDiscordantaexista deja:ocautare.prg:143,(loRezANAF.scpTVA <> loOut.lAreRO) Or loRezANAF.statusInactivi. Banda se ramifica deja pe ea la:651. Nu se scrie detectie noua.
Lucrarea e strict propagare + afisare. Nu se schimba apelul HTTP, nu se face al doilea apel.
Modificari
1. validare.prg, ANAF_VerdictDinCursor (~1657-1689)
Pe obiectul rezultat se adauga patru proprietati, toate citite din cursorul deja parsat:
-
dInceputScpTVA,dSfarsitScpTVA,dAnulareScpTVA— din coloanele de tipD, cuNvlsi garda pe gol. -
cMesajScpTVA— din coloanamesaj_ScpTVA(C(244)), NU dinmesaj.Motiv:
validare.prg:2012declaramesaj_ScpTVA C(244)darmesaj V(100), iar:2109faceloDate.mesaj = loDate.mesaj_ScpTVAurmat deInsert Intola:2112— VFP taie tacut la 100 din 244 de caractere. Proprietateamesajdeja expusa contine mesajul ANAF trunchiat la 41%.
Toate patru se citesc aici: cursorul se inchide la :1683 si nu mai exista alta ocazie.
2. ocautare.prg, ANAF_StarePartener, blocul de verdict (136-145)
Propaga cele patru proprietati in loOut.
Citirea se face cu Pemstatus(loRezANAF, 'dInceputScpTVA', 5) aici, la :140-145 — nu in
TextAnaf. ocautare.prg e incarcat si de produse ROA care pot avea un validare.prg mai vechi
(garda existenta la :63-66); citirea neprotejata ar arunca eroare in acest bloc, inainte sa se
ajunga vreodata la TextAnaf.
3. ocautare.prg, TextAnaf (683-695) — cand si unde apare data
Data de perioada apare in banda doar pe trei conditii. In rest banda ramane identica cu azi, iar perioada completa se vede in F4.
| Conditie | Data in banda |
|---|---|
lDiscordanta = .T. (ROA difera de ANAF, sau partener inactiv) |
DA |
dAnulareScpTVA nevid (anulare din oficiu) |
DA |
dSfarsitScpTVA < Date() (perioada s-a incheiat deja) |
DA |
| rest (cazul normal, concordant) | NU |
Regula de pozitionare, obligatorie: data se lipeste imediat dupa starea de TVA, inaintea
oricarui segment , Inactiv.
TextStare (ocautare.prg:680) produce Platitor TVA, Inactiv. Forma gresita
ANAF: Platitor TVA, Inactiv din 01.03.2019 afirma ca partenerul e inactiv din 2019, cand de fapt
aceea e data de inceput a perioadei de TVA. Cum lDiscordanta include statusInactivi, cazul
inactiv e chiar unul dintre cele aduse in banda — deci regula nu e optionala.
Forme corecte:
ANAF: Platitor TVA din 01.03.2019, Inactiv (DENUMIRE... RO12345678) (F4 = detalii)
ANAF: Platitor TVA din 01.03.2019 (DENUMIRE... RO12345678) (F4 = detalii)
ANAF: Platitor TVA 01.03.2019 - 31.03.2026 (DENUMIRE... RO12345678) (F4 = detalii)
ANAF: Neplatitor TVA din 12.03.2026 (DENUMIRE... 12345678) (F4 = detalii)
ANAF: Neplatitor TVA, anulat din 12.03.2026 (DENUMIRE... 12345678) (F4 = detalii)
Precedenta cand ambele date sunt nevide: pe dAnulareScpTVA — anularea din oficiu e informatia
mai grava, iar anulat e cuvantul pe care contabilul il cauta. Cele doua date NU se contopesc:
data_sfarsit_ScpTVA (incetarea inregistrarii) si data_anul_imp_ScpTVA (anulare din oficiu) au
consecinte diferite asupra dreptului de deducere.
Cand perioada apare in banda, data documentului redundanta (' la ' + Dtoc(toStare.dData)) se
scoate din text, ca sa nu rezulte doua date cu doua prepozitii alaturate.
Banda are voie 2-3 randuri: lb_anaf are WordWrap = .T., Height = 46,
Width = toForm.Width - 20 (ocautare.prg:472-476). Riscul real nu e latimea, ci ca un sufix de
lungime variabila muta punctul de wrap si (F4 = detalii) sare intre randuri la derularea cu
sagetile. Regula de mai sus il reduce mult: ~95% din randuri pastreaza banda de azi.
4. ocautare.prg, Detalii (787-873)
Bloc nou in dialog, dupa starea curenta: perioada de inregistrare in scopuri de TVA (inceput /
sfarsit / anulare, cele nevide, cu etichete distincte) si, daca cMesajScpTVA e nevid, mesajul
textual primit de la ANAF, integral.
Perioada apare in F4 intotdeauna cand ANAF a trimis-o, inclusiv in cazul concordant in care banda nu o arata.
5. validare.prg (2064-2072) — logul pe parsare esuata
Se logheaza cazul in care perioade_tva[1] exista, sirul sursa e nevid, dar data parsata e goala.
Conditia se scrie explicit, NU in CATCH: CTOD nu arunca exceptie pe format necunoscut, ci
intoarce data goala. CATCH-ul de la :2070 prinde doar erori de acces la perioade_tva[1], deci
un log pus acolo nu s-ar declansa niciodata pe cazul pentru care a fost cerut.
(Parsarea e corecta cat timp ANAF trimite YYYY-MM-DD, sub Set Date To YMD de la :2023,
restaurat in Finally la :2131.)
Limita de acceptat
ANAF v9 intoarce O SINGURA perioada — cea care acopera data interogata. Textul afisat descrie perioada relevanta pentru data documentului, nu tot istoricul.
L2 — validare CNP la codurile de 13 cifre
Problema (bug raportat)
ARGHIR MARIA (CUI: 2540324131210, ID: 149) ANAF nu a raspuns - verificarea a fost sarita.
Mesajul e fals. ANAF_StarePartener (ocautare.prg:82-84) intoarce .Null. pentru codurile de
13 cifre FARA a seta tcClasaEsec. CNP-ul din exemplu este VALID.
Localizarea exacta a defectului:
- BANDA nu acuza ANAF:
.Null.cu clasa goala cade peCase Isnull(m.loStare)(:648-650) -> promptul neutru. Nu e gresit, dar nu spune nimic. - DIALOGUL F4 e singurul care minte:
Detalii,:799-804, ultima ramura aIif-ului imbricat (:803) -> 'ANAF nu a raspuns - verificarea a fost sarita.' VerificaAlegere(:875+) intoarce.T.tacut peoStarenul — acolo nu e nimic de reparat.
Defectul e mai larg decat cazul raportat: EvalueazaRand sterge explicit clasa de esec cand codul
e invalid (:600, This.cClasaEsec = ''). Deci pentru ORICE cod fiscal invalid, banda spune corect
"CNP invalid" / "CIF invalid", dar F4 afiseaza tot 'ANAF nu a raspuns'. Cazul raportat e una din
doua instante ale aceluiasi defect.
Ce exista deja (verificat)
- Validarea locala RULEAZA DEJA:
EvalueazaRandapeleazaANAF_ValidareCodla:594si iese devreme pe orice rezultat nevid (595-604), INAINTE de apelul ANAF. Deci "CNP invalid (...)" si "CIF invalid (...)" se afiseaza deja azi. Nu se scrie validare noua. - Consecinta: un cod care pica validarea nu ajunge niciodata pe drumul ANAF. Ramurile
"CNP invalid" sub clasa noua si "CUI valid/invalid" sub
FARA_RASPUNSsunt INACCESIBILE prin constructie si NU se implementeaza. ANAF_ValidareCod(:208-227) decide CNP vs CIF cu prioritate petip_persoana, altfel lungime 13.VALIDARE_CNP(validare.prg:1296-1312),VALIDARE_CIF(validare.prg:1225-1294).- Clasa noua
COD_INVALIDurmeaza tiparul existentCOD_NENUMERICde laocautare.prg:643-646.
Modificari
-
ocautare.prg,EvalueazaRand(:600):This.cClasaEsec = 'COD_INVALID'in loc de''. -
ocautare.prg,ANAF_StarePartener(82-84): seteazatcClasaEsec = 'CNP'inainte deReturn .Null. -
ocautare.prg,ANAF_StarePartener: primeste in plustnTipPersoana, iar conditia de la:82devineLen(m.lcCui) = 13 And m.lnTipPersoana <> 1.Motiv:
:82decide "persoana fizica" doar pe lungime, ignorandtip_persoana, in timp ceANAF_ValidareCod(:222) decide invers, cu prioritate petip_persoana. Divergenta e mascata azi pentru ca banda cade pe promptul neutru si nu afirma nimic. L2 pune acolo "Persoana fizica - CNP corect", deci pentru un partener extern cu cod numeric de 13 cifre aplicatia ar afirma pe ecran ceva fals, unde azi tace. Cauza e preexistenta, consecinta vizibila ar fi introdusa de L2. -
ocautare.prg,EvalueazaRand(636-657): ramura noua inaintea luiCase Isnull(m.loStare), pe clasa'CNP'— banda arataPersoana fizica - CNP corect, culoare NEUTRA (SeteazaLabel(..., .F., .T.)), nu verde.De ce nu verde: verdele si formularea scurta stau in acelasi loc si in aceeasi culoare cu confirmarea reala de la ANAF. O cifra de control nu este o verificare la ANAF.
-
ocautare.prg,Detalii(799-804): doua ramuri noi inIif-ul imbricat:'CNP'->Persoana fizica - CNP corect.'COD_INVALID'->Cod fiscal invalid - nu s-a interogat ANAF. Corectati codul in fisa partenerului.
Informativ, fara blocare si fara dialog de confirmare — cascada RC_ANAF_VERIF_SELECTIE ramane
neatinsa.
TRANSA 2 — L4: borderou eFactura, taxare inversa
Nu se incepe inainte ca transa 1 sa fie in SVN.
Problema
In borderoul eFactura, facturile primite cu taxare inversa apar gri (diferenta fata de registrul de
cumparari). In XML-ul eFactura taxarea inversa are TVA 0 (ClassifiedTaxCategory/ID = 'AE'), dar in
contabilitate se inregistreaza 4426 = 4427, deci jc2007.totctva contine si acest TVA. Diferenta
rezultata e exact TVA-ul de taxare inversa si nu e o eroare reala.
Importul face deja corectia inversa la generarea notelor (anaf_efactura.vc2:12096-12106), dar
numai IF thisform.lPrimite.
Decizie
Corectia se face din datele contabile REALE, prin view-ul Oracle — nu prin recalcul cu cota standard (care ar da gresit pe facturi mai vechi la 19%). Scope: DOAR facturi primite.
Coloana vizibila in grid NU se face. Se livreaza doar corectia interna a expresiei diferenta.
Conditii de intrare (ambele obligatorii inainte de a scrie scriptul)
-
Trasare cap-coada a unei facturi reale: linie XML cu
ClassifiedTaxCategory/ID = 'AE'->id_jtva_coloana-> coloana dinjc2007. Se confirma pe date ca acolo sta suma. -
Definitia curenta a lui
anaf_vefactura_trimisse ia dinUSER_VIEWS.TEXTdin schema tinta, nu din arhiva CLAR.Motiv: scriptul-model
2025\06\ff_2025_06_16_02_COMUN_EFACTURA.sqlredefineste NUMAIanaf_vefactura_primit(:3-53). Corpul luianaf_vefactura_trimise in alt fisier, mai vechi (2024\08\ff_2024_08_22_01_COMUN_EFACTURA.sql:63-112); cele doua au divergat cu ~10 luni si exista 10 scripturi in arhiva care il redefinesc. Cine il rescrie "dupa model" luand fisierul gresit revine tacut la o versiune veche a view-ului.
Modificari
1. Script de migrare nou, in D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\
create or replace view pentru AMBELE view-uri, cu o coloana noua jtva_ti:
-
anaf_vefactura_primit:jtva_ti= suma coloanelor de TVA de taxare inversa dinjc2007, cu EXACT aceeasi potrivire ca cea folosita azi pentrujtotctva(an/luna/dataact/regexp pe numar act si cod fiscal emitent). -
anaf_vefactura_trimis:jtva_ti= constanta0. La facturi emise nu se inregistreaza nota contabila de TVA pentru taxare inversa, decidiferentade acolo ramane identica cu azi.Coloana e obligatorie in AMBELE:
import_efactura.prg:40folosesteFROM <<m.lcTabel>>, un singur SELECT pentru ambele view-uri (lcTabelsetat la:27). Fara ea, borderoul de facturi TRIMISE crapa cu ORA-00904.
Lista de coloane — CORECTATA 28.07.2026, verificata pe USER_TAB_COLUMNS.
Expresia din Programe\oproceduri_decont.prg:8670 NU se poate copia: e scrisa peste view-ul
VJC2025 (FROM VJC2025 J, :8677), nu peste tabela. In acel view ti19t si ti09t sunt
ALIASURI calculate (SUM(ti19bct+ti19bvt+ti19bft) as ti19t, SUM(ti09bvt+ti09bft) as ti09t).
Pe jc2007 coloanele TI19T si TI09T nu exista. Un create or replace view care le
foloseste direct pica cu ORA-00904 — si, cum acelasi script redefineste si
anaf_vefactura_trimis, ar rupe borderoul pe AMBELE sensuri.
Lista corecta pe jc2007 are 13 termeni, nu 10 (TI09 nu are varianta BC, asimetric fata
de TI19):
NVL(j.TI21T,0)+NVL(j.TI11T,0)+NVL(j.TI24T,0)+NVL(j.TI20T,0)
+ NVL(j.TI19BCT,0)+NVL(j.TI19BVT,0)+NVL(j.TI19BFT,0)
+ NVL(j.TI09BVT,0)+NVL(j.TI09BFT,0)
+ NVL(j.XX21TIT,0)+NVL(j.XX11TIT,0)+NVL(j.XX19TIT,0)+NVL(j.XX9TIT,0)
Familia NU este XX*TI* singura. Importul eFactura trece prin ProcentTva2IdJtva
(definita in COMUN\programe\oproceduri_comune.prg:5836, doar apelata din
anaf_efactura.vc2:12093), care pentru cumparari cu taxare inversa da id-urile 216/218/141/145;
in jtva_coloane, 216 = 'TX. INV. 21%' -> TI21B (pereche 217 = TI21T), 218 = 'TX. INV. 11%' ->
TI11B (219 = TI11T). Coloanele XX*TIT sunt achizitii NON-CE, pe care importul eFactura nu le
scrie. Toate confirmate ca existente in jc2007: TI21T=217, TI11T=219
(2026\03\ff_2026_03_09_02_COMUN_PACK_CONTAFIN_10G_ROMCONSTRUCT.pck:4991-4993), XX19TIB=192,
XX19TIT=193 (2026\01\PACK_CONTAFIN_ROMCONSTRUCT...pck:4891-4892).
Performanta: jtotctva e deja un subselect corelat peste jc2007 cu REGEXP_SUBSTR +
REGEXP_REPLACE in WHERE — neindexabil, scanare per rand. Un al doilea subselect identic pentru
jtva_ti ar dubla exact acest cost. Se scrie un singur subselect care intoarce ambele sume.
Se pastreaza EXEC pack_migrare.UpdateVersiune(...) + COMMIT. Fisierul se scrie cu CRLF.
Se bumpeaza versiune_db.txt. Scriptul se incheie cu o verificare de obiecte invalide: view-urile
anaf_vefactura_primit_detaliu si anaf_vefactura_trimis_detaliu
(2024\08\ff_2024_08_28_02_COMUN_EFACTURA.sql:84, :122) sunt construite peste cele doua si se
recompileaza automat, dar invaliditatea trebuie sa nu treaca neobservata.
2. COMUN\programe\import_efactura.prg — o singura expresie
Linia :36:
NVL(total_cu_tva,0.00) - (NVL(jtotctva,0.00) - NVL(jtva_ti,0.00)) as diferenta
lcSchema (:31-33) NU se modifica. jtva_ti apare doar ca termen intr-o expresie, nu ca
coloana de iesire, deci numarul de coloane al cursorului ramane acelasi. lcSchema e o schema
pozitionala imperecheata cu lcSelect in gencursor (:50); orice coloana noua de iesire ar
cere modificarea ambelor, iar modificarea uneia singure ar strica intreg borderoul.
3. Degradare gratioasa la lipsa coloanei
Inainte de a construi lcSelect, se testeaza o data existenta coloanei (SELECT jtva_ti FROM ... WHERE 1=2 intr-un TRY, sau interogare pe user_tab_columns) si se construieste lcSelect cu sau
fara termenul jtva_ti.
Motiv: exe-ul ajunge la client prin update automat, iar migrarea CLAR ruleaza pe alta cadenta. Fara sonda, prima combinatie gresita da ORA-00904 si borderoul nu se deschide deloc, nici primite nici trimise. Cu sonda, ordinea de livrare devine optimizare, nu conditie de functionare.
Ordinea recomandata ramane: scriptul se aplica INAINTE de build — de scris in nota de release.
4. Ce NU se atinge
Colorarea ramane pe diferenta <> 0 (anaf_efactura.vc2:6020-6041 Page2 si 12790-12817
frm_import_efactura) — se corecteaza doar sursa numarului. NU se inventeaza o a treia culoare:
randurile cu taxare inversa nu sunt de investigat, sunt corecte prin constructie, iar falsurile
pozitive omoara marcajul de exceptie. NU se ating Page1 / Page3 si filtrul chkDiferente
(anaf_efactura.vc2:5347-5349) — sunt facturi emise. Nu se editeaza niciun binar .vcx.
Limita cunoscuta, de consemnat
O taxare inversa inregistrata la cota GRESITA face ca diferenta sa se anuleze reciproc si randul sa devina alb. Fara coloana in grid nu mai exista nicio parghie vizuala pentru acest caz. E pretul deciziei de a nu adauga coloana si trebuie sa fie scris, nu descoperit.
TRANSA 3 — L3: avertizare de exigibilizare TVA la salvarea notelor
Ultima, singura. Nu se incepe inainte ca transele 1 si 2 sa fie in SVN.
Scopul lucrarii — ca sa nu se citeasca gresit
Singura modificare de cod e in COMUN\clase\omodificari.vc2, in inainte_de_do_termin al celor
doua clase de formular de note: frm_modific2007 (:5001) si frm_modific2024 (:13131).
NU se modifica oproceduri_inchidere.prg. NU se modifica do_adauga_tva_exigibil.
NU se genereaza nimic automat in afara butonului din dialog.
oproceduri_inchidere.prg apare mai jos doar ca drum de test: exigibilizarea din meniu deschide
chiar frm_modific2007 (:902, Createobject([frm_modific2007], ...), cu titlul
'Exigibilizare TVA Incasare'), deci avertizarea se declanseaza si acolo fara ca cineva sa fi atins
acel fisier.
Conditie de intrare
Cotele 21% si 11% in pack_contab.defalca_tva_incasare si pack_contab.cauta_facturaTVAEx.
Partial inchisa: exista suport 21%/11% in 2025\08\ff_2025_08_08_02_COMUN__PACK_CONTAB.sql
(comentariu "creeaza_note_tva_incasare TVA 21%, 11%"). De confirmat pe date.
Ce exista deja (verificat)
Command5->Thisform.do_adauga_tva_exigibil()(omodificari.vc2:13776-13778). Captionul DIFERA intre clase::2643= "Adauga nota TVA devenit exigibil" (frm_modific2007),:6923= "Adauga TVA exigibilizat" (frm_modific2024).do_adauga_tva_exigibil(:12483+) lucreaza pe conditiaales and (scc = '4428' or scd = '4428' or id_factd > 0 or id_factc > 0)(:12509). Nu contine nicio lista de cote — lucreaza pe liniile notei si peproc_tva, si deleaga defalcarea Oracle-ului. Deci e agnostic la cota si functioneaza la 21%.cmdSelect.Click= "Selecteaza tot" (:13640-13658) — face doarReplace All ales With .T.- Precedent identic ca forma in acelasi hook: avertizarea 4426-4428 (
:13165-13176), cuamessagebox(..., 4+32, ...)siReturn .F. tactpoartatipnota,id_fact,id_factd,id_factc,ales,id_act. Cursorul e construit de fiecare apelant, nu deomodificari.vc2. Codul insusi nu are incredere catipnotaexista::4752si:12847folosescIf TYPE('tact.tipnota') = 'N' AND ...Return .F.dininainte_de_do_terminopreste salvarea: apelantul din_frm_base.vc2(PROCEDURE do_termin) nu face Release/Hide si nu seteazabuton/gnButon, iar toti apelantii testeazaIf buton = 1inainte de a scrie. Nicio subclasa a celor doua clase nu exista in arbore, deci niciun override nu poate sari peste hook.
Modificari — algoritm
Pasul 0 — pozitionare in hook. Verificarea se aseaza sub acelasi IF m.llRet ca avertizarea
existenta (:13165) si dupa SELECT tact / SET FILTER TO de la inceputul procedurii
(:5001-5005, :13131-13135). Altfel apare peste dialogul de eroare de la
verificare_note_contabile, sau filtrul gridului ii ascunde randuri.
Ordinea dialogurilor la o singura apasare de Salvare: verificare_note_contabile -> avertizarea
4426-4428 -> avertizarea noua. Prima semnaleaza o greseala facuta, a doua o omisiune.
Pasul 0.5 — kill-switch. Optiune implicit pornita. Daca e oprita: nicio avertizare, nicio
interogare, in tot produsul. L1/L2 stau deja in spatele RC_ANAF_VERIF_SELECTIE; L3 intra pe drumul
de salvare al intregii suite si nu are voie sa fie fara oprire.
Mecanismul — CORECTAT 28.07.2026. NU se folosesc Optiuni_FIRMA/Optiuni_PROGRAM.dbf din
DATE\: acele tabele exista pe disc, dar nu sunt calea folosita si nu apar deloc in cod. Modelul de
urmat este chiar RC_ANAF_VERIF_SELECTIE, care are trei straturi (ocautare.prg:255-285, :341-381):
- kill-switch INI:
getini(gcGeneralIniFile, 'anaf', 'verificare_selectie'), doar'0'opreste; - optiuni Oracle (
optiuni/optiuni_util), citite cuciteste_optiune/citeste_optiune_utilizatordinoinit_optiuni.prg, cu cache intr-oCollection; - UI = intrare de meniu (
Meniuri\CONT2000.MPR:210,ON SELECTION BAR ... DO ANAF_ComutaVerificare), nu ecran cu campuri DBF.
Pasul 0.6 — flag de lot. Apelantii care instantiaza formularul in bucla seteaza un flag public
"rulez in lot", iar verificarea se sare. anaf_efactura.vc2:12733 instantiaza frm_modific2024
per factura importata: un import de 150 de facturi ar insemna 150 de AMESSAGEBOX succesive
plus 150 de interogari Oracle sincrone. Acelasi lucru la :12940 si comun.vc2:2436.
Pasul 1 — colectare. Din tact, id-urile id_factd / id_factc > 0. Daca nu exista niciunul:
nimic, cost zero, fara interogare Oracle.
Pasul 2 — suprimarea platilor deja acoperite.
Regula: exista in tact o linie cu tipnota = 1 SI id_fact = <id>.
Citirea lui tipnota se face prin TYPE('tact.tipnota') = 'N', ca la :4752 si :12847 —
tact e construit de apelant, posibil din alt produs ROA.
Santinela -5 NU intra in regula. do_adauga_tva_exigibil scrie -5 numai cand id-ul
facturii nu se poate rezolva (:12531, :12542, :12551, :12559), iar comentariul din cod spune
ce inseamna: "pun -5 ... ca sa-i completez id_fact la scrie_in_act" — adica "de completat la
scriere", nu "rezolvat". Pentru liniile colectate la pasul 1 (id_factd/id_factc > 0) codul
scrie intotdeauna id-ul real, deci -5 e imposibil prin constructie pe multimea urmarita. In
schimb, o disjunctie SAU id_fact = -5 nu ar fi conditionata de id: o singura linie cu -5
oriunde in tact ar stinge avertizarea pentru TOATE platile din lot, tacut.
Calificarea pe tipnota = 1 se pastreaza: fara ea, excluderea ar prinde si notele MANUALE
4426=4428 — exact cele despre care avertizarea existenta de la :13165 spune ca sunt probabil
gresite.
Nota de reconciliere: o decizie intermediara a review-ului (D23) ceruse mutarea cheii de pe
tipnotape perechea de conturi, pe motiv ca notele generate deinchidere_tva_soldautipnota = 0(oproceduri_inchidere.prg:884). Motivul a cazut: acel drum nu ajunge niciodata la regula, pentru caINSERT INTO actactan(:848-854) nu completeazaid_factd/id_factc, deci pasul 1 nu colecteaza nimic. Cheia ramane petipnota, fara-5.
Pasul 3 — interogarea, fara lista IN.
O singura interogare goExecutor, care intoarce id_fact-urile cu tva_incasare = 1 si sold
neexigibil <> 0. Intersectia cu tact se face local, in VFP.
Sursa — CORECTATA 28.07.2026. Interogarea NU se poate scrie peste jc2007 + jv2007:
coloana tva_incasare nu exista pe cele doua tabele (verificat pe USER_TAB_COLUMNS). Ea sta pe
DOCUMENTE (id_doc = id_fact) si pe view-urile VJC2025 / VJV2025. Se interogheaza view-urile:
au deja tot ce trebuie (cotele, tva_incasare, an/luna, id_fact) si sunt exact ce foloseste
deja pack_contab.cauta_facturaTVAEx. Cele 14 coloane de cota de mai jos exista, in schimb, si pe
jc2007/jv2007 — verificat.
Nu se construieste lista IN (...). Pragul Oracle de 1000 (ORA-01795) se atinge la utilizare
normala, nu la 10x: acelasi formular deserveste, dupa propriul caption, "Import extrase bancare,
deconturi curieri, procesatori plati" (anaf_efactura.vc2:12941), iar imperecherea se face linie cu
linie (oproceduri_import.prg:729, 755, 782, 808). Un extras obisnuit are 300-2000 linii/luna; un
decont de procesator, mult mai mult. Un singur SQL de lungime fixa elimina o clasa intreaga de esec
de pe drumul de salvare al intregii suite.
Formula de sold neexigibil — NU se copiaza din registru. Filtrul existent la
Clase\ovanzcump.vc2:38011 foloseste
ro24nb+ro24nt+ro20nb+ro20nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt, care OMITE cotele 21% si 11%,
in vigoare din august 2025 (RO21NB/RO21NT/RO11NB/RO11NT, id-uri 214/215,
2025\07\ff_2025_07_21_01_COMUN_TVA21.sql:134-140). Cu formula copiata, avertizarea nu s-ar
declansa NICIODATA pe o factura din 2025 incoace — exact pe facturile pentru care a fost ceruta.
Lista corecta:
ro24nb+ro24nt+ro20nb+ro20nt+ro21nb+ro21nt+ro11nb+ro11nt+ro19nb+ro19nt+ro9nb+ro9nt+ro5nb+ro5nt
Robustete. Verificarea ruleaza doar dupa ce verificare_note_contabile a trecut si doar cu
conexiune valida. Orice esec (tabela inexistenta in alt produs ROA, conexiune cazuta, timeout) ->
se sare, cu linie in goLog. Niciodata tacut: o verificare care moare invizibil e mai rea decat
una absenta, pentru ca nimeni nu afla ca nu mai merge. Esecul nu blocheaza salvarea.
Cum se obtine asta — PRECIZAT 28.07.2026, dupa citirea clasei. oexecutor e in
COMUN\programe\oproceduri_comune.prg:69-547. Comportamentul real:
oExecute()NU arunca eroare VFP pe SQL esuat: intoarceCT_INSUCCES(-1). Deci nu urca laON ERRORglobal.goLog.Logse apeleaza pe toate drumurile de esec. Pana aici, cerinta e indeplinita din oficiu.- DAR pe eroare ODBC de conexiune cazuta (cod 1526 cu subcod 12152/3113/3114/12560/4068/28/12 —
exact cazul numit mai sus) se deschide un
amessagebox"Doriti reconectare?" (oproceduri_comune.prg:390) NECONDITIONAT detlShowError, iar raspunsul "Nu" duce laQUIT— inchide aplicatia, in mijlocul salvarii. Exact opusul cerintei. - Deci apelul TREBUIE facut cu reconectarea dezactivata explicit. Nu exista precedent: din 150+
apeluri
oExecute/oExecutadin codebase, niciunul nu trece de 2 parametri. Tiparul se scrie aici prima oara — de verificat pozitia exacta a parametrului in semnatura inainte de a-l folosi. - Se foloseste
oExecute, NUoExecuta(aceasta din urma afiseaza mesaj propriu, neconditionat, pe orice esec). Nu se adauga niciunamessageboxpropriu. - Nu exista niciun timeout Oracle configurat (
SQLSETPROP QueryTimeout/ConnectTimeout) nicaieri: un query agatat blocheaza la nesfarsit, nu doar da eroare. De avut in vedere la testare.
Pasul 4 — dialogul.
Trei butoane:
Exista <N> plati/incasari pe facturi cu TVA la incasare pentru care nu s-a adaugat
nota de TVA exigibilizat.
[Adauga acum] [Continua] [Anuleaza]
- Adauga acum — ruleaza
do_adauga_tva_exigibilpe liniile deja identificate de interogare, apoi continua salvarea. - Continua — salveaza fara exigibilizare.
- Anuleaza —
Return .F., ramane in formular fara sa salveze.
De ce buton si nu instructiune: sistemul stie deja care plati au nevoie de exigibilizare — asta e
chiar interogarea de la pasul 3. O modala care spune "du-te si apasa un buton" ar fi fost
inexecutabila in doua feluri: captionul difera intre cele doua clase (:2643 vs :6923), iar
Command5.Enabled se calculeaza dupa randul curent (:5661-5667, :13850) si cmdSelect.Click
nu il recalculeaza — deci butonul poate fi gri exact dupa "Selecteaza tot".
<N> — de fixat inainte de implementare daca numara facturi distincte sau linii din tact.
Pasul 5 — flag anti-bucla.
Proprietate de formular lAvertizatExigibilizare, setata dupa prima avertizare; a doua oara in
aceeasi sesiune de formular nu se mai avertizeaza.
Motiv: cand chkTVAEX e bifat si linia e plata/incasare, do_adauga_tva_exigibil cheama
creeaza_note_tva_incasare (:12598-12600), unde id_fact vine din cursorul intors de
pack_contab.defalca_tva_incasare (:12412, a.id_fact As id_fact). Daca procedura nu intoarce
randuri, nu se insereaza nimic potrivit -> suprimarea nu prinde niciodata -> avertizare -> buton ->
avertizare -> buton (dubland notele generate) -> avertizare, fara iesire in afara de "Continua".
Ca "zero randuri" e un caz real: oproceduri_inchidere.prg:843-848 il trateaza explicit.
Acoperire — drumuri de instantiere
frm_modific2007 / frm_modific2024 sunt instantiate din: ocont2003.prg:416, 1230, 1679, 2141;
oproceduri_incasari.prg:299; frm_import_extrase_banca.sc2:1652;
anaf_efactura.vc2:12733, 12940; frm_initializare_facturi_balanta.sc2:1803; comun.vc2:2436;
oproceduri_inchidere.prg:719, 902, 1007, 1438; frm_import_note_a4200.sc2:1651;
frm_import_note_facturi_clienti.sc2:895; ooperatii_comune.prg:1137.
Premisa "prinde si casa, si banca, si notele manuale" TINE.
Nota de metoda:
COMUN/e in.gitignore, deci Grep/ripgrep il sare implicit. Cautarile de tip "cine apeleaza" se fac curg --no-ignoresau cu cale explicita, altfel intorc zero fals.
NU intra in scop (amanat, cu motiv)
Defectele din drumul de exigibilizare din meniu (inchidere_tva_sold). De adaugat in TODOS.md
cu descrierea de mai jos, care inlocuieste formularea anterioara — aceea descria un defect
inexistent si ar fi trimis pe cine preia lucrarea catre o harta gresita.
Ce este de fapt:
oproceduri_inchidere.prg:833testeazaIif(m.lnCota = 21, m.lnSuma21, m.lnSuma11)intr-o buclaFor lnCota = 1 To 7(:829).lnCotanu ajunge niciodata 21, decilnSuma21e cod mort, iar lalnCota = 6se ia soldul de 11% cu cota 1.21 (:834). Linia vecina:837o face corect (Iif(m.lnCota = 6, m.lnSuma21T, ...)). Este o greseala de tipar6->21.:802-803citescsoldn21/soldn11neconditionat dincrsTVAIncasareTemp. Aliasurile sunt emise doar de formele 2025 (ovanzcump.vc2:44220-44225,:55069-55073). Pe formele 2010 (:39660,:51403) nu exista -> eroare VFP 12, modala, la apasarea butonului. Exigibilizarea din registru e rupta pe perioadele anterioare lui 2025.lnSuma21,lnSuma11,lnSuma20,lnSuma19lipsesc din listaLocal(:770-773) — devin PRIVATE si se scurg in stiva de apel.
Ce NU este: ovanzcump.vc2:39660 nu "pierde 24/20"; e forma 2010, folosita pe perioade < 2025, al
carei cursor sursa vjc2010/vjc2013 nu are deloc coloanele ro21*/ro11* (oproceduri_decont.prg:18795-18801),
deci acolo omisiunea e corecta.
Nu afecteaza L3: butonul catre care trimite avertizarea L3 este do_adauga_tva_exigibil, care nu
foloseste nicio lista de cote. Sunt doua butoane diferite, pe doua drumuri diferite.
De scris in nota de release: pe o factura cu TVA la incasare 21%, L3 avertizeaza corect, dar utilizatorul care merge pe drumul din meniu (registru -> exigibilizare) gaseste lista goala. Butonul din formular functioneaza.
Alte lucruri amanate:
- Istoricul complet al atributului de TVA (mai multe perioade). ANAF v9 intoarce o singura perioada.
- Al doilea apel ANAF la data curenta ("era platitor la data documentului, dar nu mai este azi").
- Persistarea totalului cu TVA de taxare inversa pe randul din
anaf_efacturala import: nu ar acoperi facturile deja importate; view-ul repara si istoricul. - Derivarea listelor de cote din
jtva_coloanein loc de enumerare in mai multe locuri. E cauza radacina a defectelor gasite la L3 si L4.
Ce exista deja (si se reutilizeaza)
| Sub-problema | Cod existent | Se reutilizeaza? |
|---|---|---|
| Perioada TVA de la ANAF | ParseJsonANAFv8, validare.prg:2001-2114 |
Da, integral. Se propaga, nu se parseaza din nou |
| Detectia discordantei ROA vs ANAF | lDiscordanta, ocautare.prg:143 |
Da. Nu se scrie detectie noua |
| Cache de sesiune | goCacheANAF_Sesiune, ocautare.prg:127, :130 |
Da, nemodificat |
| Validare CNP / CIF | VALIDARE_CNP / VALIDARE_CIF, apelate prin ANAF_ValidareCod la :594 |
Da, integral |
| Generarea notelor de exigibilizare | do_adauga_tva_exigibil, omodificari.vc2:12483+ |
Da (rulat din butonul dialogului) |
Tiparul de avertizare in inainte_de_do_termin |
omodificari.vc2:13165-13176 |
Da, se copiaza forma |
| Lista canonica de coloane TVA taxare inversa | oproceduri_decont.prg:8670 |
Da, se preia ca atare |
Reguli de livrare
- Fiecare transa livreaza
docs\diff_runda<N>_<subiect>.patch; write-back in binar (txt2vcx.ps1) si commit DOAR dupa aprobare. Patch-urile nu se comit. - Comentarii: o singura intrare cumulativa in antetul fisierului,
*!* DD.MM.YYYY/*!* marius.mutu/ 1-2 fraze. Fara comentarii in corpul codului. La L2 (corectie de eroare) nu se adauga comentariu. ocautare.prg,validare.prgsiomodificari.vc2contin octeti cp1252 (0xBA). Orice scriere cu Edit/Write ii corupe inEF BF BD. Se editeaza TOT ce e de editat, si abia DUPA ultima scriere se verifica byte-level si se repara o singura data, luand octetul corect dinsvn cat.- Scripturile
.sqldin SCRIPTURI_CLAR se scriu cu CRLF. changelog_roacont.txt: cate o intrare scurta per transa. L1/L3/L4 =:nou:sau:modificare:; L2 =:eroare:(mesajul fals a ajuns la utilizatori).
Ce ramane neverificat
Stare la 28.07.2026, dupa verificarea pe date (schema dev MARIUSM_AUTO). Detalii in
docs\handoff_transa2_conditii.md, handoff_transa3_conditii.md, handoff_transa3_deschise.md.
Comportamentul— INCHIS, vezi "Robustete" mai sus.goExecutorla timeout / conexiune cazutaDaca— INCHIS.pack_contab.defalca_tva_incasarepoate intoarceid_factnull/0id_factin cursor e mereu parametrul trimis, deci nu poate fi null. Zero randuri ESTE posibil (filtrul final poate exclude tot), si e chiar garantat pe drumulomodificari.vc2:12547-12561, unde santinela-5ajunge ca parametru ladefalca_tva_incasare(-5, ...). Flagul anti-bucla de la Pasul 5 e confirmat necesar, nu preventiv.Cotele 21/11 in— INCHIS.pack_contabdefalca_tva_incasaredeleaga lacreeaza_note_tva_incasare, care areDECODEexplicit peid_jtva_coloana211/215 (JC) si 38/42 (JV) pentruRO21*/RO11*;cauta_facturaTVAExfiltreaza si el peRO21NT/RO11NT. Conditia de intrare a transei 3 e indeplinita.- Numarul real de linii pe un decont de curier/procesator — RAMANE DESCHIS pe cifra. Schema dev nu
are date reprezentative (
DECONT: 2 randuri in toata baza;EXTRAS CON: p95 ~10 linii/lot, cu un ordin de marime sub estimarea din plan, dar pe loturi de test, nu activitate reala). Nu schimba decizia: o interogare unica de lungime fixa eliminaORA-01795indiferent de volum, deci nu exista prag sub care listaIN(...)ar fi de preferat. - Trasarea cap-coada a unei facturi cu linie
AE(transa 2) — RAMANE DESCHISA pe date reale. In schema dev NU exista nicio factura venita din import eFactura cu taxare inversa (anaf_efactura: 487 randuri primite, 8 cuid_fact, zero suprapunere cu randuriTI*nenule). Mecanismul a fost demonstrat numeric doar pe un caz construit dinjc2007(id_fact=8007136,ti19bft=19,totctva=119: diferenta falsa de -19 se anuleaza exact cujtva_ti). De consemnat in nota de release: verificarea finala ramane de facut pe prima factura reala de taxare inversa importata dupa aplicarea scriptului.
ANEXA — istoricul review-ului
Nimic de implementat aici. Se pastreaza pentru trasabilitate.
Metoda
Doua runde: /autoplan (CEO -> Design -> Eng) pe 27.07, apoi runda 2 cu trei voci independente
(subagenti fara context de review) confruntate cu verificare proprie pe cod. Codex indisponibil pe
masina, deci consensul e "voce independenta + verificare proprie", nu Claude/Codex. Faza DX sarita:
produsul nu e pentru dezvoltatori.
Afirmatii verificate pe cod
CONFIRMATE: ParseJsonANAFv8 pune datele in cursor (validare.prg:2012); ANAF_VerdictDinCursor
expune doar 5 campuri (:1670-1675); cache-ul pastreaza obiectul intreg (ocautare.prg:127,
:130); tact poarta campurile necesare (omodificari.vc2:4496, :5661, :13166); precedentul
de avertizare (:13165-13172); un singur SELECT pentru ambele view-uri (import_efactura.prg:40);
coloanele TI21T=217, TI11T=219, XX19TIB=192, XX19TIT=193; lb_anaf multi-rand
(ocautare.prg:472-476); localizarea defectului L2 in Detalii (:648-650, :803);
Return .F. opreste salvarea (_frm_base.vc2, do_termin).
INFIRMATE: tipul coloanelor de perioada era declarat incert — sunt deja D; mesaj NU e
echivalent cu mesaj_ScpTVA (V(100) vs C(244)); santinela -5 inseamna "de completat la scriere",
nu "rezolvat"; capcana inchidere_tva_sold e evitata prin id_factd/id_factc necompletate, nu
prin tipnota; defectul de cote amanat era descris gresit.
Decizii
D1-D21 (runda 1, /autoplan): mod SELECTIVE EXPANSION; lista de coloane TI*+XX*TI*; coloana in
ambele view-uri; conditie de intrare prin trasare cap-coada; lista de cote cu 21/11; defect
preexistent semnalat nu reparat; texte distincte pentru sfarsit vs anulare; log pe parsare esuata;
eliminarea ramurilor inaccesibile din L2; corectarea localizarii defectului L2; data lipita de
stare; banda multi-rand; interval pentru perioada inchisa; Pemstatus; defectul L2 mai larg
(:600); banda neutra pentru CNP; regula de suprimare pe tipnota; jtva_ti coloana vizibila;
fara a treia culoare; ordinea DB-inainte-de-exe.
D22-D33 (runda 2): N1 mesaj_ScpTVA in loc de mesaj (rastoarna D7); N2/N3/N4/N5/N6/N7;
4+32+256; conditie de intrare pe pack_contab; rescrierea textului amanarii.
D34-D37 (poarta, marius.mutu): trei livrari separate, fixurile N7 raman amanate cu text rescris;
L3 cu buton de actiune in dialog; L4 fara coloana vizibila; L1 cu data si la lDiscordanta.
Contradictie rezolvata la consolidare: D23 (cheia de suprimare pe perechea de conturi) cade in
favoarea E.2 (tipnota = 1 AND id_fact, fara -5) — motivul lui D23 a disparut odata cu E.3.
Deciziile D36 si D37 au dizolvat trei constatari: N5, K-1 si N6 nu mai au obiect fara coloana vizibila; N3 si N4 nu mai au obiect cu butonul in dialog.
Teme transversale
Tema 1 — "corect pe hartie, inexecutabil de utilizator". Trei constatari independente (caption diferit, buton conditionat de randul curent, coloana invizibila din cauza preferintelor de grid) au avut aceeasi forma. Toate trei au fost eliminate prin deciziile de la poarta.
Tema 2 — planul verifica listele de cote in VFP si nu deschide niciun pachet Oracle. De aici
conditia de intrare pe pack_contab pentru transa 3.