Files
comun/docs/cercetare/rec_pret_lazy.md
Marius Mutu 09ddeabb1c docs: cercetarile trans-proiect din ROAFACTURARE trec in COMUN
Paisprezece rapoarte care nu erau ale ROAFACTURARE traiau in docs\cercetare\ al
acelui proiect: valuta si curs in ofacturare, TVA calculat vs salvat plus
denormalizarea VANZARI, inventarul consumatorilor VANZARI din toata suita ROA,
integrarile de contracte/politici/nomenclator (#10, #11, #12), watchdog-ul VFP
de testare, proiectarea Oracle a scrierii din S5 si view-ul VVANZARI_ARTICOLE.

Motivul mutarii, nu doar al pastrarii: planurile #10, #11 si #12 sunt amanate,
iar indexul lor spune explicit ca se reiau din aceste rapoarte - deci sunt punct
de plecare, nu istoric. Iar tinta lor e COMUN plus ROAPRETURI/ROACONTRACTE.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SN8snvkk94KuhWwoXUUey3
2026-08-11 22:31:53 +03:00

18 KiB

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_containerThis.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_internpolitici_grupuricrm_politici_preturicrm_note_vanzarinote_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_VALUTANOM_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 CONThardcodat, 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_containerbind 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 <context s-a schimbat>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=lcFiltrupocomenzi.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).