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
214 lines
14 KiB
Markdown
214 lines
14 KiB
Markdown
# 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.
|