Files
roafacturare/docs/cercetare/rec_r6_nomenclatoare_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

12 KiB

Cercetare R6 — nomenclatoare in gridul Articole (frm_modific2024)

Zona: COMUN\clase\omodificari.vc2 (formularul frm_modific2024), gridul pgfArticole.PAGE3.grdArticoleFactura. Dispecerul comun e in COMUN\programe\ofacturare_editare.prg, clasa ArticoleNotaEditor.

A. Inventarul coloanelor gridului Articole

Bloc ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura' incepe la omodificari.vc2:12330; lista completa a coloanelor (ControlSource + Name) e la omodificari.vc2:12349-12471.

Coloana (Name) ControlSource Linie ControlSource Legata de nomenclator?
cDenumireArt (Column1) tvd.denumire omodificari.vc2:12349 DA — articol
cCodmatArt (Column2) tvd.codmat omodificari.vc2:12356 nu
cSerieArt (Column3) tvd.serie omodificari.vc2:12363 nu
cLotArt (Column4) tvd.lot omodificari.vc2:12370 nu
cCantitateArt (Column5) tvd.cantitate omodificari.vc2:12377 nu
cPretArt (Column6) tvd.pret omodificari.vc2:12386 nu
cPretAchizitieArt (Column7) tvd.pret_achizitie omodificari.vc2:12395 nu
cPretCuTvaArt (Column8) tvd.pret_cu_tva omodificari.vc2:12404 nu (checkbox propriu)
cProcTvavArt (Column9) tvd.proc_tvav omodificari.vc2:12412 nu
cDiscountUnitarArt (Column10) tvd.discount_unitar omodificari.vc2:12421 nu
cGestiuneArt (Column11) tvd.nume_gestiune omodificari.vc2:12430 DA — gestiune
cValutaArt (Column12) tvd.nume_val omodificari.vc2:12437 DA — valuta
cExplicatieArt (Column13) tvd.explicatie omodificari.vc2:12444 nu (text liber)
cTaxcodeArt (Column14) tvd.taxcode omodificari.vc2:12451 DA — cod TVA SAF-T
cValoareArt (Column15) tvd.valoare omodificari.vc2:12458 nu (calculat)
cExplicatieTvaArt (Column16) Iif(Seek(Nvl(tvd.id_jtva_coloana,0),'crsJtvaTemp','id_jtva'),crsJtvaTemp.denumire,'') omodificari.vc2:12467 DA — explicatie TVA / id_jtva_coloana

Cele 5 coloane legate de un nomenclator sunt exact cele acceptate de dispecer — vezi ArticoleNotaEditor::AreNomenclator (ofacturare_editare.prg:978-981):

PROCEDURE AreNomenclator
	LPARAMETERS tcControl
	RETURN Inlist(This.NumeCamp(m.tcControl), 'denumire', 'nume_gestiune', 'nume_val', 'taxcode', 'id_jtva_coloana')
ENDPROC

Observatie importanta pentru cauza de la punctul D: cTaxcodeArt si cExplicatieTvaArt au Column.ReadOnly = .F. (omodificari.vc2:12379 / linia Column14.ReadOnly = .F. la omodificari.vc2 in blocul 12451-12457, respectiv Column16.ReadOnly = .F. in blocul 12467-12471), dar controlul Text1 din interiorul lor are ReadOnly = .T. — vezi omodificari.vc2:12759 (cTaxcodeArt.Text1) si omodificari.vc2:12594 (cExplicatieTvaArt.Text1). Diferenta reala dintre ele nu e ReadOnly-ul (identic), ci daca ControlSource e camp direct sau expresie — vezi punctul D.

B. Ce evenimente exista azi pe fiecare coloana cu nomenclator

Coloana InteractiveChange DblClick Buton lateral "Modificare" (But_modificaR)
cDenumireArt DA — omodificari.vc2:16710-16714 nu exista DA (comun, vezi E)
cGestiuneArt DA — omodificari.vc2:16739-16743 nu exista DA (comun)
cValutaArt DA — omodificari.vc2:16826-16830 nu exista DA (comun)
cTaxcodeArt DA — omodificari.vc2:16815-16819 nu exista DA (comun)
cExplicatieTvaArt DA — omodificari.vc2:16728-16732 (exista, dar nu se declanseaza — vezi D) nu exista DA (comun)

Corpul e identic pentru toate cele 5 (exemplu, taxcode):

PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cTaxcodeArt.Text1.InteractiveChange
	Local loEditor
	loEditor = Createobject('ArticoleNotaEditor', Thisform)
	loEditor.ModificaNomenclator(Thisform.pccontrol)
ENDPROC

Confirmare ca DblClick nu exista deloc pe grdArticoleFactura sau pe coloanele lui: cautare InteractiveChange|DblClick in tot omodificari.vc2 — singurele DblClick din fisier sunt pe alt grid, grdRequest (omodificari.vc2:390 si omodificari.vc2:408, vezi F).

C. Dispecerul comun — ArticoleNotaEditor::ModificaNomenclator

Definit in COMUN\programe\ofacturare_editare.prg:1069-1137, clasa ArticoleNotaEditor (ofacturare_editare.prg:947-1165).

Semnatura: PROCEDURE ModificaNomenclator LPARAMETERS tcControl — primeste un string de forma alias.camp (ex. tvd.taxcode, tvd.id_jtva_coloana).

Garda de intrare (ofacturare_editare.prg:1073-1076):

lcCamp = This.NumeCamp(m.tcControl)
IF !This.Editabil() OR Reccount('tvd') = 0 OR !This.AreNomenclator(m.lcCamp) OR Nvl(tvd.id_vanzare_set, 0) <> 0
	RETURN .F.
ENDIF

Do Case de deschidere a nomenclatorului (ofacturare_editare.prg:1078-1089):

DO CASE
	CASE m.lcCamp == 'denumire'
		loCauta = caut_articol()
	CASE m.lcCamp == 'nume_gestiune'
		loCauta = caut_gestiune()
	CASE m.lcCamp == 'nume_val'
		loCauta = caut_valuta()
	CASE m.lcCamp == 'id_jtva_coloana'
		loCauta = This.CautaExplicatieTva()
	OTHERWISE
		loCauta = This.CautaCodTva()
ENDCASE

Discrimineaza dupa numele campului extras din tcControl (nu dupa numele coloanei din grid, nu dupa un parametru separat) — NumeCamp (ofacturare_editare.prg:966-974) taie tot ce e inainte de primul .. taxcode cade pe ramura OTHERWISE (CautaCodTva, ofacturare_editare.prg:1152-1158).

Dupa alegere, al doilea Do Case (ofacturare_editare.prg:1096-1132) scrie valorile alese inapoi in tvd, cu ramura dedicata pentru id_jtva_coloana (ofacturare_editare.prg:1124-1129, recalculeaza proc_tvav si cheama This.oForm.UpdateExplicatieSAFTArt() + calculeaza_valori_articol()).

D. De ce "explicatie TVA" nu se declanseaza pe InteractiveChange

Nu e o garda care blocheaza si nu e o ramura lipsa in dispecer — id_jtva_coloana e in AreNomenclator (ofacturare_editare.prg:980) si are ramura proprie in Do Case (ofacturare_editare.prg:1085-1086). Handlerul InteractiveChange exista si e corect (omodificari.vc2:16728-16732).

Cauza e ca evenimentul InteractiveChange pur si simplu nu se produce niciodata din tastare pe aceasta coloana, pentru ca ControlSource-ul ei e o expresie, nu un camp direct:

Column16.ControlSource = "Iif(Seek(Nvl(tvd.id_jtva_coloana,0),'crsJtvaTemp','id_jtva'),crsJtvaTemp.denumire,'')"

(omodificari.vc2:12467)

versus cTaxcodeArt:

Column14.ControlSource = "tvd.taxcode"

(omodificari.vc2:12451)

In VFP, un Textbox intr-o coloana de grid cu ReadOnly = .T. (asa cum sunt ambele, omodificari.vc2:12759 si omodificari.vc2:12594) nu accepta editare directa de text, dar cand Column.ControlSource e un camp real dintr-un cursor navigabil ("bound field"), gridul VFP declanseaza cautarea incrementala nativa la tastare (type-ahead / seek pe recordset): tasta apasata muta recordul curent la prima potrivire, ceea ce schimba valoarea afisata legata de acel camp — iar aceasta schimbare de Value e cea care declanseaza InteractiveChange. Cand ControlSource e o expresie (ca la cExplicatieTvaArt, care afiseaza denumirea din crsJtvaTemp via Seek, nu campul tvd.id_jtva_coloana in sine), gridul nu are un camp indexabil pe care sa faca seek — mecanismul de cautare incrementala nu se activeaza, deci Value-ul textboxului nu se schimba niciodata din tastare, deci InteractiveChange nu are cum sa se declanseze prin tastare pe aceasta coloana.

Chiar comentariul din cod confirma asta, la GotFocus-ul aceleiasi coloane (omodificari.vc2:16723):

*!* coloana afiseaza denumirea din crsJtvaTemp, deci ControlSource e expresie - campul editat se da explicit

adica autorul stia deja ca ControlSource e o expresie si de-aia a scris explicit campul real (tvd.id_jtva_coloana) in Thisform.pccontrol la GotFocus, in loc sa se bazeze pe This.ControlSource (cum fac celelalte coloane). Explicatia asta e chiar mecanismul care face ca butonul lateral sa functioneze — vezi E.

Dublu-click nu se declanseaza pe nicio coloana pentru ca pur si simplu nu exista niciun handler DblClick pe grdArticoleFactura (vezi B) — nu e o problema specifica de "explicatie TVA", e valabil identic si pentru taxcode, doar ca la taxcode utilizatorul are alternativa tastarii, care functioneaza (camp direct).

E. Cum ajunge butonul lateral "Modificare" sa deschida explicatie TVA

Handler: PROCEDURE But_modificaR.Click, omodificari.vc2:15319-15326:

PROCEDURE But_modificaR.Click
	Local lcRul, loEditor
	IF thisform.pgfArticole.ActivePage = 3
		loEditor = Createobject('ArticoleNotaEditor', Thisform)
		loEditor.ModificaNomenclator(thisform.pccontrol)
		RETURN
	ENDIF
	...
ENDPROC

Cheia e ca butonul nu citeste ControlSource-ul coloanei curente — foloseste direct Thisform.pccontrol, o proprietate a formularului scrisa de fiecare GotFocus al coloanei active, inainte ca utilizatorul sa apuce sa tasteze ceva. Pentru cExplicatieTvaArt, GotFocus scrie explicit campul real (omodificari.vc2:16722-16726):

PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cExplicatieTvaArt.Text1.GotFocus
	*!* coloana afiseaza denumirea din crsJtvaTemp, deci ControlSource e expresie - campul editat se da explicit
	Thisform.pccontrol = 'tvd.id_jtva_coloana'
	Thisform.pncolumnorder = This.Parent.ColumnOrder
ENDPROC

Pentru celelalte 4 coloane, GotFocus foloseste Alltrim(This.ControlSource) direct (ex. cTaxcodeArt.Text1.GotFocus, omodificari.vc2:16810-16813), ceea ce functioneaza pentru ele pentru ca acolo ControlSource chiar e campul real.

Deci calea functioneaza pentru ca GotFocus — care se declanseaza la orice intrare in celula, prin click simplu, tab sau navigare cu sagetile, indiferent de tipul de ControlSource — a populat deja Thisform.pccontrol corect inainte ca butonul sa fie apasat. Butonul nu depinde deloc de InteractiveChange; de-aia merge la explicatie TVA desi tastarea nu merge.

F. Cost estimat pentru DblClick pe fiecare coloana cu nomenclator

Exista deja un sablon direct aplicabil, chiar in cadrul modelului de "coloana Text1 in grid cu InteractiveChange care deschide ceva" — grdRequest, alt grid din acelasi formular:

PROCEDURE grdRequest.cLabelItem.Text1.DblClick
	Thisform.lEditMode = .T.
ENDPROC

(omodificari.vc2:390-392)

PROCEDURE grdRequest.cValoareDefaultText.Text1.DblClick
	If !Empty(Nvl(crsRequest.fis_lista, ''))
		Thisform.Selectfromlookup()
	Endif
ENDPROC

(omodificari.vc2:408-412)

Confirmare pentru VFP: intr-adevar, evenimentul se pune pe controlul din interiorul coloanei (Column.Text1.DblClick), exact cum arata cele doua exemple de mai sus si exact cum sunt puse deja InteractiveChange si GotFocus pe grdArticoleFactura (Column.Text1.InteractiveChange, Column.Text1.GotFocus) — nu exista niciun DblClick pus pe nivelul Column insusi in tot fisierul. Modelul grdRequest e potrivit ca forma (unde se pune evenimentul), dar nu ca continut — acolo DblClick face lucruri specifice acelui grid (comuta un mod de editare / arata un lookup din alta zona), nu apeleaza un dispecer de nomenclator.

Sablonul de continut potrivit e chiar InteractiveChange-urile deja existente pe grdArticoleFactura (omodificari.vc2:16710-16714, 16728-16732, 16739-16743, 16815-16819, 16826-16830) — toate identice, 3 linii:

Local loEditor
loEditor = Createobject('ArticoleNotaEditor', Thisform)
loEditor.ModificaNomenclator(Thisform.pccontrol)

Costul e mic si uniform: adaugarea a 5 metode noi DblClick (una per coloana cu nomenclator), fiecare cu acelasi corp de 3 linii de mai sus. Pentru ca toate cele 5 GotFocus seteaza deja Thisform.pccontrol corect — fie din ControlSource (denumire, gestiune, valuta, taxcode), fie explicit (explicatie TVA, omodificari.vc2:16724) — folosirea lui Thisform.pccontrol in DblClick functioneaza uniform pe toate cele 5, inclusiv pe explicatie TVA, fara sa depinda de mecanismul de seek care lipseste la coloana cu ControlSource expresie. Practic acelasi apel pe care il face deja But_modificaR.Click (omodificari.vc2:15319-15326, vezi E).

Nu e nevoie de nicio schimbare in dispecer (ModificaNomenclator) sau in AreNomenclator — ele deja accepta toate cele 5 campuri.