Files
roafacturare/docs/cercetare/s5c_factura_din_proforma.md
2026-09-09 22:19:22 +03:00

27 KiB

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):

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).