218 lines
15 KiB
Markdown
218 lines
15 KiB
Markdown
# 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 anterioara
|
|
`docs\cercetare\s5_acoperire_tipuri.md` (tabelul de la liniile 102-103 de acolo).
|
|
- **Reachable din meniu**: `Meniuri\politica.mn2`, submeniul `Marfaincus` — tip 48 la linia 29,
|
|
tip 49 la linia 26 (citat deja corect in `s5_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-272` pe formularul standard, identic la `:750-752` pe 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 firma `IDPOLPRETFACTK`), restransa explicit la articole
|
|
**care nu sunt gestionate in stoc** (`IN_STOC=0` in `NOM_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:
|
|
|
|
1. `adauga_articol_factura` (`EXPORT:4989-5220`) nu are ramura proprie pentru `ntip IN (48,49)` —
|
|
cade in `ELSE` (`:5187-5203`), care preia `V_IN_STOC` direct din `V_IN_STOC_TEMP`, valoarea
|
|
trimisa de VFP din grid — la randul ei populata din `cursor_articole_k.GESTIONABIL`
|
|
(`C.IN_STOC AS GESTIONABIL`, `EXPORT:3634`), deci **intotdeauna 0** pentru articolele oferite pe
|
|
aceste doua tipuri.
|
|
2. `contabilizeaza_articol` (`EXPORT:7173-7547`): tip 48/49 intra in bucketul "factura normala"
|
|
pentru determinarea `SCD`/`ASCD` (`WHEN pack_facturare.ntip <= 20 or ntip IN (... 48, 49, 51, 52)`,
|
|
`EXPORT:7400-7412`) — scrie o nota contabila normala prin `scrie_nota` (`:7443-7467`), ca orice
|
|
factura obisnuita, folosind conturile din politica de pret K.
|
|
3. **Apelul catre `descarca_gestiune` e conditionat** de `detalii_articol.in_stoc = 1`
|
|
(`EXPORT:7472-7475`, ramura `IF pack_facturare.ntip <> 4`, care e adevarata pentru 48/49). Cum
|
|
`in_stoc` vine intotdeauna 0 pentru articolele acestor doua tipuri (pasul 1), **conditia nu se
|
|
indeplineste niciodata** — `descarca_gestiune` nu se executa.
|
|
4. **Confirmare independenta, in interiorul lui `descarca_gestiune` insusi**: chiar daca cineva ar
|
|
reusi sa forteze apelul, functia are propria garda de iesire timpurie:
|
|
```
|
|
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;
|
|
```
|
|
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.
|
|
5. **`scrie_fact_aviz_custodie` nu se apeleaza pentru 48/49.** Singurul apel din tot pachetul
|
|
(`EXPORT:7520-7537`) e in interiorul aceleiasi functii `contabilizeaza_articol`, pe ramura
|
|
`ELSE` a testului `IF pack_facturare.ntip <> 4` (`:7472`) — adica **doar cand `ntip = 4`**
|
|
("factura din avize"). Pentru 48/49, `ntip` e 48 sau 49, niciodata 4, deci acest cod **nu se
|
|
executa niciodata** pe aceasta ramura. Functia `scrie_fact_aviz_custodie` insasi
|
|
(`EXPORT:10089-10325`) nu scrie in `STOC`/`RUL` — cauta un rand deja existent in `RUL` (cu
|
|
`ID_TIP_RULAJ = 0`, `EXPORT:10175`) pentru a calcula valori de cost, si scrie doar **note
|
|
contabile** (`scrie_nota`, conturi `371/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:
|
|
```sql
|
|
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_CANTITATI` e tabelul de bookkeeping "cantitate ramasa din comanda/aviz" (Rol A, documentat
|
|
in `docs\cercetare\s4_punct2_registru_cantitate_ramasa.md`, citat si in `s5_acoperire_tipuri.md`
|
|
coloana "Rol"). **48/49 nu au niciodata acest rol** (`s5_acoperire_tipuri.md:103-104`: coloana Rol
|
|
= "—" pentru ambele) — articolele lor vin din `cursor_articole_k` (lista de preturi K), nu din
|
|
`cursor_comanda`. Deci acest `UPDATE` **actioneaza pe zero randuri** pentru documente 48/49 (nu
|
|
exista randuri `VANZARI_CANTITATI` legate 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)` pentru `CTR_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 in `ELSE 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 la
|
|
`IN_STOC=0`.
|
|
- `scrie_fact_aviz_custodie` se apeleaza exclusiv pentru `ntip=4`, niciodata pentru 48/49.
|
|
- `descarca_gestiune` are doua garzi independente (`in_stoc=1` la apelant, plus garda proprie pe
|
|
`NOM_ARTICOLE.IN_STOC`) care o opresc pentru articolele din 48/49.
|
|
- `sterge_factura` nu 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 niciun `UPDATE STOC`/reversare explicita in `PACK_FACTURARE`; posibil calculat prin
|
|
interogari care filtreaza `VANZARI_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.
|