# 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:`**; - corpul viu din `all_source` (`MARIUSM_AUTO.PACK_FACTURARE`, `PACKAGE BODY`, **VALID**, `last_ddl_time = 2026-08-09 20:03:50`) — prescurtat **`LIVE:`**; - `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.