52 KiB
S4f — Returul in formularul unificat
Proiectare pe cod, READ-ONLY (fara editari, fara git_sync.ps1/txt2vcx.ps1, fara commit, fara
scriere Oracle — doar SELECT), pentru povestea S4f din
docs\plan_13_unificare_formular_facturare.md:2287-2330 (decizia 17, proiectata in sectiunea N,
:1574-1655). Nu s-a atins COMUN\clase\ofacturare_comun.vc2 si
COMUN\programe\ofacturare_editare.prg — doar citite, cand au aparut in cautari.
Surse de adevar deja stabilite, citate nu reinvestigate: docs\cercetare\legatura_linie_retur.md,
docs\cercetare\factura_retur_document.md, docs\cercetare\retur_si_lista_preturi.md,
docs\cercetare\s4b_bara_butoane_meniu.md.
Verdict (esenta, 10 randuri)
Corectat dupa avertismentul S4e (docs\cercetare\s4e_lista_preturi_pe_sursa.md, sectiunile 3 si
7): mecanismul APPEND FROM din decizia 16 (ofacturare.prg:454-473) e respins pentru orice
cursor care serveste si drept registru citit de do_sterge, crsarticole fiind exact acel cursor
pe documentele de retur (Inlist(poDate.tip,8,9,24) => Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c, ofacturare.vc2:14658-14659) — riscul e coliziune de
id_c intre cursor_retur_document si cursor_preturi, ambele numerotate ROWNUM independent.
Sectiunea 5 de mai jos e rescrisa pe solutia validata de S4e: liniile libere nu intra deloc in
crsarticole, se adauga direct in crsfactura prin APPEND BLANK + combosql (tiparul deja in
productie la frm_facturare_articole2.But_nou1.do_adauga), iar campul de distinctie e
crsfactura.id_c (0 implicit pe o linie libera, valoare pe care Oracle n-o produce niciodata
pentru id_c), nu o coloana lipsa in crsarticole.
Partea grea nu e ce parea: N.1 (documentul de retur, tip 8/9/24) merge deja cap-coada — alegere
multipla de facturi, populare din cursor_retur, gestiune si pret de achizitie mostenite, stergere
si retur partial. Munca reala e in trei bucati inguste. (1) Nu se muta dialogul de alegere a
facturilor in bara de butoane a gridului — s-a verificat pe cod ca alegerea ramane la nivelul
antetului (sectiunea pliata), exact cum recomanda deja s4b_bara_butoane_meniu.md §9.3/tabelul
"puncte marunte", randul h; ce se muta in meniul "Adauga articole" e rezultatul alegerii (liniile
deja aduse), ca "Adauga tot din facturile alese" / "Alege liniile de returnat…", simetric cu
comanda/contract/avize. (2) Ridicarea lui But_retur la nivel de document e cod nou real, nu o
mutare de buton — azi alegerea e per-articol si niciodata scrisa ca legatura persistata.
(3) Liniile libere pe retur folosesc reteta S4e ("APPEND BLANK pe crsfactura, niciodata pe
crsarticole"), plus un gol nou de proiectat, gasit in aceasta sesiune si necunoscut de S4e (care
nu are dialog de gestiune pe comanda/avize): mecanismul de alegere a gestiunii
(frm_articol_gest_factura, .lRetur=.T.) suprascrie pretul de vanzare cu pretul din stoc
(ofacturare.vc2:4094-4103) — corect pentru o linie mostenita dintr-o factura sursa, dar gresit
pentru o linie libera, a carei pret de vanzare trebuie sa vina din lista de preturi (decizia 16), nu
din costul de stoc; in plus, acel dialog se intra azi doar dintr-un poArticol scatter-uit din
crsarticole (do_adauga_articol/do_alege_stoc), pe care o linie libera din crsfactura nu-l are
— e nevoie de un punct de intrare nou in dialog, nu doar de reparat pretul. Vezi sectiunea 5 si
riscurile R1/R7.
1. Inventarul celor doua cai de retur de azi
1.1 N.1 — factura de retur ca document (tip 8, 9, aviz 24)
| Pas | Ce face | fisier:linie |
|---|---|---|
| Intrare | Tile Page2.Cw1 -> politica.mpr -> factureaza(8)/factureaza(9) din meniul shortcut |
COMUN\clase\ofundal_facturare.vc2:882-884, Meniuri\politica.mn2:14-15,45-46 |
| Antet | nIdTipDoc=5, formular frm_date_factura, aviz retur (24) foloseste frm_date_aviz cu nIdTipDoc=6 |
COMUN\programe\ofacturare.prg:192-196,222-226 |
| Alegere facturi sursa | frm_date_factura.do_cauta_facturi -> caut_facturi_multiple_client(id_client, in_valuta, id_valuta, .T.) -> cauta_alfa(..., tnTipReturn=1), selectie multipla, exclude tipurile de retur din sursa |
COMUN\clase\ofacturare.vc2:9173-9212; COMUN\programe\oproceduri_facturare.prg:2091-2121 |
| Validare obligatorie | Fara alegere, antetul nu se poate inchide (inainte_de_do_termin) |
ofacturare.vc2:9523-9526 |
| Populare linii | pack_facturare.cursor_retur(V_IN_VALUTA,V_LISTAID,V_ID_UTIL) -> cursor_retur_document(...,V_COPIERE=0,...), SELECT direct din VANZARI_DETALII, filtrat pe ID_VANZARE IN (V_LISTAID) |
ofacturare.prg:306-307; ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:3943-3956,3958-4071 |
| Gestiune + pret achizitie | ID_GESTIUNE/PRET_ACHIZITIE copiate neschimbate din linia originala; GESTIONABIL = NVL2(A1.ID_GESTIUNE,1,0) |
ff_...sql:4034-4035,4055-4056,4048 |
| Stergere linie | Permisa, cantitatea reintra in cursorul sursa | ofacturare.vc2:14608-14693, ramura :14658-14659 |
| Retur partial | Permis, validat fata de maximul = CANTITATE a liniei originale, fara agregare cu retururi anterioare |
ofacturare.vc2:14743-14754, ff_...sql:4036 |
| Adaugare libera | Nu se poate azi — do_adauga_articol ia articolul mereu din crsarticole, care pe tip 8/9/24 este rezultatul lui cursor_retur |
ofacturare.vc2:12843-12851 |
1.2 N.2 — But_retur per-articol, in factura normala (tip 1, 5, 7, 10)
| Pas | Ce face | fisier:linie |
|---|---|---|
| Vizibilitate | Doar pe tip 1/5/7/10; pe documentele de retur (8/9/24) butonul nu exista in UI | ofacturare.vc2:15122-15127 |
| Declansare | caction=do_retur -> do_adauga_articol(.F.,.F.,.T.) |
cmd_butoane.vc2:324-338; ofacturare.vc2:13963-13965 |
| Alegere factura sursa | Per articol, la fiecare adaugare: caut_facturi_multiple_client_articol(id_client,in_valuta,id_valuta,.F.,id_articol) -> cauta_alfa cu titlu simplu "Alegeti factura" (nu selectie multipla) |
oproceduri_facturare.prg:2124-2159 |
| Acumulare | thisform.cListaIdArticoleRetur acumuleaza CSV de perechi id_articol:id_vanzare, cate una per articol adaugat; poDate.listaid e folosit transient (salvat in lnListaIdOld si restaurat imediat dupa) doar cat dureaza dialogul per-articol |
ofacturare.vc2:12882-12892 |
| Gestiune | Se alege, nu se mosteneste — pack_facturare.cursor_gestiuni_articol_retur, prin do_alege_stoc(...,tlRetur=.T.) -> frm_articol_gest_factura |
ofacturare.vc2:13230,13353-13385 |
| Pret | Suprascris cu pretul din stoc (pretv), nu cel din lista de preturi — vezi sectiunea 5 |
ofacturare.vc2:4094-4103 |
| Semn cantitate | Explicit poArticol.cantitate = (-1) * cantitate cand Thisform.lRetur |
ofacturare.vc2:4103 |
| Trimitere Oracle | poDate.listaid = thisform.cListaIdArticoleRetur la scriere finala |
ofacturare.vc2:13977-13979 |
| Legatura persistata | Nicio legatura scrisa — listaid e folosit doar ca filtru in calculul de disponibil pe rulaj (RUL), nu scrie nimic in VANZARI_CORESP sau pe linia noua |
ff_...sql:8142-8212 |
1.3 Ce au in comun si unde diverg
Comun: excluderea returului dintr-un retur (acelasi filtru tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11)
in ambele functii de cautare), conventia de semn negativ pe cantitate, frm_articol_gest_factura
ca formular de alegere a gestiunii pentru linia gestionabila.
Diverg pe tot restul: N.1 alege facturile o singura data, la nivel de document, inainte ca
articolele sa existe; N.2 alege per articol, in orice moment, fara limita de cate ori. N.1
mosteneste gestiune+pret_achizitie fara alegere; N.2 le cere explicit. N.1 scrie
VANZARI_CORESP(TIP=3); N.2 nu scrie nimic persistat. Zero cod comun intre cele doua cai —
ofacturare.vc2:12813-12900 (N.2, do_adauga_articol) si ofacturare.prg:306-311 (N.1,
cursor_retur) nu se ating.
2. do_cauta_facturi / cauta_alfa(..., tnTipReturn=1) — contractul exact
2.1 Cine il cheama si cand
Pe frm_date_factura exista un control generic de cautare, Ct_clb_altele (clasa
ct_clb_cautare), a carui iconita de lupa e legata de cprocedura = thisform.do_cauta_altele
(ofacturare.vc2:8721-8729). do_cauta_altele e un dispecer pe nid_tip:
Case Inlist(Thisform.nid_tip,8,9)
Thisform.do_cauta_facturi()
(ofacturare.vc2:8953-8954)
Secventa confirmata pe cod (factureaza(), ofacturare.prg:187-311): frm_date_factura se
creeaza si se afiseaza (.Show(), :230-235) inainte ca Do Case tnTip de la :266-308 sa
ruleze cursor_retur, si mult inainte ca lcObject = [frm_facturare_articole] sa fie ales
(:395). Executia continua abia dupa ce ofrmceredate (antetul) se elibereaza (:248), iar
pnButon (setat la inchiderea antetului) e verificat imediat dupa. Deci azi dialogul de alegere
a facturilor ruleaza pe formularul de antet, complet inainte ca formularul de articole sa existe —
crsarticole se incarca o singura data, cu poDate.listaid deja fixat.
Control observat, semnificativ pentru sectiunea 3: Ct_clb_altele are
cconditie = EMPTY(NVL(poDate.listaid,'')) (ofacturare.vc2:8722) — sugereaza ca iconita de
cautare e activa doar cat timp nimic nu a fost inca ales; neverificat insa exact ce proprietate
citeste cconditie (clasa ct_clb_cautare nu a fost gasita in text in acest repo, posibil intr-un
.vcx neconvertit sau in COMUNROA), deci nu se poate confirma daca astazi re-alegerea e blocata
explicit sau doar descurajata vizual. De tratat ca ipoteza, nu ca fapt confirmat.
2.2 Contractul functiei
caut_facturi_multiple_client(tnIdPart, tnInValuta, tnIdValuta, tlFacturiMultiple)
(oproceduri_facturare.prg:2091-2121):
- Intrare: client (obligatoriu — dialogul nu porneste fara el), valuta (doar daca
tnInValuta),tlFacturiMultiple=.T.la acest apel ->lnTipReturn=1incauta_alfa. - Sursa:
select serie_act,numar_act,data_act,dataora,id_vanzare from fact_vfacturi where sters=0 and tip in (1,2,3,4,5,6,10,-1,-2,-3,-4,-11) [+ conditie sucursala] [+ client] [+ valuta]— fara filtru SQL pe perioada/serie (filtrarea pe acele coloane e comportament generic alcauta_alfa, nu parametru dedicat). - Iesire: XML cu randurile bifate (
ales=1), convertit local prinXmltocursor(..., "crsFacturiTemp"); nimic nu ajunge la Oracle in acest pas. - Populare aditiva a rezultatului in VFP:
poDate.listaid = cursor2lista("crsFacturiTemp", "id_vanzare", ",")— inlocuieste intreg continutul (=, nu+=); daca dialogul se apeleaza a doua oara azi, a doua rulare suprascrie complet prima (dar azi asta nu se intampla niciodata pentru ca dialogul ruleaza o singura data, inainte de orice alta actiune pe document — vezi 2.1). cauta_alfa(...,tnTipReturn=1)(COMUN\programe\cauta_alfa.prg:16-260, mecanismul generic folosit peste tot in suita): adauga singur coloanaales(cauta_alfa.prg:124), titlu explicit "Alegeti ... (mouse-click pe numar sau apasati SPACE)", filtrare interactiva pe coloanele afisate. Nu are mecanism de dezactivare a unei optiuni individuale, nici submeniu — doar bifare/debifare.
2.3 Varianta per-articol
caut_facturi_multiple_client_articol(tnIdPart, tnInValuta, tnIdValuta, tlFacturiMultiple, tnIdArticol)
(oproceduri_facturare.prg:2124-2159) — aceeasi functie de baza, cu doua diferente: filtru
suplimentar b.id_articol = ?pnIdArticol (join pe vanzari_detalii) si tlFacturiMultiple=.F. la
apelul din do_adauga_articol (:12884), deci lnTipReturn=0 -> selectie simpla, nu multipla.
Titlu simplu "Alegeti factura". Rezultatul e un obiect cu un singur id_vanzare, nu un cursor.
3. Proiectarea punctului 1 — alegerea facturilor sursa ca sursa in meniul de adaugare
Ce NU se schimba: alegerea propriu-zisa a facturilor sursa (dialogul cu bifare multipla) ramane
la nivelul antetului — in formularul unificat, sectiunea pliata (decizia 7). Verificat impotriva
tabelului "puncte marunte" din plan (plan_13...md, randul h): „Alege facturile de returnat…"
ramane doar la antet in etapa I; mutarea (in bara de butoane) e o poveste separata — si confirmat
independent de tabelul de meniu al lui s4b_bara_butoane_meniu.md §3: pe randul "retur (8,9,24)",
meniul "Adauga articole" propus contine "Adauga tot din facturile alese" · "Alege liniile de
returnat…" · "Cauta in lista de preturi…" · "Alege din nomenclator…" — nu si "Alege facturile de
returnat…". Punctul 1 al lui S4f nu contrazice asta: ce se muta in meniul de adaugare e
rezultatul alegerii deja facute la antet (liniile din facturile alese), simetric cu comanda/
contract/avize, nu dialogul de alegere a facturilor insusi.
Ce SE schimba, si e proiectarea reala: azi secventa e rigida — antet modal -> cursor_retur ->
formular de articole (sectiunea 2.1). In formularul unificat exista un singur formular, mereu
deschis; sectiunea de antet (pliata) si gridul de articole coexista. Trei consecinte de proiectat:
-
Cand se declanseaza
cursor_retur_document? Nu mai poate fi legat de "inchiderea antetului" (nu mai exista acel eveniment). Trebuie legat de confirmarea dialogului de alegere (butonul de cautare din sectiunea pliata, echivalentul luiCt_clb_altele/do_cauta_facturi): imediat ce utilizatorul bifeaza facturile si confirma,poDate.listaidse seteaza sicursor_retur_documentruleaza pe loc, populand/repopulandcrsarticole. Documentul poate porni cu tipul deja pe 8/9/24 (ales din combo-ul de tip document) inainte ca vreo factura sa fie aleasa — grid-ul de articole ramane gol pana la prima alegere, exact ca azi candReccount(crsarticole)=0da mesajul "Nu exista articole pentru optiunile alese!" (ofacturare.prg:325). -
Poate opera la orice moment, nu doar o data. Spre deosebire de azi (dialogul ruleaza o singura data, inainte ca gridul sa existe), in formularul unificat butonul din sectiunea pliata e apasabil oricand documentul e deschis. Trebuie decis explicit comportamentul la a doua apasare — vezi punctul urmator.
-
Alegere aditiva sau inlocuitoare, la a doua apasare. Azi
poDate.listaid = ...inlocuieste (nu+=), dar azi nu conteaza pentru ca nu se poate apasa a doua oara dupa ce gridul exista. In formularul unificat, daca utilizatorul a ales deja factura A, a adaugat cateva linii din ea incrsfactura, si apoi vrea sa adauge si din factura B, doua variante:- (a) Inlocuire — a doua alegere reseteaza
poDate.listaid/crsarticolela noul set ales; liniile deja mutate incrsfacturaraman (crsfactura e independent de crsarticole dupa mutare), dar orice linie inca needitata din factura A dispare dincrsarticolefara avertisment. Simplu de implementat (identic cu azi), dar surprinzator pentru operator. - (b) Aditiv — a doua alegere extinde
poDate.listaidcu facturile noi (evitand duplicate) si ruleazacursor_retur_documentfiltrat doar pe facturile noi, cuINSERT INTO crsarticole(nuSELECT INTO), exact reteta deja propusa des4b_bara_butoane_meniu.md§9.3, optiunea 2 — cere cod VFP nou (bucla de filtrare +INSERT), dar zero cod nou inpack_facturare(aceeasi procedura, apelata de mai multe ori). Consistent cu filozofia deciziei 16 ("sursa umple documentul, nu il inchide").
Recomandare: varianta (b), aditiv — e coerenta cu tratamentul lista-de-preturi (S4e) si cu comanda/contract (unde alegerea suplimentara nu sterge ce exista deja), si evita pierderea tacuta de linii needitate. Ramane decizie de confirmat de Marius — nici plan-ul, nici
s4b_bara_butoane_meniu.mdnu au tranzat-o explicit (§9.5, punctul 2 acolo o listeaza tot ca deschisa). - (a) Inlocuire — a doua alegere reseteaza
Consecinta pentru validarea de antet: garda de azi (inainte_de_do_termin, descriere obligatoriu
pentru tip 8/9, ofacturare.vc2:9523-9526) nu mai are un moment natural "inainte de a inchide
antetul" — se muta la garda echivalenta din Termina (aceeasi verificare, alt declansator).
4. Proiectarea punctului 2 — ridicarea But_retur la nivel de document
Ce se pastreaza din calea per-articol: alegerea gestiunii ramane per-articol, prin
cursor_gestiuni_articol_retur si frm_articol_gest_factura — decizia 22/N.3 spune explicit ca
gestiunea si pretul de achizitie se aleg, nu se mostenesc, pentru orice linie fara factura
sursa unica precisa (si N.2 nu are niciodata o factura "sursa unica a documentului", are cel mult
factura aleasa pentru articolul curent). Punctul 2 nu schimba asta.
Ce se schimba: alegerea facturii sursa nu mai e per-articol (un dialog cauta_alfa cu selectie
simpla la fiecare do_retur), ci la nivel de document, dupa modelul N.1 — un singur dialog cu
selectie multipla (caut_facturi_multiple_client, acelasi ca la N.1, dar filtrat pe articolul
curent doar daca ramane necesar; de decis daca filtrul pe articol dispare complet odata cu ridicarea
la document). Consecinta directa: poDate.listaid (sau un camp nou, vezi mai jos) ar fi populat o
singura data pentru intreg documentul, nu reconstruit per articol prin caut_facturi_multiple_client_articol.
Capcana de proiectare, gasita pe cod: poDate.listaid e deja partajat intre N.1 si N.2 azi —
N.2 il suprascrie transient (lnListaIdOld = poDate.listaid ... poDate.listaid = m.lnListaIdOld,
ofacturare.vc2:12882,12892) doar cat dureaza alegerea per-articol, apoi il restaureaza. Daca N.2
ridicat la document incepe sa scrie permanent in poDate.listaid (ca N.1), cele doua mecanisme
intra in conflict pe acelasi camp — un document normal (tip 1/5/7/10) cu retur ridicat la nivel de
document ar avea poDate.listaid populat cu facturile de retur alese, camp care pe alte tipuri
(comanda/contract/avize) e deja folosit cu alt sens (id-uri de comanda/contract/aviz sursa, vezi
ofacturare.prg:266-308). Nu e conflict pe tip 1/5/7/10 — acele tipuri nu folosesc azi
poDate.listaid pentru altceva (sunt populate cu cursor_preturi, care nu ia V_LISTAID ca
parametru) — deci reutilizarea e sigura tehnic, dar merita un camp cu nume propriu
(poDate.listaid_retur sau similar) ca sa nu se ambiguizeze semantic ce inseamna listaid pe un
document normal. De decis la implementare, nu blocant.
Ce arata in bara de butoane / meniu (S4b): tabelul din s4b_bara_butoane_meniu.md §3 nu are
azi un rand pentru "retur intr-o factura normala" — doar pentru documentele de retur propriu-zise
(8,9,24). Ridicarea lui N.2 la nivel de document introduce o optiune noua in meniul "Adauga
articole" pentru tipurile 1,5,7,10: "Retur de articole…" (deja anticipata in tabelul §3 al
raportului S4b, coloana lista de preturi: "Cauta in lista de preturi… · Alege din nomenclator… ·
Retur de articole…"). Aceasta optiune deschide dialogul de alegere multipla la nivel de document
(prima data), apoi pe alegerile ulterioare acelasi comportament aditiv/inlocuitor discutat la
sectiunea 3 se aplica identic.
Ce dispare: caut_facturi_multiple_client_articol (filtrul per-articol) ramane cod mort daca
alegerea trece integral la nivel de document — sau se pastreaza ca alegere secundara optionala
("mai am nevoie de o factura sursa doar pentru articolul X", nefolosita azi in acest scenariu). Nu
e clar din decizia 17/N.3 daca trebuie eliminata explicit sau doar nu mai e calea principala — de
decis de Marius (risc R3).
5. Proiectarea punctului 3 — liniile libere pe document de retur
Corectie fata de premisa initiala a brief-ului ("prin acelasi APPEND FROM ca la S4e"): S4e a
gasit ca reteta literala a deciziei 16 (ofacturare.prg:454-473) nu e sigura pe niciun tip unde
crsarticole e citit ca registru de do_sterge/do_scrie_factura, si a documentat asta explicit
pentru retur, in tabelul sau de la §7:
"retur ca document (8,9,24) |
crsarticole= registru citit dedo_scrie_factura? Nu — cad peOtherwise, faraSum(cantitate)/pnParametruAditional|do_stergeajusteazacrsarticolepeid_c? Da, partial —Inlist(poDate.tip,8,9,24) => Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c(:14658-14659, semn opus, urmareste maximul returnabil, nu inchiderea) | Concluzie: risc de coliziuneid_cramane, dar fara poluareaSum: o linie libera adaugata literal prinAPPEND FROMincrsarticolepe un document de retur ar putea, la stergere, atinge tacut cantitatea maxima returnabila a unei linii reale — de tratat cu aceeasi solutie (linii libere in afaracrsarticole) si in S4f." (s4e_lista_preturi_pe_sursa.md, §7, randul "retur ca document")
Solutia S4e (verificata acolo pe comanda/avize) se aplica identic aici — sectiunile de mai jos sunt
rescrise pe ea, nu pe APPEND FROM.
5.1 Mecanismul corect: APPEND BLANK pe crsfactura, niciodata pe crsarticole
Liniile libere nu intra in crsarticole. Se adauga direct in crsfactura, prin acelasi gest deja
in productie la frm_facturare_articole2.But_nou1.do_adauga (ofacturare.vc2:17118-17122):
PROCEDURE do_adauga
Select crsFactura
APPEND BLANK
this.grd_factura.SetFocus()
ENDPROC
urmat de editare inline prin combosql pe celula de cod/denumire (mecanismul construit de S4/S4e
pentru cautarea filtrata pe server, pack_facturare.cursor_preturi cu V_FILTRU_COD/V_FILTRU_DEN).
Optiunea de meniu "Cauta in lista de preturi…" (deja in tabelul S4b §3, pe randul retur) declanseaza
exact acest gest — nu un cursor_retur_document suplimentar si nu un APPEND FROM peste
crsarticole.
5.2 Cum se distinge o linie libera de una din factura sursa
Campul corect e crsfactura.id_c, nu o coloana pe crsarticole. O linie mostenita ajunge in
crsfactura prin do_adauga_articol, care face Select (lcCursor) / Scatter Name poArticol pe
randul ales din crsarticole (populat de cursor_retur_document, cu id_c = ROWNUM, pornind de la
- si copiaza acel
id_cin randul nou dincrsfactura. O linie libera, adaugata prinAPPEND BLANKdirect pecrsfactura(5.1), nu trece niciodata prin acestScatter—id_cramane la valoarea implicita a campului (N(20), faraNull, deci0,creeaza_facturacrs,COMUN\programe\ofacturare_comun.prg:1775-1785, citat si verificat de S4e §3 punctul 3). Oracle nu produce niciodataid_c = 0(ROWNUMincepe la 1) — decicrsfactura.id_c = 0e semnalul curat, fara camp nou, care distinge o linie libera de una mostenita. Acelasi tipar e deja in productie pentru linia de discount (ofacturare.vc2:14531-14537,Append Blankfaraid_csetat).
Consecinta directa, fara cod suplimentar: do_sterge, ramura de retur
(Case Inlist(poDate.tip,8,9,24) => Select crsarticole / Replace cantitate With cantitate - poArticol.cantitate For id_c = poArticol.id_c, ofacturare.vc2:14658-14659) cauta in crsarticole
un rand cu id_c = poArticol.id_c. Pentru o linie libera, poArticol.id_c = 0, iar crsarticole nu
are niciodata un rand cu acel id_c — REPLACE ... FOR devine no-op prin constructie. Stergerea
unei linii libere de pe un document de retur nu atinge maximul returnabil al nici unei linii
mostenite — exact ce cerea brief-ul la punctul 5, si exact acelasi mecanism (nu doar aceeasi idee) ca
solutia S4e pentru comanda.
5.3 Pretul de vanzare — riscul gasit (R1, ramane valabil)
Nu e doar despre gestiune/pret de achizitie, si nu se rezolva prin mutarea in crsfactura. Cand
o linie ajunge la do_alege_stoc cu Inlist(poDate.tip,8,9,24) adevarat (orice linie pe un document
de retur, indiferent de origine — conditia e pe poDate.tip, nu pe un flag de linie), se deschide
frm_articol_gest_factura. In acel formular, la schimbarea coloanei de gestiune
(grd_gestiuni.RowColChange), daca Thisform.lRetur e adevarat:
If Thisform.lRetur
poArticol.pretftva = pretv && pret DIN STOC, nu din lista de preturi
...
poArticol.cantitate = (-1) * cantitate
Endif
(ofacturare.vc2:4094-4103)
Pentru o linie mostenita (N.1), asta e corect prin constructie — returnezi marfa la pretul cu
care a fost vanduta. Pentru o linie libera (decizia 22 — articol niciodata vandut clientului, deci
fara "pret de retur" de mostenit), suprascrierea cu pretul de stoc e o eroare de pret: linia
libera ar iesi cu costul de stoc in loc de pretul din lista de preturi ales prin combosql la 5.1.
Solutie propusa, actualizata: frm_articol_gest_factura primeste un al doilea semnal, distinct de
tlRetur ("esti pe flux de retur"), care sa insemne "aceasta linie are factura sursa" — derivat acum
din crsfactura.id_c <> 0 (5.2), nu dintr-o coloana lipsa in crsarticole. Ramura de suprascriere
pret (:4094-4103) se activeaza doar cand acest al doilea semnal e adevarat.
5.4 Golul nou, nu tratat de S4e: punctul de intrare in dialogul de gestiune
S4e nu are acest gol pentru ca nu are dialog de gestiune pe comanda/avize — liniile libere de
acolo se completeaza integral prin combosql (pret, TVA, valuta) fara sa mai treaca prin niciun
dialog de alegere a gestiunii. Pe retur, decizia 22 cere explicit ca gestiunea si pretul de achizitie
sa se aleaga pentru o linie libera — mecanismul care stie sa faca asta e
cursor_gestiuni_articol_retur + frm_articol_gest_factura, dar acel dialog se intra azi doar
din do_alege_stoc, apelat de do_adauga_articol pe baza unui poArticol scatter-uit dintr-un rand
deja incarcat in crsarticole (ofacturare.vc2:12843-12851,12891). O linie libera adaugata prin
APPEND BLANK pe crsfactura (5.1) nu are un asemenea rand sursa — exact acelasi gol pe care
S4e l-a semnalat, netratat, pentru validarea de cantitate pe comanda (s4e_lista_preturi_pe_sursa.md
§6: "do_verifica_articol cere un poArticol scatter-uit dintr-un cursor sursa deja incarcat... o
linie libera... nu are un asemenea rand sursa").
Consecinta pentru S4f, mai stricta decat pe comanda: pe comanda/avize (S4e), lipsa unui poArticol
de sursa afecteaza doar validarea de cantitate (un gol de acoperit, dar linia se poate scrie si fara
gestiune aleasa — comanda/avize nu cer gestiune diferita de cea din lista de preturi). Pe retur, lipsa
aceluiasi poArticol blocheaza si alegerea gestiunii, care e obligatorie prin decizia 22. Trebuie
proiectat un punct de intrare nou in frm_articol_gest_factura/do_alege_stoc, care sa porneasca de
la randul deja inserat in crsfactura (dupa combosql, cu id_articol si cantitate deja
completate) in loc de la un rand din crsarticole — practic o a doua cale de apel, cu acelasi dialog
la capat, dar poArticol construit ad-hoc din crsfactura in loc de Scatter din crsarticole.
Aceeasi problema structurala, aceeasi solutie propusa (poArticol construit ad-hoc) ca varianta (b) de
la S4e §6 pentru do_verifica_articol — de unificat la implementare daca se poate, nu de rezolvat de
doua ori independent.
5.5 Maximul returnabil — nu se aplica, si acum e clar de ce
Confirmat structural: azi maximul returnabil pe N.1 nu e un calcul de "cat s-a mai returnat", e
pur si simplu CANTITATE a liniei originale (ff_...sql:4036, ofacturare.vc2:15236-15239,
do_verifica_articol:14743-14754) — validarea respinge doar semnul gresit (tnCantitate >= 0 in mod
retur), nu o depasire fata de un istoric. Pentru o linie libera, intrebarea nici nu se pune in
termenii de azi: do_verifica_articol, ca si dialogul de gestiune (5.4), asteapta un poArticol
din crsarticole — o linie libera nu are unul, deci nu poate trece prin comparatia de maxim existenta
nici macar din greseala. Validarea proprie a liniei libere (cantitate/stoc, construita ad-hoc, 5.4)
nu are nimic de comparat cu un "maxim returnabil" — verifica doar disponibilul de stoc curent, ca pe
o linie normala de lista de preturi (acelasi gol deschis de S4e §6 pentru comanda, aceeasi solutie).
6. Efectul asupra VANZARI_CORESP
Scrierea nu depinde de continutul liniilor, ci de alegerea facuta la antet.
scrie_corespondente_vanzari(3) (ff_...sql:14834-14836, apelata din finalizeaza_factura) scrie
direct din pack_facturare.clistaid (variabila de sesiune, = poDate.listaid trimis la
initializeaza_date_factura), independent de ce a ajuns efectiv in VANZARI_DETALII la
finalizare:
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,',')));
(ff_...sql:15481-15516, citat integral in legatura_linie_retur.md:45-53)
Consecinta directa pentru liniile libere: daca documentul de retur contine si linii libere (din
lista de preturi), corespondenta tot se scrie, si scrie exact aceleasi facturi alese la antet —
liniile libere nu adauga si nu scot randuri din VANZARI_CORESP, pentru ca sursa e poDate.listaid
(fixat la antet), nu continutul crsfactura/VANZARI_DETALII. Un document de retur cu 3 linii
mostenite din factura A si 2 linii libere scrie tot un singur rand in VANZARI_CORESP
(ID_VANZARE_FACT=documentul nou, ID_VANZARE_AVIZ=factura A, TIP=3) — corespondenta descrie
"acest document a folosit ca sursa factura A", nu "aceste linii vin din factura A".
Ce se scrie cand nu s-a ales nicio factura sursa: nu e un caz posibil pentru documentul de retur
insusi — validarea de antet (inainte_de_do_termin, descriere obligatoriu, sectiunea 3) impune cel
putin o factura aleasa inainte ca documentul sa poata continua. Deci pentru N.1/S4f (documente 8/9/24)
clistaid nu e niciodata gol la scriere. Pentru N.2 ridicat la document (punctul 2) raspunsul e
diferit: acolo documentul e de tip 1/5/7/10, iar poDate.listaid/campul nou echivalent (sectiunea 4)
nu e obligatoriu — un document normal fara nicio linie de retur nu are ce sa scrie. Intrebare
deschisa, verificata partial: daca scrie_corespondente_vanzari(3) e apelata azi doar cand
ntip in (8,9) (confirmat de legatura_linie_retur.md:113: "TIP=3: factura de retur
(scrie_corespondente_vanzari(3), :14834-14836, la ntip in (8,9))"), atunci ridicarea lui N.2 la
nivel de document NU va scrie automat VANZARI_CORESP — documentul ramane tip 1/5/7/10, gardat de
ntip, nu de continutul listaid. Linia exacta a acestui IF/CASE in exportul curent
(ff_2026_08_09_01...sql) nu a fost re-verificata caracter cu caracter in aceasta sesiune (citata
din raportul sursa, care a folosit un export anterior cu alta numerotare) — de reverificat la
implementare, dar concluzia structurala (gating pe ntip, nu pe listaid) e solida.
Decizie de proiectare care rezulta: ridicarea lui N.2 la nivel de document (punctul 2) nu
capata, prin simpla ridicare, o corespondenta persistata in VANZARI_CORESP — comportamentul
raman identic cu azi (nicio legatura scrisa), cu exceptia cazului in care Marius decide explicit ca
merita cod Oracle nou (extinderea gardei ntip in (8,9) la un al treilea semnal, ex. "are listaid
populat"). Decizia 35 (un singur cod de scriere contabila, cod Oracle nou doar cand strict necesar)
face ca varianta "fara schimbare in pack_facturare" sa fie implicita — de confirmat cu Marius
(risc R4), nu de presupus.
7. Semnul cantitatii / al valorii pe retur
Doua mecanisme diferite, verificate separat pe cod:
- N.1 (documente 8/9/24): cantitatea vine deja cu semnul corect direct din
cursor_retur_document—CANTITATEa liniei originale (pozitiva ca valoare de referinta, dar interpretata cu semn de retur prinpoDate.tip); semnul efectiv de scriere inVANZARI_DETALIIe controlat de codul Oracle care insereaza documentul de retur (nu urmarit aici, in afara perimetrului VFP), iar in UI validareado_verifica_articol(llRetur = Inlist(poDate.tip,8,9,24)) respingetnCantitate >= 0in mod retur — deci utilizatorul introduce cantitatea ca valoare pozitiva ("cat returnez"), iar semnul negativ e o conventie aplicata la nivel de tip de document, nu per linie. - N.2 (
But_retur): semnul negativ e aplicat explicit in cod VFP, infrm_articol_gest_factura—poArticol.cantitate = (-1) * cantitate(ofacturare.vc2:4103), declansat deThisform.lRetur(adevarat candtlRetura fost trimis laInit, indiferent depoDate.tip). Aici semnul nu vine dinpoDate.tip(documentul e tip 1/5/7/10, pozitiv prin design), ci e o negatie explicita facuta pentru ca acea linie anume e un retur intr-un document altfel normal.
Implicatie pentru liniile libere pe document de retur (S4f punctul 3): pentru ca documentul
intreg e tip 8/9/24, orice linie — libera sau mostenita — trece prin acelasi tratament de tip de
document (semnul negativ e o proprietate a documentului, nu a liniei, in acest caz). Nu exista
risc de "linie libera cu semn pozitiv gresit" atata timp cat validarea ramane gatata pe poDate.tip
si nu pe originea liniei — de verificat explicit ca ramura noua a validarii (5.4, sarirea peste
maximul returnabil) nu atinge si sare peste verificarea de semn, care trebuie sa ramana activa
identic pe linii libere si mostenite.
Implicatie pentru N.2 ridicat la document (punctul 2): aici semnul ramane o proprietate de
linie (nu de document, pentru ca documentul e tip normal 1/5/7/10) — mecanismul de la
ofacturare.vc2:4103 se pastreaza neschimbat, declansat de acelasi tlRetur/Thisform.lRetur,
indiferent daca alegerea facturii sursa se face per-articol (ca azi) sau la nivel de document
(punctul 2). Nimic de schimbat aici — doar de confirmat ca noul flux (alegere la document) tot
seteaza tlRetur=.T. la apelul catre do_alege_stoc/frm_articol_gest_factura pentru fiecare linie
de retur adaugata.
8. Unde se aseaza informatia de provenienta in UI
Inchis pe cod, cf. legatura_linie_retur.md: legatura linie-la-linie nu se poate afisa in niciun
caz — nici cursor_retur_document nu aduce ID_VANZARE/ID_VANZARE_DET in crsarticole
(ff_...sql:3965-4028, coloanele lipsesc din SELECT), nici INSERT-ul final in VANZARI_DETALII
nu are coloana de sursa (PACK_FACTURARE:13705-13757, listata explicit, fara camp de provenienta).
Ce se poate afisa, verificat: la nivel de document, cand exact o singura factura sursa a fost
aleasa, VANZARI_CORESP(TIP=3) da fara ambiguitate factura sursa:
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;
(legatura_linie_retur.md:174-178, interogare formulata, neverificata pe date live in acel raport)
Propunere concreta de text si conditie (in romana, pentru sectiunea pliata / antetul formularului unificat):
- O singura factura sursa aleasa: eticheta fixa de tip "Provine din factura: {serie} {numar}"
langa campul de descriere existent (
poDate.text_aditional, deja populat azi cu "RETUR FACTURA {numere}" —factura_retur_document.md:65), afisata read-only, imediat sub sau langa campul de tip document. - Mai multe facturi sursa alese: eticheta devine "Provine din facturile: {lista serie+numar}"
— aceeasi sursa de date (
poDate.descriere, deja populata cu lista, nu doarVANZARI_CORESP), fara sa se sugereze vreo distributie pe linii. - Niciodata pe linie — nici coloana in grid, nici tooltip per rand care sa pretinda o sursa exacta. Pentru liniile libere in particular, nu exista nimic de afisat (nu au sursa) — nu se introduce o valoare "N/A" vizibila care ar sugera ca alte linii AU o sursa unica atunci cand de fapt (cu selectie multipla) nici ele nu o au cu certitudine.
- Conditie tehnica: textul se construieste din
poDate.descriere(deja in memorie, fara interogare suplimentara) — nu necesita interogareaVANZARI_CORESPde mai sus decat daca se doreste reafisarea la redeschiderea unui document deja emis (regenerare, etapa II) — caz in care interogarea de mai sus e necesara pentru capoDate.descrierenu mai exista in memorie.
9. Pasi de implementare ordonati
- Confirmarea comportamentului aditiv/inlocuitor la alegerea facturilor sursa (sectiunea 3, punctul 3) — decizie de produs, nu cod. Gata cand: Marius a ales (a) sau (b); fara asta pasii 2-3 nu se pot implementa fara risc de refacere. Verificabil: niciunul (decizie, nu cod).
- Butonul/actiunea de alegere a facturilor sursa, mutat in sectiunea pliata a formularului
unificat, pastrand
do_cauta_facturi/caut_facturi_multiple_clientneschimbate — doar punctul de declansare se muta din antetul modal in sectiunea pliata a formularului unic, sicursor_retur_documentse declanseaza la confirmarea dialogului, nu la inchiderea unui formular separat (sectiunea 3, punctele 1-2). Gata cand: pe un document nou de tip 8/9/24, deschis in formularul unificat, alegerea facturilor sursa din sectiunea pliata populeazacrsarticolecu exact aceleasi randuri ca azi (gestiune, pret achizitie, pret vanzare identice), verificabil prin comparatie directa a cursorului. - Meniul "Adauga articole" pe tipurile 8/9/24, cu optiunile "Adauga tot din facturile alese" /
"Alege liniile de returnat…" peste
crsarticoledeja populat (reteta comuna S4b, sectiunile 4-5 ale acelui raport) — fara alegere de facturi in acest meniu (sectiunea 3). Gata cand: meniul contine exact aceste doua optiuni pe tip 8/9/24, plus "Cauta in lista de preturi…"/"Alege din nomenclator…" (punctul urmator). - Liniile libere —
APPEND BLANKpecrsfactura, semnalul de distinctie peid_c(sectiunile 5.1-5.2): optiunea de meniu "Cauta in lista de preturi…" pe tip 8/9/24 declanseazaSelect crsFactura / APPEND BLANK+combosql, exact tiparul S4e (ofacturare.vc2:17118-17122) — nuAPPEND FROMpestecrsarticole.id_cramane implicit (0) pe randul nou. Gata cand: dupa adaugarea unei linii libere pe un document de test,crsfactura.id_c = 0pe acel rand sicrsarticoleramane neschimbat (acelasiReccount/continut ca inainte de adaugare). - Punct de intrare nou in dialogul de gestiune, pornind de la randul din
crsfactura(sectiunea 5.4) —frm_articol_gest_factura/do_alege_stocprimesc o a doua cale de apel, cupoArticolconstruit ad-hoc din randul deja inserat incrsfactura(dupacombosql), nu dinScatterpe un rand dincrsarticole. Fara acest pas, o linie libera nu poate ajunge deloc la alegerea gestiunii ceruta de decizia 22. Gata cand: pe o linie libera adaugata pe un document de retur, dialogul de gestiune se deschide si returneazaID_GESTIUNE/PRET_ACHIZITIEalese de operator, fara sa fi trecut princrsarticole. - Fixarea pretului de vanzare pe liniile libere (sectiunea 5.3, riscul R1) — ramura de
suprascriere din
frm_articol_gest_factura(ofacturare.vc2:4094-4103) primeste al doilea semnal ("are sursa" vs. "e libera"), derivat dincrsfactura.id_c <> 0(pasul 4), si nu suprascriepretftvacand linia e libera. Gata cand: o linie libera adaugata pe un document de retur pastreaza pretul din lista de preturi dupa alegerea gestiunii, verificabil comparandpoArticol.pretftvainainte si dupaRowColChangein dialogul de gestiune. - Validarea de cantitate/stoc pe liniile libere (sectiunea 5.5) — mecanism nou, nu
do_verifica_articolca atare (care cere unpoArticoldincrsarticole); verifica disponibilul de stoc curent, fara nicio comparatie cu un maxim returnabil. Unificabil cu golul echivalent deschis de S4e §6 pentru comanda/avize, daca implementarea alege aceeasi varianta (poArticolconstruit ad-hoc, parametru explicit). Gata cand: pe o linie libera, orice cantitate <= stocul curent trece validarea, cu mesaj propriu (nu "cantitate maxima de returnat"); pe o linie mostenita, comportamentul de azi ramane neschimbat. - Ridicarea
But_returla nivel de document (punctul 2) — dialog de alegere multipla la deschiderea primei linii de retur pe un document normal (1/5/7/10), populare cu un camp nou sau reutilizarea controlata a luipoDate.listaid(sectiunea 4), pastrand calea per-articol existenta ca fallback sau eliminand-o explicit (decizie separata, risc R3). Gata cand: pe o factura normala, alegerea facturilor sursa se face o singura data, iar liniile de retur adaugate ulterior (mai multe articole) folosesc acel set fara sa redeschida dialogul de cautare la fiecare articol. VANZARI_CORESPpentru N.2 ridicat la document (sectiunea 6) — de decis daca se adauga cod Oracle nou sau ramane fara corespondenta persistata (risc R4); implementat doar dupa decizia lui Marius. Gata cand: comportamentul ales (cu sau fara corespondenta) e implementat consistent si testat pe un document cu retur ridicat la nivel de document si mai multe facturi sursa.- Textul de provenienta la antet (sectiunea 8) — afisare read-only din
poDate.descriere, condusa de numarul de facturi alese (0/1/multiple). Gata cand: eticheta arata corect in toate trei cazurile (nicio factura inca, o factura, mai multe), fara sa apara pe grid/linie.
Depinde de: S2 (formular unificat de baza), S4e (mecanismul APPEND BLANK + combosql pentru
liniile libere pe document cu sursa, NU APPEND FROM) — exact ca in plan (plan_13...md:2330),
corectat fata de reteta literala a deciziei 16.
10. Cum se verifica
Proba din plan (plan_13...md:2327-2329): "un document de retur deschis in formularul unificat
aduce liniile facturilor alese cu aceleasi valori ca azi — inclusiv gestiunea si pretul de
achizitie —, permite stergere si cantitate partiala, iar pe o factura normala se poate face retur
alegand facturile o singura data."
Pasi concreti:
- Paritate N.1: pe date de test, emite un document de retur (tip 8) pe calea veche (formularul
actual) si retine
crsarticolerezultat (gestiune, pret achizitie, pret vanzare, cantitate per linie). Repeta aceeasi alegere de facturi sursa in formularul unificat si comparacrsarticolecamp cu camp — trebuie sa fie identic, pentru ca sursa Oracle (cursor_retur_document) nu se schimba, doar punctul VFP care o declanseaza. - Stergere si retur partial: pe formularul unificat, sterge o linie mostenita si verifica ca
cantitatea reintra in
crsarticole(acelasi test ca azi,do_stergeneschimbat); introdu o cantitate mai mica decat maximul pe o linie mostenita si verifica validarea. - Linie libera: adauga o linie din lista de preturi pe documentul de retur deschis (prin
APPEND BLANK+combosql, nuAPPEND FROM); verifica (a)crsfactura.id_c = 0pe acel rand sicrsarticoleneschimbat; (b) pretul de vanzare = pretul din lista de preturi, nu din stoc; (c) gestiunea/pretul de achizitie sunt cerute prin dialogul de gestiune (intrat pe calea noua, 5.4), nu completate automat; (d) cantitatea nu e limitata de niciun maxim istoric, doar de stocul curent; (e) semnul cantitatii ramane negativ (consistent cu documentul); (f) stergerea liniei libere nu modificacrsarticole(verifica direct:Reccount/continut identic inainte si dupa stergere). VANZARI_CORESPneschimbat de liniile libere: dupa emiterea documentului din pasul 3, interogheaza:— trebuie sa arate exact facturile alese la antet, indiferent de cate linii libere s-au adaugat.SELECT ID_VANZARE_FACT, ID_VANZARE_AVIZ, TIP FROM VANZARI_CORESP WHERE ID_VANZARE_FACT = :id_document_nou AND TIP = 3;- N.2 ridicat la document: pe o factura normala, adauga doua linii de retur pentru articole
diferite folosind acelasi set de facturi sursa ales o singura data (nu redeschide dialogul la
fiecare articol); verifica semnul cantitatii (negativ) si absenta oricarei scrieri in
VANZARI_CORESP(daca decizia de la punctul 8/risc R4 pastreaza comportamentul de azi). - Provenienta: deschide un document de retur cu o singura factura sursa — verifica textul de antet; alege doua facturi sursa — verifica ca textul listeaza ambele si nu implica o sursa unica.
11. Ce nu se poate testa headless
Reluat din capcanele deja confirmate pe acest proiect (s4b_bara_butoane_meniu.md §8), plus
specificul retur:
cauta_alfacutnTipReturn=1— dialog modal (.Show(1)), blocheaza thread-ul UI; testarea automata a bifarii multiple nu se poate face prin injectare de input pe aceasta masina (partajata, memoriamasina-partajata-fara-input-real). Se verifica indirect: apeland directcaut_facturi_multiple_client/cursor_retur_documentcu parametri de test si citind cursorul rezultat, ocolind UI-ul.frm_articol_gest_factura— acelasi tip de dialog modal; verificarea suprascrierii de pret (risc R1, sectiunea 5.3) si a noului punct de intrare pornit dincrsfactura(sectiunea 5.4) se poate face doar citind codul metodeiRowColChange/noua metoda de intrare si, separat, apeland direct logica de calcul cu date de test simulate — nu prin click real in grid.- Coloanele griduri (
grd_articole, gridul dialogului de alegere) — capcana deja cunoscuta:ColumnCount=0sub-A -T; verificare vizuala necesita harness UI vizibil, nu headless. (memoriagrid-coloane-nu-se-materializeaza-headless) - Textul de provenienta din sectiunea pliata (sectiunea 8) — verificabil headless ca continut
al proprietatii (
Caption/Valuea controlului), nu ca "arata bine" vizual. - Secventa reala de deschidere a dialogului din sectiunea pliata (declansarea la click, nu doar codul din spatele ei) — necesita harness UI vizibil pentru captura de interactiune.
Ce se poate verifica headless, direct: continutul crsarticole/crsfactura dupa apeluri directe
ale rutinelor (cursor_retur_document, do_adauga_articol, do_verifica_articol, APPEND BLANK pe
crsfactura) cu parametri de test; valoarea crsfactura.id_c pe randurile noi (semnalul de la 5.2,
0 pe liniile libere, valoare reala pe cele mostenite); continutul real din
VANZARI_CORESP/VANZARI_DETALII dupa emiterea unui document de test pe schema Oracle (doar
SELECT, verificare post-factum).
12. Riscuri si ce ramane de decis de Marius
R1 — Pretul de vanzare pe liniile libere se suprascrie cu pretul de stoc, daca nu se trateaza
explicit (sectiunea 5.3). Cel mai concret risc gasit in aceasta cercetare, netratat in plan pana
acum. Recomandare: al doilea semnal ("linie cu sursa" vs. "linie libera") pe langa tlRetur,
derivat din crsfactura.id_c <> 0 (5.2), care sa dezactiveze suprascrierea de pret doar pentru
liniile libere. Necesita o mica modificare in frm_articol_gest_factura (nu in pack_facturare).
R7 — Punctul de intrare in dialogul de gestiune pentru o linie libera nu exista azi (sectiunea
5.4). Gol nou, mai strict decat echivalentul lui pe comanda/avize (S4e §6, doar validare de
cantitate) — pe retur blocheaza si alegerea gestiunii/pretului de achizitie, obligatorie prin decizia
22. do_alege_stoc/frm_articol_gest_factura se intra azi doar dintr-un poArticol scatter-uit din
crsarticole; o linie libera (APPEND BLANK pe crsfactura, 5.1) nu are asa ceva. Recomandare:
a doua cale de apel, cu poArticol construit ad-hoc din randul crsfactura deja completat prin
combosql, unificata daca se poate cu solutia aleasa pentru golul echivalent de validare (R7 aici,
S4e §6/varianta b acolo) — un singur mecanism de "construieste poArticol fara sursa in crsarticole",
nu doua independente.
R2 — Alegere aditiva sau inlocuitoare la a doua apasare a dialogului de facturi sursa (sectiunea
3, punctul 3). Nu e tratat de nicio decizie existenta. Recomandare: aditiv, consistent cu
filozofia deciziei 16, dar cere cod VFP nou (bucla de filtrare pe facturi noi + INSERT INTO crsarticole).
R3 — Ce se intampla cu caut_facturi_multiple_client_articol (alegerea per-articol) dupa ridicarea
lui But_retur la nivel de document. Ramane ca optiune secundara sau se elimina? Nefolosit oriunde
altundeva in cod (verificat implicit — apelul e doar din do_adauga_articol, ramura tlRetur).
Recomandare: se elimina, pentru ca pastrarea ambelor cai ar insemna doua UX-uri pentru aceeasi
actiune, exact riscul pe care unificarea vrea sa il elimine.
R4 — VANZARI_CORESP pentru N.2 ridicat la document. Gardat azi pe ntip in (8,9), nu pe
continutul listaid — reconfirmat independent in aceasta sesiune, pe exact acelasi export
(ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql:14834-14836): WHEN pack_facturare.ntip in (8, 9) THEN pack_facturare.scrie_corespondente_vanzari(3);, in interiorul unui CASE fara alta conditie pe
listaid. Daca ramane asa, un document normal
cu retur ridicat la document nu va avea nicio legatura persistata catre facturile sursa alese — exact
ca azi cu But_retur per-articol, deci nu e o regresie, dar nici un castig. Recomandare: se lasa
neschimbat (fara cod Oracle nou), consistent cu decizia 35 (economie de cod de intretinut) — de
confirmat explicit cu Marius, pentru ca punctul 2 al S4f ("ridicarea la nivel de document") ar putea
crea asteptarea implicita ca acum exista si o legatura persistata, cand de fapt nu exista.
R5 — Ct_clb_altele.cconditie — semantica exacta neconfirmata (sectiunea 2.1). Daca acest camp
chiar dezactiveaza azi re-alegerea dupa prima selectie, design-ul nou (sectiunea 3) trebuie sa decida
explicit sa elimine aceasta restrictie (pentru varianta aditiva) — altfel comportamentul nou ar
fi mai permisiv decat parea sa fie azi, fara sa fi fost o decizie constienta. De verificat la
implementare, cand clasa ct_clb_cautare devine accesibila (posibil in COMUNROA, in afara acestui
repo).
R6 — Semnul cantitatii pe liniile libere, verificare explicita ceruta de brief (sectiunea 7): nu e un risc nou — analiza arata ca semnul e o proprietate a documentului (tip 8/9/24), nu a liniei, deci liniile libere il mostenesc automat corect. Se listeaza aici doar ca sa fie explicit ca punctul a fost verificat, nu omis.
Handoff
Cercetare incheiata fara sa fie nevoie de predare de context — un subagent de verificare
(ab0be8e27f0fb97f3, Explore/general-purpose) a esuat de doua ori sa returneze rezultate, apoi a
raspuns complet la a treia incercare (reluat prin SendMessage), confirmand independent 4 puncte deja
scrise pe cod propriu in raport: (1) do_cauta_facturi e declansat explicit de user, prin
Ct_clb_altele/caut_ora.vc2:787-798,839-844 -> do_cauta_altele -> do_cauta_facturi
(ofacturare.vc2:8940-8961,9173), inainte de orice deschidere a frm_facturare_articole; (2)
scrie_corespondente_vanzari(3) e gardat exact pe ntip in (8,9)
(ff_...sql:14834-14836) — folosit sa inchid definitiv R4; (3)
thisform.cListaIdArticoleRetur poate acumula ID_VANZARE diferit per articol
(ofacturare.vc2:12882-12892); (4) poDate.listaid e acelasi camp la N.1 si N.2, dar cu rol
tranzitoriu la N.2 (salvat/restaurat) si definitiv doar la do_scrie_articole
(ofacturare.vc2:13977-13979). Niciuna din aceste confirmari nu a schimbat vreo concluzie a
raportului, doar le-a intarit sursa.
Corectie aplicata dupa livrare, la avertismentul team-lead (bazat pe
docs\cercetare\s4e_lista_preturi_pe_sursa.md, sectiunile 3 si 7): sectiunea 5 (liniile libere) a
fost rescrisa integral — reteta APPEND FROM peste crsarticole (premisa initiala a brief-ului)
e inlocuita cu mecanismul validat de S4e (APPEND BLANK pe crsfactura + combosql, niciodata pe
crsarticole), campul de distinctie devine crsfactura.id_c = 0 (nu absenta PRET_ACHIZITIE pe
crsarticole), si s-a adaugat un gol nou, negasit de S4e (care nu are dialog de gestiune pe
comanda/avize): punctul de intrare in frm_articol_gest_factura pentru o linie fara rand sursa in
crsarticole (risc R7, nou). Verdictul de la inceputul raportului, pasii de implementare (9),
verificarea (10) si sectiunile headless (11) au fost actualizate in consecinta. Restul raportului
(sectiunile 1-4, 6-8, 12 minus R1/R7) ramane neschimbat fata de livrarea initiala.
Fisierul SQL folosit: D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql
(cel mai recent din director). Nicio editare de cod, niciun git_sync.ps1/txt2vcx.ps1, niciun
commit, nicio scriere Oracle.