# Implementarea deciziei 42 — articole needitabile pe factura trimisa in eFactura Scris 10.08.2026. Implementare + testare + write-back verificat. **ZERO commit** (git/svn), conform interdictiei primite. > ## COMPLETARE, 10.08.2026 ora ~12:55 — discountul de antet intra sub garda > > Agentul care a scris acest raport a apucat sa faca **modificarea de cod si write-back-ul**, apoi a > cazut pe limita de sesiune **inainte de verificare**. Blocul de mai jos e scris de orchestrator, > care a preluat si a dus verificarea la capat. > > **Decizia lui Marius**: `txtDiscountArt` (discountul de antet) **se blocheaza si el** cand documentul > e trimis in eFactura — schimba totalurile unui document deja depus la ANAF, chiar daca nu atinge > nicio linie. > > **Codul**: `omodificari.vc2:14813` — `This.pgfArticole.PAGE3.txtDiscountArt.ReadOnly = > This.lArticoleReadOnly`, prin acelasi flag, fara mecanism nou. > > **A doua cale de scriere — cautata si exclusa**: `txtDiscountArt.Valid` (`:16592`) doar cheama > `Thisform.ActualizeazaBaraTotaluri()`, deci **recalculeaza afisajul, nu scrie discountul nicaieri**. > Nu exista buton sau apel programatic care sa-l seteze ocolind caseta, deci garda dubla care a fost > necesara la butoanele de articole (`Click`) **nu isi are rostul aici**. Salvarea propriu-zisa trimite > discountul ca parametru catre `recalculeaza_totaluri_vanzari` (decizia 41), luand valoarea din caseta. > > **Verificat de orchestrator pe disc, dupa caderea agentului**: > - **Write-back complet**, dovedit prin reconversie binar -> text in cache temporar si comparatie > **octet cu octet**: identic, 540712 octeti. Cens de octeti `2 aa . 2 e3 . 2 fe`, zero `EF BF BD`. > - **Regresia rerulata integral pe starea de pe disc**, dupa write-back (binar 12:33:09): > `test_page3_articole` **14/2** (artefactul headless cunoscut), `test_adauga_linie_articol` **20/0**, > `test_adauga_linie_valuta` **16/0**, `test_ui_sterge_linie` **8/0**, `test_verdict_act_rul` **26/0**, > `test_incarca_vanzare_din_nota` **5/0**, `test_s5_validari_articole` **35/0**. Nicio regresie. > - **Acoperire noua**: `test_efactura_readonly.prg` extins cu doua asertii si rerulat — > **23 PASS / 0 FAIL** (de la 21). Cele doua noi: `caz A: txtDiscountArt.ReadOnly = .T.` pe documentul > real trimis in eFactura, si `caz B: txtDiscountArt.ReadOnly = .F. (neregresat)` pe cel netrimis. > Garda e verificata deci **in ambele sensuri**, nu doar pe cazul pozitiv. > - Zero procese `vfp9.exe` ramase, zero commituri. > > **Ce NU e acoperit**: suita UI vizibila (`test_ui_efactura_readonly.prg`, 14/0) **nu a fost rerulata** > dupa adaugarea discountului — ea verifica `.When`-urile de celula, neatinse de aceasta completare, > deci riscul e mic, dar golul e declarat, nu ascuns. > > Diff-ul consolidat (COMUN + ROAGEST) e regenerat in `docs\diff_d42_efactura_readonly.patch`. ## Ce s-a schimbat, si unde ### `COMUN\clase\omodificari.vc2` (`frm_modific2024`) - **Proprietate noua** `lArticoleReadOnly` (Boolean, implicit `.F.`): `*p:` la `:6827`, valoare implicita la `:6866`. - **`Show`** (`:14788-14827`): calculeaza flagul in acelasi bloc unde se determina `lAreArticoleVanzari`/`nIdVanzare`/`nTipVanzare` (adica doar cand `ofacturare_editare.prg` e incarcat si documentul are rand in `VANZARI`): `This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact,0))` (`:14798`). In blocul care pregateste `PAGE3`, aplica flagul: `cmdAdaugaArticol.Enabled`/`cmdStergeArticol.Enabled` = `!lArticoleReadOnly` (`:14811-14812`), `lblArticoleReadOnly.Visible = lArticoleReadOnly` (`:14813`). **`PAGE3` continua sa se pregateasca si sa se afiseze normal** — `PregatesteArticoleFacturaEditare`/`PageCount=3`/`grdArticoleFactura.Refresh()` raman neatinse, conform corectiei explicite a lui Marius (articolele raman vizibile). - **Control nou** `pgfArticole.PAGE3.lblArticoleReadOnly` (`ADD OBJECT` la `:12776`): eticheta discreta, `Visible=.F.` implicit, pozitionata pe randul butoanelor (`Top=4`, `Left=360`, `Width=390`) — la dreapta lui `cmdAdaugaArticol` (care se termina la `Left+Width=345`), deci **nu ia spatiu din grid** (gridul ramane la `Top=26`). Text: „Articole needitabile - factura trimisa in eFactura", `ForeColor RGB(180,120,0)` (aceeasi nuanta de atentionare folosita deja la verdictul ACT/RUL divergent). - **Garda pe butoane** (`cmdAdaugaArticol.Click` `:16488`, `cmdStergeArticol.Click` `:16531`): `OR Thisform.lArticoleReadOnly` adaugat la conditia de `RETURN` timpuriu — belt-and-suspenders fata de `Enabled=.F.`, pentru ca `Enabled` nu blocheaza un apel programatic al metodei `.Click()`. - **Garda pe celule** — cele patru `.When` care controleaza editabilitatea pe rand (mecanismul din S5): `cCantitateArt.Text1.When` (`:16549`), `cPretAchizitieArt.Text1.When`, `cPretArt.Text1.When` (`:16570`), `cPretCuTvaArt._checkbox1.When` (`:16587`) — toate primesc `Thisform.lArticoleReadOnly OR ...` (respectiv `!Thisform.lArticoleReadOnly AND ...` pe checkbox, unde conditia veche era inversa). Se construieste **peste** mecanismul de editabilitate per rand din S5 (`id_vanzare_set`/`id_vanzare_det`), nu-l inlocuieste. - **Notele/rulajele nu sunt atinse**: `Grid1` (nota contabila), `grdRulaje`/`grdRulajeObinv` (paginile 1/2) raman complet neschimbate — verificat explicit in test (`Grid1.ReadOnly` ramane `.F.` pe documentul din eFactura). ### `COMUN\programe\ofacturare_editare.prg` Corectie necesara descoperita in timpul lucrului (vezi mai jos „Decizie/corectie luata pe parcurs"): `EsteInEFactura` se apeleaza cu `VANZARI.ID_FACT`, **nu** cu `id_vanzare` — sunt doua coloane distincte (verificat pe date: 0 potriviri `id_fact = id_vanzare` din 142 facturi tip=1). Contractul existent (`ofacturare_comun.vc2:3764`, neatins) apela deja `EsteInEFactura(lnIdFact)` cu `lnIdFact = crsfacturi.id_fact`. `tvanz` (populat de `IncarcaVanzareNota`) nu avea aceasta coloana. - `CreeazaCursorTvanzGol` (linia 153 din fisier): adaugat `id_fact I NULL` la structura cursorului gol (fallback pe eroare Oracle/cod lipsa). - `IncarcaVanzareNota` (linia 177): adaugat `v.id_fact` la lista de coloane selectate din `VANZARI`. Restul interogarii (join, filtre) neatins. - Antetul fisierului (o singura intrare cumulativa, rescrisa): data actualizata la 10.08.2026, mentiunea `id_fact` adaugata la lista de campuri incarcate. ## Decizie/corectie luata pe parcurs — de raportat, nu era in briefing Implementarea initiala folosea `EsteInEFactura(This.nIdVanzare)` (adica `id_vanzare`). Verificare pe `MARIUSM_AUTO`: ```sql SELECT COUNT(*) total, SUM(CASE WHEN id_fact = id_vanzare THEN 1 ELSE 0 END) equal_cnt FROM vanzari WHERE tip = 1 AND sters = 0; -- 142 total, 0 equal_cnt ``` `id_fact` si `id_vanzare` sunt spatii de ID complet diferite (`id_fact` are valori de forma `8008013`, `id_vanzare` valori mici de forma `1013`) — cu `id_vanzare` gardarea nu s-ar fi declansat NICIODATA in productie (nicio coincidenta intamplatoare intre cele doua plaje). Corectat inainte de scrierea testelor, folosind exact coloana pe care o foloseste deja calea din `ofacturare_comun.vc2:3764` (`lnIdFact = crsfacturi.id_fact`). ## Write-back — verificat prin reconversie + diff, nu pe mtime `txt2vcx.ps1 -AllowComun` rulat de trei ori (prima incercare a picat fidelity-check-ul din cauza ordinii gresite a blocului `ADD OBJECT` — proprietatile/obiectele dintr-o clasa `.vcx` trebuie in ordine STRICT alfabetica dupa nume, nu dupa ZOrder; a doua rulare a picat pentru ca lipsea corectia `id_fact`; **a treia rulare, OK**, fidelity check trecut). Verificare **independenta** de fidelity-check-ul intern al `txt2vcx.ps1`: reconversie separata a binarului proaspat scris (`vcx2txt.ps1 -Source omodificari.vcx` intr-un cache temporar izolat) + `diff`/`cmp` octet cu octet fata de `.vc2`-ul din proiect: ``` diff -q omodificari.vc2 /omodificari.vc2 -> IDENTIC cmp omodificari.vc2 /omodificari.vc2 -> BYTE-IDENTIC ``` Text si binar sunt sincrone, dovedit, nu presupus. ## Cens de octeti (regula cp1250) — inainte/dupa, identic cu baseline `omodificari.vc2` are diacritice cp1250 preexistente (tooltip-uri „Renunțare/Adăugare/Ștergere", octeti `0xFE`/`0xE3`/`0xAA`). **Baseline: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`.** Editarea celor doua proprietati noi (`*p:`/`*`) s-a facut initial cu tool-ul `Edit` (2 apeluri) — asta a **stricat** censul (`6 ef / 6 bf / 6 bd`, adica `EF BF BD` x2 aparitii x3 octeti), exact capcana documentata (`Edit`/`Write` re-encodeaza tot fisierul la orice scriere, indiferent cat de mica). **Reparat** inainte de a continua: octetii corecti (`Renun[FE]are`, `Ad[E3]ugare`, `[AA]tergere`) preluati din `git cat-file blob HEAD:clase/omodificari.vc2` (varianta necorupta, comisa) si inlocuiti inapoi punctual. Toate editarile ulterioare (Show(), garzile pe butoane/celule, blocul `ADD OBJECT` al etichetei noi) s-au facut **pe octeti**, cu Perl (`<:raw`/`>:raw`, cautare/inlocuire literala `\Q...\E`, fara nicio decodare de encoding), tocmai ca sa nu se repete problema. **Cens final: `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** — identic cu baseline, verificat dupa fiecare grup de editari. `ofacturare_editare.prg` nu are octeti `>=0x80` (cens gol inainte si dupa) — editat direct cu `Edit`, fara risc. ## Regresie — cifre numarate din loguri, toate DUPA ultima editare de cod Ultima editare de cod: `omodificari.vc2` scris in binar la `11:37:23` (a treia rulare `txt2vcx.ps1`, cu corectia `id_fact`); `ofacturare_editare.prg` editat inainte de asta. Toate rularile de mai jos sunt **dupa** acel moment. | Suita | Rezultat | Baseline | Stare | |---|---|---|---| | `test_page3_articole.prg` | 14 PASS / 2 FAIL | 14/2 | **neregresat** (cele 2 FAIL = artefactul headless cunoscut, ColumnCount/ReadOnly pe grid needitabil sub `-A -T`) | | `test_adauga_linie_articol.prg` | 20 PASS / 0 FAIL | 20/0 | **neregresat** | | `test_adauga_linie_valuta.prg` | 16 PASS / 0 FAIL | 16/0 | **neregresat** | | `test_ui_sterge_linie.prg` | 8 PASS / 0 FAIL | 8/0 | **neregresat** | | `test_verdict_act_rul.prg` | 26 PASS / 0 FAIL | 26/0 | **neregresat** | | `test_incarca_vanzare_din_nota.prg` | 5 PASS / 0 FAIL | 5/0 | **neregresat** | | `test_s5_validari_articole.prg` | 35 PASS / 0 FAIL | 35/0 | **neregresat** (linia care contine cuvantul "FAIL" e text descriptiv al unei ramuri moarte deja documentate, nu un esec real — `REZULTAT: 35 PASS / 0 FAIL`) | Zero regresii pe toate cele sapte suite existente. ## Suite noi ### `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (headless) — **21 PASS / 0 FAIL** Documente REALE, gasite prin interogare (nu inventate): - **Caz A — trimis in eFactura**: `id_vanzare=1013` (`cod=1140509`, an=2025, luna=8), `VANZARI.ID_FACT=8008013`, prezent in `ANAF_EFACTURA`. - **Caz B — NEtrimis** (regresie): descoperit prin proprietate (`DescoperaCazTest`, `FACTURA_ARTICOLE`), `cod=1140895` (id_vanzare=1050, documentul deja folosit de restul suitei). Acopera: `EsteInEFactura` direct (cu `0` si cu `8008013`); `lArticoleReadOnly` corect pe ambele cazuri; **`PAGE3` NU e suprimata** (`PageCount=3`, `RecordSource` neschimbat, `tvd` cu linii); `cmdAdaugaArticol`/`cmdStergeArticol.Enabled`; vizibilitatea etichetei; garda pe `cmdStergeArticol.Click()` (apelat direct, fara dialog modal — confirma ca linia nu se modifica pe documentul din eFactura si ca se modifica normal pe cel obisnuit); `Grid1.ReadOnly` neatins (nota ramane editabila). Nu scrie in Oracle. **Ce nu acopera** (documentat explicit in fisier, nu ascuns): editabilitatea per-celula (`.When()` pe coloanele gridului) — coloanele **nu se materializeaza sub `-A -T`** (`ColumnCount=0`, eroare 1925 „Unknown member" la accesul pe nume), artefact cunoscut si documentat (`grid-coloane-nu-se-materializeaza-headless`). Mutat in suita UI de mai jos. ### `COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (UI vizibil) — **14 PASS / 0 FAIL** Rulat prin harnessul corect (`vfp_ui_harness.ps1 -TestPrg ... -Steps @(...) -SyncDir ...`), nu prin lansare directa — o incercare initiala prin `Start-Process` direct a dat tot `ColumnCount=0`; cauza reala **nu era lansarea**, ci lipsa apelului `IncarcaArticoleFactura(1013, 'crsArticoleFactura')` **inainte** de `Createobject` — gridul se leaga o singura data, la construire (in `Load()`), pe cursorul `tvd` existent atunci; fara precarcare, `Load()` creeaza `tvd` GOL, iar fallback-ul din `Show()` il **recreeaza prin SQL** dupa constructie — cursor diferit de cel pe care s-a legat gridul, deci `ColumnCount` ramane 0. Corectat dupa tiparul deja folosit de `test_ui_s5_grid_pret_achizitie.prg`. Acopera, pe acelasi document real (`id_vanzare=1013`, in eFactura): gridul are 15 coloane (neregresat); `.When()` pe toate cele patru controale (`cCantitateArt`, `cPretArt`, `cPretAchizitieArt`, `cPretCuTvaArt._checkbox1`) intorc `.F.` — **needitabile pe orice linie normala, nu doar pe liniile din set**; caz sintetic de control (`lArticoleReadOnly` comutat manual pe `.F.` pe acelasi document/aceleasi obiecte) — cele trei celule redevin editabile, deci gating-ul e demonstrat pe flag, nu pe o coincidenta a documentului ales. Captura: `screenshots_efactura\step_0_grid_efactura_readonly.png`. Nu scrie in Oracle. ## Ce NU s-a putut testa, si de ce - **Dialogul de adaugare articol** (`frm_articol_factura`, `Show(1)` modal): garda de pe `cmdAdaugaArticol.Click()` (Enabled=.F. + guard in cod) nu s-a putut exercita prin click real headless — consecvent cu limitarea deja documentata pe restul suitei S4/S5 (dialog modal). Doar `Enabled=.F.` verificat direct. - **Ramura moarta preexistenta, gasita dar NEATINSA** (nu in scope): linia `IF !Used('tvd') OR !This.lAreArticoleVanzari OR Thisform.lArticoleReadOnly` din `cmdAdaugaArticol.Click` (`:16497`) foloseste `This.lAreArticoleVanzari` — `This` acolo e butonul, nu formularul, deci proprietatea nu exista pe el. Ramane neexecutata in practica pentru ca `!Used('tvd')` e `.F.` de fiecare data cand butonul chiar e vizibil (short-circuit VFP), deci runtime-ul nu ajunge niciodata sa evalueze operandul gresit. Preexistenta editarii mele (adaugarea mea e doar `OR Thisform.lArticoleReadOnly`, corect scris cu `Thisform`), nu se repara aici — in afara scope-ului deciziei 42. - **Verificarea vizuala pe ecran de Marius**: eticheta discreta, pozitionarea ei fata de butoane, culoarea, comportamentul real la click de mouse pe grid. ## Stare finala verificata - **Write-back facut si dovedit** pentru `omodificari.vc2` (reconversie + diff octet cu octet, identic). `ofacturare_editare.prg` e `.prg` — sursa directa, fara pas de write-back. - Cens de octeti pe `omodificari.vc2`: **`2 aa / 2 e3 / 2 fe`, zero `EF BF BD`** — identic cu baseline, verificat dupa ultima editare. - Zero procese `vfp9.exe` ramase (verificat cu `tasklist`) dupa toate rularile mele. Procesul `vfp9.exe` al agentului `s8-creare-variante` (fereastra „S8 - creare documente") a ramas intact, neatins. - Zero scrieri in Oracle in toata sesiunea — toate interogarile (`EsteInEFactura`, `IncarcaCursoareModificareNota`, `IncarcaVanzareNota`, `IncarcaArticoleFactura`) sunt `SELECT`. - Zero commit (git/svn). - Diff consolidat: `docs\diff_d42_efactura_readonly.patch` (ambele fisiere). - Fisiere noi, necomise: `COMUN\utile\Teste\editare_factura\test_efactura_readonly.prg` (+ log), `COMUN\utile\Teste\editare_factura\test_ui_efactura_readonly.prg` (+ log + screenshot in `screenshots_efactura\`). ## Interzis — respectat `ofacturare.vc2`, `ofacturare_comun.vc2`, `comun.vc2`: neatinse (verificat — niciun `Edit`/`Write` pe ele in aceasta lucrare). `actualizeaza_vanzari`, `PACK_CONTAFIN`, `PACK_FACTURARE`: neatinse. Niciun `INSERT`/`UPDATE` pe `id_vanzare` `1049`/`1050`/`1048`.