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

256 lines
12 KiB
Markdown

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