Files
roafacturare/docs/cercetare/rec_s4b_etapa1.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

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) (coloana tvd.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):

  1. Documentul e in valuta (tvanz.in_valuta<>0, cand tvanz e deschis cu un rand) -> N-A pe toate articolele, indiferent de restul. Decizie luata in aceasta implementare, nu era in propunere.md: conversia RON<->valuta intre trul.pretvtva (presupus RON) si tvd.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.
  2. 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 pereche id_tip_rulaj=3 a carei sume egaleaza exact tvd, 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).
  3. Articol nestocat (tvd.in_stoc=0, doar cand articolul exista in tvd) -> N-A.
  4. Doar in sursa -> Adaugare.
  5. Doar in tinta -> Semnalare (niciodata stergere automata).
  6. 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_unitar pe primul rand activ gasit pe articol, pastrand pret_cu_tva existent pe rand (pretul propus, mereu cu TVA per E.3, se converteste la fara-TVA prin /proc_tvav daca 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 din CreeazaPoArticolNouTvd (tiparul cerut de brief), suprascris cu cantitate/pret din RUL, preturi_cu_tva=1 (linie noua, fara conventie de pastrat), cont/id_gestiune/proc_tvav din randul RUL al articolului.
  • ARTICOLE_SURSA: Modificare -> REPLACE doar cant sau cante (dupa care era deja populat pe rand - verificat in test, caz C1) si pretvtva, pe singurul rand RUL activ (garantat unic, altfel propunerea a marcat N-A la pasul 2). Nu atinge id_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 (fara toForm.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

  1. 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.pretvtva e RON sau in valuta proprie a randului RUL - VRUL_TOT are propriile CURS/ID_VALUTA per rand, verificat prin DESCRIBE, dar nu s-a confirmat ce inseamna practic pentru PRETVTVA).
  2. "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 a ConstruiestePropunereSincronizare, nu doar a aplicarii). Efect: pe un document cu perechi id_tip_rulaj=3 (diferenta de pret la marfa/produse la pret de vanzare, rec_suma_act.md E.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.
  3. tvd cu mai multe randuri active pe acelasi articol nu are o garda separata - AplicaModificare Tvd scrie 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)

  1. Butonul cmdSincronizeazaArticole in PAGE3 si toggle-ul de Enabled in Show() (omodificari.vc2, punctul 1 din propunere.md).
  2. Dialogul modal frm_sincronizare_articole (radio pe directie, grid needitabil pe propunere_sincronizare, Aplica/Renunta) - punctele 2-3 din propunere.md.
  3. 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).
  4. Apelul AplicaSincronizareArticole(tcDirectie, Thisform) din dialog, la "Aplica", si reactualizarea gridului/barei de totaluri folosind numarul de linii aplicate intors.