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
256 lines
12 KiB
Markdown
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.
|