diff --git a/docs/cercetare/rec_consumatori_vanzari.md b/docs/cercetare/rec_consumatori_vanzari.md deleted file mode 100644 index 9ac215f..0000000 --- a/docs/cercetare/rec_consumatori_vanzari.md +++ /dev/null @@ -1,220 +0,0 @@ -# Inventar consumatori `VANZARI.AVIZE`/`CURS`/`ID_VALUTA`/`MULTIPLICATOR` in suita ROA - -Cercetare STRICT de citire (fara modificari de cod, fara DDL, fara conexiuni DB, fara rulare de -conversii noi `vcx2txt.ps1`/`git_sync.ps1`) — masoara riscul de comportament schimbat dupa -corectiile S4 (AVIZE, WHERE lipsa) si S8/curs (garda `nin_valuta`) aplicate in `PACK_FACTURARE` -(vezi `rec_s4_aplicare.md`). Executata cu 3 subagenti in paralel: (a) ROAFACTURARE+COMUN, (b) cele -8 produse cu cache text deja generat, (c) restul suitei (~56 directoare). - -## RISC REAL - -**1. Referinta la aviz dispare de pe factura retiparita (tip=4).** -`COMUN\programe\oproceduri_facturare.prg` (`listeaza_formular`, ~:1125/:1189/:1265) si dublura ei -`COMUN\clase\ofacturare_comun.vc2` (`frm_facturi.do_listeaza_formular`, ~:4103/:4204) — cod -partajat, prezent in tot ecosistemul ROA*. Construiesc `crsFacturaListare` din `FACT_VFACTURI2` -(coloana `altele` = alias pentru `vanzari.avize` cand `tip in (4,24,8,9)`), apoi -`poDate.descriere = Alltrim(altele)` specific pentru `tip=4` ("factura din aviz"). `poDate.descriere` -ajunge pe formularul tiparit ca referinta "nr. aviz" (layout exact in `.frx`, neconvertit — vezi -gap mai jos). **Ce se schimba**: la retiparirea/relistarea unei facturi `tip=4` mai vechi, unde -`vanzari.avize` era populat gresit inainte (smearat de UPDATE-ul fara WHERE) si acum e gol pentru -majoritatea facturilor, referinta la aviz dispare vizibil de pe document. E in calea de reprint, -nu de emitere — deci afecteaza utilizatorul la orice reeditare/retiparire ulterioara corectiei. - -**2. Nota "Curs: X RON/valuta" pe factura electronica/PDF, generata fara verificare `in_valuta`.** -`xmlefactura.prg` (COMUN partajat, cod identic — verificat prin hash — in ROAEFACTURA, ROASITFIN, -ROACONIMPORT, ROAPRINT, ROAPRODUCTIE, ROACONT/OUTPUT, si prezent si in ROAFACTURARE/COMUN): -``` -IF !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0 - lcTextAditional = ... + "Curs: " + ALLTRIM(STR(loDate.curs,10,4)) + " RON/" + ... loDate.cValuta ... -ENDIF -``` -Conditia verifica doar `curs` nenul, nu si `loDate.in_valuta` (spre deosebire de blocul de cateva -linii mai jos, `DocumentCurrencyCode`, care testeaza corect `in_valuta=1`). Inainte, facturile in -LEI aveau deja `curs` populat gresit (bug), deci nota aparea eronat, dar cu o valoare "plauzibila". -**Ce se schimba**: dupa corectie, `curs=1` pe facturile in lei — `!EMPTY(1)` tot trece, deci nota -tot apare, dar acum arata constant `"Curs: 1.0000 RON/"` cu sufix de valuta gol (`id_valuta=0`). -Vizibil pe fiecare factura/aviz in lei exportata ca e-factura sau tiparita, in toate produsele de -mai sus. - -## RISC POSIBIL - -3. **`ofacturare_comun.vc2:4156-4157`** (si dublura `oproceduri_facturare.prg:1225-1226`): dupa - blocul `If poDate.in_valuta = 1 ... Else ... Endif`, `poDate.Curs`/`poDate.multiplicator` sunt - suprascrise necondiționat din valorile citite din view. Calculul de discount e corect protejat - de `in_valuta=1`, dar nu s-a putut confirma daca FRX-ul (neconvertit) afiseaza aceste campuri - necondiționat de `in_valuta`. De verificat in layout-ul tiparit. -4. **`vizualizare_facturi2` (`oproceduri_facturare.prg:431-479`)**: grid-ul de cautare/listare - facturi expune coloanele `altele`, `curs`, `multiplicator`, `valuta`, `id_valuta`, `nume_val` - direct din `FACT_VFACTURI2`. Nu s-a putut confirma legarea la `ControlSource` in `.scx` - (neconvertit) — daca vreuna e legata vizibil intr-un grid, utilizatorii ar vedea coloane - goale/"1" unde inainte vedeau valori (gresite). -5. **ROAACNPRO** `Programe\proceduri_acnpro.prg:1180-1229`, `calcul_penalitati` (calea activa): - `Select v.Curs, v.id_Valuta ... left join vnom_valute vl on v.id_valuta = vl.id_valuta From - vanzari v`, afisat probabil intr-un grid de review inainte de generarea facturilor de - penalizare. Calculul numeric al penalitatii NU foloseste `curs` (confirmat), deci fara risc de - calcul; ramane risc de **afisare**: `id_valuta=0` ar putea sa nu se potriveasca in - `left join vnom_valute` (tabela de valute proprie ACNPRO, distincta de `NOM_VALUTE`), lasand - coloana `valuta` goala. Nu s-a putut confirma daca `vnom_valute` are un rand pentru - `id_valuta=0` (spre deosebire de `NOM_VALUTE`, unde existenta randului `id_valuta=0` a fost deja - confirmata in `rec_s4_aplicare.md`, punctul 3 din sectiunea S8/curs — deci pentru view-urile - `FACT_VFACTURI*` din COMUN acest risc e deja exclus, ramane specific tabelei proprii ACNPRO). -6. **ROAAUTO** `Programe\oproceduri_devize.prg:1486-1532`, `relisteaza_factura_deviz`: citeste - `curs`/`multiplicator`/`altele` din `fact_vfacturi` la reafisarea unei facturi, dar cursorul se - inchide imediat fara ca valorile sa fie propagate mai departe — risc redus, de reverificat doar - daca un apelant viitor se bazeaza pe acelasi cursor. -7. **`CONTAFIN2ORA\VFP2ORA\Programe\acn.prg:~1247-1319`** (unealta de migrare, nu produs curent de - vanzare): scrie direct `curs`/`id_valuta`/`multiplicator` in `INSERT INTO VANZARI` + - `MERGE INTO VANZARI_CURSURI`, cu propria regula de zero-ing independenta de `PACK_FACTURARE` — - probabil neafectata functional, dar merita o verificare separata daca unealta mai e folosita - activ. - -## FARA RISC (rezumat, nu enumerate) - -- **ROAFACTURARE+COMUN**: restul celor ~930 potriviri brute pentru `AVIZE`/`CURS`/`ID_VALUTA`/ - `MULTIPLICATOR`/`ALTELE` — module NIR/import, balante/parteneri/compensari, salarii, curs - valutar BNR, sau citiri deja corect protejate de `in_valuta`/`tip_valuta` - (`ofacturare.prg::listeaza_ofacturare` la emitere, `ofacturare_stoc.prg`, `anaf_efactura.prg` cu - `decode(in_valuta,1,curs,1)`, `makexmlfacturaelectronica.prg` cu garda `mmoneda<>"RON"`). Niciun - hit `.avize` (acces direct de camp) in afara celor doua raportate mai sus. -- **ROACONT**: `Programe\saft_d406.prg` (declaratia fiscala D406, `oSalesInvoices`) — foloseste - `DECODE(v.in_valuta, 0, 0, ...)` explicit, output SAF-T neschimbat de corectie. Restul hit-urilor - pe tabele proprii (`ireg_parteneri`, `act`, `rul`) sau text necorelat. -- **ROAACNPRO** (restul), **ROACONTRACTE**, **ROAGEST**, **ROAIMOB**, **ROAREGISTRATURA**, - **ROASTART**: zero hit relevant legat de `VANZARI` in afara COMUN (verificat, nu doar negasit). -- **~40 de produse din restul suitei** (ROAEFACTURA si variante, ROASITFIN, ROAPRINT, - ROACONIMPORT, ROAPRODUCTIE, ROAHOTEL si variante, ROASAL, ROAMANAGER, ROADECL, ROAPRETURI, - ROABAZA, ROAAPROV, ROADEVIZE, etc.): hit-uri pe "AVIZE" = conceptul de business "aviz de - expeditie" (tip document), nu coloana; hit-uri "CURS"/"ID_VALUTA" pe alte tabele proprii sau in - `oDateFactura` (populate de apelant, protejate de `in_valuta`). `COMUNROA` (depozitul central) - contine doar scripturi de deployment, fara logica de facturare. - -## Rezumat acoperire - -- **ROAFACTURARE + COMUN local**: acoperire completa `.prg` + `.vc2`/`.sc2` via `vfp_symbols.ps1 - -CodeOnly` (index deja construit). **Gap**: 207 `.frx` si 30 `.mnx` fara `.fr2`/`.mn2` in cache — - layout-ul efectiv tiparit (unde `poDate.descriere`/`Curs`/`cValuta` chiar apar pe hartie) nu e - verificabil fara conversie (interzisa in acest task). Riscurile REAL #1/#2 si POSIBIL #3/#4 - depind partial de acest layout. -- **8 produse cu cache text existent** (ROAACNPRO, ROAAUTO, ROACONT, ROACONTRACTE, ROAGEST, - ROAIMOB, ROAREGISTRATURA, ROASTART): acoperire completa `.prg` + `.vc2`/`.sc2` via - `vfp_symbols.ps1 -CodeOnly`. **Gap**: proprietati/metadata (`ControlSource` de grid legat direct - de o coloana, fara linie de cod explicita) nu apar in `-CodeOnly` — dar un asemenea caz s-ar - clasifica oricum FARA RISC (simpla afisare). -- **Restul suitei** (~56 directoare, inclusiv `COMUNROA`): acoperire **doar** pe fisierele `.prg` - (text simplu, nu necesita conversie); zero cache text pentru `.vcx`/`.scx` — **niciun cod din - clase/formulare compilate al acestor produse nu a fost verificat**, conform interdictiei de a - genera cache nou. ~35 produse identificate ca in afara domeniului (unelte/infrastructura: SSH, - server, telefonie, criptare, declaratii D1xx/D3xx/D406 etc.) fara nicio potrivire pe termenii - cautati. -- Nicio conexiune la baza de date folosita; cifrele despre distributia datelor (ex. randul - `id_valuta=0` din `NOM_VALUTE`) sunt preluate din `rec_s4_aplicare.md`, deja documentate. - -## Concluzie - -Doua locuri cu **risc real** confirmat, ambele in codul COMUN partajat (deci efect cross-project): -disparitia referintei la aviz de pe facturile `tip=4` retiparite, si textul "Curs: 1.0000 RON/" -afisat gresit pe nota facturii electronice/PDF pentru facturile in lei. Restul e risc posibil, -dependent de layout-uri `.frx`/`.scx` neconvertite (gap de acoperire cunoscut, nu absenta de risc). -Nu s-a gasit niciun consumator cu risc real de **calcul** (sume/discounturi) — toate caile de -calcul verificate sunt deja protejate corect de `in_valuta`. - ---- - -## Corectie aplicata — riscul REAL #2 (nota "Curs:" din `xmlefactura.prg`) - -Modificare de cod, ceruta explicit de team-lead dupa livrarea inventarului de mai sus. Domeniu: -**doar** `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg`. Nicio alta copie din suita nu a -fost atinsa. - -### Ce s-a schimbat - -Linia 374 (acum singura diferenta fata de fisierul dinainte de editare): -```diff -- IF !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0 -+ IF loDate.in_valuta = 1 AND !EMPTY(NVL(loDate.curs,0)) AND ATC('curs', m.lcTextAditional) = 0 - lcTextAditional = m.lcTextAditional + Iif(!Empty(m.lcTextAditional), ' # ', '') + "Curs: " + ... - ENDIF -``` -Garda adaugata (`loDate.in_valuta = 1 AND`) e preluata **identic** din modelul deja corect din -acelasi fisier, la 9 linii mai jos (acum `:385`, era `:384`): `If loDate.in_valuta = 1` / -`oinvoice.lastchild.Text = m.mmoneda`, folosit pentru `DocumentCurrencyCode`. Nicio forma noua -inventata. Fara comentarii adaugate (regula 2, rezolvari de erori). Diff complet: -`D:\ROA\ROAFACTURARE\docs\diff_xmlefactura_garda_valuta.patch`. - -### Verificare pe cazuri (dupa modificare) - -1. **Factura in lei (`in_valuta=0`), `curs=1`** (comportamentul nou, generalizat, al facturilor in - lei dupa corectia `PACK_FACTURARE`): inainte, `!EMPTY(NVL(1,0))=.T.` -> nota aparea cu - `"Curs: 1.0000 RON/"` (valuta goala). Acum, `loDate.in_valuta = 1` e `.F.` -> intreg `AND`-ul e - fals -> nota NU se mai adauga. **Singurul caz care isi schimba comportamentul** (cel vizat). -2. **Factura in valuta reala (`in_valuta=1`)**, curs populat normal: `loDate.in_valuta = 1` e - `.T.`, restul conditiei neschimbat -> nota apare identic ca inainte. Neschimbat. -3. **Factura veche cu `curs` NULL** (orice `in_valuta`): `NVL(NULL,0)=0` -> `!EMPTY(0)=.F.` -> - conditia era deja falsa inainte de garda si ramane falsa (garda adaugata doar restrange in plus - cazul `in_valuta=0`, nu schimba nimic pe ramura `curs` NULL). Neschimbat. - -Confirmat: doar cazul 1 (facturi in lei cu `curs` efectiv nenul) isi schimba comportamentul, exact -riscul identificat. - -### Verificare encoding (byte-level) - -Fisierul contine octeti cp1252 `>=0x80` (`0xEE` = "î", la liniile 1203 si 1330 — "puteti încarca -prin SPV"), deci risc de corupere la scriere cu tool care nu pastreaza octetii nativ. Editare -facuta cu `perl` in mod raw (`s/.../.../ `), nu cu Edit/Write: -- Backup pre-editare: `xmlefactura.prg.pre_runda.bak` (md5 `e800c71bd08e6c472b6fe912437f37f8`, - 62093 octeti). -- Dupa editare: md5 `c9c9f4774346b2e62bfe9c12ea02dfb3`, 62118 octeti (+25 = exact lungimea - textului `loDate.in_valuta = 1 AND ` inserat). -- Comparatie linie-cu-linie (raw bytes) intre backup si fisierul editat: **1364 linii in ambele, - o singura linie diferita (374)** — restul fisierului byte-identic. -- Octetii `0xEE` de la liniile 1203/1330 confirmati neschimbati dupa editare. -- Scanare pentru markeri de corupere (`EF BF BD` = U+FFFD reincodat): zero potriviri. - -Encoding intact, nicio corupere. - -### Copii identice/asemanatoare in suita — corectie fata de raportul initial - -Raportul initial (sectiunea RISC REAL #2) afirma ca fisierul e "identic prin hash" in ROAEFACTURA, -ROASITFIN, ROACONIMPORT, ROAPRINT, ROAPRODUCTIE si ROACONT/OUTPUT — verificare hash directa acum -(md5 pe tot arborele `D:\ROA`, exclus `DATABASE`) arata ca afirmatia era **partial gresita**: doar -`ROACONIMPORT` si `ROAPRINT` sunt byte-identice intre ele; restul au fiecare continut propriu, -divergent de `ROAFACTURARE`. Ce e adevarat si ramane valabil: **toate contin acelasi tipar de cod -vulnerabil** (linia cu conditia fara garda pe `in_valuta`), verificat cu grep, o singura aparitie -in fiecare fisier. - -**Grup A — fisier byte-identic cu `ROAFACTURARE/COMUN` INAINTE de editarea de azi** -(md5 `e800c71bd08e6c472b6fe912437f37f8`, deci acelasi patch de o linie de la `:374` se aplica -identic, byte cu byte, in toate): -`ROAACNPRO`, `ROAAUTO`, `ROACONT`, `ROACONTRACTE`, `ROADEF`, `ROAGEST`, `ROAIMOB`, -`ROAREGISTRATURA`, `ROARES`, `ROASTART` — cale `D:\ROA\\COMUN\programe\xmlefactura.prg`. -(In plus, acelasi hash apare si in foldere de backup istoric fara relevanta: -`_backup_comun_conflicts\*`, `_backup_roaimob_comun_conflict\*` — nu sunt copii vii.) - -**Grup B — fisier divergent (alt continut/alte linii in rest), dar cu ACELASI tipar vulnerabil** -(conditie identica textual, gasita o singura data per fisier, doar la alt numar de linie): -| Produs | Cale | md5 | Linia conditiei | -|---|---|---|---| -| OUTPUT/ROACONT | `D:\ROA\OUTPUT\ROACONT\COMUN\programe\xmlefactura.prg` | `504dc24e771f6d66e4f028d1347671a8` | 350 | -| ROACONIMPORT | `D:\ROA\ROACONIMPORT\COMUN\programe\xmlefactura.prg` | `fa1e389839109ae46da1ef815e102259` | 356 | -| ROAEFACTURA | `D:\ROA\ROAEFACTURA\COMUN\programe\xmlefactura.prg` | `200442ad86e180c2484c96367ac9514a` | 356 | -| ROAPRINT | `D:\ROA\ROAPRINT\COMUN\programe\xmlefactura.prg` | `fa1e389839109ae46da1ef815e102259` | 356 | -| ROAPRODUCTIE | `D:\ROA\ROAPRODUCTIE\COMUN\programe\xmlefactura.prg` | `b71c1d9284d8ee78d02429b04c968a35` | 326 | -| ROASITFIN | `D:\ROA\ROASITFIN\COMUN\programe\xmlefactura.prg` | `47bb2e49770713b396e855e8af0ae2ea` | 356 | - -**Grup C — NU are acest bloc de cod deloc** (verificat, nu doar negasit — nu construiesc nota de -curs valutar in e-factura): `ROADECL`, `ROAMANAGER`, `ROAPRETURI`, `ROASAL`. Fara risc, fara -propagare necesara. - -**Fisierul modificat azi**: doar `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg` (md5 nou -`c9c9f4774346b2e62bfe9c12ea02dfb3`). Toate celelalte 16 cai listate mai sus (Grup A + Grup B) -raman NEATINSE, cu bug-ul inca prezent — propagarea e decizie de proces a lui Marius, nu s-a facut -aici. - -### Livrabile - -- Modificare: `D:\ROA\ROAFACTURARE\COMUN\programe\xmlefactura.prg` (linia 374, +garda `in_valuta`). -- Patch de review: `D:\ROA\ROAFACTURARE\docs\diff_xmlefactura_garda_valuta.patch`. -- Backup pre-editare (ramas pe disc, netracked): `xmlefactura.prg.pre_runda.bak` in acelasi folder. -- Aceasta sectiune. - -Fara commit git/svn — asteapta aprobarea patch-ului. diff --git a/docs/cercetare/rec_directie_roacont_2026_09.md b/docs/cercetare/rec_directie_roacont_2026_09.md deleted file mode 100644 index dc64f5d..0000000 --- a/docs/cercetare/rec_directie_roacont_2026_09.md +++ /dev/null @@ -1,124 +0,0 @@ -# Propuneri de directie ROACONT (09.2026) - -Propunerile finale dupa cercetarea de piata si backtestul pe 23 de scheme de productie. Cifrele -marcate "masurat" vin din backtest cronologic pe date reale, comparat cu ce a confirmat operatorul; -restul sunt marcate "nemasurat". Dovezile si metoda: `ROACONT\docs\cercetare\piata_ai_2026_09\`. - -Premisa: fara clienti noi, fara rescriere, datele raman in Oracle-ul clientului. - -## 1. Import eFactura primite - -Ecranul `frm_import_efactura` (`COMUN\clase\anaf_efactura.vcx`, lansat din -`COMUN\programe\import_efactura.prg:167`). Aici e concentrata munca manuala repetitiva a lunii: -13.418 facturi de intrare si 33.844 linii de articol pe an la un cabinet de 21 de firme, din care -15.565 linii primesc cont de la operator. Restul fluxului lunar e deja automatizat. - -**1.1 Cheie de articol normalizata.** `GetArticolEFByPartDenumire` -(`COMUN\programe\oproceduri_comune.prg:7362`) cauta in `ANAF_VEFACTURA_DETALII` cu -`TRIM(UPPER(d.articol)) = ?pcDenumire` - litera cu litera, deci orice cifra din denumire strica -potrivirea ("Abonament 08/2026" vs "09/2026"). Propunere: cheie fara cifre + prefix configurabil per -firma. Masurat: 52,0% -> 72,3% recunoscute, ~3.150 linii/an in plus; precizia scade 95,0% -> 93,4%. - -**1.2 Contabilizare in lot.** Semafor pe factura (verde = ultimele 5 facturi ale furnizorului contate -identic; galben = istoric variabil; rosu = furnizor nou), buton pentru tot ce e verde, anulare in -bloc. Masurat pe cont sintetic: 41,3% din facturi pe verde cu 93,8% precizie, nicio firma sub 85% - -circa 5.200 facturi/an fara interventie. Anularea in bloc nu e optionala. - -**1.3 LLM doar pe rest.** ~28% din linii nu au precedent, plus 7% furnizori noi. Se trimite doar -textul articolului si lista de conturi - fara sume, fara parteneri. Sub 20 USD/luna pentru toti -clientii. Obligatoriu: eticheta vizibila ca sugestia vine de la AI (regula UE, august 2026). - -## 2. Import extrase de banca - -Flux: `Programe\ocont2003.prg:845` -> fabrica `ImportNote` (`Programe\oproceduri_import.prg:57`) -> -parser per format -> imperechere in `ExtrasBanca::CreeazaNote` (`oproceduri_import.prg:312-926`) -> -corectie manuala in `frm_modific2024` -> scriere in `ACT` cu `id_set = 90023`. - -**2.1 Cheie de partener invatata din istoric.** Azi partenerul se ia de pe o pozitie fixa in -descriere (`oproceduri_import.prg:3013`) si se cauta exact in nomenclator -(`oproceduri_comune.prg:6623-6645`). Nu exista cheie disponibila la toate formatele: codul fiscal -lipseste la majoritatea (la BT e fixat gol, `oproceduri_import.prg:3015`), iar IBAN-ul nu are pe ce -lucra - doar 4,5% din parteneri au `CONT_BANCA` completat. Propunere: se retine din istoric ce -partener a fost confirmat pentru un IBAN si pentru un text de descriere normalizat, si se propune -doar cand acea cheie a dus **de fiecare data** la acelasi partener. -Masurat pe 3.490 de linii, 7 firme, 12 luni: **4,6% -> 28,5% acoperire la 97,9% precizie**. -Pe firme: 79,5% (BT) ... 10,5% (banci care trimit doar numere de referinta) - regula tace singura -acolo unde textul nu spune nimic, deci nu cere configurare per banca. -**Garda de unicitate e esentiala**: fara ea, 58,3% acoperire dar 56,4% precizie. - -**2.2 Salvarea IBAN-ului pe partener.** Parserul extrage IBAN-ul (`oproceduri_import.prg:3014`, scris -in `explicatia4` la `:902`) dar nu ajunge in baza: gol la 878 din 879 de linii. Daca s-ar salva pe -partener la confirmarea operatorului, nomenclatorul s-ar umple singur si cheia cea mai sigura ar -deveni utilizabila. - -**2.3 Factura: nu se automatizeaza, se scurteaza cautarea.** Masurat pe 3.074 de linii legate de o -factura: numarul acelei facturi apare in textul bancii doar in **25,0%** din cazuri (0% - 56,6% pe -firma). Potrivirea dupa suma pe documentele deschise acopera 21,2% cu 89,9% precizie, prea slaba -pentru completare automata. Plafonul e structural - informatia lipseste din fisier. Efortul merita -mutat pe: dupa ce partenerul e cunoscut, arata lista scurta a documentelor lui deschise ordonate -dupa potrivirea sumei. - -**2.4 Defecte confirmate (de reparat oricum, independent de propuneri).** -- Pozitiile fixe din descrierea BT nu sunt validate (`oproceduri_import.prg:3013-3014`): la "Plata OP - inter" si "Comision plata OP" descrierea are un camp in plus, deci denumirea se citeste ca numar de - OP si IBAN-ul ca denumire. Dovedit prin test headless pe fisiere reale. -- Bucla de asociere document iese neconditionat dupa primul numar incercat - (`EXIT`, `oproceduri_import.prg:736`), contrar comentariului de la `:701-706` - o plata care acopera - mai multe facturi ramane nepereche. -- La numar de document ambiguu, `GetDocumentByContPartenerAct` doar scrie in log - (`oproceduri_comune.prg:7038`) fara sa arate operatorului candidatii. -- **`VerifIBAN` (`COMUN\programe\oproceduri_comune.prg:7885`) intoarce raspuns gresit** cand apelantul - are selectat un cursor cu camp `iban`: variabilele nu sunt declarate si citirile neprefixate se - rezolva la CAMP, nu la parametru. Afecteaza si validarea IBAN-ului la introducerea partenerului - (`onomenclatoare.vcx`, `oparteneri.vcx`). Corectie: `LOCAL` + prefix `m.` pe toate referintele. - -**2.5 Adoptie.** Doar 7 din 21 de firme au linii venite din import de extras. Inainte de a imbunatati -algoritmul, merita aflat de ce nu se foloseste la celelalte. - -## 3. Restul, in ordinea recomandata (nemasurate) - -1. **Drepturi in modulul web** - blocant: pana nu se rezolva, nimic nu se poate arata unui client. -2. **Punte MCP peste Oracle** - intrebi in Claude Code, el ruleaza interogari pregatite; modelul - primeste rezultatul, nu baza. Singura cale prin care AI-ul intra adanc in ROA fara rescriere. -3. **Tablou de bord multi-firma cu alerte** (luna neinchisa, token SPV expirat, facturi - necontabilizate) - **singurul candidat de abonament nou** din toata cercetarea. -4. **Inchiderea de luna ca flux unic** - azi 13 comenzi in doua meniuri, fara ordine si fara bifare. -5. **Sablon de import la preluarea unui client** - maparea de conturi produsa o data si refolosita. -6. **Asistent de suport pe documentatie** - butonul de chat exista, ii lipseste continutul. -7. **e-Transport** - azi nu exista nimic. - -## 4. Respinse, ca sa nu fie repropuse - -- **Bon fiscal digital**: QR-ul contine doar identificatori (data/ora, numar, seria AMEF, optional CUI - cumparator), nu valoare/TVA/cote; nu exista serviciu ANAF pentru descarcarea bonurilor **primite**; - obligatiile cad pe producatorii de case de marcat. Zero efort in ROACONT. -- **Codul de articol din eFactura**: furnizorii nu-l trimit (34 linii din 4.426). -- **GPU local pentru AI**: costa cat 30 de ani de abonament la volumele actuale. -- **Rescriere in alt limbaj / mutare in browser**: un an fara actualizari legislative = pierderea - clientilor. Nici SAGA nu face asta. -- **Cloud propriu cu datele clientilor**: cost de operare imposibil pentru doi oameni si sterge - singurul avantaj fata de SmartBill/Oblio/Keez. -- **Intrebari in limbaj natural direct pe baza de date**: 31% raspunsuri corecte pe baze reale. - -## 5. Capcane de masurare (platite) - -- Numarul de linii cu `ID_FACTD/ID_FACTC` completat **nu** masoara automatizarea - imperecherea o face - operatorul. Nu exista tabel de audit: corectiile din `frm_modific2024` se fac inainte de scrierea in - `ACT` (`ocont2003.prg:1245-1257`). Singurul backtest valid: se reia regula cronologic pe - `ACT.EXPLICATIA` al liniilor cu `id_set = 90023` si se compara cu ce e inregistrat pe linie. -- Pe o linie de banca, partenerul se ia **de pe latura contului 401/411**, nu cu - `nvl(id_partd, id_partc)` - pe latura 512 partenerul e contul bancar propriu si cifrele ies fals - de bune. -- Subinterogarile corelate peste `ACT` omoara serverul; se scriu cu JOIN si hint `materialize`. - -## 6. Surse externe pentru afirmatiile de piata - -Verificate 03.09.2026. - -- SmartBill a livrat preluarea si prelucrarea automata a eFacturilor primite din SPV la 28.08.2026: - ajutor.smartbill.ro/article/1256 si /1128. Extrase bancare prin open banking: /article/1073. -- Obligatia de transparenta AI (Regulament UE, Art. 50) se aplica din 02.08.2026 - utilizatorul trebuie - informat ca interactioneaza cu AI: bchlaw.eu/articles/regulamentul-european-privind-ia-etapa-de-la-2-august-2026/ -- Pret GPU la 08.2026: RTX 5090 ~28.000 lei, RTX PRO 6000 96GB ~76.000 lei (techpowerup.com/351549). -- Intrebari in limbaj natural pe baze de date: 82% pe BIRD, 31% pe Spider - de aceea e respins. -- Bon fiscal digital: sursele legale, in `ROACONT\docs\cercetare\piata_ai_2026_09\BON_FISCAL_DIGITAL.md`. diff --git a/docs/cercetare/rec_integrari.md b/docs/cercetare/rec_integrari.md deleted file mode 100644 index 75e134f..0000000 --- a/docs/cercetare/rec_integrari.md +++ /dev/null @@ -1,358 +0,0 @@ -# Cercetare: integrare CONTRACTE, politici de preturi, nomenclator ca lista de preturi - -Metoda: `vfp_symbols.ps1` (cache text ROAFACTURARE deja la zi) + Grep pe `.prg`/`.vc2`/`.mn2`. -Fapte cu `fisier:linie`; ipoteze marcate `IPOTEZA:`. - -## SUBIECT A - Integrare pagina CONTRACTE (todo #10) - -### 1. Unde exista azi contractele - -Produs separat, working copy completa: `D:\ROA\ROACONTRACTE` (`.git` + `.svn`, `roaContracte.pjx`, -`roacontracte.exe`). Structura: `Clase\` (`ofundal.vcx`, `onom_clienti.vcx`, `oOptiuni.vcx`, -`roaclienti.vcx`, `ferestre_contracte.vcx` - probabil formularele CRUD de contracte), -`Ferestre\`, `Programe\`, `Rapoarte\`, `Meniuri\`, `COMUN\` (propria copie a librariei partajate), -`Teste\`, `docs\`. - -**Important**: ROAFACTURARE NU e izolat de contracte azi - are deja o integrare de facturare -partiala "pe baza de contract" (vezi punctul 4), care citeste direct din schema Oracle a -ROACONTRACTE prin view-uri (`vcontracte`, `fact_vcontracte`, `tipuri_contracte`), fara pagina de -editare. `ferestre_contracte.vcx` din ROACONTRACTE contine probabil formularele CRUD care ar -trebui aduse in ROAFACTURARE (nu au fost deschise/citite - binar, necesita conversie separata daca -se trece la implementare). - -Exista deja urme ale unei integrari partiale de UI in ROAFACTURARE: -- `Meniuri\contracte.mnx`/`.mn2` (`D:\ROA\ROAFACTURARE\Meniuri\contracte.mn2:1`) - NU e un meniu de - administrare contracte, ci un shortcut-popup cu 3 optiuni de facturare ("Factura fiscala lei / - Invoice / Factura fiscala valuta") - cf. continut citit integral. -- `Grafice\icon_contracte1.png`, `icon_contracte2.png`, `Grafice\Originale\contracte.png` - - iconite deja pregatite in ROAFACTURARE. - -### 2. Cum e integrata azi COMENZI in ROAFACTURARE (sablonul de urmat) - -COMENZI **nu** e produs separat legat prin exe, ci cod montat direct in ROAFACTURARE din -`COMUN\` (librarie partajata `gitea.romfast.ro:romfast/comun.git`, cf. CLAUDE.md). Exista si un -produs stand-alone `D:\ROA\ROACOMENZI` (cu `.pjx` propriu), dar in ROAFACTURARE comenzile sunt -o **pagina/panou montat direct in formularul principal (fundal)**, nu un exe separat lansat. - -Reteta pas cu pas (comenzi ca model pentru contracte): - -1. **Clasa container** `ct_comenzi` din `COMUN\clase\ocomenzi.vcx` (`.vc2` cache: - `COMUN\clase\ocomenzi.vc2`) - contine formulare/containere CRUD comenzi - (`frm_optiuni_comenzi`, cursoare `vcomenzi_elemente` etc.). -2. **Montare in formularul principal**: containerul e plasat ca obiect copil in - `Clase\ofundal_facturare.vc2` (form fundal), cu comentariul `< END OBJECT: - ClassLib="..\comun\clase\ocomenzi.vcx" BaseClass="container" />` in jurul liniei - `Clase\ofundal_facturare.vc2:831`; obiectul se numeste `lb_comenzi` - (`Clase\ofundal_facturare.vc2:824`). -3. **Butoane de actiune** ("Cw" = clase de tip buton-cu-drept, vezi punctul 3) legate la proceduri - business, ex. `Page2.Cw3.do_actiune` -> `DO facturare_comenzi IN oproceduri_facturare.prg` - (`Clase\ofundal_facturare.vc2:899-902`). -4. **Inregistrare in `Programe\roafacturare.prg`** (entry point): - - `SET CLASSLIB TO ocomenzi ADDITIVE` sub comentariul `*** COMENZI` - (`Programe\roafacturare.prg:180-181`); - - `SET PROCEDURE TO orap_comenzi.prg / onom_comenzi.prg / update_comenzi.prg ADDITIVE` - (`Programe\roafacturare.prg:239-242`), tot sub `*** COMENZI`; - - variabile module: `PRIVATE pocomenzi,pocomenzielemente,polucrari,pocomenzi2,polucrarielemente` - (`Programe\roafacturare.prg:246-247`). - - Toate cele 3 `.prg` (`orap_comenzi.prg`, `onom_comenzi.prg`, `update_comenzi.prg`) si clasa - `ocomenzi.vcx`/`.vct` locuiesc fizic in `COMUN\programe\` / `COMUN\clase\`, dar sunt - inregistrate ca membri ai proiectului `roafacturare.pjx` (confirmat prin Grep pe `.pjx`: - `COMUN\clase\ocomenzi.vcx`, `COMUN\programe\orap_comenzi.prg` etc. apar in el). -5. **Business logic de facturare din comenzi**: `Procedure facturare_comenzi` in - `COMUN\programe\oproceduri_facturare.prg:139-141` - un simplu `factureaza(3)` (tip document 3 - = "din comanda", motorul central `factureaza()` face restul). -6. **Meniu**: nu exista `Meniuri\comenzi.mnx` separat in ROAFACTURARE - comenzile nu au intrare de - meniu proprie, ci doar butonul `Cw3` de pe pagina fundal (Page2 = "Facturare"). Contractele au - deja `Meniuri\contracte.mnx` dar cu alt continut (shortcut factura), deci pentru pagina noua de - contracte ar trebui fie extins acest fisier, fie creat altul. - -Concluzie sablon: pentru CONTRACTE ar insemna (a) o clasa container tip `ct_contracte` (posibil -adaptata din `ferestre_contracte.vcx` al ROACONTRACTE, mutata/duplicata in `COMUN\clase\`), (b) -montarea ei ca obiect in `ofundal_facturare.vc2` langa `lb_comenzi`, (c) inregistrare `SET -CLASSLIB`/`SET PROCEDURE` in `roafacturare.prg` sub un bloc nou `*** CONTRACTE`, (d) adaugare in -`roafacturare.pjx`. - -### 3. Mecanismul de DREPTURI pe obiecte - -Sursa: `COMUN\programe\acces_meniu.prg` (fisier citit integral). - -- **Sursa de date**: view Oracle `contafin_oracle.vdef_util_obiecte`, interogat cu - `select cheie,id_firma from contafin_oracle.vdef_util_obiecte where id_util=?gnIdUtil and - id_program=?gnIdProgram and id_firma=?gnIdFirma` (`acces_meniu.prg:29-31`), rezultat in cursorul - `crsdrepturi` (o singura coloana cheie relevanta: `cheie`, string). -- **Codificarea cheii**: concatenare de "caractere de nivel" - `Chr(lnKey)` pentru fiecare nivel de - pageframe/pagina (`dezactiveaza_obiecte_pageframe`, `acces_meniu.prg:103-165`, recursiv pe - subpageframe-uri), plus un cod de 2 cifre pentru fiecare buton `Cw*`: - `lcCheie = lcKey + Padl(Alltrim(Str(.Objects(l).nid_cw)), 2, '0')` (`acces_meniu.prg:138`). - Fiecare obiect `Cw*` are proprietatea `nid_cw` (numarul lui in cadrul paginii) si la runtime i se - seteaza `ccheie` (`acces_meniu.prg:140`) si `coptiuni_active` (lista de operatii CRUD permise, - citita din caracterele urmatoare cheii - `acces_meniu.prg:141-149`). Butonul apeleaza - `.Objects(l).activeaza()` / `.dezactiveaza()` in functie de gasire (`acces_meniu.prg:150-152`). -- **Pentru imagini/iconite** (nivel diferit, folosit pe alte forme): proprietate `ccod` pe obiect - (`acces_meniu.prg:48`), aceeasi logica de cautare in `crsdrepturi`. -- **Cod de meniu (pad-uri)**: `GetAccesByCod(tcCod, tcAccesDefault)` (`acces_meniu.prg:236-276`) - cauta o cheie explicita (cod optiune meniu, ex. "ZA01") in `crsdrepturi` si intoarce lista de - operatii permise (ex. "1;2;3;4"). -- **Punct de intrare**: `verifica_drepturi(tcObiectFundal, tcPageFrame)` - (`acces_meniu.prg:9-15`) apelat din formularul fundal (`Ferestre\fundal.sc2:699`: - `verifica_drepturi('gofundal','_pgfrmbase1')`), care incarca `crsdrepturi` o singura data per - firma (cache in memorie, `citeste_drepturi`, `acces_meniu.prg:17-37`) si dezactiveaza in cascada - paginile/butoanele/meniurile fara drept. -- **Administrare drepturi** (unde se declara catalogul de obiecte si se atribuie pe grupuri): - `COMUN\clase\drept_grupuri.vc2` - `frm_grupuri`, apel catre pachetul Oracle - `PACK_DREPTURI.grupdreptmodproc` (`COMUN\clase\drept_grupuri.vc2:39`) si `citeste_drepturi - (loRec.id_grup)` (`COMUN\clase\drept_grupuri.vc2:205`). - -IPOTEZA: catalogul efectiv de "obiecte disponibile pentru ROAFACTURARE" (denumirile/codurile -`nid_cw`/`ccod`/coduri de meniu, ex. cele pentru COMENZI) e definit **partial in designerul VFP** -(proprietatea `nid_cw` seteaza pe fiecare buton la design-time in `.scx`/`.vcx`) si **partial -server-side** in schema Oracle `contafin_oracle` (tabelul din spatele view-ului -`vdef_util_obiecte`, populat probabil printr-un script de instalare/migrare, nu vazut in sursa -VFP). Pentru "comasarea" drepturilor ROACONTRACTE + ROAFACTURARE mentionata in cerere, ar trebui -inspectat acest tabel server-side (in afara sursei VFP disponibile aici) plus alocarea de noi -`nid_cw` pentru butoanele noi de contracte, fara sa coincida cu cele deja folosite de COMENZI/ -lista de preturi/avize pe aceeasi pagina. - -Exemplu concret COMENZI: butonul `Page2.Cw3` (facturare din comenzi) foloseste automat cheia -`+'03'` (Cw3 => `nid_cw=3`); pentru un buton nou de contracte pe aceeasi pagina ar -trebui un `nid_cw` neutilizat (ex. 11+, dat fiind ca Page2 are deja Cw1..Cw9 conform -`Clase\ofundal_facturare.vc2:882-926`). - -### 4. Facturarea pe baza de comanda / pe baza de contract - -**Comanda -> factura**: `Procedure facturare_comenzi` (`COMUN\programe\oproceduri_facturare.prg: -139-141`) => `factureaza(3)`. Cautarea comenzii disponibile pentru facturare: -`Function caut_comanda_gestiune` (`COMUN\programe\oproceduri_facturare.prg:1961-1983`), citeste -din view-ul `vcomenzi` (`... FROM ] + gcS + [.vcomenzi`), filtru -`facturat = 0 and interna = 3 ... ` (linia 1977). - -**"Pe baza de contract" EXISTA DEJA**, mai complet decat comenzile pe alocuri: -- `Procedure facturare_contracte(tcTip)` (`COMUN\programe\oproceduri_facturare.prg:119-136`) - - primeste tipul de document ("FACTURA LEI"/"INVOICE"/"FACTURA VALUTA") si apeleaza - `factureaza(2)`/`factureaza(6)`/`factureaza(52)`. -- Buton pe pagina fundal: `Page2.Cw2.do_actiune` (`Clase\ofundal_facturare.vc2:886-897`) - meniu - `xmenu` cu cele 3 optiuni, cheama `facturare_contracte`. -- **Cautare contract**: `Function caut_contract_facturare(tnIdPart, tcSirTipFacturare)` - (`COMUN\programe\oproceduri_facturare.prg:1986-2021`) - citeste din view-ul `fact_vcontracte` - (`select id_ctr, contract, numar, data, denumire, scadenta_incasare, opt_facturare, - text_standard, afisare_scadenta FROM fact_vcontracte`, linia 2001), filtrat pe - `opt_facturare in (...)` si `id_part`. -- **Alegerea contractului la factura**: `frm_date_factura.do_cauta_contract` - (`COMUN\clase\ofacturare.vc2:9067-9115`) si `frm_date_aviz.do_cauta_contract` - (`COMUN\clase\ofacturare.vc2:7049-7051`) apeleaza `caut_contract_facturare`. -- **Editorul de articole pe factura** are un tab/grid dedicat contractelor: - `frm_facturare_articole` cu controale `grd_contracte`, `cb_contracte` (combobox cu ratele / - contractele), populate din cursorul `crscontracte` (`COMUN\clase\ofacturare.vc2:15069-15107` si - in jur). Optiunea `opt_facturare` din `fact_vcontracte`/`crsfactura` marcheaza randurile "din - contract" (`COMUN\programe\oproceduri_facturare.prg:176-177`, `Inlist(opt_facturare,1,2)` in alt - context legat de seturi). -- **Aviz pe baza de contract**: exista si un tip de aviz "26 - catre clienti din contract" - (`COMUN\programe\oproceduri_facturare.prg:207`, enumerat si in `caut_avize`, - `COMUN\programe\oproceduri_facturare.prg:2045`), apelat din `emitere_aviz_clienti(tnTip=3)`. - -Concluzie: **motorul de facturare din contract e deja complet functional** in ROAFACTURARE (citire -din schema ROACONTRACTE prin view-uri Oracle `vcontracte`/`fact_vcontracte`/`tipuri_contracte`). -Ce lipseste conform cererii e (a) o **pagina de editare CRUD a contractelor** in ROAFACTURARE -(azi doar in exe-ul separat ROACONTRACTE) si (b) **rapoarte de contracte** in ROAFACTURARE, plus -(c) unificarea drepturilor. Nu a fost gasit niciun raport de contracte in -`ROAFACTURARE\Rapoarte\` (glob `*contract*` nu a dat `.frx` in Rapoarte, doar meniu/iconite). - ---- - -## SUBIECT B - Politici de preturi (todo #11) - -### 5. Unde sunt azi definite/editate - -Produs separat, mic, dedicat: `D:\ROA\ROAPRETURI` (`.pjx` propriu, `roapreturi.exe`). Structura: -`Programe\onom_preturi.prg`, `Programe\update_preturi.prg`, `Programe\update_nomenclator.prg`, -`Clase\opreturi.vcx`, `Clase\onom_preturi.vcx`, `Clase\ofundal_preturi.vcx`, -`Clase\ofundal_roapreturi.vcx`, `Ferestre\fundal.scx`. (Continutul acestor clase nu a fost convertit -in text - ROAPRETURI nu are un cache text propriu generat in aceasta sesiune; doar structura de -fisiere a fost inspectata.) - -Interfata de editare pare sa fie un produs desktop de sine statator, distinct de ROAFACTURARE si de -ROACONT, focalizat strict pe politici/liste de preturi si pe actualizarea nomenclatorului -(`update_nomenclator.prg` sugereaza ca ROAPRETURI scrie si in nomenclatorul comun de articole). - -### 6. Tabele/view-uri implicate (identificate din ROAFACTURARE) - -Din codul ROAFACTURARE care CITESTE politici de preturi (nu editeaza), gasite: -- `vcrm_politici_preturi` - view folosit in cautare dupa drepturi utilizator - (`COMUN\clase\baza.vc2:10087`, `:10157`, `:10502-10512`). Interogare efectiva: - `select nume_lista_preturi, id_pol from crm_vpolpretcurutil` (`COMUN\clase\baza.vc2:10504`) - - deci exista si view-ul `crm_vpolpretcurutil` ("politica de pret curenta pentru utilizator"), - cheie `id_pol`. -- `vvanzari_detalii` - contine coloana `nume_lista_preturi` folosita in rapoarte de marfa - (`COMUN\clase\configurare.vc2:3915-3972`, `frm_raport_marfa`). -- Meniu dedicat facturarii pe lista de preturi: `Meniuri\politica.mnx`/`.mn2`/`.MPR` in - ROAFACTURARE; procedura `facturare_lista_de_preturi` = `Do politica.mpr` - (`COMUN\programe\oproceduri_facturare.prg:113-116`), buton `Page2.Cw1.do_actiune` - (`Clase\ofundal_facturare.vc2:882-884`). -- Prefixul `crm_`/`CRM` in numele tabelelor/view-urilor (`vcrm_politici_preturi`, - `crm_vpolpretcurutil`) sugereaza schema/modul Oracle numit "CRM", separat de schema principala - de facturare (`gcS`). IPOTEZA: politicile de pret sunt un modul Oracle transversal (folosit si - de ROAGEST, ROAPRETURI, ROACONTRACTE), nu proprietatea exclusiva a unui singur produs VFP. -- Comenzile (ROACOMENZI/`ocomenzi.vcx`) au propriul mecanism de asociere pret-din-comanda: - globale `gnIdPoliticaPret`, `gnId_lista_preturi_PV` (`Programe\roafacturare.prg:467,469`), - folosite si in `frm_optiuni_comenzi` (`COMUN\clase\ocomenzi.vc2:6488-6686`, variabila - `gnID_LISTA_PRETURI_PV` = politica de pret "de productie" folosita la generarea automata a - comenzilor). Cursorul de articole al comenzii are coloanele `id_pol`, `nume_lista_preturi`, - `pret`, `pret_cu_tva`, `ptva` direct in el (`COMUN\clase\ocomenzi.vc2:1227-1229`, cursor creat - din view-ul `vcomenzi_elemente`). - -Nu a fost gasita nicio schema DBF/DDL explicita pentru "politici de preturi" / "liste de preturi" -in sursa VFP (tabelele reale sunt Oracle, definite server-side; VFP le vede doar prin view-uri -enumerate mai sus). N-a fost identificat un tabel separat de "note contabile asociate politicii de -pret" in codul cercetat - contul contabil de vanzare pare sa vina din nomenclatorul de articole -(`nom_articole.cont`, vezi punctul 10), nu dintr-o tabela separata legata de politica. - -### 7. Ce foloseste ROAFACTURARE azi din aceste date - -- **Facturare pe lista de preturi** (`Do politica.mpr`) - flux complet de vanzare pe baza unei - politici de pret selectate (analog cu vanzarea din stoc/comenzi/contract), tip document - distinct in motorul central `factureaza()`. -- **Cautare/afisare politica dupa drepturi utilizator** (`COMUN\clase\baza.vc2:10502-10512`) - - ROAFACTURARE citeste `crm_vpolpretcurutil` pentru a limita politicile vizibile la cele pe care - utilizatorul are drept (alt strat de drepturi, distinct de `acces_meniu.prg` - specific pe - politici de pret, posibil gestionat tot server-side prin pachetul `PACK_DREPTURI`). -- **Rapoarte de vanzari pe lista de preturi** (`frm_raport_marfa`, - `COMUN\clase\configurare.vc2:3915-3972`) - grupare/însumare pe `nume_lista_preturi`. -- Nu editeaza politici/liste - doar le CITESTE si le foloseste ca sursa de pret la facturare/ - raportare. Editarea (adaugare politica, adaugare articole in politica, preturi) ramane in - ROAPRETURI. - -Concluzie pentru migrare: ce ar trebui **mutat efectiv in ROAFACTURARE** (conform cererii - "se -folosesc numai in programul ROAFACTURARE") e interfata de editare (`opreturi.vcx`/ -`onom_preturi.vcx` din ROAPRETURI), nu structura de date (Oracle, deja partajata/citita corect). -Rapoartele si drepturile pe liste de preturi trebuie de asemenea aduse ca pagina/panou in -ROAFACTURARE, dupa acelasi sablon COMENZI descris la punctul 2. - ---- - -## SUBIECT C - Nomenclatorul de articole ca lista de preturi virtuala (todo #12) - -### 8. Structura tabelei de nomenclator - -Tabela Oracle **`catalog_articole`**, expusa prin view-ul **`vnom_articole`** (si `vnom_articole2` -pentru un al doilea tip - vezi `nom_articole2_nou`, `COMUN\programe\onomenclatoare.prg:1376-1396`, -tabela `catalog_articole2`). - -Coloane identificate din interogari/scatter (nu e o lista exhaustiva - vin din SELECT-uri -punctuale, nu din DDL): -`id_articol, denumire, codmat, codmatf (cod furnizor), codbare, um, grupa, subgrupa, id_grupa, -id_subgrupa, dnf, cont (cont contabil, 3-4 caractere), acont, inactiv, sters, in_stoc, in_crm, -tip (ex. 1 = manopera pt. ROAACNPRO), id_part/partener (pt. articole legate de furnizor/client)`. -Surse: `COMUN\clase\ocriterii.vc2:1531` (`select denumire, codmat, um, grupa, subgrupa, id_grupa, -id_subgrupa, dnf, cont, acont, inactiv, id_articol from vnom_articole`), -`COMUN\programe\onomenclatoare.prg:1345-1353` (`in_crm`, `in_stoc`, `tip`), -`COMUN\clase\ointroduceri.vc2:9631` (`in_stoc, cont`). - -**Nicio coloana de pret** nu a fost gasita direct pe `nom_articole`/`catalog_articole` (grep -`pret_v|pretv|pret_lista` in `onomenclatoare.prg` = fara rezultate; scatter-ul din -`nom_articole_nou` nu populeaza niciun camp de pret). Confirma punctul 11 mai jos. - -**Formular de editare**: `frm_catalog_articole` (grid/cautare) si `frm_catalog_articole_nou` -(fisa), ambele in `COMUN\clase\onom_articole.vc2` (`:531-599`, `:1655-1733`), salvare prin -`cus_odata_catalog_articole.salvare` si `Adauga_Modifica_Inregistrare('catalog_articole', ...)` -(`COMUN\programe\onomenclatoare.prg:1367,1443`). Deschidere din meniu: -`Procedure viz_catalog_articole` (`COMUN\programe\oproceduri_articole.prg:62-122`). - -**Important pentru subiectul B/C**: `nom_articole_nou` (`COMUN\programe\onomenclatoare.prg: -1343-1353`) marcheaza acelasi articol cu `in_crm = 1` cand programul curent e ROAPRETURI sau -ROACONTRACTE, respectiv `in_stoc = 1` in rest (inclusiv ROAFACTURARE) - **nomenclatorul de -articole e deja UNIC/PARTAJAT** intre ROAFACTURARE, ROAPRETURI, ROACONTRACTE si ROAACNPRO (aceeasi -tabela `catalog_articole`), flagurile `in_stoc`/`in_crm`/`tip` fiind doar clasificari de -utilizare, nu tabele separate. Asta simplifica mult todo #12: nomenclatorul nu trebuie replicat, -doar completat cu campuri de pret/tva/cont-vanzare si folosit direct ca sursa de pret la -facturare. - -### 9. Mecanismul actual de "lista de articole din stoc ca lista de preturi virtuala" - -Confirmat: e mecanismul de **"vanzare din stoc/gestiune"**, un tip de facturare paralel cu -"lista de preturi"/"contract"/"comanda", identificat prin variabila globala `gnTipGest`: -- `Procedure vanzare_materii_prime` -> `gnTipGest = 2`, `Do vanzare1.mpr` -- `Procedure vanzare_produse` -> `gnTipGest = 4`, `Do vanzare2.mpr` -- `Procedure vanzare_marfa_pret_achi` -> `gnTipGest = 5`, `Do vanzare3.mpr` (marfa la pret de - achizitie) -- `Procedure vanzare_marfa_pret_vanz` -> `gnTipGest = 6`, `Do vanzare4.mpr` (marfa la pret de - **vanzare**) -- `Procedure vanzare_marfa_pret_achi_vanz` -> `gnTipGest = 7`, `Do vanzare5.mpr` -(toate in `COMUN\programe\oproceduri_facturare.prg:1505-1534`; butoane `Page2.Cw5..Cw9` in -`Clase\ofundal_facturare.vc2:908-926`). - -Gestiunile disponibile per tip se filtreaza prin `Procedure selecteaza_gestiuni` -(`COMUN\programe\oproceduri_facturare.prg:1536-1565`), pe view-ul `vnom_GESTIUNI` filtrat -`nr_pag = ?gnTipGest`, plus un al doilea nivel de drept pe gestiuni (view-urile -`vgest_coresp_grupe_gestiuni` / `vgest_coresp_util_grupe`, linia 1552-1555) - deci "lista de -preturi virtuala" = stocul unei gestiuni, cu control de acces pe gestiune (nu pe politica de -pret). - -Motorul de scriere: `Function oscrie_vanzare_din_stoc` in `COMUN\programe\ofacturare_stoc.prg: -104-...`, apelat din `initializeaza_vanzare_din_stoc` (`ofacturare_stoc.prg:31-99`). Comentariu -explicit in cod: *"in vanzari_detalii scriu pretul cu tva daca am marfa la pret de vanzare, daca -nu scriu pretul de vanzare fara tva"* (`ofacturare_stoc.prg:107`), cu -`lnPretCuTva = Iif(INLIST(gnTipGest,6,7), 1, 0)` (linia 111) - deci flagul "pret cu TVA" e -determinat de TIPUL de vanzare din stoc ales (6/7 = la pret de vanzare), nu citit dintr-o coloana -a nomenclatorului. - -Cursorul-cheie `crsvanztemp` (`ofacturare_stoc.prg:137-139`) are coloanele: -`id_articol, Pret, proc_tvav, id_jtva_coloana, cantitate, discount_unitar, id_gestiune, Cont -(c4), pret_cu_tva, serie, id_valuta, codmat, Curs, multiplicator, pret_achizitie, pretd, -id_valuta_d, id_rul_aux, taxcode, lot`. - -### 10. Lantul de cod: pret, valuta, %TVA, pret_cu_tva, cont vanzare - la facturare "din stoc" - -Din structura `crsvanztemp` (punctul 9) rezulta explicit lantul folosit azi cand se factureaza -"virtual" din stoc (echivalentul cerut pentru nomenclator-ca-lista-de-preturi): -- **Pret**: coloana `Pret` in `crsvanztemp`, luata din inregistrarea de gestiune/stoc (miscarea de - intrare), nu din nomenclator - `pret_achizitie` separat pentru pretul de achizitie. -- **Valuta**: `id_valuta`, `Curs`, plus varianta in alta valuta `pretd`/`id_valuta_d` (pret dublu, - pentru afisare in a doua valuta). -- **%TVA**: `proc_tvav` + `id_jtva_coloana` (coloana de defalcare TVA in jurnal) + `taxcode` (cod - fiscal pt. integrari, ex. eFactura). -- **Flag pret_cu_tva**: `pret_cu_tva` in cursor, calculat din `gnTipGest` (`ofacturare_stoc.prg: - 111`), NU citit dintr-o coloana persistenta a articolului. -- **Cont vanzare (echivalent 4111=7xx)**: coloana `Cont c(4)` in `crsvanztemp` - cont contabil pe - 4 caractere (ex. "707x"/"701x"), scris explicit in cursor la nivel de linie de vanzare. Sursa lui - cea mai probabila (nu confirmata cu linie exacta de SELECT in aceasta cercetare, cursorul e - populat mai jos in fisier, dincolo de zona citita) e coloana `nom_articole.cont` (confirmata ca - existenta la punctul 8) sau contul gestiunii (`nom_gestiuni`) - **IPOTEZA**: trebuie verificat - punctual restul lui `oscrie_vanzare_din_stoc` (fisierul continua dupa linia 140, necitit - integral in aceasta trecere) pentru sursa exacta linie-cu-linie a lui `Cont`. - -Pentru comparatie, la facturarea pe **lista de preturi/politica** (nu pe stoc), pretul/valuta/TVA -vin din politica de pret (view `crm_vpolpretcurutil`/`vcrm_politici_preturi`, punctul 6), deci -lantul e diferit dupa tipul de facturare ales (`gnTipGest` vs. `id_pol`). - -### 11. Coloane de pret existente/partial folosite in nomenclator - -**Nu exista azi nicio coloana de pret pe `nom_articole`/`catalog_articole`** (cautare explicita -fara rezultate). Exista insa deja doua campuri reutilizabile direct pentru scenariul din cerere: -- `cont` (cont contabil de vanzare/achizitie, deja pe articol - vezi punctul 8) - poate fi folosit - ca "nota contabila" fara tabel separat. -- Flagurile `in_stoc` / `in_crm` - clasifica deja fiecare articol dupa modul de utilizare (stoc - vs. politica de pret / CRM), un precedent direct pentru un viitor flag suplimentar de tipul - "articol cu pret propriu in nomenclator" daca se implementeaza todo #12. - -Nu au fost gasite coloane de tipul `pret`, `pret_vanzare`, `valuta_pret`, `ptva` direct pe -nomenclator - toate preturile de vanzare vin azi fie din politici de pret (Oracle, schema CRM), -fie din miscarile de gestiune/stoc (nu din articolul insusi). Implementarea todo #12 -("nomenclatorul direct ca lista de preturi, fara politica + nota contabila asociate") ar necesita -adaugarea a cel putin: pret (+valuta), procent TVA, flag pret_cu_tva pe `catalog_articole`/ -`nom_articole` - camp nou, nu o coloana ascunsa deja existenta. - ---- - -## Rezumat surse cheie (fisier:linie) - -- Sablon COMENZI: `Programe\roafacturare.prg:180-181,239-247`; `Clase\ofundal_facturare.vc2: - 760-926`; `COMUN\clase\ocomenzi.vc2`. -- Drepturi: `COMUN\programe\acces_meniu.prg` (tot fisierul, 306 linii). -- Facturare contract: `COMUN\programe\oproceduri_facturare.prg:119-136,1986-2021`; - `COMUN\clase\ofacturare.vc2:9067-9115,15069-15107`. -- Politici de pret: `COMUN\clase\baza.vc2:10087,10157,10453-10512`; - `COMUN\programe\oproceduri_facturare.prg:113-116`. -- Vanzare din stoc (lista virtuala): `COMUN\programe\oproceduri_facturare.prg:1505-1534`; - `COMUN\programe\ofacturare_stoc.prg:31-140`. -- Nomenclator articole: `COMUN\programe\onomenclatoare.prg:1302-1373`; - `COMUN\clase\onom_articole.vc2:531-599,1655-1733`. diff --git a/docs/cercetare/rec_precompletare_efactura.md b/docs/cercetare/rec_precompletare_efactura.md deleted file mode 100644 index 432a41e..0000000 --- a/docs/cercetare/rec_precompletare_efactura.md +++ /dev/null @@ -1,233 +0,0 @@ -# Precompletarea la importul de eFacturi - -Directia, dupa masuratorile din 07-08.09.2026 pe toata productia (cabinetul `ROA_ROMFAST`, 21 de -scheme, si `VENDING`), read-only, backtest cronologic fata de ce a facut operatorul in realitate. - -Principiul, si singurul criteriu de acceptare a oricarei propuneri de aici: **liniile vin completate, -fara niciun click, ecran sau formular nou.** Importul nu e adoptat pentru ca nu aduce inca un -beneficiu; orice adaugam trebuie sa scada munca, nu s-o mute. - -Dovezile: `ROACONT\docs\backtest_precompletare_cont.md`, `backtest_precompletare_runda2.md`, -`inventar_campuri_de_retinut.md`, `masuratori_romfast_efactura.md`, `masuratori_vending_efactura.md`, -`profilare_semafor_vending.md`. Scripturi: `ROACONT\docs\cercetare\piata_ai_2026_09\sql\bt_26*`, `bt_27*`. - -## 0. Ce se arunca - -**Unde**: `COMUN\programe\semafor_contabilizare_ef.prg`, coloana de semafor din `frm_import_efactura`. - -**Cum e azi**: o interogare mare calculeaza per factura o culoare (verde/galben/gri/articol nou) din -stabilitatea istoricului de conturi al furnizorului. - -**Ce se schimba**: dispare, cu totul. - -**Ce se castiga**: 36s per rulare la VENDING, 4,2s pe cabinet, la deschiderea ecranului si la fiecare -cautare (`masurat`). Profilarea arata ca timpul nu vine din scanarea lui `ACT` (0,6s) ci din combinatia -catalog + cascada normalizata din aceeasi interogare (35,3s izolat). - -**Ce risc**: niciunul functional. Culoarea nu schimba nicio decizie a operatorului: pe cabinet 77,7% -din facturi ies "articol nou" si doar 3,8% verzi, iar relaxarea pragului de stabilitate de la 5 la 3 -documente aduce +13 facturi din 924 (`masurat`). - -Ramane din runda 18 doar verificarea locala a lipsurilor (`CoadaContabilizareEF.LipsuriDetalii`, fara -Oracle), ca sa nu iasa tacit documente cu cont gol pe ruta `ImportGeneral`. - -**Coada de import ramane**, dar numai pentru facturile complet completate: o factura careia ii lipseste -ceva nu intra in lot, se debifeaza singura si motivul se vede pe rand. Regula e deja scrisa (runda 18) si -nu depinde de semafor - lipsurile se calculeaza local, pe liniile facturii. Dupa precompletare lotul -devine util de la sine: 9,0% -> 66,5% din facturi fara nicio lipsa pe cabinet (`masurat`). - -## 1. Contul si analiticul pe linie - -**Unde**: `COMUN\programe\recunoastere_articol_ef.prg`, folosit din -`frm_import_efactura.completeazaDetaliiFactura` (`COMUN\clase\anaf_efactura.vc2`). - -**Cum e azi**: contul se cauta in catalogul de articole (denumire/codbare/codmat/codmatf, -`oproceduri_comune.prg:7267`) si in istoricul **aceluiasi furnizor pe acelasi articol**, text exact si -cheie normalizata. Ce nu prinde, ramane gol. - -**Ce se schimba**: doua surse noi, dupa cele existente, doar pentru liniile ramase goale: -1. **articolul contat oriunde in firma**, indiferent de furnizor, pe cheia normalizata, cu garda de - unicitate la 70% si fereastra **ultima factura**; -2. **contul dominant al furnizorului**, indiferent de articol, cu garda la 90%, fereastra **ultimele - trei facturi**, si **doar contul sintetic** - analiticul ramane al operatorului; -3. ce mai ramane ia **contul majoritar al celorlalte linii ale aceleiasi facturi**, fara prag. - -Analiticul liniei (`3xxx.xxx`, `6xxx.xxxx`) se propune doar din sursa 1 (94,3% precizie), niciodata din -sursa 2 (79,3%). - -Analiticul contului de furnizor si de client din antet (`401.xxxx`, `4111.xxxx`) nu intra: exista ca -mecanism (`IREG_PARTENERI`/`BALANTA_PARTENERI`, cu partener + cont + analitic), dar nu e folosit - vezi -respinse. - -**Ce se castiga** (`masurat`, cabinet, 15.828 linii/an): acoperire pe linie 77,8% -> 97,7%; facturi fara -nicio lipsa de cont 9,0% -> 66,5%; la VENDING 2,5% -> 69,2%. Fereastra conteaza mult: pe sursa 1, -ultima factura da 85,0% acoperire cu 93,7% precizie, fata de 60,5% / 90,1% la 36 de luni, iar castigul -e cel mai mare la furnizorii care factureaza lunar (>=8 facturi/an). - -**Ce risc**: precizia propunerilor scade de la 89,5% la 84,9% (`masurat` cu ferestrele vechi; de -recalculat la implementare, cifra e un plafon pesimist - treptele noi masurate cu fereastra corecta dau -93-94%). Practic: din 100 de linii precompletate circa 15 se corecteaza, fata de 22 care azi se scriu -de la zero. Mitigare fara UI nou: `sursa_cont` exista deja pe linie si arata de unde vine propunerea. - -## 2. Gestiunea pe linie - -**Unde**: aceeasi cascada; azi gestiunea vine doar din istoricul (furnizor, articol), altfel din optiunea -globala `EFACTURA_ID_GESTIUNE_P`. - -**Cum e azi**: la firmele cu mai multe gestiuni, optiunea globala e practic inutila - niciuna din cele -21 de firme nu are o singura gestiune activa (au intre 2 si 467), deci nu exista implicit cinstit. - -**Ce se schimba**: gestiunea trece prin aceleasi surse noi, cheia fiind partener+articol, fereastra -ultima factura. - -**Ce se castiga** (`masurat`): facturi complet rezolvate la VENDING 23,3% -> 86,0% (acoperire 97,2%, -precizie 98,1%); pe cabinet 53,0% -> 89,1%. Conteaza aproape numai la firmele cu stoc: acolo gestiunea -e 38,7% din blocaje, la cabinet 4,2%. - -**Ce risc**: stabilitatea per (partener, articol) e 64% - mai mica decat la cont. Ramane peste alternativa -de azi (o gestiune unica pe toata firma), dar merita marcata ca propunere, nu ca certitudine. - -## 3. Data scadentei - -**Unde**: `crsFacturi.data_scad`, `frm_import_efactura.completeazaFactura`. - -**Cum e azi**: se scrie de mana la fiecare factura. - -**Ce se schimba**: se propune scadenta de pe ultima factura a aceluiasi partener. - -**Ce se castiga** (`masurat`): se completeaza la 86,1% din facturi si coincide cu ultima factura a -aceluiasi partener in 87,3% din cazuri. - -**Ce risc**: cel mai mare din tot pachetul. O scadenta gresita nu se vede pe ecran, dar ajunge in balanta -si in raportarile de plati. Se propune doar cand campul din eFactura e gol, niciodata peste o valoare -venita din XML. - -## 4. Contractul - -**Unde**: `crsFacturi.Id_Ctr`. - -**Cum e azi**: ales de mana, cand se foloseste. - -**Ce se schimba**: se propune contractul de pe ultima factura a aceluiasi partener. - -**Ce se castiga** (`masurat`): se completeaza rar (16,8% din facturi), dar cand se completeaza e acelasi -in 93,8% din cazuri - deci ieftin si sigur, pentru firmele care lucreaza pe contracte. - -**Ce risc**: mic; camp fara efect contabil direct. - -## 5. Alegerile din antet care azi se pierd: deducerea, discountul, contul si analiticul partenerului - -**Unde**: `cboDeducere` (`COMUN\clase\anaf_efactura.vc2:9672`, folosit la `:13153`), -`chkDistribuieDiscount` (`:12254`), si campurile de antet `Cont`/`ACont` (`txtCont`/`txtAcont`, -cursorul `vizImportEFactura` in `COMUN\programe\import_efactura.prg:44`). - -**Cum e azi**: toate patru sunt **tranzitorii**. `Cont` si `acont` vin goale din interogare (`'' as Cont, -'' as acont`), se completeaza la rulare si nu se scriu inapoi; deducerea si discountul merg direct in -nota contabila. In DDL (`anaf_efactura.sql`) nu exista nicio coloana pentru ele. Deci la fiecare factura -de la acelasi furnizor se aleg din nou: analiticul lui `401`, deducerea 50%, distribuirea discountului. - -**Ce se schimba**: patru coloane noi pe `ANAF_EFACTURA` in care se salveaza ce a ales operatorul la -import (`cont`, `acont`, deducerea, distribuirea discountului), si repropunerea valorilor de la ultima -factura a aceluiasi partener - furnizor sau client, cu aceeasi cheie. - -Asta acopera si analiticul `401.xxxx` / `4111.xxxx`: nu se deduce din balanta (vezi respinse), ci se -**tine minte ce a scris operatorul** si se repropune la acelasi partener. Nu depinde de faptul ca azi -nimeni nu foloseste analitice pe aceste conturi - daca operatorul scrie unul, se retine. - -**Ce se castiga**: `nemasurat` - stabilitatea nu se poate masura azi, pentru ca valoarea nu se salveaza. -Se masoara dupa prima luna de date. - -**Ce risc**: cere script de migrare si versiune noua de `.exe`. Deducerea gresita are efect fiscal, deci -se propune, nu se aplica tacit: valoarea propusa ramane vizibila in acelasi loc in care se alege azi. - -## 6. Facturile emise (importate din SPV) - -**Cum e azi**: masuratorile s-au facut doar pe primite; 15 din 20 de scheme au si emise importate -(1.680 linii / 1.456 facturi pe 12 luni). - -**Ce se schimba**: aceeasi cascada, cu clientul in locul furnizorului. Codul e deja simetric -(`lPrimite`, perechile de optiuni `_E`/`_P`). - -**Ce se castiga** (`masurat`): acoperire 98,8%, precizie 97,7% - dar spatiul de conturi de vanzare e -foarte ingust (unele firme folosesc un singur cont pe an), deci cifra e reala si usoara, nu comparabila -cu achizitiile. La VENDING sunt 22.457 de facturi emise, dar prin alt flux, fara conturi pe linii - -nemasurabil. - -## 7. Configurarea, care azi nu se deschide niciodata - -**Unde**: `frm_import_efactura.Cmd_executa2.Click` si `frm_configurare_efactura` -(`COMUN\clase\anaf_efactura.vc2:14615`). Analiza completa: -`ROACONT\docs\analiza_configurare_import_efactura.md`. - -**Cum e azi**: 15 optiuni `EFACTURA_*`, dintre care doar patru schimba cu adevarat rezultatul importului -(contul implicit de articole si gestiunea implicita, pe primite si pe emise). Restul fie umplu un camp -fara nicio verificare, fie sunt comutatoare ale cascadei al caror raspuns corect e mereu acelasi. -Masurat pe cabinet: `EFACTURA_CONT_ART_P` e setata la **0 din 21** de firme, gestiunea implicita la 0 -efectiv (trei firme au valoarea 0), iar comutatoarele cascadei n-au fost atinse de nimeni. Ecranul de -Configurare nu se deschide, deci singurele optiuni care conteaza sunt goale peste tot. - -**Ce se schimba**, in aceasta ordine si abia **dupa** precompletare, pentru ca ea sterge cea mai mare -parte a nevoii de configurare: -1. **Ecranul se subtiaza**: raman doar cele patru optiuni care conteaza; cele fara efect dispar din - interfata, iar comutatoarele cascadei devin constante in cod (raman citite, ca sa nu se strice - singura firma care si-a oprit manual preluarea din facturi anterioare). -2. **Ce ramane urca pe ecranul de import**, pe randul liber deja masurat (`Left 130-530`, `Top 57-84`), - cu tiparul de camp + buton de cautare deja folosit pe forma. Dispare motivul de a deschide un ecran - separat. -3. **Optiunea se naste din lucru**: cand operatorul completeaza manual un camp pentru care exista o - optiune, langa el apare "foloseste asta de fiecare data", care scrie optiunea prin `scrie_optiune` - (`oinit_optiuni.prg:827`). Nu se cere nimic inainte si nu apare niciun ecran nou. - -**Ce se castiga**: gestiunea implicita globala devine inutila dupa precompletare - nicio firma din 21 nu -are o singura gestiune activa, deci un implicit global nu putea fi corect (`masurat`); ramane doar contul -implicit, ca plasa de siguranta pentru liniile pe care nimic altceva nu le rezolva, si acolo se aplica -punctul 3. - -**Ce risc**: un implicit scris din greseala se propaga tacit. Se previne cu eticheta explicita pe -alegere si cu faptul ca valoarea e mereu la vedere pe ecranul de import, nu ascunsa. - -## Respinse, cu motivul - -- **Potrivirea fuzzy a articolelor** (Jaro-Winkler, edit distance, `UTL_MATCH`): 80% precizie la - acoperire mica, sub cascada actuala (93-95%), si batuta de regula fara text "ultimele trei conturi ale - furnizorului", care e chiar sursa 2 de mai sus. -- **Deducerea analiticului `401.xxxx` / `4111.xxxx` din datele existente**: mecanismul exista - (`IREG_PARTENERI`/`BALANTA_PARTENERI`), dar e nefolosit - la cabinet doar 2 din 21 de firme au analitic - pe aceste conturi, si acolo e o categorie sau un proiect, nu identitatea partenerului (la una, un - singur cod acopera 98,6% din linii); la VENDING completarea e 0% si nici nu exista coduri analitice - definite pentru ele. Nu exista legatura partener -> analitic din care sa se deduca ceva. - **Respinsa e doar deducerea din balanta**; retinerea valorii scrise de operator si repropunerea ei la - acelasi partener sunt in plan, la punctul 5. -- **Valori implicite propuse din date pentru Configurare**: nicio firma din 21 nu are o singura gestiune - activa, iar contul de achizitie dominant e in medie 37,8% si niciodata peste 50%. -- **TVA la incasare**: nu e o decizie a operatorului, se verifica la ANAF; o valoare memorata ar putea - fi gresita. -- **Explicatia documentului**: completata la 18,1% din facturi si stabila doar in 50,9%. -- **Sectia, venitul/cheltuiala, responsabilul, lucrarea, felul documentului**: constante ale firmei, nu - decizii per factura - locul lor e in Configurare. -- **Un ecran de completare grupata pe articol** (macheta din 07.09): ar fi dus lotul de la 9% la 62%, - dar cu pretul unui formular in plus. Precompletarea de mai sus ajunge la 66,5% fara niciun ecran. -- **Index nou pe `ACT`** pentru semafor: bucata care scaneaza `ACT` costa 0,6s din 36s, deci nu ea e - problema; iar semaforul dispare. - -## Capcane de masurare platite - -- Facturile de test nu se recunosc doar dupa numar: 16 facturi aveau `TEST=1` si numar gol, si faceau ca - lunile recente sa para pline de date reale. -- `TRIM(x) = ''` e mereu fals in Oracle - a falsificat o prima rulare a backtestului. -- Fereastra de istoric e un parametru cu efect mare, nu un detaliu: 36 de luni fata de ultima factura - inseamna 25 de puncte de acoperire in minus pe sursa de articol. -- Timpul unei interogari nu se judeca dupa volumul de date: pe VENDING citirea costa nimic, iar 35 din - 36 de secunde vin din combinarea a doua bucati care, separat, ruleaza sub 4s fiecare. - -## Ordinea de implementare - -1. Scoaterea semaforului (castig imediat de viteza, sterge cod). -2. Contul si analiticul pe linie, cu ferestrele masurate. Se masoara timpul de deschidere a unei - facturi inainte si dupa: **precompletarea trebuie sa fie instantanee**, altfel nu s-a rezolvat nimic. -3. Gestiunea, pe aceleasi surse. -4. Data scadentei si contractul. -5. Deducerea si distribuirea discountului (cer script de migrare). -6. Configurarea: subtiere, urcarea pe ecranul de import, alegerea care scrie optiunea. Abia acum, cand - se stie ce a mai ramas necesar dupa precompletare. -7. Emise, dupa ce primitele sunt livrate si verificate. diff --git a/docs/cercetare/rec_pret_lazy.md b/docs/cercetare/rec_pret_lazy.md deleted file mode 100644 index cf01e72..0000000 --- a/docs/cercetare/rec_pret_lazy.md +++ /dev/null @@ -1,243 +0,0 @@ -# Cercetare: lant pret (#12) + editare politici pret (#11/#10) + lazy loading - -## REZUMAT (max 30 linii, focus A2 + C2) - -**A2 — NU exista niciun fallback la nomenclator azi.** Confirmat din chiar view-ul care alimenteaza -majoritatea ramurilor lui `cursor_preturi` (`fact_vpreturi_utilizator`, definit in -`D:\ROA\DATABASE\SCRIPTURI\2009\4\ff_2009_04_21_03_FACTURARE.sql:11-50`): clauza -`and d.id_pol is not null` (linia 49) e o conditie **obligatorie** pe `crm_politici_pret_art d` — -un articol nu apare deloc in lista de vanzare daca nu are un rand in `CRM_POLITICI_PRET_ART` pentru -politica activa a utilizatorului. `NOM_ARTICOLE` e joinat doar pentru `um/denumire/codmat/codbare/ -in_stoc` (descriptive), niciodata pentru `pret/valuta/proc_tvav`. In `PACK_FACTURARE.cursor_preturi` -insusi (`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql:2121-2627`) acelasi tipar se repeta in toate -ramurile (2, 45, 1/2, 5/6/10/52, 7, else/aviz): driver-ul e mereu `CRM_POLITICI_PRET_ART`/politica, -niciun `NVL`/`COALESCE` catre `catalog_articole`/`nom_articole` pentru pret. Nu exista deloc referinte -la `catalog_articole` in tot pachetul `PACK_FACTURARE` (grep pe fisierul de 16948 linii: 0 hit-uri). -**Concluzie: fallback-ul de #12 chiar trebuie construit de la zero.** Locul ieftin de inserat: in -`fact_vpreturi_utilizator` si/sau direct in `cursor_preturi`, un `UNION ALL`/`LEFT JOIN` suplimentar -care aduce articolele din `catalog_articole` **fara** rand in `CRM_POLITICI_PRET_ART` pentru -politica curenta, cu pret/valuta/tva **NULL sau valori implicite din optiuni firma** — deoarece -`catalog_articole` nu are nicio coloana de pret/valuta/tva (confirmat de echipa, si verificat: n-am -gasit `PRET`/`ID_VALUTA`/`PROC_TVAV` pe `NOM_ARTICOLE`/`CATALOG_ARTICOLE` in DDL). Fallback-ul e deci -"articolul apare, dar utilizatorul trebuie sa completeze pretul manual" — nu un pret implicit real. - -**C2 — Exista deja un sablon de lazy loading, complet si reutilizabil**, in -`COMUN\clase\_ct_base.vc2:278-281` (`do_activeaza_container` → `This.actualizeaza_cursoare()`), legat -la `PageX.Activate` (`Clase\ofundal_facturare.vc2:1006-1008` pentru comenzi). Implementarea reala e -in `COMUN\clase\ocomenzi.vc2:1088-1104`: cursorul se creeaza o singura data (guard -`!Used('crscomenzi') Or gcS!=This.cSchema Or ...schimbare sectie`), cu un `WHERE` imposibil -(`id_comanda = -9999999`) — deci structura se creeaza dar nu se aduc date. Datele reale vin abia la -`do_cauta()` (`ocomenzi.vc2:1484-1510`), care trimite un `WHERE` filtrat prin `gencursor`/ -`ca_baza1.afisare()` — deci cautarea e deja server-side (Oracle), nu filtrare locala. **Acesta e -sablonul de refolosit pentru #11/#10, exact cum indica deja `plan_10_integrare_contracte.md` S3.** -Atentie: baza `_ct_base.actualizeaza_cursoare` (linia 231-232) e un stub gol — clasa container noua -(`ct_preturi`/`ct_contracte`) trebuie sa suprascrie explicit `actualizeaza_cursoare`, dupa modelul -`ocomenzi`, nu doar sa mosteneasca `_ct_base`. `ct_contracte` din ROACONTRACTE **nu** face asta azi -(vezi C4) — deci nu e lazy, desi mosteneste acelasi `_ct_base`. - ---- - -## A. Lantul de determinare a pretului - -### A1. `cursor_preturi` — surse pe ramura (spec `:335-343`, body `:2121-2627`, -`ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql`) - -Toate ramurile pornesc din `pack_facturare.initializeaza_facturare` + `completare_politica_stoc` + -`verifica_cursuri_valute` (:2132-2136), apoi `CASE V_TIP`: - -- **V_TIP=45 (restaurant)**, `:2143-2247`: subselect A = politica activa a utilizatorului - (`utilizatori_rol_intern` → `politici_grupuri` → `crm_politici_preturi` → `crm_note_vanzari` → - `note_contabile`, filtrat pe `datai/datas` fata de luna curenta si `id_sucursala`), apoi - `LEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL=B.ID_POL`, `LEFT JOIN NOM_ARTICOLE C`. **Pret**: - `B.PRET`/`B.DISCOUNT_UNITAR` convertite prin curs (`F.CURS`) daca valuta politicii ≠ valuta - nationala. **Valuta**: `B.ID_VALUTA` → `NOM_VALUTE G`. **TVA%**: `B.PROC_TVAV` (direct din - `CRM_POLITICI_PRET_ART`, nicio referinta la `ID_JTVA_COLOANA` in acest cursor). **Flag - pret_cu_tva**: `A.PRETURI_CU_TVA` (de pe `crm_politici_preturi`, nu per-articol). **Cont**: - `'371' AS CONT` — **hardcodat**, nu vine din nicio tabela. -- **V_TIP IN (1,2) (factura lei)**, `:2248-2372`: acelasi tipar (A/B/C), plus `LEFT JOIN` pe `STOC` - pentru cantitate gestionabila (E) si pe `CURS`/`NOM_VALUTE` (F/G). Nicio coloana `CONT` in select. -- **V_TIP IN (5,6,10,52) (valuta)** si **V_TIP=7 (credit note)**, `:2374-2524`: sursa e view-ul - `FACT_VPRETURI_UTILIZATOR A` (nu mai construieste politica inline), plus `STOC` (C) si `CURS`/ - `NOM_VALUTE` (D/E). Filtru `A.ID_VALUTA=V_ID_VALUTA AND A.IN_VALUTA=1` (sau `A.ID_POL= - pack_facturare.nid_politica_stoc` la tip 5/6/10/52). Nicio coloana `CONT`. -- **ELSE (aviz)**, `:2526-2624`: tot din `FACT_VPRETURI_UTILIZATOR A`, fara filtru pe valuta. Nicio - coloana `CONT`. - -**Definitia `FACT_VPRETURI_UTILIZATOR`** (cea mai recenta gasita, `D:\ROA\DATABASE\SCRIPTURI\2009\4\ -ff_2009_04_21_03_FACTURARE.sql:11-50`; nu a mai fost modificata in `SCRIPTURI_CLAR`, deci pare -stabila de atunci): -``` -utilizatori_rol_intern a - left join politici_grupuri b on a.id_grup=b.id_grup - left join crm_politici_preturi c on b.id_politica=c.id_pol - left join crm_politici_pret_art d on b.id_politica=d.id_pol - left join nom_articole e on d.id_articol=e.id_articol -- doar um/denumire/codmat/codbare/in_stoc - left join crm_note_vanzari f on c.id_nota=f.id_nota - left join note_contabile g on f.id_set=g.id_set -where ... and d.id_pol is not null -- <- gate-ul, vezi A2 -``` -Coloane expuse: `id_pol, preturi_cu_tva, nume_lista_preturi, id_articol, pret, discount_unitar, -proc_tvav, um, denumire, codmat, codbare, gestionabil, id_valuta, in_valuta, nota_discount`. **Nicio -coloana `cont`.** - -**`ID_JTVA_COLOANA`**: nu apare deloc in `cursor_preturi`. Grep pe tot pachetul arata ca se -foloseste doar mai tarziu, la scriere/postare (`scrie_in_vanzari`, `descarca_gestiune`, -`contabilizeaza_tva`, in jur de liniile 3700-4130, 4660-5400, 12250-13700 din pachet) — deci cota de -TVA "oficiala" (coloana `JTVA_COLOANE`) se rezolva separat de `PROC_TVAV`-ul afisat la selectarea -pretului, probabil prin cautare dupa procent in `citeste_id_jtva_coloana`-tip logica (nu am urmarit -in detaliu — in afara bugetului A, marcat ca zona neexplorata). - -**Cont de vanzare, de fapt**: parametrul `V_CONT` din `PACK_FACTURARE.adauga_articol_factura` -(`:4972-4998`) e trimis de VFP la adaugarea liniei (valoare `'XXXX'` = "fara override" -> `V_CONT2` -ramane NULL). Nu am gasit el sa fie citit din `CRM_POLITICI_PRET_ART`/`NOM_ARTICOLE` in acest flux; -in schimb exista deja `initializeaza_date_gestiune(V_ID_GESTIUNE, V_ID_TIPGEST, V_CONT, V_ACONT)` -(spec `:311-314`) care leaga contul de **gestiune**, nu de articol/politica. Separat, pachetul -`PACK_PRETURI` (editorul din ROAPRETURI) scrie `NOM_ARTICOLE.CONT` direct la -`adauga_articol`/`modifica_articol` (`D:\ROA\DATABASE\SCRIPTURI\2008\7\ff_2008_07_31_01_PRETURI.sql -:107-130, 300-330, 386-424`) — deci **contul de vanzare al articolului exista deja pe -`NOM_ARTICOLE.CONT`** (= `catalog_articole.cont` din nomenclatura curenta), independent de orice -lista de preturi. Asta inseamna ca, pentru #12, contul NU are nevoie de fallback nou — poate fi citit -direct din nomenclator, exact ce cere planul (ramane de confirmat unde/cum VFP populeaza azi `V_CONT` -la trimiterea catre `adauga_articol_factura`, cautare separata, in afara bugetului acestei runde). - -### A2. Fallback existent — **NU exista**. Detaliat mai sus (rezumat) si in A1 -(`d.id_pol is not null`, zero hit-uri `catalog_articole` in `PACK_FACTURARE`). Singurul loc unde -`NOM_ARTICOLE`/nomenclatorul intra in calculul de pret e ca sursa a campurilor descriptive -(um/denumire/codmat/codbare/in_stoc), niciodata pentru pret/valuta/tva/cont. - -### A3. `citeste_setari_pol_pret` (`:2025-2065`) -Nu seteaza `pret_cu_tva`/TVA. Citeste doar **care politica e implicita** pentru un `V_ID_UTIL`, in -functie de `V_TIP`: `OPTIUNI.VARNAME` = `'ID_POL_PRET_TR'` (tip 23/30/41), `'ID_POL_PRET_STOC'` -(tip 1), `'IDPOLPRETFACTK'` (tip 48/49), fiecare cu `LEFT JOIN CRM_VPOLPRETCURUTIL B ON ... AND -B.ID_UTIL=V_ID_UTIL`. Deci `pret_cu_tva`/TVA vin exclusiv din randurile `crm_politici_preturi`/ -`crm_politici_pret_art` selectate ulterior de `cursor_preturi`, nu din aceasta procedura. - -### A4. Tabelele politicii de pret (coloane confirmate din uz + din -`ff_2008_07_31_01_PRETURI.sql:10-95`, ADD/FK, si `create or replace view vcrm_politici_preturi`): - -- **`CRM_POLITICI_PRETURI`**: `ID_POL, NUME_LISTA_PRETURI, DATAI, DATAS, ID_VALUTA, ID_UTIL, - DATAORA, NOTA_ONLINE, ID_NOTA, PRETURI_CU_TVA, ID_SUCURSALA, STERS`. FK: `ID_VALUTA->NOM_VALUTE`, - `ID_NOTA->CRM_NOTE_VANZARI`, `ID_SUCURSALA->CONTAFIN_ORACLE.NOM_FIRME`. -- **`CRM_POLITICI_PRET_ART`**: `ID_POL, ID_ARTICOL, ID_VALUTA, PRET, PRETFTVA, PRETCTVA, PROC_TVAV, - DISCOUNT_UNITAR, STERS` (din `modificare_politica_stoc`, `:2105-2119`, si din selectii). **Nicio - coloana CONT.** -- Nu am gasit `CREATE TABLE` originar pentru aceste doua tabele in `SCRIPTURI_CLAR` (probabil - create inainte de 2006, in afara arhivei "clare"); coloanele de mai sus sunt derivate din uz activ - in cod, nu dintr-un DDL complet — de tratat ca aproape sigure, nu 100% exhaustive (pot exista - coloane suplimentare needitate de codul cercetat). -- View-uri asociate: `VCRM_POLITICI_PRETURI` (`ff_2008_07_31_01_PRETURI.sql:42-65`), - `VPOLITICI_GRUPURI` (`:67-95`), `CRM_VPOLPRETCURUTIL` (folosit pretutindeni, definitia lui nu a - fost cautata — in afara bugetului). - ---- - -## B. Cine mai foloseste listele de preturi - -- **ROAFACTURARE**: doar citeste. `crm_vpolpretcurutil` la `COMUN\clase\baza.vc2:10087,10157, - 10502-10512` (filtrare politici dupa dreptul utilizatorului); `facturare_lista_de_preturi` = - `Do politica.mpr` (`COMUN\programe\oproceduri_facturare.prg:113-116`); rapoarte grupate pe - `nume_lista_preturi` din `vvanzari_detalii` (`COMUN\clase\configurare.vc2:3915-3972`). - (Sursa: `docs\plan_11_integrare_politici_preturi.md:15-22`, deja in `D:\ROA\ROAFACTURARE\docs\`.) -- **ROAPRETURI** (`D:\ROA\ROAPRETURI`, exe separat `roapreturi.exe`): **editeaza** politicile — - `Clase\opreturi.vcx`, `Clase\onom_preturi.vcx`, `Clase\ofundal_preturi.vcx`, - `Programe\update_preturi.prg`, `Programe\update_nomenclator.prg`. Pachet Oracle `PACK_PRETURI` - (`adauga_articol`/`modifica_articol`/`verifica_articol` — scriu si pe `NOM_ARTICOLE`, nu doar pe - politica). **Nu are cache text (.vc2/.sc2) generat** — nu s-a putut inspecta clasa in detaliu (vezi - C4); confirmat prin `Glob D:\ROA\ROAPRETURI\**\*.vc2` = 0 fisiere, doar `.vcx` binare. -- **ROACONTRACTE** (`D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2`): citeste direct - `vcrm_politici_preturi` / `vcrm_politici_pret_art` prin SQL Pass Through (`goExecutor.oExecute`), - la cautarea/atasarea unui articol pe linie de contract - (`Programe\oproceduri_roacontracte.prg:213-239`: `select id_pol,... from vcrm_politici_preturi`, - apoi `select id_articol, id_pol_art, ... from ]+gcS+[.vcrm_politici_pret_art where id_pol=...`). - Nu editeaza politica insasi, doar o consuma pentru a atasa articole+pret pe contract. -- **ROAGEST**: 0 hit-uri directe pe `CRM_POLITICI_PRET*`/`cursor_preturi`/`PACK_PRETURI` in cod VFP - (`.vc2`/`.prg`) — foloseste probabil acelasi `PACK_FACTURARE` server-side prin - `Programe\ofactureaza.prg` (fisier gasit la cautarea `id_pol`, dar doar in comentarii vechi de - schema cursor, nu apel activ identificat in bugetul alocat). -- **ROAACNPRO**: la fel, 0 hit-uri directe; `id_pol` apare doar intr-un `Text To lcSchema`/ - `lcSelect` ascuns (`Omitted long matching line` — continut necunoscut, de investigat separat daca - devine relevant). -- **ROAIMOB**: 0 hit-uri (`.vc2`). -- **COMUNROA**: 0 hit-uri (`.vc2`) — surprinzator pentru un modul "CRM transversal"; posibil ca - accesul se face exclusiv server-side (proceduri Oracle), nu prin VFP direct in produsele - verificate, sau ROAGEST/ROAACNPRO folosesc cod VFP montat din `COMUN` (acelasi `ocomenzi.vcx` etc.) - fara sa atinga politica de pret local. -- **Nomenclatorul comun** (`update_nomenclator.prg` in ROAPRETURI) scrie in tabela de articole - folosita de toate produsele — punct de atentie deja notat in `plan_11...md:82-84` (S2, perimetru). - -**Concluzie B**: politica de pret (structura de date) e deja un modul transversal minim -(ROAFACTURARE citeste, ROAPRETURI editeaza, ROACONTRACTE citeste), consistent cu ce spune deja -`plan_11...md`. Nu s-a gasit inca un al patrulea consumator activ in cod VFP (ROAGEST/ROAACNPRO -probabil trec prin acelasi `PACK_FACTURARE` server-side, fara sa atinga tabelele direct din VFP). - ---- - -## C. Incarcare lazy si cautare - -### C1. Cum incarca azi paginile mari - -- **`ct_comenzi`** (`COMUN\clase\ocomenzi.vc2`): montat ca `Page5.Ct_comenzi1` - (`Clase\ofundal_facturare.vc2:604-606`). `PROCEDURE Page5.Activate` (`:1006-1008`) apeleaza - `this.ct_comenzi1.do_activeaza_container()`. Aceasta e mostenita din `_ct_base.vc2:278-281` - (`do_activeaza_container` → `bind keypress` + `This.actualizeaza_cursoare()`). - `ocomenzi.actualizeaza_cursoare` (`:1088-1104`) **nu incarca date** — creeaza doar structura - cursorului prin `creeaza_cursoare()` (`:1191-1245`), cu `lcFiltru = [id_comanda = -9999999]` - (`:1216`) — deci 0 randuri reale la deschidere/activare de pagina. -- **`onom_articole.vc2`**: editorul de articol individual (`PROCEDURE Init`, `:1704-1772`) e per- - inregistrare (`toRec`), nu o grila; incarca doar cursoarele mici de grupe/subgrupe pentru combo-uri - (`crs_grupe_art`, `crs_subgrupe_art`, `:1717-1729`). Nu s-a gasit/verificat in bugetul alocat cum - se incarca lista/grila principala de articole a nomenclatorului (formularul-parinte, nu editorul) — - **neacoperit**, marcat ca zona pentru o runda ulterioara daca devine relevanta pentru #12/#11. - -### C2. Sablon de lazy loading existent — **DA**, detaliat in rezumat. -Cheia: `_ct_base.do_activeaza_container` (hook legat de `Page.Activate`) → `actualizeaza_cursoare()` -**suprascrisa** in clasa concreta cu un guard `!Used(cursor) Or ` → -`creeaza_cursoare()` cu `WHERE` fals → date reale doar la `do_cauta()`. `_ct_base` insusi ofera doar -stub-uri goale (`:231-232` pentru `actualizeaza_cursoare`, la fel `do_adauga/do_cauta/...` la -`:283-322`) — **fiecare container concret trebuie sa implementeze explicit lazy-load-ul**, nu vine -gratis din mostenire. - -### C3. Cautare server-side vs. filtrare locala -- **Server-side (tiparul de urmat)**: `ocomenzi.do_cauta` (`:1484-1510`) construieste `lcFiltru` - (`id_sectie = ...` + `filtru_pretty`) si il trimite prin `actualizeaza_grid1(lcFiltru)` → - `pocomenzi.ca_baza1.cfiltru=lcFiltru` → `pocomenzi.ca_baza1.afisare()` (`:1109-1123`) — clasa - `ca_baza1` (generata de `gencursor`) trimite `WHERE`-ul catre Oracle prin `goExecutor`, nu - filtreaza un cursor deja incarcat integral. -- **Local (contra-exemplu)**: `actualizeaza_grid1` in continuare (`:1119-1124`) face si operatii pur - locale pe cursor deja adus (`SELECT * FROM crscomenzi WITH (Buffering=.T.) WHERE selectat=1 INTO - CURSOR crstempcomenzi`) — dar asta e pentru pastrarea selectiei intre reincarcari, nu pentru - cautare/filtrare initiala. - -### C4. ROAPRETURI / ROACONTRACTE — incarca tot la deschidere? - -- **ROAPRETURI**: **nu se poate stabili** — lipseste cache-ul text (`.vc2`/`.sc2`), doar `.vcx` - binare (`Clase\opreturi.vcx`, `Clase\ofundal_preturi.vcx`); conform regulilor primite, nu am - convertit nimic. Precondiitia e deja documentata ca blocanta in `plan_11...md:66-70` (S1: inrolare - in fluxul text, procedura `COMUN\docs\inrolare-proiect-git-text.md`). -- **ROACONTRACTE**: `ferestre_contracte.vc2` are cache text si e vizibil. Descoperire importanta: - clasa container `ct_contracte` (`:9`, `DEFINE CLASS ct_contracte AS _ctfrmbase OF - "..\comun\clase\_ct_base.vcx"`) **mosteneste acelasi `_ct_base`** ca `ct_comenzi`, si are propriul - `filtru_pretty`/`but_start_criterii1` (vazut in `But_reset_criterii1.Click`, `:1551-1567`) — deci - infrastructura de cautare exista. **Dar nu suprascrie `actualizeaza_cursoare`/`creeaza_cursoare`** - (0 hit-uri in fisier) — inseamna ca foloseste stub-ul gol din `_ct_base` pentru acel hook, iar - cursorul principal (`cContracte`, vazut deja populat la `PROCEDURE Init` a ferestrei, - `:1518-1527`, `Select cContracte / If Reccount()>0`) se incarca **altundeva, probabil eager, la - deschiderea formularului** — nu s-a gasit punctul exact de populare in bugetul alocat (cautare - separata necesara: `cContracte` INTO CURSOR / gencursor pentru contracte). **Concluzie: ROACONTRACTE - NU e azi lazy**, desi are "schela" pentru a deveni (acelasi `_ct_base`). Pentru #10/#11, sablonul - de copiat e strict cel din `ocomenzi.vc2`, nu cel din `ferestre_contracte.vc2`. - ---- - -## Neacoperit / de reluat intr-o runda viitoare -- `CRM_VPOLPRETCURUTIL` — definitia view-ului (coloane exacte, drepturi). -- `ID_JTVA_COLOANA` — cum se leaga procentul afisat in `cursor_preturi` (`PROC_TVAV`) de coloana TVA - oficiala folosita la postare. -- Unde/cum populeaza azi VFP parametrul `V_CONT` la `adauga_articol_factura` (ipoteza: din gestiune, - nu din articol) — relevant pentru a confirma daca planul #12 poate refolosi direct - `NOM_ARTICOLE.CONT` fara alta lucrare. -- Incarcarea listei/grilei principale de articole din `onom_articole.vc2` (formularul-parinte, nu - editorul per-inregistrare). -- Unde exact se populeaza `cContracte` in `ferestre_contracte.vc2` (cautare punctuala, nu facuta). -- ROAGEST/ROAACNPRO: confirmarea ca folosesc `PACK_FACTURARE` exclusiv server-side pentru preturi - (ipoteza, nu verificata prin citirea completa a `ofactureaza.prg`/`proceduri_acnpro.prg`). diff --git a/docs/cercetare/rec_s10_s12.md b/docs/cercetare/rec_s10_s12.md deleted file mode 100644 index 7338d3f..0000000 --- a/docs/cercetare/rec_s10_s12.md +++ /dev/null @@ -1,110 +0,0 @@ -# S10 + S12 — versiune_db.txt, curatare VERSIUNE, propunere changelog 2.11.13 - -## S10 — `versiune_db.txt` - -Regula exacta, confirmata in `COMUN\docs\scripturi-migrare-db.md` ("Numerotare si versiune_db.txt"): -in `versiune_db.txt` se trece **doar versiunea ultimului script `ff_`** (nu `co_`/`sys_`/`rf_`/`ris_`), -pentru ca programele se conecteaza pe schema firmei, nu pe `CONTAFIN_ORACLE`. - -Verificat pe disc, `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08\`: cinci scripturi `ff_2026_08_06_*` -aplicate azi pe `MARIUSM_AUTO` — `_02` (`PACK_FACTURARE`, S4), `_03` (`PACK_FACTURARE`, S7), `_04` -(`VANZARI_COMANDA_CONTRACT`, S6), `_05` (`FACT_VFACTURI`, S8), `_06` (`VANZARI_BACKFILL`, S5). -Confirmat si prin interogare pe `VERSIUNE` (`order by data_script desc, seq_script desc`): ultimul -`ff_` aplicat e `ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql`. - -**Scris in `versiune_db.txt`: `2026_08_06_06`** (fara newline la final, pastrand conventia -fisierului existent — verificat byte-level, 13 octeti, identic ca lungime cu vechea valoare -`2026_08_02_01`). - -## S10 — starea tabelei `VERSIUNE` - -Interogata direct pe `MARIUSM_AUTO` (`docs\cercetare\s10_curata_versiune.sql`, pasul 1). Numar de -inregistrari per script, azi: - -| Script | Inregistrari | -|---|---| -| `ff_2026_08_06_02_COMUN_PACK_FACTURARE.sql` (S4) | 2 | -| `ff_2026_08_06_03_COMUN_PACK_FACTURARE.sql` (S7) | 1 | -| `ff_2026_08_06_04_COMUN_VANZARI_COMANDA_CONTRACT.sql` (S6) | 2 | -| `ff_2026_08_06_05_COMUN_FACT_VFACTURI.sql` (S8) | 4 | -| `ff_2026_08_06_06_COMUN_VANZARI_BACKFILL.sql` (S5) | 5 | - -14 randuri in total pentru cele 5 scripturi de azi, 9 in plus fata de cate 1 per script. Confirma -tiparul semnalat: `_02`, `_05`, `_06` (si, in plus fata de ce era asteptat, `_04`) au fost aplicate -de mai multe ori pe masura extinderii lor in cursul zilei; `_03` are deja un singur rand, nimic de -curatat acolo. - -**Propunere, nerulata**: `docs\cercetare\s10_curata_versiune.sql`. Pastreaza per script randul cu -`ID_VERSIUNE` maxim (ultima aplicare = starea finala reala a scriptului), sterge restul — scoped -strict pe cele 5 nume de script din lista de mai sus, cu `select` de verificare inainte si dupa, -`delete` la mijloc, `commit` comentat (de dat manual). Fara impact functional indiferent daca se -ruleaza sau nu: nici `versiune_db.txt`, nici aplicarea DDL nu depind de numarul de randuri din -`VERSIUNE`. **Nu s-a rulat** — stergerea de istoric ramane decizie de om. - -## S12 — propunere changelog - -Livrat: `docs\propunere_changelog_2.11.13.txt` (neaplicat in `changelog_roafacturare.txt`). - -``` - -``` - -### Motivare inclusiune/excludere - -- **Aviz, totaluri, curs valutar** (`:eroare:`) — toate trei sunt defecte confirmate ca fiind - efectiv pe date de productie (`VENDING`), vizibile pe facturi reale (lista principala si - retiparire), acum corectate. Se incadreaza clar la `:eroare:`. -- **`CLIENT` pe retur-transfer** (`:eroare:`) — `fact_vfacturi`, folosit de gridul principal de - listare, calcula gresit numele clientului pe cele 23 de facturi `tip=41`/`tip=-6`; view-ul - corect (`fact_vfacturi2`) confirma sursa deliberata din cod. E o valoare gresita afisata in - productie, nu doar o diferenta cosmetica intre doua liste — de aceea l-am pus la `:eroare:` si - nu la `:modificare:`, desi in mesajul initial parea doar "etichete neuniforme". -- **`EXPLICATIE`** (`:modificare:`) — diferenta e strict de formatare a textului - ("COMERCIAL - FACTURARE" vs "COMERCIAL-FACTURARE" etc.), nu o valoare gresita; l-am tinut separat - si mai jos in prioritate, la `:modificare:`. -- **Denormalizarea comanda/contract (S6) — EXCLUSA din changelog.** Harnessul de regresie da - aceleasi cifre inainte si dupa aplicarea scriptului; nu exista nimic vizibil pentru utilizator. - O intrare de changelog ar fi inselatoare (ar sugera o schimbare functionala inexistenta). -- **Incasarea lipsa pe facturile din devize auto — EXCLUSA din `changelog_roafacturare.txt`.** - Corectia e integral in cod VFP din **ROAAUTO** (`Programe\oproceduri_devize.prg`, - `factureaza_deviz`) plus un parametru nou cu `DEFAULT` in `PACK_FACTURARE.scrie_incasari` - (pachet Oracle comun, dar ramura noua e apelata **doar** din ROAAUTO). Recompilarea - `roafacturare.exe` singura, fara recompilarea ROAAUTO, nu produce niciun efect vizibil pentru - utilizatorul ROAFACTURARE — deci intrarea nu apartine acestui changelog, chiar daca facturile - respective ar putea fi vazute si din listele ROAFACTURARE dupa ce ROAAUTO e recompilat si el. - **Propunere de text pentru `changelog_roaauto.txt` (needitat, doar propus aici)**: - - ``` - - ``` - -## Fisiere livrate - -- `versiune_db.txt` — actualizat la `2026_08_06_06` (editat direct, marcaj de proiect). -- `docs\cercetare\s10_curata_versiune.sql` — propunere de curatare, **nerulata**. -- `docs\propunere_changelog_2.11.13.txt` — propunere, **neaplicata** in `changelog_roafacturare.txt`. -- Acest raport. - -**Fara commit** (git/SVN). Nu s-au atins scripturile de migrare, nu s-a rulat DDL, nu s-a scris in -`VERSIUNE`. diff --git a/docs/cercetare/rec_s5_proiectare_oracle.md b/docs/cercetare/rec_s5_proiectare_oracle.md deleted file mode 100644 index 17795a9..0000000 --- a/docs/cercetare/rec_s5_proiectare_oracle.md +++ /dev/null @@ -1,780 +0,0 @@ -# Cercetare S5 — proiectarea partii Oracle (plan #6, editare factura emisa) - -Data: 09.08.2026. Sursa: export PROASPAT din `MARIUSM_AUTO@ROA_CENTRAL` (`all_source`), facut in -aceasta sesiune, in scratchpad (nu in proiect): - -- `PACK_FACTURARE.pck` — 16160 linii -- `PACK_CONTAFIN.pck` — 8550 linii - -**Toate numerele de linie de mai jos sunt din ACEST export.** Raportul precedent -(`rec_s5_oracle_vanzari.md`, 08.08.2026) declara `PACK_FACTURARE.pck = 17010` linii; offset-urile -procedurilor coincid totusi exact (`scrie_in_vanzari` la `:13491`, `actualizeaza_vanzari` la -`:16015`), deci diferenta e de formatare a spool-ului, nu de continut. Concluziile lui A.1-A.2, C si -D raman valabile pe sursa de azi si nu se repeta aici. - -**Doua corectii de fond fata de raportul precedent** (detaliate la 3 si 4): - -1. agregarea NU citeste `VANZARI_SETURI_TEMP`, ci tabela **persistenta `VANZARI_SETURI`** - (`:13916`) — deci liniile de set se pot reconstitui integral la editare; -2. recomandarea „procedura noua apelata din interiorul `finalizeaza_modificare_nota`" e - **incompatibila cu ordinea corecta de scriere** si trebuie abandonata. - ---- - -## 1. Baza de plecare e la zi? DA (pentru `ff_`) - -Comparatie `VERSIUNE` (4151 randuri) vs. `D:\ROA\DATABASE\SCRIPTURI_CLAR` (3030 fisiere `.sql`): - -- **`ff_` pe disc dar neaplicate in `MARIUSM_AUTO`: 0.** Schema e la zi pe tot ce o priveste. -- Ultimul `ff_` inregistrat: `ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql`, identic cu - `versiune_db.txt` din radacina proiectului (`2026_08_08_01`). -- Cele 26 de scripturi din 2026 care lipsesc din `VERSIUNE` sunt **exclusiv `co_` si `sys_`** — se - aplica pe `CONTAFIN_ORACLE`, respectiv `SYS`, nu pe schema firmei; `VERSIUNE` din `MARIUSM_AUTO` - contine doar 3 randuri `co_`, deci absenta lor e normala, nu o restanta. - -**Verdict: se poate construi propunerea peste sursa exportata azi.** - -### Doua anomalii de semnalat (nu blocheaza S5) - -- **`ff_2026_08_08_01_COMUN_VVD_TOT.sql` e inregistrat in `VERSIUNE` dar NU exista nicaieri pe - disc** (cautat recursiv in tot `SCRIPTURI_CLAR`). Un obiect aplicat in dev fara script salvat nu - ajunge niciodata la clienti. De verificat cu Marius daca e un script de lucru abandonat sau daca - lipseste din SVN. -- Acelasi `NN` (`2026_08_08_01`) e folosit de doua scripturi `ff_` (`VVANZARI_ARTICOLE` si - `VVD_TOT`), contra regulii „NN e secventa unica pe zi". - ---- - -## 2. Blocul de agregare din `scrie_in_vanzari` — integral - -Procedura: `PACK_FACTURARE.pck:13491-13956`. Blocul de agregare + `UPDATE VANZARI` e -`:13762-13954`, citat integral: - -``` -13762 -- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi -13763 begin -13764 select DISC_TVA_VAL AS DISCOUNT_TVA, -13765 VALOARE_ACHIZITIE, -13766 a.suma_fara_tva_ron - a.disc_fara_tva_ron as TOTAL_FARA_TVA, -13767 a.suma_tva_ron - a.disc_tva_ron as TOTAL_TVA, -13768 a.suma_fara_tva_ron - a.disc_fara_tva_ron + a.suma_tva_ron - -13769 a.disc_tva_ron as TOTAL_CU_TVA, -13770 a.suma_fara_tva_val - a.disc_fara_tva_val as VALVAL, -13771 a.suma_tva_val - a.disc_tva_val as TVAVAL, -13772 a.suma_fara_tva_val - a.disc_fara_tva_val + a.suma_tva_val - -13773 a.disc_tva_val as TOTVAL, -13774 id_valuta, -13775 curs, -13776 multiplicator, -13777 pack_facturare.cserie_act_incasare as SERIE_INCASAT, -13778 pack_facturare.nnumar_act_incasare as NR_INCASAT, -13779 pack_facturare.nsuma_incasare AS SUMA_INCASAT, -13780 pack_facturare.ntip_doc_incasare as TIP_INCASAT -13781 INTO lnDiscountTVA, -13782 lnValoareAchizitie, -13783 lnTotalFaraTVA, -13784 lnTotalTVA, -13785 lnTotalCuTVA, -13786 lnValVal, -13787 lnTVAVal, -13788 lnTotVal, -13789 lnIdValuta, -13790 lnCurs, -13791 lnMultiplicator, -13792 lnSerieIncasat, -13793 lnNrIncasat, -13794 lnSumaIncasat, -13795 lnTipIncasat -13796 FROM (select MAX(decode(pack_facturare.nin_valuta, -13797 1, -13798 ROUND(a1.curs * NVL(V_DISCOUNT_FACTURA, 0) / -13799 a1.multiplicator, -13800 lnPreciziePretV), -13801 NVL(V_DISCOUNT_FACTURA, 0))) as DISC_FARA_TVA_RON, -13802 NVL(V_DISCOUNT_FACTURA, 0) as DISC_FARA_TVA_VAL, -13803 pack_facturare.nin_valuta AS IN_VALUTA, -13804 MAX(ROUND(decode(pack_facturare.nin_valuta, -13805 1, -13806 ROUND(a1.curs * -13807 NVL(V_DISCOUNT_FACTURA, 0) / -13808 a1.multiplicator, -13809 lnPreciziePretV), -13810 NVL(V_DISCOUNT_FACTURA, 0)) * -13811 (a1.proc_tvav - 1), -13812 lnPreciziePretV)) as DISC_TVA_RON, -13813 MAX(ROUND(NVL(V_DISCOUNT_FACTURA, 0) * -13814 (a1.proc_tvav - 1), -13815 lnPreciziePretV)) as DISC_TVA_VAL, -13816 sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_ron, -13817 0, -13818 1, -13819 NVL(a1.discount_unitar_ron, -13820 0), -13821 pack_facturare.ndiscount_evidentiat, -13822 a1.cantitate, -13823 a1.pret_cu_tva, -13824 a1.proc_tvav)) AS SUMA_FARA_TVA_RON, -13825 sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_ron, -13826 0, -13827 1, -13828 NVL(a1.discount_unitar_ron, -13829 0), -13830 pack_facturare.ndiscount_evidentiat, -13831 a1.cantitate, -13832 a1.pret_cu_tva, -13833 a1.proc_tvav)) as SUMA_TVA_RON, -13834 sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_val, -13835 0, -13836 1, -13837 NVL(a1.discount_unitar_val, -13838 0), -13839 pack_facturare.ndiscount_evidentiat, -13840 a1.cantitate, -13841 a1.pret_cu_tva, -13842 a1.proc_tvav)) AS SUMA_FARA_TVA_VAL, -13843 sum(pack_facturare.calculeaza_total_tva_fact(a1.pret_val, -13844 0, -13845 1, -13846 NVL(a1.discount_unitar_val, -13847 0), -13848 pack_facturare.ndiscount_evidentiat, -13849 a1.cantitate, -13850 a1.pret_cu_tva, -13851 a1.proc_tvav)) as SUMA_TVA_VAL, -13852 sum(round(a1.cantitate * a1.pret_achizitie, -13853 lnPrecizieCalcul)) AS VALOARE_ACHIZITIE, -13854 max(decode(pack_facturare.nin_valuta, 1, a1.id_valuta, 0)) as id_valuta, -13855 max(decode(pack_facturare.nin_valuta, 1, a1.curs, 1)) as curs, -13856 max(decode(pack_facturare.nin_valuta, 1, a1.multiplicator, 1)) as multiplicator -13857 from (select vd.id_vanzare_set, -13858 (case -13859 when (pack_facturare.nin_valuta = 1 or -13860 vd.id_valuta <> -13861 pack_def.GetIdMonedaNationala()) then -13862 ROUND(vc.curs * vd.pret / vc.multiplicator, -13863 lnPreciziePretV) -13864 else -13865 vd.pret -13866 end) as pret_ron, -13867 vd.pret as pret_val, -13868 vd.proc_tvav, -13869 vd.cantitate, -13870 vd.diferenta, -13871 (case -13872 when (pack_facturare.nin_valuta = 1 or -13873 vd.id_valuta <> -13874 pack_def.GetIdMonedaNationala()) then -13875 ROUND(vc.curs * vd.discount_unitar / -13876 vc.multiplicator, -13877 lnPreciziePretV) -13878 else -13879 vd.discount_unitar -13880 end) as discount_unitar_ron, -13881 vd.discount_unitar as discount_unitar_val, -13882 vd.id_valuta, -13883 vd.pret_cu_tva, -13884 vd.pret_achizitie, -13885 vc.curs, -13886 vc.multiplicator -13887 from (select a.id_vanzare_set, -13888 a.pret, -13889 a.proc_tvav, -13890 a.cantitate, -13891 a.diferenta, -13892 a.discount_unitar, -13893 a.id_valuta, -13894 a.pret_cu_tva, -13895 a.pret_achizitie -13896 from VANZARI_DETALII_TEMP a -13897 where nvl(a.id_vanzare_set, 0) = 0 -13898 union all -13899 select b.id_vanzare_set, -13900 b.pret, -13901 max(c.proc_tvav) as proc_tvav, -13902 b.cantitate, -13903 0 as diferenta, -13904 b.discount_unitar, -13905 decode(pack_facturare.nin_valuta, -13906 0, -13907 pack_def.GetIdMonedaNationala(), -13908 c.id_valuta) as id_valuta, -13909 b.pret_cu_tva, -13910 sum(decode(b.cantitate, -13911 0, -13912 0, -13913 c.pret_achizitie * c.cantitate / -13914 b.cantitate)) as pret_achizitie -13915 from vanzari_detalii_temp c -13916 left join vanzari_seturi b -13917 on b.id_vanzare_set = c.id_vanzare_set -13918 where nvl(c.id_vanzare_set, 0) <> 0 -13919 and nvl(pack_facturare.nin_valuta, -1) > -1 -13920 group by b.id_vanzare_set, -13921 b.pret, -13922 b.cantitate, -13923 b.discount_unitar, -13924 b.pret_cu_tva, -13925 decode(pack_facturare.nin_valuta, -13926 0, -13927 pack_def.GetIdMonedaNationala(), -13928 c.id_valuta)) vd -13929 left join vanzari_cursuri vc -13930 on vc.id_vanzare = V_ID_VANZARE -13931 and vd.id_valuta = vc.id_valuta) a1) a; -13932 -13933 update vanzari -13934 set discount_tva = lnDiscountTVA, -13935 valoare_achizitie = lnValoareAchizitie, -13936 total_fara_tva = lnTotalFaraTVA, -13937 total_tva = lnTotalTVA, -13938 total_cu_tva = lnTotalCuTVA, -13939 valval = lnValVal, -13940 tvaval = lnTVAVal, -13941 totval = lnTotVal, -13942 id_valuta = lnIdValuta, -13943 curs = lnCurs, -13944 multiplicator = lnMultiplicator, -13945 serie_incasat = lnSerieIncasat, -13946 nr_incasat = lnNrIncasat, -13947 suma_incasat = lnSumaIncasat, -13948 tip_incasat = lnTipIncasat -13949 where id_vanzare = V_ID_VANZARE; -13950 -13951 exception -13952 when NO_DATA_FOUND then -13953 null; -13954 end; -``` - -Variabilele locale relevante, declarate la `:13501-13523`: - -``` -13522 lnPrecizieCalcul NUMBER(2) := pack_sesiune.getOptiuneFirma('PC'); -13523 lnPreciziePretV NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV'); -``` - -### Inventarul dependentelor blocului - -| Dependenta | Linii | Sursa la emitere | Echivalent PERSISTENT la editare | Verdict | -|---|---|---|---|---| -| `V_DISCOUNT_FACTURA` | 13798, 13801, 13802, 13807, 13810, 13813 | parametru al procedurii | **`VANZARI.DISCOUNT`** — scrisa la INSERT din exact acelasi parametru (`:13621` / `:13682`) | reconstituibil | -| `pack_facturare.nin_valuta` | 13796, 13803, 13804, 13854-13856, 13859, 13872, 13905, 13919, 13925 | stare de sesiune pe pachet | **`VANZARI.IN_VALUTA`** (`NUMBER(1)`, NOT NULL) — scrisa la INSERT din aceeasi variabila (`:13625` / `:13686`) | reconstituibil | -| `pack_facturare.ndiscount_evidentiat` | 13821, 13830, 13839, 13848 | stare de sesiune pe pachet | **`VANZARI.DISCOUNT_EVIDENTIAT`** — scrisa la INSERT din aceeasi variabila (`:13622` / `:13683`) | reconstituibil | -| `cserie_act_incasare`, `nnumar_act_incasare`, `nsuma_incasare`, `ntip_doc_incasare` | 13777-13780 | stare de sesiune, setata numai in fluxul de emitere (`:13102-13144`; resetate la `:1882-1886`) | **NICIUNUL** | vezi 6 | -| `pack_def.GetIdMonedaNationala()` | 13861, 13874, 13907, 13927 | functie pura: `SELECT MIN(ID_VALUTA) FROM NOM_VALUTE WHERE STERS=0 AND MONEDA_NATIONALA=1` (PACK_DEF body `:214-230`) | idem — fara stare | fara probleme | -| `pack_sesiune.getOptiuneFirma('PC'/'PPRETV')` | 13522-13523, 13853 | `SELECT varvalue FROM optiuni WHERE ...` (PACK_SESIUNE body `:119-141`) — **lookup pe tabela, fara stare de pachet** | idem | fara probleme | -| `VANZARI_DETALII_TEMP` (liniile directe) | 13896-13897 | GTT `ON COMMIT DELETE ROWS` | **`VANZARI_DETALII WHERE ID_VANZARE = :id AND STERS = 0 AND NVL(ID_VANZARE_SET,0) = 0`** | vezi 3 | -| `VANZARI_DETALII_TEMP` (liniile de set, alias `c`) | 13915, 13918 | GTT | **`VANZARI_DETALII ... AND NVL(ID_VANZARE_SET,0) <> 0`** | vezi 3 | -| `vanzari_seturi` (alias `b`) | 13916 | **tabela PERSISTENTA, deja** | ea insasi | vezi 3 | -| `vanzari_cursuri vc` | 13929-13930 | tabela persistenta, populata cu `id_vanzare`-ul curent la `:13704` (`scrie_cursuri`) | ea insasi, deja legata pe `ID_VANZARE` | fara probleme | - -Verificat pe `all_tab_columns`: **toate cele 9 coloane citite din `VANZARI_DETALII_TEMP` de -agregare** (`id_vanzare_set, pret, proc_tvav, cantitate, diferenta, discount_unitar, id_valuta, -pret_cu_tva, pret_achizitie`) exista, cu acelasi nume, in `VANZARI_DETALII`. Singurele coloane pe -care TEMP le are in plus si care nu exista in tabela reala sunt `CURS, MULTIPLICATOR, EXPLICATIA, -ID_COMANDA, NUMAR_ACT, ID_TEMP, ID_UTIL, IN_STOC, PRETV_ORIG, ID_GESTIUNE_DEST, ID_LUCRARE_REZ, -ID_PART_REZ` — **niciuna nu e folosita de blocul de agregare** (`curs`/`multiplicator` vin din -`vanzari_cursuri vc`, nu din linie). - -**Concluzie: blocul se reproduce 1:1 pe surse persistente, schimband doar clauzele `FROM` si -inlocuind cele 3 valori de stare cu cele 3 coloane din `VANZARI`.** Nu e nevoie de nicio -reformulare a formulei — inclusiv `calculeaza_total_fara_tva_fact` / `calculeaza_total_tva_fact` -(`PACK_FACTURARE.pck:15858-16013`, semnaturi in spec la `:1167-1185`) raman apelate identic. - -Doua observatii de detaliu: -- `a1.diferenta` e selectata (`:13870`, `:13891`) dar **nu e folosita nicaieri** in agregarea din - `scrie_in_vanzari` (parametrul `V_DIFERENTA` e `0` hard-codat la `:13817`, `:13826`, `:13835`, - `:13844`). Se poate pastra pentru fidelitate sau elimina; recomand pastrarea, ca diff-ul fata de - original sa ramana citibil. -- Handler-ul `WHEN NO_DATA_FOUND THEN NULL` (`:13951-13953`) e defensiv si practic inaccesibil: - subinterogarea are agregate fara `GROUP BY`, deci intoarce mereu exact un rand. **Dar** pe zero - linii agregatele intorc `NULL`, nu `0` — la emitere cazul nu poate aparea, la editare da (vezi - riscul R4). - ---- - -## 3. Liniile din seturi — EXISTA echivalent persistent - -**Corectia raportului precedent.** Agregarea nu citeste `VANZARI_SETURI_TEMP`, ci -**`VANZARI_SETURI`** (`PACK_FACTURARE.pck:13916`), care e o tabela **normala, persistenta** -(verificat pe `all_tables`: `VANZARI_SETURI temporary=N`; doar `VANZARI_SETURI_TEMP` si -`VANZARI_DETALII_TEMP` sunt `temporary=Y duration=SYS$TRANSACTION`). - -Trecerea TEMP -> persistent o face `pack_facturare.scrie_seturi` (`:13993-14028`), apelata la -`:13706`, **inainte** de agregare: insereaza fiecare rand din `VANZARI_SETURI_TEMP` in -`VANZARI_SETURI` (`ID_VANZARE_SET` din `SEQ_VANZARI_SETURI`, prin trigger -`TRG_VANZARI_SET_BEFOINS`) si reface pointerul in `VANZARI_DETALII_TEMP.ID_VANZARE_SET`. De aceea -agregarea de la `:13915-13928` face join intre TEMP (componentele) si tabela persistenta (capul de -set). - -Structura `VANZARI_SETURI` (`all_tab_columns`), identica cu a TEMP-ului: - -``` -ID_VANZARE_SET NUMBER(10) NOT NULL -- PK, din SEQ_VANZARI_SETURI -DENUMIRE VARCHAR2(100) -EXPLICATIE VARCHAR2(100) -CANTITATE NUMBER(10,4) -UM VARCHAR2(10) -SERIE VARCHAR2(100) -PRET NUMBER(20,4) -DISCOUNT_UNITAR NUMBER(20,4) -PRET_CU_TVA NUMBER(1) NOT NULL -``` - -Nu are `ID_VANZARE` si nu are `STERS`: legatura cu documentul e **exclusiv** prin -`VANZARI_DETALII.ID_VANZARE_SET`. Deci filtrarea pe document se face tot din `VANZARI_DETALII`. - -**Precedent care confirma reconstituirea**: `pack_facturare.citeste_vanzari_seturi` -(`:16619-16698`) reface deja exact acest lucru pe surse persistente — `VANZARI` (`cod`, `sters=0`) -+ `VANZARI_DETALII` (`sters=0`, `id_vanzare_set is not null`) + `VANZARI_CURSURI` + -`VANZARI_SETURI`, cu acelasi `GROUP BY b.id_vanzare_set`. Nu inventam un tipar nou. - -**Raspuns la intrebarea din brief: DA, recalculul poate acoperi si liniile de set, fara pierdere de -informatie.** Transformarea necesara in ramura de set: - -``` -from vanzari_detalii c -- in loc de vanzari_detalii_temp c -left join vanzari_seturi b on b.id_vanzare_set = c.id_vanzare_set -where nvl(c.id_vanzare_set, 0) <> 0 - and c.id_vanzare = V_ID_VANZARE - and c.sters = 0 -``` - -Date (test, `MARIUSM_AUTO`): 4 randuri in `VANZARI_SETURI`, 4 documente cu linii de set. **Nu e o -dovada** — validarea ramane pe cod, nu pe volum. - -### Ce NU se poate face din interfata (limitare de semnalat pentru S4) - -View-ul `VVANZARI_ARTICOLE` (sursa lui `IncarcaArticoleFactura`, -`COMUN\programe\ofacturare_editare.prg:288-330`) **nu expune `ID_VANZARE_SET` si nici -`PRET_ACHIZITIE`**: - -``` -select vd.id_vanzare, vd.id_vanzare_det, vd.id_articol, vd.cantitate, vd.pret, vd.pret_cu_tva, - vd.proc_tvav, vd.discount_unitar, vd.id_gestiune, vd.cont, vd.id_valuta, - vd.id_jtva_coloana, vd.serie, vd.explicatie, vd.taxcode, vd.lot, vd.sters, - na.denumire, na.codmat, ng.nume_gestiune, nv.nume_val - from vanzari_detalii vd - left join nom_articole na on na.id_articol = vd.id_articol - left join nom_gestiuni ng on ng.id_gestiune = vd.id_gestiune - left join nom_valute nv on nv.id_valuta = vd.id_valuta -``` - -Consecinte concrete: - -1. componentele de set apar in grid ca linii obisnuite, dar formularul **nu poate sti** ca sunt - componente si nu poate edita capul de set (`VANZARI_SETURI.PRET`/`CANTITATE`), care e ceea ce - intra efectiv in totaluri. Un utilizator care schimba pretul unei componente **nu schimba - totalul documentului** — recalculul ia pretul din `VANZARI_SETURI`. Divergenta tacuta. -2. `PRET_ACHIZITIE` lipseste din cursor, deci VFP nu-l poate rescrie la un `UPDATE` de linie: la - scriere trebuie **omis din `SET`**, ca sa ramana valoarea existenta (altfel `VALOARE_ACHIZITIE` - se pierde). Pentru liniile **noi** insa nu exista sursa — vor intra cu `PRET_ACHIZITIE` NULL si - vor contribui cu NULL la `SUM(round(cantitate * pret_achizitie))`, deci **`VALOARE_ACHIZITIE` - devine NULL pe tot documentul** daca fie si o singura linie noua are NULL. Vezi riscul R3. - ---- - -## 4. Capcana de ordonare — punctul central - -### Ce ruleaza azi, in ce ordine - -Punctul de intrare nou (deja scris in ramura curenta): -`COMUN\clase\ofacturare_comun.vc2`, `do_editare_factura`, blocul de salvare: - -``` -3798 If Thisform.do_deschide_tranzactie() && SQLSetprop(gnHandle,"Transactions",2) -3800 lnSucces = OSCRIE_IN_FISIERE(2,.T.,.T.) && marcheaza STERS=1 nota veche -... -3820 lnSucces = OSCRIE_IN_FISIERE(0,.T.,.T.) && scrie nota noua (COD nou din SCRIE_IN_ACT) -3823 If lnSucces > 0 -3824 lcSql = [begin pack_contafin.finalizeaza_modificare_nota(...); end] -3826 lnSucces = Iif(goExecutor.oExecuta(lcSql),1,-1) -3827 Endif -3828 If Thisform.do_inchide_tranzactie(Iif(lnSucces<0,2,1)) && SQLCOMMIT / SQLROLLBACK -``` - -`do_deschide_tranzactie` / `do_inchide_tranzactie`: `COMUN\clase\_frm_base.vc2:251-269` si -`:278-302` — `SQLSetprop(gnHandle,"Transactions",2)` / `Sqlcommit(gnHandle)`. - -`finalizeaza_modificare_nota` (`PACK_CONTAFIN.pck:8601-8651`) apeleaza `actualizeaza_vanzari` la -`:8616`, gardat de `SELECT COUNT(*) FROM vanzari WHERE cod = tnCod > 0` (`:8613-8615`). - -`actualizeaza_vanzari` (`PACK_FACTURARE.pck:16015-16025`): - -``` -16018 -- de modificat in caz ca il las sa stearga manual inregistrari din VANZARI_DETALII -16019 -- acum se marcheaza cu STERS = 1 doar cand se sterge toata factura -16020 UPDATE VANZARI_DETALII -16021 SET STERS = 0 -16022 WHERE ID_VANZARE IN -16023 (SELECT ID_VANZARE FROM VANZARI WHERE COD = V_COD_VECHI); -16024 UPDATE VANZARI SET COD = V_COD_NOU, STERS = 0 WHERE COD = V_COD_VECHI; -``` - -### De ce exista `STERS = 0` acolo (nu e cod mort) - -E perechea lui `sterge_din_vanzari` -> `sterge_factura`, care marcheaza documentul sters: - -``` -5549 UPDATE VANZARI_DETALII -5550 SET STERS = V_STERS, ID_UTILS = V_ID_UTIL, DATAORAS = V_DATAORA -5551 WHERE ID_VANZARE = V_ID_VANZARE -5552 AND STERS = V_NESTERS -``` - -Reeditarea unei note sterse trebuie sa readuca la viata si randul din `VANZARI`, si liniile lui. -**Scoaterea reset-ului ar rupe fluxul „stergi nota, apoi o reeditezi" pe toata suita ROA.** - -### Consecinta pentru S5 — mai grava decat „stergerile se pierd" - -Reset-ul e **in bloc, fara nicio garda**: nici `AND STERS = 1` (irelevant), nici o discriminare -intre „stersa ca linie" si „stersa odata cu documentul". `sterge_factura` marcheaza doar liniile -active (`AND STERS = V_NESTERS`, `:5552`), deci o linie stearsa la o editare anterioara ramane -`STERS=1` — si e **inviata** de `actualizeaza_vanzari` la urmatoarea salvare a notei. - -Deci daca liniile se scriu inainte de `finalizeaza_modificare_nota`: - -- stergerile din editarea CURENTA se pierd tacut; -- **si**, independent de ce face utilizatorul acum, orice stergere facuta la o editare - ANTERIOARA e anulata la fiecare salvare ulterioara — inclusiv la o salvare care nu atinge deloc - articolele. Stergerea de linie **nu s-ar fixa niciodata**. - -`UPDATE`-urile de pret/cantitate si `INSERT`-urile de linii noi ar supravietui — deci esecul e -partial si asimetric, exact tipul care trece de un test superficial. - -### Variantele de ordonare - -**(a) VFP scrie detaliile inainte, `actualizeaza_vanzari` neatinsa.** -Respinsa. Motivul complet e cel de mai sus: nu doar ca stergerile din sesiunea curenta se pierd, -dar mecanismul de stergere de linie devine structural imposibil, fiindca fiecare salvare a notei -reseteaza tot documentul la `STERS = 0`. In plus, dupa `actualizeaza_vanzari` `VANZARI.COD` s-a -schimbat, deci orice scriere ulterioara ancorata pe `cod` ar rata randul (`ID_VANZARE` ramane — -vezi A.1 din raportul precedent, reconfirmat la `:16024`). - -**(a') VFP scrie inainte + `actualizeaza_vanzari` primeste o garda.** -Respinsa. Ar cere un discriminator „stearsa ca linie" vs „stearsa cu documentul", care nu exista in -schema (`VANZARI_DETALII` nu are alt marcaj decat `STERS`/`ID_UTILS`/`DATAORAS`); orice euristica -pe `DATAORAS` e fragila. Si e Varianta A din raportul precedent — modificare in-place a unei -proceduri apelate de **orice** editare de nota cu `cod` in `vanzari`, din toata suita ROA. - -**(b) VFP scrie detaliile DUPA ce `finalizeaza_modificare_nota` s-a intors, apoi apeleaza -`pack_facturare.recalculeaza_totaluri_vanzari(id_vanzare, discount)`, in aceeasi tranzactie.** -**RECOMANDATA.** Verificat, nu presupus: - -- **tranzactia e inca deschisa** cand se intoarce `finalizeaza_modificare_nota`: aceasta ruleaza la - `ofacturare_comun.vc2:3826`, iar `do_inchide_tranzactie` abia la `:3828`; tranzactia e manuala pe - `gnHandle` (`_frm_base.vc2:255`), aceeasi conexiune ODBC pe care ruleaza `goExecutor`. Deci - scrierile de dupa intra in acelasi `COMMIT`/`ROLLBACK`, fara fereastra de inconsistenta. -- `actualizeaza_vanzari` ramane **neatinsa** — zero regresie pe ROAGEST/ROACONT. -- `PACK_CONTAFIN` ramane **neatins** — nu se recompileaza pachetul central de scriere a - documentelor. -- reset-ul `STERS = 0` ruleaza primul, iar VFP re-aplica dupa el starea autoritativa a liniilor. -- `VANZARI.COD` e deja rescris cand VFP scrie — de aceea toate scrierile se ancoreaza pe - `ID_VANZARE` (`lnIdVanzare`, citit din `crsfacturi` la `ofacturare_comun.vc2:3735`, stabil). - -**Atentie — (b) naiv are un defect.** `IncarcaArticoleFactura` incarca **doar `sters = 0`** -(`ofacturare_editare.prg:302`), deci liniile sterse la o editare anterioara nu sunt in -`crsArticoleFactura`: reset-ul le-a inviat, iar VFP nu le atinge, deci raman active. Corectia e in -**forma scrierii**, nu in Oracle — VFP scrie o stare completa, nu un delta: - -``` -1. UPDATE VANZARI_DETALII SET STERS = 1, ID_UTILS = ?, DATAORAS = SYSDATE - WHERE ID_VANZARE = AND STERS = 0 -- marcheaza tot -2. pentru fiecare linie pastrata din cursor, cu id_vanzare_det > 0: - UPDATE VANZARI_DETALII SET STERS = 0, CANTITATE = ?, PRET = ?, PRET_CU_TVA = ?, ... - WHERE ID_VANZARE_DET = -- invie doar ce ramane -3. pentru fiecare linie noua: INSERT INTO VANZARI_DETALII (...) -- ID_VANZARE_DET din trigger -4. pack_facturare.recalculeaza_totaluri_vanzari(, ) -``` - -Idiomul „marcheaza tot, invie ce ramane" e idempotent, nu are limita de 1000 de elemente intr-un -`IN`, nu cere lista separata de linii sterse, si pastreaza sterse liniile scoase la editari -anterioare. La pasul 2, `PRET_ACHIZITIE` se **omite** din `SET` (nu e in cursor — vezi 3). - -**(c) recalcul apelat din interiorul `finalizeaza_modificare_nota`** (recomandarea raportului -precedent, sectiunea B). **De abandonat.** Este incompatibila cu (b): daca recalculul ruleaza -inauntrul lui `finalizeaza_modificare_nota`, el vede liniile **vechi** (VFP nu le-a scris inca, -pentru ca nu poate scrie inainte de reset), deci ar produce exact totalurile de dinainte de editare -— tacut corecte ca formula, tacut gresite ca valoare. Nu e o varianta mai riscanta, e o varianta -gresita. - -**(c') procedura Oracle care primeste si liniile** (prin `VANZARI_DETALII_TEMP` sau o colectie) si -face si scrierea, si recalculul. Respinsa: reintroduce calea TEMP pe care planul a exclus-o explicit -(`plan_06_editare_factura.md:106-114`), cere o forma de parametru incomoda prin ODBC, si dubleaza -scrierea per-linie pe care planul a decis-o deja in VFP, dupa modelul `modifica_explicatie_articol` -(`PACK_FACTURARE.pck:14514-14522`). - -### Recomandare - -**Varianta (b), cu scrierea in forma „marcheaza tot, invie ce ramane".** Argumentul decisiv nu e -comoditatea, ci ca e **singura ordine in care reset-ul `STERS = 0` din `actualizeaza_vanzari` ramane -inofensiv fara sa modificam procedura** — iar procedura aceea e folosita azi de toata suita, pentru -un scop legitim (reeditarea unei note sterse) pe care nu-l putem sacrifica. - ---- - -## 5. Discountul de document (`VANZARI.DISCOUNT`) - -**Cine il scrie azi: nimeni, dupa emitere.** Verificat pe toata schema, nu doar pe `PACK_FACTURARE`: - -- `all_source` (`PACKAGE BODY`/`PROCEDURE`/`FUNCTION`/`TRIGGER`, `MARIUSM_AUTO`), cautand - `discount\s*=` exclusiv coloanele `discount_unitar|discount_tva|discount_evidentiat`: **niciun - `UPDATE ... SET DISCOUNT = ...` pe `VANZARI`.** Rezultatele sunt toate pe alte tabele - (`PACK_COMENZI.PROC_DISCOUNT`, `PACK_CRM.val_discount`, `PACK_OFERTARE.valdiscount`, ...). -- Toate cele 8 instructiuni `UPDATE VANZARI` din `PACK_FACTURARE` (`:5485, :5493, :5516, :5615, - :14817, :15387, :15397, :15509`) plus `modifica_date_factura` (`:14463-14512`, singura procedura - de „modifica antetul facturii" existenta) ating `STERS`/`FACTURAT`/`ID_FACT`/`AVIZE`/ - `SERIE_ACT`/`NUMAR_ACT`/`DATA_ACT`/`DATA_SCAD` — **niciuna `DISCOUNT`**. -- In VFP: cautare pe `COMUN\` dupa `set discount =` / `vanzari set ... discount` — **niciun - rezultat**. -- Trigger-ele pe `VANZARI` nu-l ating: `TRG_VANZARI_BEFOUPD` face doar audit pe - `NR_ACT`/`SERIE_ACT`/`DATA_ACT`/`DATA_SCAD` (`pack_audit.verifica_val`). - -Deci `VANZARI.DISCOUNT` e scris **o singura data in viata documentului**, la `INSERT`-ul din -`scrie_in_vanzari` (`:13621` in lista de coloane, `:13682` in `VALUES`, din `V_DISCOUNT_FACTURA`). -Nu exista nici procedura de modificare, nici cale VFP. - -Pe partea VFP valoarea e deja disponibila in memorie: cursorul `tvanz` are coloana `discount` -(`ofacturare_editare.prg:152`, `CreeazaCursorTvanzGol`), populata din `VANZARI` de -`IncarcaVanzareNota` (`:176`). - -### Recomandare: **parametru al procedurii noi**, nu `UPDATE` separat din VFP - -``` -recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, V_DISCOUNT IN NUMBER DEFAULT NULL) -``` - -cu semantica `V_DISCOUNT IS NULL` = „pastreaza valoarea curenta". Motive: - -1. **discountul si totalurile nu pot diverge.** Cu doua instructiuni separate din VFP, un esec pe - a doua (sau o omisiune la un viitor call-site) lasa `DISCOUNT` nou si totaluri calculate pe cel - vechi. Cu un parametru, e imposibil sa recalculezi cu un discount invechit. -2. procedura ramane utilizabila ca **recalcul pur** (fara al doilea argument) de oriunde altundeva - — de exemplu dintr-un script de backfill. -3. e o instructiune ODBC in minus pe drumul critic. - -Implementare: `V_DISCOUNT` se aplica in acelasi `UPDATE vanzari` final, -`discount = NVL(V_DISCOUNT, discount)`, iar valoarea folosita in agregare se citeste **inainte**, -ca `NVL(V_DISCOUNT, (select discount from vanzari where id_vanzare = V_ID_VANZARE))` — altfel -agregarea ar lucra pe discountul vechi. - ---- - -## 6. Coloanele care NU se recalculeaza — reconfirmat pe sursa proaspata - -`SERIE_INCASAT` / `NR_INCASAT` / `SUMA_INCASAT` / `TIP_INCASAT` (`:13777-13780`, scrise la -`:13945-13948`) vin din `pack_facturare.cserie_act_incasare` / `nnumar_act_incasare` / -`nsuma_incasare` / `ntip_doc_incasare`. - -Cautare exhaustiva a atribuirilor catre aceste 4 variabile in `PACK_FACTURARE.pck` — **7 rezultate, -toate in fluxul de emitere**: - -``` -1882-1886 cserie_act_incasare := NULL; nnumar_act_incasare := NULL; - ntip_doc_incasare := NULL; nsuma_incasare := NULL; (initializeaza_date_factura) -13102-13105 cserie_act_incasare := V_SERIE_ACT_INCASARE; nnumar_act_incasare := V_NUMAR_ACT_INCASARE; - ntip_doc_incasare := nTipIncasareChitanta; nsuma_incasare := 0; -13136 nsuma_incasare := nsuma_incasare + ... -13140,13144 ntip_doc_incasare := V_TIP / nTipIncasareBonFiscal; -``` - -Sursele lor (`V_SERIE_ACT_INCASARE`, `V_NUMAR_ACT_INCASARE`) sunt parametri ai emiterii unei -facturi-cu-incasare combinata. **Nu exista nicio tabela din care sa fie reconstituite la o editare -ulterioara** — singura urma persistenta sunt chiar cele 4 coloane din `VANZARI`, care ar fi -suprascrise cu `NULL` de o copiere naiva a `UPDATE`-ului. - -**Concluzie reconfirmata: procedura noua scrie 11 coloane** (`discount_tva`, `valoare_achizitie`, -`total_fara_tva`, `total_tva`, `total_cu_tva`, `valval`, `tvaval`, `totval`, `id_valuta`, `curs`, -`multiplicator`), **plus optional `discount`** (vezi 5). Cele 4 de incasare raman la valoarea de la -emitere. - ---- - -## 7. Semnatura propusa si scripturile de migrare - -### Declaratia din PACKAGE SPEC - -Se adauga imediat dupa `actualizeaza_vanzari` (`PACK_FACTURARE.pck:1187-1188`), langa procedurile -surori: - -```sql - PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, - V_DISCOUNT IN NUMBER DEFAULT NULL); -``` - -`recalculeaza_totaluri_vanzari` = **29 de caractere**, sub limita de 30 a lui Oracle 10.2/11 -(peste 30 ar da `ORA-00972`). Nu mai lungi numele. - -### Corpul (schita, compatibila 10.2) - -Constructii folosite: `SELECT INTO`, `UPDATE`, `DECODE`, `CASE`, `NVL`, `ROUND`, `MAX`, `SUM`, -`LEFT JOIN`, `UNION ALL`, `GROUP BY`, subinterogari inline. **Nimic din tabelul de incompatibilitati -din `scripturi-migrare-db.md`** — fara `LISTAGG`, `CONTINUE`, `REGEXP_COUNT`, `FETCH FIRST`, -`PIVOT`, `secventa.NEXTVAL` in atribuire. - -```sql - PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, - V_DISCOUNT IN NUMBER DEFAULT NULL) IS - lnDiscountFactura VANZARI.DISCOUNT%TYPE; - lnInValuta VANZARI.IN_VALUTA%TYPE; - lnDiscountEvidentiat VANZARI.DISCOUNT_EVIDENTIAT%TYPE; - lnDiscountTVA VANZARI.DISCOUNT_TVA%TYPE; - lnValoareAchizitie VANZARI.VALOARE_ACHIZITIE%TYPE; - lnTotalFaraTVA VANZARI.TOTAL_FARA_TVA%TYPE; - lnTotalTVA VANZARI.TOTAL_TVA%TYPE; - lnTotalCuTVA VANZARI.TOTAL_CU_TVA%TYPE; - lnValVal VANZARI.VALVAL%TYPE; - lnTVAVal VANZARI.TVAVAL%TYPE; - lnTotVal VANZARI.TOTVAL%TYPE; - lnIdValuta VANZARI.ID_VALUTA%TYPE; - lnCurs VANZARI.CURS%TYPE; - lnMultiplicator VANZARI.MULTIPLICATOR%TYPE; - lnPrecizieCalcul NUMBER(2) := pack_sesiune.getOptiuneFirma('PC'); - lnPreciziePretV NUMBER(2) := pack_sesiune.getOptiuneFirma('PPRETV'); - BEGIN - SELECT NVL(V_DISCOUNT, discount), in_valuta, NVL(discount_evidentiat, 0) - INTO lnDiscountFactura, lnInValuta, lnDiscountEvidentiat - FROM vanzari - WHERE id_vanzare = V_ID_VANZARE; - - -- acelasi bloc de agregare ca in scrie_in_vanzari (:13764-13931), cu trei substitutii: - -- VANZARI_DETALII_TEMP a -> VANZARI_DETALII a WHERE a.id_vanzare = V_ID_VANZARE AND a.sters = 0 - -- vanzari_detalii_temp c -> vanzari_detalii c WHERE c.id_vanzare = V_ID_VANZARE AND c.sters = 0 - -- pack_facturare.nin_valuta -> lnInValuta - -- pack_facturare.ndiscount_evidentiat -> lnDiscountEvidentiat - -- V_DISCOUNT_FACTURA -> lnDiscountFactura - -- fara coloanele de incasare (serie/nr/suma/tip) - SELECT ... INTO lnDiscountTVA, lnValoareAchizitie, lnTotalFaraTVA, lnTotalTVA, - lnTotalCuTVA, lnValVal, lnTVAVal, lnTotVal, - lnIdValuta, lnCurs, lnMultiplicator - FROM ( ... ); - - UPDATE vanzari - SET discount = lnDiscountFactura, - discount_tva = lnDiscountTVA, - valoare_achizitie = lnValoareAchizitie, - total_fara_tva = lnTotalFaraTVA, - total_tva = lnTotalTVA, - total_cu_tva = lnTotalCuTVA, - valval = lnValVal, - tvaval = lnTVAVal, - totval = lnTotVal, - id_valuta = lnIdValuta, - curs = lnCurs, - multiplicator = lnMultiplicator - WHERE id_vanzare = V_ID_VANZARE; - END recalculeaza_totaluri_vanzari; -``` - -Idempotenta: `SELECT` + `UPDATE ... WHERE id_vanzare = :id`, fara `INSERT` — rularea de doua ori pe -acelasi id da acelasi rezultat. - -**Fara handler `WHEN NO_DATA_FOUND THEN NULL`** pe modelul originalului: la editare, un `id_vanzare` -inexistent e o eroare reala care trebuie sa opreasca tranzactia, nu sa fie inghitita. (Primul -`SELECT INTO`, pe cheia primara, e singurul care poate ridica `NO_DATA_FOUND`.) - -### Scripturile de migrare - -Azi, 09.08.2026, in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\08` nu exista niciun script cu data de azi -(ultimele sunt `..._2026_08_08_01` si `..._2026_08_08_02`), deci **`NN` porneste de la `01`**. -`NN` e secventa unica pe zi, comuna tuturor prefixelor. - -**Un singur script**, fiindca S5 atinge un singur pachet si nimic altceva: - -``` -ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql -``` - -- prefix `ff_` — pachetul sta pe schema fiecarei firme; -- **un pachet sta singur in scriptul lui**: fara DDL de tabele si fara DML alaturi (nu e nevoie de - niciunul — nu se adauga coloane si nu se curata date); -- contine SPEC + BODY (SPEC-ul se schimba: declaratia noua), CRLF obligatoriu, antet de 4-5 randuri, - fara `select` de raportare, si se incheie cu - `exec pack_migrare.UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql');` + `commit;`; -- `versiune_db.txt` din radacina proiectului se muta pe `2026_08_09_01` (fara newline final). - -**Nu e nevoie de un script separat pentru `VVANZARI_ARTICOLE`** pentru S5 asa cum e proiectat aici -— dar vezi intrebarea 3 de mai jos, care ar cere unul (`NN = 02`, si atunci **inainte** de cel al -pachetului daca pachetul l-ar folosi; aici nu-l foloseste, deci ordinea e libera). - ---- - -## 8. Riscuri si intrebari deschise - -**R1 — Componentele de set sunt editabile in grid dar nu influenteaza totalurile. (mediu)** -`VVANZARI_ARTICOLE` nu expune `ID_VANZARE_SET`, deci S4 nu poate distinge componentele de liniile -normale; recalculul ia insa pretul/cantitatea din `VANZARI_SETURI`, nu din componente. Utilizatorul -modifica o componenta, apasa salvare, totalul nu se schimba. Tacut. -*Recomandarea mea:* pentru #6, **adauga `ID_VANZARE_SET` in `VVANZARI_ARTICOLE`** (script separat, -`ff_2026_08_09_02_COMUN_VVANZARI_ARTICOLE.sql`) si fa liniile cu `id_vanzare_set` nenul -**needitabile in grid**, cu o eticheta („linie din set"). Editarea seturilor e o functionalitate -proprie, nu o extindere gratuita a lui S4. Alternativa minimala, daca Marius nu vrea scriptul de -view: blocheaza intreaga factura care contine seturi — dar asta contrazice decizia din -`plan_06_editare_factura.md:183-186` („fara blocarea facturilor care le contin"). - -**R2 — Stergerea unei componente de set. (mic, dar urat)** -Cu idiomul „marcheaza tot, invie ce ramane", stergerea in grid a unei componente lasa capul de set -in `VANZARI_SETURI` si celelalte componente pe loc: totalul ramane neschimbat (vine din cap), dar -`VALOARE_ACHIZITIE` scade (se pierde `pret_achizitie`-ul componentei). Divergenta partiala. -*Recomandare:* acoperit de R1 — daca liniile de set sunt needitabile, cazul dispare. - -**R3 — `PRET_ACHIZITIE` NULL pe liniile noi anuleaza `VALOARE_ACHIZITIE` pe tot documentul. (mediu)** -`SUM(round(cantitate * pret_achizitie))` cu un singur operand NULL nu da NULL pe total (SUM ignora -NULL-urile), dar **linia noua nu contribuie deloc** — deci `VALOARE_ACHIZITIE` (baza de calcul a -marjei) subestimeaza sistematic dupa fiecare adaugare de linie. Coloana nu e in cursorul din grid si -nu are sursa la editare (la emitere vine din stoc/politica de pret). -*Recomandare:* la `INSERT`-ul liniei noi, VFP scrie `PRET_ACHIZITIE` cu pretul de achizitie curent -al articolului (acelasi lookup pe care il face `adauga_articol_factura_stoc`), sau, daca nu se poate -determina, cu `0` explicit si o avertizare in verificarile din S4b. **Nu lasa NULL tacut.** - -**R4 — Factura fara nicio linie da totaluri NULL, nu 0. (mic)** -Agregatele pe zero randuri intorc NULL; la emitere cazul nu poate aparea, la editare da. -*Recomandare:* nu modifica formula (ar diverge de original). Interzice in S4b salvarea unei facturi -cu zero linii active — e oricum un document invalid. - -**R5 — Linie cu valuta fara rand in `VANZARI_CURSURI`. (mic)** -`left join vanzari_cursuri vc on vc.id_vanzare = V_ID_VANZARE and vd.id_valuta = vc.id_valuta` -(`:13929-13930`): daca o linie ajunge cu o valuta pentru care documentul nu are curs, `vc.curs` e -NULL si `pret_ron` iese NULL. `CreeazaPoArticolNouTvd` primeste explicit valuta documentului -(`tnIdValutaDoc`, `ofacturare_editare.prg:356`), deci in fluxul proiectat nu ar trebui sa apara. -**NEVERIFICAT** ca S4 chiar transmite acel parametru pe toate caile de adaugare. -*Recomandare:* verificare in S4b, nu garda in Oracle. - -**R6 — `pack_sesiune.getOptiuneFirma` intoarce `''` la orice eroare. (mic)** -`PACK_SESIUNE` body `:128-131`: `WHEN OTHERS THEN lcValue := ''`. Atribuit intr-un `NUMBER(2)`, `''` -devine NULL, iar `ROUND(x, NULL)` da NULL. Comportament identic cu cel de la emitere — deci nu e o -regresie introdusa de S5, dar merita stiut daca apar totaluri NULL inexplicabile. -*Recomandare:* nimic de facut in S5; consemnat pentru depanare. - -**R7 — `ff_2026_08_08_01_COMUN_VVD_TOT.sql` aplicat in dev fara script pe disc. (de clarificat)** -Obiectul nu exista in `all_objects` sub niciun nume `VVD%`, deci probabil scriptul a creat altceva -sau a fost anulat ulterior. Fisierul lipseste din `SCRIPTURI_CLAR` -> nu ajunge la clienti. -*Recomandare:* intrebare pentru Marius, nu blocheaza S5. - -### Intrebari pentru Marius - -1. **Liniile de set (R1)** — le facem needitabile in grid, cu `ID_VANZARE_SET` adaugat in - `VVANZARI_ARTICOLE` printr-un al doilea script? *Recomandarea mea: da.* Fara asta, editarea unei - facturi cu seturi arata ca merge si nu merge. -2. **Discountul de document** — parametru al procedurii (`V_DISCOUNT ... DEFAULT NULL`), sau - `UPDATE VANZARI SET DISCOUNT` separat din VFP? *Recomandarea mea: parametru*, ca discountul si - totalurile sa nu poata diverge (vezi 5). -3. **`PRET_ACHIZITIE` pe linia noua (R3)** — se citeste din nomenclator/stoc la adaugare, sau se - scrie `0` cu avertizare? *Recomandarea mea: citit din nomenclator*, cu `0` doar ca ultima - rezerva, niciodata NULL. -4. **`VALVAL`/`TVAVAL`/`TOTVAL`** — raman in recalcul? *Recomandarea mea: da* (cost zero, fac parte - din acelasi `SELECT`; excluderea lor ar lasa facturile in valuta inconsistente). Confirmare - ceruta si in raportul precedent, inca neconfirmata. -5. **`ff_2026_08_08_01_COMUN_VVD_TOT.sql`** — script de lucru abandonat, sau lipseste din SVN? - ---- - -## Ce a ramas neverificat - -- **R5**: nu am verificat pe codul S4 in lucru ca `CreeazaPoArticolNouTvd` primeste efectiv valuta - documentului pe toate caile de adaugare de linie. -- Nu am rulat nimic in Oracle in afara de `SELECT`-uri de dictionar si de export — **niciun DDL, - niciun DML, niciun test de executie a procedurii propuse.** Corpul propus la 7 e schita, nu cod - compilat. -- Numarul de documente cu seturi in `MARIUSM_AUTO` (4) e din date de test si **nu constituie - dovada** pentru niciuna dintre afirmatiile de mai sus; toate concluziile sunt din cod. diff --git a/docs/cercetare/rec_s5_script_oracle.md b/docs/cercetare/rec_s5_script_oracle.md deleted file mode 100644 index 77a3881..0000000 --- a/docs/cercetare/rec_s5_script_oracle.md +++ /dev/null @@ -1,296 +0,0 @@ -# Verificare script Oracle S5 — PACK_FACTURARE.recalculeaza_totaluri_vanzari - -Data: 09.08.2026. Livrabil: `docs/ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql` (823433 octeti, -17231 randuri; 17010->17231 fata de `.pck`-ul sursa, +221 randuri de continut adaugat). - -Construit programatic dintr-un script PowerShell (nu retastat): citeste `PACK_FACTURARE.pck` -(export proaspat, scratchpad, 810960 octeti, 17011 randuri) ca octeti ASCII, insereaza declaratia -noua in SPEC dupa `actualizeaza_vanzari` si corpul nou in BODY dupa `actualizeaza_vanzari`, adauga -`CREATE OR REPLACE` pe cele doua linii de start (absente in exportul brut din `all_source`), -antetul si coada, si scrie rezultatul CRLF. Fiecare punct de insertie e verificat printr-un -assert pe textul exact al ancorei (throw daca nu se potriveste) — scriptul s-a oprit si a fost -corectat de doua ori in timpul lucrului (vezi „Erori prinse" mai jos), rularea finala a trecut -toate ancorele. - -## Ce s-a facut - -1. **PACKAGE SPEC** (`.pck:1187-1189`): dupa declaratia `actualizeaza_vanzari`, s-a inserat - `PROCEDURE recalculeaza_totaluri_vanzari(V_ID_VANZARE IN NUMBER, V_DISCOUNT IN NUMBER DEFAULT - NULL);` — text identic cu cel din brief. -2. **PACKAGE BODY** (`.pck:16015-16025`, dupa `END actualizeaza_vanzari;`): s-a inserat procedura - noua, corpul fiind blocul de agregare din `scrie_in_vanzari` (`.pck:13762-13954`) cu substitutiile - cerute, plus SELECT-ul de discount/in_valuta/discount_evidentiat inainte, plus `discount` in - UPDATE, fara handler de exceptie — toate exact ca in sectiunea 7 a specificatiei. -3. Antet de 6 randuri (4 randuri text + 1 rand `--` gol + titlu), fara referinte la planuri/rapoarte. -4. Coada: `exec pack_migrare.UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql'); commit;` - -## Verificari cerute, cu cifre - -**CRLF** — octeti LF fara CR inainte in fisierul final: **0**. - -**Nume sub 30 caractere** — `'recalculeaza_totaluri_vanzari'.Length` = **29**. Confirmat. - -**Diff-ul blocului de agregare** — original (`.pck:13762-13954`, 193 randuri, citat integral in -`rec_s5_proiectare_oracle.md` sectiunea 2) vs. blocul nou din procedura (extras din fisierul -livrat). Generat cu `diff -u -b` (ignora *doar* diferentele de cantitate de spatiu — necesar -pentru ca tot blocul a fost mutat cu un nivel de indentare mai putin, vezi nota de mai jos; `-b` -nu ascunde nicio diferenta de continut). Diff-ul integral: - -```diff ---- orig_block.txt (PACK_FACTURARE.pck:13762-13954) -+++ new_block.txt (recalculeaza_totaluri_vanzari, corpul agregarii) -@@ -1,5 +1,4 @@ -- -- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi -- begin -+-- Completare totaluri in vanzari din vanzari_detalii pentru a usura selectiile din fact_vfacturi - select DISC_TVA_VAL AS DISCOUNT_TVA, - VALOARE_ACHIZITIE, - a.suma_fara_tva_ron - a.disc_fara_tva_ron as TOTAL_FARA_TVA, -@@ -12,11 +11,7 @@ - a.disc_tva_val as TOTVAL, - id_valuta, - curs, -- multiplicator, -- pack_facturare.cserie_act_incasare as SERIE_INCASAT, -- pack_facturare.nnumar_act_incasare as NR_INCASAT, -- pack_facturare.nsuma_incasare AS SUMA_INCASAT, -- pack_facturare.ntip_doc_incasare as TIP_INCASAT -+ multiplicator - INTO lnDiscountTVA, - lnValoareAchizitie, - lnTotalFaraTVA, -@@ -27,29 +22,25 @@ - lnTotVal, - lnIdValuta, - lnCurs, -- lnMultiplicator, -- lnSerieIncasat, -- lnNrIncasat, -- lnSumaIncasat, -- lnTipIncasat -- FROM (select MAX(decode(pack_facturare.nin_valuta, -+ lnMultiplicator -+ FROM (select MAX(decode(lnInValuta, - 1, -- ROUND(a1.curs * NVL(V_DISCOUNT_FACTURA, 0) / -+ ROUND(a1.curs * NVL(lnDiscountFactura, 0) / - a1.multiplicator, - lnPreciziePretV), -- NVL(V_DISCOUNT_FACTURA, 0))) as DISC_FARA_TVA_RON, -- NVL(V_DISCOUNT_FACTURA, 0) as DISC_FARA_TVA_VAL, -- pack_facturare.nin_valuta AS IN_VALUTA, -- MAX(ROUND(decode(pack_facturare.nin_valuta, -+ NVL(lnDiscountFactura, 0))) as DISC_FARA_TVA_RON, -+ NVL(lnDiscountFactura, 0) as DISC_FARA_TVA_VAL, -+ lnInValuta AS IN_VALUTA, -+ MAX(ROUND(decode(lnInValuta, - 1, - ROUND(a1.curs * -- NVL(V_DISCOUNT_FACTURA, 0) / -+ NVL(lnDiscountFactura, 0) / - a1.multiplicator, - lnPreciziePretV), -- NVL(V_DISCOUNT_FACTURA, 0)) * -+ NVL(lnDiscountFactura, 0)) * - (a1.proc_tvav - 1), - lnPreciziePretV)) as DISC_TVA_RON, -- MAX(ROUND(NVL(V_DISCOUNT_FACTURA, 0) * -+ MAX(ROUND(NVL(lnDiscountFactura, 0) * - (a1.proc_tvav - 1), - lnPreciziePretV)) as DISC_TVA_VAL, - sum(pack_facturare.calculeaza_total_fara_tva_fact(a1.pret_ron, -@@ -57,7 +48,7 @@ - 1, - NVL(a1.discount_unitar_ron, - 0), -- pack_facturare.ndiscount_evidentiat, -+ lnDiscountEvidentiat, - a1.cantitate, - a1.pret_cu_tva, - a1.proc_tvav)) AS SUMA_FARA_TVA_RON, -@@ -66,7 +57,7 @@ - 1, - NVL(a1.discount_unitar_ron, - 0), -- pack_facturare.ndiscount_evidentiat, -+ lnDiscountEvidentiat, - a1.cantitate, - a1.pret_cu_tva, - a1.proc_tvav)) as SUMA_TVA_RON, -@@ -75,7 +66,7 @@ - 1, - NVL(a1.discount_unitar_val, - 0), -- pack_facturare.ndiscount_evidentiat, -+ lnDiscountEvidentiat, - a1.cantitate, - a1.pret_cu_tva, - a1.proc_tvav)) AS SUMA_FARA_TVA_VAL, -@@ -84,18 +75,18 @@ - 1, - NVL(a1.discount_unitar_val, - 0), -- pack_facturare.ndiscount_evidentiat, -+ lnDiscountEvidentiat, - a1.cantitate, - a1.pret_cu_tva, - a1.proc_tvav)) as SUMA_TVA_VAL, - sum(round(a1.cantitate * a1.pret_achizitie, - lnPrecizieCalcul)) AS VALOARE_ACHIZITIE, -- max(decode(pack_facturare.nin_valuta, 1, a1.id_valuta, 0)) as id_valuta, -- max(decode(pack_facturare.nin_valuta, 1, a1.curs, 1)) as curs, -- max(decode(pack_facturare.nin_valuta, 1, a1.multiplicator, 1)) as multiplicator -+ max(decode(lnInValuta, 1, a1.id_valuta, 0)) as id_valuta, -+ max(decode(lnInValuta, 1, a1.curs, 1)) as curs, -+ max(decode(lnInValuta, 1, a1.multiplicator, 1)) as multiplicator - from (select vd.id_vanzare_set, - (case -- when (pack_facturare.nin_valuta = 1 or -+ when (lnInValuta = 1 or - vd.id_valuta <> - pack_def.GetIdMonedaNationala()) then - ROUND(vc.curs * vd.pret / vc.multiplicator, -@@ -108,7 +99,7 @@ - vd.cantitate, - vd.diferenta, - (case -- when (pack_facturare.nin_valuta = 1 or -+ when (lnInValuta = 1 or - vd.id_valuta <> - pack_def.GetIdMonedaNationala()) then - ROUND(vc.curs * vd.discount_unitar / -@@ -132,8 +123,10 @@ - a.id_valuta, - a.pret_cu_tva, - a.pret_achizitie -- from VANZARI_DETALII_TEMP a -+ from VANZARI_DETALII a - where nvl(a.id_vanzare_set, 0) = 0 -+ and a.id_vanzare = V_ID_VANZARE -+ and a.sters = 0 - union all - select b.id_vanzare_set, - b.pret, -@@ -141,7 +134,7 @@ - b.cantitate, - 0 as diferenta, - b.discount_unitar, -- decode(pack_facturare.nin_valuta, -+ decode(lnInValuta, - 0, - pack_def.GetIdMonedaNationala(), - c.id_valuta) as id_valuta, -@@ -151,17 +144,19 @@ - 0, - c.pret_achizitie * c.cantitate / - b.cantitate)) as pret_achizitie -- from vanzari_detalii_temp c -+ from vanzari_detalii c - left join vanzari_seturi b - on b.id_vanzare_set = c.id_vanzare_set - where nvl(c.id_vanzare_set, 0) <> 0 -- and nvl(pack_facturare.nin_valuta, -1) > -1 -+ and c.id_vanzare = V_ID_VANZARE -+ and c.sters = 0 -+ and nvl(lnInValuta, -1) > -1 - group by b.id_vanzare_set, - b.pret, - b.cantitate, - b.discount_unitar, - b.pret_cu_tva, -- decode(pack_facturare.nin_valuta, -+ decode(lnInValuta, - 0, - pack_def.GetIdMonedaNationala(), - c.id_valuta)) vd -@@ -170,7 +165,8 @@ - and vd.id_valuta = vc.id_valuta) a1) a; - - update vanzari -- set discount_tva = lnDiscountTVA, -+ set discount = lnDiscountFactura, -+ discount_tva = lnDiscountTVA, - valoare_achizitie = lnValoareAchizitie, - total_fara_tva = lnTotalFaraTVA, - total_tva = lnTotalTVA, -@@ -180,14 +176,5 @@ - totval = lnTotVal, - id_valuta = lnIdValuta, - curs = lnCurs, -- multiplicator = lnMultiplicator, -- serie_incasat = lnSerieIncasat, -- nr_incasat = lnNrIncasat, -- suma_incasat = lnSumaIncasat, -- tip_incasat = lnTipIncasat -+ multiplicator = lnMultiplicator - where id_vanzare = V_ID_VANZARE; -- -- exception -- when NO_DATA_FOUND then -- null; -- end; -``` - -Diff-ul contine **exact**: cele 6 substitutii din tabelul din brief (`nin_valuta`->`lnInValuta` x11, -`ndiscount_evidentiat`->`lnDiscountEvidentiat` x4, `NVL(V_DISCOUNT_FACTURA, 0)`-> -`NVL(lnDiscountFactura, 0)` x6, cele doua perechi FROM/WHERE), eliminarea celor 4 coloane de -incasare din SELECT/INTO/UPDATE (cu fixarea virgulei ramase), adaugarea `discount = -lnDiscountFactura,` in UPDATE si eliminarea wrapper-ului `begin ... exception ... end;` (cerut -explicit: „Fara handler WHEN NO_DATA_FOUND THEN NULL"). **Nicio alta diferenta de continut.** - -Nota pe metoda: `-b` a fost necesar (nu `diff` simplu) pentru ca tot blocul, o data scos din -`begin...end;`-ul intern, a coborat cu un nivel de indentare (2 spatii) — o consecinta mecanica, -uniforma, a aplatizarii cerute de sectiunea 7, nu o modificare de continut. Fara `-b`, diff-ul ar -fi aratat *toate* liniile ca schimbate, desi doar spatiul de inceput difera pe liniile -neatinse de tabelul de substitutii (verificat separat: liniile fara nicio substitutie, ex. -`select DISC_TVA_VAL AS DISCOUNT_TVA,`, `VALOARE_ACHIZITIE,`, nu apar deloc in diff-ul de mai sus). - -**`;` in comentarii `--` in interiorul unei instructiuni** — 11 aparitii ale tiparului `--.*;` in -tot fisierul, **toate preexistente** in codul neatins (`scrie_incasari`, `contabilizeaza_articol` -etc., linii 5908-14852 din script), **niciuna** introdusa de mine (verificat separat: 0 in antetul -nou, 0 in declaratia SPEC noua, 0 in corpul noii proceduri). Riscul descris in -`scripturi-migrare-db.md` (SP2-0734) se aplica instructiunilor SQL terminate cu `;` -(`CREATE VIEW` etc.); intregul script de fata e un singur bloc `CREATE OR REPLACE PACKAGE`/ -`PACKAGE BODY` terminat cu `/`, deci riscul nu se aplica structural — dar cifra e cea ceruta. - -**Constructii peste Oracle 10.2** — scanat corpul noii proceduri pentru -`LISTAGG|CONTINUE|REGEXP_COUNT|FETCH FIRST|PIVOT|NEXTVAL`: **0 aparitii** pentru fiecare. -Identificatori: cel mai lung e `recalculeaza_totaluri_vanzari` (29) si `lnDiscountEvidentiat` (20) -— niciunul peste 30. - -**Numarul de linii** — fisier final: **17231** (17230 dupa convenția `wc -l`, care nu numara -ultimul rand fiindca fisierul, la fel ca sursa, nu are newline final); `.pck` original: -**17011** (17010 `wc -l`). Delta: +221 randuri adaugate (antet 7 + insert SPEC 3 + rand gol inainte -de `CREATE OR REPLACE PACKAGE BODY` 1 + procedura noua in BODY 205 + coada 4 + `CREATE OR REPLACE` -adaugat pe 2 linii existente, fara linii noi acolo). - -**Coloanele de incasare** — `serie_incasat`, `nr_incasat`, `suma_incasat`, `tip_incasat`: **0** -aparitii in SELECT/INTO/UPDATE-ul noii proceduri (verificat separat, izolat pe textul extras al -procedurii). Apar in continuare de 5 ori fiecare **in restul fisierului** — in `scrie_in_vanzari`, -neatinsa, unde e corect sa ramana (comportamentul de emitere nu se schimba). - -## Erori prinse si corectate in timpul lucrului (nu au ajuns in fisierul livrat) - -1. Prima rulare a omis complet linia `discount = lnDiscountFactura,` din `UPDATE` (am copiat doar - eliminarea coloanelor de incasare, am uitat adaugarea cerincetei separat in brief). Prins de - verificarea numerica (`lnDiscountFactura` aparea de 8 ori in loc de 9) inainte de a scrie - raportul; corectat si re-rulat. -2. Prima rulare a scris `PACKAGE "PACK_FACTURARE" is` si `PACKAGE BODY PACK_FACTURARE is` fara - prefixul `CREATE OR REPLACE` pe **linia de SPEC** (l-am adaugat doar pe linia de BODY). Ar fi - dat eroare de sintaxa la aplicare — `PACKAGE ... is` singur nu e o instructiune DDL valida. - Prins prin citirea directa a antetului fisierului scris; corectat si re-rulat. - -## Ce NU am facut / neverificat - -- Nu am rulat nimic in Oracle — niciun `sqlplus`, niciun DDL, niciun test de compilare a - pachetului. Corectitudinea sintactica dincolo de verificarile de mai sus (paranteze, virgule, - cuvinte cheie) nu e garantata decat prin inspectie si prin construirea mecanica din blocul - original deja compilat. -- Coada scriptului foloseste `UpdateVersiune('ff_2026_08_09_01_COMUN_PACK_FACTURARE.sql')` **cu** - extensia `.sql`, asa cum cere explicit brief-ul si `scripturi-migrare-db.md` („script_final = - numele fisierului, cu tot cu .sql"). Modelul citat (`ff_2026_08_06_10_...sql:17019`) foloseste - de fapt numele **fara** `.sql` — o inconsistenta intre precedent si regula scrisa. Am urmat - regula scrisa si instructiunea explicita, nu precedentul; semnalez discrepanta, nu am - „reparat-o" in modelul vechi (nu era in scop). -- Nu am atins `versiune_db.txt`, nu am scris in `D:\ROA\DATABASE\SCRIPTURI_CLAR`, nu am dat - commit — conform interdictiilor din brief. diff --git a/docs/cercetare/rec_tva_vanzari.md b/docs/cercetare/rec_tva_vanzari.md deleted file mode 100644 index 556fb97..0000000 --- a/docs/cercetare/rec_tva_vanzari.md +++ /dev/null @@ -1,341 +0,0 @@ -# Cercetare: TVA calculat vs salvat (#7) + denormalizare VANZARI (#8) - -Sursele principale sunt fisierele "curate" din arhiva de migrare Oracle -`D:\ROA\DATABASE\SCRIPTURI_CLAR\...` (nu in working copy VFP git — DDL/PL-SQL nu e versionat in -`ROAFACTURARE`), plus `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare.vc2` (working copy VFP, text -`.vc2` deja la zi). - -Cea mai recenta definitie **completa** a pachetului `PACK_FACTURARE` (COMUN, folosit de toate -produsele ROA care factureaza) e in -`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` (16948 linii). -Toate liniile citate mai jos fara alta mentiune sunt din acest fisier. - ---- - -## SUBIECT A — TVA calculat, nu salvat (#7) - -### 1. Structura VANZARI / VANZARI_DETALII (coloane pret/TVA) - -Nu exista `CREATE TABLE VANZARI_DETALII` in arhiva cautata (tabela e mai veche decat -`SCRIPTURI_CLAR`, care incepe efectiv din 2009; originea e probabil in -`D:\ROA\DATABASE\SCRIPTURI\2006-2008`, nu am parcurs exhaustiv acel arhiv de migrari vechi). -Coloanele efective au fost confirmate prin utilizarea lor in cod (view-uri + SQL dinamic VFP): - -**VANZARI_DETALII** (per linie articol): -- `PRET` — pret unitar (fara/cu TVA, in functie de flag) -- `DIFERENTA` — ajustare pret (folosita in `calculeaza_total_*_fact`) -- `DISCOUNT_UNITAR` -- `CANTITATE` -- `PRET_CU_TVA` — flag NUMBER(1): 1 = pretul de mai sus e cu TVA inclus, 0 = fara TVA - (`ff_2026_07_27_01_FACTURARE.sql:25,43` — `b.pret_cu_tva`) -- `PROC_TVAV` — procent TVA ca multiplicator (ex. 1.19), nu procent brut - (`ff_2026_07_27_01_FACTURARE.sql:26` — `b.proc_tvav`) -- `PRET_ACHIZITIE` (`ff_2026_07_27_01_FACTURARE.sql:105,130`) -- `ID_ARTICOL`, `ID_VALUTA`, `ID_POL` (politica de pret), `SERIE`, `STERS`, `ID_VANZARE`, - `ID_VANZARE_DET` (`ff_2026_07_27_01_FACTURARE.sql:11-76`) -- `TAXCODE` — adaugata `2022\03\ff_2022_03_24_01_COMUN_SAFT.sql:6` (cod taxa SAFT) -- `ID_JTVA_COLOANA_EX` — adaugata `2019\08\ff_2019_08_20_04_COMUN.sql:7` -- `LOT` — adaugata `2024\06\ff_2024_06_04_01_COMUN_FACTURARE.sql:3` - -**NU exista** o coloana de TVA calculata/salvata per linie (nici `valoare_tva`, nici -`pret_fara_tva` rezultat) — doar inputurile (`pret`, `pret_cu_tva` flag, `proc_tvav`), confirmand -exact ce zice todo #7: TVA e derivat, nu stocat. - -**VANZARI** (antet factura) — coloane denormalizate relevante TVA, toate adaugate prin -`2017\03\ff_2017_03_28_01_FACTURARE.sql:9-38`: -- `DISCOUNT_TVA` — "TVA DISCOUNT (DISCOUNT * MAX(PROC_TVA) ARTICOLE)" -- `TOTAL_FARA_TVA`, `TOTAL_TVA`, `TOTAL_CU_TVA` — totaluri pe document (denormalizate) -- `VALOARE_ACHIZITIE` -- vezi si Subiect B pt. `SERIE_INCASAT`/`NR_INCASAT`/`SUMA_INCASAT`/`TIP_INCASAT`/`AVIZE` - -### 2. Unde se calculeaza TVA-ul pe linie — toate locurile - -Calculul e centralizat in doua straturi Oracle, apelate de fiecare punct de consum (VFP nu face -calcul TVA local — doar construieste SQL dinamic care cheama functiile Oracle): - -- **`PACK_SESIUNE.calculeaza_pret_fara_tva/tva/cu_tva`** — motorul de rotunjire per-unitate de - pret (nu e in `PACK_FACTURARE`; pachetul `PACK_SESIUNE` nu a fost gasit definit separat in - arhiva cautata — cautare punctuala pe cateva luni din 2025/2026, fara succes; probabil e intr-un - script `COMUN_PACK_SESIUNE` mai vechi, netestat exhaustiv). -- **`PACK_FACTURARE.calculeaza_pret`** (linia 14557) — wrapper subtire peste cele 3 functii - `PACK_SESIUNE` de mai sus. -- **`PACK_FACTURARE.calculeaza_sume`** (linia 14631, spec 980) — calculeaza suma_fara_tva / - suma_tva / suma_cu_tva pe linie (cantitate * pret), delegand catre: - - **`calculeaza_total_fara_tva`** (linia 15745/15769) — delega la `pack_sesiune.calculeaza_total_fara_tva` - - **`calculeaza_total_tva`** (linia 15850/15874) — delega la `pack_sesiune.calculeaza_total_tva` - - **`calculeaza_total_cu_tva`** (linia 15638/15662) — delega la `pack_sesiune.calculeaza_total_cu_tva` - - variantele `_fact` (`calculeaza_total_fara_tva_fact` 15794, `calculeaza_total_tva_fact` 15899, - `calculeaza_total_cu_tva_fact` 15687) au **formula proprie inline** (nu delega la - `pack_sesiune`), documentata explicit in cod ca fiind "folosita in view-ul - fact_vrap_centralizator_fact" (comentarii 15686, 15744, 15793, 15848, 15897). - - Formula `_fact` (exemplu `calculeaza_total_tva_fact`, 15899-15949) e explicit ROUND-based, cu - ramuri separate pentru `discount_evidentiat` — aici e punctul central de rotunjire per linie. - -- **Puncte de CONSUM ale acestor functii** (unde efectiv se calculeaza TVA afisat/raportat): - - Views `fact_vrap_fact_articole` si `fact_vrap_articole_vandute` - (`ff_2026_07_27_01_FACTURARE.sql:18-44, 131-196` — apeleaza - `calculeaza_total_fara_tva`/`calculeaza_total_tva` direct in `SELECT`) - - Raport VFP dinamic: `COMUN\programe\oproceduri_rapoarte_fact.prg:581-590` — SQL construit in - VFP apeleaza direct `pack_sesiune.calculeaza_pret_cu_tva(...)` si - `pack_sesiune.calculeaza_total_cu_tva(...)` pentru listare/relistare rapoarte articole vandute. - - `PACK_FACTURARE.scrie_in_vanzari` (13468) si `finalizeaza_avize_lucrare` (14807) — calculeaza - si scriu `VANZARI.TOTAL_FARA_TVA`/`TOTAL_CU_TVA` folosind `calculeaza_total_fara_tva_fact` in - subquery-uri (13716-13786, 14965-15008). - - `verifica_total_document` (16009) — vezi punctul 5, verifica totalul calculat vs. cel din - notele contabile si genereaza o corectie. - - Nu am gasit un apel VFP direct catre `calculeaza_pret(` sau `calculeaza_sume(` in working copy - `ROAFACTURARE`/`COMUN` (grep pe nume exact, fara rezultate) — deci formularul de introducere - factura in VFP nu recalculeaza local pretul/TVA-ul linie cu linie prin apel explicit de - procedura; cel mai probabil articolele + preturile lor (deja cu `pret`, `pret_cu_tva`, - `proc_tvav`) vin dintr-un cursor Oracle (`PACK_FACTURARE.cursor_preturi`, spec 335, body 2121) - populat cand se adauga articolul, iar TVA vizibila in grid e calculata la afisare din acele - coloane brute — nu am gasit expresia VFP exacta (`cursor_preturi` e ~500 linii, nu am parcurs - linie cu linie in bugetul acestei cercetari). - -### 3. Ce inseamna "preturi_cu_tva" / `pret_cu_tva` - -- Pe linie: `VANZARI_DETALII.PRET_CU_TVA` — NUMBER(1), 0/1, transmis ca parametru `V_PRET_CU_TVA` - / `V_PRET_ARE_TVA` la toate functiile de calcul de mai sus (controleaza care ramura de formula - se aplica — pornind de la pret cu TVA sau fara TVA). -- In grid-ul VFP exista o coloana **checkbox** `cPret_cu_tva` in - `D:\ROA\ROAFACTURARE\Clase\ofundal_facturare.vc2:696-699` (`_grdrow2.cPret_cu_tva...`) — probabil - afiseaza/permite editarea flagului per linie in formular. -- **Nu am gasit** coloana `PRET_CU_TVA` (sau similara) direct pe `CRM_POLITICI_PRETURI` in - scripturile de migrare cautate (am cautat `ALTER TABLE CRM_POLITICI_PRETURI ADD`, fara hit - pe acest nume) — deci originea exacta a valorii implicite per politica de pret ("politica are - bifat 'preturi fara TVA'", cum descrie todo #7) nu e confirmata cu `fisier:linie`; e probabil - citita/propagata in `PACK_FACTURARE.cursor_preturi` (2121) sau - `citeste_setari_pol_pret` (spec 324, body 2025) cand se adauga articolul pe factura — nu am - parcurs acele corpuri in detaliu (buget de cercetare). - -### 4. Locuri de atins daca s-ar salva `pret_cu_tva`/`valoare_tva` per linie real (nu calculat) - -Enumerare pe baza punctelor de consum gasite mai sus: - -1. **DDL**: `ALTER TABLE VANZARI_DETALII ADD (valoare_tva, pret_fara_tva_calculat, ...)` — coloane - noi + migrare date istorice. -2. **`PACK_FACTURARE`** (Oracle, `ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql`): - - `adauga_articol_factura` (spec 529, body 4972) — punctul unde se insereaza linia in - `VANZARI_DETALII_TEMP`; ar trebui sa scrie valoarea (eventual editata de user) in loc s-o - lase doar pe `pret`/`pret_cu_tva`/`proc_tvav`. - - `calculeaza_sume` (14631) — daca valoarea e editabila, aceasta procedura ar trebui sa - citeasca valoarea salvata in loc s-o recalculeze, sau sa fie ocolita. - - `scrie_in_vanzari` (13468) si `finalizeaza_avize_lucrare` (14807) — subquery-urile care insumeaza - `calculeaza_total_fara_tva_fact`/`calculeaza_total_tva_fact` pe toate liniile - (13716-13786, 14965-15008) ar trebui sa insumeze coloana noua in loc s-o recalculeze. - - `verifica_total_document` (16009) — logica de reconciliere total-vs-note-contabile ar trebui - ajustata (vezi punct 5) daca totalul nu se mai deriva strict din formula. -3. **Views Oracle**: `fact_vrap_fact_articole`, `fact_vrap_articole_vandute` - (`ff_2026_07_27_01_FACTURARE.sql:10-257`), `fact_vfacturi`/`fact_vfacturi2` (vezi Subiect B #11) - — toate ar trebui sa citeasca noua coloana in loc de `calculeaza_total_*`. -4. **VFP**: `COMUN\programe\oproceduri_rapoarte_fact.prg:581-590` — SQL-ul de raport care apeleaza - direct `pack_sesiune.calculeaza_pret_cu_tva`/`calculeaza_total_cu_tva`. -5. **VFP grid formular**: `D:\ROA\ROAFACTURARE\Clase\ofundal_facturare.vc2` (coloana - `cPret_cu_tva` + coloanele de pret/valoare din grid — nu identificate exhaustiv, cautare - punctuala doar pe flag). -6. **Rapoarte `.frx`** care afiseaza TVA pe linie de factura (ex. `usr_factura*.fr2` — 25 de - fisiere gasite cu referinta la `PACK_FACTURARE`, listate la cautarea initiala; nu au fost - deschise individual). - -Estimare: minim **6 zone distincte** (DDL, pachet Oracle ~4 proceduri, 3-4 views, 1 program raport -VFP, grid formular, rapoarte `.frx`) — consistent cu observatia ca e o schimbare "de volum", nu -locala. - -### 5. Mecanism existent de ajustare/rotunjire - -**Da, exista, dar la nivel contabil, nu la nivel de linie facturata / vizibil userului.** - -`PACK_FACTURARE.verifica_total_document` (linia 16009-16188+) compara totalul FTVA/TVA asteptat -(`pack_facturare.ntotftva`, populat din VFP la `pnTotalFtva`/`Thisform.nbazaron`) cu suma reala din -notele contabile generate (`ACT_TEMP`, grupate pe conturi `4111`/`4427`/`418`/`4428`). Daca difera -(16082-16083: `NVL(pack_facturare.ntotftva,0) <> V_TOTFTVA_VER`), calculeaza diferenta -`pack_facturare.ndifftva := pack_facturare.ntotftva - V_TOTFTVA_VER` (16085) si **insereaza automat -o linie de corectie in `ACT_TEMP`** (16086-16188, INSERT cu `suma => pack_facturare.ndifftva`) — -adica ajustarea de rotunjire se absoarbe silentios in nota contabila, nu apare ca linie editabila -pe factura si nu se reflecta in `VANZARI_DETALII`. Aceasta e probabil exact mecanismul care face ca -utilizatorul sa nu poata corecta manual TVA-ul afisat: rotunjirea se "repara" doar in contabilitate, -dupa fapt. - ---- - -## SUBIECT B — Denormalizare VANZARI, bug facturi din avize + numerar (#8) - -### 6. Locatia `PACK_FACTURARE` - -Nu exista fisier `.pck`/`.sql` cu acest pachet in working copy `ROAFACTURARE` (nici in `COMUN/` -local) — **e in afara working copy-ului VFP**, in arhiva DDL/PL-SQL Oracle -`D:\ROA\DATABASE\SCRIPTURI_CLAR\`. Cea mai recenta versiune completa (16948 linii): - - `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_23_04_COMUN_PACK_FACTURARE.sql` - -(exista si un diff mai nou, doar pe view-uri, `2026\07\ff_2026_07_27_01_FACTURARE.sql` — vezi #11). -Istoricul complet de modificari e in `SCRIPTURI_CLAR\\\ff_..._COMUN_PACK_FACTURARE.sql` -respectiv `..._FACTURARE.sql` (zeci de fisiere, 2006-2026). - -### 7. Procedura care scrie in VANZARI valorile denormalizate - -**`PACK_FACTURARE.scrie_in_vanzari`** (spec linia 894, body **linia 13468-13908**) — apelata din -`finalizeaza_factura` (linia **14740**). Face `UPDATE VANZARI SET ...` cu (13886-13898): - -``` -total_fara_tva = lnTotalFaraTVA, -... -total_cu_tva = lnTotalCuTVA, -... -serie_incasat = lnSerieIncasat, -nr_incasat = lnNrIncasat, -suma_incasat = lnSumaIncasat, -tip_incasat = lnTipIncasat -``` - -unde `lnSerieIncasat`/`lnNrIncasat`/`lnSumaIncasat`/`lnTipIncasat` sunt populate (13727-13730) din -variabilele **de pachet** `pack_facturare.cserie_act_incasare`, `.nnumar_act_incasare`, -`.nsuma_incasare`, `.ntip_doc_incasare` (declarate 179-182). - -O a doua ramura echivalenta exista in **`finalizeaza_avize_lucrare`** (spec 1011, body -**14807-15176**), care face acelasi UPDATE (15124-15130) — pentru ramura "avize pe lucrare". - -Variabilele de pachet `cserie_act_incasare`/`nnumar_act_incasare`/`ntip_doc_incasare`/ -`nsuma_incasare` sunt setate **doar** de **`PACK_FACTURARE.scrie_incasari`** (spec 864, body -**13070-13139**), apelata condiționat (`IF V_LISTA_INCASARE IS NOT NULL`) din: -- `scrie_factura2` — linia **6178** (ramura factura normala / comanda / contract) -- `scrie_factura_avize` — linia **7008** (ramura **factura din aviz**) - -Sunt resetate la `NULL` in `initializeaza_date_factura` (comentariu 1384-1386, cod la -**1876-1880**) — fix explicit din 03.07.2020: *"ramaneau completate pe facturile urmatoare de la o -factura anterioara"*. - -`VANZARI.AVIZE` (seria/numarul avizelor facturate) e scris de -**`scrie_corespondente_vanzari`** (spec 1057, body **15421-15457**, comentariu la linia **15445**: -*"Completez VANZARI.AVIZE redundant, pentru a nu face mai rapid fact_vfacturi"*) — nu am confirmat -in acest buget de cercetare din ce apeleaza `finalizeaza_factura` daca `scrie_corespondente_vanzari` -ruleaza necondiționat pe toate tipurile sau doar pe unele (`V_TIP` e parametru) — merita verificat -punctual daca se investigheaza bug-ul mai departe. - -### 8. Coloanele denormalizate din VANZARI si ramura care le populeaza - -Toate adaugate prin `2017\03\ff_2017_03_28_01_FACTURARE.sql:9-38` (comentariu fisier, linia 1-4: -*"adaugare coloane in vanzari pentru denormalizarea join-urilor din fact_vfacturi"*): - -| Coloana | Comentariu DB (linia 44-54 din script) | Populata de | -|---|---|---| -| `DISCOUNT_TVA` | TVA DISCOUNT (DISCOUNT * MAX(PROC_TVA) ARTICOLE) | `scrie_in_vanzari` | -| `VALOARE_ACHIZITIE` | Valoare la pret achizitie articole | `scrie_in_vanzari` | -| `TOTAL_FARA_TVA` | Total fara TVA lei | `scrie_in_vanzari` (13886), `finalizeaza_avize_lucrare` (15124) | -| `TOTAL_TVA` | Total TVA lei | idem | -| `TOTAL_CU_TVA` | Total cu TVA lei | `scrie_in_vanzari` (13888), `finalizeaza_avize_lucrare` (15126) | -| `SERIE_INCASAT` | Seria chitanta/bon fiscal | `scrie_in_vanzari` (13895), din `pack_facturare.cserie_act_incasare` (setat de `scrie_incasari`) | -| `NR_INCASAT` | Nr chitanta/bon fiscal | idem (13896) | -| `SUMA_INCASAT` | Suma chitanta/bon fiscal | idem (13897) | -| `TIP_INCASAT` | 11=CHITANTA, 2=BON FISCAL | idem (13898); vezi si `nTipIncasareCardBancar`=3, `nTipIncasareTichete`=5 | -| `AVIZE` | Serie/numar avize facturate (max 1000 caractere, comentariu la linia 1490) | `scrie_corespondente_vanzari` (15421) | - -### 9. Tipurile de factura/aviz si ramificarea codului - -Din `VANZARI.TIP` (CASE explicit in view `fact_vfacturi2`, -`ff_2017_03_28_01_FACTURARE.sql:89-171`) — cateva valori cheie: -`1`=POLITICA PRETURI, `2`=CONTRACT, `3`=COMANDA, **`4`=FACT. DIN AVIZ**, `21`=AVIZ PE BAZA DE -COMANDA, `24`=AVIZ DE RETUR, `43`=BON FISCAL MAGAZIN, etc. (lista completa la liniile citate). - -Ramificare in VFP, `D:\ROA\ROAFACTURARE\COMUN\clase\ofacturare.vc2`, metoda -**`do_scrie_factura`** — exista **doua copii aproape identice** ale acestei logici, in doua clase -diferite (confirmat via `vfp_symbols.ps1 -Where`): -- `frm_facturare_articole.do_scrie_factura` — **liniile 13981-14339** -- `frm_facturare_articole2.do_scrie_factura` — **liniile 18004-18331** - -Structura `DO CASE` (identica in ambele, ex. clasa 1 la liniile 14067-14174): -- `poDate.eProforma = 1` → `{call pack_facturare.scrie_proforma(...)}` (14071) -- `poDate.Tip = 4` → **`{call pack_facturare.scrie_factura_avize(...)}`** (14103) — "facturare din - aviz" (comentariu 14086-14087) -- `poDate.Tip IN (3,21,25,28,42,47)` → `{call pack_facturare.scrie_factura2(...)}` (14130) — - "facturare pe baza de comanda / avize pe baza de comanda" -- `Otherwise` → `{call pack_facturare.scrie_factura2(...)}` (14158) — politica de preturi/contract - -Inainte de asta, lista de incasare `lcListaIncasare` se construieste (14012-14038) din -`poDate.ntip_incasare` (11=chitanta, 2=bon fiscal, 3=POS/card), comun tuturor ramurilor. - -### 10. Ramura "factura din aviz" + "achitata numerar" — ce ar trebui sa scrie si ipoteza de cauza - -**Ce se intampla, pas cu pas** (`Tip = 4`, `ntip_incasare` in (11,2,3)): - -1. VFP (`ofacturare.vc2:14012-14038`) construieste `lcListaIncasare` de forma - `'11||;'` (chitanta) sau `'2|...'`/`'3|...'` (bon fiscal/card) — **daca** - `ntip_incasare` nu e in (11,2,3), `lcListaIncasare = [NULL]` (literal SQL NULL). -2. VFP construieste `lcSql = {call pack_facturare.scrie_factura_avize(pnDiscount, serie_chit, - nr_incasare, lcListaIncasare, id_delegat, id_masina, id_facturare, listare_detaliata, - dataora_exp, id_agent, text_aditional, discount_evidentiat, param_aditional, ?@nid_vanzare)}` - (14103-14115) — semnatura corespunde exact cu procedura Oracle activa - `scrie_factura_avize` (linia **6675-7041**, care NU are `V_TOTFTVA`/`V_TOTTVA` ca prime - argumente, spre deosebire de `scrie_factura2` — asta e corect, nu e discrepanta de parametri). -3. In Oracle, `scrie_factura_avize` (7007-7012): `IF V_LISTA_INCASARE IS NOT NULL THEN - pack_facturare.scrie_incasari(...)` — deci **doar daca** `lcListaIncasare` nu e literalul - `NULL` se seteaza variabilele de pachet `cserie_act_incasare`/etc. -4. `scrie_factura_avize` seteaza `pack_facturare.clistaid_avize := ...V_LISTAID` (7020) — lista de - ID-uri de avize facturate, folosita ulterior de `scrie_corespondente_vanzari` pentru - `VANZARI.AVIZE`. -5. `scrie_factura_avize` cheama `finalizeaza_factura` (7026-7034), care cheama `scrie_in_vanzari` - (14740) → scrie `serie_incasat`/`nr_incasat`/`suma_incasat`/`tip_incasat` din variabilele de - pachet setate la pasul 3. - -**La nivel de cod citit, lantul pare corect cablat** — parametrii trec prin, semnaturile se -potrivesc, iar cele doua clase VFP (`frm_facturare_articole` si `frm_facturare_articole2`) au -logica identica pentru aceasta ramura. - -**IPOTEZA (cauza posibila a bug-ului, nedemonstrata prin citire de cod — necesita investigatie -suplimentara/testare)**: -- Daca ordinea reala de operatii difera de `ordine_operatii_facturare.txt` (ex. daca intre pasul 3 - si pasul 5 se mai apeleaza `initializeaza_date_factura` pentru alt document/lucru din aceeasi - sesiune, inainte ca `finalizeaza_factura` sa apuce sa citeasca variabilele de pachet), fix-ul din - 03.07.2020 (linia 1876-1880, reset la NULL) ar putea sterge datele de incasare **inainte** ca - `scrie_in_vanzari` sa le foloseasca — dar nu am gasit in codul citit un asemenea apel intercalat. -- Alternativ: daca pe ramura aviz `scrie_corespondente_vanzari` (care scrie `VANZARI.AVIZE`) nu e - apelata necondiționat din `finalizeaza_factura` pentru `TIP=4` (nu am verificat corpul complet al - `finalizeaza_factura`, liniile 14723-14807, dincolo de apelul la `scrie_in_vanzari`) — merita - verificat explicit daca acel apel exista si e neconditionat de tip. -- Nu am verificat daca exista vreo diferenta intre `scrie_factura_avize` si - `scrie_factura_avize_retur` (spec 667, alta ramura pentru tip retur din aviz) in privinta - apelului `scrie_incasari`/`scrie_in_vanzari` — posibil ca bug-ul sa fie specific ramurii de retur, - nu celei simple. - -Recomandare pentru pasul urmator (daca se investigheaza mai departe): instrumentare/breakpoint pe -`scrie_in_vanzari` (13468) intr-un mediu de test, pentru o factura Tip=4 platita numerar, verificand -valorile efective ale `pack_facturare.cserie_act_incasare`/`nnumar_act_incasare`/`nsuma_incasare`/ -`ntip_doc_incasare` chiar inainte de UPDATE (13886-13898). - -### 11. Cele doua view-uri de facturi - -- **`fact_vfacturi`** — view-ul "original" (pe model relational, cu join-uri catre `VANZARI_DETALII` - / `ACT` / etc., fara denormalizare). Redefinit de multe ori de-a lungul timpului; cea mai recenta - gasita: `D:\ROA\DATABASE\SCRIPTURI_CLAR\2023\11\ff_2023_11_17_01_COMUN.sql` (si - `2023\02\ff_2023_02_08_01_COMUN.sql`) — nu am deschis continutul exact in acest buget. -- **`fact_vfacturi2`** — view-ul cu totaluri **denormalizate din VANZARI** (`total_fara_tva`, - `total_tva`, `total_cu_tva`, `serie_incasat`, `nr_incasat`, `suma_incasat`, `tip_incasat`, - `avize` citite direct din coloanele `VANZARI`, nu recalculate din `VANZARI_DETALII`/`ACT`). - Definit initial in **`D:\ROA\DATABASE\SCRIPTURI_CLAR\2017\03\ff_2017_03_28_01_FACTURARE.sql:59-236`**, - cu comentariul explicit (linia 3): *"View fact_vfacturi2 - temporar, urmand a inlocui view-ul - fact_vfacturi, dupa completarea coloanelor din vanzari pentru datele existente deja"*. - -Separat, exista si o a doua pereche de view-uri, mai recenta si mai granulara (pe linie de -articol, nu pe factura): **`fact_vrap_fact_articole`** / **`fact_vrap_articole_vandute`**, definite -in `D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\07\ff_2026_07_27_01_FACTURARE.sql:10-257` — acestea NU -citesc din coloane denormalizate, ci calculeaza TVA live prin `pack_facturare.calculeaza_total_*` -(vezi Subiect A #2). Nu sunt aceleasi cu perechea mentionata in cerinta (care pare sa se refere la -`fact_vfacturi`/`fact_vfacturi2`), dar sunt relevante daca se cauta "view-ul cu totaluri din -vanzari" generic. - ---- - -## Note metodologice - -- `PACK_SESIUNE` (motorul de rotunjire per-pret, apelat de `PACK_FACTURARE`) nu a fost gasit - definit ca fisier separat in cautarile punctuale facute (cateva luni din 2025-2026); daca se - continua investigatia pe rotunjire, merita o cautare dedicata `create or replace package - pack_sesiune` in `D:\ROA\DATABASE\SCRIPTURI_CLAR`. -- Arhiva `D:\ROA\DATABASE\SCRIPTURI_CLAR` e foarte mare (mii de fisiere, 2009-2026); cautarile de - mai sus au fost tintite (nume de coloane/proceduri cunoscute), nu exhaustive — un `grep` complet - pe intreg arhivul repetat timeout la 20s in unele incercari initiale. -- Nu am gasit apeluri catre `PACK_FACTURARE` din `D:\ROA\ROAFACTURARE` propriu-zis (in afara - `COMUN\clase\ofacturare.vc2`) — pachetul e consumat exclusiv prin acea clasa si prin - `COMUN\programe\oproceduri_rapoarte_fact.prg`. diff --git a/docs/cercetare/rec_view_articole_vanzare.md b/docs/cercetare/rec_view_articole_vanzare.md deleted file mode 100644 index fbc002c..0000000 --- a/docs/cercetare/rec_view_articole_vanzare.md +++ /dev/null @@ -1,164 +0,0 @@ -# Proiectare view Oracle pentru liniile de articole ale unei vanzari (VVANZARI_ARTICOLE) - -Cercetare + proiectare, read-only pe baza. Decizia lui Marius (08.08.2026): view dedicat, varianta B -din `rec_review_ancorare_s4.md` (respinsa atunci doar pentru ca insemna migrare de schema - acum -aprobata). Inlocuieste lista de 20 coloane + join pe 4 tabele din `IncarcaArticoleFactura` -(`COMUN\programe\ofacturare_editare.prg:201-208`). - -## A. Precoditia VERSIUNE - -`MARIUSM_AUTO` e la zi **pentru schema firmei (`ff_`)** pe orice ar putea atinge `VANZARI_DETALII`/ -facturare: toate scripturile `ff_` din 2015 incoace apar in `VERSIUNE`, inclusiv cele mai recente -patru (`ff_2026_08_06_09/10/11/12`, comanda/contract, `PACK_FACTURARE`, `FACT_VFACTURI`, -`VANZARI_BACKFILL`). Diferenta gasita fata de `SCRIPTURI_CLAR` (452 de fisiere, din care 14 `ff_`) -e integral din 2009-2014 (dinainte de generalizarea `UpdateVersiune`) plus scripturi de diagnostic -fara prefix de tracking (`DIAG_SPATIU_*`, ad-hoc-uri fara nume standard) - niciunul din ele nu -atinge `VANZARI`/`VANZARI_DETALII`/facturare. Verdict: **precoditia trece**, sursa `MARIUSM_AUTO` e -de incredere pentru acest DDL. - -## B. Ce exista deja - niciun candidat direct refolosibil, dar un precedent util - -Cautat in `all_views` (MARIUSM_AUTO) orice view pe `VANZARI_DETALII`/liniile unei vanzari: -`VVANZARI_DETALII`, `VVANZARI_DETALII_TOT`, `FACT_VFACTURI_DETALII` sunt cele relevante. - -- **`FACT_VFACTURI_DETALII`** (exportat integral) e cel mai apropiat candidat structural - selecteaza - direct din `vanzari_detalii`, cu join-uri catre `nom_articole`/`nom_gestiuni`/`nom_valute` ca in - proiectarea de mai jos. **Nu e reutilizabil ca atare**: `pret` si `discount_unitar` sunt - RECALCULATE la cursul valutar curent (`ROUND(NVL(g.curs,1)*NVL(a.pret,0)/NVL(g.multiplicator,1), - pack_sesiune.getoptiunefirma('PPRETV'))`, apel de functie PL/SQL per coloana per rand), construit - pentru **afisare/tiparire** facturi, nu pentru editare. Pagina de editare (#6) trebuie sa lucreze - pe valorile RAW stocate, ca la salvare (S5) sa scrie inapoi exact ce a citit - un `pret` deja - convertit ar strica exact acest contract. Confirma insa tiparul de join corect (articol/gestiune/ - valuta) si ca genul asta de view exista deja in familia `FACT_*` pentru alt scop. -- **`VVANZARI_DETALII`/`VVANZARI_DETALII_TOT`**: alt scop (afisare generica vanzari + utilizatori + - politici de pret), nu au `pret_cu_tva`, `cont`, `id_valuta`, `id_gestiune`, `taxcode`, `lot` - - nepotrivite. - -Niciunul nu inlocuieste nevoia unui view nou - se continua cu proiectarea. - -## C. Numele: `VVANZARI_ARTICOLE` - -Verificat liber in `all_objects` (MARIUSM_AUTO). 17 caractere, sub limita de 30 (Oracle 10.2). - -**Criteriul lui Marius (08.08.2026)**: numele trebuie sa pastreze prefixul familiei de vanzari, -`vvanzari_*`, pentru ca el se uita la view-uri **alfabetic** si vrea sa vada dintr-o privire ca tine -de vanzari. La o listare alfabetica: `VVANZARI_ARTICOLE`, `VVANZARI_DETALII`, -`VVANZARI_DETALII_TOT`, `VVANZARI_TOT`. - -Numele analog conventiei surorilor de pe acelasi formular (`vact_tot`, `vrul_tot`, -`vrul_obinv_tot`) ar fi fost `vvanzari_detalii_tot`, dar e **deja ocupat** (alt view, B mai sus). - -Numele de lucru din prima varianta a fost `VVD_TOT` (`v` + abreviere + `_tot`, aliniat cu aliasul -VFP `tvd`), respins de Marius pe criteriul de mai sus: nu se citea ca facand parte din familie si -cadea in alta parte a listei alfabetice. - -## D. Coloanele - RAW, fara filtru STERS in view - -Cele 20 de coloane consumate azi + **`id_vanzare` adaugat**: lista din -`ofacturare_editare.prg:201-203` filtreaza pe `vd.id_vanzare` dar nu-l intoarce niciodata ca si -coloana - omisiune reala, semnalata in misiune, acum corectata in view. - -- **Fara conversie valutara, fara valori calculate** (spre deosebire de `FACT_VFACTURI_DETALII`) - - editarea scrie inapoi exact ce citeste. -- **`STERS` ramane in view ca si coloana, dar FARA filtru `WHERE sters=0` in definitie** - acelasi - tipar ca `VACT_TOT`/`VRUL_TOT`/`VRUL_OBINV_TOT` (niciunul nu filtreaza `sters` in view, apelantul - o face explicit). Apelantul de azi (`IncarcaArticoleFactura`) deja are `WHERE ... vd.sters = 0` - - ramane neschimbat, doar `FROM vanzari_detalii vd ... WHERE vd.id_vanzare=... AND vd.sters=0` devine - `FROM vvanzari_articole vd WHERE vd.id_vanzare=... AND vd.sters=0`. - -## E. Ce s-a respins: valorile calculate `CALCULEAZA_TOTAL_FARA_TVA_FACT`/`_TVA_FACT` - -Ambele sunt functii **in `PACK_FACTURARE`**, semnatura `(V_PRET, V_DIFERENTA, V_CURS, -V_DISCOUNT_UNITAR, V_DISCOUNT_EVIDENTIAT, V_CANTITATE, V_PRET_CU_TVA, V_PROC_TVAV) RETURN NUMBER` - -strict `NUMBER`, deci **apelabile din SQL** (confirmat prin `all_arguments`, fara tip PL/SQL-only). -Exista precedent local pentru functii de pachet apelate per-rand intr-un view din aceeasi familie -(`VRUL_TOT` cheama `PACK_SESIUNE.SUMA_RON` pe aproape fiecare coloana numerica), deci performanta nu -e un argument respingator prin ea insasi pe un view filtrat pe `id_vanzare` (cateva linii/factura). - -**Respins totusi, pentru acum**: -1. `V_DISCOUNT_EVIDENTIAT` **nu e coloana pe `VANZARI_DETALII`** - e pe antet (`VANZARI. - DISCOUNT_EVIDENTIAT`, confirmat in `all_tab_columns`). A include totalul calculat per linie ar - cere fie un join suplimentar la `VANZARI` (umfla view-ul cu o dependenta noua doar pentru un - parametru), fie parametrul trimis din VFP - oricum, in afara scopului Rundei 1 (doar afisare). -2. Runda 1 (deja implementata si testata, `docs\progres.md`) **nu consuma** aceste valori - grid-ul - e readonly, fara subtotal calculat. -3. Nevoia reala apare la S4b/Runda 4 (`plan_06_s4_proiectare.md`, C.1-C.3) - dar acolo e vorba de - **totalul pe DOCUMENT** (suma peste toate liniile), comparat cu `ACT`/`RUL`, nu de o coloana pe - fiecare rand din grid. O interogare de agregare separata (sau o functie Oracle dedicata) e o - potrivire mai buna pentru "totalul de control" decat 2 coloane calculate in view-ul de grid. -4. **Costul amanarii e mic**: extinderea unui VIEW (`CREATE OR REPLACE`) nu e o migrare de schema in - sensul de risc/coordonare al unei modificari de tabela - se poate adauga oricand printr-un script - nou, fara sa afecteze datele sau consumatorii existenti ai coloanelor deja definite. Deci nu e - nevoie sa se "prevada" acum ca sa se evite un al doilea script peste o saptamana. - -**Recomandare pentru Runda 4**: cand S4b ajunge la implementare, se adauga fie doua coloane noi in -`VVANZARI_ARTICOLE` (dupa un join la `VANZARI` pentru `DISCOUNT_EVIDENTIAT`), fie - preferabil - o interogare -de agregare separata in Oracle care calculeaza direct SUMA pe document, fara sa treaca prin grid. -Decizia ramane a lui Marius/sesiunii care implementeaza S4b, pe baza planului deja scris in -`plan_06_s4_proiectare.md` C.1. - -## F. Validare pe cele doua cazuri de regresie - -Rulat direct ca `SELECT` (fara `CREATE VIEW`), corpul propus vs. interogarea de azi din -`IncarcaArticoleFactura`, pe `MARIUSM_AUTO`: - -- **`id_vanzare = 1050`** (`cod=1140888`, `tip=1`): **4 randuri**, valori identice rand-cu-rand intre - interogarea veche si corpul noului view (`id_vanzare_det` 1584-1587). Coincide cu baza de regresie - din `docs\progres.md`. -- **`id_vanzare = 1047`** (`cod=1140885`, `tip=-12`): **2 randuri** (1578, 1579), identice intre cele - doua interogari. - -Ambele cazuri: zero divergenta, inclusiv pe coloanele cu `NULL` (ex. `id_gestiune`/`nume_gestiune` -pe liniile nestocate din `id_vanzare=1047`). - -## G. Numele coloanelor la iesire - -Fara alias-uri noi - toate coloanele pastreaza numele lor de baza din tabelele sursa (Oracle -foloseste automat numele coloanei cand nu exista `AS`): - -``` -ID_VANZARE, ID_VANZARE_DET, ID_ARTICOL, CANTITATE, PRET, PRET_CU_TVA, PROC_TVAV, DISCOUNT_UNITAR, -ID_GESTIUNE, CONT, ID_VALUTA, ID_JTVA_COLOANA, SERIE, EXPLICATIE, TAXCODE, LOT, STERS, -DENUMIRE, CODMAT, NUME_GESTIUNE, NUME_VAL -``` - -**Zero schimbari fata de azi** pentru `ControlSource`-urile existente ale `grdArticoleFactura` -(`tvd.denumire`, `tvd.codmat`, etc.) - toate numele coincid cu ce se foloseste azi. Singura -schimbare vizibila e coloana noua `tvd.id_vanzare`, disponibila dar neconsumata inca de grid. - -## H. Numerotare script - -`SCRIPTURI_CLAR\2026\08\` exista deja, ultimul numar folosit azi (08.08.2026, la momentul -verificarii) e **niciunul** - nu exista fisiere `_2026_08_08_` in director (ultimele sunt din -06.08.2026, `NN` pana la 12). **`NN=01` e liber pentru 08.08.2026**, comun tuturor prefixelor - -de reverificat la momentul aplicarii, pentru ca sesiunea are mai multi agenti activi in paralel azi -care ar putea consuma acelasi numar inaintea acestui script. - -Nume final propus: **`ff_2026_08_08_01_COMUN_VVANZARI_ARTICOLE.sql`** - scriptul livrat foloseste deja acest -nume in `exec pack_migrare.UpdateVersiune(...)`; daca sesiunea principala aloca alt `NN`, fisierul -**si** acel apel trebuie schimbate impreuna (altfel `VERSIUNE` inregistreaza un nume care nu exista -pe disc). - -## I. Format script - -`CREATE OR REPLACE VIEW` (fara `FORCE`) - verificat pe modelul cel mai recent din `SCRIPTURI_CLAR` -(`ff_2026_08_06_11_COMUN_FACT_VFACTURI.sql`, care creeaza doua view-uri fara `FORCE`); `FORCE` nu e -necesar oricum, toate tabelele sursa (`VANZARI_DETALII`, `NOM_ARTICOLE`, `NOM_GESTIUNI`, -`NOM_VALUTE`) exista deja. CRLF verificat byte-safe dupa scriere (44 CRLF, 0 LF singur). Fara `;` in -comentarii inaintea instructiunii. Se incheie cu `UpdateVersiune` + `commit`. - -## Livrabil - -`D:\ROA\ROAFACTURARE\docs\cercetare\ff_view_articole_vanzare.sql` - scriptul complet, **neaplicat**. - -## Ce trebuie schimbat in VFP ca urmare (doar cand se aplica scriptul) - -1. `COMUN\programe\ofacturare_editare.prg:201-208` (`IncarcaArticoleFactura`): inlocuieste - `FROM vanzari_detalii vd LEFT JOIN nom_articole na ... LEFT JOIN nom_gestiuni ng ... LEFT JOIN - nom_valute nv ...` cu `FROM vvanzari_articole vd`, pastrand neschimbat `WHERE vd.id_vanzare = ... AND - vd.sters = 0` si toata lista de coloane din `SELECT` (numele raman identice). -2. Fallback-ul `CREATE CURSOR tvd (...)` (`:214-216`) si duplicatul din `omodificari.vc2` (~14076, - semnalate deja ca duplicare in `rec_review_ancorare_s4.md`) **nu se ating** de aceasta schimbare - - raman neschimbate structural, doar sursa `SELECT`-ului se simplifica. -3. **Opional**, daca se doreste sa se profite de coloana noua `id_vanzare`: nu e necesar niciun - consum imediat in VFP - grid-ul nu are nevoie de ea (id-ul e deja cunoscut din parametrul functiei). diff --git a/docs/cercetare/rec_watchdog_vfp.md b/docs/cercetare/rec_watchdog_vfp.md deleted file mode 100644 index aaee775..0000000 --- a/docs/cercetare/rec_watchdog_vfp.md +++ /dev/null @@ -1,207 +0,0 @@ -# Watchdog VFP + diagnostic blocaj "View Parameter" (test_page3_articole.prg) - -## 1. Utilitarul: `COMUN\utile\Teste\watchdog_vfp.ps1` - -Lanseaza `vfp9.exe -A -T "