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

471 lines
28 KiB
Markdown

# 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.