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

166 lines
11 KiB
Markdown

# 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`).