docs: cercetarile trans-proiect din ROAFACTURARE trec in COMUN

Paisprezece rapoarte care nu erau ale ROAFACTURARE traiau in docs\cercetare\ al
acelui proiect: valuta si curs in ofacturare, TVA calculat vs salvat plus
denormalizarea VANZARI, inventarul consumatorilor VANZARI din toata suita ROA,
integrarile de contracte/politici/nomenclator (#10, #11, #12), watchdog-ul VFP
de testare, proiectarea Oracle a scrierii din S5 si view-ul VVANZARI_ARTICOLE.

Motivul mutarii, nu doar al pastrarii: planurile #10, #11 si #12 sunt amanate,
iar indexul lor spune explicit ca se reiau din aceste rapoarte - deci sunt punct
de plecare, nu istoric. Iar tinta lor e COMUN plus ROAPRETURI/ROACONTRACTE.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
This commit is contained in:
2026-08-11 22:31:53 +03:00
parent 93a2718e6d
commit 09ddeabb1c
14 changed files with 3442 additions and 0 deletions

View File

@@ -0,0 +1,780 @@
# 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.