24 KiB
S10 — Pretul re-derivat in adauga_articol_factura, ramura cu ramura
Nota pe sursa folosita
docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql nu exista (nici in docs\, nici urme in
istoricul git — docs\ e integral netracked). Fisierul cu acelasi nume exista insa la
D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql si a fost folosit
ca sursa. Continutul adauga_articol_factura coincide structural cu ce descrie planul (aceeasi
ordine de ramuri, aceleasi coduri de eroare FACT-012/013/018, acelasi DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR)), dar liniile sunt deplasate cu +17 fata de citatele din plan
(corp 4989-5284 aici vs. 4972-5268 in plan; ramura de contract 5146-5185 aici vs. :5129-5168
in plan) — probabil diferente de comentarii de antet intre cele doua exporturi. Toate citatele de mai
jos sunt pe fisierul din SCRIPTURI_CLAR, verificat direct.
Verdict (raspuns la intrebarea 4 — reemiterea)
Da, exista o ramura care suprascrie tacut pretul la orice apel, inclusiv la o eventuala
reemitere: liniile provenite dintr-un contract cu OPT_FACTURARE = 3 (sau NULL, care se
implicit-eaza tot la 3). Procedura nu are nicio notiune de "reemitere" — la fiecare apel cu acelasi
V_ID_CTR, daca articolul are in CTR_ARTICOLE.PRET_UNITAR o valoare diferita de 0, acea valoare
inlocuieste pretul trimis de VFP (V_PRET_TEMP), necontidionat de faptul ca linia a fost sau nu
atinsa de utilizator pe ecran. Riscul se materializeaza doar daca pretul din contract s-a schimbat
intre emiterea initiala si reemitere — daca n-a scazut, rezultatul e identic si nimeni nu observa
diferenta pana cand se schimba. Pe toate celelalte ramuri (implicita, restaurant), pretul trimis de
VFP e respectat ca atare. Nu exista niciun parametru sau flag care sa opreasca re-derivarea —
raspunsul la intrebarea 5 e "nu exista".
1. Semnatura completa (corp, nu spec)
PACK_FACTURARE:4989-5015 (spec identica la :537-563, verificat doar ca prezenta, nu citat):
PROCEDURE adauga_articol_factura(V_ID_TEMP IN NUMBER,
V_ID_ARTICOL IN NUMBER,
V_SERIE IN VARCHAR2,
V_EXPLICATIE IN VARCHAR2,
V_ID_POL IN NUMBER,
V_ID_GESTIUNE IN NUMBER,
V_PRET_ACHIZITIE_TEMP IN NUMBER,
V_PRETD IN NUMBER,
V_ID_VALUTAD IN NUMBER,
V_PRET_TEMP IN NUMBER,
V_ID_VALUTA_TEMP IN NUMBER,
V_PRETURI_CU_TVA_TEMP IN NUMBER,
V_IN_STOC_TEMP IN NUMBER,
V_CANTITATE IN NUMBER,
V_DISCOUNT_UNITAR IN NUMBER,
V_CONT IN VARCHAR2,
V_CURS IN NUMBER,
V_MULTIPLICATOR IN NUMBER,
V_ID_JTVA_COLOANA IN NUMBER,
V_ID_PART_REZ IN NUMBER,
V_ID_LUCRARE_REZ IN NUMBER,
V_PRETV_ORIG IN NUMBER,
V_ID_VANZARE_SET IN NUMBER,
V_ID_CTR IN NUMBER,
V_ID_UTIL IN NUMBER,
V_TAXCODE IN NUMBER DEFAULT NULL,
V_LOT IN VARCHAR2 DEFAULT NULL) IS
Toti parametrii sunt IN, niciunul OUT/IN OUT — nu exista un canal de intoarcere a pretului recalculat catre VFP la momentul apelului (linia se citeste ulterior, la re-interogarea grilei).
V_OPT_FACTURARE nu e parametru. E o variabila locala (:5029), calculata in interiorul
procedurii din CONTRACTE.OPT_FACTURARE, folosind parametrul V_ID_CTR primit de la VFP
(:5039-5050):
IF pack_facturare.ntip IN (2, 6, 26, 52) THEN
BEGIN
SELECT NVL(OPT_FACTURARE, 3) INTO V_OPT_FACTURARE FROM CONTRACTE WHERE ID_CTR = V_ID_CTR;
EXCEPTION
WHEN NO_DATA_FOUND THEN
V_OPT_FACTURARE := 4;
END;
END IF;
VFP nu trimite si nu poate influenta V_OPT_FACTURARE altfel decat prin V_ID_CTR (poArt.id_ctr,
trimis NULL cand linia nu vine de pe contract). Pentru orice pack_facturare.ntip in afara lui
(2, 6, 26, 52), V_OPT_FACTURARE ramane neinitializat (blocul IF nu ruleaza deloc) — echivalent
cu "nu conteaza", ramura de contract nu se poate nimeri.
2. Ce inseamna V_OPT_FACTURARE si cum se coreleaza cu VFP
Din PACK_FACTURARE (alte proceduri, aceeasi coloana CONTRACTE.OPT_FACTURARE) si din
COMUN\clase\ofacturare.vc2 / COMUN\programe\oproceduri_facturare.prg (proprietatea locala
poArt.opt_facturare, populata la citirea contractului, in oglinda cu coloana Oracle):
| Valoare | Tip facturare | Dovada |
|---|---|---|
0 (sau lipsa contract) |
Articol normal, nelegat de contract | ofacturare.vc2:13055 If poArticol.opt_facturare = 0 |
1, 2 |
Rata (scadentar contract, CTR_SCADENTAR) — linia nu trece prin adauga_articol_factura, ci prin adauga_rata_factura (ofacturare.vc2:14041-14050) |
ofacturare.vc2:14041 If Inlist(poArt.opt_facturare,1,2); PACK_FACTURARE:2898,2915 (CTR_SCADENTAR, doar pt. OPT_FACTURARE IN (1,2)) |
3 |
Articol de pe contract, pret din CTR_ARTICOLE |
PACK_FACTURARE:2699,2820 (CTR_ARTICOLE doar pt. OPT_FACTURARE = 3); ofacturare.vc2:14750 (poDate.tip = 2 And poArticol.opt_facturare = 3) |
4 |
Fallback intern cand contractul nu (mai) exista (NO_DATA_FOUND) |
PACK_FACTURARE:5047-5048 |
VFP nu trimite V_OPT_FACTURARE ca parametru al adauga_articol_factura — coreleaza doar indirect,
prin faptul ca proprietatea locala poArt.opt_facturare (citita din acelasi CONTRACTE.OPT_FACTURARE
cand grila s-a populat) decide ce RPC se apeleaza (adauga_rata_factura pentru 1/2,
adauga_articol_factura pentru orice altceva, inclusiv 3), nu ce ramura Oracle se executa in interior
— aceea o recalculeaza serverul singur, din V_ID_CTR.
3. Ramura cu ramura pe V_OPT_FACTURARE (si pe pack_facturare.ntip, care are prioritate)
CASE la PACK_FACTURARE:5052-5220. Ramurile 1-3 sunt selectate dupa pack_facturare.ntip, nu
dupa V_OPT_FACTURARE — ramura 4 (contract) se testeaza doar daca niciuna din primele trei nu s-a
potrivit.
| Selector | Tip facturare | Pretul | Sursa re-derivarii | Citat |
|---|---|---|---|---|
ntip IN (3,21,28,42,47) |
Facturare/aviz din comenzi | Re-derivat, dar constrans sa se potriveasca cu ce a trimis VFP — SELECT A.PRET ... WHERE A.PRET = V_PRET_TEMP |
COMENZI_ELEMENTE + CRM_POLITICI_PRETURI/PRET_ART, filtrat pe A.PRET = V_PRET_TEMP; daca nu exista rand cu exact acel pret, NO_DATA_FOUND nu e tratat — procedura pica cu eroare Oracle netratata |
:5053-5078 |
ntip = 4 |
Facturare din avize | Re-derivat necondiționat, din documentul sursa — SELECT DISTINCT A.PRET ... INTO V_PRET fara filtru pe pretul trimis |
VANZARI_DETALII (linia din avizul sursa), filtrata pe articol/politica/gestiune/discount/cont, dar nu pe pret |
:5080-5103 |
ntip = 45 |
Facturare restaurant | Respectat — V_PRET := V_PRET_TEMP setat inainte de SELECT (:5109); SELECT-ul recalculeaza doar V_PROC_TVAV si V_PRET_ACHIZITIE (cost, nu pret de vanzare) |
n/a pentru pret; TVA din JTVA_COLOANE, cost din CRM_POLITICI_PRET_ART.PRETFTVA |
:5104-5145 |
V_OPT_FACTURARE = 3 (deci ntip IN (2,6,26,52) si contract cu OPT_FACTURARE=3/NULL) |
Facturare/aviz de pe contract | Re-derivat daca contractul are pret setat — DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR); daca PRET_UNITAR = 0 sau nu exista rand CTR_ARTICOLE/politica potrivita (NO_DATA_FOUND), cade pe V_PRET_TEMP |
CTR_ARTICOLE.PRET_UNITAR (prin CRM_POLITICI_PRET_ART, ID_POL_ART) |
:5146-5185 (branch), :5181-5184 (fallback V_PRET_TEMP in exceptie) |
ELSE (implicit — orice altceva, inclusiv linii normale fara contract) |
Standard | Respectat — V_PRET := V_PRET_TEMP |
n/a; TVA din JTVA_COLOANE dupa V_ID_JTVA_COLOANA trimis de VFP |
:5187-5203 |
Observatie de prioritate: daca o linie e simultan "din comanda" (ntip IN (3,21,28,42,47)) si
are si V_ID_CTR completat, ramura de comenzi castiga — V_OPT_FACTURARE nici nu se calculeaza
(blocul de la :5039 ruleaza doar pentru ntip IN (2,6,26,52)). Ramurile nu se pot suprapune in
productie curenta, dar asta inseamna ca orice extindere viitoare a lui ntip (de ex. daca #13
introduce un tip nou de document care refoloseste adauga_articol_factura pentru reemitere) trebuie
verificata explicit fata de acest CASE — un ntip nou care nu intra in niciuna din listele
(3,21,28,42,47) / 4 / 45 cade automat fie pe ramura de contract (daca are V_ID_CTR), fie pe
ELSE.
4. Reemiterea — detaliu (vezi si verdictul de mai sus)
Procedura nu primeste si nu poate primi vreun semnal de tip "acesta e un apel de reemitere, nu
recalcula". Comportamentul e identic la emiterea initiala si la orice apel ulterior cu aceiasi
parametri. Riscul descris in plan (sectiunea H) se confirma integral pentru ramura de contract
(V_OPT_FACTURARE = 3): daca CTR_ARTICOLE.PRET_UNITAR s-a modificat intre emiterea initiala si
reemitere, factura reemisa va lua pretul curent din contract, nu pretul confirmat pe ecran de
utilizator inainte de reemitere — chiar daca utilizatorul n-a atins linia.
Pentru ramurile "avize" (ntip = 4) si "comenzi" (ntip IN (3,21,28,42,47)), acelasi risc structural
exista (pretul se re-citeste din documentul sursa la fiecare apel), dar nu sunt cazul confirmat de
#13 — planul S10 spune explicit "se verifica pe factura din contract, care e cazul confirmat" — nu
s-a cerut si nu s-a facut inventar suplimentar pentru daca fluxul de reemitere din #13 (etapa II,
stergere+regenerare cu aceleasi linii) ar trece vreodata prin aceste doua ramuri. De retinut daca
#13 extinde reemiterea si la facturi/avize provenite din comanda sau din alt aviz — pe ambele,
re-derivarea e chiar mai stricta decat pe contract (ramura de comenzi cade cu eroare netratata daca
pretul nu se potriveste exact; ramura de avize suprascrie necondiționat).
5. Mecanism de "nu re-deriva"
Nu exista. Niciun parametru boolean, nicio valoare santinela, nicio ramura in CASE
(:5052-5220) care sa respecte pretul primit pentru ca i s-a cerut explicit. Ramurile "implicita"
si "restaurant" respecta pretul doar pentru ca structural nu au de unde re-deriva altceva (nu exista
document sursa de recitit), nu pentru ca ar exista o comutare intentionata. Orice solutie de tip
"pretul vine din formular, nu se re-deriva" (cum sugereaza planul, sectiunea H) ar trebui
implementata in VFP inainte de apel (de exemplu, nu retrimite V_ID_CTR la reemitere daca vrei sa
eviti ramura de contract) — nu exista un parametru in pachet pe care VFP l-ar putea seta ca sa
dezactiveze re-derivarea, iar pachetul nu se modifica (decizia 27-bis, respectata — aceasta e o
constatare, nu o propunere).
6. Discountul si TVA-ul
- Discountul (
V_DISCOUNT_UNITAR) nu e niciodata re-derivat. Parametrul intra direct inINSERT INTO VANZARI_DETALII_TEMP (..., DISCOUNT_UNITAR, ...) VALUES (..., V_DISCOUNT_UNITAR, ...)(:5236,:5266) — nicio ramura dinCASEil citeste sau il modifica. Tratament diferit de pret: discountul e mereu respectat, indiferent de ramura. - TVA-ul (
V_PROC_TVAV) e mereu recalculat server-side, pe toate ramurile — dar din surse diferite, nu dintr-un parametru brut. Nu exista parametruV_PROC_TVAV_TEMPin semnatura; VFP trimite doarV_ID_JTVA_COLOANA(un identificator de coloana de cota, nu cota insasi). Pe ramura implicita si pe cea de contract-fara-potrivire, cota se cauta inJTVA_COLOANEdupa acel ID (:5188-5198,:5169-5179); pe ramurile comenzi/avize/contract-cu-potrivire/restaurant, cota vine din documentul sursa sau din politica de pret (:5058,:5083,:5150,:5114). Deci TVA-ul are un tratament mai strict decat pretul: niciodata "pass-through" direct, intotdeauna o cautare, doar sursa cautarii difera pe ramura.
7. Cursul valutar si pretul in valuta
- Cursul (
V_CURS) e mereu respectat ca valoare, pe toate ramurile. Singura procesare eDECODE(V_CURS, 0, 1, V_CURS)laINSERT(:5270) — inlocuieste 0 cu 1, altfel scrie exact ce a trimis VFP. Procedura nu interogheaza niciodata tabelaCURSpentru un curs "de azi" — nu are de unde sa recalculeze cursul chiar daca ar vrea. - Identitatea valutei (
V_ID_VALUTA, variabila locala, nu parametrulV_ID_VALUTAD) urmeaza acelasi tipar ca pretul, ramura cu ramura: re-derivata din sursa pe comenzi (C.ID_VALUTA,:5059) si avize (A.ID_VALUTA,:5084), re-derivata din contract pe ramuraV_OPT_FACTURARE=3(B.ID_VALUTA,:5151, cu fallbackV_ID_VALUTA_TEMPin exceptie,:5182), respectata pe implicita si restaurant (V_ID_VALUTA := V_ID_VALUTA_TEMP,:5110,:5201). - Consecinta pentru reemiterea unui document in valuta pe contract: daca politica de pret a
contractului (
CRM_POLITICI_PRET_ART, prinCTR_ARTICOLE.ID_POL_ART) a fost schimbata intre timp la o alta valuta, reemiterea ar scrie articolul in noua valuta a politicii, dar cu cursul trimis de VFP (posibil cursul valutei vechi, daca VFP nu a fost actualizat sa retrimita cursul corect pentru noua valuta) — o sursa suplimentara de neconcordanta, nesemnalata explicit in plan. Nu s-a gasit nicio validare in procedura care sa verifice caV_CURScorespunde valutei re-derivateV_ID_VALUTA.
Completare: nota contabila a politicii
Sursa: aceeasi, contabilizeaza_articol la PACK_FACTURARE:7173-7547 (in fisierul din
SCRIPTURI_CLAR; corpul relevant pentru articol simplu — nu compus — e la :7391-7544), plus
scrie_nota la :12329-12561.
1. Cum ajunge de la id_pol la nota contabila — ia toate randurile setului, fara distributie
cursor_articol (:7218-7271):
FROM CRM_POLITICI_PRET_ART A
LEFT JOIN CRM_POLITICI_PRETURI B ON A.ID_POL = B.ID_POL
LEFT JOIN CRM_NOTE_VANZARI C ON B.ID_NOTA = C.ID_NOTA
LEFT JOIN NOTE_CONTABILE D ON C.ID_SET = D.ID_SET
WHERE A.ID_POL = detalii_articol.id_pol AND A.ID_ARTICOL = detalii_articol.id_articol
E un JOIN simplu pe ID_SET, fara ROWNUM, fara agregare, fara filtru suplimentar pe
NOTE_CONTABILE. Daca setul are N randuri, cursorul intoarce N randuri pentru aceeasi
combinatie id_pol/id_articol. Bucla care il consuma (:7393-7542,
OPEN cursor_articol; FETCH ...; WHILE cursor_articol%FOUND LOOP ... FETCH ...; END LOOP;) executa
intregul corp — scrie_nota, descarca_gestiune, scrie_discount — o data pentru fiecare rand
din set, cu aceeasi cantitate si acelasi pret intreg de fiecare data, nu impartite intre
randuri. Nu exista nicio coloana ORDINE in tot pachetul (cautare ORDINE in fisier: zero
rezultate) si nicio logica de distributie procentuala intre randurile unui set.
Consecinta directa pentru reteta aprobata (J-quater): daca politica tehnica pentru contul de
venit ar ajunge sa foloseasca o nota al carei ID_SET are mai mult de un rand in
NOTE_CONTABILE (cazul general — pana la 30 de randuri pe unele seturi din baza, per verificarea ta
pe date vii), contabilizeaza_articol ar scrie de N ori aceeasi suma in contabilitate si ar
apela descarca_gestiune de N ori pentru aceeasi linie de vanzare — dublare de venit si dublare de
descarcare de gestiune, nu doar zgomot. Pasul 2 al retetei ("cauta o politica a carei nota are deja
SCC-ul calculat") trebuie sa garanteze un singur rand NOTE_CONTABILE per ID_SET ales, nu
doar un rand cu SCC-ul potrivit — verificarea facuta de tine pe cele 7 note active (exact un rand
per set) e conditia care face reteta sigura azi, dar nu e impusa de cod, e o coincidenta a datelor
curente.
2. NOTE_CONTABILE.PTVA — nu e citit deloc de contabilizeaza_articol
Lista de coloane a cursor_articol (:7230-7260) selecteaza explicit
ID_NOTA, PRETURI_CU_TVA, ID_VENCHELT, ID_SECTIE, ID_SET, EXPLICATIE, SCD, ASCD, SCC, ASCC, CU_TVA, IN_VALUTA din lantul CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE — D.PTVA nu apare in acest SELECT. Coloana exista pe tabel (confirmat de
datele tale vii — 21, 5, 0), dar contabilizeaza_articol n-o citeste niciodata.
Cota de TVA folosita efectiv in scriere e alta — vine din apelul catre scrie_nota (:7444-7467),
unde parametrul V_PTVA primeste detalii_articol.proc_tvav * 100 - 100 (:7464), adica cota
calculata deja in adauga_articol_factura (din JTVA_COLOANE sau din documentul sursa, vezi
sectiunea 3 de mai sus), nu din nota. Deci raspunsul direct la intrebarea ta: daca articolul are
21% dar nota politicii are PTVA=5, nu se intampla nimic — PTVA de pe nota e complet ignorat,
cota folosita e cea a articolului/documentului, nu a notei. Coloana NOTE_CONTABILE.PTVA e moarta
din perspectiva acestei proceduri (posibil folosita in alt modul, neverificat aici).
3. CU_TVA si IN_VALUTA de pe nota
Ambele se citesc din NOTE_CONTABILE (crs_rand_articol.cu_tva, crs_rand_articol.in_valuta,
:7253, :7254-7260) si se transmit mai departe la scrie_nota ca parametri (V_CU_TVA,
V_IN_VALUTA), unde controleaza mecanic, nu semantic tot ce e legat de pret:
V_CU_TVA(scrie_nota:12416-12422): daca= 0, suma acumulata inV_INCASAT_CALCULeV_SUMA_FARA_TVA; daca= 1, eV_SUMA_CU_TVA. Separat, la:12537-12558, doar candV_CU_TVA = 1se scrie si o linie separata de TVA (pack_facturare.scrie_tva(...), cont4427/etc.). DeciCU_TVAdecide daca acest rand din notă genereaza o inregistrare contabila separata pentru TVA sau nu — nu suprascrie si nu recalculeaza cota, doar comuta daca linia de TVA se scrie.V_IN_VALUTA(scrie_nota:12391-12404,:12492-12507): daca= 1, se calculeaza siV_SUMA_VAL/V_SUMA_FARA_TVA_VAL/etc. (sumele in valuta straina) si randulACT_TEMPscrieID_VALUTA = V_ID_VALUTA(valuta reala a articolului) siCURS = V_CURS; daca= 0, randul scrieID_VALUTA = pack_facturare.nid_moneda_nationalasiCURS = 0, indiferent de valuta reala a articolului. Raspuns la "ce se intampla dacaIN_VALUTA=1pe nota dar documentul e in lei": nu apare nicio eroare si nicio validare incrucisata intreIN_VALUTAde pe nota si valuta reala a documentului — procedura calculeaza pur si simpluV_SUMA_VALfolosindV_ID_VALUTAsiV_CURSprimite dindetalii_articol(care, pe un document in lei, sunt deja moneda nationala si curs implicit 1). Rezultatul practic:ACT_TEMP.SUMA_VALse populeaza redundant (cu aceeasi valoare caSUMA, scalata la curs 1) in loc sa ramana0, iarID_VALUTAde pe randul contabil ramane oricum moneda nationala (pentru ca asta edetalii_articol.id_valutape un document in lei) — o inconsistenta cosmetica inACT_TEMP(rand cuSUMA_VALpopulat desiCURSreal e 1), nu o eroare de suma. Relevant pentru politicileSERVICII VALUTA/COMISION INTERMEDIERE(SCC=704, candidate la pasul 2 al retetei): daca oricare document in lei ar ajunge sa foloseasca una din ele, ar produce astfel de randuri cosmetic-inconsistente, fara sa strice suma facturata.
4. ASCD/ASCC si ID_PARTD/ID_PARTC
ASCD/ASCCnu sunt obligatorii — au fallback automat cand sunt nule, exact pe ramura care se aplica pe facturi (:7409-7428):Cand nota nu are analitic explicit (cazul majoritatii notelor reale, per verificarea ta), se deriva unul din grupul de utilizatori al celui care factureaza, functie de contulV_ASCD := NVL(crs_rand_articol.ascd, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCD)); ... V_ASCC := NVL(crs_rand_articol.ascc, PACK_FACTURARE.GetAnaliticByGrupUtilizatori(pack_facturare.nid_util, V_SCC));SCD/SCC. Nu s-a verificat in aceasta sesiune ce intoarceGetAnaliticByGrupUtilizatoricand nici grupul de utilizatori nu are un analitic configurat (posibilNULLmai departe, netratat explicit aici).ID_PARTD/ID_PARTCnu sunt citite de la nota deloc.cursor_articolnu le selecteaza (nu existaD.ID_PARTD/D.ID_PARTCnicaieri in fisier — verificat). Cele doua coloane de peACT_TEMPse calculeaza inscrie_nota/scrie_tvadirect din codul contului (V_SCD,V_SCC) si din variabile de sesiune ale pachetului (pack_facturare.nid_part,nid_part_rez,nid_partc), nu din nota:ID_PARTDe unCASEpe prefixul luiV_SCD(41%/46%/45%/357) la:12510-12515;ID_PARTCe unDECODEpeV_SCC(419/4111/357) la:12523-12530. DacaNOTE_CONTABILEare coloaneID_PARTD/ID_PARTC, ele sunt irelevante pentrucontabilizeaza_articol— partenerul contabil vine intotdeauna din contextul documentului (pack_facturare.nid_part), nu din configurarea notei.
5. Politica fara ID_NOTA (HOTEL TAXE, HOTEL CAZARE)
Nu exista un cod FACT-0xx dedicat pentru acest caz — spre deosebire de articolul care lipseste
din politica (FACT-024, :7278-7302), aici procedura nu detecteaza si nu semnaleaza explicit
situatia. Lantul de LEFT JOIN din cursor_articol (:7261-7271) e construit sa supravietuiasca
oricarui inel lipsa: A (politica-articol, gasita — altfel s-ar fi luat deja FACT-024 mai
devreme) se pastreaza chiar daca B.ID_NOTA e NULL — C si D devin pur si simplu toate
NULL pe acel rand, cursorul tot intoarce un rand (cursor_articol%FOUND = TRUE), nu zero.
In bucla (:7396-7541), asta inseamna:
crs_rand_articol.scd,.ascd,.scc,.ascc,.cu_tva,.in_valuta,.explicatie— toateNULL.- Ramura de calcul
V_ASCD := NVL(NULL, GetAnaliticByGrupUtilizatori(nid_util, NULL))— analitic calculat pe un contNULL, deci probabil totNULL(netestat aici ce intoarce functia pe argumentNULL). scrie_notae apelata cuV_SCD = NULL,V_SCC = NULL— insereaza inACT_TEMPun rand cu conturile de debit/credit nule.
Daca ACT_TEMP.SCD/ACT_TEMP.SCC au constrangere NOT NULL pe schema, INSERT-ul ar pica cu o
eroare Oracle generica (ORA-01400), nu cu un mesaj FACT-0xx prietenos ca la celelalte cazuri
tratate explicit — neverificat in aceasta sesiune (DDL-ul ACT_TEMP nu e in exportul
PACK_FACTURARE). In orice caz, comportamentul e cel putin la fel de riscant ca lipsa unui
articol din politica, dar fara plasa de siguranta explicita din cod — de tratat cu atentie daca
reteta aprobata ajunge sa produca vreodata o politica fara id_nota (nu pare sa fie cazul retetei
J-quater, care cere explicit gasirea unei note existente, dar HOTEL TAXE/HOTEL CAZARE arata ca
starea "politica fara nota" chiar exista azi in baza vie, pe alte fluxuri).
Ce nu s-a putut stabili si de ce
- Comportamentul exact al viitorului flux de reemitere din #13 (etapa II) fata de aceasta procedura — planul S10 cere verificarea "pe factura din contract", nu inventarul complet pentru comenzi/avize; nu s-a extins cercetarea acolo (in afara observatiei de la punctul 4, care ramane o constatare structurala, nu un verdict testat pe fluxul de reemitere, care inca nu exista in cod — decizia 30, nimic implementat).
- Ce se intampla la eroarea netratata din ramura de comenzi (
NO_DATA_FOUNDcandA.PRET = V_PRET_TEMPnu gaseste rand,:5057-5078) — daca propaga ca eroare Oracle bruta pana la utilizator sau dacagoExecutoro intercepteaza generic; n-a fost verificat (nu era in perimetrul celor 7 intrebari, dar e un risc adiacent gasit din citirea codului). - Cate contracte reale au azi
CTR_ARTICOLE.PRET_UNITARdiferit de pretul ultimei facturi emise — verificare pe date vii, nefacuta (cercetare read-only, fara acces la interogari live in aceasta sesiune). - Discrepanta de numerotare fata de
docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql(fisierul cerut in prompt nu exista pe disc) — semnalata la inceputul raportului, nu blocheaza verdictul pentru ca fisierul gasit inSCRIPTURI_CLARare acelasi nume/data si continut structural identic.