15 KiB
Custodie (tipuri 48/49): stergere + reemitere intoarce curat descarcarea din custodie?
Cercetare read-only. Raspunde la intrebarea daca editarea prin regenerare (STERS=1 pe documentul
vechi + document nou, in aceeasi tranzactie, mecanismul proiectat la S9 din
docs\plan_13_unificare_formular_facturare.md:3576-3660) pentru facturile de marfa in custodie
(tipurile 48/49) lasa stocul de custodie neschimbat.
Sursa principala citata: D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql
(prescurtat EXPORT mai jos, EXPORT:linie). Verificat direct in aceasta runda: numerotarea din
export coincide cu cea folosita in materialele anterioare citate de team-lead (scrie_fact_aviz_custodie
la :10089-10325 pentru corpul functiei si :7521-7536 pentru locul de unde e apelata;
sterge_factura la :5432-5607) — nu s-a gasit niciun offset.
Rezultat central, care rescrie premiza cererii: scrie_fact_aviz_custodie nu se apeleaza
niciodata pentru documente de tip 48/49. Se apeleaza exclusiv cand pack_facturare.ntip = 4
("factura din avize" — alt tip de document, complet diferit). Tipurile 48/49 sunt o ramura separata,
care nu atinge stocul deloc la emitere (nu doar "il descarca prin alta cale"). Detalii mai jos.
1. Ce sunt exact tipurile 48 si 49
Confirmat pe cod, nu doar pe indiciul din materiale:
- Denumirile ("custodie cu descarcare K" / "custodie fara descarcare K") vin din
COMUN\docs\tipuri_documente_facturare.md, deja verificate pe cod de cercetarea anterioaradocs\cercetare\s5_acoperire_tipuri.md(tabelul de la liniile 102-103 de acolo). - Reachable din meniu:
Meniuri\politica.mn2, submeniulMarfaincus— tip 48 la linia 29, tip 49 la linia 26 (citat deja corect ins5_acoperire_tipuri.md:22,102-103,146-147). - Amandoua sunt facturi de sine statatoare (categoria "Facturi", nu "Avize" — spre deosebire de
42/47, care sunt avize catre custodie), sursa VFP de articole fiind aceeasi pentru ambele:
Case Inlist(tnTip, 48, 49) -> pack_facturare.cursor_articole_k(...)(COMUN\programe\ofacturare.prg:271-272pe formularul standard, identic la:750-752pe prototip). cursor_articole_k(EXPORT:3595-3701, definitia activa; exista si o declaratie in spec la:382) e o interogare de lista de preturi, nu o interogare de stoc/aviz: alege articolele dintr-o politica de pret dedicata (A.ID_POL = to_number(pack_sesiune.getoptiunefirma('IDPOLPRETFACTK')),EXPORT:3681-3682) si filtreaza explicit doar articole negestionabile:WHERE C.IN_STOC = 0 AND C.IN_CRM = 1 AND C.STERS = 0 AND C.INACTIV = 0(EXPORT:3695-3698). Cu alte cuvinte: 48 si 49 sunt aceeasi sursa de articole ("K" = politica de pret speciala pentru custodie, optiunea de firmaIDPOLPRETFACTK), restransa explicit la articole care nu sunt gestionate in stoc (IN_STOC=0inNOM_ARTICOLE).- Nu s-a gasit in aceasta runda ce anume distinge 48 de 49 ("cu"/"fara descarcare K") — pe tot
codul examinat (
adauga_articol_factura,contabilizeaza_articol,cursor_articole_k,sterge_factura), cele doua tipuri sunt tratate identic, fara nicio ramura care sa le separe. Diferenta pare sa fie doar de conventie de utilizare (business), nu de cod — semnalat la sectiunea "Neacoperit".
2. Ce scrie emiterea pe un document 48/49
Nu se atinge stocul deloc, prin design, nu prin accident. Lant de dovezi:
adauga_articol_factura(EXPORT:4989-5220) nu are ramura proprie pentruntip IN (48,49)— cade inELSE(:5187-5203), care preiaV_IN_STOCdirect dinV_IN_STOC_TEMP, valoarea trimisa de VFP din grid — la randul ei populata dincursor_articole_k.GESTIONABIL(C.IN_STOC AS GESTIONABIL,EXPORT:3634), deci intotdeauna 0 pentru articolele oferite pe aceste doua tipuri.contabilizeaza_articol(EXPORT:7173-7547): tip 48/49 intra in bucketul "factura normala" pentru determinareaSCD/ASCD(WHEN pack_facturare.ntip <= 20 or ntip IN (... 48, 49, 51, 52),EXPORT:7400-7412) — scrie o nota contabila normala prinscrie_nota(:7443-7467), ca orice factura obisnuita, folosind conturile din politica de pret K.- Apelul catre
descarca_gestiunee conditionat dedetalii_articol.in_stoc = 1(EXPORT:7472-7475, ramuraIF pack_facturare.ntip <> 4, care e adevarata pentru 48/49). Cumin_stocvine intotdeauna 0 pentru articolele acestor doua tipuri (pasul 1), conditia nu se indeplineste niciodata —descarca_gestiunenu se executa. - Confirmare independenta, in interiorul lui
descarca_gestiuneinsusi: chiar daca cineva ar reusi sa forteze apelul, functia are propria garda de iesire timpurie:Comentariul insusi confirma intentia de design: articolele negestionabile (exact categoria din care se alimenteaza 48/49) sunt explicit excluse din descarcarea de gestiune, tocmai pentru ca fluxul de custodie sa poata folosi articole care nu au stoc urmarit.EXPORT:7789-7797 -- NU SE DESCARCA GESTIUNEA PENTRU ARTICOLELE NEGESTIONABILE -- ASTFEL INCAT SA SE POATA FACE OPERATII GEN AVIZ DIN CUSTODIE INCLUSIV CU ARTICOLE NEGESTIONABILE SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL; if lnInStoc = 0 then GOTO SFARSIT; end if; scrie_fact_aviz_custodienu se apeleaza pentru 48/49. Singurul apel din tot pachetul (EXPORT:7520-7537) e in interiorul aceleiasi functiicontabilizeaza_articol, pe ramuraELSEa testuluiIF pack_facturare.ntip <> 4(:7472) — adica doar candntip = 4("factura din avize"). Pentru 48/49,ntipe 48 sau 49, niciodata 4, deci acest cod nu se executa niciodata pe aceasta ramura. Functiascrie_fact_aviz_custodieinsasi (EXPORT:10089-10325) nu scrie inSTOC/RUL— cauta un rand deja existent inRUL(cuID_TIP_RULAJ = 0,EXPORT:10175) pentru a calcula valori de cost, si scrie doar note contabile (scrie_nota, conturi371/357/607/378/4428— conturi de marfuri in custodie / cheltuieli,EXPORT:10229-10324) — e o functie de conversie contabila, nu de miscare de stoc.
Concluzie sectiune: premiza din cerere ("pe ramura custodiei se cheama scrie_fact_aviz_custodie
in loc de descarca_gestiune") descrie corect fluxul pentru tip 4 (factura emisa dintr-un aviz,
posibil un aviz catre custodie 42/47 emis anterior), nu pentru tipurile 48/49 cerute explicit.
Pentru 48/49, niciuna din cele doua proceduri nu scrie nimic in stoc — documentul e din start
"fara efect de stoc", pentru ca sursa lui de articole (cursor_articole_k) e restransa la articole
negestionabile.
3. Ce face stergerea (sterge_factura) pe un document 48/49
sterge_factura (EXPORT:5432-5607) nu are nicio ramura proprie pentru V_TIP IN (48,49). Constantele
speciale verificate (EXPORT:78-86): nTipVanzareRetail=43, nTipFacturaHotel=44,
nTipFacturaRestaurant=45, nTipNotaPlata=46, nTipFacturaACN=51 — 48 si 49 nu sunt printre ele.
CASE-ul principal (EXPORT:5501-5551) evalueaza V_TIP astfel pentru 48/49:
V_TIP = 24? Nu.V_TIP > 20 AND V_TIP NOT IN (44,45,46)? Da — 48 si 49 cad in aceasta ramura generica ("alte tipuri de avize",EXPORT:5512-5523), care face:UPDATE VANZARI_CANTITATI SET STERS = 1 WHERE ID_VANZARE_DET_AVIZ IN (SELECT ID_VANZARE_DET FROM VANZARI_DETALII WHERE ID_VANZARE = V_ID_VANZARE AND STERS = 0);VANZARI_CANTITATIe tabelul de bookkeeping "cantitate ramasa din comanda/aviz" (Rol A, documentat indocs\cercetare\s4_punct2_registru_cantitate_ramasa.md, citat si ins5_acoperire_tipuri.mdcoloana "Rol"). 48/49 nu au niciodata acest rol (s5_acoperire_tipuri.md:103-104: coloana Rol = "—" pentru ambele) — articolele lor vin dincursor_articole_k(lista de preturi K), nu dincursor_comanda. Deci acestUPDATEactioneaza pe zero randuri pentru documente 48/49 (nu exista randuriVANZARI_CANTITATIlegate de ele) — e un no-op inofensiv, nu o eroare, dar nici o actiune custodie-specifica.- Restul ramurilor CASE (
V_TIP=4,V_TIP=nTipFacturaRestaurant) nu se aplica.
Restul procedurii e comun tuturor tipurilor (nimic specific 48/49):
UPDATE VANZARI_DETALII SET STERS=1 ... WHERE ID_VANZARE = V_ID_VANZARE(:5560-5564) — marcheaza liniile facturii ca sterse.IF V_TIP IN (2,6,52)pentruCTR_RATE_FACTURI(:5566-5580) — nu se aplica (48/49 nu sunt in lista).UPDATE VANZARI_CORESP SET STERS=1 ...(:5582-5585) — sterge corespondentele factura<->aviz/comanda, generic.- CASE-ul final pe pachete externe (restaurant/hotel/ACN,
:5587-5605) — nu se aplica pentru 48/49, cad inELSE NULL.
Nu exista, nicaieri in sterge_factura, vreun apel care sa reverseze explicit efectul lui
descarca_gestiune (nu s-a gasit incarca_gestiune sau echivalent, pentru niciun tip de document,
nu doar 48/49 — cautare grep -n "UPDATE STOC" in tot pachetul, zero rezultate; singurele scrieri
gasite in zona lui descarca_gestiune sunt in RUL_TEMP, EXPORT:9464,10006, tabel tranzitoriu care
se descarca in RUL mai departe in flux, nu direct in acest apel). Mecanismul prin care stocul
"revine" la stergerea unei facturi normale (ntip<=20) nu a fost identificat in aceasta runda —
posibil printr-un filtru WHERE VANZARI_DETALII.STERS=0 in interogarile de stoc disponibil, posibil
prin alt pachet (PACK_STOC?) sau printr-un trigger, in afara PACK_FACTURARE si a perimetrului
citit. Marcat explicit la "Neacoperit" — e o intrebare generala a sistemului, nu specifica
custodiei, pentru ca sterge_factura trateaza identic (fara reversare explicita) orice tip de
document.
4. Garzi existente la stergere — prind si cazul custodiei?
Cele trei garzi de la inceputul lui sterge_factura, verificate pe liniile citate de team-lead
(coincid exact, fara offset):
EXPORT:5452-5462— blocheaza daca exista facturi de retur (VANZARI_CORESP.TIP=3) pe documentul curent.EXPORT:5466-5476— blocheaza daca exista facturi/avize de retur (TIP IN (1,2)) pe un aviz curent.EXPORT:5480-5494— blocheaza daca exista avize de retur pe avizele care au generat o factura din aviz curenta.
Niciuna nu mentioneaza custodie sau ntip IN (48,49) — toate trei filtreaza exclusiv pe
VANZARI_CORESP.TIP IN (1,2,3) (relatii factura<->retur / aviz<->retur), independent de tipul
documentului curent (V_ID_VANZARE). Pentru un document 48/49 fara retur emis pe el, niciuna nu
se declanseaza — stergerea trece liber, exact ca pentru o factura normala fara retur.
5. Verdict
Regenerarea (stergere + reemitere) e SIGURA pentru documentele 48/49 in privinta stocului de
custodie — dar dintr-un motiv diferit de cel presupus in cerere. Nu pentru ca stergerea "intoarce
curat" o descarcare de custodie — ci pentru ca emiterea unui document 48/49 nu descarca nimic din
stoc/custodie in primul rand (sectiunea 2: sursa de articole e restransa structural la articole
negestionabile, IN_STOC=0, iar descarca_gestiune are doua garzi independente care o opresc pentru
astfel de articole). Stergerea (sectiunea 3) nu are nimic custodie-specific de reversat, si nici nu
are nevoie sa aiba, pentru ca nimic custodie-specific n-a fost scris la emitere. ntip=4 (factura
din avize) e ramura care foloseste efectiv scrie_fact_aviz_custodie, si e un tip de document
diferit de 48/49 — premiza din cerere ("pe ramura custodiei se cheama scrie_fact_aviz_custodie
in loc de descarca_gestiune") descrie corect tip 4, nu 48/49.
Conditie sub care verdictul s-ar putea rasturna, ne-exclusa 100% in aceasta runda: siguranta de
mai sus depinde de invariantul "un document 48/49 contine numai articole cu IN_STOC=0". Daca
articolele adaugate pe un document 48/49 ar veni vreodata printr-o alta cale decat
cursor_articole_k (o cautare libera de articole, nerestransa la politica K), un articol gestionabil
(IN_STOC=1) ar trece garda de la adauga_articol_factura/contabilizeaza_articol (sectiunea 2,
pasul 1: V_IN_STOC_TEMP ar deveni 1) si descarca_gestiune s-ar executa normal — caz in care
sterge_factura, care nu reverseaza explicit stocul pentru niciun tip (sectiunea 3), ar lasa un
decalaj real. Nu s-a gasit in aceasta runda o cale VFP care sa permita asta pentru 48/49 (grid-ul
de articole al acestor doua tipuri e populat o singura data, la deschiderea formularului, direct din
cursor_articole_k — COMUN\programe\ofacturare.prg:271-272; nu exista o cautare separata de
articole vazuta in codul citit), dar nu s-a verificat exhaustiv toate punctele de intrare posibile in
VANZARI_DETALII_TEMP pentru aceste doua tipuri.
Verificat direct / Dedus / Neacoperit
Verificat direct pe cod (fisier:linie citat in sectiunile 1-4):
- Tip 48/49 = facturi (nu avize), sursa unica de articole
cursor_articole_k, restransa laIN_STOC=0. scrie_fact_aviz_custodiese apeleaza exclusiv pentruntip=4, niciodata pentru 48/49.descarca_gestiuneare doua garzi independente (in_stoc=1la apelant, plus garda proprie peNOM_ARTICOLE.IN_STOC) care o opresc pentru articolele din 48/49.sterge_facturanu are ramura proprie pentru 48/49 (cade in bucketul generic ">20, exclus hotel/restaurant/notaplata"), iar actiunea acelui bucket (VANZARI_CANTITATI) nu are ce sa actioneze pentru aceste doua tipuri (fara rol in acel tabel).- Cele trei garzi de refuz al stergerii nu disting custodia, si nu se declanseaza pentru un document 48/49 fara retur emis pe el.
Dedus, nu verificat exhaustiv:
- Ca operatorul nu poate adauga pe un document 48/49 un articol gestionabil pe alta cale decat
cursor_articole_k— bazat pe faptul ca grid-ul se populeaza o singura data la deschidere, dar n-am urmarit tot codul de interactiune al grid-ului (adauga la lista/editare inline) pentru cele doua tipuri. - Ca diferenta reala dintre tip 48 si tip 49 e doar de conventie/business, nu de cod — n-am gasit
nicio ramura care sa le separe, dar nici n-am cautat in afara
PACK_FACTURARE/ofacturare.prg(de exemplu in rapoarte sau in alte proceduri VFP care ar putea trata diferit "cu descarcare K" vs "fara").
Neacoperit in aceasta runda:
- Mecanismul general prin care stocul "revine" la stergerea unei facturi normale (
ntip<=20) — nu s-a gasit niciunUPDATE STOC/reversare explicita inPACK_FACTURARE; posibil calculat prin interogari care filtreazaVANZARI_DETALII.STERS=0, posibil in alt pachet Oracle sau prin trigger, in afara perimetrului citit in aceasta runda. Nu e o intrebare specifica custodiei — se aplica identic la orice tip de document — dar ramane deschisa. - Semnificatia exacta si diferenta functionala/de raportare intre "custodie cu descarcare K" (48) si "custodie fara descarcare K" (49) — n-am gasit in cod ce anume descarca "K" daca nu e stoc fizic (posibil un calcul contabil de adaos comercial specific comertului cu amanuntul, coeficientul K, dar nu confirmat pe cod in aceasta runda).
- Testare pe date reale (baza de dev) a unui ciclu emitere->stergere->reemitere pe un document 48/49
— cercetarea a fost exclusiv pe cod si
SELECT-uri simple, fara sa ruleze fluxul.