225 lines
14 KiB
Markdown
225 lines
14 KiB
Markdown
# Nota contabila pentru articol fara politica de pret (proiect #13)
|
|
|
|
Cercetare pe cod, fara modificari. Continua raportul anterior
|
|
`cont_venit_corespondente.md` (SCC vine prin lantul
|
|
`CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI.ID_NOTA -> CRM_NOTE_VANZARI.ID_SET -> NOTE_CONTABILE`,
|
|
citit de `cursor_articol` din `pack_facturare.contabilizeaza_articol`).
|
|
|
|
Sursa: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql`
|
|
(pachet `pack_facturare`, 17020 linii) si `D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg` +
|
|
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql` (pachet `pack_auto`).
|
|
|
|
---
|
|
|
|
## 1. Ce face `contabilizeaza_articol` cand `id_pol` e NULL/0
|
|
|
|
Raspuns: **ridica exceptia FACT-024 si intreruce functia, inainte sa ajunga la cursorul care
|
|
citeste SCC**. Nu exista o ramura de default si nu se scrie nota cu SCC NULL pentru acest caz.
|
|
|
|
Corpul complet e la `ff_...:7182-7556`. Primul lucru pe care il face (inainte de `cursor_articol`,
|
|
inainte de orice `scrie_nota`) e:
|
|
|
|
```
|
|
ff_...:7286-7311
|
|
BEGIN
|
|
SELECT COMPUS, ID_POL_ART
|
|
INTO V_COMPUS, V_ID_POL_ART
|
|
FROM VCRM_POLITICI_PRET_ART
|
|
WHERE ID_ARTICOL = detalii_articol.id_articol
|
|
AND ID_POL = detalii_articol.id_pol;
|
|
EXCEPTION
|
|
WHEN NO_DATA_FOUND THEN
|
|
SELECT DENUMIRE INTO lcArticol FROM NOM_ARTICOLE WHERE id_articol = detalii_articol.id_articol;
|
|
SELECT NUME_LISTA_PRETURI INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol;
|
|
RAISE_APPLICATION_ERROR(-20000,
|
|
'Articolul ' || detalii_articol.id_articol || '|' || lcArticol ||
|
|
' nu este definit in politica de preturi ' ||
|
|
detalii_articol.id_pol || '|' || lcPolitica || '! (FACT-024)');
|
|
END;
|
|
```
|
|
|
|
`ID_POL = detalii_articol.id_pol` cu `id_pol` NULL nu poate potrivi niciun rand in SQL standard
|
|
(`X = NULL` e necunoscut, nu adevarat) — deci pentru `id_pol` NULL sau 0 (presupunand ca nu exista
|
|
o politica cu `ID_POL = 0`), `SELECT INTO` intra mereu pe `NO_DATA_FOUND`.
|
|
|
|
**Observatie suplimentara, neceruta explicit dar relevanta**: in ramura de exceptie, al doilea
|
|
`SELECT ... INTO lcPolitica FROM CRM_POLITICI_PRETURI WHERE id_pol = detalii_articol.id_pol` sufera
|
|
de aceeasi problema — cu `id_pol` NULL, si acest `SELECT INTO` da tot `NO_DATA_FOUND`, care **nu e
|
|
tratat** in acest bloc (nu exista un al doilea handler). Deci mesajul FACT-024 "curat" (cu numele
|
|
politicii) nu s-ar afisa niciodata pentru cazul `id_pol IS NULL` — s-ar propaga o exceptie
|
|
`NO_DATA_FOUND` neprinsa din interiorul handler-ului, cu alt mesaj Oracle generic, nu FACT-024 cu
|
|
text. Codul articolului (`lcArticol`) apuca sa fie rezolvat inaintea acestui eșec, deci
|
|
identificarea articolului nu s-ar pierde in log/eroare, dar textul final ar fi ORA-01403, nu
|
|
mesajul FACT-024 formatat. Pentru `id_pol = 0` (nu NULL), daca exista vreo politica cu id 0, acel
|
|
`SELECT` ar reusi si mesajul FACT-024 ar iesi corect.
|
|
|
|
Cursorul `cursor_articol` (care citeste SCD/ASCD/SCC/ASCC din `NOTE_CONTABILE` prin lant) **nu se
|
|
mai deschide** — funcția a ridicat deja exceptia mai sus. Deci intrebarea "cursorul intoarce zero
|
|
randuri, ce face codul mai departe" nu se pune in acest caz: nu ajunge acolo.
|
|
|
|
Concluzie Q1: **orice linie de vanzare cu `id_pol` NULL/0 trimisa la `contabilizeaza_articol` in
|
|
starea actuala a codului arunca o eroare si opreste tranzactia** (nu scrie nota cu cont NULL, nu
|
|
pune default). Cerinta proiectului #13 ("articol din nomenclator fara politica de pret, pret
|
|
tastat manual, pe orice tip de document") ar lovi FACT-024 (sau exceptia neprinsa descrisa mai sus)
|
|
daca linia respectiva e trecuta prin acest cod neschimbat.
|
|
|
|
---
|
|
|
|
## 2. Validare la `scrie_nota` pentru cont NULL
|
|
|
|
Raspuns: **nu exista**. Corpul complet e la `ff_...:12338-12570`.
|
|
|
|
- Singura verificare care ar fi atins asta e comentata:
|
|
```
|
|
ff_...:12441-12453
|
|
/* IF V_SUMA IS NULL THEN
|
|
RAISE_APPLICATION_ERROR(...) ...
|
|
END IF;*/
|
|
```
|
|
Si oricum verifica `V_SUMA` (suma calculata), nu `V_SCD`/`V_SCC`.
|
|
- `INSERT INTO ACT_TEMP (... SCD, ASCD, SCC, ASCC ...)` (`ff_...:12458-12544`) insereaza direct
|
|
`V_SCD`/`V_ASCD`/`V_SCC`/`V_ASCC` primite ca parametri, fara niciun `NVL`/`CASE`/verificare de
|
|
NULL pe ele.
|
|
- Nu exista `NOT NULL` verificat in cod pentru aceste coloane in acest fisier (constrangerea ar fi
|
|
la nivel de DDL al tabelei `ACT`/`ACT_TEMP`, care nu face parte din pachetul PL/SQL cercetat —
|
|
vezi sectiunea Neverificat).
|
|
|
|
Deci daca cineva ar ocoli blocul de la punctul 1 (de ex. printr-un `id_pol` care *exista* in
|
|
`CRM_POLITICI_PRET_ART` dar al carui lant `CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`
|
|
e incomplet, asa incat `D.SCC` iese NULL din LEFT JOIN), `scrie_nota` ar scrie nota cu `SCC = NULL`
|
|
fara sa protesteze. Asta e insa un scenariu diferit de "fara politica de pret" (aici politica exista,
|
|
dar lantul de sub ea e incomplet) — nu e cazul cerut de proiectul #13 asa cum a fost formulat.
|
|
|
|
---
|
|
|
|
## 3. Toti apelantii lui `contabilizeaza_articol` in fisier
|
|
|
|
Cautare exhaustiva `Grep 'contabilizeaza_articol'` pe tot fisierul: 3 apeluri (in afara de propria
|
|
definitie si un comentariu):
|
|
|
|
| Linie | Procedura apelanta | Domeniu / flux |
|
|
|---|---|---|
|
|
| `ff_...:6150` | `scrie_factura2` (corp `ff_...:6029-6272`) | **Fluxul principal de scriere** — pentru orice document ale carui randuri nu cad in ramurile speciale ale `CASE`-ului de la `ff_...:6081-6151`: transfer intre subunitati (`ntip IN (23,25,30,41)`), factura/aviz custodie (`ntip IN (42,47)`), rata cu `id_rata<>0` (`ntip IN (2,6,52)`). Toate celelalte tipuri — **factura normala** (`ntip<=20`), hotel, restaurant, nota de plata, vanzare retail, tipurile 48/49/51/52, aviz simplu, aviz catre clienti debitori, si **aviz retur (tip 24)** cand e scris prin `scrie_factura2` — ajung la `contabilizeaza_articol` aici. Aceasta e apelarea "de baza" pe care se sprijina interpretarea corpului functiei facuta la punctul 1 (ramurile `CASE` din interiorul `contabilizeaza_articol`, `ff_...:7407-7432`, mapeaza direct pe tipurile de document tratate de acest apelant). |
|
|
| `ff_...:6867` | `scrie_factura_avize_retur` (corp `ff_...:6273-6666`) | Flux **factura scrisa pe baza de avize + retur simultan**. Apelul e in interiorul buclei pe `articole_aviz` (`ff_...:6841-6960` zona), pentru randurile cu `custodie = 1` (marfa in custodie ce se descarca din avize). |
|
|
| `ff_...:7149` | `scrie_aviz_retur` (corp `ff_...:7094-7180`) | Procedura dedicata **aviz retur** (`V_ID_DELEGAT, V_ID_MASINA, ...`). Apelul e in ramura `ELSE` a testului `pack_facturare.nfactavizcust = 1` (`ff_...:7124-7150`) — deci pentru randurile care **nu** sunt in custodie. |
|
|
|
|
Concluzie Q3: **da**, `contabilizeaza_articol` e apelata pe fluxul principal de facturare
|
|
(`scrie_factura2`, care acopera factura normala si majoritatea celorlalte tipuri de document), nu
|
|
doar din `scrie_aviz_retur`. Raportul anterior lasase asta neverificat; e confirmat aici cu cele 3
|
|
puncte de apel gasite si citate mai sus — nu exista un al 4-lea apel in fisier.
|
|
|
|
---
|
|
|
|
## 4. Precedentul ROAAUTO "Alte servicii" — **nu e de fapt un precedent pentru cazul cerut**
|
|
|
|
Asta contrazice premisa din cerere. Firul (`crsalteserv -> crsvanztemp -> adauga_articol_factura_deviz`)
|
|
duce spre un flux care **ocoleste complet `contabilizeaza_articol`**, deci nu demonstreaza ce se
|
|
intampla in `pack_facturare` pentru un articol fara politica — demonstreaza doar ca exista un *alt*
|
|
mecanism de contabilizare, in afara pachetului `pack_facturare`.
|
|
|
|
Pasii, cu citate:
|
|
|
|
1. **`crsalteserv -> crsvanztemp`** (`D:\ROA\ROAAUTO\Programe\oproceduri_devize.prg:1040-1041`):
|
|
```
|
|
Insert Into (lcCursorDeviz)(id_articol,denumire,explicatie,cantitate,um,id_jtva_coloana,proc_Tvav,taxcode,pret,discount_unitar) ;
|
|
Select id_articol,denumire,"",cantitate,um,CAST(lnIdJTvaColoana as N(6) null) as id_jtva_coloana,CAST(lnProcTvav as N(7,2) null) as proc_tvav,CAST(lnTaxCode as N(6) null) as taxcode,pretftva,0 From crsalteserv Where !Deleted()
|
|
```
|
|
Nu exista coloana `id_pol` in `crsalteserv`, in `lcCursorDeviz`, sau in cursorul `crsvanztemp`
|
|
creat la `oproceduri_devize.prg:1190-1192` (schema explicita a cursorului nu include `id_pol`).
|
|
|
|
2. **`crsvanztemp -> adauga_articol_factura_deviz`** (`oproceduri_devize.prg:1240-1257`): apelul RPC
|
|
trimite `id_articol, explicatie, serie, pret_achizitie, pretd, id_valuta_d, pret, id_valuta,
|
|
curs, multiplicator, proc_tvav, id_jtva_coloana, cantitate, discount_unitar, id_gestiune, cont,
|
|
pret_cu_tva, NULL, NULL, taxcode` — **fara `id_pol`**, pentru ca procedura insasi nu are un
|
|
parametru `id_pol`.
|
|
|
|
3. **Semnatura `adauga_articol_factura_deviz`** (spec `ff_...:468-488`, corp `ff_...:4675-4745`):
|
|
nu exista `V_ID_POL IN NUMBER` printre parametri. `INSERT INTO VANZARI_DETALII_TEMP` la
|
|
`ff_...:4697-4744` **nu include coloana `ID_POL`** in lista de coloane inserate — deci
|
|
`ID_POL` ramane pe valoarea implicita a coloanei (probabil NULL; DDL-ul tabelei nu face parte
|
|
din pachetul cercetat, vezi Neverificat). **Asta confirma partea (a) a intrebarii: da, liniile
|
|
"alte servicii" ajung cu `id_pol` gol** in `VANZARI_DETALII_TEMP`.
|
|
|
|
4. **Dar acele randuri nu trec niciodata prin `contabilizeaza_articol`.** Apelantul din
|
|
`oproceduri_devize.prg` nu cheama `scrie_factura2` / `scrie_factura_avize` / `scrie_aviz_retur`
|
|
(singurele proceduri care cheama `contabilizeaza_articol`, vezi punctul 3). In schimb cheama, in
|
|
ordine (`oproceduri_devize.prg:1211-1310`):
|
|
- `pack_facturare.initializeaza_date_factura(...)`
|
|
- bucla `pack_facturare.adauga_articol_factura_deviz(...)` (doar insert in `VANZARI_DETALII_TEMP`)
|
|
- opțional `pack_facturare.scrie_incasari(...)` (incasare, nu venit din vanzare)
|
|
- `pack_facturare.scrie_in_vanzari(0, ...)` (`ff_...:13497-13962`)
|
|
- `pack_auto.actualizeaza_deviz(...)` (`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`)
|
|
|
|
**`scrie_in_vanzari` nu scrie nici o nota contabila de venit.** Corpul complet
|
|
(`ff_...:13497-13962`) face: `INSERT INTO VANZARI` (antetul documentului), `scrie_cursuri`,
|
|
`scrie_seturi`, apoi
|
|
```
|
|
ff_...:13714-13766
|
|
INSERT /*+ APPEND */ INTO VANZARI_DETALII (..., ID_POL, ...)
|
|
SELECT ..., ID_POL, ... FROM VANZARI_DETALII_TEMP;
|
|
```
|
|
(copiaza `ID_POL` — care e NULL pentru aceste randuri — direct in `VANZARI_DETALII`, fara nicio
|
|
validare), si la final actualizeaza totalurile cache pe `VANZARI`. **Nu apare niciun apel catre
|
|
`contabilizeaza_articol`, `scrie_nota`, `cumuleaza_note_act` sau `finalizeaza_factura` in acest
|
|
corp** (verificat citind procedura cap-coada).
|
|
|
|
`pack_auto.actualizeaza_deviz` (`ff_2026_03_31_02_AUTO_PACK_AUTO.sql:692-733`) face doar:
|
|
```
|
|
SELECT MAX(ID_FACT) INTO lnIdFact FROM ACT WHERE COD = pack_contafin.get_cod() AND SCD NOT LIKE '5%';
|
|
UPDATE DEV_ORDL SET PROC_TVAV = ... WHERE ID_ORDL IN (...);
|
|
UPDATE RUL SET ID_FACT = lnIdFact WHERE ...;
|
|
UPDATE NOM_LUCRARI SET ID_FACT = lnIdFact WHERE ... (doar pt anumite id_set);
|
|
```
|
|
Adica **presupune ca exista deja un rand in `ACT`** (nu `ACT_TEMP`) cu `SCD NOT LIKE '5%'` pentru
|
|
codul documentului curent, si doar propaga `ID_FACT` gasit acolo spre `DEV_ORDL`/`RUL`/`NOM_LUCRARI`.
|
|
Nu insereaza el insusi in `ACT` sau `NOTE_CONTABILE`, si nu contine nicio referinta la `SCC`,
|
|
`NOTE_CONTABILE` sau `CRM_POLITICI*` (cautat explicit, zero rezultate in acest fisier).
|
|
|
|
**Concluzie Q4, corectand premisa din cerere**: liniile "Alte servicii" chiar ajung cu `id_pol` gol
|
|
(confirmat), dar **nu demonstreaza ca `contabilizeaza_articol` tolereaza `id_pol` gol** — pentru ca
|
|
nu trec niciodata prin el. Ele demonstreaza doar ca exista deja, pentru fluxul deviz ROAAUTO, o cale
|
|
de facturare paralela (`scrie_in_vanzari` + `pack_auto.actualizeaza_deviz`) care **nu genereaza deloc
|
|
nota contabila de venit prin `pack_facturare`**. Daca acele randuri capata totusi un cont de venit in
|
|
`ACT`/`NOTE_CONTABILE` in productie, mecanismul nu e vizibil in codul cercetat (posibil un
|
|
trigger pe tabel, un job batch, sau o scriere manuala/alt modul neexaminat — vezi Neverificat).
|
|
**Nu se poate folosi acest precedent ca raspuns de fapt la intrebarea 1.**
|
|
|
|
---
|
|
|
|
## 5. Vreun mecanism care sa foloseasca `NOM_ARTICOLE.CONT` drept cont de venit
|
|
|
|
Raspuns: **NU**, in `pack_facturare`.
|
|
|
|
Cautat explicit `Grep -i 'NOM_ARTICOLE\.CONT'` pe intregul fisier
|
|
`ff_2026_08_06_10_COMUN_PACK_FACTURARE.sql` (17020 linii) — **zero potriviri**. Singurele utilizari
|
|
ale `NOM_ARTICOLE` gasite in `contabilizeaza_articol` insusi sunt pentru `DENUMIRE` (mesajul de
|
|
eroare FACT-024, `ff_...:7295-7298`), nu pentru `CONT`.
|
|
|
|
`crs_rand_articol.scc` (folosit ca `V_SCC` la `ff_...:7434`) vine exclusiv din
|
|
`D.SCC` din join-ul `CRM_POLITICI_PRET_ART -> CRM_POLITICI_PRETURI -> CRM_NOTE_VANZARI -> NOTE_CONTABILE`
|
|
(`ff_...:7261, 7275-7276`) — nu exista ramura alternativa care sa substituie `NOM_ARTICOLE.CONT`
|
|
cand politica lipseste. (Raportul anterior confirmase deja separat ca `NOM_ARTICOLE.CONT` e folosit
|
|
doar ca **cont de gestiune**, transmis catre `descarca_gestiune`, `ff_...:7499`.)
|
|
|
|
---
|
|
|
|
## Neverificat
|
|
|
|
- **Continutul efectiv al `NOTE_CONTABILE`/`CRM_POLITICI_PRET_ART`** (daca exista politici cu
|
|
`ID_POL = 0`, ce SCC au liniile din productie pentru documente "alte servicii" existente) —
|
|
necesita interogare pe baza de date, nu doar cod.
|
|
- **Constrangerile DDL** ale `VANZARI_DETALII_TEMP.ID_POL` si `ACT_TEMP.SCC`/`ACT.SCC` (NOT NULL?
|
|
default?) — scripturile DDL ale acestor tabele nu au fost cautate/citite in aceasta cercetare
|
|
(am cautat doar in pachetele PL/SQL `ff_...COMUN_PACK_FACTURARE.sql` si `..._AUTO_PACK_AUTO.sql`).
|
|
- **Cine scrie efectiv contul de venit (`ACT`/`NOTE_CONTABILE`) pentru documentele "alte servicii"
|
|
din ROAAUTO**, daca se scrie deloc. `pack_auto.actualizeaza_deviz` presupune ca exista deja un
|
|
rand `ACT` cu `SCD NOT LIKE '5%'` pentru codul documentului curent — sursa acelui rand nu a fost
|
|
gasita in `oproceduri_devize.prg` sau in corpul `scrie_in_vanzari`/`actualizeaza_deviz` cercetate.
|
|
Ar trebui cautat: alte proceduri `pack_auto` (fisierul `ff_2026_03_31_02_AUTO_PACK_AUTO.sql` are
|
|
si alte proceduri necercetate aici), triggere pe `VANZARI`/`VANZARI_DETALII`/`ACT`, sau apeluri
|
|
din alte forme VFP (`.scx`/`.vcx`) din ROAAUTO care preced acest apel RPC. Nu am cautat exhaustiv
|
|
triggere in afara folderului `SCRIPTURI_CLAR\2026` (cautare limitata, zero rezultate acolo).
|
|
- **Ce se intampla exact daca `id_pol = 0` si exista o politica reala cu `ID_POL = 0`** (caz
|
|
teoretic, neexclus explicit din schema) — ar schimba concluzia de la "eroare neprinsa" la
|
|
"FACT-024 cu mesaj complet", dar tot ramane o eroare, nu un default silentios.
|