Files
comun/docs/flux-modificare-stergere-nota-jurnal.md
Marius Mutu a96b6a6eef #6 editare factura emisa: S9 - ramura de facturi in fluxul notei de jurnal
flux-modificare-stergere-nota-jurnal.md descria doar nota contabila. Documentul
capata ramura de facturi: cele doua puncte de intrare cu garzile lor, pasul nou
din tranzactia manuala, contractul ScrieArticoleFacturaEditate, recalculul din
Oracle si comportamentul gridului de articole.

Doua lucruri contraintuitive, scrise explicit: ID_FACT nu se schimba la reeditare
(COD se realiniaza), deci tot ce se leaga prin id_fact supravietuieste; si garda
de referinte lipseste intentionat pe editarea generica de note din Registrul
Jurnal - protejeaza incasarile la operatia care sterge efectiv factura.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-10 23:43:30 +03:00

11 KiB

Flux: modificare/stergere nota in Registrul Jurnal

Comportament CORECT (nu bug): la modificarea unei note din Registrul Jurnal, documentul original nu se suprascrie. Se marcheaza sters = 1 pe randurile vechi (ACT/RUL/RUL_OBINV), apoi se scrie un document NOU cu alt cod, pastrand acelasi id_fact/id_factd. Ambele operatii ruleaza intr-o tranzactie manuala unica (commit sau rollback pe amandoua).

Unde

  • afisjurcom.do_modifica - COMUN\clase\comun.vc2:2222-2562. Deschide tranzactia manuala (Thisform.do_deschide_tranzactie(), linia 2448), apoi oscrie_in_fisiere(2,...) = STERGE (linia 2451), apoi oscrie_in_fisiere(0,...) = SCRIE (linia 2479), apoi pack_contafin.finalizeaza_modificare_nota(...) (2484-2486), apoi Thisform.do_inchide_tranzactie(...) (linia 2535) - commit daca tot ce a rulat inainte a reusit, rollback altfel.
  • do_deschide_tranzactie/do_inchide_tranzactie (_frmbase, COMUN\clase\_frm_base.vc2:252,279; varianta identica ca procedura globala in COMUN\programe\oproceduri_rulaje.prg:287,303): SQLSetProp(gnHandle,'Transactions',2) la deschidere, SQLCOMMIT/SQLROLLBACK + SQLSetProp(...,'Transactions',1) la inchidere.
  • oscrie_in_fisiere.prg (COMUN\programe\oscrie_in_fisiere.prg): tnScrie_Sterge 0=scriere, 2=stergere. Apeleaza server-side pack_contafin.init_scriere_act_rul_local + final_scriere_act_rul_local -> finalizeaza_scriere_act_rul, care ruleaza SCRIE_IN_ACT (scriere) sau STERGE_DIN_ACT (stergere) din PACK_CONTAFIN.pck.
  • PACK_CONTAFIN.STERGE_DIN_ACT (COMUN\docs\PACK_CONTAFIN.pck:1815-1859): UPDATE ACT SET STERS = 1 ... WHERE COD = tnCod - marcheaza vechiul document, pe cod-ul vechi.
  • PACK_CONTAFIN.SCRIE_IN_ACT (PACK_CONTAFIN.pck:630-901): LN_COD := pack_contafin.GET_COD() (linia 648) aloca un cod nou; UPDATE ACT_TEMP SET COD = LN_COD, ... (linia 897) il scrie pe noul document - ID_FACT nu e atins, ramane cel din documentul original.
  • PACK_CONTAFIN.finalizeaza_modificare_nota (PACK_CONTAFIN.pck:8601-8651): aloca din nou lnCodNou := pack_contafin.get_cod() si actualizeaza pe codul nou vanzari (pack_facturare.actualizeaza_vanzari) si atasamente_vanzari. nom_lucrari se actualizeaza DOAR pentru id_set IN (31003,31004,31005,31011) (repune id_fact), nu general. gest_inventar NU se leaga de cod-ul nou - se identifica dupa dataora_validat + an + luna (cazul id_set = 90101, note de inventariere).

Atentie: nu e valabil la fel pentru stergerea simpla

afisjurcom.do_sterge (comun.vc2:2565-2724) ofera doua optiuni (xmenu, linia 2625):

  • Stergere document (lnOptiune = 1): DOAR OSCRIE_IN_FISIERE(2,...) + finalizeaza_stergere_nota
    • marcheaza sters = 1, NU se creeaza document nou.
  • Anulare document (lnOptiune = 2): STERGE (linia 2698) + SCRIE (linia 2709, cu sumele puse pe 0) - creeaza si document nou, la fel ca la modificare - dar aici cele doua apeluri NU sunt invelite intr-o tranzactie manuala comuna (nu apare do_deschide_tranzactie/ do_inchide_tranzactie in do_sterge); fiecare OSCRIE_IN_FISIERE isi gestioneaza singur commit-ul (vezi tlModificare/llManualTransactions in oscrie_in_fisiere.prg:111-165).

Ramura noua: editare factura de vanzare (VANZARI/VANZARI_DETALII)

Cand documentul modificat prin frm_modific2024 are un rand corespunzator in VANZARI, clasa adauga o pagina noua in pageframe-ul de rulaje, PAGE3 "Articole factura" (COMUN\clase\omodificari.vc2:8707), cu un grid legat pe cursorul tvd (structura view-ului VVANZARI_ARTICOLE). Pe orice alt document (nota fara factura) formularul ramane neschimbat - pageframe-ul are PageCount = 2, ca azi.

Ramura e activa doar cand COMUN\programe\ofacturare_editare.prg e incarcat in SET PROCEDURE (verificat prin "OFACTURARE_EDITARE" $ Upper(Set("Procedure"))) - inregistrat la pornire de toate trei aplicatiile care folosesc frm_modific2024: ROAFACTURARE\Programe\roafacturare.prg:214, ROACONT\Programe\roacont.prg:212, ROAGEST\Programe\roagest.prg:260.

Doua puncte de intrare

  • frm_facturi.do_editare_factura (COMUN\clase\ofacturare_comun.vc2:3715-3872), actiune noua pe formularul de facturi din ROAFACTURARE. Refuza editarea daca documentul e sters, e proforma, nu e din luna curenta (:3742-3755), are referinte de incasari/plati (ReferinteDocumenteNota, :3758) sau a fost trimis in eFactura (EsteInEFactura, in ofacturare_editare.prg, :3764). Inainte de Createobject([frm_modific2024]) incarca crsArticoleFactura cu IncarcaArticoleFactura (:3793), ca gridul din PAGE3 sa se lege o singura data pe cursorul deja plin.
  • afisjurcom.do_modifica (COMUN\clase\comun.vc2:2222-2567) - acelasi punct folosit pentru orice nota din Registrul Jurnal, neschimbat pentru documentele care nu sunt facturi de vanzare. Inainte de Createobject, PregatesteArticoleFacturaEditare('tact') (:2436, in ofacturare_editare.prg) cauta randul din VANZARI corespunzator notei (pe combinatiile cod/nract/serie_act/dataact din tact) si, daca il gaseste, pre-incarca articolele. Pe acest punct de intrare nu se verifica garda eFactura si nici cea de referinte de incasari/plati - doar restrictia de luna curenta, deja existenta pentru orice nota (:2265-2268). Diferenta e intentionata: garda de referinte protejeaza incasarile legate prin id_fact la operatia care sterge efectiv factura; pe editarea de sume din ROAFACTURARE se aplica pentru ca stergerea si rescrierea notei sunt parte din acelasi pas, dar pe editarea generica de note din Registrul Jurnal (care poate sa nu priveasca deloc o factura) nu se aplica.

Daca apelantul nu a putut pregati articolele dinainte, frm_modific2024.Show reface legatura prin IncarcaVanzareDinNota ca fallback si decide acolo daca arata PAGE3 (omodificari.vc2:14769-14794).

Scrierea, in aceeasi tranzactie manuala

La buton = 1 (Terminat), pasul nou se adauga la coada secventei existente de stergere+scriere+realiniere, in aceeasi tranzactie manuala unica, identic pe ambele puncte de intrare (ofacturare_comun.vc2:3828-3830, comun.vc2:2491-2493):

do_deschide_tranzactie()
  oscrie_in_fisiere(2,...)                        -- sterge nota veche (ACT/RUL)
  oscrie_in_fisiere(0,...)                        -- scrie nota noua, cod nou
  pack_contafin.finalizeaza_modificare_nota(...)  -- realiniaza VANZARI.COD (actualizeaza_vanzari)
  ScrieArticoleFacturaEditate(tvanz.id_vanzare)   -- NOU
do_inchide_tranzactie(...)

Agatarea ruleaza doar cand tvanz e deschis cu exact un rand (documentul are factura asociata). VANZARI.ID_FACT nu e atins de niciun pas al secventei - ramane cel alocat la emiterea initiala a facturii, la fel ca la orice alta nota (vezi "Implicatii practice"); doar VANZARI.COD se realiniaza pe codul nou al notei. Tot ce se leaga prin id_fact (ANAF_EFACTURA, DOCUMENTE, ACT.id_factd/id_factc) sau prin ID_VANZARE supravietuieste neschimbat unei reeditari; doar ce ar tine minte cod-ul vechi il pierde.

pack_facturare.actualizeaza_vanzari, apelata din finalizeaza_modificare_nota, face UPDATE VANZARI_DETALII SET STERS = 0 pe tot documentul, fara nicio garda pe linie - reseteaza si liniile sterse la o editare anterioara. De aceea ScrieArticoleFacturaEditate ruleaza DUPA finalizeaza_modificare_nota, nu inauntrul ei: scrierea liniilor trebuie sa vina dupa acest reset, ca sa-l corecteze, nu inaintea lui.

ScrieArticoleFacturaEditate (COMUN\programe\ofacturare_editare.prg:468-555):

  1. marcheaza sters = 1 pe tot documentul din VANZARI_DETALII (:489-491);
  2. invie si actualizeaza liniile pastrate din tvd (cantitate, pret, pret_cu_tva - pret_achizitie se omite, ramane valoarea persistata) (:497-506);
  3. insereaza liniile noi (id_vanzare_det = 0), fara id_vanzare_det explicit - il genereaza trigger-ul TRG_VANZARI_DET_BEFOINS (:518-535);
  4. apeleaza pack_facturare.recalculeaza_totaluri_vanzari(id_vanzare, discount) (:544-548), cu discountul luat din tvanz.discount; NULL pastreaza valoarea curenta din VANZARI in loc s-o zeroeze.

O linie stearsa de utilizator la o editare ramane stearsa si dupa reeditari ulterioare - fiecare salvare reface pasii 1-2 pe starea curenta din tvd, deci resetul din actualizeaza_vanzari e mereu corectat inainte sa ajunga vizibil.

pack_facturare.recalculeaza_totaluri_vanzari (script de migrare ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql) recalculeaza din VANZARI_DETALII - liniile proprii si, separat, liniile din seturi agregate din VANZARI_SETURI - coloanele discount, discount_tva, valoare_achizitie, total_fara_tva, total_tva, total_cu_tva, valval, tvaval, totval, id_valuta, curs, multiplicator, cu acelasi calcul per-linie ca la emitere (calculeaza_total_fara_tva_fact/calculeaza_total_tva_fact). Coloanele de incasare (serie_incasat/nr_incasat/suma_incasat/tip_incasat) nu sunt atinse.

View-ul VVANZARI_ARTICOLE (script de migrare ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql) expune direct VANZARI_DETALII, cu id_vanzare_set si pret_achizitie printre coloanele proprii ale tabelei, plus denumire/codmat/nume_gestiune/nume_val din join-uri - sursa cursorului tvd.

Editarea in grid

Gridul pgfArticole.PAGE3.grdArticoleFactura (omodificari.vc2:12320-...) e legat pe tvd. Linia provenita dintr-un set (id_vanzare_set <> 0) e needitabila (cantitate, pret, pret_cu_tva) si apare intr-o culoare distincta in grid (DynamicForeColor); coloana pret_achizitie e editabila doar pe liniile noi (id_vanzare_set = 0 AND id_vanzare_det = 0), doar-afisare pe restul (:16526-16552). Stergerea unei linii e logica - cmdStergeArticol.Click comuta sters pe randul curent din tvd, ramane vizibila grizata pana la salvare (:16508-16517). Adaugarea reutilizeaza dialogul frm_articol_factura de la compunerea facturii (:16497-16505).

Inainte de salvare (inainte_de_do_termin, :14329-14386, activa doar cand ofacturare_editare.prg e incarcat si tvd exista), pentru fiecare linie activa din tvd: opreste salvarea daca are cantitate <= 0, pret nul sau nu are articol asociat; cere confirmare daca o linie noua are pretul de achizitie 0, respectiv daca toate liniile facturii au fost sterse.

Implicatii practice

  • Codul (cod) unui document din Registrul Jurnal NU e stabil dupa modificare/anulare - se schimba la fiecare editare. Cod hardcodat sau retinut dintr-o executare anterioara devine invalid.
  • Regasirea documentului editat se face dupa id_fact (sau alt marcaj stabil), niciodata dupa cod.
  • Randurile sters = 1 ramase in ACT/RUL/RUL_OBINV dupa o modificare sunt normale (istoric), nu date corupte sau duplicate de curatat.
  • Editarea unei facturi de vanzare (document cu rand in VANZARI) reface si liniile si totalurile denormalizate din VANZARI/VANZARI_DETALII, in aceeasi tranzactie cu nota - vezi ramura de mai sus.
  • Documentele care nu sunt facturi de vanzare nu sunt atinse de aceasta ramura - pagina de articole nu apare si scrierea in VANZARI_DETALII nu se declanseaza (garda: Reccount('tvanz') = 1).