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
229 lines
16 KiB
Markdown
229 lines
16 KiB
Markdown
# Cercetare: legatura "linie de retur -> linie/factura originala" se persista undeva?
|
|
|
|
## Verdict (10 randuri)
|
|
|
|
**NU se persista la nivel de linie. PARTIAL la nivel de document, si numai cand a fost aleasa o
|
|
singura factura sursa.** Cursorul Oracle care populeaza grila de retur pentru N.1 (documente tip
|
|
8/9/24, `pack_facturare.cursor_retur_document`, `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:3949-4062`)
|
|
**nu selecteaza deloc** `A1.ID_VANZARE` sau `A1.ID_VANZARE_DET` din `VANZARI_DETALII` — legatura cu
|
|
factura/linia sursa se pierde chiar in query-ul care aduce datele in VFP, inainte sa existe vreo
|
|
sansa sa fie afisata. INSERT-ul final in `VANZARI_DETALII` (`scrie_in_vanzari`, documentat deja in
|
|
`rec_cale_vanzari_detalii.md:105-113`) nu are nicio coloana de tip sursa. Exista in schimb un link
|
|
**la nivel de document intreg**: `VANZARI_CORESP` (`TIP=3`, `ID_VANZARE_FACT`=documentul de retur,
|
|
`ID_VANZARE_AVIZ`=fiecare factura sursa aleasa) — dar cand utilizatorul alege mai multe facturi
|
|
sursa deodata (selectie multipla, suportata explicit de dialog), acest link iti da **multimea** de
|
|
facturi posibile, nu factura exacta a liniei. Pentru N.2 (`But_retur`, per articol) nu exista niciun
|
|
document nou scris separat — returul e o linie in factura normala curenta, iar "sursa" e verificata
|
|
doar la nivel de stoc (`RUL`/`STOC` filtrat pe `COD` legat de `VANZARI.ID_VANZARE`), nu persista ca
|
|
atribut al liniei noi. Concluzie pentru S4f: **se livreaza fara coloana de provenienta pe linie**;
|
|
cel mult se poate afisa, cand e un singur document sursa, "factura de retur X provine din factura Y"
|
|
la nivel de document (din `VANZARI_CORESP`), nu per linie.
|
|
|
|
## 1. Ce face Oracle cu `poDate.listaid`
|
|
|
|
Doua cai, in functie de mecanism:
|
|
|
|
**N.1 (document, tip 8/9/24)**: `poDate.listaid` = CSV de `id_vanzare` (facturile alese la pasul de
|
|
cautare multipla, `ofacturare.vc2:9200`: `poDate.listaid = cursor2lista("crsFacturiTemp", "id_vanzare", ",")`).
|
|
Ajunge la Oracle ca parametru `V_LISTAID` in `pack_facturare.cursor_retur(V_IN_VALUTA, V_LISTAID,
|
|
V_ID_UTIL, V_CURSOR)` (`ff_...sql:3934-3947`), care e doar un wrapper peste
|
|
`cursor_retur_document(V_IN_VALUTA, V_LISTAID, V_COPIERE=0, V_PROFORMA, V_ID_UTIL, V_CURSOR)`
|
|
(`:3949-4062`). Acolo `V_LISTAID` devine CTE-ul `CRS` (`:3962-3964`):
|
|
```sql
|
|
WITH CRS AS (SELECT X as ID_VANZARE FROM table(charn2collection(V_LISTAID, V_SEPARATOR)))
|
|
```
|
|
folosit doar ca filtru: `WHERE A1.STERS = 0 AND A1.ID_VANZARE IN (SELECT ID_VANZARE FROM CRS)`
|
|
(`:4054-4055`). **Filtru, nu persistare** — dupa acest `WHERE`, `ID_VANZARE` nu mai apare deloc in
|
|
lista de coloane a `SELECT`-ului extern (`:3965-4028`: `ID_C` (=`ROWNUM`, sintetic), `ID_ARTICOL`,
|
|
`LOT`, `SERIE`, `ID_POL`, preturi, `GESTIONABIL`, `CANTITATE`, `ID_GESTIUNE`, `PRET_ACHIZITIE`... dar
|
|
nu `ID_VANZARE` si nu `ID_VANZARE_DET`). Cursorul primit de VFP in `crsarticole` nu are, deci, nicio
|
|
coloana care sa spuna din ce factura/linie vine randul.
|
|
|
|
Separat, la scrierea efectiva a documentului de retur, `scrie_corespondente_vanzari(3)`
|
|
(`:14834-14836`, apelata din `finalizeaza_factura`) foloseste tot `pack_facturare.clistaid`
|
|
(= acelasi `poDate.listaid`, tinut in variabila de sesiune a pachetului) ca sa scrie in
|
|
`VANZARI_CORESP` (`:15481-15516`):
|
|
```sql
|
|
INSERT INTO VANZARI_CORESP (ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP)
|
|
SELECT pack_facturare.nid_vanzare, ID_VANZARE, 3
|
|
FROM VANZARI WHERE ID_VANZARE IN (SELECT X FROM table(charn2collection(V_LISTAID,',')));
|
|
```
|
|
Asta scrie **cate un rand per factura sursa aleasa** (nu per linie), cu noul document de retur ca
|
|
`ID_VANZARE_FACT` si fiecare sursa ca `ID_VANZARE_AVIZ` (numele coloanei e generic, reutilizat si
|
|
pentru perechi aviz-factura, `TIP=1/2`, vezi `sterge_factura:5452-5457,5582-5585`).
|
|
|
|
**N.2 (`But_retur`, per articol)**: `poDate.listaid` = `"ID_ARTICOL:ID_VANZARE"` (una sau mai multe
|
|
perechi CSV, `ofacturare.vc2:12888`: `thisform.cListaIdArticoleRetur = ... + STR(poArticol.id_articol) + ':' + poDate.listaid`,
|
|
trimis la Oracle la `:13978`). In `pack_facturare` (verificat in ramura `WHEN V_CANTE < 0 and
|
|
pack_facturare.clistaid is not null and instr(pack_facturare.clistaid, ':') > 0`,
|
|
`ff_...sql:8142-8212`) e folosit ca filtru pentru calculul cantitatii disponibile de retur din
|
|
rulaj (`RUL`), NU ca sa scrie o legatura:
|
|
```sql
|
|
AND A.COD IN (SELECT COD FROM VANZARI WHERE ID_VANZARE IN
|
|
(SELECT id_vanzare FROM (SELECT CAST(GETWORDNUM(id_articol_id_vanzare,1,':') AS NUMBER(20,0)) id_articol,
|
|
CAST(GETWORDNUM(id_articol_id_vanzare,2,':') AS NUMBER(20,0)) id_vanzare
|
|
FROM (SELECT x AS id_articol_id_vanzare FROM table(cast(CHARC2COLLECTION(pack_facturare.clistaid,',') AS char_tab))))
|
|
WHERE id_articol = V_ID_ARTICOL))
|
|
```
|
|
Foloseste `listaid` doar ca sa restranga `RUL` la miscarile de stoc (`A.COD`) legate de factura
|
|
aleasa, ca sa calculeze **cantitatea inca disponibila in gestiune din acea vanzare** pentru articolul
|
|
respectiv (`tab_stoc`, tip=1 in acel `SELECT`). Nu se scrie nicio linie noua de legatura in vreun
|
|
tabel — e folosit exclusiv ca filtru intr-un calcul de disponibil.
|
|
|
|
## 2. Coloana de provenienta pe `VANZARI_DETALII`
|
|
|
|
Nu exista. DDL-ul complet nu e disponibil in acest repo (nu exista `CREATE TABLE VANZARI_DETALII` in
|
|
`docs/`; confirmat deja de cercetari anterioare — `docs/cercetare/discount_verificare2.md:104-111`,
|
|
`docs/cercetare/rec_tva_vanzari.md:19`), dar structura efectiva a fost verificata pe schema live in
|
|
`docs/cercetare/rec_cale_vanzari_detalii.md:157-169` (interogare `all_tab_columns`, 08.08.2026):
|
|
35 de coloane, PK `ID_VANZARE_DET` (generat prin trigger `TRG_VANZARI_DET_BEFOINS` din
|
|
`SEQ_VANZARI_DETALII`), FK logic `ID_VANZARE`. Lista coloanelor relevante citata acolo: `ID_ARTICOL`,
|
|
`PRET`, `CANTITATE`, `PRET_CU_TVA`, `DISCOUNT_UNITAR`, `PROC_TVAV`, `ID_GESTIUNE`, `CONT`,
|
|
`ID_VALUTA`, `ID_JTVA_COLOANA`, `SERIE`, `EXPLICATIE`, `TAXCODE`, `LOT`, `STERS`, `VALIDAT`,
|
|
`DATAORA_VALID`, `ID_UTIL_VALID`, `ID_UTILS`, `DATAORAS`, `DIFERENTA`, `CUSTODIE`, `DESCARCAT`,
|
|
`PRETD`, `ID_VALUTAD`, `PRETV_ORIG`, `ID_CTR`, `ID_RATA`. **Nicio coloana** de tipul
|
|
`ID_VANZARE_SURSA`, `ID_DETALIU_SURSA`, `ID_FACT_SURSA`, `ID_VANZARE_RETUR`, `ID_ORIGINAL` sau orice
|
|
self-referinta catre o alta linie `VANZARI_DETALII`. Cautat explicit acele siruri in tot exportul
|
|
`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (~28000 linii) si in `COMUN\docs\` — zero potriviri
|
|
(vezi comanda de mai jos, sectiunea "Ramas de verificat").
|
|
|
|
Confirmarea independenta finala si cea mai directa: INSERT-ul care trece liniile din
|
|
`VANZARI_DETALII_TEMP` in `VANZARI_DETALII` la finalizarea oricarui document (inclusiv retur, pentru
|
|
ca `scrie_in_vanzari` e comun tuturor tipurilor) are lista de coloane explicita
|
|
(`rec_cale_vanzari_detalii.md:105-113`):
|
|
```sql
|
|
INSERT /*+ APPEND */ INTO VANZARI_DETALII
|
|
(ID_VANZARE, ID_ARTICOL, SERIE, ID_POL, CANTITATE, PRET_ACHIZITIE, PRETD, ID_VALUTAD,
|
|
PRET, PROC_TVAV, DISCOUNT_UNITAR, ID_GESTIUNE, ID_VALUTA, CONT, PRET_CU_TVA, ID_JTVA_COLOANA)
|
|
SELECT pack_facturare.nid_vanzare, ID_ARTICOL, ... FROM VANZARI_DETALII_TEMP WHERE ...
|
|
```
|
|
Nicio coloana sursa in lista. Cum `VANZARI_DETALII_TEMP` insasi e populata pentru retur din
|
|
`cursor_retur_document` (care, cf. punctul 1, nu aduce `ID_VANZARE`/`ID_VANZARE_DET` sursa), legatura
|
|
e pierduta cu doi pasi inainte de a ajunge la acest INSERT — nu doar "nu se scrie", ci "nu mai exista
|
|
in date la momentul scrierii".
|
|
|
|
## 3. Tabel separat de legatura
|
|
|
|
**Da, exista, dar la nivel de document, nu de linie**: `VANZARI_CORESP(ID_VANZARE_FACT,
|
|
ID_VANZARE_AVIZ, TIP, STERS)`. Folosit pentru mai multe perechi de corespondenta, disambiguizate prin
|
|
`TIP`:
|
|
- `TIP=1`: factura scrisa dintr-un aviz (`scrie_corespondente_vanzari(1)`, la facturare din aviz,
|
|
`:14826`);
|
|
- `TIP=2`: aviz de retur (`scrie_corespondente_vanzari(2)`, `:14830`, la `ntip=24`);
|
|
- `TIP=3`: **factura de retur** (`scrie_corespondente_vanzari(3)`, `:14834-14836`, la `ntip in (8,9)`)
|
|
— exact cazul cerut de S4f.
|
|
|
|
Verificarile de stergere din `sterge_factura` (`:5450-5494`) confirma semantica: interogheaza
|
|
`VANZARI_CORESP WHERE ID_VANZARE_AVIZ = V_ID_VANZARE AND TIP = 3` pentru "exista facturi de retur pe
|
|
aceasta factura?" — deci pentru o factura normala, `ID_VANZARE_AVIZ` (nume generic, refolosit) e ea
|
|
insasi, iar `ID_VANZARE_FACT` gasit prin acea interogare e factura(le) de retur emise pe baza ei.
|
|
Invers, pentru un document de retur dat, `SELECT ID_VANZARE_AVIZ FROM VANZARI_CORESP WHERE
|
|
ID_VANZARE_FACT = :id_retur AND TIP = 3` da **toate** facturile sursa alese la emiterea acelui retur
|
|
(poate fi mai multe, cf. selectie multipla din `caut_facturi_multiple_client`,
|
|
`docs/cercetare/factura_retur_document.md:67-85`).
|
|
|
|
**Limita exacta**: cand pe un document de retur exista o singura factura sursa in `VANZARI_CORESP`,
|
|
"factura originala" e determinata fara ambiguitate pentru **toate** liniile documentului de retur
|
|
(pentru ca nu exista alt candidat). Cand exista mai multe (utilizatorul a bifat 2+ facturi la
|
|
cautare), `VANZARI_CORESP` da multimea, dar nu se poate spune care linie de retur vine din care
|
|
factura din multime — informatia care ar face diferenta (ID_VANZARE per linie in cursorul de
|
|
populare) a fost deja aruncata la pasul 1/2. Nu exista niciun tabel `VANZARI_RETUR`, `RETUR_DETALII`
|
|
sau `LEGATURI_DOCUMENTE`; cautate explicit in `ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` si in
|
|
`COMUN\docs\` — zero potriviri.
|
|
|
|
`DOCUMENTE.AVIZE` (coloana denormalizata pe `VANZARI`, nu tabel separat) e completata redundant tot
|
|
din `VANZARI_CORESP` (`scrie_corespondente_vanzari:15505-15514`, `UPDATE VANZARI SET AVIZE = ...`) —
|
|
tine text afisabil (serie+numar avize), nu un id structurat, si nu e populata pentru `TIP=3` (doar
|
|
pentru avize, vezi apelul unic la acel `UPDATE` in corpul procedurii, comun tuturor `V_TIP`-urilor
|
|
dar cu sens practic doar pentru avize-spre-factura).
|
|
|
|
## 4. Cum calculeaza serverul maximul returnabil
|
|
|
|
**Raspunsul e diferit pe cele doua mecanisme, si niciunul nu se sprijina pe o legatura persistata
|
|
linie-la-linie:**
|
|
|
|
**N.1 (document)**: NU exista un calcul de "cat s-a mai returnat deja". Coloana pe care utilizatorul
|
|
o vede ca "Cant. max. de returnat" (`ofacturare.vc2:15238,15243` — doar schimbare de caption pe capul
|
|
de coloana, nu logica noua) e pur si simplu `CANTITATE` a liniei originale, asa cum vine din
|
|
`cursor_retur_document` (`A1.CANTITATE`, `:4036`, filtrat doar pe `A1.STERS = 0`, fara nicio
|
|
agregare cu alte retururi anterioare pe aceeasi linie). Validarea din
|
|
`do_verifica_articol` (`:14743-14754`) nu face niciun calcul suplimentar de disponibil — blocheaza
|
|
doar cazul `tnCantitate >= 0` cand esti in mod retur (semnul gresit), nu o depasire de maxim istoric.
|
|
**Consecinta directa**: daca acelasi utilizator emite doua facturi de retur separate pe aceeasi
|
|
factura sursa, a doua interogare `cursor_retur_document` va aduce din nou linia originala cu
|
|
`CANTITATE` **intreaga**, neredusa de primul retur — nimic in cod nu scade sau marcheaza cat s-a
|
|
returnat deja la acest nivel. Acesta e cel mai clar indiciu ca legatura linie-la-linie *nu* e tinuta
|
|
nicaieri pentru N.1: daca ar fi fost tinuta, ar fi trebuit folosita exact aici, ca sa capeze
|
|
cantitatea, si nu e.
|
|
|
|
**N.2 (`But_retur`)**: exista un calcul real de disponibil, dar e un calcul de **stoc/rulaj**, nu de
|
|
"cat s-a returnat pe acea linie". Ramura din `pack_facturare` citata la punctul 1
|
|
(`ff_...sql:8142-8212`) calculeaza cantitatea inca prezenta in `RUL` (miscari de stoc) care a venit
|
|
din vanzarea aleasa (`RUL.COD` legat prin `VANZARI.COD`, filtrat pe `id_articol:id_vanzare` din
|
|
`listaid`), plus `STOC`/`RUL_TEMP` pentru cazul general. E un calcul valid de "poti scoate din
|
|
gestiune atat cat inca exista acolo cu provenienta asta", sprijinit pe legatura persistata
|
|
`RUL.COD -> VANZARI.COD` (asta e adevarata "legatura care exista" pentru N.2) — dar e o legatura la
|
|
nivelul miscarii de stoc, nu un contor "cantitate returnata" pe `VANZARI_DETALII`, si nu se
|
|
translateaza in nicio coloana de provenienta pe linia noua scrisa.
|
|
|
|
## 5. Ce se poate afisa efectiv
|
|
|
|
- **Numarul/seria facturii originale la nivel de document de retur, cand exista o singura factura
|
|
sursa**: SE POATE, din `VANZARI_CORESP` (`TIP=3`) join `VANZARI` pe `ID_VANZARE_AVIZ`. Interogare
|
|
de rulat pe baza vie (nu verificata aici, doar formulata):
|
|
```sql
|
|
SELECT v.serie_act, v.numar_act
|
|
FROM VANZARI_CORESP c JOIN VANZARI v ON v.ID_VANZARE = c.ID_VANZARE_AVIZ
|
|
WHERE c.ID_VANZARE_FACT = :id_document_retur AND c.TIP = 3 AND c.STERS = 0;
|
|
```
|
|
Daca randul e unic, se poate afisa "provine din factura X" **pe capul documentului de retur**
|
|
(nu pe linie — toate liniile ar arata aceeasi sursa, pentru ca e singura posibila).
|
|
- **Cand documentul de retur are 2+ facturi sursa** (selectie multipla permisa de dialog): se poate
|
|
afisa lista de facturi sursa posibile (tot din `VANZARI_CORESP`), dar NU care linie vine din care
|
|
factura din lista — informatia nu exista.
|
|
- **Numarul facturii originale pe fiecare linie individuala de retur**: NU SE POATE, in niciun caz —
|
|
nici cand exista un singur document sursa (pentru ca "linie cu linie" nu inseamna nimic diferit de
|
|
"documentul cu documentul" atunci, dar afirmatia stricta "aceasta linie de retur vine din linia Y a
|
|
facturii" nu poate fi demonstrata din date, doar presupusa cand exista un singur candidat), si sigur
|
|
nu cand exista mai multe facturi sursa sau cand linia e libera (permisa explicit de decizia 22).
|
|
- Pentru N.2 (retur in factura normala, tip 1/5/7/10): nu exista deloc "document de retur" separat de
|
|
arata provenienta — linia de retur e o linie normala (cu cantitate negativa) in factura curenta;
|
|
singura urma a sursei e `RUL.COD`/`VANZARI.COD` folosita tranzitoriu la calculul de disponibil, nu
|
|
persistata pe linia noua din `VANZARI_DETALII`.
|
|
|
|
## Verdict pentru plan (S4f)
|
|
|
|
**NU se persista legatura linie-la-linie.** Pentru documentul de retur (N.1), se poate afisa
|
|
"factura sursa" **la nivel de document**, din `VANZARI_CORESP` (TIP=3), **doar cand exista exact o
|
|
singura factura sursa aleasa** — cazul cu selectie multipla da doar multimea, fara atribuire per
|
|
linie. Pe linia individuala de retur nu se poate afisa nimic verificabil din date, in niciun caz.
|
|
Recomandare pentru S4f: se livreaza fara coloana de provenienta pe linie (cf. deciziei deja scrise in
|
|
plan, "nu se inventeaza"); daca se vrea un gest minim, singura afisare sustenabila cu date e un text
|
|
de tip "Retur pentru factura: X" pe **capul** documentului (deja exista, cf.
|
|
`factura_retur_document.md:85`: `poDate.text_aditional = ... + poDate.descriere`, unde
|
|
`poDate.descriere` e lista serie+numar a facturilor alese) — nu pe linie, si nu nou, e deja acolo.
|
|
|
|
## Ramas de verificat pe baza vie
|
|
|
|
- Nu s-a interogat live daca `VANZARI_CORESP.TIP=3` e scris consecvent pentru fiecare factura de
|
|
retur emisa istoric (posibil sa existe date vechi scrise inainte ca aceasta ramura sa existe, sau
|
|
prin alt cod neexaminat aici) — de rulat:
|
|
```sql
|
|
SELECT COUNT(*) FROM VANZARI v
|
|
WHERE v.TIP IN (8,9) AND v.STERS = 0
|
|
AND NOT EXISTS (SELECT 1 FROM VANZARI_CORESP c WHERE c.ID_VANZARE_FACT = v.ID_VANZARE AND c.TIP = 3);
|
|
```
|
|
Daca da >0, exista facturi de retur fara nicio legatura de document persistata, nici macar cea
|
|
partiala descrisa mai sus.
|
|
- Nu s-a verificat live cate din facturile de retur existente au >1 factura sursa in
|
|
`VANZARI_CORESP` (adica cate din documentele reale ar cadea in cazul "multime, nu atribuire") —
|
|
utila pentru a decide cat de des s-ar aplica de fapt afisarea propusa la punctul 5.
|
|
- Nu s-a gasit (si nici nu era in scop) un mecanism separat pentru avize de retur custodie (`tip=50`,
|
|
marcat "in lucru" in `tipuri_documente_facturare.md`) — daca S4f ajunge sa acopere si acel tip, de
|
|
recercetat separat.
|
|
- Subagentul de research auxiliar lansat pentru confirmarea independenta a definitiei
|
|
`caut_facturi_multiple_client`/`caut_facturi_multiple_client_articol` nu a returnat un raport
|
|
utilizabil (rezultat gol la finalizare); definitiile au fost gasite si citite direct in aceasta
|
|
sesiune, in `COMUN\programe\oproceduri_facturare.prg:2091-2160`, deci nu blocheaza verdictul, dar
|
|
nu a adaugat nimic peste ce e deja in acest raport.
|