Files
roafacturare/docs/cercetare/rec_s4_fix_culoare_valuta.md
Marius Mutu d9f5ca4226 docs: planurile, proiectarile si rapoartele de lucru intra in versionare
Folderul docs\ era pana acum in afara oricarui control de versiuni - nici git,
nici SVN - desi contine planurile pe puncte, proiectarile si rapoartele de
cercetare pe care se sprijina modificarile din cod. O stergere acolo era
definitiva.

Fisierele intermediare (handoff-uri intre sesiuni, diff-uri deja aplicate) au
fost sterse inainte, nu versionate: ce era durabil in ele a intrat in antetele
fisierelor de test la care se refereau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-11 22:17:17 +03:00

13 KiB

S4 — doua defecte pe pagina de articole: culoarea liniei sterse + valuta liniilor noi (09.08.2026)

Doua defecte raportate dupa livrarea sub-blocului B (stergere + adaugare de linii). Ambele in COMUN\clase\omodificari.vc2 (frm_modific2024, pgfArticole.PAGE3); al doilea atinge si COMUN\programe\ofacturare_editare.prg. Ambele REZOLVATE, dovedite, scrise in binar, necomise.

Defectul 1 — marcajul vizual DynamicForeColor nu se aplica pe linia stearsa

Cauza reala (nu ipoteza de start, confirmata pe cod)

grdArticoleFactura e definit ca ADD OBJECT 'pgfArticole.PAGE3.grdArticoleFactura' AS _grdrow (omodificari.vc2:12306), unde _grdrow (COMUN\clase\_grd_base.vc2:445-489) e o clasa a suitei comune (nu proprietatea acestei livrari — doar citita) care evidentiaza linia curenta a gridului:

PROCEDURE Init
	DoDefault()
	If This.nRgbrow = 1
		...
		This.SetAll("DynamicForeColor","iif(RECNO() = This.nRecno,RGB(" + This.cRGB_Font + "),RGB(0,0,0))","Column")
	Endif
ENDPROC

nrgbrow implicit e 1. La instantiere, dupa ce PropValue-urile clasei (inclusiv Column1..14.DynamicForeColor = "IIF(tvd.sters=1,RGB(150,150,150),RGB(0,0,0))") sunt aplicate, Init ruleaza si SetAll suprascrie necondiționat DynamicForeColor pe toate cele 14 coloane cu o expresie care ignora tvd.sters complet — de-asta linia stearsa avea pixeli negri puri (0,0,0), nu gri (150,150,150): codul din clasa era corect, dar era deja inlocuit inainte de primul Refresh().

Ipoteza de start din briefing ("_grdrow.Init castiga in fata lui DynamicForeColor") s-a confirmat exact, cu mecanismul precis identificat (SetAll in Init, nu doar AfterRowColChange).

De ce nu solutia gridurilor surori

grdRulaje/grdRulajeObinv (pgfArticole.PAGE1/PAGE2) rezolva coliziunea cu Init gol (*Nu sterge, omodificari.vc2:~15659/~15926) — asta taie tot lantul DoDefault(), deci si _grid.Init() (cel care seteaza ReadOnly pe coloanele text dupa lcamptextneeditabil). grdArticoleFactura are nevoie sa ramana editabil pe cantitate/pret/pret_cu_tva (lcamptextneeditabil=.F., fix din sesiunea anterioara) — un Init gol ar fi rupt din nou editabilitatea.

Fix

O singura proprietate pe ADD OBJECT-ul gridului (omodificari.vc2:12317):

nrgbrow = 0, ;

nrgbrow=0 scurt-circuiteaza intreg blocul If This.nRgbrow = 1 din _grdrow.Init (deci si SetAll) fara sa taie DoDefault() -> _grid.Init() — editabilitatea ramane intacta. Tiparul e deja folosit in 20+ griduri din suita comuna (COMUN\clase\configurare.vc2, COMUN\clase\onomenclatoare.vc2), deci nu e o solutie inventata pentru acest caz — e conventia existenta pentru "grid cu culoare proprie pe randuri, fara evidentierea implicita a liniei curente".

Dovada — esantionare de pixeli, nu vizual

Doua capturi noi, sub vfp_ui_harness.ps1 -SyncDir explicit (capcana de sincronizare deja rezolvata in sesiunea precedenta):

  • COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\step_0_contrast_gri_vs_negru.png — document cu 4 linii (cod=1140895/id_vanzare=1050), linia 2 marcata stearsa prin cmdStergeArticol.Click(), linia curenta a gridului mutata pe linia 3 (GO 3 + loGrid.SetFocus()) ca selectia (fundal albastru) sa nu acopere nici linia stearsa, nici o linie de control. Esantionare cu System.Drawing.Bitmap.GetPixel pe banda de text a fiecarei linii (PowerShell, cautare pixel cu luminanta minima in regiune):

    Linie Pixel cel mai inchis (RGB)
    Linia 1 (normala, sters=0) (0,0,0)
    Linia 2 (STEARSA, sters=1) (150,150,150) — exact RGB(150,150,150) din DynamicForeColor
    Linia 4 (normala, sters=0) (0,0,0)
  • COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\step_0_linia_grizata.png — document cu 2 linii (cod=1139934/id_vanzare=882), aceeasi verificare, acelasi rezultat (RGB(150,150,150) pe linia stearsa).

Capturile "before" (linia stearsa cu pixeli negri puri, dovada defectului inainte de fix), mutate din sesiunea anterioara: screenshots_before_fix_culoare\step_0_linia grizata dupa sters.png + step_0_crop_zoom.png.

Testat, regresie

test_ui_sterge_linie.prg (existent, nemodificat in logica — doar rerulat): 8 PASS / 0 FAIL, log complet pana la REZULTAT. test_page3_articole.prg: 14 PASS / 2 FAIL (identic cu baseline, cele 2 FAIL sunt artefactul headless cunoscut de la datoria 7 — ColumnCount/ReadOnly nu se materializeaza sub -A -T). test_incarca_vanzare_din_nota.prg: 5 PASS / 0 FAIL.

Suita noua test_ui_culoare_contrast.prg (dedicata acestui fix, ramane in suita de regresie): descopera dinamic un document cu minim 3 linii (DescoperaCazTest('FACTURA_ARTICOLE', ...), nu ancorat pe cod), marcheaza a doua linie stearsa, muta linia curenta pe a treia, face captura. 1 PASS / 0 FAIL pe asertia functionala (sters=1 dupa click); dovada vizuala e in captura + esantionarea de pixeli de mai sus, nu intr-o asertie automata (culoarea nu se poate verifica prin EVALUATE in interiorul testului — eroarea 1929, deja documentata in rec_s4_runda3b2.md).

Defectul 2 — liniile adaugate intrau fortat in RON

Cauza reala (diferita de formularea initiala din briefing)

Briefingul presupunea ca AdaugaLinieTvdDinArticol scrie tip_valuta = 0 fix — verificat pe cod, fals: tvd (structura din CreeazaCursorArticoleGol, ofacturare_editare.prg:268-271) nu are deloc un camp tip_valuta, curs sau multiplicator — acele campuri nu exista in view-ul VVANZARI_ARTICOLE (linia stocheaza doar id_valuta, o referinta la nom_valute, fara factor de conversie propriu).

Cauza reala e in alta parte: tip_valuta=0/Curs=1/multiplicator=1 sunt hardcodate pe poArticol in CreeazaPoArticolNouTvd (ofacturare_editare.prg:429-431), iar poDate.in_valuta e hardcodat 0 in cmdAdaugaArticol.Click (omodificari.vc2:16190) — asta tine dialogul frm_articol_factura in modul RON indiferent de valuta reala a documentului. Dialogul calculeaza pretftva/pretctva (campurile RON) pe baza a ce introduce utilizatorul, iar AdaugaLinieTvdDinArticol scria acele valori neconvertite in tvd.pret/tvd.discount_unitar.

Bara de totaluri (ActualizeazaBaraTotaluri, decizia 33, omodificari.vc2:12856-12899) insumeaza tvd.valoare brut (SUM valoare FOR sters<>1) si aplica o singura data tvanz.curs/multiplicator pe suma — asta presupune ca fiecare linie e deja stocata in valuta documentului, nu in RON. Verificat pe date (schema MARIUSM_AUTO):

id_vanzare VANZARI.in_valuta VANZARI.id_valuta curs linia (VANZARI_DETALII.pret)
1037 1 2 (EURO) 5.2688 pret=200 — 200 EUR brut, nu 200 RON

O linie noua scrisa in RON (ex. utilizatorul intentioneaza 1053.76 RON) ar fi ramas pret=1053.76 in tvd, iar bara de totaluri ar fi calculat 1053.76 * 5.2688 = 5551.6 RON — de peste 5 ori valoarea reala.

Fix — scopat strict pe stocare, fara sa ating dialogul

frm_articol_factura/ofacturare.vc2 nu sunt in proprietatea acestei livrari (partajate cu tot restul suitei), si a face dialogul sa accepte pret direct in valuta ar cere poDate.id_valuta/poDate.zi_curs populate corect (altfel validarea interna a dialogului respinge la "Terminare" cu mesaj — verificat pe cod, ofacturare.vc2:9484,9490) — netestabil headless (Show() e modal) si risc pe o clasa mare, necunoscuta. Fix ales, minim si sigur:

  1. tvanz extins cu in_valuta, id_valuta, nume_val (join nou pe nom_valute in IncarcaVanzareNota, ofacturare_editare.prg:150-176; CreeazaCursorTvanzGol la fel).
  2. AdaugaLinieTvdDinArticol (omodificari.vc2:12901-12934) converteste pretul/discountul calculate de dialog (RON) in valuta documentului, inainte de a le scrie in tvd: pret = pretRON * tvanz.multiplicator / tvanz.curs (si simetric pentru discount_unitar) — inversul exact al formulei din bara de totaluri, deci no-op pe documente RON (curs=multiplicator=1, verificat neregresat pe suita existenta).
  3. id_valuta/nume_val ale liniei noi preiau valorile de pe tvanz (tvanz.id_valuta, tvanz.nume_val) in loc de .Null./gol — simetric cu liniile existente, care le au populate din VVANZARI_ARTICOLE.

Limitare ramasa, de raportat explicit: dialogul tot lucreaza in RON — utilizatorul introduce pretul in RON chiar si pe un document in valuta, iar conversia se face "in spate", la scriere. STOCAREA e acum corecta valutar (bara de totaluri calculeaza corect regardless de valuta documentului), dar UX-ul de introducere a pretului direct in valuta nu e implementat — ar cere atingerea ofacturare.vc2, in afara scope-ului primit ("nu era ceruta multi-valuta in briefing" — decizie mostenita din sub-blocul B partea 2, rec_s4_runda3b2.md).

Testat

  • test_page3_articole.prg: 14 PASS / 2 FAIL (identic cu baseline).
  • test_incarca_vanzare_din_nota.prg: 5 PASS / 0 FAIL.
  • test_adauga_linie_articol.prg (existent, caz RON): 20 PASS / 0 FAIL — confirma ca conversia e no-op cand curs=multiplicator=1, nicio regresie pe calea deja acoperita.
  • Suita noua test_adauga_linie_valuta.prg: foloseste un document real cu articole (descoperit dinamic, nu ancorat pe cod), dar suprascrie manual tvanz.curs=5.2688, multiplicator=1, in_valuta=1, id_valuta=2, nume_val='EURO' dupa Show() — nu exista in schema un caz descoperibil simultan "cu articole" si "in valuta reala" (id_vanzare=1037, EURO, are o singura linie, nefolosibila pentru un test de "adaugare langa liniile existente" fara ambiguitate). Construieste poArticol cu pretftva=1053.76 (echivalentul RON a 200 EUR la cursul testat) si verifica: 6 PASS / 0 FAIL — tvd.pret convertit la 200.00, id_valuta=2, nume_val='EURO', tvd.valoare=200.00, iar bara de totaluri creste cu exact 1053.76 RON (echivalentul corect, nu suma bruta).

Cens de octeti si write-back

Baseline la inceputul sesiunii: 2 aa / 2 e3 / 2 fe, zero EF BF BD. Primul Edit pe omodificari.vc2 (adaugarea nrgbrow = 0) a reencodat tot fisierul, stricand din nou cele doua linii Caption = "CTRL+F = Terminare; ESC = Renunțare; CTRL+N = Adăugare; CTRL+D = Ștergere" (capcana deja cunoscuta, lovita si in sesiunile precedente) — cens dupa: 6 ef / 6 bf / 6 bd. Reparat byte-cu-byte cu Perl (pozitional: octetul 1 din fiecare tripleta EF BF BD -> 0xFE (ț), octetul 2 -> 0xE3 (ă), octetul 3 -> 0xAA (Ș), ciclic pe cele 2 linii x 3 caractere). Cens final, verificat inainte si dupa txt2vcx.ps1: identic cu baseline, 2 aa/2 e3/2 fe, zero EF BF BD.

ofacturare_editare.prg e ASCII pur (verificat, zero octeti >0x7F) — fara risc de encoding, nu necesita reparare.

Fidelity-check trecut din prima incercare (txt2vcx.ps1 -AllowComun, un singur fisier regenerat) — spre deosebire de sesiunile precedente, nu a fost nevoie sa adopt textul regenerat din <staging>\verify\.

Fisiere atinse, stare write-back

Fisier Stare
COMUN\clase\omodificari.vc2 Editat (nrgbrow=0 pe grid + AdaugaLinieTvdDinArticol rescrisa), write-back FACUT, fidelity check OK din prima, cens OK
COMUN\clase\omodificari.vcx / .VCT Scrise, mtime sincron cu .vc2 (16:59)
COMUN\clase\omodificari.vc2.pre_fix_culoare.bak Backup, luat la inceputul sesiunii
COMUN\programe\ofacturare_editare.prg Editat (CreeazaCursorTvanzGol + IncarcaVanzareNota extinse cu valuta documentului, antet rescris), ASCII pur
COMUN\programe\ofacturare_editare.prg.pre_fix_culoare.bak Backup, luat la inceputul sesiunii
COMUN\utile\Teste\editare_factura\test_adauga_linie_valuta.prg Nou, testat, 6/6 PASS
COMUN\utile\Teste\editare_factura\test_ui_culoare_contrast.prg Nou, testat, captura + esantionare pixeli
COMUN\utile\Teste\editare_factura\screenshots_after_fix_culoare\ Nou — 2 capturi, dovada pe pixeli
COMUN\utile\Teste\editare_factura\screenshots_before_fix_culoare\ Capturile "before" din sesiunea anterioara, mutate din screenshots\ ca sa nu se piarda
docs\diff_s4_fix_culoare_valuta.patch Nou — omodificari.vc2
docs\diff_s4_fix_culoare_valuta_ofacturare_editare.patch Nou — ofacturare_editare.prg
docs\progres.md Actualizat

Fara commit — asteapta review, conform regulii.

Ce NU e acoperit

  1. Dialogul frm_articol_factura tot lucreaza in RON — utilizatorul introduce pretul in RON chiar si pe un document in valuta; conversia se aplica la scriere, nu la intrare. A schimba asta ar cere atingerea ofacturare.vc2 (poDate.in_valuta=1 + id_valuta/zi_curs populate), in afara proprietatii/scope-ului acestei livrari.
  2. Show(1) (dialogul modal chiar deschis) — netestat automat (netestabil headless), ca in sesiunile precedente; acoperit doar prin analiza de cod si testare manuala recomandata.
  3. Editarea unei linii existente prin acelasi dialog (dublu-clic) — ramane nefacuta, in afara scope-ului primit in aceasta sesiune.
  4. Decizia de arhitectura despre _grd_base.vc2: fixul defectului 1 s-a facut fara sa ating _grd_base.vc2 (clasa comuna) — nrgbrow era deja o proprietate expusa pentru exact acest caz, nu a fost nevoie de nicio modificare acolo.