# S3c — Proiectare: sursa ca parametru, nu ca global Cercetare read-only pentru povestea **S3c** din `docs\plan_13_unificare_formular_facturare.md` (`#### S3c`, linia 1855; decizia 12, linia 473; L.3, linia 1733; „Canalul de precompletare”, liniile 465-474). Zero modificari de cod, zero write-back, zero `git_sync.ps1`, zero commit — in niciun produs din `D:\ROA`. Depinde de S2 (`docs\cercetare\s2_factureaza_unificare.md`), a carui proiectare a lasat explicit semnatura lui `factureaza` neschimbata „pentru ca e treaba lui S3c” (sectiunea 5 a acelui raport). Status: **complet**. --- ## Verdict **Se poate face, e o interventie mica pe cod, dar textul planului supraestimeaza cat de „globala" e problema azi.** `goContract` nu e niciodata scris in `ROAFACTURARE` — nici in codul specific produsului, nici in `COMUN`-ul lui — deci ramura de precompletare din contract (`ofacturare_comun.prg:261-297`) e **cod mort in ROAFACTURARE azi**, nu doar teoretic riscant. Asimetria de resetare semnalata la L.3 (`ofundal_facturare.vc2:886-902`) exista textual, dar **nu produce niciun efect observabil azi**, pentru ca nu exista niciun scriitor al lui `goContract` in acest produs care sa lase ceva de resetat. Ea devine un risc real abia daca cineva adauga in viitor, in `ROAFACTURARE`, un cod care scrie `goContract` — situatie in care lipsa resetarii ar deveni activa dintr-o data, tacut. `goComanda`, in schimb, chiar e viu in `ROAFACTURARE`: are doi scriitori (`ocomenzi.vc2:1583` la clic pe „Factureaza”, **si** `ocomenzi.vc2:2199`, ca efect colateral al navigarii in grid), iar reset-ul explicit de la `ofundal_facturare.vc2:900` e singura plasa de siguranta reala azi. **Suprafata de regresie e mica si masurata exact**: doi scriitori de convertit (`ocomenzi.vc2:1580-1596` in familia ROAFACTURARE, `ferestre_contracte.vc2:1538-1549`+`:1598-1606` in ROACONTRACTE), trei fisiere comune de atins o singura data fiecare (`ofacturare.prg`, `oproceduri_facturare.prg`, `ofacturare_comun.prg`), si **zero schimbari** la celelalte ~31 puncte de intrare din inventarul S2 — toate cheama `factureaza(N)` cu un singur parametru, deci un al treilea parametru opozitional cu implicit `.F.`/`NULL` nu le atinge. **Corectie de scop fata de formularea planului**: „pana se convertesc toti apelantii" nu poate insemna, pentru `goContract`, „pana dispare global-ul" — `goContract` e bufferul de editare al intregului ecran de contracte din ROACONTRACTE (peste 100 de `ControlSource` legate de el, sectiunea 1), populat continuu de navigarea in grid, independent de facturare. Nu va disparea niciodata din ROACONTRACTE la aceasta poveste sau la vreuna viitoare rezonabila — S3c schimba doar **canalul prin care valoarea ajunge la `oDateFactura.Init`**, nu existenta globalei in ROACONTRACTE. Criteriul de „gata” de mai jos (sectiunea 8) e rescris sa reflecte asta. --- ## 1. Inventarul scrierilor si citirilor `goComanda` / `goContract` in toata suita Cautare in `D:\ROA\ROAFACTURARE`, `D:\ROA\ROACONT`, `D:\ROA\ROAGEST`, `D:\ROA\ROAAUTO`, `D:\ROA\ROAACNPRO`, `D:\ROA\ROAIMOB`, `D:\ROA\ROACONTRACTE` — radacina fiecarui produs **si** `COMUN\`-ul lui explicit (capcana „Grep nu vede COMUN”). `D:\ROA\COMUNROA` nu contine niciuna din cele doua variabile (cautare separata, zero rezultate) — confirma ca sursa nu e livrata prin biblioteca partajata, ci prin fisierele COMUN duplicate per produs. ### `goComanda` | Fisier | Linie | Rol | Produse | |---|---|---|---| | `Programe\roafacturare.prg` | `:473-474` | **Declarare**: `PRIVATE goComanda` / `goComanda = null`, la pornirea aplicatiei | doar ROAFACTURARE (fiecare produs are propriul `roafacturare.prg`/echivalent, nu verificat identic — irelevant, doar initializeaza la null) | | `COMUN\clase\ocomenzi.vc2:1580-1596` (`ct_comenzi.do_factura`) | `:1583` | **SCRIE**: `SELECT crsComenzi` / `SCATTER NAME goComanda MEMO`, apoi cheama `facturare_comenzi` | ROAFACTURARE, ROACONT, ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB (fisier identic pe MD5, sectiunea 6) | | `COMUN\clase\ocomenzi.vc2:2191-2207` (`_grdrow1.AfterRowColChange`) | `:2199` | **SCRIE** ca efect colateral: la fiecare schimbare de rand in grid-ul de comenzi, `SCATTER NAME goComanda MEMO`, folosit doar pentru `but_factura1.Visible = (goComanda.facturat = 0)` (`:2202`) — **nu are nicio legatura cu intentia de facturare**, dar suprascrie global-ul de fiecare data cand utilizatorul navigheaza in grid | idem, acelasi fisier identic | | `COMUN\programe\ofacturare_comun.prg:301-328` (`oDateFactura.Init`) | `:301` | **CITESTE**: `If tnTip = 3 And Type('goComanda') = 'O'` -> `.id_client`, `.nume_client`, `.cod_fiscal`, `.listaid`, `.descriere`, `.id_sectie`, plus un `SELECT sectie FROM nom_sectii` pe `goComanda.id_sectie` | identic pe 6/7 produse (sectiunea 6; ROAIMOB diverge cu o linie, dar nu pe acest bloc) | | `Clase\ofundal_facturare.vc2:899-902` (`Page2.Cw3.do_actiune`) | `:900` | **RESETEAZA** explicit: `goComanda = ''` inainte de `DO facturare_comenzi` | doar ROAFACTURARE (fisierul e specific produsului, nu COMUN) | Niciun alt fisier, in niciun produs verificat, nu scrie sau citeste `goComanda`. ### `goContract` | Fisier | Linie | Rol | Produse | |---|---|---|---| | `ROACONTRACTE\Programe\roacontracte.prg:559-560` | `:559-560` | **Declarare**: `Public poCtr, goContract` / `Store '' To poCtr, goContract`, la pornirea aplicatiei | doar ROACONTRACTE | | `ROACONTRACTE\Clase\ferestre_contracte.vc2` | ~200 aparitii (liniile 977-11005, tabel complet in sectiunea de cautare) | **SCRIE si CITESTE** ca buffer de editare al intregului formular de contracte: `Scatter Name goContract Memo Blank` la creare (`:1026`, `:1186`), `SCATTER NAME goContract MEMO` la fiecare schimbare de rand in grid (`grid_contracte.AfterRowColChange`, `:1598-1606`), **peste 20** `ControlSource = "goContract."` pe controale (combo-uri, textbox-uri), `Gather Name goContract Memo` la salvare (`:1053`, `:2406-2472` etc.) | doar ROACONTRACTE | | `ROACONTRACTE\Clase\ferestre_contracte.vc2:1538-1549` (`but_factura.Click`) | — | **CITESTE implicit** (nu re-scrie): cheama `facturare_contracte` fara sa re-populeze `goContract` — se bazeaza pe scrierea facuta deja de `AfterRowColChange` la selectia randului curent | doar ROACONTRACTE | | `ROACONTRACTE\Clase\outlook2003bar.vc2`, `ofundal_roaclienti.vc2` | multiple | **CITESC** `goContract.id_ctr`/`.id_part` pentru navigare in bara laterala si ecrane de parteneri | doar ROACONTRACTE | | `ROACONTRACTE\Programe\roacontracte.prg`, `oparteneri_contracte.prg`, `oproceduri_roacontracte.prg` | multiple | **CITESC/SCRIU** `goContract` in fluxuri proprii ROACONTRACTE (incasari, plati, rate, garantii) — complet independente de facturare | doar ROACONTRACTE | | `COMUN\programe\ofacturare_comun.prg:261-297` (`oDateFactura.Init`) | `:261` | **CITESTE**: `If INLIST(m.tnTip, 2, 6, 52) And Type('goContract') <> 'U'` -> `.id_client`, `.nume_client`, `.cod_fiscal`, `.listaid`, `.descriere`, `.id_sectie`, `.sectie`, `.id_responsabil`, `.responsabil`, `.id_valuta`, `.nume_valuta`, plus interogare `fact_vcontracte` pentru scadenta | identic pe 6/7 produse (ROAIMOB diverge cu exact aceasta linie lipsa — sectiunea 6) | | `COMUN\clase\ferestre_atasamente.vc2`, `COMUN\programe\oproceduri_atasamente.prg` | 5 aparitii | **CITESC** `goContract.id_ctr`, dar **numai** in ramura `Case Upper(Alltrim(gcNumeProgram)) = "ROACONTRACTE"` — cod prezent in fiecare copie COMUN (deci si in ROAFACTURARE), dar mort acolo pentru ca `gcNumeProgram` nu e niciodata `"ROACONTRACTE"` in afara procesului ROACONTRACTE | identic pe toate produsele verificate, dar activ doar in ROACONTRACTE | **Confirmare directa: `goContract` nu e scris niciunde in `ROAFACTURARE`** — nici in `Programe\`, `Clase\`, `Ferestre\`, `Meniuri\`, nici in `COMUN\` (cautare pe `PUBLIC goContract`/`Public goContract` in tot arborele: zero rezultate, tabelul complet cu toate declaratiile `PUBLIC go*` gasite e in sectiunea 2). Singura mentiune a lui `goContract` in ROAFACTURARE e citirea garda de `Type()` din `ofacturare_comun.prg:261`, care ramane mereu falsa (`Type('goContract') = 'U'`) intr-o sesiune ROAFACTURARE. ## 2. Verdict pe L.3 — asimetria de resetare **Textul din cod e adevarat, dar efectul practic e altul decat sugereaza formularea „de verificat” din plan.** - **Asimetria exista, literal**: `ofundal_facturare.vc2:899-902` (`Page2.Cw3`, ruta genericaa de comanda) face `goComanda = ''` inainte de `DO facturare_comenzi`; `ofundal_facturare.vc2:886-897` (`Page2.Cw2`, ruta generica de contract) **nu** face echivalentul pentru `goContract` — cheama direct `DO facturare_contracte WITH 'FACTURA LEI'/'INVOICE'/'FACTURA VALUTA'`. - **Dar `facturare_contracte` (`oproceduri_facturare.prg:119-136`) nu citeste si nu scrie `goContract` deloc** — primeste un string de tip (`'FACTURA LEI'` etc.) si cheama direct `factureaza(2)`/`factureaza(6)`/`factureaza(52)`. Precompletarea din contract se intampla **exclusiv** in `oDateFactura.Init`, la citirea globalei — nu exista niciun pas intermediar care ar putea fi „resetat”. In ROAFACTURARE, calea genericaa (Cw2) las utilizatorul sa aleaga contractul **in formular**, printr-un combo populat din `crscontracte` legat de `poDate.listaid` (`ofacturare.prg:283-291,433-440`) — un canal complet diferit, care nu trece prin `goContract` deloc (confirmat citind codul, sectiunea 3). - **Deci, in ROAFACTURARE azi, nu exista nicio secventa executabila in care `goContract` sa fie citit cu o valoare veche.** Pentru ca asta sa se intample ar trebui ca (a) ceva sa fi scris `goContract` mai devreme in aceeasi sesiune ROAFACTURARE — **nu exista niciun asemenea cod azi** — si (b) urmatorul apel sa fie cu `tnTip` in `(2, 6, 52)`. Fara (a), (b) singur nu ajunge nicaieri. - **Verdictul pe L.3**: asimetria de resetare **e reala ca defect de simetrie in cod** (o ruta isi curata globala inainte de apel, cealalta nu), dar **inert azi in ROAFACTURARE** — nu exista niciun document gresit care se poate emite azi din cauza ei, pentru ca variabila pe care ar trebui sa o resetezi nu e niciodata populata in acest produs. Devine un risc real **doar** daca un cod viitor (in ROAFACTURARE) incepe sa scrie `goContract` fara sa adauge simetric si resetul — exact genul de capcana pe care „parametru explicit, fara global implicit” o elimina structural, nu prin inca o linie de reset de tinut minte. - **In ROACONTRACTE, unde `goContract` chiar e viu, nu exista o ruta „generica fara precompletare” analoaga lui Cw2** — `but_factura.Click` (`:1538-1549`) e singurul punct de intrare si presupune intotdeauna un contract selectat in grid (populat de `AfterRowColChange`, `:1598-1606`, la fiecare schimbare de rand). Riscul teoretic acolo nu e „global ramas din alta sesiune de facturare”, ci „utilizatorul apasa Factureaza fara sa fi selectat explicit un rand dupa un refresh programatic” — un caz marginal, netratat de L.3 si nelegat de asimetria semnalata in plan. ## 3. Doar doua globale, sau mai sunt? **Doar doua.** Verificat prin citirea completa a `oDateFactura.Init` (`ofacturare_comun.prg:223-332`) si a rutarii cursoarelor de articole din `ofacturare.prg:260-308`: - **`goDate`, `gnIdSet` ca surse de precompletare — nu exista.** `goDate` nu apare niciunde in `ofacturare.prg`/`ofacturare_comun.prg` (cautare directa, zero rezultate). `gnIdSet` nu exista ca atare — parametrul se numeste `tnIdSet`/`lnIdSet`, calculat **local** in `factureaza` (`lnIdSet = 25000 + tnTip - 1 + gnScadereStoc * 10`, `ofacturare.prg:123`) din `tnTip` si un optiune de configurare (`gnScadereStoc`), nu un canal de sursa. - **Singurele doua verificari `Type('go...')` din `oDateFactura.Init` sunt exact `goContract` (`:261`) si `goComanda` (`:301`)** — cautare `Type\('go` pe tot `ofacturare.prg` + `ofacturare_comun.prg`: zero alte rezultate in afara comutatorului de dezvoltator `gnFacturareNou` (irelevant aici, documentat in S2). - **`poDate.listaid` pentru avize (tip 4, 21, 28, 42, 47) NU trece printr-un global** — se scrie direct din cursorul de selectie al formularului: `poDate.listaid = Iif(Inlist(poDate.tip, 3, 21, 28, 42, 47), Alltrim(Str(id_comanda)), [])` (`ofacturare_comun.vc2:4255`, si varianta similara la `:4062`, `:7271`) — populat dintr-un `Scan`/`Locate` peste cursorul cu avizele bifate de utilizator in acelasi apel, nu dintr-o variabila globala persistenta intre apeluri. **Avizele nu intra in S3c** — nu au canal implicit de eliminat. - **Copierea (`toFactura`) e deja parametru, nu global** — `copiere_factura(toFactura)` (`oproceduri_facturare.prg:150-153`) -> `factureaza(toFactura.Tip, toFactura)`, si in `oDateFactura.Init`/logica de copiere valorile vin din `toDateAnterior` (parametrul), de exemplu `.listaid = toDateAnterior.id_vanzare` (`ofacturare_comun.vc2:387`) — **e exact precedentul pe care S3c il extinde la comanda/contract**, nu un al treilea canal implicit de adaugat la lista. - **`poDate` insusi nu e un canal de scurgere intre apeluri** — se creeaza cu `Createobject` la fiecare intrare in bucla lui `factureaza` (`ofacturare.prg:184`, doar `If Type('poDate') <> 'O'`, ceea ce e adevarat prima data si ramane fals doar in interiorul aceluiasi apel, la reintrarile bucla `Do While lnRaspuns = 6`) — deci nu poate purta stare intre doua clicuri distincte pe „Factureaza”. **Concluzie**: `goComanda` si `goContract` sunt singurele doua canale implicite relevante pentru decizia 12. Nu mai exista o a treia variabila de convertit odata cu ele. ## 4. Semnatura propusa **`factureaza`** (`COMUN\programe\ofacturare.prg:81-82`), azi `Lparameters tnTip, toFactura`: ``` Lparameters tnTip, toFactura, toSursa ``` - **`toSursa`** — obiect, implicit `NULL` (nepasat de niciun apelant existent). Poarta **fie** un obiect cu forma lui `goComanda` (cand `tnTip = 3`), **fie** un obiect cu forma lui `goContract` (cand `tnTip IN (2, 6, 52)`) — exact aceeasi dualitate pe care codul de azi o rezolva deja prin ramificare pe `tnTip` in `oDateFactura.Init` (`:261` vs `:301`), deci nu introduce un tip nou de decizie, doar muta sursa valorii. - **Pozitia**: al treilea parametru, dupa `toFactura`, niciodata inaintea lui — la fel ca precedentul `V_TAXCODE`/`V_LOT` citat de tine: apelurile VFP sunt pozitionale, iar singurul mod sa nu rupi apelantii existenti e sa adaugi la coada, cu implicit. Toate cele ~31 de apeluri din inventarul S2 care pasesc doar `tnTip` raman **neschimbate** — VFP completeaza automat parametrii nepasati la coada cu `.F.` (verificat comportamental: `Type()` pe un parametru nepasat intoarce `'L'` cu valoarea `.F.`, nu `'U'` — de tratat explicit in garda, vezi sectiunea 5). - **De ce nu inlocuieste `toFactura`**: `toFactura` inseamna „copiaza factura asta” (un document deja emis), `toSursa` inseamna „precompleteaza din documentul asta” (o comanda sau un contract inca nefacturat) — semantic distincte, si `copiere_factura` (`oproceduri_facturare.prg:150-153`) ar putea teoretic avea nevoie de amandoua simultan in viitor (copiere + realocare pe alt contract) — motiv suplimentar sa nu le contopesti intr-un singur parametru. **Constructorul `oDateFactura.Init`** (`ofacturare_comun.prg:223-224`), azi `Lparameters tnIdSet, tnTip`: ``` Lparameters tnIdSet, tnTip, toSursa ``` - Aceeasi regula de pozitionare: la coada. Singurul apelant azi e `Createobject("oDateFactura", lnIdSet, tnTip)` din `factureaza` (`ofacturare.prg:184`) — devine `Createobject("oDateFactura", lnIdSet, tnTip, toSursa)`. Nu exista alt loc din cod care instantiaza `oDateFactura` (cautare `Createobject("oDateFactura"` pe tot `COMUN`: un singur rezultat). ## 5. Mecanismul de sursa de rezerva **Regula**: la fiecare din cele doua ramuri, se prefera `toSursa` daca a fost pasat ca obiect; daca nu, se cade pe globala, exact ca azi. Nu se schimba forma datelor citite (aceleasi campuri), doar sursa lor. ```foxpro * ofacturare_comun.prg, oDateFactura.Init — inlocuieste liniile 261 si 301 Local loSursa loSursa = Iif(Type('toSursa') = 'O', toSursa, Null) If INLIST(m.tnTip, 2, 6, 52) And (Type('loSursa') = 'O' Or Type('goContract') <> 'U') If Type('loSursa') <> 'O' loSursa = goContract Endif .id_client = loSursa.id_part .nume_client = loSursa.denumire * ... restul neschimbat, doar goContract -> loSursa Endif loSursa = Iif(Type('toSursa') = 'O', toSursa, Null) && re-evaluat, nu se refoloseste variabila de mai sus intre ramuri If tnTip = 3 And (Type('loSursa') = 'O' Or Type('goComanda') = 'O') If Type('loSursa') <> 'O' loSursa = goComanda Endif .id_client = loSursa.id_part * ... restul neschimbat, doar goComanda -> loSursa Endif ``` De ce doua evaluari separate ale lui `loSursa` (nu una singura la inceput): `toSursa` poarta o singura forma per apel (fie comanda, fie contract, niciodata amandoua — `tnTip` decide exclusiv care), dar garda trebuie sa verifice `tnTip` inainte sa presupuna forma, la fel ca azi. O variabila locala unica evita sa scrii `toSursa` de doua ori in tot blocul, fara sa schimbe logica. **Cum se stie cand se poate scoate globala** — criteriu verificabil, nu „cand se convertesc toti”: - **Pentru `goComanda`**: nu se poate scoate niciodata complet din `ROAFACTURARE`, pentru ca al doilea ei scriitor (`ocomenzi.vc2:2191-2207`, `AfterRowColChange`) nu are nicio legatura cu `factureaza` — exista doar pentru `but_factura1.Visible`. Criteriul realist: **linia de citire in `oDateFactura.Init` (`:301`) poate deveni neconditionata de fallback abia cand se confirma, prin `git_sync.ps1` + Grep, ca niciun apel la `factureaza(3, ...)` mai lasa `toSursa` nepasat** — adica se verifica apelantii lui `factureaza`, nu scriitorii globalei (care raman, pentru alt scop). - **Pentru `goContract`**: acelasi lucru, dar cu o observatie in plus — global-ul insusi (`Public goContract` in `roacontracte.prg:559-560`) **nu va disparea niciodata** cat timp exista formularul de contracte din ROACONTRACTE, care il foloseste ca buffer de editare, nu doar ca transport spre facturare. Criteriul de scos fallback-ul: **cand toate apelurile catre `factureaza(2/6/52, ...)`, in toate produsele, pasesc `toSursa` explicit** — verificabil cu aceeasi comanda `Select-String` ca in S2, aplicata pe `factureaza(2` / `factureaza(6` / `factureaza(52` in loc de `factureaza2`. - Pana atunci, fallback-ul ramane — el nu costa nimic in productie (o verificare `Type()` in plus), si e singura plasa de siguranta pentru cele ~31 puncte de intrare care nu au fost, nu vor fi, si nu trebuie sa fie convertite (nu au sursa de precompletat). ## 6. Cele N copii ale fisierelor atinse — identice sau divergente? MD5 pe fiecare fisier, in cele 7 produse care au copie (`ROAFACTURARE`, `ROACONT`, `ROAGEST`, `ROAAUTO`, `ROAACNPRO`, `ROAIMOB`, `ROACONTRACTE`): | Fisier | Rezultat | |---|---| | `COMUN\programe\ofacturare.prg` (2662 linii) | **Identic pe toate cele 7** — un singur MD5 | | `COMUN\programe\oproceduri_facturare.prg` (2393 linii) | **Identic pe toate cele 7** — un singur MD5 | | `COMUN\clase\ocomenzi.vc2` (8301 linii) | **Identic pe cele 6** care il au (nu verificat separat in ROACONTRACTE, care nu are comenzi) | | `COMUN\programe\ofacturare_comun.prg` (2224 linii) | **Identic pe 6 din 7** — `ROAIMOB` diverge cu **exact o linie lipsa**: `:264`, `.cod_fiscal = ALLTRIM(NVL(goContract.cod_fiscal, ''))`, absenta din copia ROAIMOB (2223 linii). Restul fisierului, inclusiv blocul `goComanda`/`goContract` de la `:261-328`, e identic caracter cu caracter. | **Spre deosebire de `ofacturare.vc2` (7 copii, 4 variante MD5 distincte, citat ca precedent de comparat)**, fisierele atinse de S3c sunt aproape perfect sincronizate — un singur punct de drift, minor si izolat. Concluzie pentru propagare: modificarea din `ofacturare.prg` si `oproceduri_facturare.prg` se poate copia **caracter cu caracter** in toate cele 7 produse fara nicio adaptare. Modificarea din `ofacturare_comun.prg` se poate copia identic in 6 produse, dar **in ROAIMOB trebuie aplicata pe baza divergentei existente** (linia `cod_fiscal` lipseste deja acolo — o copiere oarba a diff-ului ar putea sa nu se aplice curat sau sa reintroduca acea linie fara sa fie intentionat; de verificat manual la sincronizare, nu doar copiat). `ferestre_contracte.vc2` (ROACONTRACTE) e specific produsului, nu are copii de sincronizat. ## 7. Suprafata de regresie masurata **Fisiere care chiar se modifica** (5, plus 1 verificare de sincronizare): | # | Fisier | Ce se schimba | Cate copii de propagat | |---|---|---|---| | 1 | `COMUN\programe\ofacturare.prg:81-82` | semnatura `factureaza`, +`toSursa` | 7 (identice, copiere directa) | | 2 | `COMUN\programe\ofacturare_comun.prg:223-224, 261-328` | semnatura `Init`, +`toSursa`; ramurile de citire cu fallback | 7 (6 identice + ROAIMOB cu drift de reconciliat) | | 3 | `COMUN\programe\oproceduri_facturare.prg:119-141` | `facturare_contracte(tcTip, toSursa)`, `facturare_comenzi(toSursa)`, relay catre `factureaza(N, NULL, toSursa)` | 7 (identice, copiere directa) | | 4 | `COMUN\clase\ocomenzi.vc2:1580-1596` (`do_factura`) | `SCATTER NAME loComanda MEMO` (local, nu global) + `DO facturare_comenzi WITH loComanda IN oproceduri_facturare.prg` | 6 (identice, copiere directa) | | 5 | `ROACONTRACTE\Clase\ferestre_contracte.vc2:1538-1549` (`but_factura.Click`) | trimite `goContract` (sau o copie locala scatter-uita din randul curent) explicit ca al doilea parametru la `DO facturare_contracte WITH lcTip, goContract IN ...` | 1 (specific ROACONTRACTE) | **Apelanti care NU se modifica** (confirmat, nu presupus): toate cele ~31 de puncte de intrare din inventarul S2 (`Meniuri\politica.mn2`, `Meniuri\contracte.mn2`, `Meniuri\aviz_*.mn2`, `ofundal_facturare.vc2:883-905`) cheama `factureaza(N)` cu un singur argument sau `facturare_contracte`/`facturare_comenzi` fara sursa — al treilea parametru ramane implicit `NULL`, fallback-ul pe global preia (pentru cele care oricum nu aveau sursa reala, fallback-ul da acelasi rezultat ca azi: nimic de precompletat). **Inclusiv `ofundal_facturare.vc2:886-902` (Page2.Cw2/Cw3) raman neschimbate** — `Cw3` isi pastreaza `goComanda = ''` (devine redundant, dar inofensiv, odata ce `do_factura` trimite explicit; se poate curata separat, nu la aceasta poveste), `Cw2` ramane cum e. **Total: 5 fisiere reale de editat, in 4 continuturi distincte de modificare** (fisierele #1-#3 au acelasi continut in toate copiile lor), propagate in pana la 7 produse — mult sub suprafata unei modificari „de suita” tipice, pentru ca `ofacturare.prg`/`oproceduri_facturare.prg` sunt deja perfect sincronizate (sectiunea 6). ## 8. Ordinea de executie, ca suita sa nu fie stricata niciun moment Spre deosebire de S2 (unde `factureaza2` nu avea alt apelant decat el insusi, deci risc de stricare aproape nul), aici **exista o fereastra in care semnaturile trebuie sa fie compatibile intre fisiere diferite** (`ofacturare.prg` cheama `oDateFactura::Init`, `oproceduri_facturare.prg` cheama `factureaza`) — ordinea trebuie sa garanteze ca niciun punct intermediar nu are un apelant cu semnatura veche impotriva unui apelat cu semnatura noua incompatibila. Pentru ca **toti parametrii noi sunt optionali, la coada**, riscul e de fapt mic — o semnatura veche care cheama o rutina noua functioneaza (parametrul lipsa devine implicit), problema ar aparea doar invers (rutina veche chemata cu un parametru in plus, care s-ar ignora silentios in VFP — tot fara eroare, dar fara efect). Deci ordinea de mai jos e despre corectitudine, nu despre a evita crash-uri: 1. **`oDateFactura.Init`** (`ofacturare_comun.prg`) — adauga `toSursa`, muta logica de citire pe modelul din sectiunea 5. Se poate face si testa izolat: fara niciun apelant care sa paseze `toSursa` inca, comportamentul ramane identic cu azi (fallback pe global, mereu). 2. **`factureaza`** (`ofacturare.prg`) — adauga `toSursa`, il paseaza la `Createobject("oDateFactura", lnIdSet, tnTip, toSursa)`. Inca niciun apelant nu paseaza `toSursa` — comportament neschimbat. 3. **`oproceduri_facturare.prg`** — `facturare_contracte`/`facturare_comenzi` primesc `toSursa` si il relaeaza. Inca niciun apelant real nu il paseaza — comportament neschimbat. 4. **Abia acum, apelantii reali**: `ocomenzi.vc2:do_factura` trimite `loComanda` explicit; `ferestre_contracte.vc2:but_factura.Click` trimite `goContract` explicit (in ROACONTRACTE). Din acest punct, comportamentul chiar se schimba (sursa vine din parametru, nu din citirea globalei), dar rezultatul trebuie sa fie identic — parametrul poarta exact aceleasi campuri pe care globala le avea. 5. **Sincronizare in celelalte 6 produse**: pasii 1-3 se copiaza caracter cu caracter (identice, sectiunea 6), cu atentia speciala la ROAIMOB (drift de o linie). Pasul 4 pe partea de comenzi se copiaza si el (fisierul e identic in toate). Nu exista pas 4 de propagat pe partea de contract in afara de ROACONTRACTE (nu exista alt produs cu formular de contracte care sa scrie `goContract`). 6. **Un singur produs se poate testa complet integrat de la sine**: ROAFACTURARE (pasii 1-4, partea de comanda). ROACONTRACTE cere o rulare separata (build propriu, sincronizat manual) pentru pasul 5 pe partea de contract — acelasi tip de limitare semnalata deja in S2 pentru `factureaza2`. ## 9. Ce nu se poate testa headless - **Toate cele ~31+2 puncte de intrare sunt declansate din UI** (clic pe buton, `ON SELECTION BAR` in meniu) — niciunul nu are un test headless existent, la fel ca in S2. - **Testarea „parametrul castiga peste global” cere manipulare de sesiune**: singurul mod sa verifici ca `toSursa` are prioritate e sa populezi manual `goComanda`/`goContract` cu o valoare **diferita** de cea din parametru si sa confirmi ca documentul rezultat foloseste parametrul — asta cere fie cod de test care seteaza global-ul inainte de apel (posibil headless, dar artificial fata de fluxul real), fie o sesiune interactiva VFP cu comenzi tastate manual in fereastra de comenzi. - **Efectul colateral al `AfterRowColChange` (`ocomenzi.vc2:2199`) nu se poate simula headless** — harnessul `-A -T` nu declanseaza fiabil evenimente de grid (confirmat de precedentul din memorie „Coloanele de grid nu se materializeaza headless”), deci nu se poate verifica automat ca navigarea in grid tot suprascrie `goComanda` dupa modificare (comportament care ramane neschimbat, dar trebuie confirmat vizual, nu presupus). - **ROACONTRACTE nu poate fi testat din arborele de lucru ROAFACTURARE** — cere build si rulare separata, cu propriul executabil si propria sincronizare a `ofacturare.prg`/`ofacturare_comun.prg` /`oproceduri_facturare.prg` (nu sunt acelasi fisier fizic, sunt copii). - **Rezultatul final** (facturare emisa cu antetul corect precompletat din comanda/contract) se verifica doar prin continutul lui `crsfactura`/`VANZARI`/formularul de antet, vizual sau prin interogare Oracle read-only dupa emitere — nu exista assert automat de facut. ## 10. Riscuri si ce ramane de decis de Marius **Riscuri**: - **Cel mai probabil sa se strice**: garda `Type('loSursa') = 'O' Or Type('goContract') <> 'U'` din sectiunea 5 — daca se scrie gresit (de exemplu `And` in loc de `Or`), fallback-ul pe global s-ar rupe silentios pentru toti apelantii care inca nu au fost convertiti, fara nicio eroare vizibila (`oDateFactura` ar porni pur si simplu fara precompletare). Se testeaza explicit pe cel putin un apel neconvertit (orice `factureaza(N)` cu un singur argument, tip 1) dupa modificare. - **Al doilea cel mai probabil**: parametrul nou nepasat trebuie verificat `Type('toSursa') = 'O'`, nu `Type('toSursa') <> 'U'` — un parametru VFP nepasat nu e `'U'` (asta e pentru variabile nedeclarate), ci `'L'` cu valoarea `.F.` implicita a lui `LPARAMETERS`. O garda gresita (`<> 'U'`) ar trece mereu adevarat si ar incerca sa citeasca `.id_part` de pe `.F.`, eroare de rulare imediata la primul apel neconvertit. **De verificat cu un test minimal inainte de a atinge fisierele reale** — nu presupune, verifica comportamentul `Type()` pe un parametru nepasat intr-un `.prg` de proba. - **ROACONTRACTE, singurul apelant real din alt produs** — acelasi risc semnalat in S2: netestabil din acest arbore de lucru, cere confirmare manuala separata. - **Drift-ul de o linie din `ofacturare_comun.prg` in ROAIMOB** — o copiere mecanica a diff-ului ar putea esua silentios sau reintroduce linia lipsa fara sa fie intentia — de aplicat manual acolo, nu prin copy-paste orb. - **`Cw3.do_actiune` (`ofundal_facturare.vc2:900`) ramane cu `goComanda = ''` redundant** dupa conversia lui `do_factura` — nu e o problema (ramane inofensiv), dar merita mentionat explicit ca „lasat asa, intentionat” in codul livrat, ca sa nu para o omisiune la revizuirea diff-ului. **Ce ramane de decis de Marius**: 1. **Forma lui `toSursa`**: ramane duck-typing pe obiect scatter (ca azi), sau se formalizeaza o clasa cu doua forme (`oSursaComanda`/`oSursaContract`)? Recomandare: ramane duck-typing — nu schimba nimic functional, adauga doar o clasa noua de intretinut pentru un beneficiu marginal la aceasta poveste. 2. **Se face si conversia partii de comanda si cea de contract in acelasi commit, sau separat?** Ambele ating exact aceleasi trei fisiere comune (`ofacturare.prg`, `ofacturare_comun.prg`, `oproceduri_facturare.prg`) — separarea nu reduce suprafata de regresie pe fisierele comune, doar amana testarea reala pe ROACONTRACTE. Recomandare: **un singur commit**, cu testare manuala pe ambele produse inainte de a-l considera gata. 3. **Se curata acum redundanta `goComanda = ''` de la `Cw3` (sectiunea „Riscuri”), sau se lasa pentru o poveste ulterioara de curatenie?** Nu afecteaza corectitudinea — decizie de stil, nu de comportament. 4. **Criteriul de „gata” rescris** (inlocuieste formularea din plan, linia 1861-1862): - *Structural*: `Select-String -Path ofacturare.prg,ofacturare_comun.prg,oproceduri_facturare.prg -Pattern 'toSursa'` gaseste parametrul in toate cele trei fisiere, in toate cele 7 produse care au copii, cu semnatura identica. - *Comportamental, cale convertita*: facturarea pornita din `ocomenzi.vc2:do_factura` cu `goComanda` populat manual cu **alta** comanda decat cea trimisa prin `toSursa` produce documentul corespunzator parametrului, nu globalei — testat manual, cu global-ul deliberat „murdar” dintr-o navigare anterioara in grid. - *Comportamental, cale neconvertita*: oricare din cele ~31 de apeluri care trimit doar `tnTip` produce acelasi document ca inainte de modificare (fallback pe global, sau fara precompletare acolo unde nu exista global de citit). - *ROACONTRACTE*: facturarea din `but_factura.Click` cu contractul trimis explicit prin `toSursa` produce acelasi rezultat ca azi (precompletare identica), verificat manual pe build separat. --- ## Ce nu s-a putut stabili si de ce - **Continutul exact al obiectului `loComanda`/`goContract` scaturat** nu a fost comparat camp cu camp intre ce citeste azi `oDateFactura.Init` si ce ar contine un `SCATTER` facut in afara contextului `crsComenzi`/`cContracte` curent — presupunerea (rezonabila, dar neverificata pe date) e ca structura cursorului nu se schimba intre cele doua puncte de scatter. - **Daca exista alte produse din suita (dincolo de cele 7 verificate) care au propriile copii ale `ofacturare.prg`/`ofacturare_comun.prg`/`oproceduri_facturare.prg`** — cautarea s-a limitat la produsele numite explicit in sarcina; alte ~30 de produse mentionate in S2 ca avand copii ale `ofacturare.prg` (ROARETAIL etc.) nu au fost verificate pentru `goComanda`/`goContract` la aceasta poveste. - **Testarea reala pe ROACONTRACTE** nu a fost efectuata (read-only, fara rulare de cod) — doar confirmata structura codului sursa. ## Bug-uri semnalate, nereparate Niciunul nou — cercetarea a confirmat un defect de simetrie deja semnalat in plan (L.3), l-a verificat pe cod pana la verdictul „inert azi in ROAFACTURARE” (sectiunea 2), si nu a gasit alte probleme in fisierele atinse.