# R6: zecimale la Pret si aspect gri al campurilor editabile, grid Articole (frm_modific2024) Cercetare, fara modificari de cod. Zona: `COMUN\clase\omodificari.vc2`, clasa `frm_modific2024` (liniile 6375-16838), grid-ul de articole al facturii editate: `pgfArticole.PAGE3.grdArticoleFactura` (nu vechiul `Grid1`/`Column1..44` — acela e alt grid, RecordSource `"tACT"`, folosit pentru notele contabile, nu pentru articolele facturii; grid-ul de articole are 16 coloane numite, ADD OBJECT la `omodificari.vc2:12330`). ## Partea 1 — zecimalele la pret ### A. Coloanele monetare din grid si masca lor RecordSource al grid-ului = cursorul `tvd` (creat in `COMUN\programe\ofacturare_editare.prg:278`, populat in `IncarcaArticoleFactura`, `ofacturare_editare.prg:294-328`, din view-ul Oracle `VVANZARI_ARTICOLE`). | Coloana (Header) | Name | ControlSource | Format/InputMask | Linie | |---|---|---|---|---| | Pret | cPretArt | `tvd.pret` | `get_mask(12,gnPPRET)` | `omodificari.vc2:12391` | | Pret achizitie | cPretAchizitieArt | `tvd.pret_achizitie` | `get_mask(12,gnPPRET)` | `omodificari.vc2:12400` | | Pret cu TVA | cPretCuTvaArt | `tvd.pret_cu_tva` | **fara Format/InputMask** | `omodificari.vc2:12404-12409` | | Discount unitar | cDiscountUnitarArt | `tvd.discount_unitar` | `get_mask(12,gnPPRET)` | `omodificari.vc2:12426` | | Cantitate | cCantitateArt | `tvd.cantitate` | `get_mask(12,gnPCANT)` | `omodificari.vc2:12382` | | Valoare | cValoareArt | `tvd.valoare` | `get_mask(14,gnPa)` | `omodificari.vc2:12463` | | TVA % | cProcTvavArt | `tvd.proc_tvav` | `"9.99"` (fix, 2 zecimale) | `omodificari.vc2:12417` | Structura cursorului `tvd` (`ofacturare_editare.prg:278-281`): ``` pret N(14,4) NULL, pret_cu_tva N(14,4) NULL, proc_tvav N(6,4) NULL, discount_unitar N(14,4) NULL, ..., pret_achizitie N(14,4) NULL, ..., cantitate N(12,3) NULL (nu e in acest citat, vezi mai jos) ``` Precizia campurilor din cursor e **hardcodata** (4 zecimale la pret/pret_cu_tva/discount_unitar/ pret_achizitie, 3 la cantitate — vezi linia completa `ofacturare_editare.prg:278`), independent de `gnPPret`/`gnPCant`. Asta e doar plafonul de stocare; ce se AFISEAZA il decide InputMask-ul de pe coloana (cand exista). ### B. De unde vin cele 3 zecimale afisate la "Pret" **Nu dintr-un bug de masca lipsa.** Coloana "Pret" (`cPretArt`, `tvd.pret`) ARE InputMask legat de o variabila globala: `get_mask(12,gnPPRET)`, `omodificari.vc2:12391`. Daca `gnPPRET` = 3 in mediul curent, InputMask-ul produce exact 3 zecimale — comportamentul e "controlat de o variabila globala", exact ce cere utilizatorul. **Problema e ca variabila legata e cea gresita**: `gnPPRET`, nu `gnPPretV` — vezi punctul D. ### C. Ce este `gnPPret` si care e sablonul consacrat `gnPPret` e o variabila PUBLIC incarcata din firma (parametru `OPTIUNI.PPRET`), documentata deja in cercetarea anterioara `docs\cercetare\rec_fact008_pret_achizitie_zecimale.md:28`: > `OPTIUNI.PPRET` (precizia pretului de achizitie) = **3** (in mediul de productie investigat acolo) N-am gasit in acest proiect linia exacta unde `gnPPret` e citit din `OPTIUNI` si atribuit (cautare in `COMUN\programe\oinit_optiuni.prg` — gaseste `gnPA`, `gnPC`, `gnPCurs`, `gnPPretV`, `gnZ`, dar nu `gnPPret`; probabil incarcat generic, printr-un mecanism care nu foloseste literal sirul `"gnPPret ="`) — **NESTABILIT exact unde**, dar valoarea si semantica (precizie **achizitie**) sunt confirmate atat de raportul anterior cat si de tiparul de folosire de mai jos. Exista o familie de variabile de precizie, cu roluri distincte, confirmate prin comentarii si prin folosire consecventa in cod: - `gnPPret` — precizie **pret de achizitie** (cost). Folosire: `ofacturare_stoc.prg:364` `Alltrim(Str(poArticol.pret_achizitie,18,Max(gnPPret,4)))`; masti pe `pret_achizitie` in `ointroduceri.vc2:16390,19638` (`get_mask(12,gnPPret)`, coloana NIR). - `gnPPretV` — precizie **pret de vanzare**, comentata explicit `COMUN\programe\oinit_optiuni.prg:515`: `Store 0 To gnPPretV && nr. de zecimale pret vanzare`. Folosire masiva in `ofacturare_comun.prg` (peste 40 de locuri: `pretftva`, `pretctva`, `pretv_orig`, `discountftva` etc. — toate rotunjite/formatate cu `gnPPretV`) si, esential, la **scrierea efectiva a pretului de vanzare al liniei de factura**: `ofacturare_stoc.prg:367` — `Alltrim(Str(poArticol.Pret,18,Iif(poDate.in_valuta=1,gnPVal,gnPPretV)))` (in functia care insereaza randul in `VANZARI_DETALII`, aceeasi coloana `PRET` pe care o incarca `tvd.pret`). - `gnPCant` — precizie cantitate (`get_mask(12,gnPCANT)`, `omodificari.vc2:12382`). - `gnPc` (`gnPC`) — precizie de calcul/valoare (`get_mask(14,gnPa)`/`gnPc` la coloana Valoare). - `gnPa` (`gnPA`) — precizie de afisare generica (folosit la `cValoareArt`). Sablonul consacrat de constructie a mastii: `get_mask(nrCaractere, nrZecimale)` (`COMUN\programe\proceduri_comune.prg:1090-1110`) — construieste un sir `"999 999.999"` cu atatea `9` dupa punct cate zecimale i se dau; **nu exista logica speciala in `get_mask`**, deci diferenta de comportament vine strict din CE variabila i se paseaza la fiecare coloana. ### D. Modelul corect exista deja, in acelasi fisier de clase — `ofacturare.vc2` `COMUN\clase\ofacturare.vc2:3489-3498`, grid de rulaje/stoc, doua coloane invecinate: ``` Column5.ControlSource = "pret", ; Column5.InputMask = (get_mask(14,gnPPret)), ; && cost / achizitie Column5.Name = "cPret", ; ... Column6.ControlSource = "pretv", ; Column6.InputMask = (get_mask(14,gnPPretV)), ; && vanzare Column6.Name = "cPretv", ; ``` Acelasi tipar apare si in `COMUN\clase\ocomenzi.vc2:1174` (`This._grdrow2.cPret.InputMask = get_mask(14,gnPPretV)` — pret de vanzare pe comanda) si in `ointroduceri.vc2:10071,16390,19638` (`get_mask(...,gnPPret)` — toate pe campuri de **achizitie**, in formularele de NIR). **Regula confirmata in tot codul suitei: campul care reprezinta pretul de ACHIZITIE foloseste `gnPPret`; campul care reprezinta pretul de VANZARE al liniei foloseste `gnPPretV`.** Chiar scrierea in Oracle a coloanei `VANZARI_DETALII.PRET` (aceeasi coloana din care se umple `tvd.pret`) respecta aceasta regula: `ofacturare_stoc.prg:367` foloseste `gnPPretV`, nu `gnPPret`. ### Concluzie Partea 1 — defectul `omodificari.vc2:12391` — `Column6.InputMask = (get_mask(12,gnPPRET))` pentru **`cPretArt`** (`tvd.pret`, coloana "Pret" = pretul de VANZARE al liniei) foloseste variabila gresita din familie: **`gnPPRET`** (precizie achizitie) in loc de **`gnPPretV`** (precizie vanzare, cea corecta pentru acest camp). Coloana vecina, `cPretAchizitieArt` (`omodificari.vc2:12400`, `tvd.pret_achizitie`), foloseste corect `gnPPRET` — e evident ca la scrierea acestei sectiuni de grid s-a copiat masca de la achizitie si pe coloana de vanzare de langa ea. Daca in mediul reclamat `OPTIUNI.PPRET` (achizitie) = 3 si `OPTIUNI.PPRETV` (vanzare) e alta valoare (tipic 2), exact asta explica simptomul: coloana "Pret" (vanzare) afiseaza 3 zecimale pentru ca "imprumuta" precizia de achizitie, nu pe cea de vanzare. Coloana "Pret cu TVA" (`cPretCuTvaArt`) nu are deloc InputMask (`omodificari.vc2:12404-12409`) — nu e sursa celor "3 zecimale" reclamate la "Pret", dar e un defect inrudit: afiseaza precizia bruta a campului din cursor (4 zecimale, `pret_cu_tva N(14,4)`), necontrolata de nicio variabila globala. **Schita de interventie** (fara aplicare): `Column6.InputMask = (get_mask(12,gnPPRET))` -> `Column6.InputMask = (get_mask(12,gnPPretV))` la `omodificari.vc2:12391`, dupa modelul din `ofacturare.vc2:3497` / `ocomenzi.vc2:1174`. ## Partea 2 — fundalul gri al campurilor editabile ### E-F. Sursa reala a griului si divergenta Column.ReadOnly vs Text1.ReadOnly Confirmat: aproape toate coloanele au `DynamicForeColor` (nu `BackColor`) la nivel de coloana — un singur `IIF` pentru culoarea textului dupa `tvd.sters`/`id_vanzare_set`, identic pe toate cele 16 coloane (ex. `omodificari.vc2:12350`). **Niciun `DynamicBackColor`, niciun `Enabled=.F.`** pe coloane. Culoarea de fundal reala vine din proprietatea `BackColor` fixa a controlului `Text1` inclus in fiecare coloana (`ADD OBJECT '...Text1' AS textbox`), si **nu coincide cu `Column.ReadOnly`**: | Camp | Column.ReadOnly | Column linie | Text1.ReadOnly | Text1.BackColor | Text1 linii | |---|---|---|---|---|---| | Denumire (cDenumireArt) | `.F.` (editabil) | 12354 | **`.T.`** | **225,225,225 (gri)** | 12527-12536 | | Cod material (cCodmatArt) | `.T.` | 12361 | `.T.` | 225,225,225 | 12506-12515 (consistent) | | Serie (cSerieArt) | `.F.` (editabil) | 12368 | **`.T.`** | **225,225,225 (gri)** | 12734-12743 | | Lot (cLotArt) | `.F.` (editabil) | 12375 | **`.T.`** | **225,225,225 (gri)** | 12631-12640 | | Cantitate (cCantitateArt) | `.F.` | 12384 | `.F.` | 255,255,255 (alb) | 12485-12494 (consistent) | | Pret (cPretArt) | `.F.` | 12393 | `.F.` | 255,255,255 (alb) | 12673-12682 (consistent) | | Pret achizitie (cPretAchizitieArt) | `.F.` | 12402 | `.F.` | 255,255,255 (alb) | 12652-12661 (consistent) | | TVA % (cProcTvavArt) | `.F.` (editabil) | 12419 | **`.T.`** | **225,225,225 (gri)** | 12713-12722 | | Discount unitar (cDiscountUnitarArt) | `.T.` | 12428 | `.T.` | 225,225,225 | 12548-12557 (consistent) | | Gestiune (cGestiuneArt) | `.F.` (editabil) | 12435 | **`.T.`** | **225,225,225 (gri)** | 12610-12619 | | Valuta (cValutaArt) | `.F.` (editabil) | 12442 | **`.T.`** | **225,225,225 (gri)** | 12797-12806 | | Explicatie (cExplicatieArt) | `.F.` (editabil) | 12449 | **`.T.`** | **225,225,225 (gri)** | 12569-12578 | | Taxcode (cTaxcodeArt) | `.F.` (editabil) | 12456 | **`.T.`** | **225,225,225 (gri)** | 12755-12764 | | Valoare (cValoareArt) | `.T.` | 12465 | `.T.` | 225,225,225 | 12776-12785 (consistent) | | Explicatie TVA (cExplicatieTvaArt) | `.F.` (editabil) | 12472 | **`.T.`** | **225,225,225 (gri)** | 12589-12598 | **9 din 16 coloane sunt declarate editabile la nivel de `Column.ReadOnly=.F.` dar controlul `Text1` inclus e `ReadOnly=.T.` cu fundal gri (225,225,225).** In VFP, cand o coloana de grid contine un control custom (nu editorul implicit), editabilitatea reala vine din controlul inclus, nu din `Column.ReadOnly` — deci aceste 9 campuri **nu accepta tastare directa in celula**, indiferent ce spune `Column.ReadOnly`. Asta explica de ce aratau gri: griul e corect pentru "nu se editeaza prin tastare directa". Pentru unele din ele exista insa un mecanism real de editare, prin dialog, nu prin tastare: `cGestiuneArt.Text1.GotFocus` (`omodificari.vc2:12734`... de fapt liniile de cod sunt la `16734-16744`) seteaza `Thisform.pccontrol` si `InteractiveChange` deschide un editor: ``` PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cGestiuneArt.Text1.InteractiveChange (16739) loEditor = Createobject('ArticoleNotaEditor', Thisform) loEditor.ModificaNomenclator(Thisform.pccontrol) ``` Acelasi tipar la `cExplicatieTvaArt` (`16722-16732`). Pentru `cSerieArt`, `cLotArt`, `cExplicatieArt` exista doar un handler `.When` (`16745`, `16716`, `16804`) care blocheaza intrarea in celula cand `Thisform.lArticoleReadOnly` sau `id_vanzare_set<>0`, dar **niciun cod care sa comute `Text1.ReadOnly` la `.F.`** — n-am gasit nicio atribuire dinamica `.Text1.ReadOnly = ...` in tot corpul clasei `frm_modific2024` pentru aceste coloane (cautare exhaustiva pe intervalul 6375-16838). **Concluzie verificabila pe cod**: cu configuratia actuala, `cSerieArt`, `cLotArt`, `cExplicatieArt`, `cValutaArt`, `cTaxcodeArt`, `cDenumireArt`, `cProcTvavArt` **nu au niciun mecanism de editare activ in acest grid** — nici tastare (Text1.ReadOnly=.T.), nici editor prin dublu-clic/InteractiveChange (spre deosebire de cGestiuneArt/cExplicatieTvaArt, care au editor). Daca utilizatorul le percepe ca "editabile", fie testeaza cu date/build vechi, fie editarea se intampla prin alta cale neinventariata aici (buton `but_modificaR` — vezi mai jos, NESTABILIT unde e definit click-ul lui). `Thisform.but_modificaR.Enabled` se seteaza in `AfterRowColChange` (`omodificari.vc2:16678-16682`) dupa coloana curenta si `!lArticoleReadOnly`, sugerand un buton extern de "Modifica" — dar **n-am gasit definitia obiectului `but_modificaR` sau handler-ul lui de `Click` in `omodificari.vc2`** (cautare `grep -n "but_modificaR"` in tot fisierul: doar cele 7 referinte de mai sus, toate `.Enabled = ...` sau `.Visible = ...`, niciun `ADD OBJECT` sau `PROCEDURE but_modificaR...Click`). **NESTABILIT**: butonul e probabil mostenit dintr-o clasa parinte in afara acestui fisier — nu s-a investigat mai departe (ar necesita cautare in `_frm_base.vcx`/alte `.vc2` din `COMUN\clase`, in afara scopului "aceasta clasa"). ### G. Conventia de culoare in restul aplicatiei **Exista o conventie, si e vizibila chiar in acelasi fisier de clasa**, pe pagina "Rulaje" (`pgfArticole.PAGE1.grdRulaje`, alt tab al aceluiasi formular): - editabil prin tastare directa: `BackColor = 255,255,255` (alb) + `ReadOnly = .F.` — ex. `cPret.Text1`, `omodificari.vc2:9990-9999`. - editabil prin dialog (GotFocus seteaza `pccontrol`, InteractiveChange deschide editor): `BackColor = 160,255,205` (**verde deschis**) + `ReadOnly = .F.` — ex. `cGest.Text1` (`omodificari.vc2:9689-9698`) si `cDenumire.Text1` (`omodificari.vc2:9595-9604`). - needitabil: `BackColor = 225,225,225` (gri) + `ReadOnly = .T.`. Pe pagina "Articole" (`grdArticoleFactura`, PAGE3 — grid-ul reclamat), campul `cGestiuneArt` are **exact acelasi mecanism de editare prin dialog** ca `cGest` de pe pagina Rulaje (acelasi tipar GotFocus/InteractiveChange/`ArticoleNotaEditor`), dar culoarea lui e **gri + ReadOnly=.T.** (`omodificari.vc2:12610-12619`), nu verde + ReadOnly=.F. ca omologul lui de pe Rulaje. **Asta e dovada directa a inconsistentei**: acelasi tipar functional (editare prin editor extern) e codat cu doua culori diferite in doua pagini ale aceluiasi formular — verde (corect, semnaleaza "se editeaza altfel") pe Rulaje, gri (gresit, semnaleaza "nu se editeaza") pe Articole. ## Rezumatul defectelor gasite (fara aplicare) 1. **Zecimale**: `Column6.InputMask` la `cPretArt` (`omodificari.vc2:12391`) foloseste `gnPPRET` (precizie achizitie) in loc de `gnPPretV` (precizie vanzare) — schita: schimbat argumentul. 2. **Aspect gri**: 9 coloane (`cDenumireArt`, `cSerieArt`, `cLotArt`, `cProcTvavArt`, `cGestiuneArt`, `cValutaArt`, `cExplicatieArt`, `cTaxcodeArt`, `cExplicatieTvaArt`) au `Column.ReadOnly=.F.` dar `Text1.ReadOnly=.T.` + `BackColor=225,225,225` — contrazic propria lor declaratie de editabilitate. Dintre ele, doar `cGestiuneArt` si `cExplicatieTvaArt` au mecanism real de editare (editor extern) si ar trebui colorate verde (`160,255,205`, ca modelul de pe Rulaje) + `ReadOnly=.F.` pe Text1; restul (`cDenumireArt`, `cSerieArt`, `cLotArt`, `cProcTvavArt`, `cValutaArt`, `cExplicatieArt`, `cTaxcodeArt`) fie n-au deloc cale de editare activa in cod (raman corect needitabile — atunci `Column.ReadOnly` ar trebui pus `.T.` ca sa nu mai contrazica aspectul), fie editarea lor se face pe o cale neidentificata in aceasta cercetare (butonul `but_modificaR`, NESTABILIT unde e definit).