# Cercetare S1-S3 (plan_06_editare_factura.md) - stare cod la 08.08.2026 Refera ancorele planului dupa commit-urile #7/#8. Toate liniile de mai jos sunt din textul `.vc2` regenerat de `git_sync.ps1` in aceasta sesiune (deci la zi cu binarul). ## A. Ancore re-verificate ### A1. frm_facturi.do_sterge - COMUN\clase\ofacturare_comun.vc2:4501-4717 Clasa `frm_facturi` incepe la `ofacturare_comun.vc2:1168` (mosteneste `_frmbase`). Metoda `do_sterge` e imediat dupa `do_modifica_explicatie` (4482-4499) si inainte de `do_verifica` (4719-4766). Structura pe pasi: 1. `4502-4508`: citeste `gnLuna`/`gnAn` in variabile, iese daca `crsfacturi` e gol. 2. `4516-4518`: garda **luna inchisa** (`glLunaInchisa`) - `Return` fara mesaj. 3. `4520-4527`: pozitioneaza pe randul curent din `crsfacturi`, citeste `id_vanzare`, `cod`, an/luna din `data_act`, `sters`, `eproforma`. 4. `4529-4536`: daca deja sters -> mesaj si `Return`; confirmare cu `amessagebox(...,4+32,...)`. 5. `4541-4544`: garda **luna curenta** - `(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna` -> mesaj si `Return`. 6. `4546-4559`: ramura separata **STERGERE PROFORMA** (`eproforma=1`) - apeleaza direct `pack_facturare.sterge_proforma(pnIdVanzare,gnIdUtil)` si iese cu `RETURN`, **inainte** de garda de referinte de mai jos. Facturile/avizele nu intra pe aceasta ramura. 7. `4562-4567`: garda **referinte incasari/plati** - `ReferinteDocumenteNota(pnAn, pnLuna, lnCod)` (definita in `COMUN\programe\odocumente.prg:8`) -> daca `.T.`, mesaj si `Return`. 8. `4569-4614`: incarca cursoare pe `cod` din `vact_tot`/`vrul_tot`/`vrul_obinv_tot` (schema `gcs`), filtrate `sters=0 and an=gnAn and luna=gnLuna and cod=lnCod`, in `actactan`/ `rul_temp`/`rul_temp_obinv`. 9. `4617-4620`: daca sunt randuri in `actactan`, deschide formularul modal `verificare` (confirmare vizuala inainte de stergere efectiva). 10. `4622-4685`: daca `buton=1` din `verificare`, trece manual pe tranzactie (`SQLSetprop(gnhandle,"Transactions",2)`), apeleaza `OSCRIE_IN_FISIERE(2,.F.,llRul)`, apoi `pack_contafin.finalizeaza_stergere_nota(pnLuna,pnAn,Null,lnIdSet,lnCod,lnIdFact,lnIdFactD, gnIdUtil)`, COMMIT/ROLLBACK dupa rezultat, revine pe tranzactie automata. 11. `4686-4701`: ramura alternativa (fara randuri in `actactan`, adica document fara nota) - apel direct `pack_facturare.sterge_factura(pnIdVanzare,gnLuna,gnAn,gnIdUtil)`. 12. `4707-4716`: inchide cursoarele temporare. **Nu exista nicio verificare eFactura in do_sterge** - vezi A3, e o corectie fata de plan. ### A2. Cele 3 garzi lipsa din do_modifica - confirmate, linii curente Toate trei sunt in `do_sterge` (A1) si lipsesc din `do_modifica` (`ofacturare_comun.vc2:4381-4480`, care nu verifica deloc luna sau referinte, doar `sters`+eFactura, vezi A3): - **Luna inchisa**, `ofacturare_comun.vc2:4516-4518`: ``` If glLunaInchisa Return Endif ``` - **Luna curenta**, `ofacturare_comun.vc2:4541-4544`: ``` If (pnAn * 12) + pnLuna <> (gnAn * 12) + gnLuna amessagebox('Nu puteti sterge decat inregistrari din luna curenta!',0,'Atentie!') Return Endif ``` Text hardcodat pe "stergere" - la reutilizare pentru editare trebuie schimbat mesajul. - **Referinte incasari/plati**, `ofacturare_comun.vc2:4562-4567`: ``` *** verificare restrictie stergere documente cu referinte (incasari/plati) llReferinteDocumente = ReferinteDocumenteNota(pnAn, pnLuna, lnCod) && && odocumente.prg If llReferinteDocumente amessagebox("Documentul are referinte (incasari/plati). Nu poate fi sters.", 0+48,"Stergere") Return Endif ``` Idem, mesajul e specific stergerii. ### A3. Garda eFactura - CORECTIE fata de plan: e in do_modifica, NU in do_sterge Cautare exhaustiva `anaf_efactura` in `ofacturare_comun.vc2`: **o singura aparitie**, la linia 4426, in interiorul lui `do_modifica` (4381-4480). `do_sterge` nu contine deloc `anaf_efactura`. Cod exact, `ofacturare_comun.vc2:4426-4430`: ``` lcSql = [select count(*) as lneFactura from anaf_efactura where id_fact = ] + ALLTRIM(STR(poRec.id_fact)) pneFactura = 0 llSucces = goExecutor.oSelecteaza2Value(m.lcSql, @pneFactura) If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0 ``` (`pneFactura`/`pnEFactura` e aceeasi variabila, VFP e case-insensitive.) Garda e refolosibila ca atare (interogare + conditie), dar trebuie extrasa dintr-un `If` care astazi conditioneaza doar deschiderea dialogului `frm_modifica_factura` - pentru actiunea noua S1 trebuie sa devina un `Return` explicit cu mesaj, dupa modelul celorlalte garzi din `do_sterge`, nu o simpla conditie de `If`. ### A4. Mecanismul de drepturi pe frm_facturi Nu exista o proprietate `lactiv3`/`lactiv4` setata explicit in `ofacturare_comun.vc2` - ele sunt proprietati generice mostenite din `_frmbase` (`_frm_base.vc2:7`), populate dinamic din `gcAcces` de metoda comuna `actualizeaza_drepturi`, `_frm_base.vc2:195-228`: - Format `gcAcces = "opt1;opt2;...;optN;"` (string cu numere separate prin `;`). - Pentru fiecare token `N` prezent, seteaza `thisform.lactivN = .T.` (linia 203-205: `lcProp='thisform.lactiv'+Alltrim(lcAcces)` + `&lcProp=.T.`). - Daca exista si o proprietate `thisform.cbutonN` (lista de nume de butoane separate prin `;`), seteaza `.Visible = .T.` pe fiecare buton din lista (206-221). Uzul din `inainte_de_do_modifica`/`inainte_de_do_sterge` (`_frm_base.vc2:476-481, 493-498`): `If This.lactiv3 Then This.do_modifica()` / `If This.lactiv4 Then This.do_sterge()`. Deci `lactivN` gateaza EXECUTIA actiunii, `cbutonN` gateaza VIZIBILITATEA butoanelor asociate. **Tokenii folositi azi de frm_facturi** (proprietati proprii clasei, `ofacturare_comun.vc2:1352-1353`): - `cbuton2 = but_listare1;but_listare2;But_listare3` (token "2" = listare) - `cbuton3 = but_modifica1;but_modifica2` (token "3" = modificare - **ambele** butoane de modificare, cel de antet si cel de explicatie articol, vezi A5) - Tokenul "4" (stergere) nu are `cbuton4` definit pe `frm_facturi` - vizibilitatea lui `but_sterge1` e gestionata separat, direct in `Init` (`4770-4773`): daca `glLunaInchisa`, scoate manual `"4;"` din `gcAcces` si ascunde butonul. `lactiv4` insa tot se seteaza normal din `gcAcces` (prin mecanismul generic), si `but_sterge1.Click` foloseste implicit `caction = inainte_de_do_sterge` (default din clasa de baza `but_modifica`/`but_sterge`, `cmd_butoane.vc2:358`), care verifica `This.lactiv4`. - Tokenul "1" nu e folosit de `frm_facturi` (fara `cbuton1`) - liber pentru o semnificatie noua daca s-ar dori, dar mai curat e un token nou (ex. "5"). **Sursa lui `gcAcces`**: variabila globala PUBLIC (comentariul `*:Global gcAcces`, `ofacturare_comun.vc2:4770`), NU e setata in codul lui `frm_facturi` sau in procedura care il deschide (`COMUN\programe\oproceduri_facturare.prg:416, 505` - `Createobject("frm_facturi")` fara nicio atribuire de `gcAcces` inainte). E populata inainte, la click pe iconita de pe ecranul-fundal (`ofundal.vc2:69,186,311,391` - `gcAcces = This.coptiuni_active`), unde `coptiuni_active` per iconita vine din `dezactiveaza_imagini` (`COMUN\programe\acces_meniu.prg:39-80`), care citeste central din view-ul Oracle `contafin_oracle.vdef_util_obiecte` (interogat in `citeste_drepturi`, `acces_meniu.prg:17-37`, filtrat pe `id_util`/`id_program`/`id_firma`) si mapeaza pe cheia iconitei (`cheie`) ultima cifra la un token numeric. Editarea drepturilor per grup se face prin `PACK_DREPTURI.grupdreptmodproc` (`COMUN\clase\drept_grupuri.vc2:39`, apelat din `frm_grupuri`). **Nu am gasit** un catalog central editabil in VFP care sa enumere sensul fiecarui token numeric per program (ex. un tabel `optiuni_program` cu eticheta "3 = modificare"). Sensul e o conventie fixata in cod (proprietatile `cbutonN` din fiecare clasa de formular) - vezi intrebarea D2. ### A5. frm_facturi.do_modifica - CORECTIE fata de descrierea din task/plan **Contrar formularii din plan_06 ("butonul existent din frm_facturi deschide frm_modifica_articol_factura, care editeaza doar explicatie si taxcode")**, in codul de azi exista DOUA actiuni distincte de "modificare" pe `frm_facturi`, ambele gateate de acelasi token "3" (`cbuton3`), dar cu efecte diferite: 1. **`do_modifica`** (`ofacturare_comun.vc2:4381-4480`), legata de `but_modifica1` (butonul din bara de sus, `Left=609`, fara `caction` explicit -> foloseste default-ul din clasa de baza `but_modifica` = `caction = inainte_de_do_modifica` -> `This.lactiv3` -> `do_modifica()`). Deschide **`frm_modifica_factura`** (antet document) si, la `gnButon=1`, ruleaza `pack_facturare.modifica_date_factura(...)` pe UNA sau MAI MULTE facturi (dupa selectie multipla `ales=1`) cu campurile: `id_ruta`, `id_delegat`, `id_agent`, `id_masina`, `dataora_exp`, `id_facturare`, `listare_detaliata`, `text_aditional`, `tip_saft`, `efactura`(flag intentie trimitere), `data_act`, `data_scad`, `numar_act`, `serie_act`. **Niciun camp de suma/cantitate/pret.** Contine garda eFactura (A3). 2. **`do_modifica_explicatie`** (`ofacturare_comun.vc2:4482-4499`), legata de `But_modifica2` (langa grid-ul de detalii, `caction = do_modifica_explicatie` explicit, `ofacturare_comun.vc2:1433-1441`, tooltip "Modificare explicatie articol"). Deschide **`frm_modifica_articol_factura`** (`ofacturare_comun.vc2:4959`, caption "Modifica explicatie articol"), care editeaza DOAR `explicatie` (memo) si `taxcode` (combo SAFT) pe linia curenta din `crsDetalii`. Garda: doar `poRec.sters = 0` - **fara verificare eFactura**. Deci descrierea corecta pentru plan: actiunea care deschide `frm_modifica_articol_factura` e `do_modifica_explicatie` (nu `do_modifica`), iar niciuna din cele doua actiuni existente nu atinge sume/cantitati - confirma nevoia unei actiuni noi (S1), dar sablonul de clonat pentru garzi ramane `do_sterge`, nu vreuna din cele doua `do_modifica*`. ### A6. afisjurcom.do_modifica - COMUN\clase\comun.vc2:2222-2563 Clasa `afisjurcom` (extinde `_frmbase`). Pasi: 1. `2230-2232`: `If !Thisform.lactiv3 Then Return` (acelasi mecanism de drept ca A4). 2. `2238-2240`: garda luna inchisa (`glLunaInchisa`). 3. `2242-2258`: determina daca se arata si randurile sterse (`lleSters`, dupa filtrul curent), citeste `cod`/`an`/`luna`/`id_set`/`sters`/`id_fact`/`id_factd` din `actjur`. 4. `2265-2268`: garda luna curenta - **acelasi tipar** ca in `do_sterge`: `(pnAn*12)+pnLuna <> (gnAn*12)+gnLuna` -> mesaj -> `Return`. 5. `2278-2281`: garda suplimentara - `id_set` intre 30000-30009 (note din ROAPRODUCTIE) -> blocate necontional. 6. `2313-2332`: inchide cursoarele reziduale `actactan`/`tact`/`rul_temp`/`trul`/ `rul_temp_obinv`/`trul_obinv` daca sunt deschise. 7. `2352-2368`: incarca `vact_tot` in `actactan` -> `tact` (READWRITE), filtrat `sters=0 and an=gnAn and luna=gnLuna and cod=lnCod` (daca nu se arata stersele) sau fara filtrul de sters, ORDER BY `id_act`. 8. `2370-2427`: daca succes, incarca similar `vrul_tot` -> `rul_temp`/`trul` si `vrul_obinv_tot` -> `rul_temp_obinv`/`trul_obinv`, cu recalcul de `valoare`/`valtva`/ `valoarev`/`valtvav` pe randurile goale (2383-2387, 2412-2416) inainte de a construi `trul`/`trul_obinv`. 9. `2429-2442`: alege clasa de formular dupa an (`gnAn >= gnAnFormNou` implicit 2007) -> **`frm_modific2024`** (`Createobject([frm_modific2024], lnIdSet)`) sau varianta veche `frm_modific`; `Select tact` inainte de `Omodif.Show()`. 10. `2444-2538`: daca `buton=1`, deschide tranzactie manuala (`do_deschide_tranzactie`), `oscrie_in_fisiere(2,.T.,llRul)`, reconstruieste `actactan`/`RUL_TEMP`/`RUL_TEMP_OBINV` din `tact`/`trul`/`trul_obinv` cu `id_util`/`sters=0`, apoi `oscrie_in_fisiere(0,.T.,llRul)`, apoi **`pack_contafin.finalizeaza_modificare_nota(pnLuna,pnAn,pdDataOra,lnIdSet,lnCod, lnIdFact,lnIdfactd,gnIdUtil)`** (2484-2487), `do_inchide_tranzactie` si `do_cauta` la final. 11. Cod comentat (2496-2513, dezactivat) arata o incercare anterioara de a apela direct `pack_facturare.actualizeaza_vanzari` din client dupa `finalizeaza_modificare_nota` - azi e mort, apelul real se face DOAR server-side, in interiorul lui `finalizeaza_modificare_nota` (confirma faptul deja stabilit in `progres.md`). 12. `llVanzari` e declarata (`Store .F.`, 2235) dar logica ei de activare e tot comentata (2292-2307) - variabila ramane mereu `.F.`, deci sincronizarea cu `VANZARI` e complet transparenta pentru `afisjurcom`, indiferent de tipul documentului. ### A7. frm_modific2024 - COMUN\clase\omodificari.vc2:6375-... Clasa (`DEFINE CLASS frm_modific2024 AS _frmbase OF "_frm_base.vcx"`) incepe la linia 6375. Metodele proprii merg de la `Activate` (12238) pana la ultimul handler de grid (`pgfArticole.PAGE2.grdRulajeObinv.Init`, 15422-15424) - interval `12238-15424`, usor deplasat fata de planul vechi (`12200-15319`). **Contract de intrare** (`Init`, `13551-13660`): ``` Lparameters tnIdSet, tlNotaNoua, toBackupXML, toSet, tlVizualizare ``` - `tnIdSet`: id-ul setului de nota (obligatoriu, stocat in `This.nid_set`). - `tlNotaNoua`: `.T.` daca vine din nota fara predefinire. - `toBackupXML`, `toSet`: obiecte optionale (backup XML, respectiv setul de editare restrictionata "doar Salveaza/Renunta" - `This.lEditare`). - `tlVizualizare`: parametru opus, numeric sau logic - `1`/`.T.`=vizualizare, `2`=modificare (default), `3`=verificare note (`13576-13591`). - **Nu primeste cursoare ca parametru.** Formularul se leaga la aliasul curent `tact` (setat de apelant cu `Select tact` inainte de `Createobject`) - grid-ul principal `Grid1` are `RecordSource` legat implicit pe `tact` (conventie mostenita, nu vazuta explicit in Init, dar confirmata de apelul din A6 pas 9). Grid-urile din pageframe au `RecordSource` FIX in definitia clasei: `pgfArticole.PAGE1.grdRulaje.RecordSource = "trul"` (`omodificari.vc2:8669`) si (dupa acelasi tipar, de verificat direct) `grdRulajeObinv` pe `trul_obinv`. **Deci apelantul trebuie sa aiba deschise, cu exact aceste nume de alias, cursoarele `tact`/`trul`/`trul_obinv` READWRITE inainte de instantiere** - exact ce face A6 pas 7-8. - **Iesire**: `do_termin` nu e suprascrisa in `frm_modific2024` - foloseste default-ul din `_frmbase` (`_frm_base.vc2:363-376`, seteaza `gnButon=1`/`Buton=1` si inchide/ascunde), dar trece prin `inainte_de_do_termin` proprie, foarte lunga (`13357-13549`, ~192 linii) - acolo e validarea grea (verificari de total, TVA exigibil etc.) inainte sa lase `buton=1`. **Orice validare noua legata de sume factura trebuie sa intre in acest lant**, nu doar in `do_salvare`. - **La iesire cu `buton=1`, cursoarele `tact`/`trul`/`trul_obinv` raman deschise** (formularul nu le inchide) - apelantul (A6 pas 10) le reciteste in `actactan`/`RUL_TEMP`/`RUL_TEMP_OBINV` dupa `Show()`. **Pageframe existent** (`pgfArticole`, `omodificari.vc2:8627-8642`, doar 2 pagini azi): ``` PAGE1.Caption = "Rulaje materii prime, materiale, marfuri, obiecte inventar (303)" (grid grdRulaje pe trul) PAGE2.Caption = "Rulaje obiecte inventar in folosinta (8039)" (grid grdRulajeObinv pe trul_obinv) ``` Nu exista azi PAGE3 - de adaugat pentru S4. ### A8. Butonul/actiunea in bara formularului si modelul de adaugare Modelul concret (`But_modifica2`, `ofacturare_comun.vc2:1433-1441`): ``` ADD OBJECT 'But_modifica2' AS but_modifica WITH ; Anchor = 12, ; caction = do_modifica_explicatie, ; Caption = "", ; Left = 710, ; Name = "But_modifica2", ; TabIndex = 27, ; ToolTipText = "Modificare explicatie articol", ; Top = 341 ``` Dispatch generic: `Click` din clasa de baza a butoanelor (`_cmd_base.vc2:41-...` si a doua implementare la `120-...`) citeste `This.cAction` si il executa pe `Thisform` (cu `This.clistaparametri` optional ca argument). Deci un buton nou nu are nevoie de propriul `Click` - doar de `caction = `. Pentru o actiune noua gateata de drept (ca `but_modifica1`, nu ca `But_modifica2`): 1. Adauga metoda `do_editare_sume` (sau numele ales) pe `frm_facturi`. 2. Adauga `ADD OBJECT 'But_editare_sume1' AS but_modifica WITH ... caption/picture/tooltip/ pozitie ...` (poate mosteni orice clasa vizuala din `cmd_butoane.vcx`, nu neaparat `but_modifica`). 3. Daca actiunea trebuie gateata separat de token-ul "3" (modificare antet/explicatie) - decizie de arhitectura, vezi D1 - adauga `inainte_de_do_editare_sume` proprie care verifica `This.lactivN` (N = tokenul nou ales, ex. "5"), si seteaza `caction = inainte_de_do_editare_sume` pe buton (dupa modelul `but_modifica1`, care NU seteaza caption explicit pe buton ci mosteneste `inainte_de_do_modifica` din `cmd_butoane.vc2:188`). 4. Adauga proprietatea `cbuton5 = But_editare_sume1` pe `frm_facturi` (langa `cbuton2`/`cbuton3` existente, `ofacturare_comun.vc2:1352-1353`) ca butonul sa fie ascuns automat cand tokenul "5" lipseste din `gcAcces` (mecanismul din A4). 5. Vezi `COMUN\docs\conventie_ux_formulare.md` pentru pozitionare/anchor in bara existenta. ## B. Deosebiri de fond fata de plan 1. **Garda eFactura NU e in `do_sterge`, e in `do_modifica`** (A3). Planul o citeaza gresit ca parte a sablonului `do_sterge` ("Garda eFactura, de refolosit: `ofacturare_comun.vc2:4428-4432`" sub titlul despre `do_sterge`). Practic nu schimba directia (garda tot exista si e refolosibila), dar sursa corecta de citat si tiparul de extras (azi e un simplu `If`, nu un `Return` cu mesaj ca restul garzilor) trebuie corectate in implementare. 2. **`frm_facturi.do_modifica` NU deschide `frm_modifica_articol_factura`** (A5). Planul (si textul din task) atribuie asta lui `do_modifica`; in realitate `do_modifica` deschide `frm_modifica_factura` (antet, alte campuri), iar `frm_modifica_articol_factura` (explicatie+ taxcode) e deschis de `do_modifica_explicatie`, legata de `But_modifica2`. Nu schimba concluzia planului (niciuna din cele doua nu atinge sume), dar numele metodei/formularului de citat in orice implementare viitoare trebuie sa fie cel corect. 3. **Drepturile pe `frm_facturi` nu sunt "lactiv3/lactiv4 + tokeni in gcAcces" ca fapt autonom al formularului** - sunt mecanismul GENERIC din `_frm_base.actualizeaza_drepturi` (A4), aplicat oricarui formular care extinde `_frmbase`. `frm_facturi` doar declara ce inseamna fiecare token pentru el (`cbuton2`, `cbuton3`) si manipuleaza direct `gcAcces`/ vizibilitatea pentru cazul special "luna inchisa" (`Init`, 4770-4773). Nu exista o lista centrala DB-editabila a semnificatiei tokenilor (vezi D2) - planul nu gresea factual, dar ii lipsea acest nivel de detaliu, relevant pentru cum se inregistreaza un token nou. 4. Restul ancorelor (A1, A2, A6, A7) confirma planul, doar cu liniile deplasate de commit-urile #7/#8 - nicio diferenta de fond. ## C. Propunerea de implementare S1-S3 ### Arhitectura: unde se pune ce Decizia lui Marius (progres.md, punctul 5) cere ca garzile sa se aplice pe AMBELE puncte de intrare (`frm_facturi` din ROAFACTURARE si `afisjurcom` din ROACONT/ROAGEST). Azi, garzile "luna inchisa" si "luna curenta" **exista deja si independent** in ambele clase (`do_sterge`/A1 respectiv `do_modifica`/A6) - fiecare punct de intrare are propria lor copie, pattern deja folosit in cod (nu e o incalcare noua sa le duplic). Garda "referinte incasari/plati" si garda "eFactura" insa **exista azi doar in `frm_facturi`** (ROAFACTURARE) - `afisjurcom.do_modifica` nu le are deloc. Recomandare: - **`ReferinteDocumenteNota`** (`COMUN\programe\odocumente.prg:8`) e deja in `COMUN`, deci reutilizabila ca atare din `afisjurcom.do_modifica` fara nicio mutare de cod - se apeleaza cu aceiasi parametri (`an`, `luna`, `cod`), doar ca `afisjurcom` trebuie sa stie cand documentul curent e o factura (vezi mai jos). - **Garda eFactura** foloseste `poRec.id_fact` - `afisjurcom` are deja `lnIdFact`/`lnIdfactd` (A6 pas 3) din `actjur`, deci parametrul exista, doar interogarea (azi inline in `do_modifica` a lui `frm_facturi`) trebuie extrasa intr-o functie mica in `COMUN\programe\` (ex. `EsteInEFactura(tnIdFact)`) ca sa fie apelabila din ambele clase fara duplicare literala a SQL-ului. - Cazul "documentul curent e o factura de vanzare" trebuie detectat in ambele puncte de intrare (nu doar in `frm_facturi`, care STIE deja ca lucreaza cu facturi) - pentru `afisjurcom` inseamna un test suplimentar (ex. `id_set` intre valorile care corespund facturarii, sau existenta unui rand in `vanzari` cu acel `cod`) inainte de a aplica garda eFactura/referinte - pe alte tipuri de note aceste garzi nu au sens si nu trebuie sa apara. - **Cel mai simplu 80/20**: o singura functie noua in `COMUN\programe\` (langa `odocumente.prg` sau intr-un fisier nou `ofacturare_editare.prg`), ex. `VerificaEditareFactura(tnCod, tnAn, tnLuna, tnIdFact)`, care ruleaza toate garzile aplicabile facturii (eFactura + referinte; luna inchisa/curenta raman ca azi, duplicate local, pentru ca deja exista identic in ambele clase) si intoarce `.T./.F.` + mesajul de eroare deja afisat. Apelata din `frm_facturi` (actiune noua, S1) SI din `afisjurcom.do_modifica` (adaugare minima, cateva linii), cu un test prealabil "e factura?" facut de fiecare apelant dupa contextul lui. ### S1 - Actiunea noua in frm_facturi - Metoda noua `do_editare_sume` (nume de discutat) pe `frm_facturi` (`COMUN\clase\ofacturare_comun.vc2`), clonata dupa scheletul de garzi din `do_sterge` (A1 pasii 1-7), dar FARA ramurile de stergere efectiva (pasii 8-12) - se opreste dupa garzi si preda la S2/S3. - Buton nou dupa modelul A8, cu `caption = do_editare_sume` (sau `inainte_de_do_editare_sume` daca se doreste gating explicit prin `lactivN`), token nou in `gcAcces` (propun "5", primul liber - A4) + `cbuton5` pe `frm_facturi`. - Semnatura: fara parametri (citeste contextul din `crsfacturi`/pozitia curenta, ca `do_sterge`). ### S2 - Incarcarea cursoarelor (COMUN, refolosibila) Extrage pasii 7-8 din A6 (incarcarea `vact_tot`/`vrul_tot`/`vrul_obinv_tot` in `tact`/`trul`/`trul_obinv`, filtrate pe `cod`+`an`+`luna`) intr-o procedura comuna, ex. `IncarcaCursoareModificareNota(tnCod, tnAn, tnLuna, tlAratasterse)` in `COMUN\programe\`, apelata identic din `afisjurcom.do_modifica` (inlocuind codul inline de azi, refactorizare minima) si din noua actiune din `frm_facturi`. Asta e singura cale sa se garanteze ca cele doua puncte de intrare incarca EXACT acelasi lucru, cerinta explicita a lui Marius. ### S3 - Deschiderea frm_modific2024 (cod apelant ~40 linii) Schita (in `frm_facturi.do_editare_sume`, dupa ce S1 a validat garzile si S2 a incarcat cursoarele): ```foxpro PROCEDURE do_editare_sume * garzi S1 (eFactura, referinte, luna inchisa/curenta) - vezi A1, A3 ... Local lnCod, pnAn, pnLuna, lnIdSet, lnIdFact, lnIdFactD * citeste cod/an/luna/id_set/id_fact/id_factd din crsfacturi, ca in A1 pas 3 If !IncarcaCursoareModificareNota(lnCod, pnAn, pnLuna, .F.) && S2, COMUN Return Endif If Reccount('actactan') = 0 amessagebox("Nu exista nota contabila pentru aceasta factura.",0+48,"Atentie") Return Endif Select tact Local Omodif Omodif = Createobject([frm_modific2024], lnIdSet) Omodif.Show() If Omodif.gnButon = 1 && sau variabila globala Buton, ca in A6 pas 10 If Thisform.do_deschide_tranzactie() lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.) If lnSucces > 0 * reconstruieste actactan/RUL_TEMP/RUL_TEMP_OBINV din tact/trul/trul_obinv, ca in A6 ... lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.) Endif If lnSucces > 0 lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end;] && A6 pas 10 lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1) Endif Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1)) If lnSucces > 0 Thisform.do_cauta() Endif Endif Endif * inchide actactan/rul_temp/rul_temp_obinv/tact/trul/trul_obinv ENDPROC ``` Notă: `do_deschide_tranzactie`/`do_inchide_tranzactie` exista deja pe `_frmbase` (`_frm_base.vc2:252-265` si un omolog de inchidere, de verificat numele exact la implementare - `afisjurcom` il foloseste direct, A6 pas 10) - de reutilizat, nu de reprodus manual ca in `do_sterge` (care foloseste `SQLSetprop` direct, tipar mai vechi). ### Fisiere atinse (estimare S1-S3) | Fisier | Proiect | Ce se schimba | |---|---|---| | `COMUN\clase\ofacturare_comun.vc2` | COMUN (cross-project) | metoda noua `do_editare_sume` + buton nou pe `frm_facturi`, token nou in `cbuton*` | | `COMUN\clase\comun.vc2` | COMUN (cross-project) | `afisjurcom.do_modifica` - apel la garda noua + la `IncarcaCursoareModificareNota` (inlocuind codul inline) | | `COMUN\programe\odocumente.prg` sau fisier nou `COMUN\programe\ofacturare_editare.prg` | COMUN (cross-project) | functiile comune noi: garda eFactura extrasa, `IncarcaCursoareModificareNota` | | `COMUN\clase\omodificari.vc2` | COMUN (cross-project) | NEATINS in S1-S3 (S4 adauga PAGE3) | Orice modificare in `COMUN\clase\comun.vc2` (`afisjurcom`) afecteaza registrul jurnal din TOATE produsele ROA care il folosesc (ROACONT, ROAGEST, posibil altele) - de tratat cu maxima grija si testat separat de `frm_facturi`. ## D. Intrebari deschise 1. **Ce token numeric folosim pentru dreptul nou** si daca trebuie sa fie distinct de tokenul "3" (modificare) existent, sau daca e acceptabil ca cine are drept de "modificare" (token 3) sa capete automat si dreptul de editare sume. Propunere: token separat (ex. "5"), pentru ca editarea sumelor are impact contabil mult mai mare decat editarea campurilor de antet/ explicatie - un utilizator ar trebui sa primeasca acest drept explicit, nu implicit prin dreptul existent. 2. **Cum se inregistreaza practic un token nou in sistemul de drepturi** ca un administrator sa-l poata acorda per grup din `frm_grupuri` (`COMUN\clase\drept_grupuri.vc2`). Am gasit mecanismul tehnic (`gcAcces` -> `lactivN`/`cbutonN`, populat prin `vdef_util_obiecte` + `PACK_DREPTURI.grupdreptmodproc`), dar nu am gasit un catalog editabil al semnificatiei tokenilor per program - posibil sa fie o eticheta hardcodata undeva neindexat inca in cache-ul text, sau sa fie nevoie de un rand nou in Oracle. De clarificat inainte de S1, altfel tokenul nou risca sa fie "orfan" (functioneaza in cod dar nimeni nu-l poate acorda din UI). 3. **Cum se determina in `afisjurcom` ca documentul curent e o factura de vanzare**, ca sa aplice garda eFactura/referinte doar atunci (S4 foloseste acelasi test pentru afisarea PAGE3). Optiuni: test pe `id_set` (interval cunoscut pentru facturare) sau pe existenta unui rand in `vanzari` cu `cod`-ul curent. A doua varianta e mai robusta (nu depinde de conventia de `id_set`) dar costa un SELECT suplimentar la fiecare deschidere - de decis cu Marius pragul de cost acceptat. 4. ~~Numele exact al metodelor de tranzactie pe `_frmbase`~~ - rezolvat in cercetare: `do_deschide_tranzactie` (`_frm_base.vc2:252-265`) si `do_inchide_tranzactie` (`_frm_base.vc2:279`) exista amandoua pe `_frmbase`, deci reutilizabile ca atare in S3.