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

452 lines
23 KiB
Markdown

# Runda 5 - editare inline pe pagina Articole (proiectare, fara aplicare)
Document de proiectare pentru cerinta: pe formularul unificat `frm_modific2024`, pagina 3
"Articole factura" (`pgfArticole.PAGE3.grdArticoleFactura`, cursor `tvd`), sa devina editabile
inline `serie`, `lot`, `explicatie` si `proc_tvav`, iar coloanele cu nomenclator (`denumire`,
`nume_gestiune`, `nume_val`, `taxcode`, `id_jtva_coloana`) sa deschida dialogul de cautare si pe
`InteractiveChange`, nu doar din `But_modificaR.Click`.
Linii citate din `COMUN\clase\omodificari.vc2` (17059 linii) si
`COMUN\programe\ofacturare_editare.prg` (1140 linii), stare de pe disc la data cercetarii -
fisierul e in lucru, **reconfirma numerele de linie cu `vfp_symbols.ps1` inainte de orice
`txt2vcx.ps1`**.
Fiecare bloc de cod de mai jos e marcat **VERIFICAT** (citit direct din sursa) sau **PRESUPUS**
(judecata de proiectare, nu extrasa din cod existent).
---
## 0. Constatare care schimba premisa punctului A din brief
**VERIFICAT.** Intrebarea "`cCantitateArt`/`cPretArt` marcheaza `lmodificat` si conteaza asta la
salvare" are raspuns clar: **`lmodificat` nu e citit nicaieri ca filtru de salvare.**
`ScrieArticoleFacturaEditate` (`ofacturare_editare.prg:473-571`) are doar doua `SCAN`-uri pe
`tvd`:
- `ofacturare_editare.prg:502` - `SCAN FOR id_vanzare_det > 0 AND Nvl(sters,0) <> 1` (UPDATE
liniilor existente)
- `ofacturare_editare.prg:534` - `SCAN FOR id_vanzare_det = 0 AND Nvl(sters,0) <> 1` (INSERT
liniilor noi)
Niciunul nu conditioneaza pe `lmodificat`. Comentariul de la `ofacturare_editare.prg:498` o spune
explicit: *"invie si actualizeaza liniile pastrate - toate cele active din alias, nu doar
lmodificat, pasul de mai sus le-a marcat pe toate"*. Singurele scrieri ale campului
(`AplicaAdaugareTvd:857`, `ComutaSters:1034`, `DuplicaLinie:1053`,
`ModificaNomenclator:1108`, `calculeaza_valori_articol` in `omodificari.vc2:13521`) nu au nicio
citire-pereche - `lmodificat` e scris dar niciodata citit. E camp vestigial (poate util pentru o
extensie viitoare, gen indicator vizual "linie modificata"), **nu un defect de blocat livrarea**.
Consecinta pentru A: coloanele noi (`serie`, `lot`, `explicatie`, `proc_tvav`) **nu au nevoie sa
seteze `lmodificat` ca sa se salveze** - se salveaza oricum, ca toate liniile active. Recomand
totusi sa-l seteze, din consecventa cu restul coloanelor editabile si ca sa nu ramana singurele
exceptii daca cineva incepe sa-l citeasca in viitor - cost zero, un `REPLACE` in plus.
---
## 1. Defect real gasit pe drum: UPDATE-ul nu scrie `serie`/`lot`/`explicatie`
**VERIFICAT - trebuie reparat in aceeasi livrare**, exact cum a semnalat brief-ul.
UPDATE-ul liniilor existente (`ofacturare_editare.prg:505-517`):
```foxpro
lcSql = [update vanzari_detalii set sters = 0, cantitate = ] + Alltrim(Str(Nvl(cantitate,0),18,3)) + ;
[, pret = ] + Alltrim(Str(Nvl(pret,0),18,4)) + [, pret_cu_tva = ] + Alltrim(Str(Nvl(pret_cu_tva,0))) + ;
[, pret_achizitie = ] + Alltrim(Str(Nvl(pret_achizitie,0),18,4)) + ;
[, proc_tvav = ] + Alltrim(Str(Nvl(proc_tvav,0),18,4)) + ;
[, discount_unitar = ] + Alltrim(Str(Nvl(discount_unitar,0),18,4)) + ;
[, id_articol = ] + Alltrim(Str(Nvl(id_articol,0))) + ;
[, id_gestiune = ] + Iif(Isnull(id_gestiune),[NULL],Alltrim(Str(id_gestiune))) + ;
[, id_valuta = ] + Iif(Isnull(id_valuta),[NULL],Alltrim(Str(id_valuta))) + ;
[, id_jtva_coloana = ] + Iif(Isnull(id_jtva_coloana),[NULL],Alltrim(Str(id_jtva_coloana))) + ;
[, taxcode = ] + Iif(Isnull(taxcode),[NULL],Alltrim(Str(taxcode))) + ;
[, cont = ] + Iif(Empty(Nvl(cont,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(cont,''))) + [']) + ;
[, id_utils = ] + Alltrim(Str(gnIdUtil)) + [, dataoras = sysdate ] + ;
[where id_vanzare_det = ] + Alltrim(Str(id_vanzare_det)) + [ and id_vanzare = ] + Alltrim(Str(m.tnIdVanzare))
```
`proc_tvav` **e deja in lista** (linia 508) - editarea cotei TVA persista deja corect pe linii
existente, nimic de reparat acolo. Lipsesc doar `serie`, `lot`, `explicatie` - prezente in
INSERT-ul liniilor noi (`ofacturare_editare.prg:535-544`, aceeasi forma
`Iif(Empty(Nvl(...,'')),[NULL],['] + OracleSpecialCharacters(...) + [']`) dar absente din UPDATE.
Fara reparatie, editarea inline propusa la punctul A de mai jos s-ar pierde tacut la salvare pe
orice linie deja salvata (`id_vanzare_det > 0`) - exact scenariul cel mai comun (factura cu
articole sincronizate din rulaj).
### Propunere - `ofacturare_editare.prg`, dupa linia 515 (`, cont = ...`), inainte de linia 516
(`, id_utils = ...`)
```foxpro
[, cont = ] + Iif(Empty(Nvl(cont,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(cont,''))) + [']) + ;
[, serie = ] + Iif(Empty(Nvl(serie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(serie,''))) + [']) + ;
[, lot = ] + Iif(Empty(Nvl(lot,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(lot,''))) + [']) + ;
[, explicatie = ] + Iif(Empty(Nvl(explicatie,'')),[NULL],['] + OracleSpecialCharacters(Alltrim(Nvl(explicatie,''))) + [']) + ;
[, id_utils = ] + Alltrim(Str(gnIdUtil)) + [, dataoras = sysdate ] + ;
```
Trei linii noi, tipar identic cu cel deja folosit pentru `cont` pe acelasi UPDATE si pentru
`serie`/`explicatie`/`lot` pe INSERT (`:538-540`). Comentariul de la `:503-504` ("toate campurile
pe care grila si nomenclatoarele le pot schimba") ramane valabil fara modificare.
---
## 2. Coloane care devin editabile inline (`serie`, `lot`, `explicatie`)
**VERIFICAT** - definitiile actuale, `omodificari.vc2`:
| coloana | linie definitie | `ControlSource` | `ReadOnly` azi |
|---|---|---|---|
| `cSerieArt` (Column3) | `:12359-12365` | `tvd.serie` | `.T.` |
| `cLotArt` (Column4) | `:12366-12372` | `tvd.lot` | `.T.` |
| `cExplicatieArt` (Column13) | `:12441-12447` | `tvd.explicatie` | `.T.` |
Niciuna nu are azi `Text1.When`/`Text1.Valid` propriu (singurele evenimente pe pagina 3 sunt cele
listate la `omodificari.vc2:16678-16770`, verificat prin citire directa a intervalului).
### Garda de editare - condifia de baza vs. cea extinsa a lui `cPretAchizitieArt`
**VERIFICAT.** Doua garde diferite exista azi pe pagina 3:
```foxpro
* cCantitateArt.Text1.When si cPretArt.Text1.When - garda de baza
IF Thisform.lArticoleReadOnly OR Nvl(tvd.id_vanzare_set,0) <> 0
RETURN .F.
ENDIF
* cPretAchizitieArt.Text1.When - garda extinsa, cu o conditie in plus
IF Thisform.lArticoleReadOnly OR Nvl(tvd.id_vanzare_set,0) <> 0 OR Nvl(tvd.id_vanzare_det,0) <> 0
RETURN .F.
ENDIF
```
**PRESUPUS** (nu exista comentariu care sa explice; judecata de proiectare pe baza codului
inconjurator): conditia suplimentara `Nvl(tvd.id_vanzare_det,0) <> 0` de pe pret de achizitie
blocheaza editarea manuala pe liniile **deja legate de o vanzare persistata** (`id_vanzare_det`
nenul inseamna linie care exista deja in `VANZARI_DETALII`, deci a venit dintr-o miscare de stoc
reala). Sustinut de garda de la salvare (`omodificari.vc2:14457-14460`): un avertisment de "pret
de achizitie 0" apare doar pentru linii **noi** (`id_vanzare_det = 0`) - semn ca liniile vechi au
deja o valoare de incredere, mostenita din stoc, si nu trebuie rescrisa manual dupa fapt (ar
strica marja/COGS calculat la vremea vanzarii). E o garda de **integritate financiara pe o
valoare derivata**, nu una generica de editare.
`serie`/`lot`/`explicatie` sunt campuri **descriptive/text**, nu valori derivate din stoc -
corectarea unei greseli de tastare pe o linie deja salvata (serie gresita, lot gresit, o
explicatie de corectat) e exact scenariul uzual de folosit al acestei livrari, inclusiv pe linii
vechi. Recomand garda de baza (fara conditia `id_vanzare_det`) pentru toate trei. Daca exista un
motiv de trasabilitate (serie/lot leaga factura de un lot fizic expediat, iar schimbarea lui dupa
livrare ar fi o problema de conformitate) - e o decizie de business, nu una pe care o pot confirma
din cod; semnalez-o explicit ca punct de validat cu tine inainte de aplicare.
### Propunere - `omodificari.vc2`, dupa `cPretArt.Text1.Valid` (`:16759`, inainte de
`cPretArt.Text1.When`)
```foxpro
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Text1.When
IF Thisform.lArticoleReadOnly OR Nvl(tvd.id_vanzare_set,0) <> 0
RETURN .F.
ENDIF
Thisform.oldvalue = This.Value
ENDPROC
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cSerieArt.Text1.Valid
IF NVL(Thisform.oldvalue,'') <> NVL(This.Value,'')
REPLACE lmodificat WITH .T. IN tvd
Thisform.oldvalue = This.Value
ENDIF
ENDPROC
```
Identic (nume schimbat) pentru `cLotArt` (`tvd.lot`) si `cExplicatieArt` (`tvd.explicatie`).
Coloana 3 din `Column3.ReadOnly = .T.`, 4 din `Column4.ReadOnly = .T.`, 13 din
`Column13.ReadOnly = .T.` trec pe `.F.` (`omodificari.vc2:12365`, `:12372`, `:12447`).
---
## 3. Cazul delicat: `proc_tvav` (Column9, `cProcTvavArt`)
### 3.1 Forma stocata - VERIFICAT, nu presupus
`tvd.proc_tvav` e in forma multiplicativa (1.21, nu 21), confirmat in trei locuri independente:
- `CreeazaPoArticolNouTvd`... `calculeaza_valori_articol` (`omodificari.vc2:13511-13521`):
`lnProcTvav = NVL(proc_tvav, 1)` si `lnValoare = ... * lnPretNet * lnProcTvav` - daca ar fi
forma "21", valoarea liniei ar fi de 21x mai mare, evident gresit.
ei
- `ArticoleNotaEditor.ModificaNomenclator`, ramura `id_jtva_coloana`
(`ofacturare_editare.prg:1099-1101`): `proc_tvav WITH (Nvl(loCauta.cota_tva, 0) + 100) / 100` -
`cota_tva` vine din nomenclator ca "21", transformarea explicita in "1.21" e in cod.
- `CautaExplicatieTva` (`ofacturare_editare.prg:1117-1120`):
`lnCotaFiltru = Round((Nvl(tvd.proc_tvav, 0) - 1) * 100, 2)` - transformarea inversa, "1.21" ->
"21".
### 3.2 Precedent direct in acelasi grid family: editare libera in forma "1.xx"
**VERIFICAT.** Coloana `cProc_tva` de pe grila de rulaje (`pgfArticole.PAGE1.grdRulaje`,
`omodificari.vc2:8956-8963`, si dubletul ei pe `PAGE2.grdRulajeObinv`) e **deja editabila
direct**, in forma bruta:
```foxpro
Column24.ControlSource = "proc_tva", ;
Column24.Format = "R", ;
Column24.InputMask = "9.99", ;
Column24.Name = "cProc_tva", ;
Column24.ReadOnly = .F., ;
```
cu evenimentul (`omodificari.vc2:16337-16343`):
```foxpro
PROCEDURE pgfArticole.PAGE1.grdRulaje.cProc_tva.Text1.Valid
IF NVL(thisform.oldvalue, 0) <> NVL(this.Value, 0)
Thisform.calculeaza_valori_rul(this.ControlSource)
thisform.oldvalue = this.Value
ENDIF
ENDPROC
```
Utilizatorul tasteaza deja "1.21", nu "21", pe grila de rulaje din **acelasi formular**.
`cProcTvavArt` de pe grila de articole are deja azi `Column9.InputMask = "9.99"`
(`omodificari.vc2:12417`, mostenit inca de cand coloana era doar de afisare) - acelasi format,
gata pregatit.
### 3.3 Recomandare: pastreaza forma "1.21", nu converti la "21"
**Argument**: forma "1.21" e cea stocata in `proc_tvav`, cea folosita direct de
`calculeaza_valori_articol`, si cea deja tastata de utilizatori pe grila de rulaje din acelasi
formular - e conventia existenta, nu una noua. Varianta "utilizatorul tasteaza 21" ar cere:
- o proprietate ajutatoare separata pe care sa se afiseze/editeze (`Text1` legat printr-o
expresie de transformare, `ControlSource` nu mai poate fi direct `tvd.proc_tvav`), pentru ca
grid column text boxes nu pot face transformarea la afisare fara sa piarda editarea directa pe
`ControlSource`;
- conversia dus-intors (`/100+1` la citire, `(x-1)*100` la scriere) e exact riscul semnalat -
o greseala de semn sau de ordine ar strica toate liniile la urmatoarea recalculare, silentios
(nu exista validare care sa prinda "1900" in loc de "19" introdus gresit);
- ar fi **singura** coloana din tot formularul cu conventia asta, cand exact aceeasi valoare, pe
aceeasi pagina, la un tab distanta (rulaje), se editeaza deja in forma "1.21".
Nu recomand conversia. Ramane `InputMask = "9.99"`, neschimbat.
### 3.4 Riscul real: corelarea cu `id_jtva_coloana`/`taxcode` se poate dezincroniza
**VERIFICAT ca risc, nu ca deja tratat.** Spre deosebire de `cProc_tva` de pe rulaje (unde
`trul` nu are corelare SAF-T de taxcode legata de cota), pe `tvd` cota TVA e legata explicit de
`id_jtva_coloana` si de `taxcode`:
- `ModificaNomenclator`, ramura `id_jtva_coloana` (`ofacturare_editare.prg:1099-1104`): alegerea
unei explicatii TVA scrie **impreuna** `id_jtva_coloana` si `proc_tvav`, apoi cheama
`UpdateExplicatieSAFTArt()` care recoreleaza `taxcode` din `id_jtva_coloana`
(`omodificari.vc2:15049-15073`, verificat: `lnIdJtva = tvd.id_jtva_coloana`,
`GetTaxCodeIdPart(...)`, `Replace taxcode With m.lnTaxCode In tvd`).
- Daca utilizatorul editeaza `proc_tvav` direct (tasteaza "1.19" peste "1.21"), fara sa treaca si
prin nomenclatorul de explicatie TVA, **`id_jtva_coloana` si `taxcode` raman la cota veche** -
`cExplicatieTvaArt` (coloana 16) ar continua sa arate explicatia de 21% langa o cota de 19%, iar
`taxcode`-ul folosit la raportarea SAF-T ar fi cel corelat cu explicatia gresita. E o
inconsistenta silentioasa, nu doar cosmetica - `taxcode` alimenteaza raportarea SAF-T 406.
Pe grila de rulaje, editarea directa a lui `proc_tva`/`proc_tvav` **nu recoreleaza nimic** legat
de TVA (`trul` nu poarta `taxcode`/`id_jtva_coloana` in acelasi fel) - acolo riscul asta nu
exista, deci precedentul de la 3.2 nu acopera si problema asta.
### 3.5 Doua variante, cu recomandare
**Varianta A (recomandata) - blocheaza corelarea veche in loc s-o lase gresita**
```foxpro
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Text1.When
IF Thisform.lArticoleReadOnly OR Nvl(tvd.id_vanzare_set,0) <> 0
RETURN .F.
ENDIF
Thisform.oldvalue = This.Value
ENDPROC
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cProcTvavArt.Text1.Valid
IF NVL(Thisform.oldvalue, 0) <> NVL(This.Value, 0)
SELECT tvd
REPLACE id_jtva_coloana WITH NULL, taxcode WITH NULL
Thisform.calculeaza_valori_articol()
Thisform.oldvalue = This.Value
This.Parent.Parent.Refresh()
ENDIF
ENDPROC
```
Dupa editare manuala a cotei, `cExplicatieTvaArt` si `cTaxcodeArt` raman **goale** pe randul
respectiv - semnal vizibil, imediat, ca utilizatorul trebuie sa aleaga din nou explicatia TVA
(punctul 4 de mai jos ii da exact calea: click sau tastare pe coloana Explicatie TVA deschide
dialogul, filtrat deja pe noua cota introdusa). `taxcode WITH NULL` inseamna insa ca linia nu mai
are cod SAF-T pana la re-alegere - de verificat cu tine daca exista vreo validare la salvare care
sa avertizeze pe `taxcode` nul (nu am gasit una explicita pentru `tvd`, doar cea de pret de
achizitie 0 de la `:14457`); daca nu exista, merita adaugata odata cu asta, ca sa nu scape o
factura fara cod SAF-T la salvare.
**Varianta B (respinsa) - lasa corelarea veche neatinsa, ca pe rulaje**
Doar `Thisform.calculeaza_valori_articol()` in `Valid`, fara sa atinga
`id_jtva_coloana`/`taxcode`. Simetrica cu precedentul de la 3.2, dar pe `tvd` inseamna taxcode
SAF-T incorect ramas silentios dupa o editare manuala de cota - risc pe raportare fiscala, nu doar
UX. Nu o recomand.
**Nu am incercat o a treia varianta ("re-coreleaza automat")** - ar insemna sa caut in
`crsJtvaTemp` o explicatie care sa aiba exact noua cota si sa o aplic fara dialog; las-o
deoparte pentru ca poate exista mai mult de o explicatie pe aceeasi cota (JC vs JV, exigibil vs
neexigibil - vezi parametrii `tlTipEx` din `caut_explicatie_tva`,
`ocautare.prg:3174-3181`), iar alegerea automata a uneia ar fi arbitrara exact acolo unde conteaza
sa fie corecta.
---
## 4. Nomenclatoarele pe `InteractiveChange`
**VERIFICAT** - sablonul de referinta indicat de tine (`Grid1.Column15/16/17` pe grila de note,
`omodificari.vc2:5890-5940`) e construit pe **`do_modifica`** generic (parametri `pcx_item`,
`pccontrol`, `pnid_item`, cautare in cursorul `xitems`) - un mecanism diferit fata de
`ArticoleNotaEditor.ModificaNomenclator`, care primeste **doar `pccontrol`** si decide singur ce
cautare deschide printr-un `DO CASE` pe numele campului
(`ofacturare_editare.prg:1073-1090`). **Sablonul se preia doar partial**: pattern-ul
`GotFocus` seteaza `pccontrol`+`pncolumnorder`, `InteractiveChange` cheama dialogul - dar apelul e
catre `ArticoleNotaEditor.ModificaNomenclator(pccontrol)`, fara `pcx_item`/`pnid_item` (nu exista
in semnatura ei).
Cele 5 coloane cu nomenclator (`AreNomenclator`, `ofacturare_editare.prg:1004-1007`:
`'denumire', 'nume_gestiune', 'nume_val', 'taxcode', 'id_jtva_coloana'`) au deja `Text1.GotFocus`
care seteaza `pccontrol`+`pncolumnorder` (`omodificari.vc2:16700-16704` `cDenumireArt`,
`:16723-16727` `cExplicatieTvaArt` cu `pccontrol` explicit `'tvd.id_jtva_coloana'` pentru ca
`ControlSource` e o expresie, `:16729-16733` `cGestiuneArt`, `:16750-16754` `cTaxcodeArt`,
`:16755-16759` `cValutaArt`) - functioneaza deja azi desi coloanele sunt `ReadOnly = .T.` (un
textbox readonly primeste `GotFocus` la navigare cu sagetile, doar nu accepta tastare). Asta e
mecanismul care tine `But_modificaR` sincronizat cu coloana curenta (punctul 5).
### Propunere - adauga `Text1.InteractiveChange` pe fiecare, `ReadOnly` -> `.F.`
```foxpro
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.cDenumireArt.Text1.InteractiveChange
LOCAL loEditor
loEditor = Createobject('ArticoleNotaEditor', Thisform)
loEditor.ModificaNomenclator(Thisform.pccontrol)
ENDPROC
```
Identic (nume schimbat) pentru `cGestiuneArt`, `cValutaArt`, `cTaxcodeArt`, `cExplicatieTvaArt` -
`Thisform.pccontrol` e deja setat corect de `GotFocus`-ul existent al fiecareia. `Column1.ReadOnly`
(`:12354`), `Column11.ReadOnly` (`:12428`), `Column12.ReadOnly` (`:12434`), `Column14.ReadOnly`
(`:12453`), `Column16.ReadOnly` (`:12474`) trec pe `.F.`.
### Risc: caracterul tastat inainte de deschiderea dialogului
**VERIFICAT ca exista deja acelasi risc, neremediat, in sablonul citat.** In `do_modifica`
(`omodificari.vc2:13960` si dublurile ei), `REPLACE`-ul cu valoarea aleasa se face **doar** in
ramura `IF gnButon = 1` (`omodificari.vc2:14019-14025` pentru `tact`) - la anulare (`gnButon <> 1`
sau formular inchis fara alegere), campul **nu e restaurat**. Cum coloana e `ReadOnly = .F.`,
`InteractiveChange` se declanseaza pe **prima tasta** apasata (Value s-a schimbat deja cu acel
caracter inainte ca evenimentul sa ruleze) - daca utilizatorul apasa o litera si apoi renunta la
dialog, acel caracter ramane in camp.
Pe `ArticoleNotaEditor.ModificaNomenclator` e identic: `REPLACE`-ul final
(`ofacturare_editare.prg:1093-1107`) e dupa `IF gnButon <> 1: RETURN .F. ENDIF`
(`:1082-1084`) - la anulare, campul nu se atinge, deci caracterul parazit ramane in `tvd.denumire`
(sau alt camp editat). Fara refresh explicit pe ramura de anulare (`RefreshGrid()` e apelat doar
dupa `REPLACE`, in afara ramurii de `RETURN` timpuriu), gridul ramane cu textul modificat vizual
pana la urmatoarea reimprospatare.
**Nota:** `lmodificat` nu se atinge pe ramura de anulare, dar cum am aratat la punctul 0, asta nu
opreste totusi salvarea - daca linia era oricum activa (`sters<>1`), caracterul parazit ar fi
scris in Oracle la urmatoarea salvare a documentului, indiferent de `lmodificat`.
**Propunere de atenuare (in plus fata de sablon, nu cerinta din brief):** in
`ArticoleNotaEditor.ModificaNomenclator`, muta `This.RefreshGrid()` inainte de
`RETURN .F.` din garda de anulare, ca sa readuca vizual valoarea corecta din cursor peste orice
caracter tastat:
```foxpro
IF gnButon <> 1
This.RefreshGrid()
RETURN .F.
ENDIF
```
`RefreshGrid()` doar re-deseneaza gridul din cursor (`This.oForm.pgfArticole.PAGE3.grdArticoleFactura.Refresh()`,
`ofacturare_editare.prg:1136-1138`) - nu scrie nimic, deci sigur de adaugat si pe ramura de
anulare. Nu rezolva 100% (daca utilizatorul apasa doua taste rapid inainte ca dialogul sa apuce sa
se deschida, a doua tasta tot ar intra), dar acopera cazul uzual (o tasta, apoi Esc pe dialog).
`But_modificaR` ramane functional neschimbat: click-ul lui cheama tot
`ArticoleNotaEditor.ModificaNomenclator(thisform.pccontrol)` (`omodificari.vc2:15319-15322`,
verificat), acelasi `pccontrol` pe care acum si `InteractiveChange`-ul il foloseste - **nu se
dubleaza deschiderea dialogului**, sunt doua declansatoare catre aceeasi metoda, niciodata
concurente (butonul se apasa explicit, `InteractiveChange` doar la tastare in celula).
---
## 5. `BeforeRowColChange`/`AfterRowColChange` - raman neschimbate
**VERIFICAT.**
```foxpro
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.AfterRowColChange
Lparameters nColIndex
DODEFAULT(m.nColIndex)
Thisform.but_modificaR.Enabled = (Thisform.pncolumnorder = m.nColIndex) AND !Thisform.lArticoleReadOnly
ENDPROC
PROCEDURE pgfArticole.PAGE3.grdArticoleFactura.BeforeRowColChange
LPARAMETERS nColIndex
IF Thisform.pncolumnorder # m.nColIndex
STORE [] TO Thisform.pccontrol
ENDIF
ENDPROC
```
Nu au nevoie de nicio schimbare:
- Coloanele cu nomenclator continua sa seteze `pncolumnorder` in `GotFocus` (neschimbat la
punctul 4) - `But_modificaR` ramane activat/dezactivat exact ca azi.
- Coloanele noi editabile fara nomenclator (`cSerieArt`, `cLotArt`, `cExplicatieArt`,
`cProcTvavArt`) **nu primesc `GotFocus` care sa seteze `pccontrol`/`pncolumnorder`** - la fel ca
`cCantitateArt`/`cPretArt`/`cPretAchizitieArt` azi (verificat: niciuna dintre astea trei nu are
`Text1.GotFocus` in intervalul `:16678-16770`). Cand utilizatorul navigheaza pe una din ele,
`pncolumnorder` ramane la valoarea din ultima coloana cu nomenclator vizitata, deci
`Thisform.pncolumnorder = m.nColIndex` e fals si `But_modificaR` ramane dezactivat - corect,
pentru ca aceste patru coloane n-au nomenclator si nu trebuie sa activeze butonul.
Nu propun sa le adaug `GotFocus` - ar activa gresit `But_modificaR` pe coloane fara cautare.
---
## 6. Ordinea coloanelor - doar de retinut, nu de aplicat acum
`cExplicatieTvaArt` (Column16) e ultima coloana din grid, dupa `cValoareArt` (Column15) -
`ColumnOrder`-ul azi urmeaza indicii (1-16). Mutarea ei langa `cTaxcodeArt` (Column14) ar cere
renumerotarea `ColumnOrder` pe toate cele 16 coloane (nu doar schimbarea pozitiei uneia), cost
deja notat in `docs\propunere_runda4_note_sincronizare_tva.md:242-244`. Ramane a doua iteratie,
separata de livrarea asta.
---
## Rezumat - ce e usor, ce e delicat
**Usor, cu incredere mare:**
- `serie`/`lot`/`explicatie` editabile inline (punctul 2) - tipar identic cu `cPretArt`, fara
recalcul necesar.
- UPDATE-ul din `ScrieArticoleFacturaEditate` (punctul 1) - trei linii, tipar deja folosit alaturi
(`cont` pe acelasi UPDATE, `serie`/`lot`/`explicatie` pe INSERT-ul de doua ori mai jos).
- Nomenclatoarele pe `InteractiveChange` (punctul 4) - `GotFocus` deja exista pe toate cele 5
coloane, doar `ReadOnly` si `InteractiveChange` lipsesc.
- `BeforeRowColChange`/`AfterRowColChange` (punctul 5) - zero schimbari, verificat ca raman
corecte.
**Delicat, cere o decizie a ta inainte de aplicare:**
- `proc_tvav` (punctul 3) - forma "1.21" e clar cea corecta de pastrat (precedent direct pe
aceeasi pagina, la rulaje), dar corelarea cu `id_jtva_coloana`/`taxcode` la editare manuala e un
risc real de raportare SAF-T netratat de niciun precedent existent. Recomand Varianta A
(goleste corelarea, forteaza re-alegere) - confirma daca vrei asta sau preferi sa nu atingi
`id_jtva_coloana`/`taxcode` deloc (Varianta B, mai simpla dar cu riscul asumat).
- Garda de editare pe `serie`/`lot`/`explicatie` - am recomandat garda de baza (fara restrictia
`id_vanzare_det<>0` de la pret de achizitie), dar e o decizie de business (trasabilitate lot pe
linii deja livrate), nu una pe care am putut-o confirma din cod.
- Riscul caracterului parazit la deschiderea nomenclatorului pe `InteractiveChange` (punctul 4) -
exista deja, neremediat, in sablonul `do_modifica` de pe grila de note; am propus o atenuare de
o linie (`RefreshGrid()` pe ramura de anulare) care nu era in cerinta ta, spune daca o vrei in
livrare sau ramane pentru alta runda.