# S2 — Proiectare: o singura procedura `factureaza` Cercetare read-only pentru povestea **S2** din `docs\plan_13_unificare_formular_facturare.md`. Niciun fisier de cod atins, `git_sync.ps1` nerulat, niciun write-back, niciun commit. ## Verdict **Se poate unifica, si e mai simplu decat pare.** `factureaza2` nu e o a doua implementare funcţională care trebuie fuzionata cu grija — e un fork din 08.06.2017 la care s-a **dezactivat execuţia interogarii de articole** (`lnSucces = 1` hardcodat, `goExecutor.oExecute` niciodata apelat) si mai multe blocuri intregi sunt inchise cu `If .F.`. Are **exact un singur apelant** in tot codul (`ofacturare.prg:90`, din interiorul lui `factureaza` insusi, in spatele unui `AMESSAGEBOX` de confirmare) si **zero utilizatori reali** dincolo de acel switch de test. Riscul de regresie e mic pentru ca nu exista nimic funcţional de pierdut in `factureaza2` — obstacolul principal nu e tehnic, e ca formularul spre care duce (`frm_facturare_articole2`) e tot un prototip neterminat (`Init` de 92 de linii, nu completeaza antetul), deci unificarea proceduri lor **nu** face formularul nou utilizabil — doar elimina duplicarea de cod. Asta ramane treaba lui S3. --- ## 1. Inventarul celor doua proceduri Ambele sunt proceduri globale (nu metode de clasa) in **`COMUN\programe\ofacturare.prg`**, incarcat via `SET PROCEDURE ... ADDITIVE` din `Programe\roafacturare.prg`. Nu exista omonime — verificat cu `Get-ChildItem -Recurse *.prg | Select-String '^\s*(PROCEDURE|FUNCTION)\s+factureaza2?\b'` pe tot `ROAFACTURARE` si cu Grep pe `.vc2` din `COMUN`: un singur rezultat pentru fiecare nume. | | `factureaza` | `factureaza2` | |---|---|---| | Locatie | `COMUN\programe\ofacturare.prg:81-577` (497 linii) | `COMUN\programe\ofacturare.prg:583-1081` (499 linii) | | Parametri | `LPARAMETERS tnTip, toFactura` (`:82`) — `toFactura` = obiect, pentru copiere/modificare | `LPARAMETERS tnTip` (`:584`) — **fara** al doilea parametru | | Apelanti | ~20+ puncte de intrare reale (sectiunea 3) | **unul singur**: `ofacturare.prg:90`, din `factureaza` | `ofacturare.prg` in sine e cod comun al **intregii suite**: exista o copie identica-la-origine in `COMUN\programe\ofacturare.prg` a fiecarui produs ROA verificat (ROACONT, ROAGEST, ROACONTRACTE, ROAAUTO, ROAACNPRO, ROAIMOB, plus alte ~30 produse) — fiecare cu propriile `factureaza`/`factureaza2` la linii apropiate (de regula `:76-77` sau `:87-88` pentru comutatorul `gnFacturareNou`, dupa versiune). Nu exista in `COMUNROA` (biblioteca partajata separata) — e sincronizat manual intre produse ca fisier COMUN, nu ca livrabil COMUNROA. ## 2. Diff-ul semantic Comparatie linie-cu-linie, cu citate `ofacturare.prg:linie`. **Sase din cele noua diferente listate in sectiunea A a planului se confirma exact; una e imprecisa; una lipseste din plan.** ### Ce face `factureaza` si nu face `factureaza2` | Ce | `factureaza` | `factureaza2` | |---|---|---| | Tipurile 51 (ROAACNPRO), 52 (contract factura fiscala valuta) rutate la FACTURA | `Inlist(tnTip,45,48,49,**51,52**)` la `:192` si `:222` | `Inlist(tnTip,45,48,49)` la `:674` si `:700` — **51/52 lipsesc**, ar cadea in `Otherwise` -> AVIZ | | Ramura `llCopiere`/`toFactura` (copiere/modificare factura) | declarata `:102`, populata `:111`, folosita la completarea datelor (`:200-206`), la construirea interogarii (`Case m.llCopiere` -> `cursor_retur_document`, `:267-268`), si la adaugarea articolelor din lista de preturi peste cele copiate (`:454-474`) | **absenta complet** — nicio declarare a `llCopiere`, niciun tratament al lui `toFactura` | | Deschiderea `frm_date_factura`/`frm_date_aviz` | activa, cu `toFactura` transmis constructorului (`:229-235`) | inchisa cu `If .F.` (`:707-711`) | | Filtrul `RORTC` pe `jtva_coloane` | `AND !'RORTC'$UPPER(coloana_jv)` la ambele ramuri (`:243`, `:245`) | absent (`:715`, `:717`) | | Executia interogarii de articole | `lnSucces = goExecutor.oExecute(lcSqlCursor, lcCursor)` (`:311`) | **inchisa cu `If .F.`** (`:823-826`); imediat dupa, `lnSucces = 1` hardcodat (`:827`) — cursorul SQL construit la `:748-822` nu ruleaza niciodata | | Verificarea "nu exista articole" | activa (`:324-328`) | **inchisa cu `If .F.`** (`:838`) — combinata cu `lnSucces=1` de mai sus, ramura merge mereu pe calea "am articole", indiferent de continut | | Zeroizarea `gestionabil` pe proforma | `IF poDate.eProforma = 1 ... UPDATE (lcCursor) SET gestionabil = 0` (`:333-336`) | **absenta** — `eProforma` nu apare nicaieri in `factureaza2` (verificat cu grep pe tot fisierul) | | `crspolitici` / `crscontracte` (populare combo-uri) | necondiţionate (`:420-440`) | **ambele inchise cu `If .F.`** (`:956-968`, `:969-980`) | | `GetInstitutiePublica` | `poDate.institutie_publica = GetInstitutiePublica(...)` (`:509`) | **absenta** | | `codnc8`/`codcpv` pe fiecare linie | `Replace codnc8 WITH ..., codcpv WITH ...` in `Scan` (`:516-517`), pe langa `codmatc` | **doar `codmatc`** (`:1027`) — `codnc8`/`codcpv` lipsesc | | `GetSoldClient` + `poDate.sold_lei`/`sold_valuta` inainte de listare | prezent, in ramura non-bon-fiscal (`:530-533`) | **absent** — ramura echivalenta (`:1040-1041`) sare direct la `listeaza_ofacturare()` | | Formularul de articole | `frm_facturare_articole` (`:395`) | `frm_facturare_articole2` (`:929`) — **singura diferenta functionala reala** care justifica existenta lui `factureaza2` | ### Corectii fata de sectiunea A a planului - **"`verifica_numar(16, ...)` pentru chitanta" — planul GRESESTE.** E prezent **identic** in ambele: `factureaza:502-504` si `factureaza2:1018-1020` (`If poDate.incasat <> 0 ... poGeneratorNumere.verifica_numar(16, poDate.nr_incasare) Endif`). Nu lipseste din `factureaza2`. - **"`cursor_avize` cu tip 23" — planul e imprecis.** Nu exista nicio asociere `cursor_avize`/tip 23 in niciuna din cele doua proceduri (`cursor_avize` trateaza doar `tnTip = 4`, identic in ambele, `:294-295` / `:774-775`). Ce difera real pentru tipul 23: in `factureaza`, tipul 23 e prins in `Case Inlist(tnTip,1,22,5,29,7,10,**23**)` -> `cursor_preturi` (`:279-282`); in `factureaza2`, 23 **nu** e in acea lista (`:758`, doar `1,22,5,29,7,10`) si cade in schimb in `Case Inlist(tnTip,**23**,41)` -> `cursor_gestiune` (`:776-778`). E o rutare complet diferita pentru acelasi tip de document, nu o simpla lipsa — **de adaugat explicit la lista din sectiunea A**. - **Nementionat in plan — tipul 52 lipseste si din `Do Case` de contract**: `factureaza` `Case Inlist(tnTip,2,26,6,**52**)` (`:283`) vs `factureaza2` `Case Inlist(tnTip,2,26,6)` (`:762`) — aceeasi lipsa a tipului 52 ca la nIdTipDoc, dar intr-un loc separat din cod; **tipul 24** (aviz de retur) lipseste similar din `Case Inlist(tnTip,8,9,**24**)` (`:306`) vs `Case Inlist(tnTip,8,9)` (`:819`). ### Ce fac amandoua identic (verificat, nu presupus) Structura comentariilor `lnIdSet`/`pnTipFacturare`, bucla `Do While lnRaspuns = 6`, apelul `actualizeaza_optiuni_program()`, crearea `poDate`/`poGeneratorNumere`, alegerea `frm_date_factura` / `frm_date_aviz_lucrare` / `frm_date_aviz` pentru antet (desi in `factureaza2` deschiderea propriu-zisa e dezactivata), tratarea `tnTip=30` (aviz din NIR, inclusiv bucla `Scatter`/`Insert Into crsfactura` identica caracter-cu-caracter), `verifica_numar(16,...)`, dezalocarea celor trei numere (`nIdTipDoc`, 16, 3/26) la abandon, si intreaga bucla finala de `AMESSAGEBOX` "Doriti sa continuati" + `CloneObj`/`poDate.Reset()`. ### Ce face `factureaza2` si nu face `factureaza` Un singur lucru: verificari defensive suplimentare de tip la iesirea timpurie (`pnButon = 2`): ``` IF TYPE('poDate.nr_incasare') = 'N' poDate.nr_incasare = 0 ENDIF IF TYPE('poDate.incasat') = 'N' poDate.incasat = 0 ENDIF ``` (`factureaza2:727-732`) — `factureaza` face resetarea echivalenta necondiţionat, dar mai tarziu, in ramura de succes (`:546-547`), nu pe calea de abandon. Diferenta e cosmetica, nu comportamentala pe fluxul normal. ## 3. Toti apelantii **Cautare in tot arborele `D:\ROA`** (fiecare produs + `COMUN`-ul lui + `COMUNROA`), cu capcana "Grep nu vede COMUN" tratata explicit (path dat direct pe fiecare `COMUN`, nu doar pe radacina produsului — altfel cautarea sare tacut peste el, per gitignore-ul fiecarui produs). **Niciun produs verificat (ROACONT, ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB) nu apeleaza `factureaza` direct din cod propriu — nici in `COMUN`, nici in partea specifica produsului.** Singura urma in `COMUN`-urile lor e propria copie a `ofacturare.prg`/`oproceduri_facturare.prg` (definitia, nu un apel). Confirma independent observatia din `coresp_cont_venchelt.md` ca ROAACNPRO nu trece prin acest flux (foloseste `pack_acn.salveaza_regdoc`, nu `contabilizeaza_articol`). **Exceptia: ROACONTRACTE**, care are un apel real, specific produsului, la wrapper-ul `facturare_contracte`. ### Apelanti directi ai `factureaza(N)` | Apelant | Produs | Parametri | Tip document | |---|---|---|---| | `Meniuri\politica.mn2:12` | ROAFACTURARE | `factureaza(1)` | lista de preturi, lei | | `Meniuri\politica.mn2:15` | ROAFACTURARE | `factureaza(8)` | retur factura lei | | `Meniuri\politica.mn2:18` | ROAFACTURARE | `factureaza(45)` | restaurant | | `Meniuri\politica.mn2:26` | ROAFACTURARE | `factureaza(49)` | marfa custodie fara descarcare K | | `Meniuri\politica.mn2:29` | ROAFACTURARE | `factureaza(48)` | marfa custodie cu descarcare K | | `Meniuri\politica.mn2:37` | ROAFACTURARE | `factureaza(5)` | lista de preturi, valuta (invoice) | | `Meniuri\politica.mn2:40` | ROAFACTURARE | `factureaza(7)` | credit note | | `Meniuri\politica.mn2:43` | ROAFACTURARE | `factureaza(10)` | factura fiscala valuta | | `Meniuri\politica.mn2:46` | ROAFACTURARE | `factureaza(9)` | retur factura valuta | | `Meniuri\contracte.mn2:12` | ROAFACTURARE | `factureaza(2)` | contract, lei | | `Meniuri\contracte.mn2:15` | ROAFACTURARE | `factureaza(6)` | contract, valuta | | `Meniuri\contracte.mn2:18` | ROAFACTURARE | `factureaza(52)` | contract, factura fiscala valuta | ### Apelanti prin `COMUN\programe\oproceduri_facturare.prg` (dispecer comun, un wrapper per grup de tipuri) | Wrapper (`oproceduri_facturare.prg`) | -> `factureaza(N)` | Apelat din | |---|---|---| | `facturare_contracte(tcTip)` (`:119-136`) | `factureaza(2)`/`factureaza(6)`/`factureaza(52)` dupa `tcTip` | `ROAFACTURARE\Clase\ofundal_facturare.vc2:890-894`, `ROAFACTURARE\Ferestre\fundal.sc2:924`, **`ROACONTRACTE\Clase\ferestre_contracte.vc2:1542-1546`** (produs diferit, apel real) | | `facturare_comenzi()` (`:139-141`) | `factureaza(3)` | `COMUN\clase\ocomenzi.vc2:1580-1596`, metoda `do_factura` — `SCATTER NAME goComanda MEMO` inainte de apel | | `facturare_avize()` (`:144-146`) | `factureaza(4)` | `ROAFACTURARE\Clase\ofundal_facturare.vc2:905`, `ROAFACTURARE\Ferestre\fundal.sc2:932` | | `copiere_factura(toFactura)` (`:150-153`) | `factureaza(toFactura.Tip, toFactura)` | `COMUN\clase\ofacturare_comun.vc2:3710` — fisierul de perimetrul #6, doar citit, neatins | | `facturare_lista_de_preturi()` (`:114-116`) | `Do politica.mpr` -> popup-ul din `politica.mn2` (vezi tabelul de mai sus) | `ROAFACTURARE\Clase\ofundal_facturare.vc2:883`, `ROAFACTURARE\Ferestre\fundal.sc2:920` | | `emitere_aviz_clienti(tnTip)` (`:198-228`) | `factureaza(21/22/26/24)` dupa `tnTip=1/2/3/7`; `tnTip=4,5,6` -> `initializeaza_vanzare_din_stoc`, nu `factureaza` | `ROAFACTURARE\Meniuri\aviz_clienti.mn2:21,47,51,55,59,63,67` | | `emitere_aviz_clienti_debitori(tnTip)` (`:230-243`) | `factureaza(28/29)` dupa `tnTip=1/2` | `ROAFACTURARE\Meniuri\aviz_clienti_debitori.mn2:22,26` | | `emitere_aviz_clienti_custodie(tnTip)` (`:244-259`) | `factureaza(42/47)` dupa `tnTip=1/2`; `tnTip=3` -> `initializeaza_vanzare_din_stoc` | `ROAFACTURARE\Meniuri\aviz_clienti_custodie.mn2:30,34,38` | | `emitere_aviz_transfer(tnTip)` (`:261-280`) | `factureaza(25/23/27/30/41)` dupa `tnTip=1..5` | `ROAFACTURARE\Meniuri\aviz_subunitati.mn2:36,40,44,48,52` | **Total: ~33 puncte de intrare reale in cod pentru `factureaza`, doar unul pentru `factureaza2`** (`ofacturare.prg:90`, in interiorul lui `factureaza`, gatit de `gnFacturareNou=1` + confirmare DA la `AMESSAGEBOX`). ## 4. Rolul lui `gnFacturareNou` **Nu e un comutator de productie — e un switch de dezvoltator, fara nicio persistenta.** - **Declarat:** nicaieri. Cautare exhaustiva (`gnFacturareNou`, tot `D:\ROA`, extensii `.prg/.vc2/.sc2/.mn2`) — singura aparitie e exact linia care il citeste (`ofacturare.prg:88`, sau liniile echivalente in fiecare copie de produs). Nu exista intr-un ecran de optiuni, nu e coloana intr-un tabel de configurare (spre deosebire de `gnScadereStoc`, `gl406` etc., citite din `oinit_optiuni.prg`). - **Citit:** o singura data, `ofacturare.prg:88` — `If Type('gnFacturareNou') = 'N' And m.gnFacturareNou = 1`. - **Valoare implicita:** inexistenta ca variabila -> `Type()` intoarce `'U'` (Undefined), deci conditia e falsa implicit. Devine `.T.` doar daca cineva a facut manual, in sesiunea VFP curenta (de regula din fereastra de comenzi a IDE-ului), `gnFacturareNou = 1`. - **Cine il seteaza:** nimeni, in cod. E gandit sa fie setat manual de un dezvoltator care vrea sa testeze prototipul. - **Confirma sau infirma ca e comutator intre proceduri, nu intre formulare?** Azi, chiar intre **proceduri** — `factureaza:88-93` face `Return factureaza2(m.tnTip)` dupa raspunsul DA la dialog, adica sare complet in cealalta procedura, cu tot ce lipseste din ea (sectiunea 2). Planul (S2, linia 1423) vrea sa-l transforme in comutator **intre formulare**, in interiorul unei singure proceduri — schimbare corecta, pentru ca azi dubleaza cod, nu doar UI. ## 5. Proiectarea unificarii ### Semnatura **Neschimbata la aceasta poveste:** `factureaza(tnTip, toFactura)`. Parametrul de sursa explicit (comanda/contract) e treaba lui **S3c**, care depinde de S2 si il trateaza separat — nu se amesteca aici (planul insusi spune "Atinge cod comun intregii suite — nu se face impreuna cu alta modificare"). ### Ramificarea interna Nu e nevoie de o rescriere — `factureaza` de azi e deja versiunea completa si functionala. Interventia e chirurgicala: 1. **Muta verificarea `gnFacturareNou`** de la inceputul procedurii (azi `:88-93`, unde face `Return factureaza2(...)`) la **punctul unde se alege `lcObject`** pentru formularul de articole (azi `:395` in `factureaza`, ramura corespunzatoare celei din `factureaza2:929`): ``` Case tnTip = 27 lcObject = [frm_avizare_lucrare] Otherwise lcObject = IIF(m.llFacturareNoua, [frm_facturare_articole2], [frm_facturare_articole]) Endcase ``` unde `llFacturareNoua` e calculat **o singura data**, la fel ca azi (`Type('gnFacturareNou')='N' And gnFacturareNou=1`, urmat de acelasi `AMESSAGEBOX` DA/NU), dar **fara** `Return` in alta procedura — doar seteaza flagul si continua executia normala. 2. **Tot restul ramane identic** — cursorul de articole, `eProforma`, `codmatc`/`codnc8`/`codcpv`, `GetInstitutiePublica`, `GetSoldClient`, filtrul `RORTC`, rutarea tipurilor 51/52/23/24, ramura `llCopiere`/`toFactura` — pentru ca acestea nu au nicio legatura cu care formular de articole se deschide. `factureaza2` nu avea o varianta "corecta, dar diferita" a acestor blocuri — pur si simplu nu le avea, pentru ca fusesera dezactivate in graba la prototipare (`If .F.` peste tot), nu pentru ca noul formular ar avea nevoie de alt comportament acolo. 3. **Sterge `factureaza2`** in intregime (`:583-1082`, inclusiv bannerul `INCEPUT`/`SFARSIT`). ### Ordinea, ca suita sa nu fie stricata niciun moment Riscul de "moment in care suita e stricata" e mic aici, spre deosebire de S3c — pentru ca `factureaza2` **nu are alt apelant decat el insusi prin `factureaza`**. Ordinea propusa: 1. Muta logica de selectie a lui `lcObject` (pasul 1 de mai sus) **inainte** de a sterge `factureaza2` — la acest punct, codul are temporar ambele cai active (comutatorul nou + `factureaza2` inca existent, dar orfan). Se poate testa manual ca `gnFacturareNou=1` deschide `frm_facturare_articole2` din interiorul lui `factureaza`, cu restul comportamentului corect (spre deosebire de azi, unde deschiderea prin `factureaza2` sare peste `eProforma`, `codnc8` etc.) 2. Abia dupa verificare, **sterge `factureaza2`** — pasul e sigur pentru ca nu mai are niciun apelant (linia 90, singurul, a fost deja inlocuita la pasul 1). 3. **Un singur fisier se schimba**: `COMUN\programe\ofacturare.prg`. Niciun apelant din tabelul de la punctul 3 nu are nevoie de nicio modificare — toti cheama `factureaza(N)` cu aceeasi semnatura, niciunul nu cheama `factureaza2` direct. 4. **ROACONTRACTE nu necesita nicio schimbare** la aceasta poveste — apelul lui la `facturare_contracte` -> `factureaza(2/6/52)` nu atinge `factureaza2` deloc. ## 6. Riscurile de regresie - **Cel mai probabil sa se rupa:** ramura `llCopiere`/`toFactura`, pentru ca e cea mai complexa bucata de logica prezenta doar in `factureaza` (`cursor_retur_document`, apoi suprapunerea cu `cursor_preturi` pentru a permite adaugarea de articole noi peste cele copiate, `:454-474`). Nu are nicio acoperire azi in `factureaza2` de comparat — deci orice greseala de copy-paste la mutarea liniei `lcObject` risca sa rupa exact aceasta ramura, nu partea "noua". **Testat manual din `copiere_factura` (`ofacturare_comun.vc2:3710`) inainte si dupa.** - **Al doilea cel mai probabil:** rutarea tipurilor 23/24/51/52, pentru ca azi cad in `Do Case`-uri diferite intre cele doua proceduri (sectiunea 2) — o gresala de aliniere la stergerea lui `factureaza2` nu ar afecta functional (pentru ca acele Do Case-uri raman neatinse, doar duplicate disparute), dar merita o trecere vizuala pe fiecare tip listat la punctul 3 dupa modificare. - **ROACONTRACTE** — singurul apelant real din alt produs. **Nu poate fi testat din arborele de lucru ROAFACTURARE** — cere un build/rulare separata a ROACONTRACTE, cu propriul `ofacturare.prg` sincronizat manual (nu e acelasi fisier fizic, e o copie). Verificarea "gata" trebuie sa includa explicit macar un test manual pe ROACONTRACTE, tip contract-factura, nu doar pe ROAFACTURARE. - **`frm_facturare_articole2` insusi ramane netestabil functional** la aceasta poveste — `Init`-ul lui nu completeaza antetul (S1), deci deschiderea cu `gnFacturareNou=1` va arata un formular cu campuri goale la fel ca azi. Nu e o regresie introdusa de S2, dar e o asteptare de gestionat: S2 **nu** face `frm_facturare_articole2` utilizabil, doar elimina procedura duplicata din spatele lui. - **Nimic din asta e testabil headless** — toate cele ~33 puncte de intrare sunt declansate din meniuri/formulare UI (`ON SELECTION BAR`, `DO ... IN ...` din metode de clic), iar rezultatul se verifica prin `ACT`/`VANZARI`/`RUL` in Oracle sau vizual pe formular. Testarea de dupa modificare trebuie sa fie manuala, minim pe: o factura lista de preturi lei (tip 1), un aviz din comanda (tip 21), o factura din contract lei (tip 2, din `ROACONTRACTE` daca fezabil), o copiere de factura (`toFactura` populat), si — cu `gnFacturareNou=1` setat manual — confirmarea ca `frm_facturare_articole2` se deschide fara eroare (nu neaparat ca arata corect, asta e S3). ## 7. Criteriul de "gata", rescris si verificabil Planul spune azi: *"`factureaza2` nu mai exista, iar comutatorul alege formularul, nu procedura."* Rescris, verificabil fara ambiguitate: 1. **Structural** (verificabil cu o comanda, fara sa citesti codul): ``` Get-ChildItem -Recurse 'D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare.prg' | Select-String -Pattern '^\s*(PROCEDURE|FUNCTION)\s+factureaza2\b' ``` trebuie sa intoarca **zero rezultate**. ``` Select-String -Path 'D:\ROA\ROAFACTURARE\COMUN\programe\ofacturare.prg' -Pattern 'gnFacturareNou' ``` trebuie sa intoarca **exact o aparitie**, situata in interiorul lui `factureaza`, la punctul unde se alege `lcObject` (nu inainte de constructia lui `poDate`, ca azi). 2. **Comportamental**, testat manual, fara `gnFacturareNou` setat (calea implicita, majoritatea utilizatorilor): cele patru documente listate la sectiunea 6 (factura lista de preturi, aviz din comanda, factura din contract, copiere factura) produc aceleasi randuri in `ACT`/`VANZARI`/`RUL` ca inainte de modificare. 3. **Comportamental**, cu `gnFacturareNou = 1` setat manual si DA la dialog: se deschide `frm_facturare_articole2` (nu `frm_facturare_articole`), fara eroare la deschidere, cu `eProforma`/`codnc8`/`codcpv`/`GetInstitutiePublica`/`GetSoldClient`/filtrul RORTC/rutarea 51-52-23-24 toate active identic cu calea implicita (spre deosebire de azi, cand `gnFacturareNou=1` le sarea pe toate). 4. **ROACONTRACTE**: minim un test manual de facturare din contract, dupa sincronizarea `ofacturare.prg` in acel produs, confirma acelasi rezultat ca inainte. ## Ce nu s-a putut stabili si de ce - **Cine activeaza popup-urile `politica.mn2`/`contracte.mn2`** (nivelul chiar deasupra apelurilor directe la `factureaza(N)`) nu a fost trasat pana la butonul/grid-ul exact — nu era necesar pentru diff-ul procedurilor sau pentru tabelul de apelanti (punctul de interes e apelul la `factureaza`, nu inca un nivel de indirectare deasupra), dar daca implementarea muta si aceste meniuri, merita o trecere separata. - **Daca alte produse (ROAGEST, ROAAUTO, ROAACNPRO, ROAIMOB, ROACONT) au propriul lor `oproceduri_facturare.prg`/`ocomenzi.vc2` invocat din cod specific produsului, dincolo de ce am cautat** — cautarea a acoperit exact numele `factureaza`/`factureaza2` si cei noua wrapperi din `oproceduri_facturare.prg`; nu a acoperit eventuale cai complet diferite catre acelasi fisier (de exemplu un meniu `.mn2` specific unui alt produs care ar chema un wrapper cu alt nume). Pentru aceste cinci produse, cautarea directa (`factureaza(`, cei noua wrapperi) a dat zero rezultate in codul specific produsului — suficient pentru concluzia "nu apeleaza azi", dar nu e o dovada negativa absoluta de "nu ar putea apela niciodata prin alt canal". - **Testarea reala pe ROACONTRACTE** nu a fost efectuata (read-only, fara rulare de cod) — doar confirmata existenta apelului in sursa (`ferestre_contracte.vc2:1542-1546`). - **Diferenta minora de text** intre mesajele "Luna inchisa" ale celor doua proceduri (`factureaza:105` vs `factureaza2:594`, un caracter diacritic afisat diferit la citire) nu a fost investigata mai departe — pare artefact de encoding la citire (cp1250 in fisier), nu o diferenta de continut intentionata; oricum dispare odata cu stergerea lui `factureaza2`. ## Bug-uri semnalate, nereparate - **`factureaza2` e, in forma actuala, non-functional dincolo de deschiderea formularului de antet dezactivata** — chiar daca cineva ar apela azi acest cod pe o cale ipotetica ocolind `factureaza`, executia interogarii SQL e dezactivata (`lnSucces = 1` hardcodat la `:827`, fara `goExecutor.oExecute`) si verificarea "nu exista articole" e dezactivata (`:838`) — codul ar merge mereu pe ramura de succes cu un cursor `crsarticole` nepopulat de aceasta rulare (posibil ramas dintr-un apel anterior, cu alt `tnTip`). Nu se repara aici — S2 il sterge oricum, deci bug-ul dispare odata cu procedura, nu prin fix separat. - Niciun bug nou gasit in `COMUN\clase\ofacturare_comun.vc2` sau `COMUN\programe\ofacturare_editare.prg` (perimetrul #6) — singura atingere a acestor fisiere in aceasta cercetare a fost citirea liniei `copiere_factura` din `ofacturare_comun.vc2:3710`, care nu are nimic suspect.