Files
comun/docs/cercetare/rec_view_articole_vanzare.md
Marius Mutu 6de489950c sync SVN r18016: editare articole in factura de vanzare, precizie pret achizitie
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
2026-08-20 14:07:12 +03:00

10 KiB

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).