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
19 KiB
Proiectare — Decizia 42: articole factura vizibile, needitabile dupa trimiterea in eFactura
Scris 10.08.2026. Agent read-only, doar cercetare/proiectare — nicio modificare de cod facuta de acest agent.
ATENTIE — implementarea era deja IN LUCRU, de catre alt agent; bugul de mai jos e DEJA CORECTAT
Inainte de a ajunge la proiectare: la momentul cercetarii, COMUN\clase\omodificari.vc2 avea deja
modificari necomise in working tree (git status in COMUN: M clase/omodificari.vc2) care
implementeaza aproape exact Decizia 42 corectata (vizibil, doar needitabil). Agentul d42-efactura,
activ in aceeasi sesiune, lucra chiar atunci pe exact acest subiect.
Acest raport nu descrie deci o proiectare de la zero, ci: (1) verificarea contractelor si (2) un review al diff-ului in lucru, cu un bug real gasit si dovedit pe schema Oracle — vezi §1 si §8.
UPDATE, dupa trimiterea raportului: d42-efactura a gasit acelasi bug independent, in timpul
propriei lucrari (nu din briefingul primit de la team-lead), l-a corectat si scris in binar
inainte sa primeasca mesajul meu. Verificat direct pe disc de acest agent (nu doar preluat
din raportarea lui d42-efactura): git diff pe COMUN\clase\omodificari.vc2 arata
This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact,0)), iar git diff pe
COMUN\programe\ofacturare_editare.prg arata v.id_fact adaugat in SELECT-ul din
IncarcaVanzareNota si id_fact I NULL adaugat in schema CREATE CURSOR tvanz din
CreeazaCursorTvanzGol — exact varianta B recomandata la §8. Bugul e inchis, nu mai necesita
actiune.
Legat de linia necomisa gasita atunci in ROAGEST\Programe\roagest.prg
(SET PROCEDURE TO ofacturare_editare.prg ADDITIVE, "Not Committed Yet" la 10.08.2026 11:28):
d42-efactura confirma ca nu e a lui — a atins doar omodificari.vc2 si ofacturare_editare.prg
(plus fisiere de test noi). Ramane deci dintr-un alt bloc de lucru (posibil S9), de verificat separat
de team-lead — nu descrie starea lui d42-efactura.
1. Cum se afla ca documentul e in eFactura
Functie: FUNCTION EsteInEFactura, globala (nu metoda de clasa), definita in
COMUN\programe\ofacturare_editare.prg:16-25:
*!* parametru: id_fact
*!* verifica daca factura cu id_fact dat a fost deja trimisa in eFactura (anaf_efactura)
FUNCTION EsteInEFactura
LPARAMETERS tnIdFact
LOCAL lcSql, lnEFactura, llSucces
lnEFactura = 0
lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + Alltrim(Str(Nvl(m.tnIdFact,0)))
llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @lnEFactura)
RETURN (Nvl(m.lnEFactura,0) > 0)
ENDFUNC
Contract, deschis din RETURN: primeste tnIdFact — ID_FACT, nu ID_VANZARE — si intoarce
.T./.F. (numar de randuri in ANAF_EFACTURA cu acel id_fact > 0). Foloseste goExecutor
(disponibil global, aceeasi conventie ca restul aplicatiei).
Disponibilitate cross-project — VERIFICAT, nu presupus: ofacturare_editare.prg e inregistrat
prin SET PROCEDURE ... ADDITIVE in toate cele trei aplicatii:
| App | Fisier | Linie | Stare git |
|---|---|---|---|
| ROAFACTURARE | Programe\roafacturare.prg |
214 | comis demult |
| ROACONT | Programe\roacont.prg |
212 | comis, 3af0089 (08.08.2026) — mesaj: "Fara el, pagina de articole ale facturii nu apare in registrul jurnal > modificare" |
| ROAGEST | Programe\roagest.prg |
260 | necomis, adaugat azi 10.08.2026 (vezi avertismentul de mai sus) |
Deci EsteInEFactura este apelabila din contextul omodificari.vc2, inclusiv din ROACONT si
(dupa commit-ul in curs) ROAGEST. Comentariul din omodificari.vc2:14786-14787 ("apare doar cand
ofacturare_editare.prg e incarcat (doar ROAFACTURARE - ROACONT/ROAGEST nu-l inregistreaza)") e
invechit — scris inainte de commit-ul 3af0089, care a inversat exact aceasta premisa pentru
ROACONT. Nu se corecteaza comentariul in acest raport (read-only), dar oricine implementeaza ar
trebui sa-l actualizeze cand atinge zona.
BUG GASIT in diff-ul in lucru — id_fact confundat cu id_vanzare. Apelul din
omodificari.vc2:14798 (diff necomis) e:
This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
dar This.nIdVanzare e populat cu tvanz.id_vanzare (linia 14796), adica VANZARI.ID_VANZARE —
alt camp decat VANZARI.ID_FACT, pe care EsteInEFactura il asteapta. Dovada, in trei straturi:
- Cod: precedentul functional existent,
ofacturare_comun.vc2:3739(lnIdFact = id_fact) si:3764(EsteInEFactura(lnIdFact)), citesteid_factdintr-un camp separat deid_vanzare(:3734,lnIdVanzare = id_vanzare, aceeasi cursorcrsfacturi, doua LOCAL-uri distincte). Acelasi tipar inanaf_efactura.prg:3123-3124:pnIdFact = id_factsilnIdVanzare = id_vanzarecitite pe acelasi rand dincrsFacturiEmise— daca ar fi acelasi numar, codul n-ar avea nevoie de doua variabile. - Schema Oracle (verificat read-only,
user_tab_columns,MARIUSM_AUTO):VANZARIare ambele coloane,ID_FACTsiID_VANZARE, distincte;ANAF_EFACTURAare doarID_FACT. - Date reale (verificat read-only, join
anaf_efactura.id_fact = vanzari.id_fact): pentru documentele deja trimise in eFactura, cele doua valori difera constant —id_fact id_vanzare cod numar_act data_act 8008013 1013 1140509 510 31-AUG-25 8007922 1007 1140439 503 03-JAN-25 8007836 993 1140380 490 15-AUG-24 8007810 991 1140369 488 11-JUL-24
Cu bug-ul curent, EsteInEFactura(1013) cauta id_fact = 1013 in ANAF_EFACTURA — care nu exista
cu acel numar — deci intoarce mereu .F., chiar si pentru documente reale trimise in eFactura.
Garda ar fi complet inoperanta pe date reale. Corectia: §8.
Niciun document dintre cele patru de mai sus nu e din luna curenta (limitare de date deja cunoscuta
din bloc — garda de editare cere luna curenta), deci un test headless pe un caz real din productie
de date nu se poate face acum; testul trebuie sa foloseasca un cursor tact/tvanz mock cu
id_fact setat manual (acelasi tipar folosit deja pentru id_vanzare_set in S5).
2. Unde se aseaza conditia in omodificari.vc2
Locul folosit deja de diff-ul in lucru e corect si e cel recomandat: frm_modific2024.Show()
(omodificari.vc2:14748-14837 in varianta comisa 1c42ae0; extins la 14748-14856 in diff-ul
necomis), imediat dupa blocul care rezolva This.nIdVanzare/This.nTipVanzare prin
IncarcaVanzareDinNota('tact') si inainte de This.pgfArticole.PageCount = 3. E punctul unde
formularul stie deja daca documentul curent are rand in VANZARI (This.lAreArticoleVanzari) —
conditia eFactura se agata direct pe acest rezultat, fara sa duplice logica de potrivire
cod/nract/serie_act/dataact -> id_vanzare.
Proprietatea noua, lArticoleReadOnly (declarata la nivelul clasei, langa lAreArticoleVanzari,
omodificari.vc2:6827 si 6867 in diff), e citita apoi din .When-urile coloanelor editabile ale
gridului grdArticoleFactura (mecanismul de editabilitate per rand din S5, §3-4) — deci conditia
de formular compune cu mecanismul existent, nu-l inlocuieste.
3. Controale care se dezactiveaza — confirmate pe cod
| Control | Path | Linii (comis) | Ce face diff-ul |
|---|---|---|---|
| Buton adaugare | pgfArticole.PAGE3.cmdAdaugaArticol |
Click: 16488-16529 |
.Enabled = !This.lArticoleReadOnly la afisare (Show); plus guard OR Thisform.lArticoleReadOnly in Click (aparare in adancime, cazul Enabled sarit programatic) |
| Buton stergere | pgfArticole.PAGE3.cmdStergeArticol |
Click: 16531-16540 |
idem |
| Cantitate | grdArticoleFactura.cCantitateArt.Text1.When |
16549-16554 |
adauga Thisform.lArticoleReadOnly OR in fata conditiei existente Nvl(tvd.id_vanzare_set,0)<>0 |
| Pret achizitie | grdArticoleFactura.cPretAchizitieArt.Text1.When |
16556-16561 |
idem |
| Pret | grdArticoleFactura.cPretArt.Text1.When |
16570-16575 |
idem |
| Pret cu TVA (checkbox) | grdArticoleFactura.cPretCuTvaArt._checkbox1.When |
16587-16589 |
RETURN !Thisform.lArticoleReadOnly AND ... |
| Discount | pgfArticole.PAGE3.txtDiscountArt |
— | neatins in diff — vezi nota de mai jos |
Gol observat: txtDiscountArt (discountul pe factura, cu ControlSource = tvanz.discount) nu
are .When si nu apare in diff. Daca discountul e considerat parte din "articolele facturii" in
sensul Deciziei 42 (afecteaza totalul liniilor), ramane editabil dupa trimiterea in eFactura — de
clarificat cu Marius sau de inclus explicit. Nu era in lista cmdAdaugaArticol/cmdStergeArticol
ceruta explicit in brief, deci il semnalez ca gol, nu-l tratez ca bug.
4. Tipar read-only pe grid, folosit deja in proiect
Nu se inventeaza un tipar nou. Proiectul (din S5) foloseste deja exact acest idiom pentru randurile
needitabile (liniile din seturi, id_vanzare_set <> 0): fiecare coloana editabila a gridului are
un handler .When care intoarce .F. cand conditia de blocare e adevarata — VFP nu lasa controlul
sa intre in editare daca .When intoarce .F.. Diff-ul in lucru extinde exact aceste .When-uri
existente, adaugand Thisform.lArticoleReadOnly OR in fata conditiei deja acolo — e continuarea
directa a mecanismului S5, nu un tipar paralel. Confirma cererea din brief: "foloseste tiparul deja
folosit in proiect, nu inventa unul nou" — respectat.
5. Feedback vizual pentru utilizator
Diff-ul adauga o eticheta noua, pgfArticole.PAGE3.lblArticoleReadOnly
(omodificari.vc2:12857-12871 in diff), cu Caption = "Articole needitabile - factura trimisa in eFactura", Visible legat de This.lArticoleReadOnly in Show(). E minimul cerut de brief —
niciun tipar de marcaj standard read-only nu exista deja in proiect (nu s-a gasit unul in cautarea
pentru §4), deci eticheta simpla e alegerea rezonabila. Singura observatie: eticheta e pozitionata
Top = 4, Left = 360 — de verificat pe ecran (fara VFP IDE nu se poate confirma vizual) ca nu se
suprapune cu alt control din PAGE3 la latimile de forma folosite azi.
6. Suprafata de regresie — de ce notele obisnuite din registrul jurnal nu sunt atinse
Blocul care calculeaza lArticoleReadOnly ruleaza doar in interiorul conditiei deja existente:
IF "OFACTURARE_EDITARE" $ Upper(Set("Procedure")) AND Reccount('tact') > 0
IncarcaVanzareDinNota('tact')
IF Reccount('tvanz') = 1
This.lAreArticoleVanzari = .T.
...
This.lArticoleReadOnly = EsteInEFactura(...)
ENDIF
ENDIF
IncarcaVanzareDinNota cauta in VANZARI un rand cu tripletul (cod, nract, serie_act, dataact) al
notei curente. Pentru o nota contabila obisnuita (nu factura de vanzare), acest rand nu exista,
Reccount('tvanz') ramane 0, deci intreg blocul IF Reccount('tvanz') = 1 e sarit —
This.lAreArticoleVanzari ramane .F. si This.lArticoleReadOnly ramane la valoarea implicita
.F. (setata explicit chiar inainte de bloc, :14791). Consecinta directa: This.pgfArticole.PageCount = 2 (fara PAGE3), deci cmdAdaugaArticol/cmdStergeArticol/gridul de articole nici nu exista
pentru documentul respectiv — nu doar ca nu sunt dezactivate, ci nu sunt instantiate in fluxul de
afisare. Riscul de regresie pe notele obisnuite din ROAGEST/ROACONT e deci zero prin constructie,
mostenit din gating-ul lAreArticoleVanzari deja livrat si testat in S4/S5 — Decizia 42 doar adauga
o conditie suplimentara in interiorul ramurii deja izolate pentru facturi de vanzare, nu schimba
gating-ul insusi. Acesta e exact argumentul cerut in brief la punctul 6, si e verificabil citind
codul, nu presupus.
comun.vc2 (clasa afisjurcom, do_modifica, 2222-2572) nu e atins de acest diff — ramane
neschimbat, confirmand ca intreaga logica sta in omodificari.vc2, un singur punct de intretinere.
7. Teste minime propuse (headless, in stilul suitei existente)
Suita COMUN\utile\Teste\editare_factura\ foloseste harness-ul ui_harness.prg + asserteaza, cu
formular vizibil (WindowType = 0, Show(), DOEVENTS FORCE), fara input real (nici un
keybd_event/SendInput — doar citire directa de proprietati si apel direct de metode). Propunere,
dupa modelul test_ui_sterge_linie.prg:
test_d42_efactura_readonly.prg — cazul pozitiv, cu date mock (nu exista document real din
luna curenta trimis in eFactura, cf. §1):
- Incarca
tact/tvdpentru un document real din luna curenta culAreArticoleVanzari = .T.(ex. acelasiid_vanzare = 1049mentionat inhandoff_punct6_dupa_s5.md, daca inca in luna curenta la momentul rularii). - Dupa
IncarcaVanzareDinNota, forteazatvanz.id_fact(sautact.id_fact, dupa care varianta se alege in §8) la o valoare stiuta ca exista inANAF_EFACTURA(mock:INSERTintr-un cursor local, nu in Oracle) — sau, mai simplu, mock-uieste directEsteInEFacturaprinSET PROCEDURE/redefinire temporara, dupa tiparul deja folosit in proiect pentru izolarea de Oracle in teste UI. assert:loForm.lArticoleReadOnly = .T.assert:loForm.pgfArticole.PAGE3.cmdAdaugaArticol.Enabled = .F.assert:loForm.pgfArticole.PAGE3.cmdStergeArticol.Enabled = .F.assert:loForm.pgfArticole.PAGE3.lblArticoleReadOnly.Visible = .T.assert: grid-ul e in continuare vizibil si populat —loForm.pgfArticole.PageCount = 3,Reccount('tvd') > 0— confirma partea corectata a deciziei (nu se suprima pagina).assert: pozitionare pegrdArticoleFactura,SetFocuspe coloanacCantitateArtnu intra in editare — verificat prin apelul direct al handlerului.When(loForm.pgfArticole.PAGE3. grdArticoleFactura.cCantitateArt.Text1.When()trebuie sa intoarca.F.), nu prin tastare.
test_d42_efactura_editabil.prg — cazul negativ (control): acelasi document, dar
EsteInEFactura mock-uit sa intoarca .F. -> toate assert-urile de mai sus inversate (Enabled = .T., .When() nu intoarce .F. din cauza flagului — poate intoarce .F. din alt motiv, ex.
id_vanzare_set, testat separat).
test_d42_nota_obisnuita_neatinsa.prg — cazul de regresie cerut la §6: incarca o nota
contabila fara corespondent in VANZARI (orice test existent din COMUN\utile\Teste\ care nu tine
de facturare), verifica loForm.pgfArticole.PageCount = 2 si ca lArticoleReadOnly ramane .F.
fara sa fi fost nevoie sa se apeleze EsteInEFactura deloc (se poate confirma indirect, verificand
ca nu s-a facut nicio interogare Oracle suplimentara, sau direct daca se mock-uieste functia cu un
contor de apeluri).
Toate cele trei suite: fara scriere in Oracle, QUIT la final, log langa .prg cu acelasi nume +
_log.txt, conform conventiei din handoff_punct6_dupa_s5.md.
8. Schita de diff — corectia necesara peste diff-ul in lucru
Doua variante, cu recomandare pentru B.
Varianta A — minima, refoloseste id_fact deja prezent pe cursorul tact (confirmat: tact
vine din view-ul vact_tot, care are coloana id_fact, folosita deja in ofacturare_comun.vc2:3776
ca Locate For Nvl(id_fact, 0) = lnIdFact pe acelasi cursor actactan/tact):
--- a/COMUN/clase/omodificari.vc2
+++ b/COMUN/clase/omodificari.vc2
@@ frm_modific2024.Show
This.nIdVanzare = tvanz.id_vanzare
This.nTipVanzare = tvanz.tip
- This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
+ This.lArticoleReadOnly = EsteInEFactura(Nvl(tact.id_fact, 0))
Risc al variantei A: presupune ca recordul curent din tact (la momentul Show(), imediat dupa
incarcare, deci pe Top) are id_fact valid pentru documentul gasit — valabil in cazul normal, dar
nu la fel de robust ca precedentul din ofacturare_comun.vc2:3775-3783, care cauta explicit randul
cu id_fact potrivit inainte sa cada pe fallback (Go Top).
Varianta B — recomandata, aduce id_fact chiar pe tvanz (randul din VANZARI deja gasit prin
tripletul cod/nract/serie_act/dataact), simetric cu id_vanzare:
--- a/COMUN/programe/ofacturare_editare.prg
+++ b/COMUN/programe/ofacturare_editare.prg
@@ CreeazaCursorTvanzGol
- CREATE CURSOR tvanz (id_vanzare I, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2), curs N(10,4), multiplicator N(10,4), ;
+ CREATE CURSOR tvanz (id_vanzare I, id_fact I NULL, tip I, discount N(12,2), total_fara_tva N(14,2), total_tva N(14,2), total_cu_tva N(14,2), curs N(10,4), multiplicator N(10,4), ;
in_valuta I NULL, id_valuta I NULL, nume_val C(20) NULL)
@@ IncarcaVanzareNota
- lcSql = [select v.id_vanzare, v.tip, v.discount, v.total_fara_tva, v.total_tva, v.total_cu_tva, v.curs, v.multiplicator, ] + ;
+ lcSql = [select v.id_vanzare, v.id_fact, v.tip, v.discount, v.total_fara_tva, v.total_tva, v.total_cu_tva, v.curs, v.multiplicator, ] + ;
[v.in_valuta, v.id_valuta, nv.nume_val from vanzari v left join nom_valute nv on nv.id_valuta = v.id_valuta where v.cod = ] + Transform(m.tnCod) + ;
--- a/COMUN/clase/omodificari.vc2
+++ b/COMUN/clase/omodificari.vc2
@@ frm_modific2024.Show
This.nIdVanzare = tvanz.id_vanzare
This.nTipVanzare = tvanz.tip
- This.lArticoleReadOnly = EsteInEFactura(This.nIdVanzare)
+ This.lArticoleReadOnly = EsteInEFactura(Nvl(tvanz.id_fact, 0))
Varianta B e mai robusta pentru ca foloseste VANZARI.ID_FACT direct — exact coloana pe care
ANAF_EFACTURA o are ca cheie (verificat pe schema Oracle, §1) — fara sa depinda de pozitia
curenta a cursorului tact. Costul: doua fisiere in loc de unul (ofacturare_editare.prg +
omodificari.vc2), plus verificarea ca select v.id_fact nu produce eroare Oracle daca vreun rand
vechi din VANZARI are id_fact NULL (coloana e deja NULL-abila judecand dupa restul cursorului,
in_valuta I NULL etc., deci nu ar trebui sa fie o problema).
Neschimbat, corect asa cum e: restul diff-ului (.When-urile pe grid, cmdAdaugaArticol/
cmdStergeArticol.Enabled, eticheta lblArticoleReadOnly) — vezi §2-5.
Rezumat pentru implementare
- Diff-ul lui
d42-efactura(necomis la momentul acestui raport, inCOMUN\clase\omodificari.vc2COMUN\programe\ofacturare_editare.prg) e structural corect — locul (§2), controalele (§3), tiparul de grid (§4) si feedback-ul (§5) respecta cerintele Deciziei 42 corectate.
- Bug gasit, dovedit pe schema si date, si INCHIS:
EsteInEFactura(This.nIdVanzare)trebuia sa foloseascaid_fact, nuid_vanzare—d42-efactural-a gasit independent si l-a corectat cu exact varianta B din §8 (EsteInEFactura(Nvl(tvanz.id_fact,0))), verificat pe disc de acest agent dupa corectie. Nu mai necesita nicio actiune. - Gol de clarificat, nu bug:
txtDiscountArtramane editabil dupa eFactura — de decis cu Marius daca discountul intra sub "articole" (§3). Confirmat si ded42-efacturaca gol cunoscut, in afara scope-ului primit de la team-lead. - Comentariul din
omodificari.vc2:14786-14787("ROACONT/ROAGEST nu-l inregistreaza") e invechit de la commit-ul3af0089— de actualizat cand se atinge zona (§1). - Teste propuse in §7, aliniate stilistic cu suita existenta — de confirmat cu
d42-efacturadaca au fost deja scrise (mesajul lui mentioneaza "doua fisiere noi de test"). ROAGEST\Programe\roagest.prg(linia necomisaSET PROCEDURE TO ofacturare_editare.prg) nu apartine luid42-efactura— ramane dintr-un alt bloc de lucru, de identificat separat de team-lead.