ROAFACTURARE 2.11.15 (r18015): programe/ofacturare_editare.prg, programe/ofacturare_stoc.prg. docs: conventia de encoding .sc2/.vc2 corectata la cp1250; cercetarile trans-proiect mutate din ROAFACTURARE in docs/cercetare (r18014); actualizari reguli_lucru, oracle_export, flux-editare-vfp-text, scripturi-migrare-db, flux-modificare-stergere-nota-jurnal, todos. .gitignore: watchdog_out si PNG-urile din rularile headless (r18008). Text FoxBin2Prg regenerat: clase/comun.vc2, ferestre/frm_import_note_facturi_clienti.sc2, ferestre/frm_initializare_facturi_balanta.sc2. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AV7dQbTLAqvrtQbH7zxXxw
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_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 pedatai/datasfata de luna curenta siid_sucursala), apoiLEFT JOIN CRM_POLITICI_PRET_ART B ON A.ID_POL=B.ID_POL,LEFT JOIN NOM_ARTICOLE C. Pret:B.PRET/B.DISCOUNT_UNITARconvertite prin curs (F.CURS) daca valuta politicii ≠ valuta nationala. Valuta:B.ID_VALUTA→NOM_VALUTE G. TVA%:B.PROC_TVAV(direct dinCRM_POLITICI_PRET_ART, nicio referinta laID_JTVA_COLOANAin acest cursor). Flag pret_cu_tva:A.PRETURI_CU_TVA(de pecrm_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), plusLEFT JOINpeSTOCpentru cantitate gestionabila (E) si peCURS/NOM_VALUTE(F/G). Nicio coloanaCONTin select. - V_TIP IN (5,6,10,52) (valuta) si V_TIP=7 (credit note),
:2374-2524: sursa e view-ulFACT_VPRETURI_UTILIZATOR A(nu mai construieste politica inline), plusSTOC(C) siCURS/NOM_VALUTE(D/E). FiltruA.ID_VALUTA=V_ID_VALUTA AND A.IN_VALUTA=1(sauA.ID_POL= pack_facturare.nid_politica_stocla tip 5/6/10/52). Nicio coloanaCONT. - ELSE (aviz),
:2526-2624: tot dinFACT_VPRETURI_UTILIZATOR A, fara filtru pe valuta. Nicio coloanaCONT.
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(dinmodificare_politica_stoc,:2105-2119, si din selectii). Nicio coloana CONT.- Nu am gasit
CREATE TABLEoriginar pentru aceste doua tabele inSCRIPTURI_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_vpolpretcurutillaCOMUN\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 penume_lista_preturidinvvanzari_detalii(COMUN\clase\configurare.vc2:3915-3972). (Sursa:docs\plan_11_integrare_politici_preturi.md:15-22, deja inD:\ROA\ROAFACTURARE\docs\.) - ROAPRETURI (
D:\ROA\ROAPRETURI, exe separatroapreturi.exe): editeaza politicile —Clase\opreturi.vcx,Clase\onom_preturi.vcx,Clase\ofundal_preturi.vcx,Programe\update_preturi.prg,Programe\update_nomenclator.prg. Pachet OraclePACK_PRETURI(adauga_articol/modifica_articol/verifica_articol— scriu si peNOM_ARTICOLE, nu doar pe politica). Nu are cache text (.vc2/.sc2) generat — nu s-a putut inspecta clasa in detaliu (vezi C4); confirmat prinGlob D:\ROA\ROAPRETURI\**\*.vc2= 0 fisiere, doar.vcxbinare. - ROACONTRACTE (
D:\ROA\ROACONTRACTE\Clase\ferestre_contracte.vc2): citeste directvcrm_politici_preturi/vcrm_politici_pret_artprin 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, apoiselect 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_PRETURIin cod VFP (.vc2/.prg) — foloseste probabil acelasiPACK_FACTURAREserver-side prinPrograme\ofactureaza.prg(fisier gasit la cautareaid_pol, dar doar in comentarii vechi de schema cursor, nu apel activ identificat in bugetul alocat). - ROAACNPRO: la fel, 0 hit-uri directe;
id_polapare doar intr-unText To lcSchema/lcSelectascuns (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 dinCOMUN(acelasiocomenzi.vcxetc.) fara sa atinga politica de pret local. - Nomenclatorul comun (
update_nomenclator.prgin ROAPRETURI) scrie in tabela de articole folosita de toate produsele — punct de atentie deja notat inplan_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 caPage5.Ct_comenzi1(Clase\ofundal_facturare.vc2:604-606).PROCEDURE Page5.Activate(:1006-1008) apeleazathis.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 princreeaza_cursoare()(:1191-1245), culcFiltru = [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) construiestelcFiltru(id_sectie = ...+filtru_pretty) si il trimite prinactualizeaza_grid1(lcFiltru)→pocomenzi.ca_baza1.cfiltru=lcFiltru→pocomenzi.ca_baza1.afisare()(:1109-1123) — clasaca_baza1(generata degencursor) trimiteWHERE-ul catre Oracle pringoExecutor, nu filtreaza un cursor deja incarcat integral. - Local (contra-exemplu):
actualizeaza_grid1in 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.vcxbinare (Clase\opreturi.vcx,Clase\ofundal_preturi.vcx); conform regulilor primite, nu am convertit nimic. Precondiitia e deja documentata ca blocanta inplan_11...md:66-70(S1: inrolare in fluxul text, proceduraCOMUN\docs\inrolare-proiect-git-text.md). - ROACONTRACTE:
ferestre_contracte.vc2are cache text si e vizibil. Descoperire importanta: clasa containerct_contracte(:9,DEFINE CLASS ct_contracte AS _ctfrmbase OF "..\comun\clase\_ct_base.vcx") mosteneste acelasi_ct_basecact_comenzi, si are propriulfiltru_pretty/but_start_criterii1(vazut inBut_reset_criterii1.Click,:1551-1567) — deci infrastructura de cautare exista. Dar nu suprascrieactualizeaza_cursoare/creeaza_cursoare(0 hit-uri in fisier) — inseamna ca foloseste stub-ul gol din_ct_basepentru acel hook, iar cursorul principal (cContracte, vazut deja populat laPROCEDURE Inita 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:cContracteINTO 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 dinocomenzi.vc2, nu cel dinferestre_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 incursor_preturi(PROC_TVAV) de coloana TVA oficiala folosita la postare.- Unde/cum populeaza azi VFP parametrul
V_CONTlaadauga_articol_factura(ipoteza: din gestiune, nu din articol) — relevant pentru a confirma daca planul #12 poate refolosi directNOM_ARTICOLE.CONTfara alta lucrare. - Incarcarea listei/grilei principale de articole din
onom_articole.vc2(formularul-parinte, nu editorul per-inregistrare). - Unde exact se populeaza
cContracteinferestre_contracte.vc2(cautare punctuala, nu facuta). - ROAGEST/ROAACNPRO: confirmarea ca folosesc
PACK_FACTURAREexclusiv server-side pentru preturi (ipoteza, nu verificata prin citirea completa aofactureaza.prg/proceduri_acnpro.prg).