Files
roafacturare/docs/cercetare/garda_aviz_facturat.md
Marius Mutu d9f5ca4226 docs: planurile, proiectarile si rapoartele de lucru intra in versionare
Folderul docs\ era pana acum in afara oricarui control de versiuni - nici git,
nici SVN - desi contine planurile pe puncte, proiectarile si rapoartele de
cercetare pe care se sprijina modificarile din cod. O stergere acolo era
definitiva.

Fisierele intermediare (handoff-uri intre sesiuni, diff-uri deja aplicate) au
fost sterse inainte, nu versionate: ce era durabil in ele a intrat in antetele
fisierelor de test la care se refereau.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-11 22:17:17 +03:00

236 lines
13 KiB
Markdown

# Garda "aviz deja facturat" — verificare pe cod
Verificare pe cod, fara nicio modificare de fisier. Sursele citate:
- export pachet: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`
(mai jos: `EXPORT:<linie>`);
- corpul **desfasurat pe DB** (`MARIUSM_AUTO@ROA_CENTRAL`, `all_source`), citit ca sa se confirme ca
ce e in export e si ce ruleaza (mai jos: `DB PACK_FACTURARE:<linie>`). **Numerotarea difera**:
`sterge_factura` incepe la `EXPORT:5432`, dar la `DB PACK_FACTURARE:4192`. Nu exista offset
constant; textul insa e identic cuvant cu cuvant pe zona gardelor.
---
## 1. Blocheaza garda de azi si un AVIZ care are deja factura generata din el?
**DA.** Nu e nevoie de nicio garda noua pentru cazul asta — este exact ce testeaza a doua garda din
`sterge_factura`, prin `TIP IN (1, 2)`.
`EXPORT:5464-5476` = `DB PACK_FACTURARE:4224-4236`:
```
-- ptr. un aviz normal:
-- verific daca exista facturi sau avize de retur pe avizul resp.
SELECT COUNT(*)
INTO V_NR_AVIZE_FACT
FROM VANZARI_CORESP
WHERE STERS = 0
AND ID_VANZARE_AVIZ = V_ID_VANZARE
AND TIP IN (1, 2);
IF V_NR_AVIZE_FACT > 0 THEN
RAISE_APPLICATION_ERROR(-20000,
'Pe acest aviz s-au emis facturi / aviz de retur. Trebuie sa stergeti mai intai facturile / avizul de retur!');
END IF;
```
Cheia e semantica lui `TIP`, citita din **singurul scriitor** al tabelei, ramura cu ramura
(`finalizeaza_factura`, `EXPORT:14818-14839`):
| `VANZARI_CORESP.TIP` | scris cand | `ID_VANZARE_FACT` | `ID_VANZARE_AVIZ` | e retur? |
|---|---|---|---|---|
| **1** | `ntip = 4` — facturare din aviz (`EXPORT:14823-14826`) | factura | avizul-sursa | **NU** |
| 2 | `ntip = 24` — aviz de retur (`EXPORT:14828-14830`) | avizul de retur | avizul original | DA |
| 3 | `ntip in (8, 9)` — factura de retur (`EXPORT:14834-14836`) | factura de retur | factura originala | DA |
Deci `TIP = 1` este **corespondenta aviz -> factura normala**, nu retur. Garda de la `EXPORT:5473`
prinde ambele cazuri; textul mesajului chiar o spune ("s-au emis **facturi** / aviz de retur").
Formularea din brief ("garda de azi blocheaza documentul care are facturi/avize **de retur**") vine
dintr-o citire a comentariului `-- verific daca exista facturi sau avize de retur` in care "de retur"
se distribuie si peste "facturi"; codul zice altceva.
Deci: la ora asta, **exact regula ceruta de decizia 50 este deja implementata pentru avize**
(document cu urmasi = blocat; capatul lantului = liber).
### Ce NU citeste garda
- **`VANZARI.FACTURAT` nu e citit de nicio garda.** Pe calea de stergere e doar **scris**
(`EXPORT:5504-5510` pentru `V_TIP = 24`, `EXPORT:5527-5533` pentru `V_TIP = 4` — resetare la 0
cand dispare factura/avizul de retur), iar la facturare e **pus** de `marcheaza_facturat`
(`EXPORT:15381-15418`). Niciun `IF` / `RAISE` nu il interogheaza. Semnalul autoritar este
`VANZARI_CORESP`, `FACTURAT` e derivat redundant.
- **`ID_VANZARE_SURSA` / `ID_VANZARE_DEST` nu exista.** `VANZARI_CORESP` are exact 5 coloane
(interogare pe `all_tab_columns`): `ID_VANZARE_CORESP`, `ID_VANZARE_FACT`, `ID_VANZARE_AVIZ`,
`STERS`, `TIP`. Nici `VANZARI` nu are coloane `*_SURSA` / `*_DEST` (aceeasi interogare).
---
## 2. Exista alte garzi pe calea de stergere / modificare?
### 2a. Oracle — nu exista alta, dar garda e **atinsa pe ambele ramuri** de stergere
Interogare pe `all_source` (owner curent): singurele obiecte care contin `VANZARI_CORESP` sunt
**`PACK_FACTURARE` (package body)** si **`TRG_VANZARI_CORESP_BEFOINS`**. Deci nu exista o a doua
garda ascunsa in alt pachet.
**Triggerele nu contin garzi** (sursa citita integral din `all_source`):
| trigger | tabela | eveniment | ce face |
|---|---|---|---|
| `TRG_VANZARI_BEFOUPD` | `VANZARI` | UPDATE | 4 apeluri `pack_audit.verifica_val` (NR_ACT, SERIE_ACT, DATA_ACT, DATA_SCAD) — audit, nu blocare |
| `TRG_VANZARE_BEFOINS` | `VANZARI` | INSERT | — |
| `TRG_VANZARI_DET_BEFOINS` | `VANZARI_DETALII` | INSERT | — |
| `TRG_VANZARI_CORESP_BEFOINS` | `VANZARI_CORESP` | INSERT | doar `SEQ_VANZARI_CORESP.nextval` |
**Punct important de verificat, pentru ca la prima citire pare o portita:** in
`frm_facturi.do_sterge` apelul direct `pack_facturare.sterge_factura` e **comentat** pe ramura
documentelor cu note contabile — `ofacturare_comun.vc2:4807-4809` (`*!* modificare v 2.2.5`), iar
ramura activa (`:4810-4811`) cheama numai `pack_contafin.finalizeaza_stergere_nota`. **Nu e o
portita**: lantul se inchide in Oracle.
```
PACK_CONTAFIN:8322-8326 SELECT COUNT(*) INTO lnEInVanzari FROM vanzari WHERE cod = tnCod;
IF lnEInVanzari > 0 THEN
pack_facturare.sterge_din_vanzari(tnCod, tnAn, tnLuna, tnIdUtil);
PACK_FACTURARE:14996-14998 SELECT ID_VANZARE INTO V_ID_VANZARE FROM VANZARI WHERE COD = V_COD;
pack_facturare.sterge_factura(V_ID_VANZARE, V_LUNA, V_AN, V_ID_UTIL);
```
Apelantii lui `sterge_factura` in baza (cautare pe `all_source`) sunt exact doi:
`PACK_FACTURARE.sterge_din_vanzari` (`DB PACK_FACTURARE:14998`) si procedura standalone
`STERGE_DOCUMENT` (`DB STERGE_DOCUMENT:416`). Ambele cai trec prin garda.
### 2b. VFP — pe calea de stergere: nicio garda pe urmasi
`frm_facturi.do_sterge` (`COMUN\clase\ofacturare_comun.vc2:4661-4877`) verifica, inainte de apel:
luna inchisa (`:4676`), `sters = 1` (`:4689`), confirmare (`:4694`), luna curenta (`:4701`) si
referinte de incasari/plati (`ReferinteDocumenteNota`, `:4723-4727`). **Nimic despre `FACTURAT`,
`VANZARI_CORESP` sau urmasi** — verificarea lantului e delegata integral Oracle-ului.
### 2c. VFP + Oracle — pe calea de **modificare**: nicio garda, nici pe urmasi, nici pe lant
`frm_facturi.do_modifica` (`ofacturare_comun.vc2:4541-4640`) blocheaza doar doua lucruri
(`:4590`, `:4635`):
```
If poRec.sters = 0 AND NVL(m.pnEFactura,0) = 0
...
amessagebox("Nu puteti face modificari pe inregistrarile sterse sau facturile trimise in eFactura!", 48, "Atentie")
```
`pack_facturare.modifica_date_factura` (`EXPORT:14439-14509`) e un lant de `UPDATE`-uri fara niciun
`IF` de validare si fara niciun `RAISE_APPLICATION_ERROR`. Ceea ce e coerent cu ce modifica azi
(ruta, delegat, agent, masina, dataora exp., text aditional, tip SAFT, eFactura, serie/numar/data act,
data scadenta) — campuri de antet care nu ating lantul aviz -> factura.
---
## 3. Concluzia operationala pentru decizia 50 / S7
**Regula ceruta de decizia 50 exista deja, si nu are gol pe aviz.** `sterge_factura` implementeaza
azi, in trei garzi consecutive, exact "documentul cu urmasi e blocat, capatul lantului e liber":
| garda | `EXPORT` | ce blocheaza |
|---|---|---|
| 1 | 5452-5462 | **factura** care are facturi de retur peste ea (`TIP = 3`) |
| 2 | 5466-5476 | **aviz** care are factura (`TIP = 1`) sau aviz de retur (`TIP = 2`) peste el |
| 3 | 5480-5494 | **factura din aviz** ale carei avize-sursa au primit intre timp aviz de retur |
A treia garda merita subliniata pentru decizia 50: factura din aviz e editabila **doar** cat timp
niciunul dintre avizele ei nu are aviz de retur; nu e "capat de lant" neconditionat.
**Deci S7 nu are nevoie de o garda noua ca regula — dar are nevoie de o citire noua a aceleiasi
conditii, ca moment.** Garda de azi e in interiorul lui `sterge_factura`, adica se manifesta ca
`ORA-20000` **in mijlocul** pasului de stergere din regenerare, dupa ce utilizatorul a completat
formularul si dupa ce s-a deschis tranzactia. Pentru un flux de editare asta e o esuare tarzie.
Ce lipseste e un **pre-flight read-only**, inainte de intrarea in formular, pe exact aceeasi
conditie (fara reimplementarea regulii):
```sql
select count(*) from vanzari_coresp
where sters = 0 and id_vanzare_aviz = :id_vanzare and tip in (1, 2, 3)
```
plus, pentru cazul "factura din aviz", subinterogarea din garda 3 (`EXPORT:5480-5488`). Garda din
`sterge_factura` ramane pe loc ca plasa de siguranta — nu se muta, nu se slabeste.
Interogarea se face pe `VANZARI_CORESP`, **nu** pe `VANZARI.FACTURAT`: `FACTURAT` e un marcaj
redundant, derivat, scris/resetat de `marcheaza_facturat` / `sterge_factura`, si necitit de nicio
garda; `VANZARI_CORESP` e semnalul autoritar.
---
## 4. Inventar: ce tipuri de documente-parinte produc urmasi prin `VANZARI_CORESP`?
**Doar trei, toate scrise din acelasi `CASE` din `finalizeaza_factura` (`EXPORT:14818-14839`), prin
singurul scriitor `scrie_corespondente_vanzari` (`EXPORT:15481-15516`, singurul `INSERT INTO
VANZARI_CORESP` din tot pachetul — si din toata baza, cf. `all_source`).**
| parinte | urmas | `TIP` | de unde vine lista parintilor |
|---|---|---|---|
| **aviz** (`VANZARI.TIP in 21, 22, 26, 42`) | factura din aviz (`ntip = 4`) | 1 | `clistaid_avize`, setat la `EXPORT:7037` in `scrie_factura_avize`; lista o construieste VFP prin `caut_avize`, filtrata `a.tip in (21,22,26,42) and a.facturat = 0` — `COMUN\programe\oproceduri_facturare.prg:2036-2038` |
| **aviz** | aviz de retur (`ntip = 24`) | 2 | `clistaid` |
| **factura** | factura de retur (`ntip in 8, 9`) | 3 | `clistaid` |
**Ce NU produce urmasi prin `VANZARI_CORESP`** (deci decizia 50 nu are acoperire acolo prin garda
existenta):
- **proforma -> factura.** Proforma sta in `VANZARI` cu `EPROFORMA = 1`; `finalizeaza_factura` nu are
ramura care sa scrie corespondenta pentru ea. `TIP = 4` este o **propunere** de la S5c, nu cod
existent. Mai mult, `pack_facturare.sterge_proforma` (`EXPORT:5610-5635`) **nu are nicio garda** —
corpul ei e doar doua `UPDATE ... SET STERS = 1` pe `VANZARI` si `VANZARI_DETALII`. O proforma din
care s-a emis factura se poate sterge azi fara niciun avertisment. (Calea VFP:
`ofacturare_comun.vc2:4707-4719`, care iese din `do_sterge` inainte de restul verificarilor.)
- **comanda -> factura.** Legatura e `VANZARI.ID_COMANDA` + `pack_facturare.inchide_comanda`
(`EXPORT:5769`), nu `VANZARI_CORESP`. `COMENZI` **nu are coloana `FACTURAT`** (verificat pe
`all_tab_columns`) — flagul `facturat` din grid vine din view-ul de incarcare. Garda exista, dar e
**in VFP si pe comanda**, nu pe factura: `COMUN\clase\ocomenzi.vc2:1806-1807` la modificare
("Aceasta comanda a fost facturata si nu mai poate fi modificata!") si `:2065-2066` la stergere.
- **contract -> factura.** Legatura e `VANZARI.ID_CTR` + `CTR_RATE_FACTURI`
(atinsa de `sterge_factura` la `EXPORT:5566-5580` pentru `V_TIP IN (2, 6, 52)`); nicio linie in
`VANZARI_CORESP`, nicio garda de tip "are urmasi".
---
## 5. Ce am verificat direct vs. ce am dedus
**Verificat direct pe cod / pe metadate:**
- textul celor trei garzi din `sterge_factura`, in export **si** desfasurat din `all_source` (identice);
- `CASE`-ul din `finalizeaza_factura` care da semantica lui `TIP`, ramura cu ramura;
- corpul lui `scrie_corespondente_vanzari` si `marcheaza_facturat`;
- ca `INSERT INTO VANZARI_CORESP` exista intr-un singur loc (grep pe export + `all_source` pe toata baza);
- sursa integrala a celor 4 triggere de pe `VANZARI` / `VANZARI_DETALII` / `VANZARI_CORESP`;
- lista completa a apelantilor lui `sterge_factura` (`all_source`), inclusiv lantul
`finalizeaza_stergere_nota -> sterge_din_vanzari -> sterge_factura`;
- coloanele reale ale `VANZARI_CORESP`, `PROFORME`, si absenta lui `FACTURAT` din `COMENZI`
(`all_tab_columns`);
- `frm_facturi.do_sterge` si `frm_facturi.do_modifica` integral, plus `modifica_date_factura`;
- filtrul `caut_avize` din `oproceduri_facturare.prg`.
**Dedus / cu limite declarate:**
- Ca `TIP = 1` inseamna "factura normala din aviz" e o deductie din singurul punct de scriere
(`ntip = 4` -> `scrie_corespondente_vanzari(1)`) — solida, dar e deductie, nu o eticheta declarata
intr-un nomenclator.
- Ca setul tipurilor-parinte pentru `TIP = 1` e `{21, 22, 26, 42}` vine din filtrul VFP `caut_avize`,
nu dintr-o restrictie in Oracle. Pachetul insereaza **orice** `ID_VANZARE` primit in
`clistaid_avize`, fara filtru pe tip (`EXPORT:15494-15504`). Alt apelant (alt produs ROA, un import)
ar putea introduce alte tipuri.
- Nu am verificat daca vreun **alt produs ROA** (ROACONT / ROAGEST / ...) are o cale proprie de
stergere care ocoleste `sterge_factura`. Am verificat doar ca in Oracle nu exista alt apelant si
ca in ROAFACTURARE ambele ramuri din `do_sterge` ajung acolo.
**Din date, deci nedovaditor:** interogarea pe `VANZARI_CORESP` din baza de dev arata `TIP=1` cu
parinti de tip 21 si 22, `TIP=2` cu parinte 22, `TIP=3` cu parinte 1 — consistent cu tabelul de mai
sus, dar volumul e de ordinul unitatilor (8 randuri in total). **Nu e dovada**; concluziile de mai
sus vin din cod.
## 6. Ce nu s-a putut stabili
Nimic din cele 4 intrebari nu a ramas nedeterminat. Singurul punct pe care l-as lasa explicit
deschis pentru S7 este cel de la §4: **golul real nu e pe aviz, e pe proforma** —
`sterge_proforma` nu are absolut nicio garda, iar daca S5c chiar introduce `TIP = 4`
(proforma -> factura), garda din `sterge_factura` **nu se aplica automat**, pentru ca `sterge_proforma`
e o procedura complet separata care nu o apeleaza.