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
21 KiB
Cercetare — Verificarea 4: descarcare de gestiune pe proforma (Oracle)
Investigatie read-only, 10.08.2026. Nicio modificare de cod, niciun git_sync.ps1. Continua
docs\cercetare\proforma_copiere_puncte_intrare.md (nu il reia) si raspunde punctual la
"Necunoscute ramase" #1 de acolo.
Nota sursa Oracle: docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (mentionat in brief) nu
exista in docs\. Fisierul real e la
D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql (823 337 octeti,
confirma marimea asteptata). Am semnalat discrepanta catre team-lead prin mesaj si am continuat pe
acest fisier — toate citatele PACK:linie de mai jos sunt pe fisierul din DATABASE, nu pe unul
din docs\, pentru ca al doilea nu exista.
Verdict (raspuns la intrebarea 2)
NU — la emiterea unei proforme, gestiunea nu se descarca, pentru niciun articol, indiferent daca
articolul e cu adevarat gestionabil in nomenclator sau nu. Blocajul e prin design: VFP marcheaza
toate liniile unei proforme "negestionabile" inainte de compunerea documentului, ceea ce le trimite
la server cu sentinela id_gestiune = -1000 (dedus, nu confirmat linie-cu-linie — vezi sectiunea
"Ce nu s-a putut stabili"), iar pe Oracle contabilizeaza_articol sare apelul catre
descarca_gestiune exact pe acest sentinel. Concluzia se sprijina si pe intentia de business
explicita din changelog (12.03.2021 / 2.7.x): "Proforma. Articolele din proforma sunt marcate
'negestionabile', astfel incat nu mai este necesara existenta articolelor in stoc pentru a genera
proforma." — adica cerinta initiala a fost explicit "proforma trebuie sa mearga si fara stoc",
nu doar "nu arata plafonul".
1. Tipurile de document "proforma"
Deja stabilit in proforma_copiere_puncte_intrare.md §1 si reconfirmat aici pe partea Oracle:
proforma nu e o valoare in TIP (pack_facturare.ntip, 1-52) — e un atribut ortogonal.
- VFP:
poDate.nIdTipDoc = 23(fata de5= FACTURA), setat din combo-ul "Tip document" (COMUN\clase\ofacturare.vc2:9396-9403,:8745-8754). Setter-ul deriva boolean-ulpoDate.eProforma:COMUN\programe\ofacturare_comun.prg:593-599—This.eProforma = IIF(m.tnIdTipDoc = This.nIdTipDocProforma, 1, 0). - Oracle: nu exista
nIdTipDoc— documentul se scrie inVANZARIcuTIPnormal (business type, 1-52), iarEPROFORMAe o coloana separata peVANZARI. Dovada directa:PACK:5637-5671(PROCEDURE scrie_proforma) — scrie intai antetul cuscrie_in_vanzari(acelasi helper ca la o factura normala), apoi:Deci pe Oracle, proforma e o factura normala inPACK:5666-5669 -- completez vanzari.eproforma update vanzari set eproforma = 1 where id_vanzare = pack_facturare.nid_vanzare;VANZARI/VANZARI_DETALII, cu un flag in plus. - Exista si un mecanism legacy, tabele separate
PROFORME/PROFORME_DETALII(PACK:5674-5767,PROCEDURE scrie_proforma_old/sterge_proforma_old,:5413-5429) — nefolosit de fluxul curent (VFP apeleazascrie_proforma, nuscrie_proforma_old; nu am gasit niciun apel VFP catre varianta_oldinCOMUN\programe\*.prg). Tratati ca schela moarta, nu ca mecanism activ. V_TIP = -102inciteste_setari_document(PACK:1960-1994, ramura:1985-1987,V_VARNAME := 'ID_FDOC_PROFORMA') e un cod folosit doar pentru alocarea de serie/numar (id_fdoc), apelat din VFP lainitializeaza_setari_document(-102)(COMUN\clase\ofacturare.vc2:9415, deja in cercetarea anterioara) — nu are legatura cupack_facturare.ntip, care ramane tipul de business real al documentului.
2. Descarcarea de gestiune la proforma — DA/NU si mecanismul exact
NU. Trasat pe trei straturi, VFP si Oracle:
2.1 VFP: articolele devin "negestionabile" inainte sa intre pe document
COMUN\programe\ofacturare.prg:330-336 (in factureaza, imediat dupa incarcarea cursorului sursa
crsarticole, indiferent de sursa — lista de preturi, comanda, contract, aviz, retur):
* Daca este o proforma, consider toate articolele negestionabile, pentru a nu mai alege din stoc
* 12.03.2021
IF poDate.eProforma = 1
UPDATE (m.lcCursor) SET gestionabil = 0
GO TOP IN (m.lcCursor)
ENDIF
gestionabil = 0 se propaga in crsfactura prin prelucreaza_facturacrs
(COMUN\programe\ofacturare_comun.prg:1801-1810, coloana gestionabil e in lista de INSERT).
La adaugarea/editarea unei linii pe formular, ramura pe gestionabil decide dialogul:
COMUN\clase\ofacturare.vc2:13803-13809:
Case (poArticol.gestionabil = 0 Or gnScadereStoc = 0 Or poDate.tip = 45) && 45 = ROARESTAURANT
ofrmadarticol = Createobject("frm_articol_factura", lnCantitateMax, .F.)
adica acelasi dialog folosit pentru orice articol negestionabil in restul aplicatiei (nu unul
proforma-specific), care ocoleste do_alege_stoc (dialogul de alegere lot din stoc). Pentru
articolele care intra pe frm_articol_factura, id_gestiune implicit e sentinela -1000
(COMUN\clase\ofacturare.vc2:13618-13623, do_initializeaza_articol:
If Type('toArticol.id_gestiune') = "U" THEN AddProperty(toArticol,'id_gestiune',-1000); acelasi
tipar la :17836-17837). La scriere, poArt.id_gestiune se trimite direct ca parametru
V_ID_GESTIUNE catre pack_facturare.adauga_articol_factura
(COMUN\clase\ofacturare.vc2:14069-14073: ... + Nvl(Alltrim(Str(poArt.id_gestiune)),[NULL]) + ...).
2.2 Oracle: id_gestiune = -1000 e sentinela care blocheaza descarcarea
adauga_articol_factura (PACK:4989-5284), primeste V_ID_GESTIUNE si il traduce:
PACK:5032-5034
IF V_ID_GESTIUNE <> -1000 THEN
V_ID_GESTIUNE2 := V_ID_GESTIUNE;
END IF;
V_ID_GESTIUNE2 (necompletat, deci NULL, cand V_ID_GESTIUNE = -1000) e cel scris efectiv in
VANZARI_DETALII_TEMP.ID_GESTIUNE (PACK:5237,5267).
La emitere, contabilizeaza_articol (PACK:7173-7547) parcurge liniile din
VANZARI_DETALII_TEMP si apeleaza descarca_gestiune doar aici:
PACK:7472-7476
IF pack_facturare.ntip <> 4 THEN
IF pack_facturare.nscadere_stoc = 1 AND
detalii_articol.id_gestiune <> -1000 AND
detalii_articol.in_stoc = 1 THEN
pack_facturare.descarca_gestiune(...)
NULL <> -1000 evalueaza la NULL in PL/SQL (nu TRUE), deci conditia pica indiferent de
in_stoc — liniile de pe o proforma nu ajung niciodata la descarca_gestiune, cata vreme
id_gestiune a intrat ca -1000.
Exista si o a treia bariera, independenta, in interiorul lui descarca_gestiune
(PACK:7648-7797), dar aceasta priveste articolul insusi, nu documentul:
PACK:7789-7797
-- NU SE DESCARCA GESTIUNEA PENTRU ARTICOLELE NEGESTIONABILE
-- ASTFEL INCAT SA SE POATA FACE OPERATII GEN AVIZ DIN CUSTODIE INCLUSIV CU ARTICOLE NEGESTIONABILE
SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL;
IF lnInStoc = 0 THEN GOTO SFARSIT; END IF;
Aceasta verifica NOM_ARTICOLE.IN_STOC real (nomenclator), nu flagul de proforma — protejeaza un
articol cu adevarat negestionabil, indiferent de tipul documentului. Nu e mecanismul care
protejeaza proforma; mecanismul de proforma e strict gate-ul id_gestiune <> -1000 de la 2.1-2.2.
2.3 in_stoc trimis de VFP: uneori ignorat de Oracle, dar nu e el gate-ul decisiv
V_IN_STOC_TEMP (parametrul care ajunge in VANZARI_DETALII_TEMP.IN_STOC) e fie preluat direct
de la VFP (V_IN_STOC := V_IN_STOC_TEMP, ramurile implicita si restaurant, PACK:5200-5203, 5111-5112), fie recalculat de Oracle din nomenclator/contract, ignorand ce a trimis VFP, pe
ramurile comenzi (PACK:5061-5066), avize (:5086-5091) si contract cu pret de contract
(:5153-5158, 5184). Asta inseamna ca pentru o proforma facuta din comanda/aviz/contract, campul
IN_STOC scris efectiv poate reveni la valoarea reala din nomenclator (1 pentru un articol
gestionabil), dar asta nu conteaza — gate-ul din 2.2 cere id_gestiune <> -1000 AND in_stoc = 1
cu AND, iar id_gestiune ramane blocat la -1000/NULL indiferent de sursa documentului
(sentinela vine din UI, la nivelul liniei, nu din cursorul de incarcare). Deci recalcularea lui
in_stoc de catre Oracle pe aceste ramuri nu redeschide descarcarea.
3. De la proforma la factura
Nu exista o rutina de "transformare" dedicata — mecanismul e copierea, deja documentata complet
in proforma_copiere_puncte_intrare.md §2 (tooltip explicit COMUN\clase\ofacturare_comun.vc2:1409:
"Se foloseste si pentru generarea unei facturi din proforma prin copiere").
- Punct de intrare VFP:
frm_facturi.But_copiaza1.Click -> do_copiaza(degradeaza tipul de business,COMUN\clase\ofacturare_comun.vc2:3628-3713)-> copiere_factura(COMUN\programe\oproceduri_facturare.prg:150-153)-> factureaza(tip_degradat, toFactura). - Punct de intrare Oracle: acelasi
pack_facturare.adauga_articol_factura/scrie_in_vanzarica la orice document nou — nu exista unpack_facturare.transforma_proformasau echivalent. Singurul apel Oracle specific copierii e cursorul de precompletare,pack_facturare.cursor_retur_document(vezi §4), apelat cuV_COPIERE = 1(COMUN\programe\ofacturare.prg:267-268). completeaza_setari_document(toDateAnterior, .T.)(COMUN\programe\ofacturare_comun.prg:362-412) nu propaganIdTipDoc(linia comentata,:370) — documentul nou porneste cunIdTipDocimplicit (5=FACTURA sau6=AVIZ, dupatnTipdegradat,COMUN\programe\ofacturare.prg:187-196), decipoDate.eProforma = 0pentru documentul nou, indiferent ca sursa era proforma.
4. Ce se intampla cu stocul intre proforma si factura
Nimic de reconciliat, pentru ca proforma nu a atins niciodata stocul (§2). Nu exista concept de "rezervare de stoc" pe proforma:
- tabelele legacy
PROFORME/PROFORME_DETALII(§1) nu au coloane de rezervare si oricum nu sunt pe calea activa; - nu am gasit, in
PACK_FACTURARE, niciun apel care sa insereze inRULsau sa actualizezeSTOClascrie_proforma— funcita se limiteaza lascrie_in_vanzari+UPDATE vanzari SET eproforma=1(§1,PACK:5637-5671); - cautare directa in fisierul PACK pentru orice mentiune de rezervare pe proforma (
rezerv,blocheaza stoc) nu a dat rezultate relevante (v. "Ce nu s-a putut stabili" pentru limitele cautarii text simple pe un fisier de 823 KB).
La copiere (transformarea efectiva in factura), gestionabilitatea reala se restaureaza:
cursorul de precompletare la copiere, cursor_retur_document
(PACK:3949-4000), calculeaza GESTIONABIL asa:
PACK:3993-4000
(case
when V_PROFORMA = 1 then 0
when V_COPIERE = 1 then B.IN_STOC -- NOM_ARTICOLE.IN_STOC, articolul real
else A.GESTIONABIL
end) AS GESTIONABIL,
La copiere, V_COPIERE = 1 e hardcodat (COMUN\programe\ofacturare.prg:267-268:
cursor_retur_document(?poDate.in_valuta,?poDate.listaid,1,?poDate.eProforma,?gnIdUtil) — al treilea
parametru pozitional 1 e V_COPIERE), iar V_PROFORMA trimis e poDate.eProforma al
documentului nou, care e 0 (§3) — deci ramura V_PROFORMA=1 nu se activeaza la copiere, si
GESTIONABIL = B.IN_STOC (flagul real din nomenclator). Rezultat: liniile copiate dintr-o proforma
redevin gestionabile normal daca articolul chiar e in stoc, trec prin do_alege_stoc la editare
(ofacturare.vc2:13804, ramura Otherwise), primesc un id_gestiune real, si descarcarea de
gestiune se face normal la emiterea facturii rezultate din copiere — exact ca la orice factura noua,
nu printr-un pas separat de "transformare".
5. Ce verifica serverul la descarcare, si cu ce eroare
Verificari observate direct in PACK_FACTURARE, toate independente de proforma (se aplica oricarei
descarcari reale de gestiune):
- Gestiune inexistenta/stearsa:
PACK:7847-7858—SELECT ... FROM NOM_GESTIUNI WHERE ID_GESTIUNE = V_ID_GESTIUNE AND STERS = 0;NO_DATA_FOUND -> FACT-007. - Stoc epuizat / lot inexistent:
PACK:7860-8493— construiestetab_stocdinRUL/STOCdupa criterii (articol, gestiune, cont, serie, pret etc.) si, daca nu gaseste nimic (SQL%ROWCOUNT = 0):FACT-008("Articolul ... nu mai e in stoc") sau, daca nici macar denumirea nu se gaseste,FACT-009. - Ramuri similare mai jos in acelasi fisier pentru alte cazuri de gestiune/combinatii invalide:
FACT-010(:10001),FACT-011(:10323),FACT-014combinatie invalida de gestiuni (:12127),FACT-019gestiune (:10449),FACT-020/FACT-021variante "nu mai e in stoc" (:10748,10752). - Optiune globala de bypass:
RF_FACTURARE_FARA_STOC(PACK:7783-7784,lnFacturareFaraStoc) — permite facturarea peste cantitatea disponibila pentru articole gestionabile; nu e specifica proformei, e o optiune de firma generala. - Cota TVA lipsa / articol fara politica de pret — nu sunt verificari de stoc, dar sunt cele mai
frecvente erori vecine (
FACT-024lacontabilizeaza_articol,PACK:7278-7302;FACT-018,FACT-012,FACT-013la cautarea cotei TVA inadauga_articol_factura, deja semnalate inplan_13_unificare_formular_facturare.md§G). O proforma cuid_gestiune=-1000nu trece deloc prin verificarile de stoc de mai sus (FACT-007/008/009/010/011/014/019/020/021), pentru ca nu ajunge ladescarca_gestiune— dar tot trece prin verificarea de politica de pret / cota TVA, care nu are legatura cu stocul.
6. Consecinte pentru S5b — constrangeri de proiectare
- Formularul unificat trebuie sa reproduca exact mecanismul
gestionabil=0la incarcarea liniilor candpoDate.eProforma = 1— nu doar sa ascunda vizual plafonul. Fara acest pas, articolele gestionabile ar intra pe document cuid_gestiunereal si ar declansadescarca_gestiunela emitere, contrazicand comportamentul de azi si cerinta de business ("proforma merge fara stoc"). - Nu se apeleaza
do_alege_stoc(dialogul de alegere lot) pentru liniile unei proforme. Traseul corect e cel al articolului negestionabil (frm_articol_factura/do_initializeaza_articol), care garanteazaid_gestiune = -1000pe linie. id_gestiune = -1000trebuie sa ajunga efectiv in parametrulV_ID_GESTIUNEtrimis catrepack_facturare.adauga_articol_factura— verificarea de gate e strict pe aceasta valoare (<> -1000), nu pe un flag de document. Daca formularul unificat schimba felul in care construieste liniile (de ex. reutilizeaza un obiect de linie comun facturii si proformei), acest-1000trebuie sa fie explicit setat pe ramuraeProforma=1, nu mostenit implicit.in_stoc/gestionabiltrimis de VFP nu e suficient de la sine — pe unele surse (comanda, aviz, contract cu pret de contract) Oracle il rescrie din nomenclator/contract (§2.3). Gate-ul real eid_gestiune, deci formularul unificat nu poate conta pe faptul ca a trimisin_stoc=0; trebuie sa garantezeid_gestiune=-1000.- La copiere proforma -> factura, comportamentul trebuie sa fie opus: liniile trebuie sa-si
recapete gestionabilitatea reala (
B.IN_STOCdin nomenclator), nu sa ramana blocate la negestionabil. Decizia deja luata in plan ("degradarea de tip dindo_copiazaramane pentru copiere si nu se aplica la regenerare") e consistenta cu asta, dar merita spus explicit: regulaeProforma=1 -> gestionabil=0se aplica doar la incarcarea/compunerea unei proforme noi, nu si la copierea din ea — documentul nou pleaca cueProforma=0(§3-4) si trebuie sa lase Oracle sa recalculezeGESTIONABILnormal. - Formularul unificat nu trebuie sa implementeze nicio logica de "eliberare stoc rezervat" la trecerea proforma -> factura — nu exista rezervare de stoc pe proforma (§4), deci nu exista nimic de eliberat. Riscul tehnic real ramane cel deja semnalat in plan §G (ordinea stergere-inaintea-reemiterii in aceeasi tranzactie la regenerare), care e independent de proforma.
- Verificarile de stoc (
FACT-007/008/009/010/011/014/019/020/021) nu se vor manifesta niciodata pentru o linie de proforma cata vreme regula #1-#3 e respectata — formularul unificat nu are nevoie de tratament special pentru aceste coduri de eroare pe ramura proforma (nu pot aparea acolo), dar tot trebuie sa trateze erorile de politica de pret/TVA (FACT-012/013/018/024), care raman valabile si pe proforma.
7. Copierea proformei in formularul unificat — ce lipseste
Plecand de la proforma_copiere_puncte_intrare.md §2 (traseul general de copiere, deja complet
documentat) si de la S5b din plan (plan_13_unificare_formular_facturare.md:1674-1689):
- Ce exista deja si se reutilizeaza neschimbat:
do_copiaza(degradarea de tip),copiere_factura,factureaza(tip, toFactura),completeaza_setari_document,cursor_retur_documentcuV_COPIERE=1. Niciunul din aceste puncte de intrare nu are legatura speciala cu proforma dincolo de parametrulV_PROFORMAdeja tratat corect (§4) — nu trebuie adaugat nimic nou aici pentru ca formularul unificat sa suporte copierea unei proforme. - Ce lipseste, specific formularului unificat, nu copierii in sine: mecanismul
crsarticoleintreg (incarcarea de masa +UPDATE ... SET gestionabil=0, §2.1) presupune un cursor complet incarcat inainte de afisare. Planul (plan_13_unificare_formular_facturare.md:1470) stabileste deja cacrsarticolenu se mai incarca in masa in formularul unificat — deci pasul "seteaza gestionabil=0 pe toate liniile cand eProforma=1" trebuie reimplementat linie-cu-linie, la momentul in care fiecare linie e adaugata pe formularul unificat (fie la copiere, fie la compunere noua), nu ca un singurUPDATEde masa pe un cursor care nu mai exista. Constrangerea #1-#3 de mai sus (sectiunea 6) e exact specificatia acestui pas lipsa. - Combo-ul de tip document si realocarea de serie — deja acoperite de decizia S5b din plan
(
Ct_clb_fdocramane, realocare la comutare); nu am gasit nimic suplimentar de adaugat aici fata de ce e deja scris in plan.
Ce nu s-a putut stabili
- Linia exacta unde
poArt.id_gestiunedevine efectiv-1000pentru o linie de proforma, in loc de a ramane la valoarea implicita de camp (0, cursorulcrsfacturacreat cuid_gestiune N(20)faraNULL, iarprelucreaza_facturacrsnu includeid_gestiunein lista sa de INSERT —COMUN\programe\ofacturare_comun.prg:1801-1810). Am gasit sentinela-1000setata conditionat ("daca proprietatea lipseste") indo_initializeaza_articol(COMUN\clase\ofacturare.vc2:13618-13623), dar nu am confirmat ca proprietatea chiar "lipseste" (Type = 'U') in momentul in carefrm_articol_facturaproceseaza o linie de proforma provenita dinScatterpecrsfactura. Argument indirect, nu dovada directa: dacaid_gestiunear ajunge0(nu-1000) la server,descarca_gestiunear cautaNOM_GESTIUNI WHERE ID_GESTIUNE=0si ar aruncaFACT-007la fiecare emitere de proforma cu articol gestionabil din comanda/aviz — eroare care ar fi vizibila si raportata de ani (proforma exista din 2014+ in changelog); absenta oricarei asemenea raportari sustine indirect ca sentinela-1000chiar ajunge la server, dar nu e o dovada pe cod. - Nicio verificare pe date vii — tot ce e mai sus e trasare de cod static (VFP text + PL/SQL text), nu rulare/log real. Nu am rulat nimic, conform mandatului read-only.
- Cautarea de "rezervare de stoc pe proforma" (§4) s-a facut prin grep text simplu pe
PACK_FACTURAREdupa cuvinte cheie (rezerv,PROFORMA) — nu e o dovada de completitudine pentru intreaga baza de date Oracle (declanșatoare/triggere peVANZARI/VANZARI_DETALII, proceduri din alte pachete). Zero rezultate nu inseamna cu certitudine ca nu exista niciun mecanism de rezervare in alta parte a schemei. - Fisierul
docs\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sqlnu a fost creat de mine — am lucrat pe originalul dinDATABASE\SCRIPTURI_CLAR. Daca cineva copiaza ulterior fisierul indocs\cu alta numerotare de linii, citatelePACK:liniedin acest raport trebuie re-verificate pe copia noua.
Verificari recomandate pe date vii (daca raman intrebari)
- Emis o proforma de test cu un articol cu adevarat gestionabil si cu stoc real, sursa = comanda
(ramura unde Oracle rescrie
IN_STOC, §2.3) — confirma caRUL/STOCnu se modifica dupa emitere si caVANZARI_DETALII.ID_GESTIUNEa fost scrisNULLpentru acea linie. - Acelasi test, sursa = lista de preturi (ramura unde Oracle are incredere in
V_IN_STOC_TEMP) — pentru comparatie. - Copiaza proforma de mai sus in factura si confirma ca
VANZARI_DETALII.ID_GESTIUNEal facturii rezultate e populat cu o gestiune reala si caRULinregistreaza descarcarea la emiterea facturii. - Interogare directa pe schema pentru triggere/joburi legate de
EPROFORMAsau de rezervare de stoc, daca exista suspiciunea din punctul 3 de mai sus:SELECT trigger_name, table_name FROM user_triggers WHERE table_name IN ('VANZARI','VANZARI_DETALII','STOC','RUL');