# S5 — grid PAGE3: coloana `pret_achizitie` si editabilitate per rand Implementare in `COMUN\clase\omodificari.vc2`, clasa `frm_modific2024` (singura clasa afectata din fisier — fisierul mai contine `frm_editare_set`, `frm_modific` si `frm_modific2007`, cu metode `inainte_de_do_termin` byte-identice intre `frm_modific` (`:5004`) si `frm_modific2007`; scrierea a fost restransa explicit la sufixul de dupa `DEFINE CLASS frm_modific2024` ca sa nu atinga duplicatele mai vechi). ## A. Sincronizare cursor `tvd` (ramura ROACONT/ROAGEST) `frm_modific2024.Load` (`:14554-14591` inainte de editare) are un `CREATE CURSOR tvd` duplicat literal, folosit cand `ofacturare_editare.prg` nu e incarcat in `SET("PROCEDURE")`. I s-au adaugat `id_vanzare_set I NULL, pret_achizitie N(14,4) NULL` intre `sters` si `denumire`, identic ca pozitie si tip cu `CreeazaCursorArticoleGol` (`COMUN\programe\ofacturare_editare.prg:273-276`). ## B. Coloana noua `pret_achizitie` in `grdArticoleFactura` - inserata ca `Column7` (dupa coloana de pret, `Column6`), cu renumerotarea `Column7..14 -> Column8..15` — gridurile VFP nu au `ColumnOrder` implicit setat in acest fisier (ordinea vizuala = ordinea numerica a `Column`), deci pastrarea conventiei existente a insemnat renumerotare, nu introducerea unei proprietati noi; - `ControlSource = "tvd.pret_achizitie"`, `Format`/`InputMask` copiate de la `Column6` (pret, `get_mask(12,gnPPRET)`), `Width = 90` (comparabil cu discount unitar), eticheta „Pret achizitie” (fara diacritice, ca sa evite riscul de corupere cp1250 pe siruri noi); - `ColumnCount` 14 -> 15; blocurile `ADD OBJECT` pentru `Header1`/`Text1` inserate in pozitia alfabetica corecta (dupa `cLotArt`, inainte de `cPretArt` — `cPretAchizitieArt` < `cPretArt` alfabetic, verificat impotriva ordinii reale din fisier, nu presupus). ## C. Editabilitate per rand (nu per coloana) `ReadOnly` a ramas `.F.` la nivel de coloana pentru `cantitate`/`pret`/`pret_cu_tva`/ `pret_achizitie` (ca si azi) — gating-ul e mutat in metodele `When` ale controalelor din coloana, singurul punct din care VFP decide daca celula primeste focus: - `cCantitateArt.Text1.When`, `cPretArt.Text1.When`: adaugat `IF Nvl(tvd.id_vanzare_set,0)<>0 RETURN .F. ENDIF` inaintea liniei existente (`Thisform.oldvalue = This.Value`), fara alta modificare de comportament pe liniile normale; - `cPretCuTvaArt._checkbox1` nu avea `When` — s-a adaugat unul nou, `RETURN Nvl(tvd.id_vanzare_set,0) = 0`; - `cPretAchizitieArt.Text1.When` (nou): editabil doar cand `id_vanzare_set = 0 AND id_vanzare_det = 0` (linie noua, nu componenta de set). Marcaj vizual: `DynamicForeColor` extins pe toate cele 15 coloane (era pe toate cele 14), `IIF(tvd.sters=1,RGB(150,150,150),IIF(NVL(tvd.id_vanzare_set,0)<>0,RGB(0,70,153),RGB(0,0,0)))` — gri pentru sters (neschimbat), albastru `RGB(0,70,153)` nou pentru linie de set, negru normal in rest. `nrgbrow = 0` pe `ADD OBJECT`-ul gridului nu a fost atins. ## D. Validari noi in `inainte_de_do_termin` Inserate inaintea lui `RETURN m.llRet`, gardate pe `"OFACTURARE_EDITARE" $ Upper(Set("Procedure")) AND Used('tvd')`. Pe liniile active (`Nvl(sters,0)<>1`, parcurse cu un singur `SCAN`): `cantitate<=0` si `pret` NULL si `id_articol` nul/0 blocheaza salvarea (`RETURN .F.`, mesaj cu numele liniei din `denumire`); linie noua cu `pret_achizitie` 0/NULL cere confirmare Da/Nu (tiparul `amessagebox(...,4+32,...)` deja folosit in metoda, la `<>6` = anulare); zero linii active cu documentul avand rand in `tvanz` (semnalul din `rec_s5_cale_scriere_vfp.md` 2.5, `Used('tvanz') AND Reccount('tvanz')=1`) cere aceeasi confirmare. Workarea de dinainte de validare se salveaza in `lnAreaTvd` si se restaureaza pe toate iesirile. ## Runda 2 — corectii din code-review obligatoriu pe diff - **`AdaugaLinieTvdDinArticol` nu copia `pret_achizitie`.** Linia noua adaugata prin dialogul `frm_articol_factura` (`cmdAdaugaArticol.Click` -> `CreeazaPoArticolNouTvd`, `ofacturare_editare.prg:379`) primeste `poArticol.pret_achizitie` ca proprietate, dar `REPLACE`-ul care creeaza randul in `tvd` nu o citea — coloana noua ramanea goala pe orice linie noua, desi valoarea putea fi deja disponibila. Corectat: `pret_achizitie WITH Nvl(toArticol.pret_achizitie,0)` adaugat in acelasi `REPLACE`. `id_vanzare_set` nu are nevoie de valoare explicita — `Nvl(id_vanzare_set,0)` pe camp `NULL` dupa `APPEND BLANK` evalueaza deja corect la 0. - **Recno('tvd') nu se restaura la iesire timpurie din validari.** `SELECT (m.lnAreaTvd)` restaura doar workarea apelantului, nu si pozitia in `tvd` insusi. Corectat: `lnRecnoTvd = Recno('tvd')` salvat inainte de `SCAN`, restaurat cu `GO (m.lnRecnoTvd) IN tvd` pe toate cele 5 iesiri (4x `RETURN .F.` + finalul cu succes). - **`Isnull(pret_achizitie) OR Nvl(pret_achizitie,0)=0` era redundant** — `Nvl` transforma deja `NULL` in `0`, deci a doua conditie il acopera pe primul. Simplificat la o singura conditie. - **Analizat, nu schimbat**: garda `"OFACTURARE_EDITARE" $ Upper(Set("Procedure")) AND Used('tvd')` se reduce practic la "sunt in ROAFACTURARE", pentru ca `tvd` exista mereu dupa `Load()`. Nu s-a extins gardarea: `tvd` are randuri active doar cand exista un match real cu `VANZARI` (deci randurile pornesc valide, din Oracle), iar confirmarea pe "zero linii active" e ea insasi gardata separat pe `Used('tvanz') AND Reccount('tvanz')=1` — riscul practic de blocare pe un ecran neasociat unei vanzari e deja redus de aceasta a doua conditie. - **Neschimbate, evaluate ca stil existent, nu bug**: `DynamicForeColor` repetat identic pe cele 15 coloane, verificarea `id_vanzare_set` duplicata in 4 handlere `When` separate, `cPretAchizitieArt.Text1` fara `Valid` (nu are nevoie — nu alimenteaza `calculeaza_valori_articol`, iar `lmodificat` nu e citit pe calea liniilor noi la salvare). ## Runda 3 — inconsecventa latenta semnalata de al doilea review (`docs\review_s5_grid_articole.md`) Avertismentul de `pret_achizitie = 0/NULL` la salvare (`inainte_de_do_termin`) exempteaza doar `Nvl(id_vanzare_det,0) = 0` (linie noua). Garda de editare `cPretAchizitieArt.Text1.When` (`omodificari.vc2`, cauta `PROCEDURE ...cPretAchizitieArt.Text1.When`) exempteaza in plus `Nvl(id_vanzare_set,0) <> 0` — adica, daca ar exista vreodata o linie cu `id_vanzare_det = 0 AND id_vanzare_set <> 0` (linie noua care apartine deja unui set), campul ar fi needitabil in grid, dar avertismentul tot ar aparea la fiecare salvare, fara ca userul sa poata corecta valoarea. **Neexploatabil pe codul actual**: singura cale de adaugare a unei linii noi e `AdaugaLinieTvdDinArticol` (`APPEND BLANK` + `REPLACE`), care nu scrie niciodata `id_vanzare_set` — campul ramane `.NULL.`, deci `Nvl(id_vanzare_set,0) = 0` intotdeauna pe linii noi. Combinatia `id_vanzare_det = 0 AND id_vanzare_set <> 0` nu se poate produce azi. Fara fix. **Conditia care ar activa-o**: daca se implementeaza vreodata editarea/adaugarea de linii in seturi de articole si liniile noi rezultate primesc `id_vanzare_set` populat, cele doua conditii (avertismentul din `inainte_de_do_termin` si garda din `When`) trebuie aliniate in acelasi commit care aduce acea functionalitate — altfel userul ramane blocat intr-un nag fara iesire. ## Ce nu s-a atins `ofacturare.vc2`, `ofacturare_comun.vc2`, `comun.vc2`, `ofacturare_editare.prg` — nicio scriere. Helperul `ScrieArticoleFacturaEditate` si agatarea in cele doua puncte de intrare raman lucrarea altor loturi ale sesiunii S5. ## Netestabil headless Coloanele gridului nu se materializeaza sub `-A -T` (`grid-coloane-nu-se-materializeaza-headless`, memorie recurenta) — verificarea vizuala a coloanei noi si a marcajului de culoare cere harnessul UI existent (`test_ui_grid_articole.prg` sau echivalent). Validarile din `inainte_de_do_termin` sunt totusi testabile headless, apeland metoda direct pe o instanta cu `tvd` populat manual.