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
375 lines
27 KiB
Markdown
375 lines
27 KiB
Markdown
# S5C — Factura din proforma (proiectare)
|
|
|
|
Status: INCHEIAT
|
|
|
|
## Sarcina
|
|
Cerinta noua (decizia 43, runda 12): dintr-o proforma emisa sa se poata genera o
|
|
FACTURA ca document NOU (nu prin comutarea tipului pe acelasi document — comutarea
|
|
PROFORMA -> FACTURA cu linii e deja blocata cu mesaj). Mecanismul pare sa existe deja
|
|
pe calea de copiere (`do_copiaza`).
|
|
|
|
## (a) Poate fi azi o proforma aleasa ca sursa de copiere?
|
|
|
|
**Da, fara nicio excludere.** Trei dovezi convergente:
|
|
|
|
1. `COMUN\clase\ofacturare_comun.vc2:4964-4974` — `frm_facturi.IsCopy(tnTip)`:
|
|
```
|
|
RETURN .T. && POT SA COPIEZ ORICE, TRATEZ TIPURILE IN DO_COPIAZA
|
|
*!* RETURN INLIST(m.lnTip, 1,5,7,10,22,23,43) && pot sa copii doar avize si facturi pret de lista, ...
|
|
```
|
|
Varianta veche (restrictiva, comentata) verifica doar `tip` (1-52) — niciodata `eproforma`. Varianta
|
|
activa returneaza necondiționat `.T.`. Nu exista, si n-a existat vreodata in acest cod, o excludere
|
|
pe `eproforma`.
|
|
2. `COMUN\clase\ofacturare_comun.vc2:5110` — vizibilitatea butonului de copiere pe randul selectat:
|
|
`Thisform.but_copiaza1.Visible = Thisform.IsCopy(crsFacturi.tip)` — acelasi apel, acelasi rezultat
|
|
necondiționat.
|
|
3. `COMUN\clase\ofacturare_comun.vc2:5082-5083` — gridul de facturi are un filtru dedicat pe
|
|
`eproforma`, cu proforma tratata ca subset normal, nu ascuns:
|
|
```
|
|
"Facturi&Avize\nofiled\E\(eproforma = 0)\" + crlf + ;
|
|
"Proforme\nofiled\E\(eproforma=1)\" + crlf + ;
|
|
```
|
|
Chiar filtrul "Proforme" arata explicit ca proformele sunt navigabile si selectabile normal in
|
|
acelasi grid — butonul de copiere ramane vizibil identic pe orice rand selectat din acest filtru.
|
|
|
|
**Concluzie**: azi orice utilizator poate selecta o proforma in grid si apasa "Copiere (CTRL+K)"
|
|
(tooltip-ul insusi anunta explicit acest caz de folosire — vezi citatul din
|
|
`s5b_proiectare_proforma_copiere.md` §"1.4"/`proforma_copiere_puncte_intrare.md:41-47`). Nu exista
|
|
nicio garda de blocat, la niciun nivel (`IsCopy`, vizibilitate buton, filtru grid).
|
|
|
|
## (b) Ce tip rezulta din copierea unei proforme?
|
|
|
|
**Rezultatul e intotdeauna `nIdTipDoc=5` (FACTURA)** — corect pentru o factura fiscala — dar tipul de
|
|
business (`VANZARI.TIP`, 1-52) degradeaza dupa tabelul deja existent din `do_copiaza`, **nemodificat
|
|
pentru cazul proforma**: nu exista nicio ramura speciala pe `eproforma` in `do_copiaza`
|
|
(`COMUN\clase\ofacturare_comun.vc2:3628-3713`) — degradarea se face **strict dupa `loFactura.tip`**,
|
|
indiferent daca documentul sursa era proforma sau nu.
|
|
|
|
**Pasul 1 — degradarea de tip business** (`:3693-3708`, tabel deja confirmat in
|
|
`s5b_proiectare_proforma_copiere.md` §2.1):
|
|
- Proforma poate exista doar pe tipuri "de factura" (combo-ul `Ct_clb_fdoc` traieste in
|
|
`frm_date_factura`, nu si in `frm_date_aviz` — cf. `proforma_copiere_puncte_intrare.md` §1). Setul
|
|
posibil de `loFactura.tip` pentru o proforma e deci printre `{1,2,3,4,5,6,7,8,9,10,43,44,45,47,48,49,51}`
|
|
(grupul "Facturi" din `COMUN\docs\tipuri_documente_facturare.md`).
|
|
- Din acest set: `{1,5,7,10}` raman neschimbate (`CASE INLIST(loFactura.tip,T1,T5,T7,T10,T22,T23)`,
|
|
`:3694`); `{2,3,4,8,43,44,45,47,48,49,51}` degradeaza la `T1` (`:3696-3697`); `{6}` la `T10`
|
|
(`:3698-3699`); `{9}` la `T5` (`:3700-3701`).
|
|
- Deci, pentru orice proforma emisa astazi (indiferent de tipul de business original), documentul
|
|
copiat va avea `TIP` in `{1,5,7,10}` — nucleul "lista de preturi" (lei/valuta) sau credit note.
|
|
|
|
**Pasul 2 — `nIdTipDoc` NU se propaga** (confirmat deja in
|
|
`s5b_proiectare_proforma_copiere.md` §2.3, `COMUN\programe\ofacturare_comun.prg:370`:
|
|
`*.nIdTipDoc = toDateAnterior.nIdTipDoc` — comentata). Documentul nou primeste `nIdTipDoc` implicit
|
|
dupa tipul degradat: `Do Case` la `COMUN\programe\ofacturare.prg:187-196`, toate valorile din
|
|
`{1,5,7,10}` cad sub `5` (FACTURA) → `poDate.eProforma = 0` pe documentul nou, **indiferent ca sursa
|
|
era proforma**.
|
|
|
|
**Concluzie pentru (b)**: mecanismul de copiere transforma azi orice proforma intr-o **FACTURA reala
|
|
(`nIdTipDoc=5`, `eproforma=0`)**, de tip business `1` (lista de preturi, cel mai frecvent caz — orice
|
|
tip din `{2,3,4,8,43,44,45,47,48,49,51}` cade tot pe `T1`), `5`/`10` (daca sursa era deja pe lista de
|
|
preturi in valuta/factura valuta), sau `7` (credit note, ramas neschimbat). Tipul rezultat **e cel bun
|
|
pentru o factura fiscala** din perspectiva `nIdTipDoc`/`eproforma` (nu ramane proforma), dar tipul de
|
|
business e intotdeauna **degradat catre "lista de preturi"** — proforma emisa dintr-o comanda (`tip=3`)
|
|
sau dintr-un aviz (`tip=4`) devine, dupa copiere, o factura "banala" `tip=1`, **la fel ca la orice alta
|
|
copiere non-proforma** (comportament deja documentat si acceptat in S5b §7 punctul 5: "degradarea de
|
|
tip din `do_copiaza` ramane pentru copiere si nu se aplica la regenerare" — nicio schimbare ceruta aici
|
|
fata de acel raport).
|
|
|
|
## (c) Legatura proforma -> factura (VANZARI_CORESP.TIP)
|
|
|
|
### Structura tabelei (confirmata pe schema vie, `MARIUSM_AUTO`)
|
|
```
|
|
ID_VANZARE_CORESP NUMBER NOT NULL (PK, populat de trigger BEFORE INSERT din SEQ_VANZARI_CORESP)
|
|
ID_VANZARE_FACT NUMBER NOT NULL
|
|
ID_VANZARE_AVIZ NUMBER NOT NULL (nume generic mostenit — nu neaparat un aviz, vezi mai jos)
|
|
STERS NUMBER NULL
|
|
TIP NUMBER NOT NULL
|
|
```
|
|
Singurul trigger gasit pe tabela (`TRG_VANZARI_CORESP_BEFOINS`, prezent identic in schemele `ACN` si
|
|
`MARIUSM_AUTO`) doar genereaza PK-ul din secventa — nu atinge/valideaza `TIP`.
|
|
|
|
### Cine scrie in tabela — un singur punct, in tot codul Oracle
|
|
`grep` pe `all_source` (schema vie) dupa `VANZARI_CORESP` gaseste **un singur writer**:
|
|
`pack_facturare.scrie_corespondente_vanzari` (`PACK_FACTURARE:15481-15516`, singurul `INSERT INTO
|
|
VANZARI_CORESP` din toata baza). Nu exista alt pachet, trigger sau produs ROA (ROAGEST, ROAIMOB,
|
|
ROACONTRACTE, ROAACNPRO etc.) care sa scrie in aceasta tabela — `PACK_FACTURARE` traieste in `COMUN`,
|
|
partajat de toata suita, deci **orice** consumator ar trece prin acelasi punct.
|
|
|
|
### Valorile de `TIP` deja folosite — confirmate cod + date
|
|
**Cod** (singurele 3 apeluri la `scrie_corespondente_vanzari` din tot `PACK_FACTURARE`,
|
|
`:14818-14839`, in `finalizeaza_factura`):
|
|
- `TIP=1`: `WHEN pack_facturare.ntip = 4 THEN ... scrie_corespondente_vanzari(1)` — factura scrisa
|
|
dintr-un aviz (`ntip=4` = "FACT. DIN AVIZ"). Foloseste `pack_facturare.clistaid_avize` (lista
|
|
separata, populata pentru facturare-din-aviz cu selectie multipla).
|
|
- `TIP=2`: `WHEN pack_facturare.ntip = 24 THEN ... scrie_corespondente_vanzari(2)` — aviz de retur
|
|
(`ntip=24`).
|
|
- `TIP=3`: `WHEN pack_facturare.ntip IN (8, 9) THEN ... scrie_corespondente_vanzari(3)` — factura de
|
|
retur.
|
|
Toate trei folosesc `pack_facturare.nid_vanzare` (documentul curent, tocmai scris) ca
|
|
`ID_VANZARE_FACT`; pentru `TIP=1` sursa vine din `clistaid_avize`, pentru `TIP=2`/`TIP=3` (ramura
|
|
`ELSE` din `scrie_corespondente_vanzari`, `:15490-15491`) din `pack_facturare.clistaid` generic.
|
|
|
|
**Date** (schema `MARIUSM_AUTO`, interogare directa `SELECT tip, COUNT(*) FROM vanzari_coresp GROUP BY
|
|
tip`): `TIP=1` → 6 randuri, `TIP=2` → 1, `TIP=3` → 1. **Zero randuri cu alt `TIP`.** Coerent cu codul
|
|
(nu exista alt loc care sa scrie alte valori) — dovada dubla (cod + date), nu doar una din ele (per
|
|
memoria de proiect "zero cazuri in date nu e dovada": aici avem *si* absenta din date, *si* absenta
|
|
structurala in cod, ceea ce e o dovada tare, nu doar un data point izolat).
|
|
|
|
### Valoare noua libera
|
|
**`TIP=4` e liber**, confirmat pe ambele fronturi (cod: niciun apel existent la
|
|
`scrie_corespondente_vanzari(4)`; date: zero randuri `TIP=4` in schema testata). Recomandare: **`TIP=4`
|
|
= "factura scrisa dintr-o proforma"**, urmatorul numar disponibil in secventa deja folosita (1,2,3),
|
|
fara conflict cu niciun consumator existent (nu exista alt produs ROA care sa scrie sau sa citeasca
|
|
`VANZARI_CORESP` in afara de `PACK_FACTURARE`). Structura tabelei **nu se schimba** — doar o noua
|
|
valoare de enum in coloana `TIP`, exact cum a cerut misiunea.
|
|
|
|
### Unde s-ar scrie corespondenta — punct de intrare, cu rezerva importanta
|
|
Tiparul de azi (`TIP=1/2/3`) scrie corespondenta **din interiorul** `finalizeaza_factura`, intr-un
|
|
`CASE` cheie **`pack_facturare.ntip`** — semnalul de business-type al documentului nou scris. Aceasta
|
|
cheie **nu poate distinge** "factura rezultata dintr-o copiere de proforma" de "orice alta factura
|
|
obisnuita cu acelasi tip degradat" (vezi (b): rezultatul copierii unei proforme cade intotdeauna in
|
|
`{1,5,7,10}`, niciodata `4`/`24`/`8`/`9` — deci nu exista azi nicio ramura `WHEN` pe care s-o extinda,
|
|
si niciuna nu s-ar putea scrie corect doar din `ntip`, pentru ca acelasi `ntip=1` rezulta si dintr-o
|
|
copiere obisnuita de factura, nelegata de nicio proforma). Vezi Capcana (i) pentru raspunsul complet la
|
|
"de unde stie Oracle ca sursa a fost o proforma" si propunerea de proiectare pentru rezolvare.
|
|
|
|
## Capcana (i): supravietuieste id_fact/id_vanzare al sursei pana la scrierea corespondentei?
|
|
|
|
**Da, `id_vanzare` al proformei supravietuieste — dovedit pas cu pas — dar faptul ca sursa "era o
|
|
proforma" (nu doar "era un document oarecare") NU supravietuieste nicaieri azi. Asta e golul real.**
|
|
|
|
**Partea care functioneaza deja, neschimbata:**
|
|
1. `do_copiaza` (`COMUN\clase\ofacturare_comun.vc2:3690-3691`): `SELECT crsFacturi / SCATTER NAME
|
|
loFactura MEMO` — `loFactura` e o copie completa a randului sursa din grid, **inclusiv
|
|
`loFactura.id_vanzare`** (campul cheie) si `loFactura.eproforma` (coloana de grid confirmata la
|
|
`ofacturare_comun.vc2:2494`, `Column37.ControlSource = "eproforma"`) — **ambele disponibile in
|
|
acest moment**, inainte ca degradarea de tip (`:3693-3708`) sa ruleze.
|
|
2. `copiere_factura` (`COMUN\programe\oproceduri_facturare.prg:150-153`) → `factureaza(loFactura.tip,
|
|
loFactura)` — `loFactura` intreg (cu `id_vanzare` si `eproforma` inca pe el) devine `toFactura`,
|
|
parametrul opțional.
|
|
3. `completeaza_setari_document(toDateAnterior, .T.)`
|
|
(`COMUN\programe\ofacturare_comun.prg:362-412`), ramura de copiere: **`.listaid =
|
|
toDateAnterior.id_vanzare`** (`:387`) — **aici** `id_vanzare` al proformei ajunge in `poDate`,
|
|
proprietate care **nu e atinsa de degradarea de tip** (aceea opereaza doar pe `loFactura.tip`,
|
|
variabila locala din `do_copiaza`, complet separata de `poDate`).
|
|
4. `poDate.listaid` calatoreste neschimbat prin toata sesiunea (folosit si la §2.5 din
|
|
`s5b_proiectare_proforma_copiere.md` pentru `cursor_retur_document`), pana la scriere:
|
|
`do_scrie_articole` (`COMUN\clase\ofacturare.vc2:6104`): `Alltrim(Nvl(poDate.listaid,''))` e trimis
|
|
ca parametru `V_LISTAID` catre `pack_facturare.initializeaza_date_factura`, care il pune in
|
|
`pack_facturare.clistaid := V_LISTAID` (`PACK_FACTURARE:1883`) — **inainte** ca `do_scrie_factura`
|
|
sa aleaga `scrie_factura2`/`finalizeaza_factura`. La momentul in care `scrie_corespondente_vanzari`
|
|
ar rula, `pack_facturare.clistaid` **este deja** `id_vanzare`-ul proformei (ca text), exact valoarea
|
|
pe care ramura `ELSE` a lui `scrie_corespondente_vanzari` (`:15490-15491`, folosita azi de `TIP=2` si
|
|
`TIP=3`) o citeste.
|
|
|
|
**Partea care NU exista azi — golul real:** `completeaza_setari_document` (pasul 3 de mai sus) copiaza
|
|
explicit `id_lucrare`, `nrord`, `id_sectie`, `sectie`, `id_agent`, `nume_agent`, `id_delegat`,
|
|
`nume_delegat`, `BIdelegat`, `CNPdelegat`, `nrinmat`, `id_masina`, `listaid`, `descriere`, `id_client`,
|
|
`nume_client` de pe `toDateAnterior` — **dar niciodata `.eproforma`**. Documentul nou stie "din ce
|
|
`id_vanzare` a fost copiat" (`.listaid`), dar **nu stie daca acel document sursa era o proforma sau o
|
|
factura obisnuita** — informatia se pierde exact la acest pas, inainte sa ajunga la Oracle.
|
|
|
|
**De ce conteaza**: `finalizeaza_factura` (Oracle) decide azi ce `TIP` de corespondenta sa scrie
|
|
uitandu-se **doar** la `pack_facturare.ntip` (business-type-ul documentului nou). Cum am stabilit la
|
|
(b), rezultatul unei copieri de proforma cade intotdeauna in `{1,5,7,10}` — **acelasi interval** in
|
|
care cade si o copiere obisnuita (proforma sau nu). Oracle **nu poate reconstitui** din `ntip` singur
|
|
daca documentul curent a fost copiat dintr-o proforma sau dintr-o factura normala — nu exista niciun
|
|
semnal in `pack_facturare` care sa poarte aceasta distinctie.
|
|
|
|
**Ce trebuie adaugat, minimal** (propunere, nu implementare):
|
|
1. **VFP**: la `completeaza_setari_document:387`, langa `.listaid = toDateAnterior.id_vanzare`, adauga
|
|
o proprietate noua, de exemplu `.lProformaSursa = (toDateAnterior.eproforma = 1)` — un simplu boolean
|
|
client-side, capturat in acelasi moment si din acelasi obiect sursa unde `listaid` e deja capturat
|
|
(zero risc suplimentar de "se pierde intre timp", pentru ca foloseste exact acelasi tipar dovedit la
|
|
pasul 3-4 de mai sus).
|
|
2. **Scrierea corespondentei, NU prin `finalizeaza_factura`/`ntip`**: pentru ca `ntip` nu poate purta
|
|
distinctia (vezi mai sus), cea mai sigura ruta e un apel Oracle **explicit, separat**, facut din VFP
|
|
imediat dupa ce `do_scrie_factura` confirma succesul scrierii documentului nou, gardat de
|
|
`poDate.lProformaSursa`:
|
|
```
|
|
IF poDate.lCopiere AND poDate.lProformaSursa
|
|
lcSql = [{call pack_facturare.scrie_corespondente_vanzari(4)}]
|
|
* ... goExecutor.oExecute(lcSql) ...
|
|
ENDIF
|
|
```
|
|
Aceasta reutilizeaza **exact** procedura Oracle existenta, neschimbata (ramura `ELSE`,
|
|
`pack_facturare.clistaid`/`pack_facturare.nid_vanzare` inca valide in sesiune la acel moment, per
|
|
pasul 4 de mai sus) — **zero cod PL/SQL nou**, doar un nou punct de apel VFP si o noua valoare de
|
|
`TIP`. Alternativa (adaugarea unei ramuri noi in `CASE`-ul din `finalizeaza_factura`, cheie pe un
|
|
parametru nou trimis prin `V_PARAMETRU_ADITIONAL` sau similar) ar fi mai fragila: acel `CASE` e
|
|
punctul comun al **oricarei** facturi/aviz/retur scrise in tot codul, folosit de toate produsele ROA
|
|
prin `PACK_FACTURARE` partajat — o ramura noua acolo, keyed pe o combinatie de `ntip` + un flag nou,
|
|
ar creste suprafata unui switch deja incarcat, pentru un caz care oricum nu poate fi exprimat corect
|
|
doar din `ntip`. Apelul explicit izolat e mai simplu si nu atinge deloc `finalizeaza_factura`.
|
|
3. **Ordinea conteaza**: apelul explicit trebuie sa ruleze **inainte** ca orice alt cod Oracle din
|
|
aceeasi sesiune sa resetteze `pack_facturare.nid_vanzare`/`clistaid` (de exemplu, o alta scriere de
|
|
document in acelasi batch) — de plasat imediat dupa `do_scrie_factura`, inainte de listare/atasamente
|
|
(care oricum nu ating Oracle pentru partea de scriere). Daca se prefera robustete completa (fara
|
|
dependenta de stare de sesiune Oracle), varianta alternativa e sa se paseze explicit
|
|
`V_ID_VANZARE_FACT` (= `poDate.id_vanzare`, cunoscut client-side dupa scriere) si
|
|
`V_ID_VANZARE_PROFORMA` (= `poDate.listaid`, deja cunoscut) direct ca parametri, printr-o mica
|
|
procedura Oracle noua care ocoleste `clistaid`/`nid_vanzare` cu totul — cost: un nou obiect PL/SQL in
|
|
loc de zero, beneficiu: independenta de ordinea altor apeluri din sesiune. **Alegere ramasa lui
|
|
Marius** (vezi propunerea finala).
|
|
|
|
## Capcana (ii): `marcheaza_facturat` pe proforma — corect sau nu?
|
|
|
|
**Nu trebuie chemat pe proforma. Confirmat cu dovada, pe patru argumente convergente.**
|
|
|
|
**Ce face, exact** (`PACK_FACTURARE:15381-15418`):
|
|
```sql
|
|
PROCEDURE marcheaza_facturat(V_VERIFICARE IN NUMBER) IS
|
|
BEGIN
|
|
IF V_VERIFICARE = 0 THEN
|
|
UPDATE VANZARI SET FACTURAT = 1, ID_UTILFACT = pack_facturare.nid_util
|
|
WHERE ID_VANZARE IN (SELECT id_vanzare_aviz FROM vanzari_coresp
|
|
WHERE id_vanzare_Fact = pack_facturare.nid_vanzare
|
|
AND sters = 0 AND tip <> 3)
|
|
AND FACTURAT = 0;
|
|
ELSE
|
|
-- varianta "verificare cantitate ramasa": marcheaza FACTURAT=1 doar daca toata cantitatea
|
|
-- din VANZARI_DETALII a documentului sursa a fost deja consumata in VANZARI_CANTITATI
|
|
...
|
|
END IF;
|
|
END;
|
|
```
|
|
Flipeaza `VANZARI.FACTURAT=1` (+`ID_UTILFACT`) pe **documentul(ele) sursa** legate prin
|
|
`VANZARI_CORESP` de documentul tocmai scris — fie neconditionat (`V_VERIFICARE=0`), fie doar cand
|
|
cantitatea documentului sursa a fost epuizata (`V_VERIFICARE=1`, mecanismul de **facturare partiala** a
|
|
avizelor, bazat pe `VANZARI_CANTITATI`).
|
|
|
|
**Argumentul 1 — nu exista un `TIP` cu care sa se cupleze corect azi.** `marcheaza_facturat` se cheama
|
|
azi **doar** din `finalizeaza_factura`, in aceleasi doua ramuri `WHEN pack_facturare.ntip = 4` si
|
|
`WHEN pack_facturare.ntip = 24` care scriu si corespondenta (`:14823-14831`) — cuplate mereu impreuna cu
|
|
`scrie_corespondente_vanzari(1)`/`(2)`, niciodata separat. Cum am stabilit la Capcana (i), calea propusa
|
|
pentru `TIP=4` (factura din proforma) e un **apel explicit separat**, in afara acestui `CASE` — deci
|
|
n-ar exista niciun loc "natural" unde `marcheaza_facturat` sa se agate fara sa introduca exact acelasi
|
|
tip de cod nou-scris ca la corespondenta insasi.
|
|
|
|
**Argumentul 2 — mecanismul de "cantitate ramasa" (`V_VERIFICARE=1`) nu are pe ce sa opereze pentru o
|
|
proforma.** Verificarea citeste `VANZARI_CANTITATI` (populat **doar** de
|
|
`scrie_cantitati_vanzari_avize`, apelata **doar** in ramura `ntip=4` a lui `finalizeaza_factura`).
|
|
Proforma nu trece niciodata prin `finalizeaza_factura` (confirmat in
|
|
`s5b_proiectare_proforma_copiere.md`, "Descoperire centrala": `scrie_proforma` cheama doar
|
|
`scrie_in_vanzari`) — deci **nu exista niciodata randuri `VANZARI_CANTITATI` pentru o proforma**.
|
|
Varianta `V_VERIFICARE=1` a lui `marcheaza_facturat` ar gasi mereu "cantitate ramasa = cantitate totala"
|
|
(nimic consumat), fie nu ar marca niciodata `FACTURAT=1` (comportament inutil), fie (daca s-ar folosi
|
|
gresit `V_VERIFICARE=0`) ar marca neconditionat, ca la punctul urmator.
|
|
|
|
**Argumentul 3 — asimetrie la stergere: proforma ar ramane blocata `FACTURAT=1` definitiv.**
|
|
`sterge_factura` (`PACK_FACTURARE:5501-5533`) reface `FACTURAT=0` pe documentele sursa **doar** pentru
|
|
`V_TIP=24` (aviz retur, `:5502-5510`) si `V_TIP=4` (factura din aviz, `:5525-5533`) — tipurile care azi
|
|
chiar cheama `marcheaza_facturat`. Rezultatul copierii unei proforme cade intotdeauna in `{1,5,7,10}`
|
|
(per (b)) — **niciuna din aceste valori nu are ramura in `CASE`-ul de stergere**. Daca s-ar chema
|
|
`marcheaza_facturat` la scrierea facturii din proforma, iar utilizatorul ar sterge ulterior acea
|
|
factura, **proforma sursa ar ramane cu `FACTURAT=1` pentru totdeauna** — o stare orfana, fara niciun
|
|
cod care s-o repare, introdusa exact de acest apel. Corespondenta `VANZARI_CORESP` insasi nu are aceeasi
|
|
problema (nimic n-o citeste ca sa se strice daca ramane "orfana" dupa stergerea facturii — cel mult
|
|
devine o legatura catre un document sters, inofensiv).
|
|
|
|
**Argumentul 4 — nimic nu filtreaza azi proformele dupa `FACTURAT`, deci n-ar exista niciun beneficiu
|
|
de blocat.** Spre deosebire de avize (`cursor_avize`/candidatii de facturat, filtrati implicit prin
|
|
fluxul dedicat "Factura din aviz") si comenzi (`VCOMENZI.FACTURAT=0`, folosit explicit in
|
|
`cauta_date_comanda`/`cauta_date_comanda_gest`, `PACK_FACTURARE:15659,15685`, ca sa nu ofere din nou o
|
|
comanda deja facturata), **nimic in codul citit** filtreaza dupa `FACTURAT` cand se alege o proforma ca
|
|
sursa de copiere — confirmat la (a): `IsCopy`/vizibilitatea butonului/filtrul de grid nu se uita
|
|
niciodata la `facturat`. Marcarea n-ar preveni nicio re-copiere accidentala a aceleiasi proforme (care
|
|
oricum ramane posibila, vezi propunerea finala, punctul de decizie 2).
|
|
|
|
**Concluzie**: `marcheaza_facturat` **nu trebuie chemat** pentru "factura din proforma". Se scrie
|
|
**doar** corespondenta (`VANZARI_CORESP`, `TIP=4`), fara actualizare de `VANZARI.FACTURAT` pe proforma.
|
|
Confirma explicit suspiciunea din misiune ("proforma nu e document de livrare") cu evidenta concreta:
|
|
proforma n-are urma in `VANZARI_CANTITATI` (Argumentul 2), n-are ramura de reversare la stergere
|
|
(Argumentul 3), si n-are niciun consumator care sa citeasca `FACTURAT` pe ea (Argumentul 4).
|
|
|
|
## Propunere de proiectare
|
|
|
|
Mecanismul de baza **ramane copierea existenta** (`do_copiaza`/`copiere_factura`/`factureaza`,
|
|
neschimbata in structura ei) — cerinta "document nou, nu comutare pe acelasi document" e deja
|
|
satisfacuta de calea de azi (confirmat la (a)/(b)). Ce lipseste e strict **legatura persistata**
|
|
proforma → factura si excluderea explicita a lui `marcheaza_facturat`. Pasi, in ordine:
|
|
|
|
1. **Captureaza `eproforma` al sursei la copiere.** In `completeaza_setari_document`
|
|
(`COMUN\programe\ofacturare_comun.prg:387`, ramura `tlFactura=.T.`), langa
|
|
`.listaid = toDateAnterior.id_vanzare`, adauga o proprietate noua pe `poDate`
|
|
(ex. `.lProformaSursa`), citind `toDateAnterior.eproforma` — singurul loc unde informatia mai e
|
|
disponibila, inainte sa se piarda (Capcana (i)). *Gata cand:* dupa copierea unei proforme,
|
|
`poDate.lProformaSursa = .T.`; dupa copierea oricarui alt document, `.F.`.
|
|
2. **Rezerva `TIP=4`** in `VANZARI_CORESP` pentru "factura scrisa dintr-o proforma" — doar o conventie
|
|
documentata (ca la 1/2/3), zero schimbare de schema (confirmat la (c): tabela ramane
|
|
`ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP, STERS`).
|
|
3. **Scrie corespondenta cu un apel Oracle explicit, separat de `finalizeaza_factura`.** Imediat dupa
|
|
ce `do_scrie_factura` confirma succesul (acelasi punct unde azi se decid listarea/atasamentele),
|
|
daca `poDate.lCopiere AND poDate.lProformaSursa`: `{call
|
|
pack_facturare.scrie_corespondente_vanzari(4)}` — **reutilizeaza procedura Oracle existenta,
|
|
neschimbata** (ramura `ELSE`, deja scrisa pentru `TIP=2`/`3`). Zero cod PL/SQL nou pentru scriere.
|
|
*Alternativa mai robusta, cu cost:* o mica procedura Oracle noua care primeste explicit
|
|
`V_ID_VANZARE_FACT`/`V_ID_VANZARE_PROFORMA` ca parametri (nu se bazeaza pe
|
|
`pack_facturare.clistaid`/`nid_vanzare` inca valide in sesiune) — de ales intre simplitate (varianta
|
|
de mai sus) si robustete fata de ordinea apelurilor (varianta cu parametri expliciti); vezi punctul
|
|
de decizie 1 mai jos.
|
|
4. **NU cheama `marcheaza_facturat`.** Confirmat cu 4 argumente independente la Capcana (ii) — proforma
|
|
nu are `VANZARI_CANTITATI`, nu are ramura de reversare la stergere, nimic n-o filtreaza dupa
|
|
`FACTURAT`, si oricum n-ar exista un `WHEN pack_facturare.ntip=...` natural de unde s-o cheme (calea
|
|
aleasa la pasul 3 e explicit separata de `finalizeaza_factura`).
|
|
5. **Afisare optionala "provine din proforma X"** pe factura noua — se poate construi din
|
|
`VANZARI_CORESP` (`TIP=4`) la fel ca tiparul deja folosit pentru retur (`legatura_linie_retur.md`
|
|
§5): la nivel de **document**, nu de linie (nicio schimbare fata de tiparul deja acceptat pentru
|
|
retur — nu exista niciun tabel de legatura la nivel de linie in tot codul citit, per acelasi raport).
|
|
Nu e cerut explicit de misiune, dar e disponibil "gratis" din legatura scrisa la pasul 3.
|
|
|
|
**Ce NU se schimba** (confirmat, fara nevoie de atingere):
|
|
- `IsCopy`, vizibilitatea `But_copiaza1`, filtrul de grid "Facturi&Avize / Proforme" — proforma ramane
|
|
selectabila ca sursa exact ca azi (a).
|
|
- Degradarea de tip din `do_copiaza` (`{1,5,7,10}` pentru orice proforma) si alocarea de numar nou —
|
|
raman neschimbate, deja produc `nIdTipDoc=5`/`eproforma=0` corect pentru documentul nou (b).
|
|
- `cursor_retur_document`, restaurarea `GESTIONABIL=B.IN_STOC` la copiere — neschimbat, mecanism deja
|
|
corect pentru orice copiere (mostenit din `s5b_proiectare_proforma_copiere.md` §7).
|
|
- `scrie_corespondente_vanzari` insasi — zero cod PL/SQL nou (varianta recomandata la pasul 3).
|
|
|
|
### Riscuri si ce ramane de decis de Marius
|
|
|
|
1. **Apel explicit pe stare de sesiune (`clistaid`/`nid_vanzare`) vs. procedura noua cu parametri
|
|
expliciti** (pasul 3) — simplitate (zero cod Oracle nou, dar depinde ca nimic altceva sa nu resetteze
|
|
starea pachetului intre scrierea facturii si apelul de corespondenta) vs. robustete (un obiect
|
|
PL/SQL nou, insensibil la ordine). Recomandare: varianta simpla, **daca** apelul se plaseaza imediat
|
|
dupa `do_scrie_factura`, inainte de orice alt apel Oracle din acelasi flux (listare/atasamente nu
|
|
ating Oracle pentru scriere) — de verificat pe cod exact la implementare ca nu exista un apel Oracle
|
|
intercalat care ar reseta `pack_facturare.nid_vanzare`.
|
|
2. **Poate fi copiata de mai multe ori aceeasi proforma?** Azi nu exista nicio garda (FACTURAT nu se
|
|
marcheaza — decizia de la Capcana (ii)), deci un utilizator poate genera N facturi din aceeasi
|
|
proforma, fiecare cu propriul rand `TIP=4` in `VANZARI_CORESP` catre aceeasi proforma sursa. E
|
|
comportamentul implicit al oricarei copieri azi (nimic n-o limiteaza nici pentru facturi/avize
|
|
normale) — de confirmat daca e acceptabil sau daca se doreste un avertisment (nu o blocare, pentru
|
|
ca ar contrazice tiparul existent de copiere liber-repetabila).
|
|
3. **Guard simetric la stergere?** `sterge_factura` blocheaza azi stergerea unui aviz/unei facturi care
|
|
are deja o factura de retur legata (`TIP=3`) sau facturi/avize-retur legate (`TIP IN (1,2)`,
|
|
`PACK_FACTURARE:5450-5476`). Nu exista cerinta explicita in misiune pentru un guard simetric pe
|
|
`TIP=4` (ex. "nu poti sterge o proforma care are deja o factura generata din ea") — de decis daca se
|
|
doreste, sau daca proforma ramane liber stersa oricand (comportament actual, neschimbat daca nu se
|
|
adauga nimic).
|
|
4. **Afisarea "provine din proforma X"** (pasul 5) — optionala, nu ceruta explicit; de decis daca
|
|
merita implementata acum sau ramane pentru o poveste ulterioara (costul e mic, data fiind legatura
|
|
deja scrisa la pasul 3).
|
|
5. **`TIP=4` ca valoare aleasa** — libera si fara conflict azi (confirmat cod+date), dar e o alocare
|
|
ireversibila din punct de vedere al datelor odata folosita in productie; de confirmat explicit de
|
|
Marius inainte de implementare (nu doar acceptata tacit).
|
|
|
|
## STARE / CE RAMANE
|
|
|
|
**Cercetare + proiectare incheiate.** Toate cele trei intrebari (a/b/c) si ambele capcane (i/ii) au
|
|
raspuns cu dovada `fisier:linie`, verificat pe fisierele text reale (`ofacturare_comun.vc2`,
|
|
`ofacturare.vc2`, `ofacturare_comun.prg`, `ofacturare.prg` — nu `.bak`) si pe `PACK_FACTURARE`
|
|
(`ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql`), plus verificare directa pe schema Oracle vie
|
|
(`MARIUSM_AUTO`: structura `VANZARI_CORESP`, distributia `TIP` din date, singurul trigger existent).
|
|
|
|
Descoperirea centrala a acestei cercetari: mecanismul de copiere de azi rezolva deja "document nou" si
|
|
"tip corect" (a, b) fara nicio schimbare, dar **pierde tacit** informatia "sursa era o proforma" chiar
|
|
in metoda care ar trebui s-o pastreze (`completeaza_setari_document:387`, care copiaza `listaid` dar nu
|
|
si `eproforma`) — motiv pentru care legatura `VANZARI_CORESP` nu se poate agata de `CASE`-ul existent
|
|
din `finalizeaza_factura` (cheie doar pe `ntip`, care nu poarta aceasta distinctie) si are nevoie de un
|
|
semnal nou, client-side, plus un apel Oracle explicit separat (pasii 1 si 3 din propunere).
|
|
|
|
Niciun fisier de cod atins, niciun `git_sync.ps1`/`txt2vcx.ps1` rulat, niciun commit, nicio scriere pe
|
|
Oracle (doar `SELECT`, rulat cu `sqlplus.exe` pe schema `MARIUSM_AUTO`).
|