Files
roafacturare/docs/cercetare/s10_rederivare_pe_calea_reemiterii.md
2026-09-09 22:19:22 +03:00

28 KiB

S10 — Se re-deriva valorile liniei pe calea de REEMITERE?

Stare: TERMINAT.

Surse:

  • D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (17217 linii; versiune_db.txt = 2026_08_09_02) — prescurtat PF:<linie>;
  • corpul viu din all_source (MARIUSM_AUTO.PACK_FACTURARE, PACKAGE BODY, VALID, last_ddl_time = 2026-08-09 20:03:50) — prescurtat LIVE:<linie>;
  • COMUN\clase\ofacturare.vc2, COMUN\programe\ofacturare_editare.prg.

Exportul = ce ruleaza. Verificat pe cinci ancore; in zona relevanta offsetul e constant, LIVE + 1240 = PF: LIVE:3749↔PF:4989, LIVE:3840↔PF:5080, LIVE:3909↔PF:5149, LIVE:3982↔PF:5222, LIVE:4044↔PF:5284, LIVE:12466↔PF:13706, LIVE:13735↔PF:14975. Nu generalizez offsetul in afara zonei masurate — il dau doar ca dovada de identitate.


1. Unde sta SELECT-ul de la PACK_FACTURARE:5149-5166 si cine il cheama

Numarul de linie e corect, verificat direct pe fisier. PF:5149-5166:

5149          SELECT DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR),
5150                 B.PROC_TVAV,
5151                 B.ID_VALUTA,
5152                 A.PRET_CU_TVA,
5153                 C.IN_STOC
5154            INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
5159            FROM CTR_ARTICOLE A
5160            LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL_ART = B.ID_POL_ART
5162            LEFT JOIN NOM_ARTICOLE C         ON B.ID_ARTICOL = C.ID_ARTICOL
5164           WHERE B.ID_ARTICOL = V_ID_ARTICOL AND A.ID_CTR = V_ID_CTR AND B.ID_POL = V_ID_POL;

Procedura: adauga_articol_factura — spec PF:537, corp PF:4989, END adauga_articol_factura; PF:5284. Deci DA, e adauga_articol_factura.

CORECTIE fata de raportul rundei 9: procedura nu scrie in VANZARI_DETALII. Se termina cu un singur INSERT, PF:5222, in VANZARI_DETALII_TEMP:

5222    INSERT INTO VANZARI_DETALII_TEMP (... PRET, PRET_CU_TVA, PROC_TVAV, ... ID_VALUTA, ... IN_STOC ...)
5252    VALUES (... V_PRET, V_PRETURI_CU_TVA, V_PROC_TVAV, ... V_ID_VALUTA, ... V_IN_STOC ...)

Re-derivarea se produce deci pe drumul catre temp, nu dupa el. Afirmatia „scrie_in_vanzari copiaza PRET neschimbat din temp" e adevarata (vezi 3) si totusi irelevanta ca protectie: valoarea din formular e inlocuita inainte sa intre in temp.

Cine cheama procedura: numai VFP-ul, din metoda de salvare a formularului:

  • COMUN\clase\ofacturare.vc2:14069 — frm_facturare_articole.do_scrie_articole
  • COMUN\clase\ofacturare.vc2:18104 — frm_facturare_articole2.do_scrie_articole

(:14054 si :18089 sunt variante comentate, cu bind ?, ale aceluiasi apel.) In pachet nu exista apelant intern: grep 'adauga_articol_factura\b' da doar PF:537 (spec), PF:4989 (corp), PF:5284 (END) si doua comentarii de antet (PF:22, PF:1497).

Traseul complet pe calea de scriere (frm_facturare_articole):

  1. ofacturare.vc2:13981 — pack_facturare.initializeaza_date_factura(...), care primeste Alltrim(Str(poDate.Tip)) (ofacturare.vc2:13994) si il pune in variabila de pachet: PF:1882 pack_facturare.ntip := V_TIP; (corp PF:1808, END la PF:1917). ntip = tipul documentului din formular — acelasi care ajunge in VANZARI.TIP (PF:13670). Tot aici, PF:1835 DELETE FROM VANZARI_DETALII_TEMP; si PF:1836 nid_act := 0;.
  2. ofacturare.vc2:14036-14115 — SCAN pe cursorul de grid crsfactura, cate un pack_facturare.adauga_articol_factura(...) per linie (:14069), executat prin goExecutor.oExecute (:14105).
  3. frm_facturare_articole.do_scrie_factura — scrie_factura2 (ofacturare.vc2:14345, :14373), scrie_factura_avize (:14318) sau scrie_factura_avize_retur (:14434, :14497), care ajung la pack_facturare.scrie_in_vanzari (PF:13488).

Raspuns Q1: e adauga_articol_factura, si e pe calea de scriere a documentului (nu pe cea de creare/incarcare din sursa) — dar tinta insertului e VANZARI_DETALII_TEMP, iar re-derivarea se aplica inainte de insert, deci nimic de dupa temp nu o mai poate repara.

Poarta care decide re-derivarea

adauga_articol_factura are un singur CASE (PF:5052-5220), pe pack_facturare.ntip:

WHEN linii conditie
comenzi PF:5053-5078 ntip IN (3, 21, 28, 42, 47)
avize PF:5080-5103 ntip = 4
restaurant PF:5104-5145 ntip = 45
contract PF:5146-5185 V_OPT_FACTURARE = 3
ELSE PF:5187-5218 restul

V_OPT_FACTURARE se seteaza numai daca ntip IN (2, 6, 26, 52) (PF:5039-5050): SELECT NVL(OPT_FACTURARE, 3) INTO V_OPT_FACTURARE FROM CONTRACTE WHERE ID_CTR = V_ID_CTR;, cu NO_DATA_FOUND -> V_OPT_FACTURARE := 4. Pentru orice alt ntip ramane NULL, iar WHEN NULL = 3 e NULL -> fals -> se merge pe ELSE. Implicitul e ramura care re-deriva: NVL(OPT_FACTURARE, 3).

Tipurile (COMUN\docs\tipuri_documente_facturare.md): 2 = factura pe contract, 6 = contract in valuta, 26 = aviz pe contract, 52 = contract factura valuta; 4 = factura din avize; 3/21/28/42/47 = din comenzi; 45 = restaurant.

2. Cele cinci valori, una cate una

Intai maparea parametrilor — ce trimite formularul (apel ofacturare.vc2:14069-14091 confruntat cu semnatura PF:4989-5015; 27 de parametri, pozitional, potrivire completa):

formular (crsfactura -> poArt) parametru
poArt.pretftva/pretctva/vpretftva/vpretctva V_PRET_TEMP
poArt.id_valuta V_ID_VALUTA_TEMP
poArt.cu_tva V_PRETURI_CU_TVA_TEMP
poArt.gestionabil V_IN_STOC_TEMP
poArt.id_jtva_coloana V_ID_JTVA_COLOANA
poArt.id_pol V_ID_POL
poArt.id_ctr V_ID_CTR

PROC_TVAV nu e parametru. Nu exista V_PROC_TVAV_TEMP in semnatura — cota de TVA a liniei se calculeaza intotdeauna pe server, in toate ramurile. Formularul trimite ID_JTVA_COLOANA, din care ramura ELSE deriva PROC_TVAV. Pentru PROC_TVAV intrebarea „vine din temp?" nu are raspuns „da" pe nicio ramura; intrebarea reala e din ce se deriva.

Ramura contract (V_OPT_FACTURARE = 3, PF:5146-5185)

  • PRET — DECODE(A.PRET_UNITAR, 0, V_PRET_TEMP, A.PRET_UNITAR) (PF:5149). Se re-deriva din CTR_ARTICOLE.PRET_UNITAR ori de cate ori aceasta e <> 0, indiferent daca linia a fost atinsa pe ecran. Numai cand contractul are PRET_UNITAR = 0 trece valoarea din formular. Capcana NULL: CTR_ARTICOLE.PRET_UNITAR e nullable=Y (verificat pe DB); un NULL nu potriveste literalul 0 in DECODE, deci rezultatul e NULL, nu V_PRET_TEMP — pretul din formular se pierde si linia intra in temp cu PRET NULL. (dedus din semantica DECODE, nu rulat.)
  • PROC_TVAV — B.PROC_TVAV din CRM_POLITICI_PRET_ART (PF:5150). Se re-deriva din politica de preturi, nu din ID_JTVA_COLOANA trimis de formular. Diferit de ELSE.
  • ID_VALUTA — B.ID_VALUTA din CRM_POLITICI_PRET_ART (PF:5151). Se re-deriva; V_ID_VALUTA_TEMP e ignorat.
  • PRET_CU_TVA — A.PRET_CU_TVA din CTR_ARTICOLE (PF:5152). Se re-deriva; V_PRETURI_CU_TVA_TEMP (poArt.cu_tva) e ignorat.
  • IN_STOC — C.IN_STOC din NOM_ARTICOLE (PF:5153). Se re-deriva din nomenclatorul curent; V_IN_STOC_TEMP (poArt.gestionabil) e ignorat.

Cele cinci nu merg impreuna nici macar aici: PRET are un DECODE care uneori lasa valoarea din formular sa treaca, celelalte patru sunt inlocuite neconditionat, din trei tabele diferite (CTR_ARTICOLE, CRM_POLITICI_PRET_ART, NOM_ARTICOLE).

Iesirea de siguranta: EXCEPTION WHEN NO_DATA_FOUND (PF:5167-5185) deriva PROC_TVAV din JTVA_COLOANE si pune toate celelalte patru pe valorile din formular (PF:5181-5184): V_PRET := V_PRET_TEMP; V_ID_VALUTA := V_ID_VALUTA_TEMP; V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP; V_IN_STOC := V_IN_STOC_TEMP;. Adica daca linia nu mai are corespondent in contract, formularul castiga — exact comportamentul cerut de decizia 54, existent deja in cod, dar numai pe calea de exceptie.

Ramura ELSE (PF:5187-5218) — cazul „bun"

PROC_TVAV din JTVA_COLOANE pe ID_JTVA_COLOANA trimis de formular (PF:5189-5192), iar PF:5200-5203 pune explicit V_PRET := V_PRET_TEMP, V_ID_VALUTA := V_ID_VALUTA_TEMP, V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP, V_IN_STOC := V_IN_STOC_TEMP. Patru din cinci vin din formular; PROC_TVAV se deriva, dar din date trimise de formular.

Ramura comenzi (ntip IN (3,21,28,42,47), PF:5053-5078)

5057          SELECT A.PRET,
5058                 NVL2(A.PTVA, ROUND((A.PTVA + 100) / 100, 2), C.PROC_TVAV),
5059                 C.ID_VALUTA, B.PRETURI_CU_TVA, D.IN_STOC
5075           WHERE A.ID_COMANDA = V_ID_COMANDA AND A.ID_ARTICOL = V_ID_ARTICOL
5077             AND A.PRET = V_PRET_TEMP AND A.STERS = 0;
  • PRET — formal A.PRET din COMENZI_ELEMENTE, dar WHERE ... A.PRET = V_PRET_TEMP (PF:5077) fixeaza rezultatul pe pretul din formular. Practic nu se schimba.
  • PROC_TVAV, ID_VALUTA, PRET_CU_TVA, IN_STOC — se re-deriva din COMENZI_ELEMENTE.PTVA / CRM_POLITICI_PRET_ART / CRM_POLITICI_PRETURI / NOM_ARTICOLE.
  • Ramura nu are bloc EXCEPTION. Un SELECT INTO gol da NO_DATA_FOUND (ORA-01403) netratat, care urca prin goExecutor in VFP. Deci daca la reemitere pretul liniei a fost modificat pe ecran (sau linia nu mai e in comanda), scrierea cade cu eroare — nu se re-deriva tacit. Este o a doua ramura de re-derivare, pe care raportul rundei 9 nu o numara.

Ramura restaurant (ntip = 45, PF:5104-5145)

PF:5109-5112 pune explicit V_PRET := V_PRET_TEMP, V_ID_VALUTA := V_ID_VALUTA_TEMP, V_PRETURI_CU_TVA := V_PRETURI_CU_TVA_TEMP, V_IN_STOC := V_IN_STOC_TEMP; SELECT-ul de la PF:5114-5139 deriva doar V_PROC_TVAV (din JTVA_COLOANE) si V_PRET_ACHIZITIE. Patru din cinci vin din formular.

Ramura avize (ntip = 4) — la punctul 5

3. UPDATE / recalcul care suprascrie valorile DUPA insertul din temp

Nu exista, pentru cele cinci valori.

Scrierea temp -> definitiv, in scrie_in_vanzari (PF:13488-13953), e o copiere 1:1:

13705    INSERT /*+ APPEND */
13706    INTO VANZARI_DETALII (... PRET, PROC_TVAV, ... ID_VALUTA, ... PRET_CU_TVA, DIFERENTA, ...)
13732      SELECT V_ID_VANZARE as ID_VANZARE, ... PRET, PROC_TVAV, ... ID_VALUTA, ... PRET_CU_TVA, DIFERENTA, ...
13757        FROM VANZARI_DETALII_TEMP;

Capcana de cautare platita aici: grep 'INSERT INTO VANZARI_DETALII' da zero potriviri — hint-ul /*+ APPEND */ rupe cuvintele pe doua randuri. Cautarea corecta e INTO VANZARI_DETALII.

IN_STOC nu apare in lista de coloane (PF:13707-13731), si VANZARI_DETALII nu are coloana IN_STOC (verificat pe DB: all_tab_columns -> 0 randuri). Traieste doar in VANZARI_DETALII_TEMP, unde decide descarcarea de gestiune. Re-derivarea lui nu murdareste documentul salvat, dar schimba comportamentul de stoc al reemiterii.

Toate scrierile pe VANZARI_DETALII din pachet:

linie procedura ce face
PF:13705 scrie_in_vanzari (PF:13488) INSERT 1:1 din temp
PF:14974 finalizeaza_avize_lucrare (PF:14854) INSERT 1:1 din temp (cale avize de lucrare)
PF:5560 sterge_factura (PF:5432) SET STERS, ID_UTILS, DATAORAS
PF:5630 sterge_proforma (PF:5610) SET STERS, ID_UTILS, DATAORAS
PF:14516 modifica_explicatie_articol (PF:14511) SET EXPLICATIE, TAXCODE
PF:16017 actualizeaza_vanzari (PF:16012) SET STERS = 0

Niciun UPDATE nu atinge PRET, PROC_TVAV, ID_VALUTA, PRET_CU_TVA. Confirmat si pe DB: all_source are exact doua INTO VANZARI_DETALII (LIVE:12466, LIVE:13735).

Mutatiile pe VANZARI_DETALII_TEMP intre adauga_articol_factura si scrie_in_vanzari:

linie procedura ce schimba
PF:5297 adauga_diferente_pret numai DIFERENTA (PF:5344: UPDATE SET DIFERENTA = B.DIFERENTA)
PF:6860, PF:6864 scrie_factura_avize numai CANTITATE (split pe custodie); in MERGE, PRET, PRET_CU_TVA, PROC_TVAV, ID_VALUTA, IN_STOC sunt in clauza ON, nu in UPDATE SET
PF:14020 scrie_seturi numai ID_VANZARE_SET
PF:14057 scrie_seturi_proforma numai ID_VANZARE_SET (cale proforma)
PF:12266 transfera_articol cale de transfer, in afara scrierii de factura

pack_auto.actualizeaza_deviz (D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733) atinge DEV_ORDL.PROC_TVAV, RUL.ID_FACT, NOM_LUCRARI.ID_FACT — nu atinge VANZARI_DETALII.

Recalculele de totaluri (PF:13760+, recalculeaza_totaluri_vanzari PF:16021) si rotunjirile lucreaza pe VANZARI, agregat — nu rescriu linia.

Raspuns Q3: nu. Dupa insertul in temp, cele cinci valori nu mai sunt suprascrise nicaieri. DIFERENTA si CANTITATE da, restul nu.

4. Verdict: ajung valorile din formular neatinse in VANZARI_DETALII?

NU, pentru trei familii de tipuri. DA, pentru restul.

Se pierd intr-un singur loc: PACK_FACTURARE.adauga_articol_factura, in CASE-ul de la PF:5052-5220, adica inainte de INSERT INTO VANZARI_DETALII_TEMP (PF:5222). Precis:

  • contract (ntip IN (2,6,26,52) cu CONTRACTE.OPT_FACTURARE NULL sau 3) — PF:5149-5153: se pierd PRET (cand CTR_ARTICOLE.PRET_UNITAR <> 0), PROC_TVAV, ID_VALUTA, PRET_CU_TVA, IN_STOC;
  • aviz (ntip = 4) — PF:5082-5086: se pierd toate cinci, inclusiv PRET, neconditionat;
  • comenzi (ntip IN (3,21,28,42,47)) — PF:5057-5061: se pierd patru; PRET e fixat de WHERE, dar la nepotrivire scrierea cade cu ORA-01403 in loc sa treaca.

Pentru toate celelalte tipuri (1, 5, 10, 22, 45, ...) valorile din formular ajung neatinse: ramurile ELSE (PF:5200-5203) si restaurant (PF:5109-5112) le copiaza explicit, iar traseul de dupa (PF:13705-13757) e copiere 1:1.

Exceptie transversala, valabila pe TOATE tipurile: PROC_TVAV nu vine niciodata din formular — nu e parametru al procedurii. Pe calea „buna" se deriva din JTVA_COLOANE pe ID_JTVA_COLOANA-ul trimis de formular, deci reproduce documentul atat timp cat cota din JTVA_COLOANE nu s-a schimbat. La o modificare legala de cota, reemiterea schimba TVA-ul chiar si pe ramura ELSE.

5. Sursa AVIZ (ntip = 4) — calea difera, si e mai grava

Verbatim, PF:5080-5103 (confirmat identic pe DB, LIVE:3840-3863):

5080      WHEN pack_facturare.ntip = 4 THEN
5081        -- facturare din avize
5082        SELECT DISTINCT A.PRET,
5083                        A.PROC_TVAV,
5084                        A.ID_VALUTA,
5085                        A.PRET_CU_TVA,
5086                        B.IN_STOC
5087          INTO V_PRET, V_PROC_TVAV, V_ID_VALUTA, V_PRETURI_CU_TVA, V_IN_STOC
5092          FROM VANZARI_DETALII A
5093          LEFT JOIN NOM_ARTICOLE B ON A.ID_ARTICOL = B.ID_ARTICOL
5095         WHERE A.ID_ARTICOL = V_ID_ARTICOL
5096           AND A.ID_POL = V_ID_POL
5097           AND NVL(A.ID_GESTIUNE, -1000) = V_ID_GESTIUNE
5098           AND A.DISCOUNT_UNITAR = V_DISCOUNT_UNITAR
5099           AND NVL(A.CONT, 'XXXX') = V_CONT
5100           AND A.ID_VANZARE IN
5101               (SELECT X AS ID_VANZARE
5102                  FROM table(cast(CHARN2COLLECTION(pack_facturare.clistaid, ',') AS num_tab)));

Diferentele fata de contract, toate in defavoarea deciziei 54:

  1. PRET se re-deriva neconditionat, direct din VANZARI_DETALII al avizului sursa. Nu exista DECODE(..., 0, V_PRET_TEMP, ...) si nu exista AND A.PRET = V_PRET_TEMP in WHERE (spre deosebire de ramura comenzi, PF:5077). Un pret modificat pe ecran la reemitere e inlocuit tacit cu pretul din aviz. Aceasta e ramura cea mai agresiva din tot CASE-ul.
  2. Nu are bloc EXCEPTION. Ramura contract are NO_DATA_FOUND care cade inapoi pe formular (PF:5167-5185); aici, orice modificare pe ecran a DISCOUNT_UNITAR, CONT, ID_GESTIUNE sau ID_POL scoate randul din WHERE -> ORA-01403 urcata in VFP. SELECT DISTINCT peste mai multe avize cu preturi diferite pe acelasi articol poate da si ORA-01422 (TOO_MANY_ROWS).
  3. Nu filtreaza A.STERS = 0, desi VANZARI_DETALII are coloana STERS (verificat pe DB) si sterge_factura o foloseste (PF:5560). Linii sterse ale avizului sursa pot fi citite.
  4. Depinde de pack_facturare.clistaid — lista de avize sursa, trimisa de VFP prin initializeaza_date_factura (poDate.listaid, ofacturare.vc2:13992). La reemitere, clistaid trebuie repopulata cu aceleasi avize, altfel WHERE nu potriveste nimic -> ORA-01403.

Ce nu difera: dupa CASE traseul e identic (INSERT in temp PF:5222, apoi copiere 1:1 PF:13705), iar scrie_factura_avize (PF:6692) modifica in temp numai CANTITATE (PF:6860, PF:6864) — nu re-deriva nimic in plus.

Raspuns Q5: calea difera, si e mai stricta. Pe contract exista o portita (PRET_UNITAR = 0 si NO_DATA_FOUND) prin care valorile din formular trec; pe aviz nu exista niciuna — ori se re-deriva tot, ori pica cu eroare.

6. Consecinta pentru decizia 54, la nivel de contract

6.1 Se poate curat VFP? Nu.

Confirm afirmatia rundei 9 — dar acum cu dovada, nu prin absenta:

  • Semnatura nu are flag. PF:4989-5015: 27 de parametri, toti date de linie; ultimii doi (V_TAXCODE, V_LOT) sunt DEFAULT NULL, niciunul nu e comutator.
  • Globalele pachetului nu au flag. PF:126-212 — stare de sesiune (ntip, clistaid, nid_part, ...), niciun comutator de comportament pe re-derivare.
  • Poarta nu e influentabila legitim din VFP. ntip ajunge in VANZARI.TIP (PF:13670) — a-l falsifica inseamna a schimba tipul documentului. CONTRACTE.OPT_FACTURARE e date de contract, nu parametru de apel.
  • Singurele parghii VFP care ar devia pe calea NO_DATA_FOUND sunt, ambele, de aceeasi natura ca varianta (d) deja respinsa:
    • V_ID_CTR = NULL — respinsa; PF:5280 duce V_ID_CTR in temp.ID_CTR, iar PF:13755 in VANZARI_DETALII.ID_CTR, deci legatura se pierde permanent;
    • V_ID_POL = NULL — acelasi defect, alta coloana: PF:5258 duce V_ID_POL in temp.ID_POL, PF:13737 in VANZARI_DETALII.ID_POL; in plus ar rupe ramura aviz, care potriveste pe A.ID_POL = V_ID_POL (PF:5096). Nu o propun — o mentionez ca sa nu fie redescoperita ca „solutie" intr-o runda urmatoare.

Concluzie: decizia 54 cere obligatoriu modificare in pack_facturare.

6.2 Ce forma trebuie sa aiba semnalul

Doua forme sunt inerte pentru apelantii de azi:

  • (i) variabila noua de pachet („regenerare in curs"), implicit 0 = comportamentul actual, scrisa de VFP dupa initializeaza_date_factura si inainte de bucla de adauga_articol_factura;
  • (ii) parametru DEFAULT 0 adaugat dupa V_LOT in semnatura — apelantii de azi trimit 27 de argumente pozitional si raman valizi.

Recomand (i), din trei motive concrete: se potriveste cu stilul existent al pachetului (care e deja o punga de stare de sesiune); se scrie o data pe document, nu o data pe linie, in toate produsele; si punctul de resetare exista deja — initializeaza_date_factura (PF:1808-1917) reinitializeaza ~40 de globale si face DELETE FROM VANZARI_DETALII_TEMP (PF:1835), deci flag-ul nu poate scapa in documentul urmator din aceeasi sesiune. Atentie la ordine: VFP il seteaza dupa apelul de la ofacturare.vc2:13981, nu inainte. Ambele variante modifica spec-ul, deci ambele forteaza recompilarea dependentilor — nu e un criteriu de departajare.

6.3 Ce face semnalul, cand e pornit

Nimic nou — forteaza ramura care exista deja. Cea mai mica forma: un WHEN nou, primul in CASE-ul de la PF:5052, cu acelasi corp ca ELSE-ul de azi (PF:5189-5203): PROC_TVAV din JTVA_COLOANE pe V_ID_JTVA_COLOANA, si V_PRET/V_ID_VALUTA/V_PRETURI_CU_TVA/V_IN_STOC din parametrii *_TEMP. INSERT-ul de la PF:5222 ramane neatins. Acopera dintr-o data toate trei ramurile problematice (contract, aviz, comenzi), pentru ca toate sunt in acelasi CASE.

6.4 Trei consecinte de acceptat explicit, nu ocolite

  1. IN_STOC ar veni din formular (poArt.gestionabil) in loc de NOM_ARTICOLE. Nu e o problema de fidelitate a documentului — VANZARI_DETALII nu are coloana IN_STOC (verificat pe DB) — ci de comportament de stoc la reemitere. Ca reemiterea sa fie identica, incarcarea (S8) trebuie sa dea valoarea cu care s-a scris documentul initial. Azi nu o da: loader-ul lui #6 o citeste din nomenclatorul curent — ofacturare_editare.prg:302-303, left join nom_articole na on na.id_articol = v.id_articol, cu comentariul care spune ca view-ul n-o expune. Flag-ul singur nu rezolva asta.
  2. Se pierde o validare pe ramura comenzi. A.PRET = V_PRET_TEMP (PF:5077) plus lipsa lui EXCEPTION fac azi ca o linie care nu se mai potriveste cu comanda sa opreasca scrierea. Cu flag-ul pornit, reemiterea unei „facturi din comanda" nu mai verifica linia fata de comanda. Decizia 54 pare sa vrea exact asta, dar e o schimbare de comportament care trebuie spusa, nu descoperita la S12.
  3. PROC_TVAV ramane derivat, nu preluat. Reproducerea exacta a documentului cere ca S8 sa pastreze ID_JTVA_COLOANA si ca JTVA_COLOANE.COTA_TVA sa nu se fi schimbat intre timp. Daca se cere reproducere exacta si peste o modificare de cota, PROC_TVAV trebuie sa devina parametru — schimbare mai mare decat flag-ul, de decis separat.

6.5 Un obstacol de incarcare, gasit in treacat (pentru S8, nu pentru S10)

View-ul pe care se sprijina incarcarea de azi, VVANZARI_ARTICOLE, expune (interogat pe DB): ID_VANZARE, ID_VANZARE_DET, ID_ARTICOL, CANTITATE, PRET, PRET_CU_TVA, PROC_TVAV, DISCOUNT_UNITAR, ID_GESTIUNE, CONT, ID_VALUTA, ID_JTVA_COLOANA, SERIE, EXPLICATIE, TAXCODE, LOT, STERS, ID_VANZARE_SET, PRET_ACHIZITIE, DENUMIRE, CODMAT, NUME_GESTIUNE, NUME_VAL.

Nu expune ID_POL si nu expune ID_CTR — exact cei doi pe care adauga_articol_factura ii cere (V_ID_POL, V_ID_CTR) si pe care VANZARI_DETALII ii pastreaza. Reemiterea S9 nu poate folosi acest view ca atare; ori se completeaza view-ul, ori loader-ul citeste direct din VANZARI_DETALII. Nu e in perimetrul S10, dar blocheaza S9 daca nu e prins din timp.


Tabel sintetic — cele cinci valori pe ramura

„temp" = valoarea trimisa de formular; „re-derivat" = citita din alta sursa si suprascrisa.

valoare contract (2/6/26/52, OPT_FACTURARE NULL sau 3) aviz (ntip = 4) comenzi (3/21/28/42/47) restaurant (45) ELSE
PRET_UNITAR (PRET) re-derivat din CTR_ARTICOLE.PRET_UNITAR daca <> 0; temp daca = 0; NULL daca e NULL (PF:5149) re-derivat din VANZARI_DETALII al avizului, neconditionat (PF:5082) temp de facto — WHERE A.PRET = V_PRET_TEMP (PF:5077); nepotrivire = ORA-01403 temp (PF:5109) temp (PF:5200)
PROC_TVAV re-derivat din CRM_POLITICI_PRET_ART (PF:5150) re-derivat din avizul sursa (PF:5083) re-derivat din COMENZI_ELEMENTE.PTVA / politica (PF:5058) re-derivat din JTVA_COLOANE (PF:5114) derivat din JTVA_COLOANE pe ID_JTVA_COLOANA din formular (PF:5189)
ID_VALUTA re-derivat din CRM_POLITICI_PRET_ART (PF:5151) re-derivat din avizul sursa (PF:5084) re-derivat din politica (PF:5059) temp (PF:5110) temp (PF:5201)
PRET_CU_TVA re-derivat din CTR_ARTICOLE (PF:5152) re-derivat din avizul sursa (PF:5085) re-derivat din CRM_POLITICI_PRETURI (PF:5060) temp (PF:5111) temp (PF:5202)
IN_STOC re-derivat din NOM_ARTICOLE (PF:5153) re-derivat din NOM_ARTICOLE (PF:5086) re-derivat din NOM_ARTICOLE (PF:5061) temp (PF:5112) temp (PF:5203)

PROC_TVAV nu vine din temp pe nicio ramura — nu e parametru al procedurii. IN_STOC nu ajunge in VANZARI_DETALII (coloana nu exista) — traieste doar in temp, unde decide descarcarea de gestiune. Pe ramura contract, EXCEPTION WHEN NO_DATA_FOUND (PF:5167-5185) muta toate cele cinci pe coloana „temp"; ramurile aviz si comenzi nu au un asemenea bloc.

Verificat direct vs. dedus

Verificat direct pe fisier SI confirmat pe DB (all_source, MARIUSM_AUTO.PACK_FACTURARE, PACKAGE BODY, VALID, last_ddl_time = 2026-08-09 20:03:50): granitele lui adauga_articol_factura; toate cele cinci ramuri ale CASE-ului, ramura cu ramura; textul integral al ramurii aviz; faptul ca insertul procedurii merge in VANZARI_DETALII_TEMP; ca exista exact doua INTO VANZARI_DETALII in tot pachetul.

Verificat direct pe fisier (nereconfirmat separat pe DB, dar in aceeasi zona cu offset masurat): copierea 1:1 temp -> VANZARI_DETALII (PF:13705-13757); cele patru UPDATE VANZARI_DETALII si ce coloane ating; mutatiile pe temp intre adauga_articol_factura si scrie_in_vanzari; corpul lui pack_auto.actualizeaza_deviz.

Verificat pe metadatele DB: VANZARI_DETALII nu are IN_STOC, are STERS; CTR_ARTICOLE.PRET_UNITAR e nullable=Y; lista de coloane a lui VVANZARI_ARTICOLE.

Verificat direct in VFP: apelantii lui adauga_articol_factura; maparea celor 27 de parametri; ntip := poDate.Tip; loader-ul IncarcaArticoleFactura (ofacturare_editare.prg:292-327).

Dedus, nerulat: comportamentul DECODE cu PRET_UNITAR NULL (semantica Oracle, nu test); ORA-01403 / ORA-01422 pe ramurile fara EXCEPTION (din absenta blocului, nu din reproducere).

Din date de dev — NU e dovada, nu extrapolati: CTR_ARTICOLE are 27 de randuri (0 NULL, 10 cu PRET_UNITAR = 0, 17 cu <> 0) — deci cazul NULL nu apare in dev, ceea ce nu spune nimic despre productie. CONTRACTE.OPT_FACTURARE: 176 NULL, 53 = 0, 9 = 1, 3 = 3, 1 = 4 — adica pentru 176 + 3 din 242 de contracte NVL(OPT_FACTURARE, 3) da 3 si ramura re-deriva.

Neacoperit: n-am rulat niciun flux real (nici VFP, nici o reemitere efectiva) — totul e analiza statica plus interogari SELECT pe metadate. N-am citit corpurile scrie_factura2 si finalizeaza_factura integral, doar punctele in care ating VANZARI_DETALII / temp.

Corectii la rapoartele anterioare

docs\cercetare\s10_pret_rederivat.md (runda 9)

  1. „exista exact o ramura care suprascrie pretul — contractul" — FALS. Ramura aviz (ntip = 4, PF:5080-5103) suprascrie PRET neconditionat, fara DECODE si fara filtru pe pretul din formular — mai agresiv decat contractul. Ramura comenzi (PF:5053-5078) nu suprascrie PRET, dar suprascrie celelalte patru si arunca ORA-01403 la nepotrivire. Ramurile care re-deriva sunt trei, nu una.
  2. „pe calea de scriere" — corect ca moment, gresit ca destinatie. Se intampla la salvare, dar insertul e in VANZARI_DETALII_TEMP (PF:5222), nu in VANZARI_DETALII. Diferenta conteaza: explica de ce copierea „neschimbata" de mai tarziu nu protejeaza nimic.
  3. „nu exista niciun parametru sau flag care sa opreasca re-derivarea" — CONFIRMAT, acum cu dovada pozitiva (semnatura PF:4989-5015, globalele PF:126-212), nu prin absenta.

docs\cercetare\s10_pret_contract_reemitere.md (runda 13)

  1. „acelasi SELECT alimenteaza cinci valori" — corect (PF:5149-5166), dar de completat: nu merg impreuna — PRET are DECODE, celelalte patru sunt neconditionate, si vin din trei tabele diferite.
  2. „IN_STOC din nomenclatorul curent" — corect, de completat cu faptul decisiv: VANZARI_DETALII nu are coloana IN_STOC (verificat pe DB). Nu ajunge in document; efectul e pe descarcarea de gestiune.
  3. „scrie_in_vanzari copiaza PRET neschimbat din temp" — corect (PF:13705-13757), de marcat insa ca nu e o protectie: dauna e amonte de temp.
  4. Varianta „avertizare + confirmare" ramane respinsa (decizia 54) — nu am reargumentat-o.

docs\plan_13_unificare_formular_facturare.md

  • Trimiterea „initializeaza_date_factura (PACK_FACTURARE:1808-1846)" — corpul incepe la PF:1808 dar se termina la PF:1917. Citarile :1835 / :1836 din plan sunt corecte.