# Proiectare S4/S4b — pagina de articole factura in frm_modific2024 Cercetare + proiectare pentru `plan_06_editare_factura.md`, story S4 (pagina noua de articole) si S4b (helpere/totaluri/verificari). NU e implementare — propunere supusa aprobarii lui Marius. Stare de plecare (verificata, nu presupusa): S1-S3 sunt deja **implementate si testate** (`docs\progres.md`, sectiunea "#6, runda 1"). Actiunea `frm_facturi.do_editare_factura` (`COMUN\clase\ofacturare_comun.vc2:3727-3869`) si `afisjurcom.do_modifica` (`COMUN\clase\comun.vc2:2222-2563`) sunt cele doua puncte de intrare reale, ambele deschid deja `frm_modific2024` pe cursoarele `tact`/`trul`/`trul_obinv`. Tot ce descrie documentul de fata se adauga **peste** acest cod existent, fara sa-l modifice decat unde e explicit spus (D, E). ## Deciziile lui Marius pe intrebarile din F (08.08.2026) — au prioritate fata de recomandarile din text - **F.1 — respinsa recomandarea "strict facturi".** Pagina se aplica pe **orice rand din `VANZARI`**, deci **si pe avize**. Tot ce spune A.3 despre restrangerea la lista de `TIP` de facturi se reciteste in cheia asta. - **F.2 — premisa din C.1 e gresita.** Contul nu e `4111` peste tot: **avizele folosesc `418`**. In plus, nota contine **randuri de discount** si poate contine **note adaugate manual de utilizator**. Deci filtrul fix `SCD='4111'` nu e o regula, ci o potrivire pe un singur document. Regula corecta se stabileste in `docs\cercetare\rec_suma_act.md` (cercetare in curs), si **C.1 se rescrie dupa ea**. Pana atunci, nu implementa indicatorul pe formula din C.1. - **F.3 — raspuns de la Marius**: in `RUL` pot fi **si linii cu diferente de pret**, cand pretul de vanzare din factura difera de cel din stoc — **doar pentru marfa tinuta la pret de vanzare**. Deci **suma bruta din `RUL` nu e comparabila prin constructie** cu totalul documentului (pe `cod=1140888`: 10 randuri `RUL` pentru 4 linii, 4476.28 fata de 1924.59). O bara de totaluri care le compara direct ar semnala "desincronizat" permanent pe orice document cu marfa la pret de vanzare. Subsetul comparabil se stabileste in `docs\cercetare\rec_suma_act.md`. - **F.4 — varianta A** (bara de totaluri sub grid, permanent vizibila). - **F.5 — alegere globala** a directiei de sincronizare, pe document, nu per linie. - Separat, din decizia 18: **liniile din seturi se trateaza ca orice alta linie**. - **Transfer si custodie** (23, 25, 30, 41, 27, 42, 47): pagina **apare**, dar **fara bara de totaluri** — nu bara goala cu mesaj, ci fara ea. Pe aceste tipuri nu exista suma comparabila (transferurile merg pe cont de stoc, custodia nu genereaza randuri `ACT` per articol). - **Tipul 51 (ROAACNPRO) foloseste `4111`** — deci divergenta gasita in cercetare are alta cauza decat contul; prima suspiciune e filtrarea pe `cod` fara `an`+`luna`. - **Comparatia stricta e imposibila prin constructie**: `ACT` nu marcheaza originea randului, deci un rand adaugat manual nu se distinge de unul generat. Bara de totaluri **arata cifrele si diferenta, fara verdict automat de eroare**. - **Garda pe `id_set` se scoate de tot** (decizia 24) — premisa ei a picat. - **Documente mixte** (decizia 25): suma `RUL` se corecteaza cu valoarea liniilor nestocate din `VANZARI_DETALII`, marcata in bara ca ajustata. - **`RUL` are formula comparabila** (nu mai e doar informativ): `SUM(CANT*PRETVTVA) + SUM(CANTE*PRETVTVA WHERE ID_TIP_RULAJ <> 3)`. **C.1 se rescrie** dupa `docs\cercetare\rec_suma_act.md`, care are si propunerile concrete de corectie la final. Ipoteza lui Marius de verificat, cu efect asupra codului deja scris: `id_set + 5` la discount ar fi un **marcaj tranzitoriu** consumat inainte de `ACT`, nu o valoare persistata — caz in care garda pe `id_set` din `do_editare_factura` (runda 3) e construita pe o premisa falsa. ## A. Ce se poate face concret pe `frm_modific2024` ### A.1 Structura curenta a `pgfArticole` si a celor doua pagini de rulaje Clasa `frm_modific2024` incepe la `COMUN\clase\omodificari.vc2:6375`. Pageframe-ul: - **Nu are `PageCount` propriu setat** in `ADD OBJECT 'pgfArticole'...` (`:8627-8641`) — mosteneste `PageCount = 2` din clasa de baza `_pageframe` (`COMUN\clase\_baza.vc2:496`). Cele doua pagini sunt configurate doar prin proprietatile `PAGE1.Caption/ForeColor/Name` si `PAGE2.Caption/ForeColor/Name` in acelasi bloc `ADD OBJECT`. - `PAGE1` contine `_grdfooter1` (`:8644-8655`, footer cu sume pe coloane, `csumcolumns=...`) si `grdRulaje` (`:8657-...`, `ColumnCount=63`, `RecordSource="trul"`, `ReadOnly=.F.`). - `PAGE2` are aceeasi structura pe `trul_obinv`/`grdRulajeObinv` (confirmat prin indexul de metode: `pgfArticole.PAGE2.grdRulajeObinv.*`, `omodificari.vc2:15159-15424`), nu am recitit blocul `ADD OBJECT` complet (nu era necesar — tiparul e identic cu PAGE1, doar alt cursor). - **`Init`** (`:13551-13660`): primeste `Lparameters tnIdSet, tlNotaNoua, toBackupXML, toSet, tlVizualizare`; seteaza `This.nid_set`, `lEditare`/`lVizualizare`/`lModificare`/`lVerificare`. Zona `:13610-13643` ascunde `but_nou1`/`but_sterge1` si face `grid1` readonly pe seturi speciale (id_set 25000-25099 sau o lista fixa) — logica veche, fara legatura cu facturile de vanzare (acele id_set-uri sunt pentru note "cu scadere", nu pentru pagina noua). - **`Activate`** (`:12238-12243`): la prima activare cheama `resize_grid1()`. - `resize_grid1()` (`:13680-13688`) si `afiseaza_rulaje()` (`:12245-12281`) folosesc deja `this.pgfArticole.Visible` ca switch — **dar e un toggle manual, comandat de utilizator** (butonul `but_afiseaza_rulaje`, colapseaza/expandeaza TOT pageframe-ul ca sa faca loc pentru `grid1`), nu o decizie "documentul e de tip X". Nu e mecanismul de folosit pentru afisarea conditionata a PAGE3. - **`Show`** (`:13719-13775`) e unde se leaga efectiv footerele de sume la grid-uri: `this.pgfArticole.page1._grdfooter1.attachtogrid(...)` +`.calcTotal()`, identic pentru PAGE2 (`:13748-13752`) si unde se ascunde automat tot pageframe-ul cand nu exista deloc rulaje (`:13764-13770`, `If Reccount('trul')=0 And Reccount('trul_obinv')=0 Then This.afiseaza_rulaje()`). ### A.2 Mecanica adaugarii PAGE3 `PageCount` nu e o proprietate care se citeste o singura data — poate fi modificata la runtime, si exact acest tipar exista deja in codebase, la un alt pageframe: `comun.vc2:10521-10531` (`frm_...Init`) face `THISFORM.pgcod.PageCount = n+1` + `.Pages(n+1).Caption = 'Gestiuni'` cand conditia e adevarata, altfel `PageCount = n` (pagina ramane ascunsa, pentru ca nu exista in colectia activa de pagini). **Acesta e mecanismul recomandat pentru PAGE3**, nu `.Visible` pe pagina (VFP pageframe `Page` are `Visible`, dar codebase-ul nu-l foloseste nicaieri pentru show/hide conditionat — a fost cautat explicit, 0 rezultate `Page.*Visible` in `COMUN\clase`). Propunere concreta: - In definitia clasei, `ADD OBJECT 'pgfArticole'` capata `PageCount = 3` **explicit** (nu mai ramane pe default-ul 2) + `PAGE3.Caption = "Articole factura"`, `PAGE3.Name = "PAGE3"`, plus grid-ul nou `pgfArticole.PAGE3.grdArticoleFactura` (dupa modelul `grdRulaje`) si un `_grdfooter` propriu (`pgfArticole.PAGE3._grdfooter1`), la fel ca PAGE1/PAGE2. - La runtime, in `Show` (langa blocul `:13764-13770`, dupa acelasi principiu): daca documentul curent **nu** e o factura de vanzare (vezi A.3), `This.pgfArticole.PageCount = 2` — PAGE3 dispare din colectia activa de pagini, comportament identic cu azi pentru orice alt tip de nota. Cand **este** factura, `PageCount` ramane `3` (valoarea din clasa) si se leaga footerul nou: `this.pgfArticole.page3._grdfooter1.attachtogrid(...)` + `.calcTotal()`, exact ca la PAGE1/PAGE2. - Consecinta directa: pentru **orice document care nu e factura** (99.9% din utilizarile din ROAGEST/ROACONT), `PageCount` scade inapoi la 2 la fiecare deschidere — clasa arata **byte-cu-byte ca azi**, nicio schimbare vizuala sau de comportament. Asta e conditia ceruta explicit in plan (S4: "pagina se afiseaza doar cand documentul curent are rand in vanzari... altfel formularul arata exact ca azi") si raspunde direct la riscul cel mai mare listat in plan. ### A.3 Cum decide formularul ca documentul curent are randuri in `VANZARI` **Comparatia celor trei variante**, asa cum a cerut misiunea. Concluzia (varianta 3) nu se schimba fata de versiunea anterioara a acestei sectiuni — se schimba doar **filtrul** aplicat dupa ea, cf. `[DECIS — decizia 19 din progres.md]` mai jos: 1. **Test pe `id_set`** — respins. Intervalele facturilor si ale avizelor din `COMUN\docs\tipuri_documente_facturare.md` se suprapun aproape complet (facturi: 25000-25009, 25042-25048, 25051, 50100 + variantele "cu scadere" +10; avize: 25020-25029, 25040-25041, 25046 + variantele +10 — ambele in acelasi interval brut 25000-25099). Un test de forma `Between(tnIdSet,25000,25099)` (deja folosit in `Init`, `:13610-13612`, dar pentru alt scop) ar prinde si avizele, nu doar facturile. Documentul insusi semnaleaza o coliziune nerezolvata pe `25051` (punctul 3 din capcanele acelui fisier) — nu e o baza solida pentru o decizie care controleaza afisarea/ascunderea unei pagini cu bani. 2. **Flag pasat de apelant** — respins ca mecanism principal. `afisjurcom.do_modifica` (ROACONT/ROAGEST, registrul jurnal) e cod generic pentru **orice** tip de nota; azi nu stie si nu are motiv sa stie ca documentul curent are randuri in `VANZARI` (asta a fost motivul pentru care garda eFactura si cea de referinte au trebuit extrase in `COMUN\programe\` la S1, nu lasate in `frm_facturi`). A cere unui al doilea apelant sa afle si sa transmita acest flag ar duplica exact interogarea pe care oricum trebuie sa o facem undeva, cu riscul ca un al treilea apelant viitor sa uite s-o transmita corect. 3. **`SELECT` in `vanzari` dupa `cod`** — recomandat. `tact` (cursorul pe care se leaga deja formularul, incarcat de `IncarcaCursoareModificareNota`, `COMUN\programe\ofacturare_editare.prg:27-140`) contine coloana `cod` din `vact_tot` (filtrul `WHERE ... cod = tnCod` de la `:53` confirma coloana). `tact.cod` se poate citi **oricare ar fi workarea curenta** (referinta calificata pe alias), deci **nu conteaza care apelant a deschis formularul** — informatia necesara e deja in cursorul pe care oricum formularul il primeste prin contract. Un singur `SELECT tip, id_vanzare FROM vanzari WHERE cod = ` (rulat o singura data, la deschidere) da simultan raspunsul la "are rand in `vanzari`?" si, daca da, `tip`-ul exact — necesar in Runda 4 pentru tratamentul special al transferului/custodiei (decizia 22, mai jos). **Recomandare**: detectia se face **in interiorul `frm_modific2024`** (nu in apelanti), intr-o metoda noua apelata din `Init` sau din `Show` (inaintea blocului de la A.2), care citeste `tact.cod`, interogheaza `vanzari` o singura data, si populeaza **trei** proprietati noi pe formular: `This.lAreArticoleVanzari`, `This.nIdVanzare` si `This.nTipVanzare` (tip-ul documentului din `vanzari`). **Asta inseamna ca PAGE3 apare automat din ambele puncte de intrare fara nicio modificare in `do_editare_factura` sau `afisjurcom.do_modifica`** — exact arhitectura ceruta de plan ("extinderea clasei comune, nu cod apelant nou"). Numele `lAreArticoleVanzari` (nu `lEsteFacturaVanzare`, cum se numea in versiunea anterioara a acestei sectiuni) e ales deliberat: sub decizia 19 de mai jos flagul devine adevarat si pe avize, transferuri si custodie, nu doar pe facturi — numele vechi ar fi mintit. `nTipVanzare` se retine separat, tot din acelasi `SELECT`, pentru ca Runda 4 (decizia 22: transfer/custodie afiseaza pagina, dar fara bara de totaluri) are nevoie sa stie tipul exact, nu doar "are/nu are randuri". **`[DECIS — decizia 19 din progres.md]`** Filtrul de mai sus **nu** se restrange la lista de `TIP` de factura — pagina apare pe **orice rand din `VANZARI`**, deci si pe avize, transfer intre subunitati, transfer pe lucrare si custodie. Varianta "strict facturi" (recomandarea acestei sectiuni intr-o versiune anterioara, cand decizia inca nu fusese luata) a fost **respinsa explicit de Marius**. Consecinte pentru restul lucrarii: - Garda eFactura/S1 ramane specifica facturilor si **nu se extinde** — pe avize/transfer/custodie pur si simplu nu se aplica azi, pentru ca acele tipuri de document nu trec pe acolo. - Scrierea (E, S5) si bara de totaluri (C.1, C.3) raman gatate separat, dupa `nTipVanzare`: transfer/custodie (decizia 22) primesc pagina, dar fara bara. - `frm_modific2024` deschis din `afisjurcom.do_modifica` (registrul jurnal ROACONT/ROAGEST) capata aceeasi pagina pe orice document cu rand in `VANZARI`, nu doar pe facturi — de retinut la testarea riscului D, care azi verifica doar cazul "document care nu e deloc in `VANZARI`". ### A.4 Lantul `inainte_de_do_termin` — unde intra validarile noi `omodificari.vc2:13357-13549`. Ce face azi, pe scurt: - `:13360-13367` reseteaza filtrul pe `tact`, completeaza `id_set` gol pe `tact`/`trul`/`trul_obinv`. - `:13369-13386` verificare generica de completare cont/analitic/partener (`verificare_note_contabile('tact',...)`, `oOperatii_comune`), sarita pentru seturile speciale (`id_set` 99998/90024). - `:13389-13402` (doar `gnAn >= 2013`): avertisment pe combinatia de conturi `4426-4428`/ `4428-4427` fara sa fi folosit optiunea dedicata, apoi `This.VerificaAvertizareExigibilizareTVA()` (`:13909-14083`, verificare separata, neatinsa de aceasta propunere). - `RETURN m.llRet` — daca oricare pas a esuat, formularul nu inchide (butonul Termina ramane blocat pana la corectare). **Punctul de agatare pentru validarile noi ale lui S4b**: chiar inainte de `RETURN m.llRet` (`:13404`), un bloc nou gatat de `This.lAreArticoleVanzari` (A.3) — de exemplu, garda "nu lasa utilizatorul sa iasa cu `buton=1` daca a marcat sincronizarea ca necesara dar n-a confirmat-o explicit" (detaliu in C). **Nu inlocuieste nimic din ce exista azi** — se adauga dupa validarile generice, cu acelasi tipar (`If m.llRet Then ... Endif`). ## B. Cursorul de articole ### B.1 Sursa si momentul incarcarii Confirmat in `docs\cercetare\rec_cale_vanzari_detalii.md`: scrierea la editare merge **direct** in `VANZARI_DETALII` (fara `VANZARI_DETALII_TEMP`, care e GTT populata doar la emitere). Simetric, **citirea** pentru formular trebuie sa vina direct din `VANZARI_DETALII`, nu din vreo tabela temp. Propunere: o functie noua in `COMUN\programe\ofacturare_editare.prg` (alaturi de `IncarcaCursoareModificareNota`, acelasi stil de cod — `goExecutor.oExecute`, gestiune de eroare simetrica), de exemplu: ```foxpro FUNCTION IncarcaArticoleFactura LPARAMETERS tnIdVanzare * incarca header-ul (1 rand, cursor tvanz) si liniile active (cursor tvd) pentru factura data * tvd/tvanz raman deschise READWRITE - apelantul (frm_modific2024) le foloseste si le inchide ENDFUNC ``` Apelata **din interiorul `frm_modific2024`** (Init/Show, dupa ce A.3 a stabilit `This.lAreArticoleVanzari = .T.` si `This.nIdVanzare`), nu din apelanti — acelasi motiv ca la A.3: zero cod nou in `do_editare_factura`/`afisjurcom.do_modifica` pentru partea de citire. `tvanz` (1 rand, header): `id_vanzare, cod, discount` (singurul camp editabil din antet, decizia 17 din `progres.md`) + campurile needitabile utile ca referinta vizuala (`total_fara_tva, total_tva, total_cu_tva` — valorile **vechi**, denormalizate, afisate readonly langa totalurile live din S4b, nu suprascrise decat de S5 la salvare). `tvd` (liniile), coloane din `VANZARI_DETALII` (lista completa in `rec_cale_vanzari_detalii.md`, sectiunea 2.2) — subsetul relevant editarii: `id_vanzare_det, id_articol, cantitate, pret, pret_cu_tva, proc_tvav, discount_unitar, id_gestiune, cont, id_valuta, id_jtva_coloana, serie, explicatie, taxcode, lot, sters`. Filtrul de incarcare: `WHERE id_vanzare = :tnIdVanzare AND sters = 0` (liniile deja sterse nu se mai arata — simetric cu `tact`, care si el filtreaza `sters=0` la incarcare). ### B.2 Marcaje de stare, fara concept nou fata de restul clasei Clasa foloseste deja doua idiomuri simple pentru starea liniilor din `tact`, ambele reutilizabile ca atare pentru `tvd`, fara sa inventam un al treilea: - **Sters = flag pe randul existent**, nu stergere fizica din cursor — exact cum `tact`/`trul` reprezinta deja `STERS` ca o coloana obisnuita (rescrisa la scriere, nu `DELETE`d din cursor). `tvd.STERS` (coloana deja prezenta in `VANZARI_DETALII`) se flipuieste in cursor la actiunea "sterge linie"; la scriere (D), un rand cu `STERS=1` care avea `STERS=0` la incarcare devine un `UPDATE ... SET STERS=1`. - **Adaugat = `id_vanzare_det = 0`** — acelasi sentinel folosit deja in `do_adauga` (`omodificari.vc2:12685`, `loadd.id_act = 0` pentru randurile noi din `tact`, inainte de `Append Blank`/`Gather`). La scriere, orice rand din `tvd` cu `id_vanzare_det = 0` e un `INSERT` (PK-ul real vine automat din `SEQ_VANZARI_DETALII`, confirmat in `rec_cale_vanzari_detalii.md` sectiunea 1.3/3.2 — nu trebuie generat in VFP). - **Modificat** — singurul marcaj cu adevarat nou necesar, pentru ca "a fost atins" nu se poate deduce din `id_vanzare_det`/`STERS`. Propunere: o coloana logica `_modificat` (prefix `_`, convenabil pentru un camp de lucru care nu exista in tabela reala — verifica totusi ca VFP nu interpreteaza gresit numele; alternativ `lModificat`), setata `.T.` din handler-ele `Valid`/ `InteractiveChange` ale coloanelor editabile din grid — acelasi tipar folosit deja de clasa pe `trul` (`pgfArticole.PAGE1.grdRulaje.cCant.Text1.Valid`, `omodificari.vc2:14906-14911`, si restul handler-elor `Valid`/`When`/`InteractiveChange` din acelasi grid). La scriere, un rand cu `id_vanzare_det > 0` si `_modificat = .T.` e un `UPDATE`; fara flag, randul nu se atinge (evita `UPDATE`-uri inutile pe linii doar rasfoite). Acest model evita complet o alternativa mai grea (snapshot + diff intre cursorul original si cel curent) care ar fi introdus un concept nou, fara sa aduca vreun beneficiu fata de flag-urile deja folosite in clasa pentru `tact`. ## C. Helperele si verificarile ### C.1 Ce inseamna "suma comparabila" — regula pe tip de document, verificata pe date reale Corectie fata de versiunea anterioara a acestei sectiuni (premisa ei — filtru fix `SCD='4111'` — a fost respinsa explicit de Marius, F.2 mai jos). Cercetarea completa, cu toate interogarile pe cele trei scheme si sursele exacte pe cod, e in `docs\cercetare\rec_suma_act.md`; ce urmeaza e concluzia ei. Doua completari ulterioare, verificate separat pe `MARIUSM_AUTO` (08.08.2026), sunt in `docs\cercetare\rec_cele_41_facturi.md`: derivarea `an`/`luna` si cauza reala a divergentei pe `cod=1138989`. Nu se reimplementeaza nicio formula fiscala in VFP — recomandarea ramane cea de dinainte: "suma din `VANZARI_DETALII`" se ia direct din `calculeaza_total_fara_tva_fact`/ `calculeaza_total_tva_fact` (Oracle, aceleasi functii care vor rula la salvarea din S5), niciodata recalculata in VFP. **Nu exista un filtru fix de cont pentru "suma din ACT".** Contul de debit al liniei depinde de **tipul documentului** (`PACK_FACTURARE.pck`, `contabilizeaza_articol` decide contul la `:7390-7415`): | Grup de `TIP` | Cont debit (linie) | Comparabil cu `TOTAL_CU_TVA`? | |---|---|---| | Facturi (1,2,3,5,7,8,9,10,43,44,45,46,48,49,51,52 fara rata) | `4111` (empiric stabil pe 3 scheme) | DA | | Factura din aviz (tip 4) | `4111`, discount direct pe el cu semn negativ | DA | | Vanzare pe rate/contract (2,6,52 cu `id_rata<>0`) | din `NOTE_CONTABILE`, legat de `CONTRACTE` | DA | | Avize catre clienti debitori (28, 29) | `461` (hardcodat) | DA | | Restul avizelor (21,22,24,26) | `418` (hardcodat) | DA | | Transfer intre subunitati (23,25,30,41) | cont de STOC, nu de client | NU | | Transfer pe lucrare (27) | cont de STOC | NU | | Custodie (42,47) | — (`descarca_gestiune` nu scrie rand `ACT` per articol) | NU | | ROAACNPRO (51) | `4111`, confirmat stabil de Marius | cont OK, dar comparatie nesigura — vezi mai jos | **Filtrul pe `ACT` cere `cod` + `an` + `luna`, niciodata `cod` singur.** Dovada: `cod=1140632` are un rand de achizitie straina (OCR furnizor) in `an=2026,luna=1` si nota de vanzare reala in `an=2026,luna=2`, cu **acelasi** `cod` reutilizat intre module. `IncarcaCursoareModificareNota( tnCod, tnAn, tnLuna, ...)` (`COMUN\programe\ofacturare_editare.prg:27-140`) filtreaza deja corect — orice interogare noua din S4b trebuie sa foloseasca acelasi tipar de filtru complet, nu doar `cod`. **`an`/`luna` nu se deriva din `VANZARI.DATA_ACT`** — trebuie luate din contextul notei deja incarcate, niciodata recalculate din antet. Pe 703 documente `VANZARI` (`MARIUSM_AUTO`, `docs\cercetare\rec_cele_41_facturi.md`): 542 au nota in luna din `DATA_ACT`, **78 (11%) au nota intr-o alta luna**, 83 n-au deloc randuri `ACT` pe `cod`. Exemplu: `cod=1138989` are `VANZARI.DATA_ACT = 01-JAN-19`, dar cele 12 randuri `ACT` sunt in `an=2019, luna=3` (`dataact=31-MAR-19`) — un filtru `cod + an(data_act) + luna(data_act)` ar intoarce zero randuri. Pe datele de test cazurile sunt concentrate pe tip=51 (ROAACNPRO, `DATA_ACT` sablon `01-JAN-19`), deci nu e dovedit tipar general de productie — dar consecinta de implementare e reala: `an`/`luna` se iau din cursorul `tact`/`actactan` deja incarcat de `IncarcaCursoareModificareNota` (apelata cu `an`/`luna` explicite), niciodata recalculate din `VANZARI.DATA_ACT`. Pentru cele 78 de documente cu luna divergenta, `do_editare_factura` raspunde azi "Nu exista nota contabila pentru aceasta factura" si refuza editarea — comportament sigur, dar de consemnat ca limitare cunoscuta. **Discountul de document intra NET (debit minus credit), nu ca `SUM(SCD=cont)` simplu.** `scrie_discount` (`PACK_FACTURARE.pck:12859-13057`) scrie discountul pe sensul OPUS liniei de vanzare: pe facturi normale (`tip<=20` sau in `(44,45,46,43,48,49,51,52)`) discountul e `SCD='667'`/`SCC='4111'`, adica **pe credit** fata de contul de client — un `SUM(SUMA) WHERE SCD='4111'` simplu il ignora complet. Suma corecta e **soldul net**, aceeasi formula pe care aplicatia insasi o foloseste la auto-verificarea de la emitere (`verifica_total_document`, `PACK_FACTURARE.pck:16073-16145`): ```sql SUM(CASE WHEN SCD = :cont THEN SUMA WHEN SCC = :cont AND SCD NOT IN ('5311','5314','5121','5125','5126') THEN -SUMA ELSE 0 END) ``` (pe factura din aviz, tip=4, discountul e deja direct pe `4111` cu semn negativ, deci formula neta da acelasi rezultat ca un `SUM` simplu pe acel tip — nu strica nimic sa se aplice uniform pe toate tipurile comparabile din tabel.) **`RUL` are acum o formula comparabila** (nu mai ramane doar informativ): ``` SUM(CANT*PRETVTVA) + SUM(CANTE*PRETVTVA WHERE ID_TIP_RULAJ <> 3) ``` Randurile "in plus" observate initial (10 randuri `RUL` pentru 4 linii, suma bruta 4476.28 in loc de 1924.59 pe `cod=1140888`) vin din **perechile de diferenta de pret**, generate de `PACK_FACTURARE.descarca_gestiune` pentru marfa/produse tinute la pret de vanzare (`V_CONT IN ('371','357') AND V_TIP_GESTIUNE=6`, `:9361-9540`; produse/ambalaje similar, `:9641-9818`) cand pretul de vanzare inregistrat in stoc difera de cel facturat efectiv (`V_PRETV_ORIG <> V_PRETV`). Fiecare diferenta scrie o pereche marcata `ID_TIP_RULAJ=3` (`:7745`): un rand cu `CANTE>0` la pretul VECHI din stoc (de exclus din suma) si unul cu `CANT>0` la pretul REAL facturat (de inclus). Formula de mai sus, aplicata pe `cod=1140888`, da exact `1924.59` = `TOTAL_CU_TVA`. **Documente mixte (decizia 25): liniile nestocate nu au deloc rand `RUL`.** `descarca_gestiune` sare complet peste articolele cu `NOM_ARTICOLE.IN_STOC=0` (`:7783-7789`) — nu scrie nimic in `RUL` pentru ele (confirmat pe productie, `cod=1397106`: linia de "SERVICII TRANSPORT" lipseste integral din `RUL`). Pe orice document cu linii stocate SI nestocate, suma `RUL` de mai sus **subestimeaza sistematic** documentul cu exact valoarea liniilor nestocate. Corectie: suma `RUL` se aduna cu suma liniilor `IN_STOC=0` din `VANZARI_DETALII`, iar bara de totaluri marcheaza explicit ca cifra e **ajustata** (nu doar `RUL` brut). **Tipuri fara suma comparabila — nu se afiseaza bara, nu se da verdict** (decizia 22): transfer intre subunitati (23, 25, 30, 41) si transfer pe lucrare (27) merg pe cont de **stoc**, nu de client; custodia (42, 47) nu scrie **niciun** rand `ACT` per articol. Pe niciunul din aceste tipuri nu exista ce compara — tratament explicit ("pagina apare, bara nu"), nu o eroare de raportat. Pe tip=50 (marcat "in lucru" in pachet), acelasi tratament, prin analogie. **ROAACNPRO (tip 51): cauza divergentei pe `cod=1138989` gasita — nota e DUBLATA, nu e cazul deciziei 9.** Cele 12 randuri `ACT` (toate in aceeasi `an`/`luna`, deci nu e capcana de filtrare de mai sus; toate pe `4111`, zero `411`) sunt **doua blocuri de cate 6**, iar al doilea e **exact 2x** primul, rand cu rand (`docs\cercetare\rec_cele_41_facturi.md`): blocul A insumeaza exact `TOTAL_CU_TVA = 13895.45` (0.01 lei rotunjire), blocul B e dublul lui, iar suma totala peste toate cele 12 randuri e `41686.35` = 3x totalul — exact raportul semnalat initial. **Regula pentru suma din `ACT` se inchide si pe acest document**: nu e o exceptie a regulii, e o nota postata de doua ori — o anomalie reala de date pe care un indicator corect trebuie s-o semnaleze, nu s-o ascunda. **Nu e printre cele 41 de facturi de la decizia 9** (#8/S9) — acelea sunt toate `STERS=1`, iar `cod=1138989` are `STERS=0` si o linie activa; presupunerea anterioara ca ar fi "aceeasi familie" nu se sustine. Ramane deschis, separat: cele 12 randuri `ACT` explica antetul `VANZARI`, dar linia unica din `VANZARI_DETALII` (`2468.21`) nu reconciliaza cu niciuna din cele doua cifre — asta chiar ramane neexplicat, si e un argument in plus pentru caracterul informativ (nu verdict automat) al comparatiei `ACT` vs `VANZARI_DETALII` de mai jos. **Comparatia ramane informativa, niciodata verdict automat de eroare.** `ACT` **nu are nicio coloana care sa marcheze originea randului** (`omodificari.vc2:12653-12701`, `do_adauga`) — un rand adaugat manual de utilizator (posibil, decizia F.1: pagina apare pe orice document din `VANZARI`) e indistinctibil, dupa salvare, de unul generat automat la emitere. Indicatorul din S4b ramane deci **informativ pe subset bine definit**, niciodata sursa unica de adevar pentru un verdict de eroare. **Gradul de incredere**: regula de mai sus (cont pe tip + filtru `cod+an+luna` + sold net) e verificata pe **360 de documente, 12 tipuri de document, 3 scheme** (`MARIUSM_AUTO` date de test, `ROMFAST@ROA_ROMFAST` client real, `VENDING` productie) — **~97.5% potrivire exacta** (`docs\cercetare\rec_suma_act.md`, sectiunea "Concluzie C"). `cod=1138989` (ROAACNPRO) nu mai e un caz neexplicat — cauza e gasita (nota dublata, de mai sus) — dar un indicator automat tot ar semnala divergenta pe el, corect, pentru ca e o anomalie reala de date. Restul cazurilor **raman deschise, nu ascunse**: transfer/custodie (necomparabile prin design, de mai sus), 5 documente `ROMFAST` fara nicio nota `ACT` scrisa, si un document `VENDING` in valuta (`cod=1165566`, tip=9) cu o diferenta de 5454.12 lei neexplorata — niciunul din aceste cazuri nu infirma regula, dar niciunul nu trebuie prezentat ca "inchis" fara nuanta de mai sus. ### C.2 Ce inseamna "live" vs "la ultima salvare" Cele trei surse nu pot fi comparate coerent "in timp real" cat timp utilizatorul tasteaza intr-o celula din grid, pentru ca `ACT`/`RUL`/`VANZARI_DETALII` reala raman la valoarea de dinaintea editarii curente pana la `Salveaza`. Propunere clara, ca sa nu induca fals sentiment de precizie: - **Subtotal pe linie, in grid** (cantitate x pret, cu/fara TVA dupa flag) — calcul simplu, live, in VFP, la fiecare `InteractiveChange`/`Valid` (acelasi tipar ca `calculeaza_valori_rul`, `omodificari.vc2:12519-12588`, aplicat pe `trul`). Nu implica formula fiscala complexa (fara discount de document, fara rotunjiri de agregare), deci riscul de divergenta e neglijabil si local, vizibil imediat de utilizator. - **Cele trei totaluri de control (RUL / VANZARI_DETALII / ACT)** raman "la ultima stare persistata" — se recalculeaza (interogare Oracle) la deschiderea paginii si dupa fiecare `Salveaza` reusit, **nu** la fiecare tasta. Rolul lor real (asa cum reiese din problema descrisa de Marius) e sa arate ca un document editat anterior a ramas nesincronizat, nu sa dea un preview in timp real al editarii curente — editarea curenta oricum nu poate fi "corecta" pana nu trece prin acelasi calcul Oracle care va rula la salvare. ### C.3 Indicatorul de stare a sincronizarii Un label vizibil pe PAGE3 (langa footerul de totaluri), 3 stari: **verde/OK** (toate sumele aplicabile coincid, in limita rotunjirii de 2 zecimale — pe tipurile fara suma comparabila, transfer/custodie, bara nici nu apare, cf. C.1), **galben/atentie** (`VANZARI_DETALII` si `ACT` coincid, dar cifra din `RUL` e ajustata pentru linii nestocate sau documentul e de un tip cu comparatie nesigura, ex. ROAACNPRO — cf. C.1), **rosu/desincronizat** (`VANZARI_DETALII` si `ACT` NU coincid — semnalul real ca ceva nu s-a propagat corect, singurul caz in care indicatorul trebuie sa opreasca vizual atentia utilizatorului). Recalculat la deschidere si dupa fiecare salvare reusita (C.2). ### C.4 Actiunea explicita de sincronizare Cerinta lui Marius: directia (rulaj->articol sau articol->rulaj) o alege utilizatorul, niciodata implicit. Propunere de flux (schita UI in F, intrebarea de UX): 1. Buton "Verifica sincronizarea" (sau automat la deschidere, doar afisare) — ruleaza C.1/C.3, populeaza un cursor de diferente `tvd_diff` (id_articol, cantitate_rul, cantitate_vd, pret_rul, pret_vd, ...) doar pentru randurile unde difera. 2. Daca exista diferente, buton "Propune sincronizare" deschide un dialog/grid cu liniile afectate si valorile vechi/noi, **pe ambele directii posibile** (utilizatorul alege per-sesiune care parte e sursa — RUL sau VANZARI_DETALII —, nu per-linie individual, ca sa evite o combinatie inconsistenta). 3. Confirmarea aplica modificarile **doar in cursorul in memorie** (`tvd` sau `trul`, dupa directie) — nu scrie nimic in Oracle pana la `Termina`/`Salveaza`. Consistent cu principiul "nimic nu se aplica silentios si nimic nu se declanseaza automat la `do_termin`" din plan. 4. Refuzul propunerii nu modifica nimic — utilizatorul poate corecta manual, linie cu linie, in oricare din cele doua griduri. ### C.5 Linii adaugate/sterse fara corespondent in RUL O linie noua in `tvd` (id_vanzare_det=0) nu are, prin definitie, niciun rand `RUL` corespunzator — nu exista "vechi" de comparat. Propunere: astfel de linii sunt automat excluse din comparatia C.1/C.3 (nu pot fi "desincronizate", pentru ca n-au fost niciodata sincronizate) si marcate separat in UI ("linie noua, fara rulaj — se creeaza la salvare" / "linie stearsa"). Simetric pentru liniile sterse (`STERS=1` in `tvd`): nu mai intra in suma "curenta" din C.2, dar raman vizibile (tacuate/ strikethrough) pana la salvare, ca utilizatorul sa vada ce a marcat pentru stergere inainte sa confirme. ### C.6 Ce NU se poate verifica automat - Corelatia RUL <-> VANZARI_DETALII **linie-cu-linie** (nu agregat) — ramane nesigura: formula din C.1 e verificata ca sumă pe tot documentul, nu mapeaza un rand `RUL` anume pe o linie anume din `VANZARI_DETALII`. Suma agregata (C.1) are acum formula verificata; ce nu se poate face e legatura 1-la-1 intre randuri. - Corectitudinea contabila a notei dupa editare (echilibrul debit=credit, alegerea corecta a conturilor) — ramane acoperita de validarile generice deja existente in `inainte_de_do_termin` (A.4), care nu se ating. - Impactul asupra eFactura/SAFT dupa editare — in afara scopului #6 (garda S1 blocheaza deja editarea facturilor trimise in eFactura). ## D. Riscul asupra registrului jurnal `omodificari.vc2` e in COMUN si serveste si `afisjurcom`/registrul jurnal ROACONT/ROAGEST. Ce poate regresa, concret, si cum se limiteaza: 1. **`PageCount` schimbat global pe clasa** — daca noul `PageCount=3` din definitia clasei nu e readus la 2 la runtime pentru non-facturi (A.2), PAGE3 ar aparea (goala sau cu date gresite) pe orice nota din ROACONT/ROAGEST. Mitigare: testul din A.2 ruleaza necontional in `Show`, inaintea oricarei afisari, si defaultul din clasa e explicit "1 pas de siguranta" (daca testul crapa/nu ruleaza, `PageCount` ramane 3 din clasa — deci testul TREBUIE sa aiba un `Catch`/`else` care forteaza `PageCount=2`, nu invers). **De verificat explicit la implementare**: comportamentul pe eroare al noii interogari Oracle (A.3) trebuie sa fie "ascunde PAGE3", nu "las-o vizibila". 2. **Interogarea noua din A.3 (`SELECT ... FROM vanzari WHERE cod=...`) ruleaza la FIECARE deschidere a formularului**, inclusiv pentru note care n-au nicio legatura cu facturarea — cost suplimentar mic (un SELECT indexat pe `cod`), dar **trebuie sa fie garantat sa nu blocheze deschiderea** pe eroare de retea/Oracle. Mitigare: acelasi tipar defensiv ca `IncarcaCursoareModificareNota` (`ofacturare_editare.prg:58-61`) — pe eroare, se comporta ca "nu e factura" (ascunde PAGE3), nu propaga eroarea in sus si nu blocheaza formularul. 3. **Cursoarele noi (`tvd`/`tvanz`) nu trebuie sa interfereze cu `tact`/`trul`/`trul_obinv`** — nume de alias distincte, verificate ca nu exista deja in cod (`tvd`/`tvanz` cautate, 0 rezultate azi). Grid-ul nou trebuie sa aiba `ControlSource` calificat complet pe fiecare coloana (`COMUN\docs\capcana_grid_controlsource.md`) — capcana confirmata activa exact in acest scenariu (3+ griduri pe acelasi formular: `grid1`/`grdRulaje`/`grdRulajeObinv`/noul grid). 4. **Scrierea (nu doar afisarea)**: partea cea mai sensibila. Scrierea noua in `VANZARI_DETALII` (E, S5) trebuie sa fie **strict gatata de `This.lAreArticoleVanzari`**, apelata din apelanti (`do_editare_factura`/`afisjurcom.do_modifica`) DOAR dupa ce pasul existent `finalizeaza_modificare_nota` a reusit deja — deci pe orice nota fara rand in `VANZARI`, pasul nou nu se executa niciodata (flag-ul e `.F.`), cod identic cu azi. 5. **`gridextra1.setup()`** (`:13729`) — salveaza/restaureaza preferinte per-grid, cheie `SYS(1272, grid)`. Grid-ul nou (`pgfArticole.PAGE3.grdArticoleFactura`) e complet nou, deci nu are preferinte salvate de niciun utilizator — capcana din `capcana_grid_preferinte_utilizator.md` (coloana noua intr-un grid EXISTENT ajunge la coada) nu se aplica la infiintare, doar daca se adauga o coloana ulterior. **Neverificat**: daca `gridextra1` inregistreaza automat orice grid nou de pe formular sau necesita inregistrare explicita — de confirmat direct in `gridextras.vc2` la implementare, nu presupus aici. **Cum se testeaza D**: un caz de test obligatoriu (deja in S8 din plan) e "document care nu e factura, deschis din registrul jurnal — pagina de articole nu apare si comportamentul e identic cu azi". Recomand completarea lui cu: (a) o rulare explicita cu Oracle temporar indisponibil pe interogarea din A.3 (verifica gracious degradation, punctul 2 de mai sus), (b) o comparatie byte-cu-byte a XML-ului salvat de `salveazaxml` (`:13690-13717`) inainte/dupa modificare, pe un document non-factura, ca sa confirme ca noul cod n-a atins deloc acel drum. ## E. Impartirea in runde de implementare Ordonat pe risc, cu rezultat testabil la finalul fiecarei runde. S1-S3 (deja facute) raman runda 0. **Runda 1 — PAGE3 doar afisare, fara scriere** (depinde doar de VFP + Oracle read-only, nu de S5) - A.2 (PageCount/Caption/grid nou) + A.3 (detectie factura, in `frm_modific2024`) + B (incarcare `tvanz`/`tvd`, read-only). - Grid needitabil (`ReadOnly=.T.` pe toate coloanele), fara buton de salvare separat pe pagina. - *Gata cand*: PAGE3 apare pe orice document cu rand in `VANZARI` (facturi, avize, transfer, custodie — decizia 19), din ambele puncte de intrare, arata liniile corecte; pe orice document fara rand in `VANZARI` dispare complet (testul de risc D). - **Nu depinde de S5.** Se poate livra si testa independent. **Runda 2 — editare in memorie, fara scriere in Oracle** - Grid editabil (B.2, marcaje `_modificat`/`sters`/`id_vanzare_det=0`), dialogul per-linie (reutilizarea `frm_articol_factura`, vezi nota tehnica de mai jos), adaugare/stergere linie in cursor, discount de antet editabil in `tvanz`. - Subtotalul live pe linie (C.2, calcul simplu VFP). - *Gata cand*: utilizatorul poate adauga/sterge/modifica linii in grid, vede subtotaluri live; `Renunta` lasa totul neschimbat; `Termina` **nu** scrie inca nimic in `VANZARI_DETALII` (doar nota contabila, ca azi). - **Nu depinde de S5** — poate rula complet pe VFP, testabil headless fara risc de scriere Oracle. **Runda 3 — S5 (Oracle) + scrierea reala** - Procedura `recalculeaza_totaluri_vanzari` (Oracle, `rec_s5_oracle_vanzari.md` sectiunea B) + procedurile de UPDATE/INSERT/soft-DELETE pe `VANZARI_DETALII` (`rec_cale_vanzari_detalii.md` sectiunea 4, Varianta B). - Scrierea efectiva din VFP: apel nou, simetric in ambii apelanti, gatat de `Omodif.lAreArticoleVanzari`, dupa `finalizeaza_modificare_nota` reusit (D.4). - *Gata cand*: dupa `Termina`, `VANZARI_DETALII`/`VANZARI` reflecta editarea; S7 (rotunjire la reeditare) verificat pe acest flux. - **Depinde de Runda 2** (cursorul editat trebuie sa existe) si de S5/S6 din planul general. **Runda 4 — S4b complet (helpere/verificari)** - C.1-C.6: totalurile de control (interogare directa a functiilor Oracle existente, nu formula VFP), indicatorul de stare, actiunea explicita de sincronizare. - *Gata cand*: criteriile din plan_06 S4b (indicator vizibil, propunere enumerata, refuzul nu modifica nimic). - **Depinde de Runda 3** — comparatia cu ACT/VANZARI_DETALII n-are sens pana nu exista scriere reala de comparat. **Nota tehnica pentru Runda 2**: dialogul per-linie recomandat e **reutilizarea** `frm_articol_factura` (`COMUN\clase\ofacturare.vc2:2315-...`, deschis azi din `frm_facturare_articole.do_modifica`, `ofacturare.vc2:13746-13844`, model documentat si in `plan_06_editare_factura.md` "Ce preda #7 catre S6"). Dialogul citeste `PRIVATE poArticol` (setat de apelant inainte de `Createobject`) si `Lparameters tnCantitate, tlAscunde` — **fara plafon** (decizia 15), `tnCantitate` se transmite cu o valoare santinela mare (ex. `999999999`), nu se recalculeaza din stoc. `poArticol` asteptat de dialog are un set bogat de proprietati calculate (`valftva`, `vval*`, etc. — vezi lista completa la `ofacturare.vc2:13835-13840`), diferite de coloanele brute din `VANZARI_DETALII`; adaptorul nou trebuie sa populeze campurile de baza (`pret_achizitie, cantitate, id_articol, cont, id_gestiune, proc_tvav, pretftva/pretctva dupa flag, discount_unitar, id_valuta, ...`) din `tvd`, apoi sa cheme aceeasi functie VFP `calculeaza_totaluri(poArticol)` (apelata deja la `:13875` pentru randuri noi) ca sa deriveze restul — **nu se reinventeaza formula**, se refoloseste exact ca la compunere. Ramura `do_alege_stoc` (redeschiderea dialogului de gestiuni, folosita azi doar la compunere) **nu se foloseste in #6** — decizia "fara verificare de stoc" (15) inseamna ca toate liniile, gestionabile sau nu, trec prin acelasi dialog simplu. ## F. Intrebari pentru Marius 1. **[DECIS — decizia 19 din progres.md, vezi A.3]** Nu strict facturi: pagina apare pe **orice rand din `VANZARI`**, deci si pe avize, transfer si custodie. Varianta "strict facturi" recomandata initial in A.3 a fost respinsa explicit de Marius. 2. **[REZOLVAT — vezi C.1]** Contul nu e fix `4111`: regula e pe tip de document (facturi `4111`, avize `418`, avize catre clienti debitori `461`), verificata pe 360 de documente / 12 tipuri / 3 scheme (`docs\cercetare\rec_suma_act.md`). Raman deschise, fara sa infirme regula: 5 documente `ROMFAST` fara nicio nota `ACT` si un document `VENDING` in valuta (`cod=1165566`) cu diferenta neexplorata. 3. **[REZOLVAT — vezi C.1]** Regula gasita: perechile `cant`/`cante` marcate `ID_TIP_RULAJ=3` sunt randuri de diferenta de pret (`PACK_FACTURARE.descarca_gestiune`), de exclus randul cu pretul vechi din stoc. Formula `SUM(CANT*PRETVTVA) + SUM(CANTE*PRETVTVA WHERE ID_TIP_RULAJ<>3)` reproduce exact totalul pe documente cu toate liniile stocate; pe documente mixte se corecteaza cu liniile nestocate (C.1). 4. **UX-ul concret al zonei de totaluri si al indicatorului** — trei variante, cu recomandare: **Varianta A (recomandata) — bara de totaluri sub grid-ul PAGE3, indicator ca punct colorat + text:** ``` +-----------------------------------------------------------------------+ | [Articole factura] Discount document: [____] % | | +---------------------------------------------------------------+ | | | Articol | Cant | Pret | Cu TVA | ... | | | | ... | | | +---------------------------------------------------------------+ | | Total ACT (contabil): 1924.59 lei | | Total VANZARI_DETALII: 1924.59 lei | | Total RUL (formula C.1): 1924.59 lei [*] Sincronizat | | [Verifica sincronizare] [Propune] | +-----------------------------------------------------------------------+ ``` Exemplu `cod=1140888` (C.1): dupa formula corecta, cele trei sume coincid — nu mai e un caz care sa ilustreze o divergenta. Pentru un document mixt (linii stocate + nestocate, decizia 25), randul RUL se marcheaza explicit ca ajustat, de exemplu: ``` | Total RUL (ajustat, +linii nestocate): 1170.00 lei | ``` Simplu, aliniat cu `_grdfooter1` deja existent pe PAGE1/PAGE2 (acelasi loc, acelasi stil vizual). **Varianta B — indicator langa caption-ul paginii** (`PAGE3.Caption = "Articole factura ⚠"` sau cu iconita), totalurile doar la cerere (buton "Arata totaluri de control" care deschide un dialog separat). Mai compact, dar ascunde informatia pana la un click — risc sa nu fie observat. **Varianta C — culoare de fond pe intreaga pagina** (rosu deschis) cand desincronizat, fara text explicit pana la deschiderea dialogului de sincronizare. Cel mai putin verbose, dar ambiguu (utilizatorul nu stie CE e desincronizat fara sa deschida dialogul). Recomand **A** — respecta convenția UX (`conventie_ux_formulare.md`: informatia de control trebuie vizibila, nu ascunsa dupa un click) si reutilizeaza tiparul deja vizual familiar din PAGE1/PAGE2 (footer de sume sub grid). 5. **Dialogul de propunere de sincronizare (C.4)** — schita: ``` +---------------------------------------------------------+ | Propunere sincronizare (sursa: Articole factura -> Rulaj)| | +-------------------------------------------------------+| | | Articol | Rulaj (vechi) | Articol (nou) | || | | Piesa X | cant=2 pret=100 | cant=3 pret=110 | || | | Piesa Y | -- (fara rulaj) | cant=1 pret=50 | || | +-------------------------------------------------------+| | [Alege directia: Articol->Rulaj | Rulaj->Articol]| | [Aplica in memorie] [Renunta] | +---------------------------------------------------------+ ``` De confirmat daca alegerea directiei e un singur radio-button global (recomandat, C.4 punctul 2) sau daca Marius vrea control per-linie (mai flexibil, mult mai complex de implementat si de explicat utilizatorului — nerecomandat pentru complexitatea/beneficiul). ## Ce nu am putut verifica - Daca `gridextra1.setup()` inregistreaza automat grid-uri noi de pe formular (D.5). - Comportamentul `_grdfooter`/`attachtogrid` pe un grid gol (0 randuri) la prima deschidere a PAGE3 — nu a fost testat, doar citit codul PAGE1/PAGE2 ca precedent. (Cele trei puncte legate de formula `ACT`/`RUL` care erau listate aici — divergenta 903.53 vs 1924.59, regula perechilor `cant`/`cante`, stabilitatea contului `4111` — s-au rezolvat prin cercetarea din `docs\cercetare\rec_suma_act.md` si sunt acum in C.1 / F.2 / F.3.)