Files
roafacturare/docs/propunere_s4b_sincronizare.md
Marius Mutu b5a7108f34 docs: cercetarile comune trec in COMUN, reziduul #6 dispare, progres.md la zi
Curatenie ceruta dupa inchiderea lui #6. Folderul cercetare\ NU se putea sterge
in bloc: plan_13 se sprijina pe el cu 85 de trimiteri, deci e baza de dovezi a
planului aflat in lucru. Impartirea:

- 14 cercetari trans-proiect trec in COMUN\docs\cercetare\ - valuta si curs,
  TVA/VANZARI, consumatorii VANZARI din toata suita, integrarile #10/#11/#12,
  watchdog VFP, proiectarea Oracle a lui S5, view-ul VVANZARI_ARTICOLE. Nu sunt
  ale ROAFACTURARE, iar #10/#11/#12 se reiau chiar din ele.
- 20 de rapoarte de executie ale lui #6, nereferite de nimic viu, sterse.
- 91 raman, neatinse.

Trimiterile catre handoff-urile si diff-urile intermediare deja desfiintate au
fost curatate peste tot (39 de fisiere): 50 catre handoff-uri, 37 catre diff-uri
aplicate, plus caile celor mutate in COMUN. Zero trimiteri rupte ramase.

progres.md preia rolul de predare: ce ramane din #6 (cele sase documente
parazite, cele doua esecuri reale din S8 pe factura din aviz), cifrele de test
citite din log, si cele doua capcane de mediu platite - .FXP vechi executat in
locul .prg-ului, si GETFONT() care atarna un formular instantiat fara goApp.

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

14 KiB

Propunere S4b — actiunea explicita de sincronizare RUL <-> articole factura

Document de proiectare, nu implementare. Niciun .vc2/.prg nu a fost modificat. Cerinta sursa: docs\plan_06_editare_factura.md:208-231. Context: handoff intermediar (sters) (sectiunea „S4b — ce e facut si ce lipseste"), handoff intermediar (sters).

Corectie fata de predarea anterioara — nu e nevoie de cursor de instantaneu

docs\cercetare\rec_s5_cale_scriere_vfp.md 2.3 propunea un cursor tvd_initial, luat imediat dupa IncarcaArticoleFactura, ca solutie la blocajul „tvd nu pastreaza valorile de dinainte de editare". Verificat pe cod si pe plan: acea propunere rezolva o alta problema — istoricul editarilor utilizatorului in aceeasi sesiune (cat a schimbat el insusi o cantitate) — nu ce cere literal S4b.

Planul spune explicit: „preturile si cantitatile din rulaje si cele din articolele facturii se pot desincroniza la editare" (plan_06_editare_factura.md:209-210) — deci comparatia ceruta e intre trul (rulaje) si tvd (articole), doua reprezentari independente ale aceluiasi document, editabile separat in acelasi formular (PAGE1 vs PAGE3). Nu e nevoie de niciun instantaneu: „vechi" = valoarea curenta din cursorul-tinta (ce s-ar salva daca utilizatorul apasa Salveaza acum, fara sincronizare), „nou" = valoarea calculata din cursorul- sursa. Ambele cursoare sunt deja rezidente si populate cand utilizatorul ajunge pe PAGE3 — comparatia se face live, nu din istoric.

Confirmare suplimentara ca ACT/tact nu poate fi parte a acestei comparatii (desi indicatorul existent ActualizeazaVerdictActRul compara ACT cu RUL): tact e un jurnal de postari debit/credit (scd/scc/suma), fara cantitate/pret/id_articol per linie de marfa — structural nu poate fi sursa sau tinta a unei sincronizari „cantitate/pret". Sincronizarea din S4b ramane exclusiv RUL <-> articole, distincta de indicatorul de verdict deja livrat.

1. Unde traieste actiunea

Buton nou cmdSincronizeazaArticole, in randul de butoane din PAGE3, langa cele existente:

COMUN\clase\omodificari.vc2:12291-12305   ADD OBJECT 'pgfArticole.PAGE3.cmdAdaugaArticol' ...  Left=175 Width=170
COMUN\clase\omodificari.vc2:12307-12321   ADD OBJECT 'pgfArticole.PAGE3.cmdStergeArticol' ...   Left=0   Width=170

Randul e la Top=0, latimea paginii e 764 (omodificari.vc2:8702); cmdAdaugaArticol se termina la 345 — spatiul liber pana la 764 (419px) e suficient pentru un al treilea buton. Propunere: Left=350, Top=0, Width=250, Height=22, caption „Sincronizeaza cu rulaje...". lblArticoleReadOnly (:12776-12787, Left=360 Top=4) ocupa aceeasi zona vizual, dar e vizibila doar cand lArticoleReadOnly=.T. — exact starea in care butonul trebuie oricum dezactivat, deci overlap-ul nu se vede niciodata simultan (acelasi tipar folosit deja pentru celelalte doua butoane).

Toggle vizibilitate/enabled: se extinde blocul deja existent din Show():

omodificari.vc2:14811-14814
    This.pgfArticole.PAGE3.cmdAdaugaArticol.Enabled = !This.lArticoleReadOnly
    This.pgfArticole.PAGE3.cmdStergeArticol.Enabled = !This.lArticoleReadOnly
    This.pgfArticole.PAGE3.txtDiscountArt.ReadOnly = This.lArticoleReadOnly
    This.pgfArticole.PAGE3.lblArticoleReadOnly.Visible = This.lArticoleReadOnly

cu o linie This.pgfArticole.PAGE3.cmdSincronizeazaArticole.Enabled = !This.lArticoleReadOnly.

Gardare gratuita pentru ROACONT/ROAGEST: butonul exista doar in PAGE3, care la randul ei exista doar cand This.lAreArticoleVanzari (:14792-14818, gatat deja pe "OFACTURARE_EDITARE" $ Upper(Set("Procedure"))). Nu e nevoie de nicio garda noua — butonul mosteneste gating-ul deja livrat in S3/S4.

2. Cum se calculeaza „vechi -> nou"

Fara FK la nivel de rand intre trul si VANZARI_DETALII/tvd — verificat direct pe schema Oracle (DESCRIBE VRUL_TOT prin sqlplus, 09.08.2026): view-ul sursa al lui trul (ofacturare_editare.prg:33-100, in special :74) are 218 coloane, niciuna de tip id_vanzare_det/id_rulaj_vanzare. Singura cheie comuna e ID_ARTICOL, prezenta in ambele: VRUL_TOT.ID_ARTICOL (confirmat pe schema) si tvd.id_articol (ofacturare_editare.prg:274, CreeazaCursorArticoleGol). Matching-ul e deci obligatoriu la nivel de articol (agregat), nu la nivel de linie individuala — nu exista alta optiune.

Agregarea RUL per articol refoloseste formula validata pe date reale, nu una noua: docs\cercetare\rec_suma_act.md, sectiunea E.3, verificata exact pe doua documente (unul de test, unul de productie, E.4/E.5):

valoare_articol_rul = SUM(cant * pretvtva) + SUM(CASE WHEN id_tip_rulaj <> 3 THEN cante * pretvtva ELSE 0 END)
cantitate_articol_rul = SUM(cant) + SUM(CASE WHEN id_tip_rulaj <> 3 THEN cante ELSE 0 END)
pret_propus = valoare_articol_rul / cantitate_articol_rul   -- pret mediu ponderat, daca sunt mai multe randuri RUL pe acelasi articol

GROUP BY id_articol, filtrat sters = 0 (trul incarca deja doar randuri active, ofacturare_editare.prg:57 cu tlAratasterse=.F. din apelantii de editare).

Articolele nestocate (in_stoc=0, rec_suma_act.md E.5/E.6) nu au niciodata randuri in RUL — excluse automat din comparatie, afisate cu actiune „N/A — articol nestocat, fara corespondent in rulaje" (aceeasi coloana in_stoc deja incarcata in tvd, ofacturare_editare.prg:301, folosita azi doar pentru corectia verdictului RUL).

Liniile adaugate/sterse (cerinta explicita din plan) intra natural in acelasi matching pe id_articol, ca diferenta de multimi:

  • articol activ in sursa, absent (sau sters=1) in tinta -> actiune Adaugare in tinta;
  • articol activ in tinta, absent (sau agregat 0) in sursa -> actiune Semnalare (vezi risc, punctul 6 — NU stergere automata);
  • articol in ambele, cantitate/pret diferite -> actiune Modificare;
  • articol in ambele, identic -> nu apare in enumerare (fara zgomot).

3. Cum alege utilizatorul directia

Dialog modal nou, frm_sincronizare_articole, in COMUN\clase\omodificari.vc2 (langa frm_modific2024, ca sa poata referi direct cursoarele tvd/trul din acelasi data session implicit — sectiunea 2.5 din rec_s5_cale_scriere_vfp.md). Deschis din cmdSincronizeazaArticole.Click, modal (WindowType=1, acelasi tipar ca frm_modific2024 insusi si ca frm_modifica_articol_factura).

Continut:

  • doi radio-butoni (optiongroup): „Rulajul e sursa (actualizeaza articolele facturii)" (implicit, recomandat — vezi punctul 5) / „Articolele sunt sursa (actualizeaza rulajul)"; schimbarea selectiei recalculeaza si reafiseaza enumerarea imediat (fara buton „recalculeaza" separat);
  • grid needitabil pe cursorul propunere_sincronizare, coloane: Articol (denumire + codmat), Cantitate veche, Cantitate noua, Pret vechi, Pret nou, Actiune (Modificare/Adaugare/Semnalare/N-A), cu DynamicForeColor gri pe randurile N-A (acelasi tipar ca tvd.sters in grdArticoleFactura, omodificari.vc2:12344);
  • „Aplica" — activ doar daca exista minim o linie cu actiune Modificare sau Adaugare; „Renunta".

Dialogul citeste tvd/trul doar pentru afisare — nu le modifica pana la „Aplica". Refuzul („Renunta" sau inchiderea ferestrei) nu are nimic de desfacut, pentru ca nimic n-a fost atins: satisface direct cerinta din plan („refuzul propunerii lasa datele nemodificate").

4. Ce scrie efectiv sincronizarea, si prin ce cale

Nimic in Oracle, niciodata. AplicaSincronizareArticole (nou, ofacturare_editare.prg, langa restul helperelor pure — nu un nou punct de scriere Oracle) scrie doar in cursoarele VFP in-memory tvd/trul, la apasarea „Aplica":

  • Directia „rulajul e sursa": pentru fiecare articol cu actiune Modificare — REPLACE tvd.cantitate, tvd.pret, tvd.pret_cu_tva WITH ..., lmodificat WITH .T., apoi recalculul lui valoare cu aceeasi formula deja folosita in calculeaza_valori_articol (omodificari.vc2:13397-13409) — refolosita, nu reimplementata — si apel la Thisform.ActualizeazaBaraTotaluri() ca dupa orice editare manuala. Pentru Adaugare, se refoloseste tiparul din AdaugaLinieTvdDinArticol (omodificari.vc2:13130+), populat cu valorile din RUL.
  • Directia „articolele sunt sursa": pentru fiecare articol cu match unic activ in trul — REPLACE trul.cant, trul.pretvtva WITH ... pe randul respectiv, fara sa atinga id_tip_rulaj/conturi/scd/scc. Cand exista mai multe randuri RUL active pe acelasi articol (perechi de diferenta de pret, id_tip_rulaj=3, sau randurile „duplicat" nelamurite din rec_suma_act.md E.4), linia se marcheaza N-A — mai multe randuri RUL, verificati manual — nu se alege automat care rand sa fie atins.

Scrierea reala in Oracle ramane exact calea deja livrata in S5, neschimbata: do_termin -> OSCRIE_IN_FISIERE pentru trul/tact (neatins de aceasta lucrare) + ScrieArticoleFacturaEditate pentru tvd (ofacturare_editare.prg:469-556, comisa in S5). Sincronizarea doar pregateste cursoarele exact cum ar face utilizatorul manual din grid — niciun helper Oracle nou.

5. Alternative, cu recomandare

A. Granularitatea matching-ului: pe linie vs pe articol. Pe linie — respins, nu exista nicio cheie (verificat pe schema, punctul 2). Recomandat: pe articol (id_articol), singura cheie comuna confirmata.

B. O singura directie vs alegere intre doua. Planul cere explicit alegerea utilizatorului (plan_06_editare_factura.md:226-227). Recomandat: ambele directii, dar cu directia „articole -> RUL" restransa la actualizarea cantitate/pret pe randuri RUL deja existente, niciodata la crearea de randuri noi de contabilitate (motivat la punctul 6 — un rand RUL nou cere cont/scd/scc pe care sincronizarea nu le poate deduce sigur din articol). Directia „RUL -> articole" nu are aceasta limitare, pentru ca tvd/ VANZARI_DETALII nu poarta conturi contabile — de aici si recomandarea ei ca implicit in dialog.

C. Dialog modal separat vs panou inline pe PAGE3. PAGE3 n-are loc: layout-ul complet (omodificari.vc2:12780-12956) foloseste toata latimea de 764px pe cele doua randuri de totaluri, iar randul de butoane are doar 419px liberi — insuficient pentru un grid de propuneri cu 6 coloane. Recomandat: dialog modal separat, ca frm_modifica_articol_ factura (acelasi tipar deja folosit in acest formular).

D. Stergerea automata de linii cand sursa nu mai are articolul. Riscant — vezi punctul 6. Recomandat: fara stergere automata, in nicio directie — doar semnalare in enumerare; stergerea efectiva ramane pe butonul deja existent cmdStergeArticol, actionat manual dupa ce utilizatorul a vazut divergenta.

6. Ce poate strica

  • Cel mai mare risc concret: randurile RUL „duplicat" cu id_tip_rulaj=0 gasite langa perechi id_tip_rulaj=3 (rec_suma_act.md E.4, intrebarea 3 nerezolvata catre Marius) — pe un document cu asemenea randuri, agregarea per articol ar putea propune o cantitate/pret gresit(a). Atenuare: eticheta explicita pe dialog („propunere calculata, verificati inainte de aplicare"), niciodata aplicare automata sau implicita; cand exista >1 rand activ pe acelasi articol, linia se marcheaza N-A in loc sa se aleaga arbitrar (punctul 4).
  • Registrul jurnal ROACONT/ROAGEST: butonul si dialogul exista doar in interiorul gardei deja existente pe PAGE3 (lAreArticoleVanzari) — cod complet inert acolo, fara garda noua de adaugat (punctul 1). Risc zero suplimentar fata de ce e deja livrat in S3-S5.
  • omodificari.vc2 e partajat de toata suita — orice atingere in afara blocului gatat pe lAreArticoleVanzari/PAGE3 (de ex. o modificare gresita in Load()/Show() inainte de gate) ar afecta toate notele contabile editate din ROACONT/ROAGEST, nu doar facturile. Implementarea trebuie sa ramana strict in interiorul blocului PAGE3 existent, fara sa atinga grid1/tact (grid-ul comun de note, folosit de toata suita).
  • Directia „articole -> RUL" scrie in randuri de contabilitate (trul) fara sa recalculeze conturile — acceptabil DOAR daca ramane strict la actualizarea cantitate/pret pe randuri deja existente (punctul 5.B), exact echivalent cu o corectie manuala facuta azi direct in grid-ul de rulaje (PAGE1) — nu introduce o cale de scriere noua sau mai permisiva decat ce exista deja.

7. Estimare de efort

Bucata Zile
Agregare RUL per articol (formula E.3) + agregare tvd per articol, logica pura testabila headless 0.5-1
ConstruiestePropunereSincronizare (matching pe id_articol, ambele directii, adaugat/modificat/semnalare) 1
AplicaSincronizareArticole (mutatii in memorie pe tvd/trul, reutilizare calculeaza_valori_articol/AdaugaLinieTvdDinArticol) 1
frm_sincronizare_articole (radio directie, grid needitabil, Aplica/Renunta) 1-1.5
Buton + toggle pe PAGE3 (txt2vcx.ps1 pe omodificari.vc2) 0.5
Teste headless (logica pura de agregare/matching, pe cursoare construite in test, model S5) 0.5
Teste UI vizibile (dialogul modal nu e testabil -A -T, la fel ca frm_articol_factura) 0.5-1
Total ~5-6.5 zile

Confirma caracterizarea din plan: „cea mai mare ramasa, nu blocheaza pe nimeni" (handoff intermediar (sters)).

Ce ramane deschis, de decis cu Marius inainte de implementare

  1. Directia implicita in dialog — recomandare: „rulajul e sursa" preselectat (punctul 5.B).
  2. Randurile RUL „duplicat" nelamurite (rec_suma_act.md E.4/F.3) — daca raman nerezolvate, orice document cu ele va produce linii N-A in loc de propunere, ceea ce e sigur dar posibil frustrant pentru utilizator pe acele documente specifice.
  3. Daca se doreste si optiunea „aplica pe toate liniile deodata" vs selectie linie cu linie in grid — propunerea de mai sus e „aplica tot ce nu e N-A", cea mai simpla; o selectie fina ar adauga complexitate UI fara sa fie ceruta explicit de plan.