# Cercetare: totaluri goale pe factura editata din aviz (LISTA FACTURI, AVIZE SI PROFORME) Simptom: dupa editarea din formularul unificat a unei facturi emise DIN AVIZ, randul facturii in lista principala apare cu **Total fara TVA / Total TVA / Total cu TVA GOALE** (NULL, nu 0.00). Randul avizului de dedesubt ramane corect. Regresie fata de comportamentul anterior. Diagnostic STRICT — nu s-a modificat niciun fisier de cod, nu s-a facut write-back, nu s-a comis nimic. > **Depasit partial.** Acest raport se opreste la "cauza probabila, NEVERIFICAT pe date". > Interogarea pe `MARIUSM_AUTO@ROA_CENTRAL` a inchis intre timp intrebarea: linia facturii are > `ID_VALUTA = 2` (EURO) fara rand corespunzator in `VANZARI_CURSURI`, iar ramura de conversie > valutara a procedurii produce NULL. Concluzia si reparatia sunt in > `docs\propunere_runda5_articole_valuta_rate.md`, punctul 2. Ce ramane valabil aici: analiza > lantului de scriere si infirmarea ipotezei cu `id_vanzare_set`/`id_vanzare_det`. ## 1. De unde vin coloanele Total fara TVA / Total TVA / Total cu TVA Gridul `grid_facturi` din `frm_facturi` (`COMUN\clase\ofacturare_comun.vc2:1172` obiectul, `:1203-1208` coloanele `cTotal_cu_tva`/`cTotal_fara_tva`/`cTotal_tva`) e legat pe cursorul `crsfacturi` (`RecordSource = "crsFacturi"`, `COMUN\clase\ofacturare_comun.vc2:2238`), populat prin `gencursor('poFacturi','crsfacturi', lcSelect, ...)`. Cursorul e umplut din UNA din doua proceduri Oracle, **alese la RUNTIME de utilizator**, printr-un prompt (`Clase\ofundal_facturare.vc2:944-953`, `Page4.Cw1.do_actiune`): ``` lnOptiune = xmenu('Vizualizare \ 0` din cursorul `tvd` (`:498-518`) — UPDATE pe cheia `id_vanzare_det`, camp cu camp: `sters, cantitate, pret, pret_cu_tva, pret_achizitie, proc_tvav, discount_unitar, id_articol, id_gestiune, id_valuta, id_jtva_coloana, taxcode, cont, id_utils, dataoras`. **NU** atinge `id_vanzare_set` — coloana nu apare in lista SET, deci valoarea existenta in DB ramane neschimbata la UPDATE. 3. **Insereaza** liniile noi (`id_vanzare_det = 0`, `:522-540`) — la fel, **fara** `id_vanzare_set` in lista de coloane (linii noi ies cu `id_vanzare_set` implicit NULL in DB). 4. **Doar daca 1-3 au reusit complet** (`IF m.llSucces`, verificat dupa fiecare pas, `EXIT` la primul esec Oracle — deci un esec partial NU ajunge la pasul urmator), cheama procedura Oracle de recalcul totaluri (`:559-563`, vezi §3). Pe o factura din aviz **fara** articole compuse ("seturi"), toate liniile din `tvd` au `id_vanzare_set = 0/NULL` — confirmat de cercetarea anterioara `docs/livrare_s5.md:117-118`: "*Liniile din seturi de articole (id_vanzare_set nenul) — neacoperibil pe datele actuale, nu din omisiune: interogare pe MARIUSM_AUTO, zero documente cu id_vanzare_set nenul*". Deci pentru cazul din screenshot (SSS 100037), branch-ul de "seturi" din view/procedura Oracle (vezi §3) probabil nu se activeaza — **ramane insa NEVERIFICAT direct pe acest document**, n-am rulat SQL pe schema reala. **Nu am gasit nicio scriere directa pe antetul `VANZARI` in `ScrieArticoleFacturaEditate` in afara apelului la procedura Oracle de la pasul 4** — totalurile de antet nu sunt niciodata calculate in VFP, sunt lasate integral pe seama Oracle. ## 3. Procedura Oracle de recalcul — cea mai probabila cauza `ScrieArticoleFacturaEditate` (`ofacturare_editare.prg:559-563`) cheama necondiționat: ``` lcSql = [begin pack_facturare.recalculeaza_totaluri_vanzari(] + Alltrim(Str(m.tnIdVanzare)) + [,] + ; Iif(m.llDiscountNul,[NULL],Alltrim(Str(m.lnDiscount,18,4))) + [); end;] llSucces = goExecutor.oExecuta(m.lcSql) ``` Aceasta procedura este **cod nou**, introdus in exact aceeasi runda de modificari ca bug-ul raportat: - Script-ul care o documenteaza in `SCRIPTURI_CLAR` e `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (comentariu la inceput: "*adauga procedura recalculeaza_totaluri_vanzari*"). - Apelul din VFP a fost adaugat in commit-ul `1c42ae0` din `COMUN` ("*#6 editare factura emisa: S5 - scrierea sumelor editate in Oracle*"), **10.08.2026**, adica o zi dupa ce procedura Oracle a fost capturata in script (09.08.2026) — coerent cu "procedura noua in DB, apoi codul VFP care o cheama". Corpul procedurii (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16024-16228`) face un `SELECT ... INTO` cu agregare (SUM) peste vanzari_detalii/vanzari_seturi — **aceeasi structura** ca formula din `FACT_VFACTURI` (§1): UNION ALL intre liniile normale (`nvl(a.id_vanzare_set,0)=0 and a.id_vanzare=V_ID_VANZARE and a.sters=0`) si liniile "set" (`vanzari_seturi` join `vanzari_detalii`), apoi `SUM(pack_facturare.calculeaza_total_fara_tva_fact(...))` etc. Rezultatul e scris **necondiționat**, fara nicio garda `NVL`: ``` update vanzari set discount = lnDiscountFactura, ... total_fara_tva = lnTotalFaraTVA, total_tva = lnTotalTVA, total_cu_tva = lnTotalCuTVA, ... where id_vanzare = V_ID_VANZARE; ``` (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16211-16223`) Contrast direct cu scriptul de backfill istoric din aceeasi runda (`ff_2026_08_06_12_COMUN_VANZARI_BACKFILL.sql`), care recalculeaza aceleasi coloane dar explicit **"fill-only"**: `v.total_fara_tva = NVL(v.total_fara_tva, src.c_ftva)`, cu comentariu propriu care spune raspicat ca scrierea trebuie sa fie doar completare de goluri, "*niciodata peste o valoare deja scrisa*". `recalculeaza_totaluri_vanzari` **nu are aceasta garda** — daca `SELECT INTO` calculeaza `NULL` pe oricare coloana (SUM peste zero randuri, sau peste randuri toate NULL), UPDATE-ul suprascrie o valoare corecta deja existenta cu NULL. **Cand poate iesi NULL din SUM**: in Oracle, `SUM()` peste un set de randuri produs de un `LEFT JOIN` fara nicio potrivire da NULL (nu 0), iar daca TOATE liniile relevante ale documentului ies cu pret/discount NULL din subquery (de ex. `vanzari_seturi` fara rand pentru `id_vanzare_set`-ul cerut, in branch-ul de "seturi"), rezultatul agregat pe acel document e NULL. Pentru un document fara linii de tip "set" (cazul obisnuit, §2), acest branch nu ar trebui sa se activeze — dar **nu am verificat pe date reale** daca liniile facturii SSS 100037 au ramas cu `sters=0` dupa salvare sau daca vreo alta conditie (curs valutar lipsa in `vanzari_cursuri` pentru `id_valuta`-ul liniei, de ex.) a produs NULL in agregat. ## 4. Regresia, concret — NEVERIFICAT complet, dar convergenta puternica Nu exista fisiere `.bak.vc2` pentru `ofacturare_editare.prg` (bak-urile mentionate in cerere — `omodificari.pre_cantitate.bak.vc2` etc. — sunt pentru `omodificari.vc2`, o clasa diferita; codul de scriere efectiva a articolelor si totalurilor traieste in `ofacturare_editare.prg`, care nu are un `.bak`). Istoricul git (`COMUN`) arata insa clar ca **intreg mecanismul de recalcul al totalurilor pe factura editata e cod nou din 09-10.08.2026** (S5), introdus in acelasi pachet cu extinderea UPDATE-ului mentionata in cerere (`id_articol, id_gestiune, id_valuta, proc_tvav, taxcode, cont, pret_achizitie, discount_unitar, id_jtva_coloana`) — commit-urile ulterioare (S4b etapa 2, 11.08.2026) nu ating aceasta zona. **Ipoteza suspectata explicit de cerere** (UPDATE-ul extins scrie campuri NULL peste linii existente si strica `id_vanzare_set`/`id_vanzare_det`) **NU se confirma din citirea codului**: UPDATE-ul de la pasul 2 (§2) nu atinge deloc coloana `id_vanzare_set`, iar `id_vanzare_det` e folosit doar in clauza `WHERE`, niciodata scris. Round-trip-ul cursorului `tvd` (incarcat din `VVANZARI_ARTICOLE`, view 1:1 pe `vanzari_detalii` — vezi `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql`, fara nicio agregare) e coerent camp cu camp. **Cauza cea mai probabila, cu incredere medie-mare**: nu o eroare in codul VFP de scriere a liniilor, ci procedura Oracle noua `pack_facturare.recalculeaza_totaluri_vanzari` (§3) — cod introdus in aceeasi runda, apelat necondiționat dupa fiecare salvare de factura editata din formularul unificat, care scrie fara garda NULL peste coloanele de total din `VANZARI`. Pe "vizualizarea standard" (`FACT_VFACTURI`), acelasi tip de agregare NULL-propagabila se repeta live la fiecare afisare a listei, deci simptomul ar aparea indiferent care view e activ. ## 5. Trigger/procedura declansata la INSERT — nu se aplica aici Nu exista trigger Oracle care sa recalculeze totalurile la INSERT in `vanzari_detalii` — scrierea e facuta explicit, o singura data, prin apelul manual la `recalculeaza_totaluri_vanzari` de la finalul lui `ScrieArticoleFacturaEditate` (§3). Punctul 4 din cererea initiala nu se aplica. ## Reparatie propusa (fara aplicare) Minimal, in `D:\ROA\DATABASE\SCRIPTURI_CLAR\...\PACK_FACTURARE.sql` / `recalculeaza_totaluri_vanzari`: inlocuit UPDATE-ul necondiționat cu varianta "fill-safe" folosita deja in scriptul de backfill — fie NVL pe fiecare coloana (`total_fara_tva = NVL(lnTotalFaraTVA, total_fara_tva)` etc., pastreaza valoarea veche daca recalculul da NULL), fie un `RAISE`/log explicit cand agregatul iese NULL, ca sa nu treaca neobservat. Inainte de asta, e nevoie de o verificare directa pe schema reala (SQL pe `vanzari_detalii`/`vanzari_seturi` pentru `id_vanzare`-ul facturii SSS 100037) ca sa se confirme ce ramura produce NULL — recomand asta ca prim pas al oricarei remedieri, nu modificarea pe ghicite. ## Ce ramane NEVERIFICAT (runda 1) - Ce optiune de vizualizare (standard/experimentala) a fost activa la momentul screenshot-ului. - Continutul real al `vanzari_detalii`/`vanzari_seturi` pentru factura SSS 100037 dupa editare — **verificat in runda 2** (mai jos), pe baza interogarilor SQL facute de team-lead + interogari proprii read-only, cu `sqlplus`. --- # Runda 2 — cauza confirmata prin SQL pe date reale Team-lead a interogat direct Oracle (`MARIUSM_AUTO@ROA_CENTRAL`) si a stabilit cauza imediata: linia `VANZARI_DETALII.id_vanzare_det = 1602` (singura linie activa a facturii `id_vanzare = 1054`, SSS 100037) are `ID_VALUTA = 2` (EURO), desi documentul e `IN_VALUTA = 0` si linia-sursa din aviz avea `ID_VALUTA = 3` (RON). `VANZARI_CURSURI` nu are niciun rand pentru `id_vanzare = 1054`, deci `recalculeaza_totaluri_vanzari` calculeaza `pret_ron = NULL` pentru acea linie (branch-ul de conversie valutara, fara curs) si `total_fara_tva/total_tva/total_cu_tva` ies `NULL`. Am confirmat independent, cu SQL read-only propriu (`sqlplus`, vezi mai jos), amploarea si mecanismul. ## 1. Cine scrie `id_valuta` pe linia de articol — CONFIRMAT Singura cale prin care `tvd.id_valuta` se schimba pe o linie **existenta** e nomenclatorul de valuta din grid: `ArticoleNotaEditor.ModificaNomenclator`, ramura `nume_val` (`COMUN\programe\ofacturare_editare.prg:1093-1094`): ``` CASE m.lcCamp == 'nume_val' REPLACE nume_val WITH loCauta.nume_val, id_valuta WITH loCauta.id_valuta ``` `loCauta = caut_valuta()` — nomenclatorul standard de valute, deschis fara nicio conditie legata de `tvanz.in_valuta`. Singura garda de la inceputul procedurii (`:1069`) e `Nvl(tvd.id_vanzare_set,0) <> 0` (blocheaza doar liniile din seturi de articole) — **nu exista nicio garda legata de tipul documentului**, deci utilizatorul poate alege orice valuta pe orice linie normala, indiferent daca factura e in RON sau in valuta. UPDATE-ul care duce `id_valuta` in `VANZARI_DETALII` e in `ScrieArticoleFacturaEditate` (`COMUN\programe\ofacturare_editare.prg:512`): ``` [, id_valuta = ] + Iif(Isnull(id_valuta),[NULL],Alltrim(Str(id_valuta))) + ; ``` **Confirmat prin diff cu `COMUN\programe\ofacturare_editare.prg.pre_runda_butoane.bak:501-505`**: inainte de runda curenta, UPDATE-ul pe liniile existente scria doar `sters, cantitate, pret, pret_cu_tva, id_utils, dataoras` — **`id_valuta` nu era in lista**. Deci inainte, o alegere de valuta pe o linie existenta (facuta prin `nume_val`) se pierdea silentios la salvare (UI arata schimbarea, dar UPDATE-ul n-o scria) — inofensiv, dar si fara efect. Extinderea UPDATE-ului (runda curenta, aceeasi runda care a adaugat si `recalculeaza_totaluri_vanzari`, vezi runda 1 §3-4) e cea care face ca alegerea gresita de valuta sa ajunga acum in `VANZARI_DETALII` si sa strice totalurile. **Simptomul e nou din exact acest motiv — confirmat pe cod, nu presupunere.** ## 2. Ce ar trebui sa fie corect pe un document `in_valuta = 0` — CONFIRMAT `VANZARI_CURSURI` e scris o singura data, la EMITERE, de `pack_facturare.scrie_cursuri` (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:14538-14548`): ```sql PROCEDURE scrie_cursuri(V_ID_VANZARE IN NUMBER) IS BEGIN INSERT INTO VANZARI_CURSURI (ID_VANZARE, ID_VALUTA, CURS, MULTIPLICATOR) SELECT DISTINCT V_ID_VANZARE, ID_VALUTA, CURS, MULTIPLICATOR FROM VANZARI_DETALII_TEMP WHERE ID_VALUTA <> pack_facturare.nid_moneda_nationala; END scrie_cursuri; ``` Sursa e tabela de STAGING folosita la emitere (`VANZARI_DETALII_TEMP`), nu `VANZARI_DETALII` live — deci **nu exista niciun mecanism care sa adauge/actualizeze `VANZARI_CURSURI` cand se schimba `id_valuta` pe o linie DUPA emitere**, din editarea unificata sau din oricare alt punct. Raspuns direct la intrebare: **da, e conceptual posibil ca o linie sa aiba alta valuta decat RON pe un document in lei** (mecanismul de facturare mixta exista, cu curs propriu per linie in `VANZARI_CURSURI`) — dar **doar daca acea alegere s-a facut la emitere**, cand `scrie_cursuri` inca ruleaza si scrie perechea `(id_vanzare, id_valuta) -> curs`. O schimbare **post-emitere**, prin editarea unificata, nu are nicio cale sa creeze acel rand — deci orice `id_valuta` diferit de RON ales dupa emitere e, prin constructie, orfan (fara curs), garantand `pret_ron = NULL` in `recalculeaza_totaluri_vanzari`. ## 3. Toate caile prin care agregatele pot iesi NULL — enumerare + masurare pe date reale Din citirea corpului `recalculeaza_totaluri_vanzari` (`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:16024-16228`): 1. **Zero randuri active in `VANZARI_DETALII`** pentru `id_vanzare` (toate `sters=1`, sau document fara nicio linie) — `SUM()`/`MAX()` peste zero randuri = NULL pentru toate coloanele. 2. **Linie cu `id_valuta` diferit de moneda nationala, fara rand in `VANZARI_CURSURI`** pentru acea pereche `(id_vanzare, id_valuta)` — cazul masurat mai jos (Marius). `LEFT JOIN vc` nu gaseste nimic, `vc.curs`/`vc.multiplicator` = NULL, `pret_ron` = NULL pentru acea linie. Daca **toate** liniile documentului sunt afectate, `SUM()` total iese NULL; daca doar unele, `SUM()` ignora randurile NULL si totalul iese **trunchiat, nu NULL** (lipseste contributia liniei respective, fara sa fie vizibil ca eroare). 3. **Linie din "set de articole" (`id_vanzare_set <> 0`) fara rand corespunzator in `VANZARI_SETURI`** — acelasi tipar ca #2, prin `LEFT JOIN vanzari_seturi b`. Neconfirmat pe date reale (branch aproape neutilizat — vezi `docs/livrare_s5.md:117-118`, zero documente cu `id_vanzare_set` nenul cunoscute anterior). 4. **`VANZARI.in_valuta` NULL** — `nvl(lnInValuta,-1) > -1` devine fals, exclude tot branch-ul de "seturi"; nu produce NULL pe branch-ul normal, dar poate goli branch-ul 2 pe un document compus doar din linii de set. 5. **Argument NULL in `pack_facturare.calculeaza_total_fara_tva_fact`/`_tva_fact`** (ex. `proc_tvav` sau `cantitate` NULL pe o linie) — acelasi tipar trunchiat/total, dupa cate linii sunt afectate. **Masurat pe schema reala** (`MARIUSM_AUTO@ROA_CENTRAL`, SELECT-uri read-only, script-urile folosite raman in `scratchpad`, nu s-a scris nimic in baza): | Categorie (din cele 235 `VANZARI.total_cu_tva IS NULL`) | Numar documente | |---|---| | Total `VANZARI` cu `total_cu_tva IS NULL` | **235** | | Fara nicio linie activa in `VANZARI_DETALII` (cauza #1, veche — carve-out cunoscut, vezi `ff_2026_08_06_12_COMUN_VANZARI_BACKFILL.sql`, "facturile fara nicio linie activa raman neatinse, prin decizie de produs") | **120** | | Linie cu `id_valuta` diferit de RON si fara rand in `VANZARI_CURSURI` (cauza #2 — **exact bug-ul curent**) | **1** (chiar SSS 100037 / `id_vanzare=1054`, confirmat `IN_VALUTA=0`) | | Neexplicat de #1 sau #2 (alta cauza, preexistenta, in afara scopului acestei cercetari) | **114** — din acestea, 109 au `VANZARI.discount_evidentiat IS NULL` (posibil o cauza separata, nelegata de `id_valuta`; neinvestigat in continuare, iese din scopul cererii) | **Concluzie importanta**: bug-ul de `id_valuta` orfan e **izolat la 1 singur document in toata baza**, in acest moment — consistent cu faptul ca UPDATE-ul extins care il face vizibil e cod de cateva zile (runda curenta). Nu e nevoie de o reparare in masa; celelalte 234 de documente cu total NULL au alta cauza (majoritar #1, cunoscuta si acceptata prin design) si nu trebuie atinse de reparatia acestui bug. ## 4. Reparatie propusa, in trei straturi (fara aplicare) ### Client (VFP) In `ArticoleNotaEditor.ModificaNomenclator` (`COMUN\programe\ofacturare_editare.prg:1069`), extinde garda existenta ca sa blocheze nomenclatorul de valuta pe liniile unui document care nu e in valuta: ``` IF !This.Editabil() OR Reccount('tvd') = 0 OR !This.AreNomenclator(m.lcCamp) OR Nvl(tvd.id_vanzare_set, 0) <> 0 ; OR (m.lcCamp == 'nume_val' AND Nvl(tvanz.in_valuta,0) <> 1) RETURN .F. ENDIF ``` (presupune ca `tvanz` e vizibil din contextul clasei — de verificat la implementare; alternativ, o proprietate `This.oForm.lDocInValuta` populata la incarcare). Efect: pe o factura in RON, coloana `nume_val` devine needitabila, la fel ca liniile din seturi — elimina posibilitatea de a introduce `id_valuta` orfan prin UI. ### DB — `recalculeaza_totaluri_vanzari` Doua schimbari, ambele minime: 1. **Restrange conditia de conversie** la cazul in care documentul insusi e in valuta, nu cand linia are o valuta diferita de RON pe un document RON (elimina exact vulnerabilitatea gasita): ```sql -- inainte: (case when (lnInValuta = 1 or vd.id_valuta <> pack_def.GetIdMonedaNationala()) then ROUND(vc.curs * vd.pret / vc.multiplicator, lnPreciziePretV) else vd.pret end) as pret_ron -- dupa: (case when lnInValuta = 1 then ROUND(NVL(vc.curs,1) * vd.pret / NVL(vc.multiplicator,1), lnPreciziePretV) else vd.pret end) as pret_ron ``` Motivatie: pe un document `in_valuta=0`, `vd.pret` e prin definitie deja in RON (asa scrie `ScrieArticoleFacturaEditate` liniile, indiferent de `id_valuta` afisat) — conversia n-are ce sa faca acolo, indiferent ce `id_valuta` a ajuns (corect sau nu) pe linie. Pastrez `NVL(vc.curs,1)` doar ca ultima plasa de siguranta pe ramura `lnInValuta=1` (document CHIAR in valuta) — daca acolo lipseste cursul e o eroare de date reala care merita semnalata, nu ascunsa; de discutat cu Marius daca `NVL(...,1)` e acceptabil acolo sau daca ar trebui sa opreasca salvarea cu eroare in loc sa scrie o suma gresita tacut. **Nu propun `NVL` necondiționat pe ramura de conversie reala** — ar masca o factura in valuta cu curs lipsa, scriind un total fals dar nenul, mai greu de observat decat un NULL. 2. **Plasa finala de siguranta la UPDATE**, dupa modelul "fill-safe" deja folosit in `ff_2026_08_06_12_COMUN_VANZARI_BACKFILL.sql`, ca sa nu se mai poata suprascrie tacut o valoare corecta cu NULL, indiferent ce cauza noua ar aparea in viitor: ```sql update vanzari set total_fara_tva = NVL(lnTotalFaraTVA, total_fara_tva), total_tva = NVL(lnTotalTVA, total_tva), total_cu_tva = NVL(lnTotalCuTVA, total_cu_tva), ... where id_vanzare = V_ID_VANZARE; ``` Cu un `dbms_output`/log undeva (tabela de erori aplicative, daca exista una) cand recalculul iese NULL, ca sa nu treaca neobservat un caz nou. ### Date (script propus, NU RULAT) ```sql -- 1. Corectie punctuala pentru SSS 100037 (id_vanzare=1054): id_valuta-ul liniei 1602 revine la -- RON, aliniat cu documentul (in_valuta=0) si cu linia-sursa din aviz (id_vanzare_det=1599, -- care avea deja id_valuta=3). UPDATE VANZARI_DETALII SET ID_VALUTA = pack_def.GetIdMonedaNationala() WHERE ID_VANZARE_DET = 1602 AND ID_VANZARE = 1054; COMMIT; -- 2. Retrigger recalcul dupa fix (acelasi apel pe care il face si formularul la salvare) BEGIN pack_facturare.recalculeaza_totaluri_vanzari(1054); END; / COMMIT; ``` Restrans STRICT la acest document — cele 234 de alte randuri cu total NULL au alta cauza (§3) si nu intra in scopul acestei reparatii. Daca se doreste o baleiere completa dupa ce fix-ul de la client e livrat (sa nu mai apara alte cazuri noi), propun mai intai o interogare de monitorizare periodica (varianta de query C/F de mai sus), nu o corectie automata in masa. ## Ce ramane NEVERIFICAT (runda 2) - Cauza celor 114 documente "neexplicate" (mult mai vechi, posibil legate de `discount_evidentiat IS NULL`) — iese din scopul cererii, semnalez doar ca exista. - Daca `tvanz` e efectiv vizibil ca alias in contextul `ArticoleNotaEditor.ModificaNomenclator` la momentul apelului (necesar pentru fix-ul de client propus) — de verificat la implementare, nu am urmarit domeniul complet de vizibilitate al claselor `.vc2`.