Files
roafacturare/docs/cercetare/rec_r6_zecimale_si_aspect_grid.md
Marius Mutu ca3c5d7eea docs: runda 6 - cercetari, propuneri si conventia mediului Oracle
Cercetarile si propunerile rundelor 4-6 pe editarea facturii emise. Starea
rundei 6 si ce s-a stabilit intra in progres.md.

Nou: docs/conventii_mediu_oracle.md - pe dev/test se lucreaza numai cu
ROA_CENTRAL si schemele CONTAFIN_ORACLE si MARIUSM_AUTO; schema ACN nu se
foloseste. Scripturile de pachet sunt necalificate, deci schema tinta o
decide sirul de conectare, nu fisierul.

roafacturare.pj2 regenerat de git_sync.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013gYCNE26G1G7UoGu2ju7aS
2026-08-20 16:35:03 +03:00

15 KiB

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