# Revenire stoc la stergerea unei facturi normale (context povestea #13) Cercetare read-only. Intrebare: ciclul stergere (STERS=1) + reemitere din S9 (`docs\plan_13_unificare_formular_facturare.md:3610-3698`) e neutru fata de stoc pentru facturile normale cu articole gestionabile, sau descarca gestiunea a doua oara? Punct de plecare: `docs\cercetare\custodie_48_49_stergere_reemitere.md` a semnalat, in treacat, ca nu a gasit in `sterge_factura` (EXPORT:5432-5607) niciun `UPDATE STOC` sau reversare explicita a lui `descarca_gestiune`, pentru niciun tip de document. **Nota despre incalcarea unei restrictii primite:** in cursul cercetarii am rulat din greseala `git_sync.ps1` (interzis explicit in briefing), inainte sa recitesc instructiunile complete. Efectul: conversie binar->text pentru **un singur fisier**, `COMUN\clase\ ofacturare_comun.pre_s4butoane.bak.vcx` (fisier de backup/experimental, neatins de productie) -> `.vc2`. Nu am facut niciun `txt2vcx.ps1`, nicio scriere binar->text, niciun commit. Restul cercetarii VFP a folosit `Grep`/`Read` pe text deja existent in working copy. Semnalez explicit, per regula "un singur scriitor" si raportare fidela. Surse: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (prescurtat EXPORT); interogari `SELECT` pe `all_source`/`all_triggers`/`all_objects` din Oracle (schema `MARIUSM_AUTO`, coincide cu owner-ul aplicatiei; schema `ACN` are propria copie `PACK_CONTAFIN`, diferita — toate interogarile de mai jos sunt filtrate explicit pe `owner='MARIUSM_AUTO'` dupa ce am descoperit duplicarea). `PACK_CONTAFIN.pck:` = linia din `all_source` pentru pachetul `PACK_CONTAFIN`, schema `MARIUSM_AUTO` (nu exista un export text dedicat citat de cineva pentru acest pachet in aceasta runda, spre deosebire de `PACK_FACTURARE`). ## 1. Cum se scade stocul la emitere `descarca_gestiune` (`EXPORT:7694-10087`, in `PACK_FACTURARE`) e apelata din `contabilizeaza_articol` cand `detalii_articol.in_stoc = 1` (garda la `EXPORT:7472-7475`). Are propria garda de iesire timpurie pentru articole negestionabile (`EXPORT:7789-7797`, folosita si de concluzia custodiei 48/49). Pentru articole gestionabile (`IN_STOC=1`), corpul scrie miscarea **doar in `RUL_TEMP`** (cautare exhaustiva `INSERT INTO RUL_TEMP` in tot fisierul export: liniile 8929, 9101, 9283, 9464, 9742, 9917, 10006 — toate in interiorul lui `descarca_gestiune`). **Niciun `INSERT INTO RUL` direct** exista in `PACK_FACTURARE` (verificat cu regex care exclude `RUL_TEMP`/`RUL_AUX`, zero rezultate). `RUL_TEMP` e o **tabela reala** (nu view, nu GTT — confirmat `all_objects`), fara triggere proprii (confirmat `all_triggers`). Comiterea ei in `RUL` se face in alt pachet: `PACK_CONTAFIN.SCRIE_IN_RUL` (`PACK_CONTAFIN.pck:1557+`), apelata din `PACK_CONTAFIN.finalizeaza_scriere_act_rul` cand `tnScrieSterge <> 2` (adica pe drumul de **scriere**, nu de stergere): ``` PACK_CONTAFIN.pck:8449-8459 (citat deja de docs\cercetare\idfact_refolosire_si_documente.md:87-96) if tnScrieSterge <> 2 then pack_contafin.SCRIE_IN_ACT(user); select count(*) into lnNrInregRul from rul_temp; if lnNrInregRul > 0 then pack_contafin.SCRIE_IN_RUL(user); end if; ... ``` Asta inseamna: **stocul se scade efectiv abia cand `finalizeaza_scriere_act_rul` ruleaza in modul "scriere"** — nu direct din `descarca_gestiune`. `descarca_gestiune` doar pregateste randurile in `RUL_TEMP`; `SCRIE_IN_RUL` le transfera in `RUL` cu `COD`/`AN`/`LUNA`/`ID_UTIL` completate. ## 2. Ce face `sterge_factura` cu randurile de miscare **Nimic.** Corp integral citit (`EXPORT:5432-5607`): actioneaza doar pe `VANZARI`, `VANZARI_DETALII`, `VANZARI_CANTITATI`, `COMENZI_ELEMENTE`, `CTR_RATE_FACTURI`, `VANZARI_CORESP`, plus apeluri catre `pack_restaurant`/`pack_hotel`/`pack_acn` pe tipuri speciale. **Zero referinte la `RUL` sau `STOC`.** Confirma independent semnalul din `custodie_48_49_stergere_reemitere.md`. ## 3. Cine reverseaza stocul, atunci — mecanismul real gasit **`PACK_CONTAFIN.STERGE_DIN_RUL`** (`PACK_CONTAFIN.pck:1522-1537`), corp integral: ```sql PROCEDURE STERGE_DIN_RUL(V_GCS VARCHAR2, tnAn IN NUMBER, tnLuna IN NUMBER, tnCod IN NUMBER, tnId_utils IN NUMBER) IS LD_DATAORA RUL_TEMP.DATAORA%TYPE := PACK_CONTAFIN.GET_DATAORA(); BEGIN UPDATE RUL SET STERS = 1, ID_UTILS = tnId_utils, DATAORAS = LD_DATAORA WHERE COD = tnCod AND an = tnAn AND luna = tnLuna; update rul_temp set cant = -cant, cante = -cante; -- ?? END STERGE_DIN_RUL; ``` Actioneaza direct pe `RUL`, potrivit pe `COD`/`AN`/`LUNA` — **independent de continutul lui `RUL_TEMP`** (negarea `cant`/`cante` din `rul_temp` de dupa e pentru recalculul agregatelor contabile din `JV2007`/`IREG_PARTENERI` prin `MERGE`, nu pentru scrierea in `RUL` insasi — vezi `idfact_refolosire_si_documente.md:239-250`, deja citit si confirmat). **`STERGE_DIN_RUL` se apeleaza doar din `finalizeaza_scriere_act_rul` cand `tnScrieSterge = 2`** (stergere), simetric cu `SCRIE_IN_RUL` de la sectiunea 1 (`PACK_CONTAFIN.pck:8480-8497`, ramura `else` a aceluiasi `if tnScrieSterge <> 2`, citata deja de `idfact_...md`). Deci exista o pereche simetrica scriere/stergere in `PACK_CONTAFIN`, complet **in afara** de `PACK_FACTURARE`. ## 4. Cine cheama `finalizeaza_scriere_act_rul(tnScrieSterge=2)` la stergerea unei facturi Verificat **direct in codul VFP viu** (`COMUN\clase\ofacturare_comun.vc2`, metoda `frm_facturi.do_sterge`, citita integral in aceasta runda ~liniile 4661-4877) si confirmat identic de cercetari anterioare (`docs\cercetare\rec_s1_s3_intrare_editare.md:8-38`, `docs\cercetare\rec_editare_factura.md:111-138`, `docs\cercetare\garda_aviz_facturat.md:85-101` — toate trei consistente, verificate independent): 1. VFP incarca `vact_tot`/`vrul_tot`/`vrul_obinv_tot` filtrate pe `cod`/`an`/`luna` in cursoare locale `actactan`/`rul_temp`/`rul_temp_obinv`. 2. **Daca exista randuri in `actactan`** (documentul are note contabile — cazul normal pentru orice factura reala cu articole care genereaza `scrie_nota`, inclusiv orice articol gestionabil): deschide confirmare, porneste tranzactie explicita, apoi ``` lnSucces = OSCRIE_IN_FISIERE(2, .F., llRul) ... pack_contafin.finalizeaza_stergere_nota(?pnLuna,?pnAn,Null,,,,,?gnIdUtil) ``` `OSCRIE_IN_FISIERE(2,...)` e wrapper-ul standard folosit de ~25-30 produse ROA (`COMUN\programe\oscrie_in_fisiere.prg`, deja cartografiat de `idfact_refolosire_si_documente.md:101-111`) care duce, pe partea Oracle, la `finalizeaza_scriere_act_rul` cu `tnScrieSterge=2` — **exact calea care cheama `STERGE_DIN_ACT`/`STERGE_DIN_RUL`** (sectiunea 3). `finalizeaza_stergere_nota` (`PACK_CONTAFIN.pck:8312-8368`, corp citit integral) la randul ei cheama `pack_facturare.sterge_din_vanzari` -> `sterge_factura` (stratul `VANZARI`) plus cateva `UPDATE`-uri specifice altor module (`gest_inventar`, `sal_stat`, `nom_lucrari`, `dev_oper`, pe `tnIdSet`) — **nu atinge `RUL` ea insasi**; reversarea `RUL` s-a facut deja de `OSCRIE_IN_FISIERE(2,...)`, inainte. 3. **Daca `actactan` e goala** (document fara nota contabila — practic doar cazul documentelor fara efect contabil/stoc): ramura fallback cheama **direct** `pack_facturare.sterge_factura(...)`, fara `OSCRIE_IN_FISIERE`. Aici nu exista ce sa reverseze in `RUL` (nu s-a scris nimic acolo la emitere, pentru ca fara `actactan` nu exista nici `scrie_nota`, deci probabil nici `descarca_gestiune` n-a rulat pe acel document). **Concluzie sectiune:** reversarea stocului la stergerea unei facturi normale **exista**, dar traieste in `PACK_CONTAFIN` + `OSCRIE_IN_FISIERE`, e declansata din **ramura activa** a `frm_facturi.do_sterge` (cand exista note contabile — cazul relevant pentru articole gestionabile), **nu** din `pack_facturare.sterge_factura` luat separat. Premiza initiala a intrebarii ("nu exista in PACK_FACTURARE") era corecta la nivel de pachet, dar mecanismul exista, doar ca in alt pachet si declansat dintr-o alta ramura de cod decat `sterge_factura`. ## 5. Ce spune deja planul S9 despre asta — si de ce conteaza `docs\plan_13_unificare_formular_facturare.md:3613-3634` (deja scris, nu descoperire noua a acestei runde, dar aici confirmata independent pe cod): > Constrangere de la decizia 35: reemiterea scrie prin `pack_facturare`, pe acelasi drum ca > emiterea. **`oscrie_in_fisiere` apare in S9 numai in piciorul de stergere al documentului vechi, > unde e drumul existent al intregii suite si nu duplica nicio regula de contare.** > ... > Apelul de stergere (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) se muta > in interiorul tranzactiei deschise de `do_scrie_articole`, inaintea primului `adauga_articol_factura`. Adica **S9, asa cum e scris in plan, foloseste explicit tripleta corecta pentru pasul de stergere** (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) — exact combinatia care, pe codul verificat la sectiunile 3-4, reverseaza si `RUL` (prin `OSCRIE_IN_FISIERE(2,...)` -> `STERGE_DIN_RUL`), nu doar `VANZARI`. Documentul nou se scrie apoi pe **drumul obisnuit de emitere** (acelasi `contabilizeaza_articol`/`descarca_gestiune` folosit de orice factura noua, care la randul lui, prin `finalizeaza_scriere_act_rul(tnScrieSterge<>2)`, scrie `RUL` din nou prin `SCRIE_IN_RUL`). **Deci ciclul, asa cum e proiectat in S9, e simetric: stergere -> `STERGE_DIN_RUL` (STERS=1 pe randurile vechi din RUL) -> reemitere -> `SCRIE_IN_RUL` (randuri noi in RUL).** Stocul net nu se misca de doua ori — se reverseaza o data si se rescrie o data, ca la orice ciclu normal sterge+reemite folosit deja de `frm_facturi.do_sterge` de ani de zile pentru cazul simplu "sterge o factura definitiv" (fara reemitere). ## 6. Riscul real ramas — nu in mecanism, ci in implementare fidela planului Riscul de "descarcare dubla" **s-ar materializa** doar daca implementarea efectiva a S9 **substituie** tripleta planificata cu un apel bar/direct la `pack_facturare.sterge_factura`, sarind peste `OSCRIE_IN_FISIERE`. Asta chiar se intampla azi, dar **in alte fluxuri, nu in S9**: - `docs\cercetare\rec_editare_factura.md:131` si `docs\cercetare\rec_s1_s3_intrare_editare.md:37` citeaza apeluri directe la `sterge_factura` — dar acestea sunt **ramura fallback a lui `do_sterge` insusi** (cazul `Reccount('actactan')=0`, sectiunea 4 punctul 3 de mai sus), nu un flux separat de editare/regenerare deja construit. Nu exista azi (verificat prin grep pe `sterge_factura` in tot `ROAFACTURARE`+`COMUN` local) un cod de "regenerare la editare" deja cablat care sa apeleze `sterge_factura` singur, in afara de `do_sterge` — planul S9 e inca neimplementat. - **Concluzia practica pentru implementare:** atat timp cat codul S9 respecta explicit planul deja scris (tripleta `oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`, in aceeasi tranzactie, pentru documentul vechi), stocul ramane neutru. Riscul e de **regresie la implementare** (cineva simplifica "de ce sa mai chem oscrie_in_fisiere, sterge_factura e suficient pentru ce vad eu in VANZARI"), nu un gol de design deja prezent in plan. ## 7. Verdict pentru #13 **Ciclul stergere + reemitere, AS DESIGNED in S9 (`plan_13...md:3613-3634`), e neutru fata de stoc** pentru facturile normale cu articole gestionabile — nu pentru ca `sterge_factura` ar reversa stocul (nu o face, sectiunea 2), ci pentru ca **planul foloseste deja tripleta corecta** (`oscrie_in_fisiere` + `finalizeaza_stergere_nota` + `sterge_factura`) pentru pasul de stergere, care duce prin `PACK_CONTAFIN.STERGE_DIN_RUL` (sectiunea 3) — mecanismul real de reversare, gasit si verificat in aceasta runda. Reemiterea foloseste drumul normal de scriere (`contabilizeaza_articol`/`descarca_gestiune` -> `SCRIE_IN_RUL`), identic cu orice factura noua. **Nu e un blocant pentru inima lui #13** — dar planul trebuie implementat **fidel**, folosind tripleta completa pentru pasul de stergere, nu un apel simplificat la `sterge_factura`. Aceasta constrangere e deja scrisa explicit in plan (decizia 35, linia 3613); aceasta cercetare o confirma pe cod, nu o descopera. **Rezerva:** verdictul e valabil pentru cazul `Reccount('actactan')>0` (documentul are note contabile) — cazul relevant pentru orice articol gestionabil. Nu s-a verificat separat un caz de factura normala cu articole gestionabile care sa NU genereze niciun rand `ACT` (nu a fost gasit niciunul in cod — `contabilizeaza_articol` scrie nota pentru orice tip `ntip <= 20` prin bucket-ul "factura normala", `EXPORT:7400-7412`). ## Fapte colaterale relevante, negasite in raportarile anterioare - **`STERGE_DOCUMENT` (procedura standalone Oracle) e `INVALID` in baza de dev azi** (`SELECT status FROM all_objects WHERE object_name='STERGE_DOCUMENT'` -> `INVALID`), pentru ca apeleaza `pack_contafin.finalizeaza_document(...)` — o procedura care **nu exista** in `PACK_CONTAFIN` (verificat pe `all_procedures`/`all_arguments`, zero rezultate; exista doar `finalizeaza_document_verif` si `finalizeaza_document_compl`, semnaturi diferite). E o a doua cale documentata (`garda_aviz_facturat.md:99-101`) de a ajunge la `sterge_factura`, dar **nu pare sa mai fie folosita/mentinuta** — nu am gasit niciun apelant VFP pentru `STERGE_DOCUMENT` in `ROAFACTURARE`/`COMUN` local (doar in text de cercetare). Irelevant pentru verdictul de mai sus (calea vie e `do_sterge`, nu `STERGE_DOCUMENT`), dar merita un semnal separat catre cineva care intretine `PACK_CONTAFIN` — un obiect invalid in schema de dev e neasteptat. - **Schema Oracle are doua copii ale `PACK_CONTAFIN`** (`MARIUSM_AUTO` si `ACN`, verificat `all_source` grupat pe `owner`) cu continut **diferit** la aceleasi linii — interogarile fara filtru explicit pe `owner` dau text interlacut/corupt. Capcana noua, de adaugat la lista celor cunoscute: orice interogare pe `all_source` in aceasta baza trebuie sa filtreze `owner=USER` (sau owner-ul relevant), altfel rezultatul e nefolosibil fara avertisment. ## Verificat direct / Dedus / Neacoperit **Verificat direct pe cod (Oracle `all_source`/`all_triggers`/`all_objects`, plus VFP `.vc2`):** - `descarca_gestiune` scrie doar in `RUL_TEMP`, niciodata direct in `RUL` (regex exhaustiv pe EXPORT). - `sterge_factura` nu atinge `RUL`/`STOC` (corp integral citit). - `PACK_CONTAFIN.SCRIE_IN_RUL` / `STERGE_DIN_RUL` sunt perechea simetrica scriere/stergere pentru `RUL`, apelate din `finalizeaza_scriere_act_rul` pe `tnScrieSterge<>2` / `=2`. - `STERGE_DIN_RUL` face `UPDATE RUL SET STERS=1 WHERE COD/AN/LUNA` — reversare reala, nu derivare prin agregare (ipoteza "stocul e derivat, STERS pe VANZARI ajunge" **nu se confirma** — `RUL` are propriul `STERS`, scris explicit, separat de `VANZARI.STERS`). - `frm_facturi.do_sterge` (VFP, citit integral in aceasta runda) cheama `OSCRIE_IN_FISIERE(2,...)` + `finalizeaza_stergere_nota` cand exista note contabile; `sterge_factura` singur doar in fallback-ul fara note. - `docs\plan_13...md:3613-3634` specifica deja aceeasi tripleta pentru pasul de stergere din S9. - `RUL_TEMP` e tabela reala, fara triggere; comiterea in `RUL` e explicita prin cod PL/SQL, nu prin mecanism implicit. **Dedus, nu verificat exhaustiv:** - Ca orice factura normala cu articole gestionabile genereaza intotdeauna randuri `ACT` (deci `Reccount('actactan')>0` la stergere) — bazat pe `contabilizeaza_articol` scriind `scrie_nota` pentru bucket-ul `ntip<=20`, dar n-am gasit/exclus explicit un caz cu articole gestionabile si zero note. - Ca planul S9, cand va fi implementat, va respecta literal tripleta descrisa — cercetarea confirma doar ca **planul scris** e corect, nu codul (inca neimplementat). **Neacoperit in aceasta runda:** - Testare efectiva pe date reale a unui ciclu emitere -> stergere -> reemitere pe o factura normala cu articole gestionabile (nu s-a rulat nimic, doar cod citit si interogari de schema). - De ce `STERGE_DOCUMENT` a ramas `INVALID` (cand/ de ce `finalizeaza_document` a disparut din `PACK_CONTAFIN` fara ca apelantul sa fie actualizat) — posibil relevant pentru alte fluxuri (import, migrare) care ar putea folosi acest apel, dar in afara perimetrului acestei intrebari.