# Verificare discount pe linie de factura — frm_facturare_articole / VANZARI_DETALII Investigatie read-only. Toate liniile citate au fost verificate pe fisierul text real din working copy (`ofacturare.vc2`, 23087 linii, ultima scriere 07.08 22:18) si pe scripturile DDL din `D:\ROA\DATABASE\SCRIPTURI_CLAR`. Nu s-a executat nimic pe baza de date. ## 1. Confirmare/infirmare afirmatii initiale **Concluzie**: toate afirmatiile despre `frm_facturare_articole` sunt corecte, cu linii care se potrivesc exact sau aproape exact. Confirmat via `vfp_symbols.ps1 -Where` ca formularul `frm_facturare_articole` ocupa exact `ofacturare.vc2:10968-15739`. **Dovezi**: - `Column5.ControlSource = "discountctva"`, `Column5.Name = "cDiscountCTva"`, `Column5.ReadOnly = .T.` — confirmat la `ofacturare.vc2:12311-12317` (identic cu afirmatia). - `Column9.ControlSource = "vdiscountftva"`, `Column9.Name = "cVdiscountftva"`, **fara** `ReadOnly` — confirmat la `ofacturare.vc2:12340-12345` (identic). - Capete de coloana: `Caption = "Discount unitar cu TVA"` la `:12409`, `Caption = "Discount unitar in valuta fara TVA"` la `:12546` — ambele confirmate exact. - Excludere reciproca pe valuta la `ofacturare.vc2:15269-15278`: ``` 15269 If poDate.in_valuta = 0 15270 Thisform.grd_factura.RemoveObject([cVpretFtva]) 15271 Thisform.grd_factura.RemoveObject([cVdiscountftva]) 15272 Thisform.grd_factura.RemoveObject([cVvaldiminuatftva]) 15273 Else 15274 Thisform.grd_factura.RemoveObject([cPretFtva]) 15275 Thisform.grd_factura.RemoveObject([cDiscountctva]) ``` confirmat identic (linii exacte, nu doar apropiate). - `VANZARI_DETALII.DISCOUNT_UNITAR NUMBER(22,6)` — confirmat, dar cu precizare: linia corecta in `ff_2024_06_13_02_COMUN_FACTURARE.sql` e `:3` (nu si `:9`/`:16` cum lasa sa se inteleaga formularea initiala — acelea sunt `VANZARI_DETALII_TEMP` si, respectiv, `CRM_POLITICI_PRET_ART`, vezi punctul 4). ## 2. Consecinta practica pe ecran **Concluzie**: pe factura in lei, coloana vizibila e **"Discount unitar cu TVA"** (`discountctva`) si e **needitabila** in grid (`ReadOnly = .T.`). Pe factura in valuta, coloana vizibila e **"Discount unitar in valuta fara TVA"** (`vdiscountftva`) si **este editabila direct in grid** (nicio proprietate `ReadOnly` setata pe coloana sau pe `Text1`-ul ei → mosteneste default-ul VFP, `.F.`). **Dovezi**: - Ramane pe ecran: cand `in_valuta = 0` se elimina cele 3 coloane "V..." (inclusiv `cVdiscountftva`) → ramane `cDiscountCTva`. Cand `in_valuta <> 0` se elimina `cDiscountctva` (si celelalte 3 coloane fara "V") → ramane `cVdiscountftva`. (`:15269-15278`, citat mai sus). - Ca sa nu presupun ca lipsa lui `Column9.ReadOnly` inseamna implicit editabil, am verificat lantul de clase: grid-ul `grd_factura` e `ADD OBJECT 'grd_factura' AS _grdrow` (`:12263`), fara `ReadOnly` la nivel de grid intre `:12263-12364`; clasa `_grdrow` (`_grd_base.vc2:445`) nu seteaza `ReadOnly` nicaieri in propriul body, iar parintele ei `_grdbase`/`_grid` de asemenea nu (singurele 3 aparitii de `ReadOnly` in `_grd_base.vc2` sunt in clasa separata `_grdfooter`, neinrudita). Deci Column9 chiar e editabila. - Confirmare suplimentara: in formularul **`frm_facturare_articole2`** (prototip separat, clasa la `ofacturare.vc2:15741-19355`, NU formularul in productie), aceleasi doua coloane apar cu `ReadOnly` explicit: `Column5.ReadOnly = .F.` (`:16657`) si `Column9.ReadOnly = .F.` (`:16688`) — adica in prototip discountul e editabil in ambele monede direct din grid; in formularul real doar varianta in valuta e editabila din grid. ## 3. Poate operatorul introduce azi un discount pe linie, si pe ce cale **Concluzie**: da, poate — dar nu prin `do_calculeaza_discount` de la `frm_facturare_articole:13405-13424` (asta calculeaza discountul **global pe toata factura**, `Thisform.ndiscfactron`/`ndiscfactval`, nicio legatura cu `discountctva`/`vdiscountftva` pe linie — vezi corectia de la final). Calea reala e formularul **`frm_articol_factura`** (`ofacturare.vc2:1108-2659`), deschis din `do_adauga_articol` la adaugarea unui articol (`:12873`, `ofrmadarticol.Show(1)` doar daca `!tlImplicit`). Acolo exista metoda `frm_articol_factura.do_calculeaza_discount` (`:1874-1976`) legata de 3 controale editabile: `Clb_procent_discount.Text_simplu1` (procent), `Clb_discount_unitar.tx_suma_nat`/`tx_suma_val` (suma in lei / valuta), `Clb_discountctva.tx_suma_nat`/`tx_suma_val` (varianta cu TVA) — toate cu handler `Valid`/`InteractiveChange` care apeleaza `do_calculeaza_discount(valoare, tip)` cu `tip=1` procent, `tip=2` lei, `tip=3` valuta (`:2602-2624`, `:2646-2649`). **Lantul, cu linii**: 1. Operator tasteaza in unul din campurile de mai sus → `Valid`/`InteractiveChange` → `Thisform.do_calculeaza_discount(valoare, tip)` (`ofacturare.vc2:2602-2649`). 2. `do_calculeaza_discount` (`:1874-1976`) scrie in obiectul `poArticol`: `poArticol.discount_unitar`, `discount_unitar_val`, `discount_unitar_ctva`, `discount_unitar_ctva_val` (ex. `:1898-1906`, `:1943-1951`). 3. La revenirea in `do_adauga_articol` (`:12813-13086`), `poArticol` e scris in `crsfactura` prin `Gather`/`Replace`: ``` 12956 Replace id_temp With Recno(), codmat With Nvl(poArticol.codmat, Space(50)), ; ... 12957 discountftva With poArticol.discount_unitar, discountctva With poArticol.discount_unitar_ctva, ; vdiscountftva With Nvl(poArticol.discount_unitar_val, 0), vdiscountctva With Nvl(poArticol.discount_unitar_ctva_val, 0) ``` (linii `12956-12957`; varianta pentru selectie multipla de articole la `13003-13005`). 4. `discount_unitar` initial (inainte de tastare) e preluat din `crsarticole` (cursorul de stoc, populat inainte de deschiderea dialogului) prin `do_initializeaza_articol` (`:13618` si urm.): `toArticol.discount_unitar = Nvl(toArticol.discount_unitar, 0)` (`:13630`) — deci daca stocul / politica de pret vine deja cu un discount populat, acela e valoarea implicita afisata in dialog, pe care operatorul o poate suprascrie. 5. Cale suplimentara, directa: pe factura in valuta, cum `cVdiscountftva` e editabil in grid (punctul 2), operatorul poate scrie si direct in celula `vdiscountftva` din `grd_factura` — dar fara niciun `Valid`/`InteractiveChange` propriu definit pentru acea coloana in `frm_facturare_articole` (cautat explicit `cVdiscountftva`/`cDiscountCTva` in intervalul `10968-15739`: singurele hit-uri sunt definitiile de coloana si `RemoveObject`, niciun handler de eveniment) — editarea directa in grid NU declanseaza recalcularea automata a `vvaldiminuatftva`/totaluri, doar modifica valoarea bruta in `crsfactura`. ## 4. Structura reala a coloanelor de discount pe VANZARI_DETALII **Concluzie**: nu exista un `CREATE TABLE VANZARI_DETALII` in `SCRIPTURI_CLAR` (arhiva incepe din 2009, iar tabela exista deja atunci — coloana `DISCOUNT_UNITAR` era deja in uz in pachete PL/SQL din 2009, deci a fost creata inainte de arhiva). Singura coloana de discount pe `VANZARI_DETALII`/`VANZARI_DETALII_TEMP` gasita in `SCRIPTURI_CLAR` e **`DISCOUNT_UNITAR`**, si singura modificare de tip/precizie inregistrata e cea din 2024. **Dovezi (cronologic, tot ce am gasit cu `DISCOUNT` in contextul acestei tabele)**: - Nu exista niciun `CREATE TABLE VANZARI_DETALII` sau `ALTER TABLE VANZARI_DETALII ADD DISCOUNT...` in toata arhiva `SCRIPTURI_CLAR` (2009-2026). Cel mai vechi hit pe `DISCOUNT_UNITAR` legat de aceasta tabela e o declaratie de variabila `V_DISCOUNT_UNITAR VANZARI_DETALII.DISCOUNT_UNITAR%TYPE` in pachetul `PACK_FACTURARE`, prezenta deja in scripturile din 2009 (ex. `2009\9\ff_2009_09_03_01_FACTURARE_PACK_FACTURARE.sql`) — coloana exista deja atunci. - Singura modificare de precizie gasita: `ff_2024_06_13_02_COMUN_FACTURARE.sql:3` — `alter table VANZARI_DETALII modify discount_unitar NUMBER(22,6);` — si simetric pentru `VANZARI_DETALII_TEMP` la linia `:9`, si pentru `CRM_POLITICI_PRET_ART` (tabela de **politici de pret**) la linia `:16`. Deci forma finala confirmata: **`DISCOUNT_UNITAR NUMBER(22,6)`**, o singura coloana de discount (valoare, nu procent), identica pe toate cele 3 tabele. - Nu exista alte coloane `DISCOUNT%`/`VDISCOUNT%` la nivel Oracle pe `VANZARI_DETALII` — cele patru campuri VFP `discountftva`/`discountctva`/`vdiscountftva`/`vdiscountctva` din `crsfactura` NU au corespondent 1:1 in schema Oracle; la scriere (`Gather`/`Replace` in `do_adauga_articol`, punctul 3) doar `discount_unitar` (si varianta cu TVA calculata din el) ajunge, prin campurile intermediare, la coloana unica Oracle. - Convenția de interogare a bazei de dezvoltare, gasita in `COMUN\docs\scripturi-migrare-db.md:36-40`: sursa de referinta pentru DDL e schema de dezvoltare **`MARIUSM_AUTO`** (bazata pe `ROA_CENTRAL`), interogata prin `goExecutor`, niciodata o schema de client. Nu am rulat nimic pe baza — doar raportez conventia, asa cum a cerut sarcina. ## 5. Coloana de procent de discount pe VANZARI_DETALII / campul procdisc **Concluzie**: **nu** exista o coloana de procent de discount pe `VANZARI_DETALII` (doar `DISCOUNT_UNITAR`, o valoare absoluta). Campul `procdisc` din `frm_facturare_articole2` e doar un camp de lucru in grid, **fara nicio scriere in cursorul local si fara corespondent Oracle** — practic un camp scaffolded si neconectat. **Dovezi**: - Cautare `DISCOUNT`+`PROCENT`/`PROC` in `ff_2024_06_13_02_COMUN_FACTURARE.sql` (scriptul care fixeaza forma finala a coloanelor de discount): nicio potrivire — confirma ca nu exista un "procent discount" ca si coloana pe `VANZARI_DETALII`. - `procdisc` apare **o singura data** in tot `ofacturare.vc2`: `Column14.ControlSource = "procdisc"` la `:16721`, in interiorul clasei `frm_facturare_articole2` (`15741-19355` — prototip, nu formularul in productie). - Nicio instructiune `Gather`/`Replace ... procdisc With ...` in tot fisierul (cautat pe tot `ofacturare.vc2`) — camp fara sursa de populare in cod. - Toate celelalte aparitii de "procdisc" din fisier sunt de fapt variabila de memorie `gnMemProcDisc` ("memorare procent discount" — o optiune de aplicatie care controleaza daca procentul de discount tastat se retine intre articole, `:2299`, `:2441`, `:12835` etc.), fara legatura cu campul de cursor `procdisc`. - Cautare `PROCDISC` in `SCRIPTURI_CLAR`: doar 2 hit-uri, ambele in scripturi din 2015 pentru tabela de **optiuni firma** (`co_2015_12_09_01_OPTIUNI.sql`, `ff_2015_12_09_01_OPTIUNI.sql`) — legate de aceeasi optiune `gnMemProcDisc`, nu de `VANZARI_DETALII`. ## Ce era gresit in afirmatiile de mai sus - Formularea "linia 3, 9, 16" pentru coloana Oracle `DISCOUNT_UNITAR` grupa laolalta 3 tabele diferite (`VANZARI_DETALII` la `:3`, `VANZARI_DETALII_TEMP` la `:9`, `CRM_POLITICI_PRET_ART` la `:16`) ca si cum ar fi acelasi lucru repetat de 3 ori — corect ca valoare (toate devin `NUMBER(22,6)`), dar sunt 3 tabele distincte, nu 3 confirmari ale aceleiasi coloane. - Cea mai importanta corectie: linia indicata pentru "de unde se scrie discountctva/vdiscountftva — din `do_calculeaza_discount` (`ofacturare.vc2:13405-13424`)" trimite la metoda gresita. `frm_facturare_articole.do_calculeaza_discount` de la acea linie calculeaza discountul **global pe factura** (`Thisform.ndiscfactron`/`ndiscfactval`), nu discountul pe linie. Metoda care chiar calculeaza `discount_unitar`/`discount_unitar_ctva` (sursa reala pentru `discountctva` si `vdiscountftva`) e **`frm_articol_factura.do_calculeaza_discount`**, o metoda cu acelasi nume dar in alta clasa, la `ofacturare.vc2:1874-1976`. Cele doua metode au nume identic dar apartin la doua clase diferite din acelasi fisier — o capcana reala de grep fara indexul de simboluri. ## Necunoscute ramase - Nu am verificat daca `crsarticole` (cursorul de stoc din care pleaca `poArticol.discount_unitar` la `do_initializeaza_articol:13630`) e populat vreodata cu un discount nenul direct dintr-o interogare de politica de pret (`CRM_POLITICI_PRET_ART`) inainte de a ajunge in dialogul `frm_articol_factura` — am gasit doar ca acea tabela are aceeasi coloana `discount_unitar` (`NUMBER(22,6)`), nu am urmarit interogarea SQL efectiva care umple `crsarticole`/`crsartselectate` (cod probabil in `Programe/`, in afara `ofacturare.vc2`, netrasat din lipsa de timp alocat). - Nu am confirmat pe date reale (Oracle) daca exista astazi randuri cu `DISCOUNT_UNITAR` populat pe `VANZARI_DETALII` provenind din editarea directa in grid pe factura in valuta (punctul 2/3, ultimul paragraf) — doar am aratat ca acea cale exista in cod, fara handler de recalcul. - Nu am cautat daca `frm_facturare_articole2` (prototipul) e instantiat undeva in productie sau e cu adevarat mort/nefolosit — task-ul l-a framat deja ca "prototip" si am pastrat presupunerea.