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