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
12 KiB
S4b etapa 1 - contractul ConstruiestePropunereSincronizare/AplicaSincronizareArticole
Implementare, nu doar proiectare. Cod nou exclusiv in COMUN\programe\ofacturare_editare.prg (dupa
ScrieArticoleFacturaEditate). Niciun .vc2 atins - formularul si dialogul raman etapa 2, a altui
agent. Baza: docs\propunere_s4b_sincronizare.md (proiectarea aprobata, punctele 2 si 4) si
docs\cercetare\rec_suma_act.md E.3 (formula de agregare RUL, reutilizata neschimbata).
Functii noi (publice, apelabile din etapa 2)
ConstruiestePropunereSincronizare(tcDirectie)
Parametru: tcDirectie - accepta exact doua valori, 'RUL_SURSA' (rulajul e sursa, actualizeaza
articolele facturii) sau 'ARTICOLE_SURSA' (articolele sunt sursa, actualizeaza rulajul). Orice alta
valoare (inclusiv goala) cade pe 'RUL_SURSA' - e implicit-ul recomandat de Marius (docs\handoff_ punct6_10082026_seara.md, decizia 4).
Lasa deschis, READWRITE, cursorul propunere_sincronizare:
| camp | tip | continut |
|---|---|---|
id_articol |
I | cheia de matching (singura comuna intre trul/tvd) |
denumire |
C(100) | preferata din tvd daca articolul exista acolo, altfel din trul |
codmat |
C(30) | idem |
cantitate_veche |
N(12,3) | valoarea curenta din cursorul-tinta |
cantitate_noua |
N(12,3) | valoarea calculata din cursorul-sursa |
pret_vechi |
N(14,4) | idem, pret unitar cu TVA |
pret_nou |
N(14,4) | idem |
actiune |
C(12) | Modificare / Adaugare / Semnalare / N-A |
motiv |
C(80) | populat pe N-A/Semnalare, si pe Adaugare in ARTICOLE_SURSA |
Articolele identice intre sursa si tinta nu apar in cursor (fara zgomot, ca in propunere.md).
Retur logic: .F. doar cand tvd/trul nu sunt ambele deschise la apel (cursorul iese oricum creat,
gol) - restul cazurilor (0 articole, document fara diferente) intorc .T. cu cursorul gol sau partial.
Agregarea, per id_articol, separat pe trul si pe tvd, doar randuri Nvl(sters,0)<>1:
- RUL:
cant_articol = SUM(cant) + SUM(IIF(id_tip_rulaj<>3, cante, 0)),val_articol = SUM(cant*pretvtva) + SUM(IIF(id_tip_rulaj<>3, cante*pretvtva, 0))(formula E.3 neschimbata),pret_articol = val_articol/cant_articol. - tvd:
cant_articol = SUM(cantitate),val_articol = SUM(valoare)(coloanatvd.valoare, deja calculata cu TVA la incarcare/editare - citita, nu recalculata -IncarcaArticoleFactura,ofacturare_editare.prg:318-320, e chiar in acest fisier),pret_articol = val_articol/cant_articol.
Actiune, in ordinea exacta de verificare (prima conditie adevarata castiga):
- Documentul e in valuta (
tvanz.in_valuta<>0, candtvanze deschis cu un rand) ->N-Ape toate articolele, indiferent de restul. Decizie luata in aceasta implementare, nu era in propunere.md: conversia RON<->valuta intretrul.pretvtva(presupus RON) sitvd.pret(in valuta documentului cand documentul e in valuta) nu a fost verificata pe date reale in bugetul alocat - mai sigur sa semnalez decat sa scriu o suma gresita. Fara aceasta garda, restul logicii (agregare, matching, Modificare/Adaugare/Semnalare) e neschimbata pe documente RON. - Mai multe randuri RUL active pe acelasi articol (
nrand_rul>1) ->N-A, chiar daca agregatul ar fi identic cu tinta (verificat explicit in test, caz A6: o perecheid_tip_rulaj=3a carei sume egaleaza exacttvd, tot N-A) - decizia lui Marius/propunere.md punctul 6, generalizata la ambele directii (nu doar la aplicare, ca in propunere.md sectiunea 4 - vezi "Diferente fata de propunere" mai jos). - Articol nestocat (
tvd.in_stoc=0, doar cand articolul exista intvd) ->N-A. - Doar in sursa ->
Adaugare. - Doar in tinta ->
Semnalare(niciodata stergere automata). - In ambele, diferit ->
Modificare; identic -> nu apare in cursor.
AplicaSincronizareArticole(tcDirectie, toForm)
Parametru nou fata de brief: toForm, opus (contractul descris mai jos, punctul "Ce ramane pe
seama etapei 2"). Reconstruieste propunerea (apeleaza ConstruiestePropunereSincronizare intern -
etapa 2 nu trebuie sa o apeleze separat inainte) si aplica tot ce nu e N-A/Semnalare - deci
Modificare + Adaugare, decizia lui Marius ("fara selectie pe linie"). Niciun INSERT/UPDATE
Oracle - doar tvd/trul in memorie.
Retur numeric: cate linii au fost efectiv aplicate (nu cate erau in propunere) - formularul il foloseste ca sa stie daca sa reactualizeze bara de totaluri/gridul.
RUL_SURSA:Modificare->REPLACE tvd.cantitate/pret/discount_unitarpe primul rand activ gasit pe articol, pastrandpret_cu_tvaexistent pe rand (pretul propus, mereu cu TVA per E.3, se converteste la fara-TVA prin/proc_tvavdaca randul era asa) - decizie luata acum, nu era in propunere.md (care zicea doar "REPLACE ... pret_cu_tva WITH ..." fara sa spuna cu ce): am ales sa NU schimb convenția per-rand, ca sa nu inversez brusc semnificatia unei coloane pe care utilizatorul a vazut-o intr-un fel;Adaugare->toForm.AdaugaLinieTvdDinArticol(), cu obiectul construit dinCreeazaPoArticolNouTvd(tiparul cerut de brief), suprascris cu cantitate/pret din RUL,preturi_cu_tva=1(linie noua, fara conventie de pastrat),cont/id_gestiune/proc_tvavdin randul RUL al articolului.ARTICOLE_SURSA:Modificare->REPLACEdoarcantsaucante(dupa care era deja populat pe rand - verificat in test, caz C1) sipretvtva, pe singurul rand RUL activ (garantat unic, altfel propunerea a marcat N-A la pasul 2). Nu atingeid_tip_rulaj/conturi/campuri derivate (valoare/tva/etc.) - raman de recalculat de apelant daca e nevoie, in afara scopului acestei livrari.Adaugare-> nu se aplica niciodata (niciun rand RUL nou, decizia din propunere.md punctul 5.B).
Ce ramane pe seama etapei 2 - contractul lui toForm
Am ales varianta "primesc obiectul formular ca parametru", nu "duplic tiparul separat". Fara
toForm (sau un obiect care nu implementeaza metodele), AplicaSincronizareArticole tot face
REPLACE-ul de baza pe tvd pentru Modificare (verificat in test, caz B2), dar:
- nu recalculeaza
tvd.valoare(ramane cea veche pana la un recalcul extern); - nu cheama
ActualizeazaBaraTotaluri; - sare complet liniile
Adaugare(faratoForm.AdaugaLinieTvdDinArticol, nu exista alta cale sa adauge linia fara sa duplice acel helper).
Deci etapa 2 (butonul/dialogul din PAGE3) trebuie sa apeleze AplicaSincronizareArticole(tcDirectie, Thisform), cu Thisform fiind instanta frm_modific2024 deja incarcata (are ambele metode:
calculeaza_valori_articol, AdaugaLinieTvdDinArticol). Contractul verificat prin Pemstatus(), nu
presupus - un obiect fara aceste metode e tratat exact ca "fara toForm".
Diferente fata de propunere_s4b_sincronizare.md - de confirmat cu Marius/etapa 2
- Documentele in valuta sunt N-A pe tot (mai sus, punctul 1 al ordinii de actiune) - propunere.md
nu mentiona deloc valuta pentru S4b. Scop deliberat restrans: fara o verificare pe un document real
in valuta CU randuri RUL, nu am vrut sa livrez o conversie neverificata. Daca Marius vrea si
documentele in valuta acoperite, e nevoie de o cercetare separata (confirmarea daca
trul.pretvtvae RON sau in valuta proprie a randului RUL -VRUL_TOTare propriileCURS/ID_VALUTAper rand, verificat prinDESCRIBE, dar nu s-a confirmat ce inseamna practic pentruPRETVTVA). - "Mai multe randuri RUL active" e N-A in ambele directii, la nivelul propunerii (nu doar la
aplicarea
ARTICOLE_SURSA, cum sugera propunere.md sectiunea 4) - generalizare ceruta explicit de briefing-ul acestei sarcini ("niciodata alegere automata a randului", listat ca regula aConstruiestePropunereSincronizare, nu doar a aplicarii). Efect: pe un document cu perechiid_tip_rulaj=3(diferenta de pret la marfa/produse la pret de vanzare,rec_suma_act.mdE.1), articolul respectiv rama mereu N-A, chiar daca suma agregata (E.3) ar fi corecta si identica - propunerea nu ofera Modificare/Adaugare automata pe acele articole, doar afisare informativa. tvdcu mai multe randuri active pe acelasi articol nu are o garda separata -AplicaModificare Tvdscrie pe primul rand activ gasit. Cazul e rar (articol adaugat de doua ori manual pe aceeasi factura) si n-a fost cerut explicit in briefing; il semnalez ca limitare cunoscuta, nu l-am tratat ca sa nu extind scopul peste ce s-a cerut.
Teste
COMUN\utile\Teste\editare_factura\test_s4b_sincronizare.prg, model test_s5_validari_articole.prg.
Complet headless, fara Oracle - nici ConstruiestePropunereSincronizare, nici
AplicaSincronizareArticole nu ating goExecutor, deci testul nu are nevoie de test_init_env_auto/
conexiune - doar SET PROCEDURE TO ofacturare_editare.prg si gnPC setat manual. tvd/trul sunt
construite direct in test (helpere AdaugaTvd/AdaugaTrul); trul e o structura minimala (doar
campurile citite de cod), nu cele 218 coloane reale ale VRUL_TOT.
Cazuri acoperite (sectiunea A - ConstruiestePropunereSincronizare, cate un caz pe ambele directii
unde se aplica): identic (A1), modificare cu valori inversate corect intre directii (A2), doar-in-
sursa/doar-in-tinta -> Adaugare/Semnalare cu roluri schimbate intre directii (A3/A4), articol nestocat
(A5), mai multe randuri RUL active - N-A chiar cand agregatul ar fi identic (A6), randuri sters
excluse din agregare pe ambele cursoare (A7), document in valuta -> N-A pe tot (A8), tvd/trul lipsa la
apel (A9). Sectiunea B (AplicaSincronizareArticole, RUL_SURSA): aplicare completa cu toForm
(Modificare + Adaugare, verificate valorile scrise in tvd si apelurile pe test-double, semnalare/N-A
neatinse - B1), fara toForm (Adaugare sarita fara eroare, Modificare tot se aplica - B2),
pastrarea conventiei pret_cu_tva=0 cu conversia pretului propus (B3). Sectiunea C
(AplicaSincronizareArticole, ARTICOLE_SURSA): cant vs cante pastrat dupa care era populat pe
rand, Adaugare niciodata scrisa in trul (C1).
test-double-ul dummyform (definit la finalul fisierului, tipar identic cu dummyexecutor din
test_s5_validari_articole.prg) oglindeste EXACT formula din calculeaza_valori_articol/
AdaugaLinieTvdDinArticol - verifica ca AplicaSincronizareArticole cheama metodele corecte cu
argumentele corecte, fara sa deschida formularul real sau sa atinga vreun .vc2.
Capcana gasita si reparata in acest bloc: comparatii == intre un camp Character de latime
fixa (actiune, C(12)) si un literal mai scurt ('Modificare') esueaza mereu din cauza spatiilor de
umplere din dreapta - VFP == e comparatie stricta, nu trece prin SET EXACT. Aparea atat in codul
de productie (AplicaSincronizareArticole, filtrul SCAN FOR Inlist(actiune,...) si DO CASE), cat
si in asertiunile testului. Reparat cu Alltrim() pe partea citita din camp, in ambele fisiere.
Cifra din log (test_s4b_sincronizare_log.txt, rulare vfp9.exe -A -T):
REZULTAT: 35 PASS / 0 FAIL
Toate testate (headless, cursoare construite in test) - niciun caz "doar analizat static". Nu s-a verificat pe un document real din Oracle (nu era ceruta si nici necesara pentru logica pura), si nici comportamentul pe un document real in valuta (vezi punctul 1 din "Diferente fata de propunere" - scop restrans deliberat).
Ce lipseste pentru punctul #6 complet (etapa 2, alt agent)
- Butonul
cmdSincronizeazaArticolein PAGE3 si toggle-ul deEnabledinShow()(omodificari.vc2, punctul 1 din propunere.md). - Dialogul modal
frm_sincronizare_articole(radio pe directie, grid needitabil pepropunere_sincronizare, Aplica/Renunta) - punctele 2-3 din propunere.md. - Verificarea la salvare (
inainte_de_do_termin) care ofera enumerarea si permite salvarea mai departe fara sincronizare - decizia 2 a lui Marius (docs\handoff_punct6_10082026_seara.md). - Apelul
AplicaSincronizareArticole(tcDirectie, Thisform)din dialog, la "Aplica", si reactualizarea gridului/barei de totaluri folosind numarul de linii aplicate intors.