# Cercetare S5 — proiectarea partii Oracle (plan #6, editare factura emisa)

Data: 09.08.2026. Sursa: export PROASPAT din `MARIUSM_AUTO@ROA_CENTRAL` (`all_source`), facut in
aceasta sesiune, in scratchpad (nu in proiect):

- `PACK_FACTURARE.pck` — 16160 linii
- `PACK_CONTAFIN.pck` — 8550 linii

**Toate numerele de linie de mai jos sunt din ACEST export.** Raportul precedent
(`rec_s5_oracle_vanzari.md`, 08.08.2026) declara `PACK_FACTURARE.pck = 17010` linii; offset-urile
procedurilor coincid totusi exact (`scrie_in_vanzari` la `:13491`, `actualizeaza_vanzari` la
`:16015`), deci diferenta e de formatare a spool-ului, nu de continut. Concluziile lui A.1-A.2, C si
D raman valabile pe sursa de azi si nu se repeta aici.

**Doua corectii de fond fata de raportul precedent** (detaliate la 3 si 4):

1. agregarea NU citeste `VANZARI_SETURI_TEMP`, ci tabela **persistenta `VANZARI_SETURI`**
   (`:13916`) — deci liniile de set se pot reconstitui integral la editare;
2. recomandarea „procedura noua apelata din interiorul `finalizeaza_modificare_nota`" e
   **incompatibila cu ordinea corecta de scriere** si trebuie abandonata.

---

## 1. Baza de plecare e la zi? DA (pentru `ff_`)

Comparatie `VERSIUNE` (4151 randuri) vs. `D:\ROA\DATABASE\SCRIPTURI_CLAR` (3030 fisiere `.sql`):

- **`ff_` pe disc dar neaplicate in `MARIUSM_AUTO`: 0.** Schema e la zi pe tot ce o priveste.
- Ultimul `ff_` inregistrat: `ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql`, identic cu
  `versiune_db.txt` din radacina proiectului (`2026_08_08_01`).
- Cele 26 de scripturi din 2026 care lipsesc din `VERSIUNE` sunt **exclusiv `co_` si `sys_`** — se
  aplica pe `CONTAFIN_ORACLE`, respectiv `SYS`, nu pe schema firmei; `VERSIUNE` din `MARIUSM_AUTO`
  contine doar 3 randuri `co_`, deci absenta lor e normala, nu o restanta.

**Verdict: se poate construi propunerea peste sursa exportata azi.**

### Doua anomalii de semnalat (nu blocheaza S5)

- **`ff_2026_08_08_01_COMUN_VVD_TOT.sql` e inregistrat in `VERSIUNE` dar NU exista nicaieri pe
  disc** (cautat recursiv in tot `SCRIPTURI_CLAR`). Un obiect aplicat in dev fara script salvat nu
  ajunge niciodata la clienti. De verificat cu Marius daca e un script de lucru abandonat sau daca
  lipseste din SVN.
- Acelasi `NN` (`2026_08_08_01`) e folosit de doua scripturi `ff_` (`VVANZARI_ARTICOLE` si
  `VVD_TOT`), contra regulii „NN e secventa unica pe zi".

---

## 2. Blocul de agregare din `scrie_in_vanzari` — integral

Procedura: `PACK_FACTURARE.pck:13491-13956`. Blocul de agregare + `UPDATE VANZARI` e
`:13762-13954`, citat integral:

```
13762     -- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi
13763     begin
13764       select DISC_TVA_VAL AS DISCOUNT_TVA,
13765              VALOARE_ACHIZITIE,
13766              a.suma_fara_tva_ron - a.disc_fara_tva_ron as TOTAL_FARA_TVA,
13767              a.suma_tva_ron - a.disc_tva_ron as TOTAL_TVA,
13768              a.suma_fara_tva_ron - a.disc_fara_tva_ron + a.suma_tva_ron -
13769              a.disc_tva_ron as TOTAL_CU_TVA,
13770              a.suma_fara_tva_val - a.disc_fara_tva_val as VALVAL,
13771              a.suma_tva_val - a.disc_tva_val as TVAVAL,
13772              a.suma_fara_tva_val - a.disc_fara_tva_val + a.suma_tva_val -
13773              a.disc_tva_val as TOTVAL,
13774              id_valuta,
13775              curs,
13776              multiplicator,
13777              pack_facturare.cserie_act_incasare as SERIE_INCASAT,
13778              pack_facturare.nnumar_act_incasare as NR_INCASAT,
13779              pack_facturare.nsuma_incasare AS SUMA_INCASAT,
13780              pack_facturare.ntip_doc_incasare as TIP_INCASAT
13781         INTO lnDiscountTVA,
13782              lnValoareAchizitie,
13783              lnTotalFaraTVA,
13784              lnTotalTVA,
13785              lnTotalCuTVA,
13786              lnValVal,
13787              lnTVAVal,
13788              lnTotVal,
13789              lnIdValuta,
13790              lnCurs,
13791              lnMultiplicator,
13792              lnSerieIncasat,
13793              lnNrIncasat,
13794              lnSumaIncasat,
13795              lnTipIncasat
13796         FROM (select MAX(decode(pack_facturare.nin_valuta,
13797                                 1,
13798                                 ROUND(a1.curs * NVL(V_DISCOUNT_FACTURA, 0) /
13799                                       a1.multiplicator,
13800                                       lnPreciziePretV),
13801                                 NVL(V_DISCOUNT_FACTURA, 0))) as DISC_FARA_TVA_RON,
13802                      NVL(V_DISCOUNT_FACTURA, 0) as DISC_FARA_TVA_VAL,
13803                      pack_facturare.nin_valuta AS IN_VALUTA,
13804                      MAX(ROUND(decode(pack_facturare.nin_valuta,
13805                                       1,
13806                                       ROUND(a1.curs *
13807                                             NVL(V_DISCOUNT_FACTURA, 0) /
13808                                             a1.multiplicator,
13809                                             lnPreciziePretV),
13810                                       NVL(V_DISCOUNT_FACTURA, 0)) *
13811                                (a1.proc_tvav - 1),
13812                                lnPreciziePretV)) as DISC_TVA_RON,
13813                      MAX(ROUND(NVL(V_DISCOUNT_FACTURA, 0) *
13814                                (a1.proc_tvav - 1),
13815                                lnPreciziePretV)) as DISC_TVA_VAL,
13816                      sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_ron,
13817                                                                        0,
13818                                                                        1,
13819                                                                        NVL(a1.discount_unitar_ron,
13820                                                                            0),
13821                                                                        pack_facturare.ndiscount_evidentiat,
13822                                                                        a1.cantitate,
13823                                                                        a1.pret_cu_tva,
13824                                                                        a1.proc_tvav)) AS SUMA_FARA_TVA_RON,
13825                      sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_ron,
13826                                                                   0,
13827                                                                   1,
13828                                                                   NVL(a1.discount_unitar_ron,
13829                                                                       0),
13830                                                                   pack_facturare.ndiscount_evidentiat,
13831                                                                   a1.cantitate,
13832                                                                   a1.pret_cu_tva,
13833                                                                   a1.proc_tvav)) as SUMA_TVA_RON,
13834                      sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_val,
13835                                                                        0,
13836                                                                        1,
13837                                                                        NVL(a1.discount_unitar_val,
13838                                                                            0),
13839                                                                        pack_facturare.ndiscount_evidentiat,
13840                                                                        a1.cantitate,
13841                                                                        a1.pret_cu_tva,
13842                                                                        a1.proc_tvav)) AS SUMA_FARA_TVA_VAL,
13843                      sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_val,
13844                                                                   0,
13845                                                                   1,
13846                                                                   NVL(a1.discount_unitar_val,
13847                                                                       0),
13848                                                                   pack_facturare.ndiscount_evidentiat,
13849                                                                   a1.cantitate,
13850                                                                   a1.pret_cu_tva,
13851                                                                   a1.proc_tvav)) as SUMA_TVA_VAL,
13852                      sum(round(a1.cantitate * a1.pret_achizitie,
13853                                lnPrecizieCalcul)) AS VALOARE_ACHIZITIE,
13854                      max(decode(pack_facturare.nin_valuta, 1, a1.id_valuta, 0)) as id_valuta,
13855                      max(decode(pack_facturare.nin_valuta, 1, a1.curs, 1)) as curs,
13856                      max(decode(pack_facturare.nin_valuta, 1, a1.multiplicator, 1)) as multiplicator
13857                 from (select vd.id_vanzare_set,
13858                              (case
13859                                when (pack_facturare.nin_valuta = 1 or
13860                                     vd.id_valuta <>
13861                                     pack_def.GetIdMonedaNationala()) then
13862                                 ROUND(vc.curs * vd.pret / vc.multiplicator,
13863                                       lnPreciziePretV)
13864                                else
13865                                 vd.pret
13866                              end) as pret_ron,
13867                              vd.pret as pret_val,
13868                              vd.proc_tvav,
13869                              vd.cantitate,
13870                              vd.diferenta,
13871                              (case
13872                                when (pack_facturare.nin_valuta = 1 or
13873                                     vd.id_valuta <>
13874                                     pack_def.GetIdMonedaNationala()) then
13875                                 ROUND(vc.curs * vd.discount_unitar /
13876                                       vc.multiplicator,
13877                                       lnPreciziePretV)
13878                                else
13879                                 vd.discount_unitar
13880                              end) as discount_unitar_ron,
13881                              vd.discount_unitar as discount_unitar_val,
13882                              vd.id_valuta,
13883                              vd.pret_cu_tva,
13884                              vd.pret_achizitie,
13885                              vc.curs,
13886                              vc.multiplicator
13887                         from (select a.id_vanzare_set,
13888                                      a.pret,
13889                                      a.proc_tvav,
13890                                      a.cantitate,
13891                                      a.diferenta,
13892                                      a.discount_unitar,
13893                                      a.id_valuta,
13894                                      a.pret_cu_tva,
13895                                      a.pret_achizitie
13896                                 from VANZARI_DETALII_TEMP a
13897                                where nvl(a.id_vanzare_set, 0) = 0
13898                               union all
13899                               select b.id_vanzare_set,
13900                                      b.pret,
13901                                      max(c.proc_tvav) as proc_tvav,
13902                                      b.cantitate,
13903                                      0 as diferenta,
13904                                      b.discount_unitar,
13905                                      decode(pack_facturare.nin_valuta,
13906                                             0,
13907                                             pack_def.GetIdMonedaNationala(),
13908                                             c.id_valuta) as id_valuta,
13909                                      b.pret_cu_tva,
13910                                      sum(decode(b.cantitate,
13911                                                 0,
13912                                                 0,
13913                                                 c.pret_achizitie * c.cantitate /
13914                                                 b.cantitate)) as pret_achizitie
13915                                 from vanzari_detalii_temp c
13916                                 left join vanzari_seturi b
13917                                   on b.id_vanzare_set = c.id_vanzare_set
13918                                where nvl(c.id_vanzare_set, 0) <> 0
13919                                  and nvl(pack_facturare.nin_valuta, -1) > -1
13920                                group by b.id_vanzare_set,
13921                                         b.pret,
13922                                         b.cantitate,
13923                                         b.discount_unitar,
13924                                         b.pret_cu_tva,
13925                                         decode(pack_facturare.nin_valuta,
13926                                                0,
13927                                                pack_def.GetIdMonedaNationala(),
13928                                                c.id_valuta)) vd
13929                         left join vanzari_cursuri vc
13930                           on vc.id_vanzare = V_ID_VANZARE
13931                          and vd.id_valuta = vc.id_valuta) a1) a;
13932
13933       update vanzari
13934          set discount_tva      = lnDiscountTVA,
13935              valoare_achizitie = lnValoareAchizitie,
13936              total_fara_tva    = lnTotalFaraTVA,
13937              total_tva         = lnTotalTVA,
13938              total_cu_tva      = lnTotalCuTVA,
13939              valval            = lnValVal,
13940              tvaval            = lnTVAVal,
13941              totval            = lnTotVal,
13942              id_valuta         = lnIdValuta,
13943              curs              = lnCurs,
13944              multiplicator     = lnMultiplicator,
13945              serie_incasat     = lnSerieIncasat,
13946              nr_incasat        = lnNrIncasat,
13947              suma_incasat      = lnSumaIncasat,
13948              tip_incasat       = lnTipIncasat
13949        where id_vanzare = V_ID_VANZARE;
13950
13951       exception
13952         when NO_DATA_FOUND then
13953           null;
13954       end;
```

Variabilele locale relevante, declarate la `:13501-13523`:

```
13522     lnPrecizieCalcul   NUMBER(2) := pack_sesiune.getOptiuneFirma('PC');
13523     lnPreciziePretV    NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV');
```

### Inventarul dependentelor blocului

| Dependenta | Linii | Sursa la emitere | Echivalent PERSISTENT la editare | Verdict |
|---|---|---|---|---|
| `V_DISCOUNT_FACTURA` | 13798, 13801, 13802, 13807, 13810, 13813 | parametru al procedurii | **`VANZARI.DISCOUNT`** — scrisa la INSERT din exact acelasi parametru (`:13621` / `:13682`) | reconstituibil |
| `pack_facturare.nin_valuta` | 13796, 13803, 13804, 13854-13856, 13859, 13872, 13905, 13919, 13925 | stare de sesiune pe pachet | **`VANZARI.IN_VALUTA`** (`NUMBER(1)`, NOT NULL) — scrisa la INSERT din aceeasi variabila (`:13625` / `:13686`) | reconstituibil |
| `pack_facturare.ndiscount_evidentiat` | 13821, 13830, 13839, 13848 | stare de sesiune pe pachet | **`VANZARI.DISCOUNT_EVIDENTIAT`** — scrisa la INSERT din aceeasi variabila (`:13622` / `:13683`) | reconstituibil |
| `cserie_act_incasare`, `nnumar_act_incasare`, `nsuma_incasare`, `ntip_doc_incasare` | 13777-13780 | stare de sesiune, setata numai in fluxul de emitere (`:13102-13144`; resetate la `:1882-1886`) | **NICIUNUL** | vezi 6 |
| `pack_def.GetIdMonedaNationala()` | 13861, 13874, 13907, 13927 | functie pura: `SELECT MIN(ID_VALUTA) FROM NOM_VALUTE WHERE STERS=0 AND MONEDA_NATIONALA=1` (PACK_DEF body `:214-230`) | idem — fara stare | fara probleme |
| `pack_sesiune.getOptiuneFirma('PC'/'PPRETV')` | 13522-13523, 13853 | `SELECT varvalue FROM optiuni WHERE ...` (PACK_SESIUNE body `:119-141`) — **lookup pe tabela, fara stare de pachet** | idem | fara probleme |
| `VANZARI_DETALII_TEMP` (liniile directe) | 13896-13897 | GTT `ON COMMIT DELETE ROWS` | **`VANZARI_DETALII WHERE ID_VANZARE = :id AND STERS = 0 AND NVL(ID_VANZARE_SET,0) = 0`** | vezi 3 |
| `VANZARI_DETALII_TEMP` (liniile de set, alias `c`) | 13915, 13918 | GTT | **`VANZARI_DETALII ... AND NVL(ID_VANZARE_SET,0) <> 0`** | vezi 3 |
| `vanzari_seturi` (alias `b`) | 13916 | **tabela PERSISTENTA, deja** | ea insasi | vezi 3 |
| `vanzari_cursuri vc` | 13929-13930 | tabela persistenta, populata cu `id_vanzare`-ul curent la `:13704` (`scrie_cursuri`) | ea insasi, deja legata pe `ID_VANZARE` | fara probleme |

Verificat pe `all_tab_columns`: **toate cele 9 coloane citite din `VANZARI_DETALII_TEMP` de
agregare** (`id_vanzare_set, pret, proc_tvav, cantitate, diferenta, discount_unitar, id_valuta,
pret_cu_tva, pret_achizitie`) exista, cu acelasi nume, in `VANZARI_DETALII`. Singurele coloane pe
care TEMP le are in plus si care nu exista in tabela reala sunt `CURS, MULTIPLICATOR, EXPLICATIA,
ID_COMANDA, NUMAR_ACT, ID_TEMP, ID_UTIL, IN_STOC, PRETV_ORIG, ID_GESTIUNE_DEST, ID_LUCRARE_REZ,
ID_PART_REZ` — **niciuna nu e folosita de blocul de agregare** (`curs`/`multiplicator` vin din
`vanzari_cursuri vc`, nu din linie).

**Concluzie: blocul se reproduce 1:1 pe surse persistente, schimband doar clauzele `FROM` si
inlocuind cele 3 valori de stare cu cele 3 coloane din `VANZARI`.** Nu e nevoie de nicio
reformulare a formulei — inclusiv `calculeaza_total_fara_tva_fact` / `calculeaza_total_tva_fact`
(`PACK_FACTURARE.pck:15858-16013`, semnaturi in spec la `:1167-1185`) raman apelate identic.

Doua observatii de detaliu:
- `a1.diferenta` e selectata (`:13870`, `:13891`) dar **nu e folosita nicaieri** in agregarea din
  `scrie_in_vanzari` (parametrul `V_DIFERENTA` e `0` hard-codat la `:13817`, `:13826`, `:13835`,
  `:13844`). Se poate pastra pentru fidelitate sau elimina; recomand pastrarea, ca diff-ul fata de
  original sa ramana citibil.
- Handler-ul `WHEN NO_DATA_FOUND THEN NULL` (`:13951-13953`) e defensiv si practic inaccesibil:
  subinterogarea are agregate fara `GROUP BY`, deci intoarce mereu exact un rand. **Dar** pe zero
  linii agregatele intorc `NULL`, nu `0` — la emitere cazul nu poate aparea, la editare da (vezi
  riscul R4).

---

## 3. Liniile din seturi — EXISTA echivalent persistent

**Corectia raportului precedent.** Agregarea nu citeste `VANZARI_SETURI_TEMP`, ci
**`VANZARI_SETURI`** (`PACK_FACTURARE.pck:13916`), care e o tabela **normala, persistenta**
(verificat pe `all_tables`: `VANZARI_SETURI temporary=N`; doar `VANZARI_SETURI_TEMP` si
`VANZARI_DETALII_TEMP` sunt `temporary=Y duration=SYS$TRANSACTION`).

Trecerea TEMP -> persistent o face `pack_facturare.scrie_seturi` (`:13993-14028`), apelata la
`:13706`, **inainte** de agregare: insereaza fiecare rand din `VANZARI_SETURI_TEMP` in
`VANZARI_SETURI` (`ID_VANZARE_SET` din `SEQ_VANZARI_SETURI`, prin trigger
`TRG_VANZARI_SET_BEFOINS`) si reface pointerul in `VANZARI_DETALII_TEMP.ID_VANZARE_SET`. De aceea
agregarea de la `:13915-13928` face join intre TEMP (componentele) si tabela persistenta (capul de
set).

Structura `VANZARI_SETURI` (`all_tab_columns`), identica cu a TEMP-ului:

```
ID_VANZARE_SET  NUMBER(10)   NOT NULL   -- PK, din SEQ_VANZARI_SETURI
DENUMIRE        VARCHAR2(100)
EXPLICATIE      VARCHAR2(100)
CANTITATE       NUMBER(10,4)
UM              VARCHAR2(10)
SERIE           VARCHAR2(100)
PRET            NUMBER(20,4)
DISCOUNT_UNITAR NUMBER(20,4)
PRET_CU_TVA     NUMBER(1)    NOT NULL
```

Nu are `ID_VANZARE` si nu are `STERS`: legatura cu documentul e **exclusiv** prin
`VANZARI_DETALII.ID_VANZARE_SET`. Deci filtrarea pe document se face tot din `VANZARI_DETALII`.

**Precedent care confirma reconstituirea**: `pack_facturare.citeste_vanzari_seturi`
(`:16619-16698`) reface deja exact acest lucru pe surse persistente — `VANZARI` (`cod`, `sters=0`)
+ `VANZARI_DETALII` (`sters=0`, `id_vanzare_set is not null`) + `VANZARI_CURSURI` +
`VANZARI_SETURI`, cu acelasi `GROUP BY b.id_vanzare_set`. Nu inventam un tipar nou.

**Raspuns la intrebarea din brief: DA, recalculul poate acoperi si liniile de set, fara pierdere de
informatie.** Transformarea necesara in ramura de set:

```
from vanzari_detalii c            -- in loc de vanzari_detalii_temp c
left join vanzari_seturi b on b.id_vanzare_set = c.id_vanzare_set
where nvl(c.id_vanzare_set, 0) <> 0
  and c.id_vanzare = V_ID_VANZARE
  and c.sters = 0
```

Date (test, `MARIUSM_AUTO`): 4 randuri in `VANZARI_SETURI`, 4 documente cu linii de set. **Nu e o
dovada** — validarea ramane pe cod, nu pe volum.

### Ce NU se poate face din interfata (limitare de semnalat pentru S4)

View-ul `VVANZARI_ARTICOLE` (sursa lui `IncarcaArticoleFactura`,
`COMUN\programe\ofacturare_editare.prg:288-330`) **nu expune `ID_VANZARE_SET` si nici
`PRET_ACHIZITIE`**:

```
select vd.id_vanzare, vd.id_vanzare_det, vd.id_articol, vd.cantitate, vd.pret, vd.pret_cu_tva,
       vd.proc_tvav, vd.discount_unitar, vd.id_gestiune, vd.cont, vd.id_valuta,
       vd.id_jtva_coloana, vd.serie, vd.explicatie, vd.taxcode, vd.lot, vd.sters,
       na.denumire, na.codmat, ng.nume_gestiune, nv.nume_val
  from vanzari_detalii vd
  left join nom_articole na on na.id_articol = vd.id_articol
  left join nom_gestiuni ng on ng.id_gestiune = vd.id_gestiune
  left join nom_valute nv on nv.id_valuta = vd.id_valuta
```

Consecinte concrete:

1. componentele de set apar in grid ca linii obisnuite, dar formularul **nu poate sti** ca sunt
   componente si nu poate edita capul de set (`VANZARI_SETURI.PRET`/`CANTITATE`), care e ceea ce
   intra efectiv in totaluri. Un utilizator care schimba pretul unei componente **nu schimba
   totalul documentului** — recalculul ia pretul din `VANZARI_SETURI`. Divergenta tacuta.
2. `PRET_ACHIZITIE` lipseste din cursor, deci VFP nu-l poate rescrie la un `UPDATE` de linie: la
   scriere trebuie **omis din `SET`**, ca sa ramana valoarea existenta (altfel `VALOARE_ACHIZITIE`
   se pierde). Pentru liniile **noi** insa nu exista sursa — vor intra cu `PRET_ACHIZITIE` NULL si
   vor contribui cu NULL la `SUM(round(cantitate * pret_achizitie))`, deci **`VALOARE_ACHIZITIE`
   devine NULL pe tot documentul** daca fie si o singura linie noua are NULL. Vezi riscul R3.

---

## 4. Capcana de ordonare — punctul central

### Ce ruleaza azi, in ce ordine

Punctul de intrare nou (deja scris in ramura curenta):
`COMUN\clase\ofacturare_comun.vc2`, `do_editare_factura`, blocul de salvare:

```
3798   If Thisform.do_deschide_tranzactie()                      && SQLSetprop(gnHandle,"Transactions",2)
3800     lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.)                  && marcheaza STERS=1 nota veche
...
3820     lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.)                  && scrie nota noua (COD nou din SCRIE_IN_ACT)
3823     If lnSucces > 0
3824       lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end]
3826       lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1)
3827     Endif
3828     If Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1))    && SQLCOMMIT / SQLROLLBACK
```

`do_deschide_tranzactie` / `do_inchide_tranzactie`: `COMUN\clase\_frm_base.vc2:251-269` si
`:278-302` — `SQLSetprop(gnHandle,"Transactions",2)` / `Sqlcommit(gnHandle)`.

`finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`) apeleaza `actualizeaza_vanzari` la
`:8616`, gardat de `SELECT COUNT(*) FROM vanzari WHERE cod = tnCod > 0` (`:8613-8615`).

`actualizeaza_vanzari` (`PACK_FACTURARE.pck:16015-16025`):

```
16018     -- de modificat in caz ca il las sa stearga manual inregistrari din VANZARI_DETALII
16019     -- acum se marcheaza cu STERS = 1 doar cand se sterge toata factura
16020     UPDATE VANZARI_DETALII
16021        SET STERS = 0
16022      WHERE ID_VANZARE IN
16023            (SELECT ID_VANZARE FROM VANZARI WHERE COD = V_COD_VECHI);
16024     UPDATE VANZARI SET COD = V_COD_NOU, STERS = 0 WHERE COD = V_COD_VECHI;
```

### De ce exista `STERS = 0` acolo (nu e cod mort)

E perechea lui `sterge_din_vanzari` -> `sterge_factura`, care marcheaza documentul sters:

```
5549     UPDATE VANZARI_DETALII
5550        SET STERS = V_STERS, ID_UTILS = V_ID_UTIL, DATAORAS = V_DATAORA
5551      WHERE ID_VANZARE = V_ID_VANZARE
5552        AND STERS = V_NESTERS
```

Reeditarea unei note sterse trebuie sa readuca la viata si randul din `VANZARI`, si liniile lui.
**Scoaterea reset-ului ar rupe fluxul „stergi nota, apoi o reeditezi" pe toata suita ROA.**

### Consecinta pentru S5 — mai grava decat „stergerile se pierd"

Reset-ul e **in bloc, fara nicio garda**: nici `AND STERS = 1` (irelevant), nici o discriminare
intre „stersa ca linie" si „stersa odata cu documentul". `sterge_factura` marcheaza doar liniile
active (`AND STERS = V_NESTERS`, `:5552`), deci o linie stearsa la o editare anterioara ramane
`STERS=1` — si e **inviata** de `actualizeaza_vanzari` la urmatoarea salvare a notei.

Deci daca liniile se scriu inainte de `finalizeaza_modificare_nota`:

- stergerile din editarea CURENTA se pierd tacut;
- **si**, independent de ce face utilizatorul acum, orice stergere facuta la o editare
  ANTERIOARA e anulata la fiecare salvare ulterioara — inclusiv la o salvare care nu atinge deloc
  articolele. Stergerea de linie **nu s-ar fixa niciodata**.

`UPDATE`-urile de pret/cantitate si `INSERT`-urile de linii noi ar supravietui — deci esecul e
partial si asimetric, exact tipul care trece de un test superficial.

### Variantele de ordonare

**(a) VFP scrie detaliile inainte, `actualizeaza_vanzari` neatinsa.**
Respinsa. Motivul complet e cel de mai sus: nu doar ca stergerile din sesiunea curenta se pierd,
dar mecanismul de stergere de linie devine structural imposibil, fiindca fiecare salvare a notei
reseteaza tot documentul la `STERS = 0`. In plus, dupa `actualizeaza_vanzari` `VANZARI.COD` s-a
schimbat, deci orice scriere ulterioara ancorata pe `cod` ar rata randul (`ID_VANZARE` ramane —
vezi A.1 din raportul precedent, reconfirmat la `:16024`).

**(a') VFP scrie inainte + `actualizeaza_vanzari` primeste o garda.**
Respinsa. Ar cere un discriminator „stearsa ca linie" vs „stearsa cu documentul", care nu exista in
schema (`VANZARI_DETALII` nu are alt marcaj decat `STERS`/`ID_UTILS`/`DATAORAS`); orice euristica
pe `DATAORAS` e fragila. Si e Varianta A din raportul precedent — modificare in-place a unei
proceduri apelate de **orice** editare de nota cu `cod` in `vanzari`, din toata suita ROA.

**(b) VFP scrie detaliile DUPA ce `finalizeaza_modificare_nota` s-a intors, apoi apeleaza
`pack_facturare.recalculeaza_totaluri_vanzari(id_vanzare, discount)`, in aceeasi tranzactie.**
**RECOMANDATA.** Verificat, nu presupus:

- **tranzactia e inca deschisa** cand se intoarce `finalizeaza_modificare_nota`: aceasta ruleaza la
  `ofacturare_comun.vc2:3826`, iar `do_inchide_tranzactie` abia la `:3828`; tranzactia e manuala pe
  `gnHandle` (`_frm_base.vc2:255`), aceeasi conexiune ODBC pe care ruleaza `goExecutor`. Deci
  scrierile de dupa intra in acelasi `COMMIT`/`ROLLBACK`, fara fereastra de inconsistenta.
- `actualizeaza_vanzari` ramane **neatinsa** — zero regresie pe ROAGEST/ROACONT.
- `PACK_CONTAFIN` ramane **neatins** — nu se recompileaza pachetul central de scriere a
  documentelor.
- reset-ul `STERS = 0` ruleaza primul, iar VFP re-aplica dupa el starea autoritativa a liniilor.
- `VANZARI.COD` e deja rescris cand VFP scrie — de aceea toate scrierile se ancoreaza pe
  `ID_VANZARE` (`lnIdVanzare`, citit din `crsfacturi` la `ofacturare_comun.vc2:3735`, stabil).

**Atentie — (b) naiv are un defect.** `IncarcaArticoleFactura` incarca **doar `sters = 0`**
(`ofacturare_editare.prg:302`), deci liniile sterse la o editare anterioara nu sunt in
`crsArticoleFactura`: reset-ul le-a inviat, iar VFP nu le atinge, deci raman active. Corectia e in
**forma scrierii**, nu in Oracle — VFP scrie o stare completa, nu un delta:

```
1. UPDATE VANZARI_DETALII SET STERS = 1, ID_UTILS = ?, DATAORAS = SYSDATE
    WHERE ID_VANZARE = <id> AND STERS = 0                        -- marcheaza tot
2. pentru fiecare linie pastrata din cursor, cu id_vanzare_det > 0:
   UPDATE VANZARI_DETALII SET STERS = 0, CANTITATE = ?, PRET = ?, PRET_CU_TVA = ?, ...
    WHERE ID_VANZARE_DET = <det>                                 -- invie doar ce ramane
3. pentru fiecare linie noua: INSERT INTO VANZARI_DETALII (...)  -- ID_VANZARE_DET din trigger
4. pack_facturare.recalculeaza_totaluri_vanzari(<id>, <discount>)
```

Idiomul „marcheaza tot, invie ce ramane" e idempotent, nu are limita de 1000 de elemente intr-un
`IN`, nu cere lista separata de linii sterse, si pastreaza sterse liniile scoase la editari
anterioare. La pasul 2, `PRET_ACHIZITIE` se **omite** din `SET` (nu e in cursor — vezi 3).

**(c) recalcul apelat din interiorul `finalizeaza_modificare_nota`** (recomandarea raportului
precedent, sectiunea B). **De abandonat.** Este incompatibila cu (b): daca recalculul ruleaza
inauntrul lui `finalizeaza_modificare_nota`, el vede liniile **vechi** (VFP nu le-a scris inca,
pentru ca nu poate scrie inainte de reset), deci ar produce exact totalurile de dinainte de editare
— tacut corecte ca formula, tacut gresite ca valoare. Nu e o varianta mai riscanta, e o varianta
gresita.

**(c') procedura Oracle care primeste si liniile** (prin `VANZARI_DETALII_TEMP` sau o colectie) si
face si scrierea, si recalculul. Respinsa: reintroduce calea TEMP pe care planul a exclus-o explicit
(`plan_06_editare_factura.md:106-114`), cere o forma de parametru incomoda prin ODBC, si dubleaza
scrierea per-linie pe care planul a decis-o deja in VFP, dupa modelul `modifica_explicatie_articol`
(`PACK_FACTURARE.pck:14514-14522`).

### Recomandare

**Varianta (b), cu scrierea in forma „marcheaza tot, invie ce ramane".** Argumentul decisiv nu e
comoditatea, ci ca e **singura ordine in care reset-ul `STERS = 0` din `actualizeaza_vanzari` ramane
inofensiv fara sa modificam procedura** — iar procedura aceea e folosita azi de toata suita, pentru
un scop legitim (reeditarea unei note sterse) pe care nu-l putem sacrifica.

---

## 5. Discountul de document (`VANZARI.DISCOUNT`)

**Cine il scrie azi: nimeni, dupa emitere.** Verificat pe toata schema, nu doar pe `PACK_FACTURARE`:

- `all_source` (`PACKAGE BODY`/`PROCEDURE`/`FUNCTION`/`TRIGGER`, `MARIUSM_AUTO`), cautand
  `discount\s*=` exclusiv coloanele `discount_unitar|discount_tva|discount_evidentiat`: **niciun
  `UPDATE ... SET DISCOUNT = ...` pe `VANZARI`.** Rezultatele sunt toate pe alte tabele
  (`PACK_COMENZI.PROC_DISCOUNT`, `PACK_CRM.val_discount`, `PACK_OFERTARE.valdiscount`, ...).
- Toate cele 8 instructiuni `UPDATE VANZARI` din `PACK_FACTURARE` (`:5485, :5493, :5516, :5615,
  :14817, :15387, :15397, :15509`) plus `modifica_date_factura` (`:14463-14512`, singura procedura
  de „modifica antetul facturii" existenta) ating `STERS`/`FACTURAT`/`ID_FACT`/`AVIZE`/
  `SERIE_ACT`/`NUMAR_ACT`/`DATA_ACT`/`DATA_SCAD` — **niciuna `DISCOUNT`**.
- In VFP: cautare pe `COMUN\` dupa `set discount =` / `vanzari set ... discount` — **niciun
  rezultat**.
- Trigger-ele pe `VANZARI` nu-l ating: `TRG_VANZARI_BEFOUPD` face doar audit pe
  `NR_ACT`/`SERIE_ACT`/`DATA_ACT`/`DATA_SCAD` (`pack_audit.verifica_val`).

Deci `VANZARI.DISCOUNT` e scris **o singura data in viata documentului**, la `INSERT`-ul din
`scrie_in_vanzari` (`:13621` in lista de coloane, `:13682` in `VALUES`, din `V_DISCOUNT_FACTURA`).
Nu exista nici procedura de modificare, nici cale VFP.

Pe partea VFP valoarea e deja disponibila in memorie: cursorul `tvanz` are coloana `discount`
(`ofacturare_editare.prg:152`, `CreeazaCursorTvanzGol`), populata din `VANZARI` de
`IncarcaVanzareNota` (`:176`).

### Recomandare: **parametru al procedurii noi**, nu `UPDATE` separat din VFP

```
recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, V_DISCOUNT IN NUMBER DEFAULT NULL)
```

cu semantica `V_DISCOUNT IS NULL` = „pastreaza valoarea curenta". Motive:

1. **discountul si totalurile nu pot diverge.** Cu doua instructiuni separate din VFP, un esec pe
   a doua (sau o omisiune la un viitor call-site) lasa `DISCOUNT` nou si totaluri calculate pe cel
   vechi. Cu un parametru, e imposibil sa recalculezi cu un discount invechit.
2. procedura ramane utilizabila ca **recalcul pur** (fara al doilea argument) de oriunde altundeva
   — de exemplu dintr-un script de backfill.
3. e o instructiune ODBC in minus pe drumul critic.

Implementare: `V_DISCOUNT` se aplica in acelasi `UPDATE vanzari` final,
`discount = NVL(V_DISCOUNT, discount)`, iar valoarea folosita in agregare se citeste **inainte**,
ca `NVL(V_DISCOUNT, (select discount from vanzari where id_vanzare = V_ID_VANZARE))` — altfel
agregarea ar lucra pe discountul vechi.

---

## 6. Coloanele care NU se recalculeaza — reconfirmat pe sursa proaspata

`SERIE_INCASAT` / `NR_INCASAT` / `SUMA_INCASAT` / `TIP_INCASAT` (`:13777-13780`, scrise la
`:13945-13948`) vin din `pack_facturare.cserie_act_incasare` / `nnumar_act_incasare` /
`nsuma_incasare` / `ntip_doc_incasare`.

Cautare exhaustiva a atribuirilor catre aceste 4 variabile in `PACK_FACTURARE.pck` — **7 rezultate,
toate in fluxul de emitere**:

```
1882-1886   cserie_act_incasare := NULL; nnumar_act_incasare := NULL;
            ntip_doc_incasare := NULL; nsuma_incasare := NULL;    (initializeaza_date_factura)
13102-13105 cserie_act_incasare := V_SERIE_ACT_INCASARE; nnumar_act_incasare := V_NUMAR_ACT_INCASARE;
            ntip_doc_incasare := nTipIncasareChitanta; nsuma_incasare := 0;
13136       nsuma_incasare := nsuma_incasare + ...
13140,13144 ntip_doc_incasare := V_TIP / nTipIncasareBonFiscal;
```

Sursele lor (`V_SERIE_ACT_INCASARE`, `V_NUMAR_ACT_INCASARE`) sunt parametri ai emiterii unei
facturi-cu-incasare combinata. **Nu exista nicio tabela din care sa fie reconstituite la o editare
ulterioara** — singura urma persistenta sunt chiar cele 4 coloane din `VANZARI`, care ar fi
suprascrise cu `NULL` de o copiere naiva a `UPDATE`-ului.

**Concluzie reconfirmata: procedura noua scrie 11 coloane** (`discount_tva`, `valoare_achizitie`,
`total_fara_tva`, `total_tva`, `total_cu_tva`, `valval`, `tvaval`, `totval`, `id_valuta`, `curs`,
`multiplicator`), **plus optional `discount`** (vezi 5). Cele 4 de incasare raman la valoarea de la
emitere.

---

## 7. Semnatura propusa si scripturile de migrare

### Declaratia din PACKAGE SPEC

Se adauga imediat dupa `actualizeaza_vanzari` (`PACK_FACTURARE.pck:1187-1188`), langa procedurile
surori:

```sql
  PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER,
                                          V_DISCOUNT   IN NUMBER DEFAULT NULL);
```

`recalculeaza_totaluri_vanzari` = **29 de caractere**, sub limita de 30 a lui Oracle 10.2/11
(peste 30 ar da `ORA-00972`). Nu mai lungi numele.

### Corpul (schita, compatibila 10.2)

Constructii folosite: `SELECT INTO`, `UPDATE`, `DECODE`, `CASE`, `NVL`, `ROUND`, `MAX`, `SUM`,
`LEFT JOIN`, `UNION ALL`, `GROUP BY`, subinterogari inline. **Nimic din tabelul de incompatibilitati
din `scripturi-migrare-db.md`** — fara `LISTAGG`, `CONTINUE`, `REGEXP_COUNT`, `FETCH FIRST`,
`PIVOT`, `secventa.NEXTVAL` in atribuire.

```sql
  PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER,
                                          V_DISCOUNT   IN NUMBER DEFAULT NULL) IS
    lnDiscountFactura     VANZARI.DISCOUNT%TYPE;
    lnInValuta            VANZARI.IN_VALUTA%TYPE;
    lnDiscountEvidentiat  VANZARI.DISCOUNT_EVIDENTIAT%TYPE;
    lnDiscountTVA         VANZARI.DISCOUNT_TVA%TYPE;
    lnValoareAchizitie    VANZARI.VALOARE_ACHIZITIE%TYPE;
    lnTotalFaraTVA        VANZARI.TOTAL_FARA_TVA%TYPE;
    lnTotalTVA            VANZARI.TOTAL_TVA%TYPE;
    lnTotalCuTVA          VANZARI.TOTAL_CU_TVA%TYPE;
    lnValVal              VANZARI.VALVAL%TYPE;
    lnTVAVal              VANZARI.TVAVAL%TYPE;
    lnTotVal              VANZARI.TOTVAL%TYPE;
    lnIdValuta            VANZARI.ID_VALUTA%TYPE;
    lnCurs                VANZARI.CURS%TYPE;
    lnMultiplicator       VANZARI.MULTIPLICATOR%TYPE;
    lnPrecizieCalcul      NUMBER(2) := pack_sesiune.getOptiuneFirma('PC');
    lnPreciziePretV       NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV');
  BEGIN
    SELECT NVL(V_DISCOUNT, discount), in_valuta, NVL(discount_evidentiat, 0)
      INTO lnDiscountFactura, lnInValuta, lnDiscountEvidentiat
      FROM vanzari
     WHERE id_vanzare = V_ID_VANZARE;

    -- acelasi bloc de agregare ca in scrie_in_vanzari (:13764-13931), cu trei substitutii:
    --   VANZARI_DETALII_TEMP a  -> VANZARI_DETALII a WHERE a.id_vanzare = V_ID_VANZARE AND a.sters = 0
    --   vanzari_detalii_temp c  -> vanzari_detalii  c WHERE c.id_vanzare = V_ID_VANZARE AND c.sters = 0
    --   pack_facturare.nin_valuta            -> lnInValuta
    --   pack_facturare.ndiscount_evidentiat  -> lnDiscountEvidentiat
    --   V_DISCOUNT_FACTURA                   -> lnDiscountFactura
    -- fara coloanele de incasare (serie/nr/suma/tip)
    SELECT ... INTO lnDiscountTVA, lnValoareAchizitie, lnTotalFaraTVA, lnTotalTVA,
                    lnTotalCuTVA, lnValVal, lnTVAVal, lnTotVal,
                    lnIdValuta, lnCurs, lnMultiplicator
      FROM ( ... );

    UPDATE vanzari
       SET discount          = lnDiscountFactura,
           discount_tva      = lnDiscountTVA,
           valoare_achizitie = lnValoareAchizitie,
           total_fara_tva    = lnTotalFaraTVA,
           total_tva         = lnTotalTVA,
           total_cu_tva      = lnTotalCuTVA,
           valval            = lnValVal,
           tvaval            = lnTVAVal,
           totval            = lnTotVal,
           id_valuta         = lnIdValuta,
           curs              = lnCurs,
           multiplicator     = lnMultiplicator
     WHERE id_vanzare = V_ID_VANZARE;
  END recalculeaza_totaluri_vanzari;
```

Idempotenta: `SELECT` + `UPDATE ... WHERE id_vanzare = :id`, fara `INSERT` — rularea de doua ori pe
acelasi id da acelasi rezultat.

**Fara handler `WHEN NO_DATA_FOUND THEN NULL`** pe modelul originalului: la editare, un `id_vanzare`
inexistent e o eroare reala care trebuie sa opreasca tranzactia, nu sa fie inghitita. (Primul
`SELECT INTO`, pe cheia primara, e singurul care poate ridica `NO_DATA_FOUND`.)

### Scripturile de migrare

Azi, 09.08.2026, in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08` nu exista niciun script cu data de azi
(ultimele sunt `..._2026_08_08_01` si `..._2026_08_08_02`), deci **`NN` porneste de la `01`**.
`NN` e secventa unica pe zi, comuna tuturor prefixelor.

**Un singur script**, fiindca S5 atinge un singur pachet si nimic altceva:

```
ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql
```

- prefix `ff_` — pachetul sta pe schema fiecarei firme;
- **un pachet sta singur in scriptul lui**: fara DDL de tabele si fara DML alaturi (nu e nevoie de
  niciunul — nu se adauga coloane si nu se curata date);
- contine SPEC + BODY (SPEC-ul se schimba: declaratia noua), CRLF obligatoriu, antet de 4-5 randuri,
  fara `select` de raportare, si se incheie cu
  `exec pack_migrare.UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql');` + `commit;`;
- `versiune_db.txt` din radacina proiectului se muta pe `2026_08_09_01` (fara newline final).

**Nu e nevoie de un script separat pentru `VVANZARI_ARTICOLE`** pentru S5 asa cum e proiectat aici
— dar vezi intrebarea 3 de mai jos, care ar cere unul (`NN = 02`, si atunci **inainte** de cel al
pachetului daca pachetul l-ar folosi; aici nu-l foloseste, deci ordinea e libera).

---

## 8. Riscuri si intrebari deschise

**R1 — Componentele de set sunt editabile in grid dar nu influenteaza totalurile. (mediu)**
`VVANZARI_ARTICOLE` nu expune `ID_VANZARE_SET`, deci S4 nu poate distinge componentele de liniile
normale; recalculul ia insa pretul/cantitatea din `VANZARI_SETURI`, nu din componente. Utilizatorul
modifica o componenta, apasa salvare, totalul nu se schimba. Tacut.
*Recomandarea mea:* pentru #6, **adauga `ID_VANZARE_SET` in `VVANZARI_ARTICOLE`** (script separat,
`ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql`) si fa liniile cu `id_vanzare_set` nenul
**needitabile in grid**, cu o eticheta („linie din set"). Editarea seturilor e o functionalitate
proprie, nu o extindere gratuita a lui S4. Alternativa minimala, daca Marius nu vrea scriptul de
view: blocheaza intreaga factura care contine seturi — dar asta contrazice decizia din
`plan_06_editare_factura.md:183-186` („fara blocarea facturilor care le contin").

**R2 — Stergerea unei componente de set. (mic, dar urat)**
Cu idiomul „marcheaza tot, invie ce ramane", stergerea in grid a unei componente lasa capul de set
in `VANZARI_SETURI` si celelalte componente pe loc: totalul ramane neschimbat (vine din cap), dar
`VALOARE_ACHIZITIE` scade (se pierde `pret_achizitie`-ul componentei). Divergenta partiala.
*Recomandare:* acoperit de R1 — daca liniile de set sunt needitabile, cazul dispare.

**R3 — `PRET_ACHIZITIE` NULL pe liniile noi anuleaza `VALOARE_ACHIZITIE` pe tot documentul. (mediu)**
`SUM(round(cantitate * pret_achizitie))` cu un singur operand NULL nu da NULL pe total (SUM ignora
NULL-urile), dar **linia noua nu contribuie deloc** — deci `VALOARE_ACHIZITIE` (baza de calcul a
marjei) subestimeaza sistematic dupa fiecare adaugare de linie. Coloana nu e in cursorul din grid si
nu are sursa la editare (la emitere vine din stoc/politica de pret).
*Recomandare:* la `INSERT`-ul liniei noi, VFP scrie `PRET_ACHIZITIE` cu pretul de achizitie curent
al articolului (acelasi lookup pe care il face `adauga_articol_factura_stoc`), sau, daca nu se poate
determina, cu `0` explicit si o avertizare in verificarile din S4b. **Nu lasa NULL tacut.**

**R4 — Factura fara nicio linie da totaluri NULL, nu 0. (mic)**
Agregatele pe zero randuri intorc NULL; la emitere cazul nu poate aparea, la editare da.
*Recomandare:* nu modifica formula (ar diverge de original). Interzice in S4b salvarea unei facturi
cu zero linii active — e oricum un document invalid.

**R5 — Linie cu valuta fara rand in `VANZARI_CURSURI`. (mic)**
`left join vanzari_cursuri vc on vc.id_vanzare = V_ID_VANZARE and vd.id_valuta = vc.id_valuta`
(`:13929-13930`): daca o linie ajunge cu o valuta pentru care documentul nu are curs, `vc.curs` e
NULL si `pret_ron` iese NULL. `CreeazaPoArticolNouTvd` primeste explicit valuta documentului
(`tnIdValutaDoc`, `ofacturare_editare.prg:356`), deci in fluxul proiectat nu ar trebui sa apara.
**NEVERIFICAT** ca S4 chiar transmite acel parametru pe toate caile de adaugare.
*Recomandare:* verificare in S4b, nu garda in Oracle.

**R6 — `pack_sesiune.getOptiuneFirma` intoarce `''` la orice eroare. (mic)**
`PACK_SESIUNE` body `:128-131`: `WHEN OTHERS THEN lcValue := ''`. Atribuit intr-un `NUMBER(2)`, `''`
devine NULL, iar `ROUND(x, NULL)` da NULL. Comportament identic cu cel de la emitere — deci nu e o
regresie introdusa de S5, dar merita stiut daca apar totaluri NULL inexplicabile.
*Recomandare:* nimic de facut in S5; consemnat pentru depanare.

**R7 — `ff_2026_08_08_01_COMUN_VVD_TOT.sql` aplicat in dev fara script pe disc. (de clarificat)**
Obiectul nu exista in `all_objects` sub niciun nume `VVD%`, deci probabil scriptul a creat altceva
sau a fost anulat ulterior. Fisierul lipseste din `SCRIPTURI_CLAR` -> nu ajunge la clienti.
*Recomandare:* intrebare pentru Marius, nu blocheaza S5.

### Intrebari pentru Marius

1. **Liniile de set (R1)** — le facem needitabile in grid, cu `ID_VANZARE_SET` adaugat in
   `VVANZARI_ARTICOLE` printr-un al doilea script? *Recomandarea mea: da.* Fara asta, editarea unei
   facturi cu seturi arata ca merge si nu merge.
2. **Discountul de document** — parametru al procedurii (`V_DISCOUNT ... DEFAULT NULL`), sau
   `UPDATE VANZARI SET DISCOUNT` separat din VFP? *Recomandarea mea: parametru*, ca discountul si
   totalurile sa nu poata diverge (vezi 5).
3. **`PRET_ACHIZITIE` pe linia noua (R3)** — se citeste din nomenclator/stoc la adaugare, sau se
   scrie `0` cu avertizare? *Recomandarea mea: citit din nomenclator*, cu `0` doar ca ultima
   rezerva, niciodata NULL.
4. **`VALVAL`/`TVAVAL`/`TOTVAL`** — raman in recalcul? *Recomandarea mea: da* (cost zero, fac parte
   din acelasi `SELECT`; excluderea lor ar lasa facturile in valuta inconsistente). Confirmare
   ceruta si in raportul precedent, inca neconfirmata.
5. **`ff_2026_08_08_01_COMUN_VVD_TOT.sql`** — script de lucru abandonat, sau lipseste din SVN?

---

## Ce a ramas neverificat

- **R5**: nu am verificat pe codul S4 in lucru ca `CreeazaPoArticolNouTvd` primeste efectiv valuta
  documentului pe toate caile de adaugare de linie.
- Nu am rulat nimic in Oracle in afara de `SELECT`-uri de dictionar si de export — **niciun DDL,
  niciun DML, niciun test de executie a procedurii propuse.** Corpul propus la 7 e schita, nu cod
  compilat.
- Numarul de documente cu seturi in `MARIUSM_AUTO` (4) e din date de test si **nu constituie
  dovada** pentru niciuna dintre afirmatiile de mai sus; toate concluziile sunt din cod.
