Cercetarile si propunerile rundelor 4-6 pe editarea facturii emise. Starea rundei 6 si ce s-a stabilit intra in progres.md. Nou: docs/conventii_mediu_oracle.md - pe dev/test se lucreaza numai cu ROA_CENTRAL si schemele CONTAFIN_ORACLE si MARIUSM_AUTO; schema ACN nu se foloseste. Scripturile de pachet sunt necalificate, deci schema tinta o decide sirul de conectare, nu fisierul. roafacturare.pj2 regenerat de git_sync. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013gYCNE26G1G7UoGu2ju7aS
23 KiB
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_CENTRALa inchis intre timp intrebarea: linia facturii areID_VALUTA = 2(EURO) fara rand corespunzator inVANZARI_CURSURI, iar ramura de conversie valutara a procedurii produce NULL. Concluzia si reparatia sunt indocs\propunere_runda5_articole_valuta_rate.md, punctul 2. Ce ramane valabil aici: analiza lantului de scriere si infirmarea ipotezei cuid_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 \<standard;Vizualizare \<experimentala (mai rapida)')
If m.lnOptiune = 1
Do vizualizare_facturi In oproceduri_facturare.prg && FACT_VFACTURI
Else
Do vizualizare_facturi2 In oproceduri_facturare.prg && FACT_VFACTURI2
Endif
Cele doua proceduri (COMUN\programe\oproceduri_facturare.prg:314 si :398) selecteaza
total_fara_tva, total_tva, total_cu_tva din doua view-uri Oracle diferite cu semantica
diferita — asta e cheia problemei:
FACT_VFACTURI("standard"): coloanele sunt calculate live, printr-unSUM(...)pestevanzari_detalii(sivanzari_seturipentru liniile de tip set). Nu citeste niciodata coloanele stocate dinVANZARI. Definitie:D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_06_11_COMUN_FACT_VFACTURI.sql:192-194(a.suma_fara_tva - a.disc_fara_tva_ron as total_fara_tva, etc.), agregarea la:408-460(subqueryvd,LEFT JOINintrev.id_vanzaresi rezultatul agregat).FACT_VFACTURI2("experimentala"): coloanele sunt citite direct dinVANZARI(coloane stocate), fara recalcul la interogare — comentariul din cod spune explicit de ce: "totalurile ... sunt calculate in vanzari, in loc sa fie luate din vanzari_detalii, pentru rapiditate; totalurile sunt completate in vanzari la insert into vanzari" (COMUN\programe\oproceduri_facturare.prg:397-399). Definitie view:ff_2026_08_06_11_COMUN_FACT_VFACTURI.sql:682-684(a.total_fara_tva, a.total_tva, a.total_cu_tvadinvanzari a).
NEVERIFICAT: nu stiu ce optiune a ales Marius la momentul screenshot-ului (standard sau
experimentala) — promptul e interactiv, nu am gasit un default hard-codat. Concluzia de mai jos
e valabila pentru amandoua variantele, din motive diferite (vezi §3).
2. Ce scrie salvarea din formularul unificat pe partea de factura
ScrieArticoleFacturaEditate (COMUN\programe\ofacturare_editare.prg:473-571), apelata cu
tvanz.id_vanzare (id-ul corect al FACTURII, verificat — tvanz vine din
IncarcaVanzareNota/IncarcaVanzareDinNota, care interogheaza VANZARI dupa
cod/nract/serie_act/data_act ale notei editate, deci nu e confuzie aviz/factura; apelurile reale
sunt in COMUN\clase\comun.vc2:2492 si COMUN\clase\ofacturare_comun.vc2:3829, ambele in ramura
"OFACTURARE_EDITARE" $ Upper(Set("Procedure"))):
- Marcheaza sters=1 TOATE liniile active din
vanzari_detaliipentru acelid_vanzare(:492-495). - Reinvie/actualizeaza liniile pastrate, cele cu
id_vanzare_det > 0din cursorultvd(:498-518) — UPDATE pe cheiaid_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 atingeid_vanzare_set— coloana nu apare in lista SET, deci valoarea existenta in DB ramane neschimbata la UPDATE. - Insereaza liniile noi (
id_vanzare_det = 0,:522-540) — la fel, faraid_vanzare_setin lista de coloane (linii noi ies cuid_vanzare_setimplicit NULL in DB). - Doar daca 1-3 au reusit complet (
IF m.llSucces, verificat dupa fiecare pas,EXITla 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_CLAReD:\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
1c42ae0dinCOMUN("#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_seturipentru factura SSS 100037 dupa editare — verificat in runda 2 (mai jos), pe baza interogarilor SQL facute de team-lead + interogari proprii read-only, cusqlplus.
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):
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):
- Zero randuri active in
VANZARI_DETALIIpentruid_vanzare(toatesters=1, sau document fara nicio linie) —SUM()/MAX()peste zero randuri = NULL pentru toate coloanele. - Linie cu
id_valutadiferit de moneda nationala, fara rand inVANZARI_CURSURIpentru acea pereche(id_vanzare, id_valuta)— cazul masurat mai jos (Marius).LEFT JOIN vcnu 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). - Linie din "set de articole" (
id_vanzare_set <> 0) fara rand corespunzator inVANZARI_SETURI— acelasi tipar ca #2, prinLEFT JOIN vanzari_seturi b. Neconfirmat pe date reale (branch aproape neutilizat — vezidocs/livrare_s5.md:117-118, zero documente cuid_vanzare_setnenul cunoscute anterior). VANZARI.in_valutaNULL —nvl(lnInValuta,-1) > -1devine 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.- Argument NULL in
pack_facturare.calculeaza_total_fara_tva_fact/_tva_fact(ex.proc_tvavsaucantitateNULL 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:
-
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):
-- 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_ronMotivatie: pe un document
in_valuta=0,vd.prete prin definitie deja in RON (asa scrieScrieArticoleFacturaEditateliniile, indiferent deid_valutaafisat) — conversia n-are ce sa faca acolo, indiferent ceid_valutaa ajuns (corect sau nu) pe linie. PastrezNVL(vc.curs,1)doar ca ultima plasa de siguranta pe ramuralnInValuta=1(document CHIAR in valuta) — daca acolo lipseste cursul e o eroare de date reala care merita semnalata, nu ascunsa; de discutat cu Marius dacaNVL(...,1)e acceptabil acolo sau daca ar trebui sa opreasca salvarea cu eroare in loc sa scrie o suma gresita tacut. Nu propunNVLnecondiț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. -
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: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)
-- 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
tvanze efectiv vizibil ca alias in contextulArticoleNotaEditor.ModificaNomenclatorla momentul apelului (necesar pentru fix-ul de client propus) — de verificat la implementare, nu am urmarit domeniul complet de vizibilitate al claselor.vc2.