# S4 runda 3, sub-blocul B partea 2 — adaugarea de linii + doua goluri, 09.08.2026 Continuarea lui `rec_s4_runda3b.md` (stergerea logica, GATA) si `handoff_s4_runda3b_adaugare.md` (cercetarea de contract, predata). Aici: **adaugarea de linii prin dialogul `frm_articol_factura`**, plus inchiderea celor doua goluri lasate de partea 1. ## 1. Adaugarea de linii — IMPLEMENTATA ### Selectorul de articol (decizia 34) **Nu s-a scris niciun selector nou.** Cautand un "picker simplu pe nomenclator, fara stoc, fara politica de preturi", am gasit `caut_articol()` (`COMUN\programe\ocautare.prg:1636`) — functie GLOBALA deja folosita in toata aplicatia, deja inregistrata app-wide (`Programe\roafacturare.prg:191`, `SET PROCEDURE TO ocautare ADDITIVE`). Cauta pe view-ul `vnom_articole` (denumire/codmat/codbare), **fara nicio legatura cu `crsarticole`/stocul de la compunere** — satisface exact decizia 34. Returneaza un obiect cu `.id_articol`, `.denumire`, `.codmat`, `.um`, `.cont` etc. ### Contractul `frm_articol_factura` — confirmat pe cod, nu doar reluat din cercetarea veche - `poDate` foloseste doar 3 proprietati in tot corpul clasei (`ofacturare.vc2:1108-2657`): `tip`, `in_valuta`, `dataact` — verificat din nou cu grep pe intervalul exact. - `gnScadereStoc = 0` bypasseaza complet verificarea de stoc (`Do Case` la `ofacturare.vc2:13804`-echivalent in clasa `frm_articol_factura`), conform deciziei 15. - `do_initializeaza_articol`/`do_modifica` (`ofacturare.vc2:13618`/`13746`) **NU apartin** `frm_articol_factura` — sunt metode pe `frm_facturare_articole` (clasa de compunere), verificat cu `vfp_symbols.ps1 -Where`. Nu au putut fi reutilizate direct (clasa nu-mi apartine oricum); s-a construit in schimb `CreeazaPoArticolNouTvd`, dupa modelul **PROVEN in productie** din `COMUN\utile\Teste\facturare_pret_cu_tva\test_pret_cu_tva_dialog.prg` (49 proprietati numerice + 11 caracter, array `laPropN`/`laPropC`) — acelasi test trece 38/38 pe #7, deci setul de proprietati e dovedit suficient pentru tot ce cere `frm_articol_factura` (Init + toate handlerele + `inainte_de_do_termin`). ### Ce s-a scris `COMUN\programe\ofacturare_editare.prg` — functie noua **`CreeazaPoArticolNouTvd(tnIdArticol, tcCodmat, tcDenumire, tcUm, tcCont)`**: construieste `poArticol` gol cu toate proprietatile cerute. Valori implicite: `cantitate=1`, `gestionabil=0` (fara stoc), `tip_valuta=0` (RON), `preturi_cu_tva=0`, `proc_tvav=.NULL.` (Init-ul dialogului alege singur cota TVA standard curenta din `jtva_coloane` — nu inventez eu o cota), `id_gestiune=-1000` (sentinela "fara gestiune", ca la `do_initializeaza_articol`), `id_ctr=.NULL.`. `COMUN\clase\omodificari.vc2` (`frm_modific2024`): - Buton nou **`cmdAdaugaArticol`** pe `pgfArticole.PAGE3` (`Left=175, Width=170, Top=0`, langa `cmdStergeArticol` — grid-ul ramane `Top=26, Height=81`, neschimbat; **inca incape un al treilea buton** pe acelasi rand pana la marginea grid-ului, 759px latime). - **`PROCEDURE pgfArticole.PAGE3.cmdAdaugaArticol.Click`**: alege articolul prin `caut_articol()`, construieste `poArticol`/`poDate`, seteaza `gnScadereStoc=0`, deschide `Createobject('frm_articol_factura', 1, .F.)` + `.Show(1)` (modal — exact tiparul din `do_adauga_articol`, `ofacturare.vc2:12873`), si daca `gnButon=1` cheama `Thisform.AdaugaLinieTvdDinArticol(poArticol)`. - **`PROCEDURE AdaugaLinieTvdDinArticol(toArticol)`** (metoda noua, separata deliberat de `Click`): `APPEND BLANK` in `tvd` + `REPLACE` toate campurile (`id_vanzare_det=0`, `sters=0`, `lmodificat=.T.`, `pret`/`discount_unitar` alese dupa flagul `preturi_cu_tva` — simetric cu citirea din `IncarcaArticoleFactura`), apoi `Thisform.calculeaza_valori_articol()` (recalculeaza `valoare`, cheama `ActualizeazaBaraTotaluri()` deja existenta din sub-blocul C — **nicio modificare** acolo). Separarea de `Click` a fost necesara ca sa fie testabila: `Show(1)` e modal, nu poate fi condus headless. ### Limitari cunoscute, de raportat explicit - **Doar RON**: liniile noi au `tip_valuta=0`, `Curs=1`, `multiplicator=1` fix — nicio factura in valuta nu poate primi inca o linie noua prin acest buton. Nu era ceruta multi-valuta in briefing; 80/20, notat ca gol. - **Editarea unei linii existente prin acelasi dialog (dublu-clic)** — **NU e in scope-ul primit in aceasta sesiune** (briefingul cerea explicit doar "adaugarea"). Ramane nefacuta. ## 2. Golul "comutare inapoi" (al doilea click pe stergere) — INCHIS `COMUN\utile\Teste\editare_factura\test_ui_sterge_linie.prg`: toate asertiile (inclusiv click 2 — restaurare `sters` 1->0) mutate **inainte** de singurul `HarnessStep` ramas (era programata dupa `HarnessStep WITH 0` in versiunea veche si nu rula niciodata daca harness-ul se bloca la READY). Adaugat un al treilea click (re-marcheaza linia), strict ca linia sa fie in starea "stearsa" pentru captura de la final. **Rulat, 8/8 PASS**, log complet pana la `REZULTAT`: ``` PASS butonul cmdStergeArticol exista PASS butonul e vizibil PASS linia 1 incarcata cu sters=0 PASS dupa click 1: sters=1 pe linia curenta PASS dupa click 1: lmodificat=.T. PASS linia 2 neatinsa de stergerea liniei 1 PASS dupa click 2: sters=0 (restaurata) PASS dupa click 3: sters=1 (re-marcata pentru captura) REZULTAT: 8 PASS / 0 FAIL ``` **Comutarea pe ambele sensuri e acum dovedita**, nu doar sensul de stergere ca la runda 3B partea 1. Codul din `cmdStergeArticol.Click` era deja corect (`REPLACE sters WITH IIF(Nvl(sters,0)=1,0,1)`) — golul era strict in ordinea asertiilor din test, nu in implementare. ## 3. Golul vizual (captura `DynamicForeColor`) — OBTINUTA, si REVELEAZA UN DEFECT REAL **Cauza radacina a esecurilor anterioare (16 incercari in 2 sesiuni), gasita**: testul seta `gcSyncDir = '...\uisync4\'`, dar `vfp_ui_harness.ps1` foloseste implicit `...\uisync\` (fara "4") — handshake-ul `ready_0.txt`/`cont_0.txt` se scria si se astepta in **doua directoare diferite**, deci nu se intalneau niciodata. Nu era masina ocupata — era o nepotrivire de parametru. Fix: apelat harness-ul cu `-SyncDir` explicit, potrivit cu `uisync4`. **A functionat din prima incercare** dupa corectie. Captura obtinuta: `COMUN\utile\Teste\editare_factura\screenshots\step_0_linia grizata dupa sters.png` (si o versiune decupata+marita 3x, `step_0_crop_zoom.png`, pentru verificare de culoare). Cursorul de grid a fost mutat pe linia 2 inainte de captura (`SELECT tvd; SKIP`), ca selectia (fundal albastru) sa nu acopere culoarea liniei 1 (cea marcata sters=1). **Rezultat, verificat prin esantionare de pixeli (nu doar vizual)**: textul liniei 1 (`tvd.sters=1`, confirmat prin asertie in aceeasi rulare) are pixeli cu luminanta **0** (negru pur) in zona literelor — `RGB(150,150,150)` nu poate produce niciodata un pixel cu luminanta 0, indiferent de anti-aliasing. **`DynamicForeColor` NU se aplica vizual**, desi codul e corect scris pe toate cele 14 coloane (`IIF(tvd.sters=1,RGB(150,150,150),RGB(0,0,0))`, `omodificari.vc2:12326-12426`, verificat din nou acum). **Defect real, nou descoperit**, apartine livrarii anterioare (sub-blocul B partea 1, stergerea logica) — **NU l-am reparat**, nu era in scope-ul acestei sesiuni si ar cere investigatie separata (posibil `_grdrow`/`_grid.Init` din `_baza.vc2` suprascrie `ForeColor` static dupa `DynamicForeColor`, sau grid-ul are nevoie de un `Requery`/re-bind pe care `Refresh()` simplu nu-l declanseaza pentru randuri deja randate). **Recomandare**: agent proaspat, sesiune dedicata, cu acest fisier PNG ca dovada de start. ## Testare — cifre numarate din log, run-uri complete pana la linia finala | Suita | Rezultat | Exit / dialoguri | |---|---|---| | `test_page3_articole.prg` (regresie) | **14 PASS / 2 FAIL** (identic cu baseline — cele 2 FAIL, artefact headless cunoscut, datoria 7) | exit 0, 0 dialoguri | | `test_incarca_vanzare_din_nota.prg` (regresie) | **5 PASS / 0 FAIL** (identic cu baseline) | exit 0, 0 dialoguri | | `test_adauga_linie_articol.prg` (NOU, headless, fara dialog modal) | **20 PASS / 0 FAIL**, log complet pana la `REZULTAT` | exit 0, 0 dialoguri | | `test_ui_sterge_linie.prg` (MODIFICAT — golul #2) | **8 PASS / 0 FAIL**, log complet pana la `REZULTAT` + `READY 0` + `CONTINUE 0 (semnal primit)` + `GATA` | UI harness, captura obtinuta | `test_adauga_linie_articol.prg` acopera direct `CreeazaPoArticolNouTvd` (valori implicite) si `Thisform.AdaugaLinieTvdDinArticol` pe un document real (`cod=1140895`, `id_vanzare=1050`, cazul `FACTURA_ARTICOLE`), cu un `poArticol` construit ca dupa un OK de dialog (cantitate=2, pret fara TVA=100, TVA 19%) — verifica `Reccount(tvd)` crescut cu 1, toate campurile liniei noi, si ca bara de totaluri (`nTotalLiniiRon`) creste exact cu valoarea liniei. **Nu testeaza `Show(1)`/dialogul modal insusi** (netestabil headless — ar bloca procesul, exact ca in `test_pret_cu_tva_dialog.prg` pentru #7) — acoperit doar in productie / la testare manuala pe ecran. ## Cens de octeti si write-back Cens baseline (inceputul sesiunii): `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`. **Stricat de doua ori** in aceasta sesiune (o data la prima editare a butonului/Click, o data la refactorul care a extras `AdaugaLinieTvdDinArticol` din `Click`) — de fiecare data acelasi tipar (`Renunțare`/`Adăugare`/ `Ștergere` din `Caption`-ul de pe alt buton, needitat de mine dar in aceeasi zona de fisier), reparat byte-cu-byte cu Perl (pozitional, nu inlocuire oarba — cele 3 caractere au octeti diferiti: `0xFE`=ț, `0xE3`=ă, `0xAA`=Ș). Cens final: **identic cu baseline-ul, `2 aa / 2 e3 / 2 fe`, zero `EF BF BD`**, verificat de 4 ori (dupa fiecare din cele 2 stricari + reparari, plus verificarea finala). **Fidelity-check picat de 2 ori** (ordine `ADD OBJECT`/metoda — capcana deja cunoscuta), rezolvat de fiecare data prin adoptarea textului regenerat din `\verify\omodificari.vc2`. **Scris in binar cu succes** dupa 3 rulari totale ale `txt2vcx.ps1 -AllowComun` (2 esecuri de fidelity + 1 succes pentru prima parte, apoi inca 2 rulari pentru refactor — vezi tabelul de mai jos). `.vc2`/`.vcx`/`.VCT` sincrone, mtime **14:26**. **Observatie de mediu**: fiecare rulare `txt2vcx.ps1` a durat neobisnuit de mult (5-8 minute, `Responding=True` tot timpul, CPU crescator constant, deci NU blocat) — masina pare ocupata de sesiunea reala a lui Marius (ferestre vizibile la enumerare read-only: Brave, VS Code, notepad++, `roastart`), tipar deja documentat in sesiunile precedente din aceeasi zi. Nu a fost nevoie de nicio interventie, doar asteptare. ## Fisiere atinse, stare write-back | Fisier | Stare | |---|---| | `COMUN\clase\omodificari.vc2` | Editat (buton + Click + `AdaugaLinieTvdDinArticol`), write-back FACUT, cens OK | | `COMUN\clase\omodificari.vcx` / `.VCT` | Scrise, mtime sincron cu `.vc2` (14:26) | | `COMUN\clase\omodificari.vc2.pre_runda3b2.bak` | Backup, luat la inceputul sesiunii | | `COMUN\programe\ofacturare_editare.prg` | Editat (functie noua `CreeazaPoArticolNouTvd` + antet), ASCII pur, zero risc de encoding | | `COMUN\utile\Teste\editare_factura\test_adauga_linie_articol.prg` | Nou, testat, 20/20 PASS | | `COMUN\utile\Teste\editare_factura\test_ui_sterge_linie.prg` | Modificat (golul #2 + pozitionare pentru captura), testat, 8/8 PASS | | `docs\diff_s4_runda3b2_adaugare.patch` | Nou — scopat strict pe modificarile mele in `omodificari.vc2` | | `docs\diff_s4_runda3b2_ofacturare_editare.patch` | Nou — **atentie**: `COMUN` are git propriu, diff-ul e fata de ultimul commit, deci contine si munca altor agenti din aceeasi zi, inca necomisa (linia `CreeazaCursorTvdGol()` -> `CreeazaCursorArticoleGol` in `IncarcaArticoleFactura`, `PregatesteArticoleFacturaEditare` intreaga functie). **Partea mea**: antetul fisierului (rescris) + functia `CreeazaPoArticolNouTvd` intreaga, adaugata la coada fisierului. | | `COMUN\utile\Teste\editare_factura\screenshots\step_0_linia grizata dupa sters.png` | Nou — dovada vizuala (revela defectul DynamicForeColor) | | `docs\handoff_s4_runda3b2.md` | Handoff intermediar scris in timpul asteptarii write-back-ului — poate fi sters, sesiunea s-a incheiat normal | **Fara commit** — asteapta review, conform regulii. ## Ce NU e acoperit (predat mai departe / descoperit dar nerezolvat) 1. **Editarea unei linii existente prin `frm_articol_factura`** (dublu-clic) — nu era in scope-ul acestei sesiuni. 2. **Linii noi in valuta** — buton functional doar pentru RON (`tip_valuta` fix 0). 3. **Defectul `DynamicForeColor`** (sectiunea 3 de mai sus) — dovedit cu captura + esantionare de pixeli, nereparat, apartine livrarii anterioare (stergere logica). 4. **`Show(1)` (fluxul complet cu dialogul modal deschis efectiv)** — netestat automat, doar prin analiza de cod si testare manuala recomandata pe ecran, cand masina e libera.