sync SVN r18198
Sters codul mort frm_istoric_comenzi si vizualizare_ist_comenzi (inlocuite de frm_viz_comenzi(tlIstoric)); changelog 2.5.6 detaliat; doc flux-vizualizare-comenzi cu linii reverificate; sterse docs temporare. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cfkx1QfeDv987o8x1rAtrr
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -442,41 +442,6 @@ Endif
|
|||||||
Release pocomenzi,pomanopera
|
Release pocomenzi,pomanopera
|
||||||
Endproc && normare salarii
|
Endproc && normare salarii
|
||||||
*****************************************************************************************
|
*****************************************************************************************
|
||||||
Procedure vizualizare_ist_comenzi
|
|
||||||
Private pcselect,pcschema,pcfiltru,pcorder,pocomenzi,llAfiseaza
|
|
||||||
Store '' To pocomenzi
|
|
||||||
|
|
||||||
pcschema=['ID_ORDL n(10),ID_LUCRARE n(10),ID_MASINICLIENT n(8),ID_TIP n(5),DATAI d,'+]+;
|
|
||||||
['VALIDAT n(1),DATAORAVALID T,UTIL_VALID C(50),NRORD c(50),FACTURAT n(1),DATAFACT d,NRFACT N(14),'+]+;
|
|
||||||
['VALCTVA_FACTURA N(20,4),VAL_MANOPERA_FACTURA N(20,4),VAL_MATERIALE_FACTURA N(20,4),'+]+;
|
|
||||||
['VAL_MATERIALE_ACH N(20,4),VAL_MATERIALE_VZ N(20,4),ORE_MANOPERA N(20,4),VAL_MANOPERA N(20,4),'+]+;
|
|
||||||
['ID_PARTENER n(10),NRINMAT c(35),MASINA c(20),MARCA c(24),NUME c(50),'+]+;
|
|
||||||
['ASIGURATOR c(40),INSPECTOR c(40),NR_DOSAR c(40),TIP_COMANDA c(50),PROC_TVAV N(10,4), INCHIS_FORTAT N(1), DATAORAINCHIS T, UTIL_INCHIS C(30), ID_PART_REF N(20), PART_REF C(100),'+]+;
|
|
||||||
['SERIES V(100), KMINT I, ORE_FUNCTIONARE I']
|
|
||||||
|
|
||||||
pcselect=[select a.id_ordl,a.id_lucrare,a.id_masiniclient,a.id_tip,a.datai,]+;
|
|
||||||
[a.validat,a.dataoravalid,a.util_valid,a.nrord,a.facturat,a.datafact,a.nrfact,]+;
|
|
||||||
[a.valctva_factura, a.val_manopera_factura, a.val_materiale_factura, a.val_materiale_ach, a.val_materiale_vz, a.ore_manopera, a.val_manopera,]+;
|
|
||||||
[a.id_partener,a.nrinmat,a.masina,a.marca,a.nume,a.asigurator,a.inspector,a.nr_dosar,]+;
|
|
||||||
[a.tip_comanda,a.proc_tvav, ] + ;
|
|
||||||
[a.inchis_fortat, a.dataorainchis, a.util_inchis, a.id_part_ref, a.part_ref, ]+;
|
|
||||||
[a.series, a.kmint, a.ore_functionare ] + ;
|
|
||||||
[ from auto_istoric_comenzi a where 1=2]
|
|
||||||
|
|
||||||
pcfiltru=[1=2]
|
|
||||||
pcorder=[a.datai,a.nrord]
|
|
||||||
llAfiseaza=.F.
|
|
||||||
gencursor('pocomenzi','crscomenzi',pcselect,pcfiltru,pcschema,pcorder,llAfiseaza)
|
|
||||||
pocomenzi.ca_baza1.afisare()
|
|
||||||
|
|
||||||
ofrmistoric=Createobject('frm_istoric_comenzi')
|
|
||||||
ofrmistoric.Show(1)
|
|
||||||
If Used('crscomenzi')
|
|
||||||
Use In crscomenzi
|
|
||||||
Endif
|
|
||||||
Release pocomenzi
|
|
||||||
Endproc && vizualizare_ist_comenzi
|
|
||||||
*****************************************************************************************
|
|
||||||
Procedure vizualizare_manopera
|
Procedure vizualizare_manopera
|
||||||
*!* If glLunaInchisa
|
*!* If glLunaInchisa
|
||||||
*!* amessagebox("Nu puteti vizualiza manopera, deoarece luna este inchisa!",0+48,"Luna inchisa")
|
*!* amessagebox("Nu puteti vizualiza manopera, deoarece luna este inchisa!",0+48,"Luna inchisa")
|
||||||
|
|||||||
@@ -2,8 +2,13 @@
|
|||||||
23/09/2026
|
23/09/2026
|
||||||
ROAAUTO - 2.5.6
|
ROAAUTO - 2.5.6
|
||||||
|
|
||||||
:,modificare:
|
:modificare:
|
||||||
Vizualizare comenzi si Istoric comenzi folosesc acelasi ecran (filtre noi: asigurator, inspector, nr. dosar, referinta; coloane noi: asigurator, marca, masina, inspector, nr. dosar, arhivat); in Vizualizare comenzi si Vizualizare facturi s-au adaugat coloanele ore/valoare manopera, valoare materiale (achizitie/vanzare) si total fara/cu TVA, cu totaluri in subsolul gridului.
|
Vizualizare comenzi luna curenta/istoric:
|
||||||
|
- S-au adaugat filtre noi: asigurator, inspector, nr. dosar, referinta;
|
||||||
|
- S-au adaugat coloane noi: asigurator, marca, masina, inspector, nr. dosar, arhivat;
|
||||||
|
|
||||||
|
Vizualizare comenzi si Vizualizare facturi:
|
||||||
|
- S-au adaugat coloanele ore/valoare manopera, valoare materiale (achizitie/vanzare) si total fara/cu TVA, cu totaluri in subsolul gridului.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|||||||
@@ -2,62 +2,56 @@
|
|||||||
|
|
||||||
## Lanț
|
## Lanț
|
||||||
|
|
||||||
- `Programe/oproceduri_vizualizare.prg:651` `Procedure vizualizare_comenzi` `Lparameters tlIstoric`
|
- `Programe/oproceduri_vizualizare.prg:616` `Procedure vizualizare_comenzi` `Lparameters tlIstoric`
|
||||||
(`:652`) — **o singura procedura pentru ambele tile-uri**, nu doua separate. `pcschema`/`pcselect`
|
(`:617`) — **o singura procedura pentru ambele tile-uri**, nu doua separate. `pcschema`/`pcselect`
|
||||||
(`:658-667`) pe `auto_istoric_comenzi a`, cu **+6 campuri** fata de forma veche: `asigurator`,
|
(`:623-632`) pe `auto_istoric_comenzi a`, cu **+6 campuri** fata de forma veche: `asigurator`,
|
||||||
`marca`, `masina`, `inspector`, `nr_dosar`, `inchis_fortat`. `pcorder = a.datai,a.nrord` (`:674`).
|
`marca`, `masina`, `inspector`, `nr_dosar`, `inchis_fortat`. `pcorder = a.datai,a.nrord` (`:639`).
|
||||||
- **Capcană**: `pcfiltru = [1=2]` (`:672`) — cursorul `crscomenzi` se deschide **gol**; gridul se
|
- **Capcană**: `pcfiltru = [1=2]` (`:637`) — cursorul `crscomenzi` se deschide **gol**; gridul se
|
||||||
populează abia la căutarea din formular. Neschimbat fata de forma veche.
|
populează abia la căutarea din formular. Neschimbat fata de forma veche.
|
||||||
- `gencursor('pocomenzi','crscomenzi',...)` (`:676`) → `pocomenzi.ca_baza1.afisare()` (`:677`) →
|
- `gencursor('pocomenzi','crscomenzi',...)` (`:641`) → `pocomenzi.ca_baza1.afisare()` (`:642`) →
|
||||||
`Createobject('frm_viz_comenzi', m.tlIstoric)` (`:679`) → `.Show(1)` (`:680`).
|
`Createobject('frm_viz_comenzi', m.tlIstoric)` (`:644`) → `.Show(1)` (`:645`).
|
||||||
- Tile-uri (`Clase/ofundal_dev.vc2`): `Page2.Cw4.do_actiune` (`:681`) `DO vizualizare_comenzi ...
|
- Tile-uri (`Clase/ofundal_dev.vc2`): `Page2.Cw4.do_actiune` (`:681`) `DO vizualizare_comenzi ...
|
||||||
WITH .F.` (`nid_cw=5`, luna curenta), `Page2.Cw5.do_actiune` (`:685`) `WITH .T.` (`nid_cw=6`,
|
WITH .F.` (`nid_cw=5`, luna curenta), `Page2.Cw5.do_actiune` (`:685`) `WITH .T.` (`nid_cw=6`,
|
||||||
istoric). Drepturile pe cele doua tile-uri raman separate (nid_cw diferit).
|
istoric). Drepturile pe cele doua tile-uri raman separate (nid_cw diferit).
|
||||||
- Formular: `Clase/oviz_devize.vc2:14503` (`DEFINE CLASS frm_viz_comenzi`). Proprietate `lIstoric`
|
- Formular: `Clase/oviz_devize.vc2:13110` (`DEFINE CLASS frm_viz_comenzi`). Proprietate `lIstoric`
|
||||||
(`*p: listoric`, `:14590`), primita in `Init(tlIstoric)` — controleaza titlul (ISTORIC /
|
(`*p: listoric`, `:13196`), primita in `Init(tlIstoric)` — controleaza titlul (ISTORIC /
|
||||||
VIZUALIZARE COMENZI) si filtrul de mai jos.
|
VIZUALIZARE COMENZI) si filtrul de mai jos.
|
||||||
- `frm_viz_comenzi.do_cauta` (`Clase/oviz_devize.vc2:15667`) — **aici** se bifurca cele doua moduri
|
- `frm_viz_comenzi.do_cauta` (`Clase/oviz_devize.vc2:14272`) — **aici** se bifurca cele doua moduri
|
||||||
si se construieste filtrul real:
|
si se construieste filtrul real:
|
||||||
- `lcFiltru = Iif(Thisform.lIstoric, [2=2], gcCondLuna)` (`:15679`) — istoricul vede tot, modul
|
- `lcFiltru = Iif(Thisform.lIstoric, [2=2], gcCondLuna)` (`:14284`) — istoricul vede tot, modul
|
||||||
"luna curenta" ramane limitat la `gcCondLuna`;
|
"luna curenta" ramane limitat la `gcCondLuna`;
|
||||||
- + filtrele bifate: `ck_datai` (`:15681`), `ck_nrinmat` (`:15685`), `ck_nrord` (`:15689`),
|
- + filtrele bifate: `ck_datai` (`:14286`), `ck_nrinmat` (`:14290`), `ck_nrord` (`:14294`),
|
||||||
`ck_nume` (`:15693`), `ck_asigurator` (`:15697`), `ck_inspector` (`:15701`), `ck_nr_dosar`
|
`ck_nume` (`:14298`), `ck_asigurator` (`:14302`), `ck_inspector` (`:14306`), `ck_nr_dosar`
|
||||||
(`:15705`), `ck_series` (`:15709`), `ck_referinta` (`:15738`) — **ultimii 4 (asigurator,
|
(`:14310`), `ck_series` (`:14314`), `ck_referinta` (`:14343`) — **ultimii 4 (asigurator,
|
||||||
inspector, nr_dosar, referinta) sunt noi**, nu existau in forma veche de "luna curenta";
|
inspector, nr_dosar, referinta) sunt noi**, nu existau in forma veche de "luna curenta";
|
||||||
- + `and a.id_tip = ...` dacă s-a ales un tip (`:15713`);
|
- + `and a.id_tip = ...` dacă s-a ales un tip (`:14318`);
|
||||||
- + `and a.validat = 0/1` după `cbValidat` (`:15718-15722`);
|
- + `and a.validat = 0/1` după `cbValidat` (`:14323-14327`);
|
||||||
- + `and a.inchis_fortat = 0/1` după `cbArhivat` (`:15724-15729`);
|
- + `and a.inchis_fortat = 0/1` după `cbArhivat` (`:14331-14335`);
|
||||||
- apoi `Thisform.actualizeaza_grid1(lcFiltru)`.
|
- apoi `Thisform.actualizeaza_grid1(lcFiltru)`.
|
||||||
- `actualizeaza_grid1` — pune `pocomenzi.ca_baza1.cfiltru`, reapelă `afisare()`, cu `save_grid` /
|
- `actualizeaza_grid1` — pune `pocomenzi.ca_baza1.cfiltru`, reapelă `afisare()`, cu `save_grid` /
|
||||||
`restore_grid`.
|
`restore_grid`.
|
||||||
- Coloane noi, adaugate **la coada** grid-ului (`Column22-27`, `:15021-15054`): `cAsigurator`,
|
- Coloane noi, adaugate **la coada** grid-ului (`Column22-27`, `:13628-13661`): `cAsigurator`,
|
||||||
`cMarca`, `cMasina`, `cInspector`, `cNr_dosar`, `cArhivat` (`IIF(inchis_fortat=1,'Da','Nu')`).
|
`cMarca`, `cMasina`, `cInspector`, `cNr_dosar`, `cArhivat` (`IIF(inchis_fortat=1,'Da','Nu')`).
|
||||||
- `Cmd_sterge1`/`do_sterge` exista in clasa (`:14858`, `:15982`) dar `Visible = .F.` (`:14865`) —
|
- `Cmd_sterge1`/`do_sterge` exista in clasa (`:13465`, `:14587`) dar `Visible = .F.` (`:13472`) —
|
||||||
butonul de stergere ramane ascuns, ca in fosta forma de istoric; activarea lui e o decizie
|
butonul de stergere ramane ascuns, ca in fosta forma de istoric; activarea lui e o decizie
|
||||||
separata, netratata de unificare.
|
separata, netratata de unificare.
|
||||||
|
|
||||||
## Capcană: forma unificata e deschisa de `vizualizare_comenzi`, nu de `vizualizare_ist_comenzi`
|
|
||||||
|
|
||||||
`vizualizare_ist_comenzi` (`Programe/oproceduri_vizualizare.prg:445`) si clasa
|
|
||||||
`frm_istoric_comenzi` **raman inca in cod dar nu mai sunt apelate din niciun tile** — cautarea unei
|
|
||||||
proceduri "de istoric" dupa nume duce la codul gresit. Cod mort, de sters.
|
|
||||||
|
|
||||||
## Valorile implicite ale combo-urilor (contează la orice măsurătoare)
|
## Valorile implicite ale combo-urilor (contează la orice măsurătoare)
|
||||||
|
|
||||||
| combo | implicit | efect în `do_cauta` |
|
| combo | implicit | efect în `do_cauta` |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `cbArhivat` | `"Active"` (`Clase/oviz_devize.vc2:14453`) | mereu `and a.inchis_fortat = 0` (`:15726`) |
|
| `cbArhivat` | `"Active"` (`Clase/oviz_devize.vc2:14665`) | mereu `and a.inchis_fortat = 0` (`:14332`) |
|
||||||
| `cbValidat` | `"<Toate>"` (`:14471`) | nimic |
|
| `cbValidat` | `"<Toate>"` (`:14701`) | nimic |
|
||||||
| `cbtip_deviz` | `"<Toate tipurile>"` (`:65`, clasa `ctip_deviz`) | nimic |
|
| `cbtip_deviz` | `"<Toate tipurile>"` (`:65`, clasa `ctip_deviz`) | nimic |
|
||||||
|
|
||||||
## Ecranul pereche „Vizualizare facturi"
|
## Ecranul pereche „Vizualizare facturi"
|
||||||
|
|
||||||
- `Programe/oproceduri_vizualizare.prg:231` `Procedure vizualizare_facturi` — sursa
|
- `Programe/oproceduri_vizualizare.prg:231` `Procedure vizualizare_facturi` — sursa
|
||||||
`auto_facturi_emise a` (`:247`); `pcFiltru = [1=2]` (`:253`), deci din nou cursor gol.
|
`auto_facturi_emise a` (`:247`); `pcFiltru = [1=2]` (`:253`), deci din nou cursor gol.
|
||||||
- Filtrul real e în `frm_viz_facturi.do_cauta` (`Clase/oviz_devize.vc2:17795`) și **nu** folosește
|
- Filtrul real e în `frm_viz_facturi.do_cauta` (`Clase/oviz_devize.vc2:16941`) și **nu** folosește
|
||||||
`gcCondLuna` (linia e comentată la `:17800`), ci `extract(month from dataact)=gnLuna` +
|
`gcCondLuna` (linia e comentată la `:16946`), ci `extract(month from dataact)=gnLuna` +
|
||||||
`extract(year from dataact)=gnAn` (`:17799`) + checkbox-uri; `actualizeaza_grid1` (`:17837`).
|
`extract(year from dataact)=gnAn` (`:16945`) + checkbox-uri; `actualizeaza_grid1` (`:16983`).
|
||||||
- Formular: `Clase/oviz_devize.vc2:16936` (`DEFINE CLASS frm_viz_facturi`).
|
- Formular: `Clase/oviz_devize.vc2:16005` (`DEFINE CLASS frm_viz_facturi`).
|
||||||
|
|
||||||
## Editare de grid
|
## Editare de grid
|
||||||
|
|
||||||
|
|||||||
@@ -1,72 +0,0 @@
|
|||||||
# Handoff: cercetare "ecran comenzi in luna curenta" (read-only)
|
|
||||||
|
|
||||||
Sarcina: identificare ecran ROAAUTO pentru lista de comenzi (work orders) din luna curenta,
|
|
||||||
la cererea team-lead. Cercetare READ-ONLY — nu s-a modificat niciun fisier din proiect.
|
|
||||||
Toate constatarile au fost deja transmise integral catre `team-lead` prin doua mesaje
|
|
||||||
SendMessage (cu citate exacte de cod si file:line). Acest fisier e doar predarea pe disc,
|
|
||||||
conform REGULA ZERO — pentru cazul in care mesajele s-ar pierde.
|
|
||||||
|
|
||||||
## Stare: COMPLET pentru intrebarile puse pana acum (2 runde)
|
|
||||||
|
|
||||||
Nu exista lucru neterminat, nu exista fisiere editate, nu exista tranzactii deschise,
|
|
||||||
nu exista date de test consumate. Subagentul nu a scris/modificat cod.
|
|
||||||
|
|
||||||
## Inventar constatari (file:line)
|
|
||||||
|
|
||||||
### Runda 1 — identificarea ecranului
|
|
||||||
- Punct de intrare: tile dashboard "Comenzi în luna curentă"
|
|
||||||
- `Clase/ofundal_dev.vc2:266` — caption `Label_item1.Caption`
|
|
||||||
- `Clase/ofundal_dev.vc2:681-682` — `DO vizualizare_comenzi IN oproceduri_vizualizare.prg`
|
|
||||||
- Procedura care construieste cursorul: `Programe/oproceduri_vizualizare.prg:649-678`
|
|
||||||
(`Procedure vizualizare_comenzi`), sursa = view Oracle `auto_normare_comenzi`,
|
|
||||||
cursor `crscomenzi`, porneste cu `pcfiltru=[1=2]` (grid gol la deschidere),
|
|
||||||
deschide formularul `frm_viz_comenzi`.
|
|
||||||
- Filtrul real de "luna curenta" = `gcCondLuna`, aplicat in formular la `do_cauta`
|
|
||||||
(`Clase/oviz_devize.vc2:15148`, clasa `frm_viz_comenzi` incepe la `:14503`).
|
|
||||||
- `gcCondLuna` definit in `Programe/ovariabile_globale.prg:14-18` — NU e "creat luna asta",
|
|
||||||
ci "luna de lucru curenta (gnLuna/gnAn) SAU comenzi mai vechi inca deschise/nefacturate/
|
|
||||||
nevalidate".
|
|
||||||
- Coloane grid (13) + Oracle view sursa + lipsa camp manopera/piese calculat — detaliate in
|
|
||||||
mesajul 1 catre team-lead.
|
|
||||||
|
|
||||||
### Runda 2 — detalii cerute explicit (puncte 1-4)
|
|
||||||
1. Grid `frm_viz_comenzi`: `Clase/oviz_devize.vc2:14745` (ADD OBJECT 'grdcomenzi',
|
|
||||||
ColumnCount=13, RecordSource="crscomenzi"), coloane 1-13 la liniile 14760-14818,
|
|
||||||
headere la 14827-14962. Coloana noua → extinde `ColumnCount` + bloc `ColumnN` acolo,
|
|
||||||
plus camp adaugat in `pcschema`/`pcselect` din `oproceduri_vizualizare.prg:656-666`.
|
|
||||||
2. Preferinte grid per utilizator: mecanism `GridExtras`
|
|
||||||
(`COMUN/utile/GridExtras/gridextras.vc2:337-1434`, clasa `gridextra`), instantiat ca
|
|
||||||
`Gridextra1` (`Clase/oviz_devize.vc2:15065`), pornit din `Init` (`:15438-15441`) prin
|
|
||||||
`this.gridextra1.setup()`. `restoregridpreferences` (`gridextras.vc2:1051`) si
|
|
||||||
`savegridpreferences` (`:1130`) salveaza perechi `ColumnOrder,Width` **pozitional pe
|
|
||||||
index de coloana** (nu pe nume/ControlSource) in `%APPDATA%\...\gridprefs.tmp`, cheie
|
|
||||||
`SYS(1272, grid)`. Confirma capcana din `COMUN/docs/capcana_grid_preferinte_utilizator.md`:
|
|
||||||
coloana noua trebuie adaugata la coada (ultimul index), nu in mijloc.
|
|
||||||
3. `gencursor()`: `COMUN/programe/gencursor.prg:1` — creeaza `NEWOBJECT('deca_baza')` +
|
|
||||||
`.ADDOBJECT('ca_baza1','ca_baza')`. Clasa `ca_baza` (`COMUN/clase/decabaza.vc2:7`) e
|
|
||||||
bazata pe `cursoradapter` (via `_cabase`/`_ca_base.vcx` — FetchSize nu am gasit sa fie
|
|
||||||
suprascris explicit, ramane implicit din `_ca_base.vcx`, neverificat). `afisare()`
|
|
||||||
(`decabaza.vc2:36-74`) taie SQL-ul de la `WHERE` incolo si il reconstruieste cu
|
|
||||||
`cfiltru` curent — aici se inlocuieste `1=2` cu filtrul real.
|
|
||||||
4. Ecran cu coloanele `AUTO_ISTORIC_COMENZI` (VAL_MANOPERA_FACTURA etc.): DA, exista deja —
|
|
||||||
`frm_istoric_comenzi` (`Clase/oviz_devize.vc2:9115-10506`), grid cu `ColumnCount=25`,
|
|
||||||
coloanele 19-25 (`:9579-9622`) afiseaza exact `valctva_factura, val_manopera_factura,
|
|
||||||
val_materiale_factura, val_materiale_ach, val_materiale_vz, ore_manopera, val_manopera`.
|
|
||||||
Filtrul de luna NU e `gcCondLuna` — `do_cauta` (`:10190`) porneste cu `lcFiltru=[2=2]`
|
|
||||||
(fara restrictie de luna), filtrare doar optionala prin checkbox-uri UI.
|
|
||||||
|
|
||||||
## Ce s-a stabilit deja (sa nu se reia)
|
|
||||||
- Ecranul-tinta pt "comenzi in luna curenta" = `frm_viz_comenzi` (nu `frm_istoric_comenzi`,
|
|
||||||
nu `vizualizare_manopera`).
|
|
||||||
- Query-ul de baza si mecanismul de filtrare (gencursor + ca_baza.afisare) sunt clarificate,
|
|
||||||
nu mai cauta SQL-ul de la zero.
|
|
||||||
- Capcana pozitionala GridExtras e confirmata in cod, nu doar in doc.
|
|
||||||
|
|
||||||
## Interzis / neverificat
|
|
||||||
- Nu am citit `_ca_base.vcx` — FetchSize exact al CursorAdapter-ului ramane neconfirmat daca
|
|
||||||
devine relevant (ex. pentru performanta pe volum mare).
|
|
||||||
- Nu am cautat DDL-ul view-urilor Oracle (`auto_normare_comenzi`, `auto_istoric_comenzi`) —
|
|
||||||
nu exista in acest repo VFP; ar necesita acces Oracle (`roa-oracle-production-access`).
|
|
||||||
|
|
||||||
## Comanda de rulare teste
|
|
||||||
N/A — sarcina a fost strict cercetare/cautare in cod, fara modificari, fara teste rulate.
|
|
||||||
@@ -1,156 +0,0 @@
|
|||||||
# Handoff: cercetare "cost materiale / rulaj + manoperă" (read-only)
|
|
||||||
|
|
||||||
Sarcina (subagent `lane-cost`): găsește și documentează cum se determină azi (a) costul de
|
|
||||||
achiziție al unei piese ieșite pe o comandă/factură și (b) valoarea + orele de manoperă,
|
|
||||||
pentru cererea clientului de a afișa aceste valori în listele de comenzi/facturi. Cercetare
|
|
||||||
READ-ONLY — **niciun fișier din proiect nu a fost modificat.**
|
|
||||||
|
|
||||||
## Stare: COMPLET
|
|
||||||
|
|
||||||
Toate constatările au fost transmise integral către `team-lead` prin două mesaje SendMessage
|
|
||||||
(cu citate exacte de cod și file:line). Acest fișier e doar predarea pe disc, conform REGULA
|
|
||||||
ZERO — pentru cazul în care mesajele s-ar pierde. Nu există lucru neterminat, fișiere editate,
|
|
||||||
tranzacții deschise sau date de test consumate.
|
|
||||||
|
|
||||||
**Important**: în timp ce scriam handoff-ul am găsit că exista deja pe disc
|
|
||||||
[`docs/propuneri_coloane_manopera_piese_viz.md`](propuneri_coloane_manopera_piese_viz.md) —
|
|
||||||
un document mult mai complet (scris cu acces direct la Oracle: `EXPLAIN PLAN`, `autotrace`,
|
|
||||||
măsurători reale pe schema `MARIUSM_AUTO`/`ROA_CENTRAL`), care **acoperă și depășește** tot ce
|
|
||||||
am găsit eu static din cod. Acela e documentul de referință pentru implementare, nu acesta.
|
|
||||||
Constatările mele (fără acces DB, doar citire de cod) coincid cu ale lui la toate punctele
|
|
||||||
verificabile static.
|
|
||||||
|
|
||||||
## Inventar constatări (file:line)
|
|
||||||
|
|
||||||
### 1. Tabelul RUL (rulaj) — coloane relevante
|
|
||||||
Schema cursorului `viz_rulaje`: `COMUN/programe/oproceduri_rulaje.prg:15-25`.
|
|
||||||
`PRET n(16,4)` = preț achiziție/cost per rând de mișcare, `PRETV n(16,4)` = preț vânzare,
|
|
||||||
`CANT`/`CANTE` = cantitate, `COD` = document sursă, `ID_LUCRARE`, `ID_GESTIUNE`, `STERS`.
|
|
||||||
|
|
||||||
### 2. Cost achiziție — DEJA STOCAT pe linia de vânzare/factură (nu recalculat la citire)
|
|
||||||
- Schema cursor linii deviz: `Programe/oproceduri_devize.prg:882` — `pret_achizitie N(20,4)`.
|
|
||||||
- Populat din lotul de stoc consumat: `COMUN/clase/ofacturare.vc2:4233,13131,13511` —
|
|
||||||
`poArticol.pret_achizitie = Pret`.
|
|
||||||
- Scris efectiv prin `pack_facturare.adauga_articol_factura_deviz`
|
|
||||||
(`Programe/oproceduri_devize.prg:1218-1244`).
|
|
||||||
- Persistă și la editare facturi: `COMUN/programe/ofacturare_editare.prg:225,547,652,775,807-817`;
|
|
||||||
schema tabel `vanzari_det`: `COMUN/programe/oproceduri_facturare.prg:378-491,1114-1133`.
|
|
||||||
- Rapoarte care citesc costul direct de pe linie, fără recalcul:
|
|
||||||
`COMUN/programe/oproceduri_rapoarte_fact.prg:579-590` (view `fact_vfacturi_detalii`).
|
|
||||||
|
|
||||||
### 3. Algoritm de determinare a costului la ieșire — FIFO pe LOT, din tabela STOC
|
|
||||||
Sursă (în afara repo-ului git ROAAUTO, în `D:\ROA\DATABASE\SCRIPTURI_CLAR\` — istoric SVN al
|
|
||||||
schemei Oracle COMUN, actualizat curent, ultimul fișier relevant la 2026-09-16):
|
|
||||||
`PACK_FACTURARE.cursor_gestiuni_articol`
|
|
||||||
(`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\09\ff_2026_09_16_04_COMUN_PACK_FACTURARE.sql:4513-4597`).
|
|
||||||
Selectează loturi din **`STOC`** (nu din `RUL`), filtrate pe `LUNA`/`AN`/`ID_ARTICOL`/
|
|
||||||
`ID_GESTIUNE`, cantitate rămasă = `CANTS + CANT - CANTE > 0`, ordonate **`ORDER BY DATAIN`**
|
|
||||||
(FIFO pe data intrării lotului). `PRET` = costul lotului ales, scris o singură dată pe linia
|
|
||||||
de vânzare (punctul 2). Rapoartele nu re-rulează FIFO, doar re-însumează ce s-a scris deja.
|
|
||||||
|
|
||||||
### 4. Manoperă — ore și valoare
|
|
||||||
DDL `DEV_OPER`: `Scripturi_instalare/tabele.sql:674-693` — `TIMPN NUMBER(8,3)` (ore),
|
|
||||||
`PRET NUMBER(17,4)` (tarif orar), `ID_ORDL` (FK spre `DEV_ORDL`, fără index explicit pe
|
|
||||||
`DEV_OPER.ID_ORDL` în DDL). `DEV_ORDL` are index pe `ID_LUCRARE` (`IDX_ORDL_00001`,
|
|
||||||
`Scripturi_instalare/tabele.sql:636`).
|
|
||||||
Valoare manoperă = `TIMPN * PRET`, agregată în raport:
|
|
||||||
`Programe/oproceduri_listari.prg:1608-1621` (`facturi_emise_pe_sectii`).
|
|
||||||
|
|
||||||
### 5. Raportul cerut de client EXISTĂ DEJA — view Oracle `AUTO_ISTORIC_COMENZI`
|
|
||||||
Versiune curentă (ultima modificare găsită, 2025-06-30, nimic mai nou):
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2025\06\ff_2025_06_30_01_AUTO.sql:37-95`.
|
|
||||||
```sql
|
|
||||||
(select sum(round(pret * cante, 2)) from rul where sters = 0 and id_lucrare = a.id_lucrare) as val_materiale_ach,
|
|
||||||
(select sum(round(pretv * cante, 2)) from rul where sters = 0 and id_lucrare = a.id_lucrare) as val_materiale_vz,
|
|
||||||
(select sum(b1.timpn) from dev_ordl a1 left join dev_oper b1 on a1.id_ordl=b1.id_ordl where a1.id_lucrare=a.id_lucrare and a1.sters=0 and b1.sters=0) as ore_manopera,
|
|
||||||
(select sum(round(b1.timpn*b1.pret,2)) from dev_ordl a1 left join dev_oper b1 on a1.id_ordl=b1.id_ordl where a1.id_lucrare=a.id_lucrare and a1.sters=0 and b1.sters=0) as val_manopera,
|
|
||||||
```
|
|
||||||
Subselecte **corelate pe `id_lucrare`** (nu scan fără filtru), susținute de indexul
|
|
||||||
`IDX_RUL_001 on RUL(ID_LUCRARE, STERS)` (creat `D:\ROA\DATABASE\SCRIPTURI\2009\1\ff_2009_01_21_01_GESTIUNI.sql:63`,
|
|
||||||
încă folosit activ cu hint în producție — ultima apariție
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:711`).
|
|
||||||
Folosit deja în VFP: `Programe/oproceduri_vizualizare.prg:441-457` (`vizualizare_ist_comenzi`),
|
|
||||||
afișat în grid `Clase/oviz_devize.vc2:9585-9607` (`ControlSource`: `val_materiale_ach`,
|
|
||||||
`val_materiale_vz`, `val_materiale_factura`, `val_manopera_factura`, `ore_manopera`).
|
|
||||||
|
|
||||||
### 6. Raportul care CHIAR scanează tot RUL fără scopare pe lucrare (risc real, dar altă bucată de cod)
|
|
||||||
`Programe/oproceduri_listari.prg:1607-1625` (`facturi_emise_pe_sectii`):
|
|
||||||
```sql
|
|
||||||
left join (select sum(round(pret*cante,2)) as valoarea, sum(round(pretv*cante,2)) as valoarev,
|
|
||||||
id_lucrare, id_sectie from rul where sters=0 group by id_lucrare, id_sectie) e
|
|
||||||
on a.id_lucrare = e.id_lucrare and a.id_sectie = e.id_sectie
|
|
||||||
```
|
|
||||||
`GROUP BY` peste tot `RUL` (fără filtru pe `id_lucrare` în where), join-ul pe perioadă se face
|
|
||||||
abia după — spre deosebire de `AUTO_ISTORIC_COMENZI` (punctul 5), care e corelat per lucrare.
|
|
||||||
Acesta e adevăratul candidat de "selecție pe toată baza de date", dacă vreodată devine relevant
|
|
||||||
de optimizat.
|
|
||||||
|
|
||||||
## Ce s-a stabilit deja (să nu se reia)
|
|
||||||
- Costul de achiziție e stocat pe linia de vânzare/factură (`pret_achizitie`), nu recalculat FIFO
|
|
||||||
la fiecare citire — FIFO rulează o singură dată, la facturare, pe tabela `STOC`.
|
|
||||||
- View-ul `AUTO_ISTORIC_COMENZI` deja livrează exact coloanele cerute de client și e deja folosit
|
|
||||||
în ecranul „Istoric comenzi"; documentul de propuneri recomandă copierea acelorași subinterogări
|
|
||||||
în `AUTO_NORMARE_COMENZI`/`AUTO_FACTURI_EMISE` pentru ecranele „Vizualizare comenzi"/"Facturi".
|
|
||||||
- Sursa de adevăr pentru DDL/PL-SQL Oracle (istoric complet de migrări, inclusiv versiuni curente
|
|
||||||
ale pachetelor și view-urilor) NU e în `Scripturi_instalare\` din ROAAUTO, ci în
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI\` (brut, cronologic) și `D:\ROA\DATABASE\SCRIPTURI_CLAR\` (reformatat) —
|
|
||||||
repo SVN separat, partajat între toate aplicațiile ROA.
|
|
||||||
|
|
||||||
## Interzis / nu s-a făcut
|
|
||||||
Nicio modificare de cod, niciun script Oracle rulat, niciun write-back `.vc2`/`.sc2`. Cercetare
|
|
||||||
pur read-only, conform mandatului primit.
|
|
||||||
|
|
||||||
## Runda 2 — întrebări punctuale de la team-lead (trimise, nu doar aici)
|
|
||||||
Sursă: `PACK_FACTURARE.descarca_gestiune`, în
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\09\ff_2026_09_16_04_COMUN_PACK_FACTURARE.sql` (versiune
|
|
||||||
curentă, 2026-09-16).
|
|
||||||
|
|
||||||
1. **`RUL.PRET` la ieșire — SIGUR**: nu se recalculează în `descarca_gestiune`. Procedura primește
|
|
||||||
`V_PRET_ACHIZITIE IN NUMBER` ca parametru, selectează din `STOC` exact lotul cu acel preț
|
|
||||||
(`AND A.PRET = V_PRET_ACHIZITIE`, linia 8766 și analog 8659/8899/10642), apoi
|
|
||||||
`V_PRET := tab_stoc(i).PRET` (linia 8975) și `V_PRET as PRET` în `INSERT INTO RUL_TEMP`
|
|
||||||
(linia 9456). FIFO-ul (alegerea lotului) se face separat, mai devreme, în
|
|
||||||
`cursor_gestiuni_articol` (`ORDER BY DATAIN`, raportat runda 1).
|
|
||||||
**Incert**: n-am găsit niciun `INSERT INTO RUL` literal (fără `_TEMP`) în acest fișier — nu am
|
|
||||||
urmărit cum `RUL_TEMP` ajunge fizic în `RUL`. Nu schimbă răspunsul (valoarea `PRET` e fixată la
|
|
||||||
`V_PRET` oricum), dar rămâne un gol de investigat dacă cineva vrea firul complet.
|
|
||||||
2. **RUL pe `id_lucrare` = doar piese, niciodată manoperă — SIGUR**: gardă la intrarea în
|
|
||||||
`descarca_gestiune` (liniile 8264-8270):
|
|
||||||
```sql
|
|
||||||
SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL;
|
|
||||||
if lnInStoc = 0 then GOTO SFARSIT; end if;
|
|
||||||
```
|
|
||||||
Articolele cu `IN_STOC=0` (servicii/manoperă) nu ajung niciodată să scrie în `RUL_TEMP`/`RUL`.
|
|
||||||
Replicat pe VFP prin `gestionabil = Iif(Nvl(in_stoc,0)<>0,1,0)`
|
|
||||||
(`COMUN/programe/ofacturare_editare.prg:242`).
|
|
||||||
3. **`CANTE` vs `CANT` — SIGUR**: `CANTE`=ieșire, `CANT`=intrare, din formula soldului
|
|
||||||
`CANTS+CANT-CANTE` (folosită consecvent, ex. `cursor_gestiuni_articol`). La retur (ramura
|
|
||||||
`WHEN pack_facturare.ntip IN (8,9)` din `descarca_gestiune`, ~linia 8355) nu se folosesc
|
|
||||||
cantități negative — ieșirea originală (`a.cante`) devine `cant` (intrare) pe rândul nou:
|
|
||||||
`SELECT 1 as tip, ..., a.cante as cant, 0 as cante, ... FROM RUL A ... WHERE A.CANTE<>0`.
|
|
||||||
4. **`DEV_OPER.TIMPN` = ore — SIGUR pe bază de uz**, nicio conversie de unitate întâlnită:
|
|
||||||
`Programe/oproceduri_listari.prg:1620` (`sum(...timpn) as ore`), `:2005` (`sum(timpn) as ore`),
|
|
||||||
caption `Clase/odevize.vc2:6310` (`"Total ore"`). Niciun `COMMENT ON COLUMN` găsit în DDL —
|
|
||||||
eticheta vine din convenția de cod, nu dintr-un comentariu de schemă.
|
|
||||||
5. **`VANZARI_DETALII.PRET_ACHIZITIE` — mecanism SIGUR, procentul de 95% zero INCERT**: scris de
|
|
||||||
același flux (`descarca_gestiune`/finalizare factură), doar pentru linii gestionabile
|
|
||||||
(`IN_STOC<>0`), cu `V_PRET` din `STOC` (condiție de MERGE, linia 12741:
|
|
||||||
`AND A.PRET_ACHIZITIE = V_PRET ...`). Pentru linii de manoperă (`IN_STOC=0`) rămâne 0 **prin
|
|
||||||
design** (codul nici nu rulează pentru ele — punctul 2). Nu am verificat empiric (fără acces
|
|
||||||
Oracle) dacă cele ~95% zero din schema de test chiar corespund liniilor de manoperă sau ascund
|
|
||||||
și piese needescărcate din alt motiv — am recomandat team-lead-ului un count pe
|
|
||||||
`IN_STOC × (PRET_ACHIZITIE=0)` pentru confirmare.
|
|
||||||
|
|
||||||
**Concluzie rundă 2**: `pret_achizitie` de pe `VANZARI_DETALII` e de încredere ca sursă a costului
|
|
||||||
pe factură pentru liniile de piese; un 0 pe linie de manoperă e corect, nu semnal de problemă.
|
|
||||||
|
|
||||||
**CORECTARE ulterioară (din `docs/propuneri_coloane_manopera_piese_viz.md`, actualizat de altcineva
|
|
||||||
cu acces Oracle, după ce am trimis răspunsul de mai sus)**: pe schema de test, `PRET_ACHIZITIE = 0`
|
|
||||||
nu doar pe liniile de manoperă (`IN_STOC=0`: 2475/2526 = 98%), ci **și pe 96% din liniile de piese
|
|
||||||
gestionabile** (`IN_STOC=1`: 8561/8889 = 96%). Deci concluzia mea "e de încredere pentru piese" nu
|
|
||||||
se confirmă empiric — mecanismul de scriere există (descris mai sus), dar pe date reale coloana e
|
|
||||||
goală aproape peste tot, inclusiv acolo unde ar trebui completată. Motivul exact nu e stabilit
|
|
||||||
(posibil: câmpul se completează doar pe un anumit flux de facturare, sau pe majoritatea documentelor
|
|
||||||
din baza de test descărcarea de gestiune nu s-a mai executat din alt motiv). **Nu folosiți
|
|
||||||
`VANZARI_DETALII.PRET_ACHIZITIE` ca sursă de cost fără verificare suplimentară — `RUL.PRET` (via
|
|
||||||
`AUTO_ISTORIC_COMENZI`) rămâne sursa confirmată empiric.**
|
|
||||||
@@ -1,462 +0,0 @@
|
|||||||
# Propunere: ore/valoare manoperă + valoare piese (facturare și achiziție) în „Vizualizare comenzi" și „Facturi emise"
|
|
||||||
|
|
||||||
Cercetare + plan. Data: 22.09.2026. Dovezile de plan/IO sunt luate pe schema `MARIUSM_AUTO` de pe
|
|
||||||
`ROA_CENTRAL`.
|
|
||||||
|
|
||||||
## 0. Stare — 22.09.2026, implementat integral (pașii 1-4 + 6), în așteptare de review
|
|
||||||
|
|
||||||
**Acesta este fișierul de implementat.** Planul e la §5, aprobat de Marius pe 22.09.2026.
|
|
||||||
|
|
||||||
- **Pas 1 — baza de date: SCRIS ȘI RULAT pe `MARIUSM_AUTO` de pe `ROA_CENTRAL`** (aprobat de Marius).
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\09\ff_2026_09_22_01_AUTO.sql`, cu antet de comentarii care
|
|
||||||
explică ce s-a modificat față de versiunile anterioare ale celor două view-uri.
|
|
||||||
ASCII, CRLF, se încheie cu `UpdateVersiune` + `commit`.
|
|
||||||
Dovadă: „View created" ×2, `VERSIUNE` conține `ff_2026_09_22_01_AUTO.sql`, toate cele 5 coloane noi
|
|
||||||
există în `USER_TAB_COLUMNS`, zero obiecte `AUTO_*` invalide.
|
|
||||||
**Nepublicat încă** la clienți (`publicare_scripturi.ps1` nu a fost rulat).
|
|
||||||
- **Pas 2 — cursoarele VFP: FĂCUT.** `Programe/oproceduri_vizualizare.prg` — `vizualizare_comenzi`
|
|
||||||
trecut pe `auto_istoric_comenzi` (+6 coloane), `vizualizare_facturi` +4 coloane.
|
|
||||||
- **Pas 3 — gridurile: FĂCUT, cu write-back pe binar.** `Clase/oviz_devize.vc2` — `frm_viz_comenzi`
|
|
||||||
`ColumnCount` 13→19, `frm_viz_facturi` `ColumnCount` 12→16, coloane noi **la coadă**.
|
|
||||||
- **Pas 4 — totalurile de sub gridul de facturi: FĂCUT.** 4 containere `clb_tx_simplu` noi
|
|
||||||
(`Clb_ore_manopera`, `Clb_val_manopera`, `Clb_val_mat_ach`, `Clb_val_mat_vz`) pe două rânduri sub
|
|
||||||
cele existente, `frm_viz_facturi.Height` 497→560, iar `refreshdata` însumează cele 4 coloane cu
|
|
||||||
`Nvl(...,0)` și garda `nrcrt=1`.
|
|
||||||
- **Pas 5 (raportul `rap_facturi_clienti`) — NEFĂCUT**, opțional: `.frx` se editează doar în IDE-ul VFP.
|
|
||||||
- **Pas 6 — testat pe bază: 7 PASS / 1 FAIL.** Raport: `docs/review/teste_coloane_manopera_piese_viz.md`.
|
|
||||||
Rularea efectivă a ecranelor în VFP rămâne de făcut (necesită IDE).
|
|
||||||
- **Necomis.** Diff-ul complet: `docs/review/diff_coloane_manopera_piese_viz.patch`.
|
|
||||||
|
|
||||||
### Ce au arătat testele (rezumat)
|
|
||||||
|
|
||||||
- **Riscul principal e eliminat**: mutarea sursei ecranului de comenzi **nu schimbă setul de
|
|
||||||
comenzi afișate** — `AUTO_NORMARE_COMENZI` și `AUTO_ISTORIC_COMENZI` întorc exact aceleași 375 de
|
|
||||||
`ID_LUCRARE` (0 diferențe în ambele sensuri), iar cu filtrul `gcCondLuna` aplicat, exact aceleași
|
|
||||||
179 de rânduri. `INCH_VALIDARE` coincide cu `DEV_TIP_DEVIZ` și cu `AUTO_NORMARE_COMENZI`, 0 NULL.
|
|
||||||
- Cele 4 coloane noi din `AUTO_FACTURI_EMISE` sunt **identice** cu omoloagele din
|
|
||||||
`AUTO_ISTORIC_COMENZI` pe toate cele 131 de `ID_LUCRARE` comune.
|
|
||||||
- Garda `id_lucrare > 0` este necesară și funcționează: `RUL` are 6 597 de rânduri cu
|
|
||||||
`ID_LUCRARE = 0`, iar view-urile nu întorc niciunul.
|
|
||||||
- **NULL-urile sunt frecvente** (§6.6 de mai jos) — orice sumă/afișare are nevoie de `Nvl`.
|
|
||||||
- **§3.2 se confirmă pe producție, se infirmă pe dev.** Pe schema de test (`RUL` = 10 374 rânduri)
|
|
||||||
optimizatorul dez-corelează subinterogările și face `TABLE ACCESS FULL` pe `RUL` — de aici „T8
|
|
||||||
FAIL". **Pe producția clientului AUTOMOTIVE (`RUL` = 571 508 rânduri) planul folosește
|
|
||||||
`INDEX RANGE SCAN IDX_RUL_001`**, corelat, exact cum prezicea §3.2; la fel manopera, pe
|
|
||||||
`IDX_ORDL_00001` + `IDX_OPER_01`. Deci T8 era un artefact al volumului mic.
|
|
||||||
- ~~Dar apare o problemă mai mare: ecranul întoarce 32 790 de rânduri, +28 % timp~~ — **RETRAS
|
|
||||||
23.09.2026**, măsurătoare invalidă (lipsea `pack_sesiune.setluna/setan`). Real: **164 de
|
|
||||||
rânduri, ~3.3 s, +0.4 s de la coloanele noi**. Vezi §7 și `docs/vfp_oracle_pack_sesiune.md`.
|
|
||||||
- Cost I/O pe schema de test: 642 → 1 207 `consistent gets` (**1.88×**) pentru aceleași 179 de rânduri.
|
|
||||||
|
|
||||||
### Ce e de reținut pentru sesiunile următoare
|
|
||||||
|
|
||||||
- **Capcană FoxBin2Prg**: blocurile `ADD OBJECT '<grid>.<coloana>.<control>'` trebuie scrise în
|
|
||||||
**ordine alfabetică** (case-insensitive) în `.vc2`; altfel `txt2vcx.ps1` cade la fidelity-check.
|
|
||||||
Ordinea canonică se citește din `<staging>\verify\*.vc2` — fișierul acela e chiar editarea ta
|
|
||||||
rescrisă canonic, deci se poate adopta ca sursă.
|
|
||||||
- **Decizii deja luate, nu le relua**: §4 varianta 1; manopera în ambele forme (deviz + facturat);
|
|
||||||
costul din `RUL.PRET`, nu din `VANZARI_DETALII.PRET_ACHIZITIE`.
|
|
||||||
- **Interzis**: să atingi `AUTO_NORMARE_COMENZI` (§4); coloane noi la mijlocul gridurilor (§6.1);
|
|
||||||
să publici scriptul la clienți fără cererea explicită a lui Marius; commit fără ca Marius să vadă
|
|
||||||
diff-ul.
|
|
||||||
- Conectare la Oracle de dev: vezi `COMUN\docs\conventie_mediu_oracle.md` §4.
|
|
||||||
- `docs/handoff_comenzi_luna_curenta.md` și `docs/handoff_cost_materiale_manopera.md` sunt predări de
|
|
||||||
subagenți, integral acoperite de acest document — de ignorat sau de șters.
|
|
||||||
|
|
||||||
## 1. Cererea clientului
|
|
||||||
|
|
||||||
> „în vizualizare comenzi în luna curentă (la fel și pentru facturile în luna curentă), am nevoie
|
|
||||||
> să apară și orele manoperă, valoare manoperă, valoare piese facturate și valoare piese achiziție"
|
|
||||||
|
|
||||||
Îngrijorarea ta: comenzile deschise în luna curentă pot fi foarte vechi, deci calculul valorii și
|
|
||||||
costului materialelor din `RUL` ar însemna o selecție pe toată baza. Constrângeri: Oracle Express
|
|
||||||
(fără view-uri materializate), compatibil Oracle 10g.
|
|
||||||
|
|
||||||
## 2. Descoperirea care schimbă tot: funcționalitatea există deja
|
|
||||||
|
|
||||||
Ecranul **„Istoric comenzi"** (meniu Comenzi, butonul de lângă „Vizualizare comenzi" —
|
|
||||||
`Clase/ofundal_dev.vc2:685` → `vizualizare_ist_comenzi`) afișează **deja exact cele patru valori
|
|
||||||
cerute**, plus încă două.
|
|
||||||
|
|
||||||
Cursorul vine din view-ul Oracle `AUTO_ISTORIC_COMENZI`
|
|
||||||
(`Programe/oproceduri_vizualizare.prg:443-476`), iar gridul din `frm_istoric_comenzi`
|
|
||||||
(`Clase/oviz_devize.vc2:9115`) are coloanele:
|
|
||||||
|
|
||||||
| Coloană grid | Coloană view | Ce e |
|
|
||||||
|---|---|---|
|
|
||||||
| `cOreManopera` | `ORE_MANOPERA` | ore manoperă (normate, din deviz) |
|
|
||||||
| `cValManopera` | `VAL_MANOPERA` | valoare manoperă (din deviz) |
|
|
||||||
| `cValManoperaFactura` | `VAL_MANOPERA_FACTURA` | manoperă efectiv facturată (din contabilitate, cont 704) |
|
|
||||||
| `cValMaterialeVz` | `VAL_MATERIALE_VZ` | **valoare piese la preț de vânzare** |
|
|
||||||
| `cValMaterialeAch` | `VAL_MATERIALE_ACH` | **valoare piese la preț de achiziție** |
|
|
||||||
| `cValMaterialeFactura` | `VAL_MATERIALE_FACTURA` | materiale efectiv facturate (cont 707/419) |
|
|
||||||
|
|
||||||
Diferența față de ce cere clientul este **doar filtrul**: „Istoric comenzi" pornește de la
|
|
||||||
`lcFiltru = [2=2]` (`Clase/oviz_devize.vc2:10193`) cu filtre opționale pe interval de `datai`, în
|
|
||||||
timp ce „Vizualizare comenzi" pornește de la `gcCondLuna`
|
|
||||||
(`Clase/oviz_devize.vc2:15187`, definit în `Programe/ovariabile_globale.prg:16`).
|
|
||||||
|
|
||||||
**Deci munca reală nu e „de calculat ceva nou", ci „de mutat 4-6 coloane deja existente și
|
|
||||||
verificate în producție pe alte două ecrane".**
|
|
||||||
|
|
||||||
## 3. Analiza de cost pe bază de date
|
|
||||||
|
|
||||||
### 3.1 Costul de achiziție al pieselor NU se recalculează — e fixat la bonul de consum
|
|
||||||
|
|
||||||
Pe fluxul auto, piesele **ies din gestiune la bonul de consum**, nu la facturare. În momentul
|
|
||||||
emiterii bonului, pe rândul de ieșire din `RUL` se scriu deodată:
|
|
||||||
|
|
||||||
- `RUL.PRET` = preț de achiziție
|
|
||||||
- `RUL.PRETV` = preț de vânzare
|
|
||||||
- `RUL.ADAOS` / `VALOARE_ADAOS` = adaosul
|
|
||||||
- `RUL.CANTE` = cantitatea ieșită
|
|
||||||
|
|
||||||
Exemplu real (`id_lucrare=14`): `pret=27.88`, `pretv=32.062`, `cante=1`.
|
|
||||||
|
|
||||||
**Facturarea comenzii auto nu mai descarcă nimic** — doar citește din `RUL` ce s-a consumat deja și
|
|
||||||
calculează valoarea de vânzare a materialelor, alături de manoperă.
|
|
||||||
`frm_emitere_facturi.do_factureaza_final` (`Clase/oviz_devize.vc2:2358-2366`):
|
|
||||||
|
|
||||||
```sql
|
|
||||||
select b.denumire, b.um, a.cante as cant, a.pretv, a.pret, a.dataact, a.id_rul, ...
|
|
||||||
from (select id_articol, id_lucrare, pretv, ..., SUM(cante) as cante, ...
|
|
||||||
from rul where sters = 0 and id_lucrare = <id_lucrare>
|
|
||||||
group by id_lucrare, id_articol, pretv) a
|
|
||||||
left join nom_articole b on a.id_articol = b.id_articol
|
|
||||||
where a.cante <> 0
|
|
||||||
```
|
|
||||||
|
|
||||||
Deci `PACK_FACTURARE.cursor_gestiuni_articol` (descărcarea FIFO din `STOC` la emiterea facturii)
|
|
||||||
**nu e pe traseul comenzii auto** — acela e fluxul de facturare direct din stoc, al celorlalte
|
|
||||||
aplicații ROA. Pentru ROAAUTO, sursa de adevăr pentru ambele prețuri este rândul de ieșire din
|
|
||||||
`RUL`, scris la bonul de consum.
|
|
||||||
|
|
||||||
Consecința pentru cerere: `val_materiale_ach = sum(pret*cante)` și
|
|
||||||
`val_materiale_vz = sum(pretv*cante)` citesc exact valorile de pe bonurile de consum ale comenzii.
|
|
||||||
**Nicio reconstrucție de cost la raportare** — nici FIFO, nici medie ponderată. Îngrijorarea legată
|
|
||||||
de recalculul costului nu se confirmă.
|
|
||||||
|
|
||||||
`RUL` nu conține niciodată manoperă: descărcarea sare articolele cu `NOM_ARTICOLE.IN_STOC = 0`
|
|
||||||
(`SCRIPTURI_CLAR\2026\09\ff_2026_09_16_04_COMUN_PACK_FACTURARE.sql:8264-8270`):
|
|
||||||
|
|
||||||
```sql
|
|
||||||
SELECT MAX(IN_STOC) INTO lnInStoc FROM NOM_ARTICOLE WHERE ID_ARTICOL = V_ID_ARTICOL;
|
|
||||||
if lnInStoc = 0 then GOTO SFARSIT; end if;
|
|
||||||
```
|
|
||||||
|
|
||||||
Confirmat și pe date: ieșirile cu `id_lucrare` au doar conturi de stoc (371, 303, 345, 302x),
|
|
||||||
niciodată 704. Deci suma nu amestecă manopera cu piesele.
|
|
||||||
|
|
||||||
**De ce NU se folosește `VANZARI_DETALII.PRET_ACHIZITIE` ca sursă a costului.** Tocmai pentru că, pe
|
|
||||||
fluxul auto, factura nu descarcă gestiunea, coloana aceea nu se populează. Pe schema de test e 0 pe
|
|
||||||
aproape tot, inclusiv pe liniile de piese:
|
|
||||||
|
|
||||||
| `NOM_ARTICOLE.IN_STOC` | linii | din care `PRET_ACHIZITIE = 0` |
|
|
||||||
|---|---|---|
|
|
||||||
| 0 (servicii/manoperă) | 2 526 | 2 475 (98 %) |
|
|
||||||
| 1 (piese, gestionabile) | 8 889 | **8 561 (96 %)** |
|
|
||||||
|
|
||||||
`RUL.PRET` rămâne singura sursă corectă — și e oricum cea folosită deja de `AUTO_ISTORIC_COMENZI`.
|
|
||||||
|
|
||||||
### 3.2 Subinterogarea pe `RUL` merge pe index, nu pe toată baza
|
|
||||||
|
|
||||||
Formularea din `AUTO_ISTORIC_COMENZI`:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
(select sum(round(pret * cante, 2)) from rul where sters = 0 and id_lucrare = a.id_lucrare) as val_materiale_ach,
|
|
||||||
(select sum(round(pretv * cante, 2)) from rul where sters = 0 and id_lucrare = a.id_lucrare) as val_materiale_vz
|
|
||||||
```
|
|
||||||
|
|
||||||
Există indexul **`IDX_RUL_001 (ID_LUCRARE, STERS)`**, creat încă din
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI\2009\1\ff_2009_01_21_01_GESTIUNI.sql:63` și folosit explicit, cu hint,
|
|
||||||
în `pack_auto.actualizeaza_deviz`
|
|
||||||
(`D:\ROA\DATABASE\SCRIPTURI_CLAR\2026\03\ff_2026_03_31_02_AUTO_PACK_AUTO.sql:711`, acum șase luni)
|
|
||||||
— deci e viu în producție, la toți clienții actualizați. `EXPLAIN PLAN` confirmă că Oracle împinge
|
|
||||||
predicatul și accesează `RUL` prin:
|
|
||||||
|
|
||||||
```
|
|
||||||
VIEW PUSHED PREDICATE VW_SSQ_4
|
|
||||||
SORT GROUP BY
|
|
||||||
TABLE ACCESS BY INDEX ROWID BATCHED RUL
|
|
||||||
INDEX RANGE SCAN IDX_RUL_001 (access "ID_LUCRARE"=... AND "STERS"=0)
|
|
||||||
```
|
|
||||||
|
|
||||||
Costul scalează cu **numărul de rânduri afișate × rândurile de rulaj ale acelei comenzi**, nu cu
|
|
||||||
mărimea istoricului. O comandă veche nu costă mai mult decât una nouă.
|
|
||||||
|
|
||||||
### 3.3 Ce chiar costă — și costă DEJA, azi, fără nicio modificare
|
|
||||||
|
|
||||||
`AUTO_NORMARE_COMENZI` (sursa ecranului „Vizualizare comenzi") face deja
|
|
||||||
`left join auto_vordl_facturi` → `auto_vordl_facturate` → **`MV_ORDL_SUME_ACT`**, care e un view
|
|
||||||
normal (nu materializat, în ciuda numelui) ce agregă tabela `ACT` fără filtru de dată.
|
|
||||||
|
|
||||||
La fel `AUTO_FACTURI_EMISE`, care are `join mv_ordl_sume_act`.
|
|
||||||
|
|
||||||
Adică partea „scumpă" e deja plătită la fiecare deschidere a celor două ecrane. În plan, și aceasta
|
|
||||||
primește predicat împins (`INDEX RANGE SCAN IDX_ORDL_AVANS` pe `ACT(ID_LUCRARE,STERS,ID_SET,SCD)`).
|
|
||||||
|
|
||||||
### 3.4 Măsurători (schema de test — cifre relative, nu absolute)
|
|
||||||
|
|
||||||
`autotrace` pe `MARIUSM_AUTO`, toate comenzile din istoric (375 rânduri), respectiv toate facturile
|
|
||||||
(154 rânduri):
|
|
||||||
|
|
||||||
| Variantă | consistent gets | Δ |
|
|
||||||
|---|---|---|
|
|
||||||
| A — `AUTO_NORMARE_COMENZI`, lista de coloane de azi | 660 | — |
|
|
||||||
| B — A + cele 4 coloane, formularea din `AUTO_ISTORIC_COMENZI` | 1 149 | +74 % |
|
|
||||||
| C — ca B, dar cu `/*+ NO_UNNEST */` pe subinterogările de manoperă | 2 107 | +219 % (mai rău) |
|
|
||||||
| D — ca B, dar manopera corelată direct pe `a.id_ordl` | 1 050 | +59 % |
|
|
||||||
| E — `AUTO_FACTURI_EMISE`, lista de coloane de azi | 1 726 | — |
|
|
||||||
| F — E + cele 4 coloane | 1 703 | ≈ 0 |
|
|
||||||
|
|
||||||
Concluzii:
|
|
||||||
|
|
||||||
- Pe **facturi** adăugarea coloanelor e practic gratuită (diferența e zgomot de măsurare): view-ul
|
|
||||||
plătește deja agregarea peste `ACT`.
|
|
||||||
- Pe **comenzi** creșterea e de ordinul a +60-75 % din I/O al ecranului, pe o interogare care azi
|
|
||||||
costă sub o secundă. Absolut: aici baza de test e mică (`RUL` 10 320 rânduri, `ACT` 70 723,
|
|
||||||
`DEV_OPER` 2 414). **Cifra trebuie reconfirmată la client** (punctul 7).
|
|
||||||
- Partea de manoperă (`DEV_ORDL` ⋈ `DEV_OPER` pe `id_lucrare`) este singura care, în planul implicit,
|
|
||||||
se „dez-corelează" într-un `HASH GROUP BY` peste tabelele întregi — deci singura care scalează cu
|
|
||||||
istoricul. Varianta D o evită, dar schimbă semantica dacă o lucrare poate avea mai multe `ordl`
|
|
||||||
(în baza de test raportul e 1:1 pe toate cele 375 de lucrări — de verificat la client).
|
|
||||||
|
|
||||||
### 3.5 Capcană de date
|
|
||||||
|
|
||||||
`RUL.ID_LUCRARE` **nu e null niciodată** — mișcările care nu țin de o lucrare au `ID_LUCRARE = 0`
|
|
||||||
(4 110 din 7 358 rânduri în baza de test, adică 56 %). La un client real acolo stau milioanele de
|
|
||||||
mișcări de stoc obișnuite. O comandă auto are întotdeauna un `id_lucrare > 0` din `NOM_LUCRARI`, deci
|
|
||||||
subinterogarea nu ar trebui să nimerească niciodată „găleata" 0 — dar merită o gardă explicită
|
|
||||||
(`and a.id_lucrare > 0`), altfel un singur rând cu `id_lucrare = 0` scanează tot.
|
|
||||||
|
|
||||||
### 3.6 Unde chiar există problema de care te temeai (dar în alt loc)
|
|
||||||
|
|
||||||
`Programe/oproceduri_listari.prg:1607-1625`, procedura `facturi_emise_pe_sectii`:
|
|
||||||
|
|
||||||
```sql
|
|
||||||
left join (select sum(round(pret * cante, 2)) as valoarea,
|
|
||||||
sum(round(pretv * cante, 2)) as valoarev, id_lucrare, id_sectie
|
|
||||||
from rul where sters = 0 group by id_lucrare, id_sectie) e
|
|
||||||
on a.id_lucrare = e.id_lucrare and a.id_sectie = e.id_sectie
|
|
||||||
```
|
|
||||||
|
|
||||||
Aici subselectul chiar grupează **tot** `RUL` (singurul filtru e `sters = 0`), iar join-ul pe
|
|
||||||
perioadă se face abia după. Ăsta e „selecția pe toată baza" reală — dar în raportul de facturi
|
|
||||||
emise pe secții, nu în ecranele din cerere. De reținut ca anti-pattern (formularea propusă aici,
|
|
||||||
corelată pe `id_lucrare`, îl evită) și ca loc de reparat separat dacă raportul acela e lent la
|
|
||||||
client.
|
|
||||||
|
|
||||||
## 4. Variante
|
|
||||||
|
|
||||||
### Varianta 0 — niciun cod: clientul folosește „Istoric comenzi"
|
|
||||||
Zero efort, zero risc. Dezavantaj: filtrul e pe interval de `datai`, nu „comenzi deschise în luna
|
|
||||||
curentă", și nu acoperă deloc ecranul de facturi. **Merită propusă clientului ca soluție imediată**,
|
|
||||||
cât timp se lucrează la restul.
|
|
||||||
|
|
||||||
### Varianta 1 (APROBATĂ) — ecranul de comenzi trece pe `AUTO_ISTORIC_COMENZI`
|
|
||||||
Ideea lui Marius, mai bună decât varianta inițială: nu se copiază subinterogările în
|
|
||||||
`AUTO_NORMARE_COMENZI`, ci **`vizualizare_comenzi` își schimbă sursa** pe `AUTO_ISTORIC_COMENZI`,
|
|
||||||
păstrând filtrul `gcCondLuna`.
|
|
||||||
|
|
||||||
Comparația coloanelor celor două view-uri (rulată pe `MARIUSM_AUTO`) arată că
|
|
||||||
`AUTO_ISTORIC_COMENZI` conține tot ce folosește azi `frm_viz_comenzi`, cu **o singură excepție**:
|
|
||||||
`INCH_VALIDARE`, de care are nevoie `gcCondLuna`. Se adaugă din `dev_tip_deviz`, deja joinat acolo
|
|
||||||
(`i.inch_validare`).
|
|
||||||
|
|
||||||
De ce e mai bună:
|
|
||||||
|
|
||||||
- **un singur view modificat, cu o singură coloană** — în loc de patru subinterogări în două view-uri;
|
|
||||||
- `AUTO_NORMARE_COMENZI` rămâne **neatins**, iar el mai e folosit în **10 alte locuri**
|
|
||||||
(`Programe/oproceduri_devize.prg:233` și `:1632`, `Programe/oproceduri_listari.prg:998`,
|
|
||||||
`Programe/oproceduri_vizualizare.prg:387` și `:515`, `Clase/oviz_devize.vc2:1579`, `:2316`,
|
|
||||||
`:4481`, `:11724`, `:18751`), inclusiv un `select *`. Varianta inițială le-ar fi pus pe toate să
|
|
||||||
plătească subinterogările degeaba;
|
|
||||||
- SQL-ul de calcul rămâne exact cel rulat deja în producție pe „Istoric comenzi" → risc semantic zero;
|
|
||||||
- compatibil Oracle 10g, fără obiecte noi, fără indecși noi, fără MV.
|
|
||||||
|
|
||||||
Ecranul de facturi rămâne pe `AUTO_FACTURI_EMISE` (altă formă — un rând per factură, cu `nrcrt`),
|
|
||||||
deci acolo cele patru coloane se adaugă în view.
|
|
||||||
|
|
||||||
### Varianta 2 — optimizarea manoperei (corelare pe `id_ordl`)
|
|
||||||
Subinterogările de manoperă scrise direct pe `DEV_OPER` prin `a.id_ordl` (index `IDX_OPER_01`), în
|
|
||||||
loc de `DEV_ORDL ⋈ DEV_OPER` pe `id_lucrare`. Scapă de singurul acces care scalează cu istoricul.
|
|
||||||
Marius a confirmat că **o lucrare are exact un `dev_ordl`**, deci e aplicabilă — dar rămâne o
|
|
||||||
optimizare ulterioară, de făcut doar dacă măsurătorile la client o cer. Nu intră în livrarea curentă.
|
|
||||||
|
|
||||||
### Varianta 3 — tabelă de totaluri întreținută la validare/facturare
|
|
||||||
Un `AUTO_COMENZI_TOTALURI(id_lucrare, ore_manopera, val_manopera, val_mat_ach, val_mat_vz)` scris de
|
|
||||||
`PACK_DEVIZE`/`PACK_FACTURARE` la validare și la facturare. Citire O(1) per rând.
|
|
||||||
**Nerecomandat acum**: cost mare (pachet + migrare + backfill + risc de desincronizare) pentru o
|
|
||||||
problemă care, după măsurători, nu există încă. De ținut în sertar dacă varianta 1 se dovedește
|
|
||||||
lentă la un client cu volum mare.
|
|
||||||
|
|
||||||
## 5. Plan de implementare — APROBAT de Marius, 22.09.2026
|
|
||||||
|
|
||||||
Ordinea contează: întâi baza, apoi VFP — altfel cursorul cere coloane inexistente.
|
|
||||||
|
|
||||||
**Pas 1 — script de bază de date.** Versiunile curente ale celor trei view-uri sunt în
|
|
||||||
`D:\ROA\DATABASE\SCRIPTURI_CLAR\` (istoricul de migrări, SVN, partajat între aplicațiile ROA — nu
|
|
||||||
în `Scripturi_instalare\` din ROAAUTO, care e doar install-ul inițial):
|
|
||||||
|
|
||||||
- `AUTO_ISTORIC_COMENZI` — `2025\06\ff_2025_06_30_01_AUTO.sql:37-95`
|
|
||||||
- `AUTO_FACTURI_EMISE` — de localizat în același arbore
|
|
||||||
|
|
||||||
Se scrie un script nou cu `CREATE OR REPLACE VIEW`, necalificat, fără prefix de schemă:
|
|
||||||
|
|
||||||
- **`AUTO_ISTORIC_COMENZI`**: se adaugă o singură coloană, `i.inch_validare`, din `dev_tip_deviz`
|
|
||||||
deja joinat. Restul view-ului rămâne neschimbat.
|
|
||||||
- **`AUTO_FACTURI_EMISE`**: se adaugă `ORE_MANOPERA`, `VAL_MANOPERA`, `VAL_MATERIALE_ACH`,
|
|
||||||
`VAL_MATERIALE_VZ`, copiate literal din `AUTO_ISTORIC_COMENZI`, cu garda `a.id_lucrare > 0`.
|
|
||||||
(`MANOPERA` și `MATERIALE` — cele facturate — există deja acolo.)
|
|
||||||
|
|
||||||
`AUTO_NORMARE_COMENZI` **nu se atinge.**
|
|
||||||
|
|
||||||
Se rulează **doar la cererea ta explicită**, pe `MARIUSM_AUTO` de pe `ROA_CENTRAL` întâi. Se publică
|
|
||||||
apoi prin fluxul obișnuit de scripturi de actualizare (vezi skill-ul `roa-oracle-migration`).
|
|
||||||
|
|
||||||
**Pas 2 — cursoarele VFP** (`Programe/oproceduri_vizualizare.prg`):
|
|
||||||
|
|
||||||
- `vizualizare_comenzi` (`:649`) — sursa se schimbă din `auto_normare_comenzi` în
|
|
||||||
**`auto_istoric_comenzi`**; `pcschema` și `pcselect` se extind cu `ORE_MANOPERA`, `VAL_MANOPERA`,
|
|
||||||
`VAL_MANOPERA_FACTURA`, `VAL_MATERIALE_VZ`, `VAL_MATERIALE_ACH`, `VAL_MATERIALE_FACTURA`
|
|
||||||
(`N(20,4)`, ca în `vizualizare_ist_comenzi`). Filtrul rămâne `gcCondLuna`.
|
|
||||||
- `vizualizare_facturi` (`:231`) — `pcschema`/`pcselect` extinse cu cele 4 coloane noi.
|
|
||||||
|
|
||||||
**Pas 3 — gridurile** (`Clase\oviz_devize.vc2`, write-back prin `txt2vcx.ps1`):
|
|
||||||
|
|
||||||
- `frm_viz_comenzi` (`:14503`, grid `grdcomenzi`) — coloane noi **la coadă**, copiate ca definiție
|
|
||||||
(format, aliniere, `InputMask`) din coloanele omoloage ale lui `frm_istoric_comenzi` (`:9115`,
|
|
||||||
`Column19`-`Column25`).
|
|
||||||
- `frm_viz_facturi` (`:16762`, grid `grdfacturi`) — idem.
|
|
||||||
|
|
||||||
`do_excel` iterează generic peste `grid.Columns` pe ambele formulare
|
|
||||||
(`Clase/oviz_devize.vc2:15208` și `:17472`) — coloanele noi apar automat în export, fără cod.
|
|
||||||
|
|
||||||
`do_listare` diferă între ecrane:
|
|
||||||
- la comenzi (`:15381`) nu atinge gridul — nimic de făcut;
|
|
||||||
- la facturi (`:17570`) exportă prin raportul `.frx` **`rap_facturi_clienti`**
|
|
||||||
(`goExport.export2frx`). Dacă se vrea coloana și pe listarea tipărită, raportul se editează
|
|
||||||
**doar în IDE-ul VFP** (fără write-back din text).
|
|
||||||
|
|
||||||
**Pas 4 (opțional) — totaluri pe ecranul de facturi.** `frm_viz_facturi.refreshdata`
|
|
||||||
(`Clase/oviz_devize.vc2:17610`) calculează deja sumele afișate sub grid pe `valctva`, `manopera`,
|
|
||||||
`materiale`, cu `WHERE nrcrt=1` pentru deduplicarea liniilor multiple pe aceeași factură. Totalurile
|
|
||||||
pentru coloanele noi se adaugă aici, cu aceeași gardă `nrcrt=1`, altfel se dublează.
|
|
||||||
|
|
||||||
**Pas 5 (opțional) — listarea facturilor.** `do_listare` la facturi (`:17570`) exportă prin raportul
|
|
||||||
`.frx` `rap_facturi_clienti`. Coloanele noi se adaugă acolo **doar în IDE-ul VFP** (fără write-back
|
|
||||||
din text). La comenzi, `do_listare` (`:15381`) nu atinge gridul — nimic de făcut.
|
|
||||||
|
|
||||||
**Pas 6 — testare.** Pe lângă cronometrarea pe lună curentă la un client cu volum mare:
|
|
||||||
- valorile din ecranul de comenzi trebuie să coincidă cu cele din „Istoric comenzi" pentru aceleași
|
|
||||||
comenzi (aceeași sursă, deci trebuie să fie identice);
|
|
||||||
- `do_executa` și `do_listare` din `frm_viz_comenzi` fac `Scatter Name ocomanda` pe cursor și pasează
|
|
||||||
obiectul la `vizualizeaza_detalii_comanda` / `listare_comanda_deviz`. Câmpurile folosite
|
|
||||||
(`id_ordl`, `id_lucrare`, `proc_tvav`, `validat`) există în ambele view-uri, dar **schimbarea
|
|
||||||
sursei cursorului trebuie verificată la rulare** — e singurul punct unde se poate rupe ceva.
|
|
||||||
|
|
||||||
## 6. Capcane de reținut la implementare
|
|
||||||
|
|
||||||
1. **GridExtras — coloanele noi se adaugă OBLIGATORIU la coadă.** Ambele formulare apelează
|
|
||||||
`this.gridextra1.setup()` (`Clase/oviz_devize.vc2:15441` și `:17607`), deci preferințele de
|
|
||||||
coloane sunt salvate per utilizator în `gridprefs.tmp`. `restoregridpreferences`
|
|
||||||
(`COMUN/utile/GridExtras/gridextras.vc2:1051`) aplică perechile `ColumnOrder,Width`
|
|
||||||
**pozițional**, pe index de coloană:
|
|
||||||
`loColumn = toGridObject.Columns((lnCounter + 1)/2)`, cu
|
|
||||||
`lnMax = Min(ColumnCount_nou * 2, Alen(preferinte_vechi))`.
|
|
||||||
Consecințe:
|
|
||||||
- coloană adăugată **la coadă** (`Column14`, `Column13`): preferințele vechi 1..N se aplică
|
|
||||||
corect, iar coloana nouă ajunge vizual ultima (acceptabil — vezi soluția de repoziționare
|
|
||||||
runtime din `COMUN\docs\capcana_grid_preferinte_utilizator.md`, aplicată pe `frm_modific2024`);
|
|
||||||
- coloană **inserată la mijloc**: preferințele vechi se aplică peste coloane deplasate → lățimi
|
|
||||||
și ordini greșite pentru toți utilizatorii existenți. **De evitat.**
|
|
||||||
2. **`ALTER TABLE` pe cursorul de la `goExecutor`** nu merge — coloanele noi trebuie să fie în
|
|
||||||
`SELECT` de la început (`COMUN\docs\conventie_goexecutor_alter_table.md`). Aici e respectat by
|
|
||||||
design, pentru că se modifică `pcselect`.
|
|
||||||
3. **Encoding CP1252** la editarea `.vc2` (`COMUN\docs\conventie_encoding_cp1252.md`); write-back doar
|
|
||||||
prin `txt2vcx.ps1`, skill `roa-vfp-text-edit`.
|
|
||||||
4. `CursorFill` aduce **tot** setul de rezultate în cursor local (`COMUN\clase\decabaza.vc2:36`), deci
|
|
||||||
costul e proporțional cu numărul de rânduri returnate — filtrul de lună chiar contează.
|
|
||||||
5. Filtrele sunt diferite pe cele două ecrane: facturi = strict `dataact` în luna curentă
|
|
||||||
(`Clase/oviz_devize.vc2:17425`); comenzi = `gcCondLuna`, care include **și comenzi mai vechi
|
|
||||||
nefacturate/nevalidate** (`Programe/ovariabile_globale.prg:16`). Asta e sursa reală a comenzilor
|
|
||||||
„foarte vechi" — dar, cum s-a arătat la 3.2, vechimea nu scumpește subinterogările.
|
|
||||||
|
|
||||||
6. **Planul de execuție măsurat pe `MARIUSM_AUTO` nu spune nimic despre client — și greșește în
|
|
||||||
ambele sensuri.** Plătită pe 22.09.2026, măsurând aceeași interogare pe dev și pe producția
|
|
||||||
AUTOMOTIVE:
|
|
||||||
- pe dev (`RUL` = 10 374 rânduri) optimizatorul **dez-corelează** subinterogările scalare
|
|
||||||
(unnesting) într-un `GROUP BY` global și face `TABLE ACCESS FULL` pe `RUL` — concluzia ar fi
|
|
||||||
fost „indexul nu se folosește, e periculos";
|
|
||||||
- pe producție (`RUL` = 571 508 rânduri) aceeași interogare păstrează subinterogările corelate
|
|
||||||
și folosește `INDEX RANGE SCAN IDX_RUL_001` — exact invers.
|
|
||||||
|
|
||||||
Costul subinterogărilor corelate se înmulțește cu numărul de rânduri afișate
|
|
||||||
(~16 buffer gets/rând), deci și numărul acela trebuie luat de la client.
|
|
||||||
|
|
||||||
**Regulă**: orice afirmație despre plan sau cost pentru o interogare cu subinterogări corelate
|
|
||||||
se verifică pe un client real, nu pe `MARIUSM_AUTO`. Două lucruri trebuie luate de la client,
|
|
||||||
nu de pe dev: **forma planului** (corelat vs dez-corelat) și **numărul de rânduri returnate**.
|
|
||||||
|
|
||||||
7. **`gcCondLuna` nu înseamnă „luna curentă".** Include și comenzile vechi nefacturate
|
|
||||||
(`inch_validare=0`) sau nevalidate (`inch_validare=1`). La AUTOMOTIVE, luna 10/2025: 107 comenzi
|
|
||||||
ale lunii + 88 vechi = **195 de rânduri** (164 după filtrul implicit „Active") — deci coada
|
|
||||||
veche e mică aici, dar numărul trebuie măsurat, nu presupus. **Atenție**: se măsoară doar cu
|
|
||||||
`pack_sesiune.setluna/setan` inițializate (`docs/vfp_oracle_pack_sesiune.md`); altfel `validat`
|
|
||||||
iese 0 peste tot și numărul sare la 32 790.
|
|
||||||
|
|
||||||
## 7. Verificat pe producție (AUTOMOTIVE, 22-23.09.2026) — închis
|
|
||||||
|
|
||||||
Măsurat prin tunel SSH, strict read-only. Detalii și planuri:
|
|
||||||
`docs/review/teste_coloane_manopera_piese_viz.md`, secțiunea „Teste pe PRODUCTIE".
|
|
||||||
|
|
||||||
> **Corectat 23.09.2026.** Măsurătoarea din 22.09 (32 790 rânduri / ~50 s) era **invalidă**:
|
|
||||||
> rulată din `sqlplus` fără inițializarea lunii de lucru. Vezi
|
|
||||||
> `docs/vfp_oracle_pack_sesiune.md`. Cifrele de mai jos sunt cele refăcute corect.
|
|
||||||
|
|
||||||
1. **Câte rânduri întoarce „Vizualizare comenzi" pe luna curentă și cât durează?**
|
|
||||||
Cu luna de lucru 10/2025 inițializată (`pack_sesiune.setluna/setan`, exact ce face aplicația la
|
|
||||||
login): **195 de rânduri** cu filtrul `gcCondLuna` gol, **164** cu filtrul implicit al
|
|
||||||
formularului (`cbArhivat = "Active"` → `inchis_fortat = 0`, `Clase/oviz_devize.vc2:15630`).
|
|
||||||
**~3.3 s prin tunel.** Ecranul nu e greu la acest client.
|
|
||||||
2. **Dimensiunile reale**: `ACT` 833 257, `RUL` 571 508, `DEV_OPER` 137 285, `DEV_ORDL` 38 609.
|
|
||||||
`RUL` are 215 269 de rânduri cu `ID_LUCRARE = 0` (161 259 cu `STERS = 0`) — garda
|
|
||||||
`id_lucrare > 0` nu e teoretică, chiar ține la distanță 161 de mii de rânduri.
|
|
||||||
3. **`IDX_RUL_001` există la client?** **Da**, `NORMAL NONUNIQUE (ID_LUCRARE, STERS)`, și **este
|
|
||||||
folosit** de planul formei noi. Nu e nevoie de `CREATE INDEX`.
|
|
||||||
4. ~~Poate o lucrare să aibă mai multe `dev_ordl`?~~ **Închis**: exact unul.
|
|
||||||
5. ~~„Valoare manoperă" = deviz sau facturat?~~ **Închis**: se livrează amândouă.
|
|
||||||
|
|
||||||
### 7.6 Costul măsurat pe producție, pe filtrul real (refăcut 23.09.2026)
|
|
||||||
|
|
||||||
Aceeași sesiune, luna de lucru 10/2025 inițializată, filtrul implicit al formularului
|
|
||||||
(`inchis_fortat = 0`), 164 de rânduri, două rulări fiecare, scăzut overhead-ul de conectare:
|
|
||||||
|
|
||||||
| Variantă | timp net |
|
|
||||||
|---|---|
|
|
||||||
| fără coloanele noi | 3.3 s |
|
|
||||||
| cu cele 6 coloane noi | 3.7 s |
|
|
||||||
| raport | **×1.13 (+0.4 s)** |
|
|
||||||
|
|
||||||
Prin tunel SSH; în LAN-ul clientului, mai puțin. Costul scalează cu **numărul de rânduri
|
|
||||||
afișate** (~16 buffer gets/rând), deci diferența rămâne mică atâta timp cât ecranul întoarce
|
|
||||||
sute, nu zeci de mii de rânduri.
|
|
||||||
|
|
||||||
### 7.7 Ce facem cu asta — decis 23.09.2026
|
|
||||||
|
|
||||||
**Nu e nimic de decis.** Problema de performanță (cele 32 790 de rânduri / 50 s) nu există:
|
|
||||||
era artefactul măsurătorii, nu al datelor. Pe filtrul real ecranul întoarce 164 de rânduri, iar
|
|
||||||
coloanele noi adaugă ~0.4 s.
|
|
||||||
|
|
||||||
Variantele 2 (strângerea filtrului) și 3 (tabelă de totaluri întreținută) **nu se mai justifică**
|
|
||||||
— nu mai au ce să rezolve. Se merge cu implementarea existentă, la review pe diff.
|
|
||||||
|
|
||||||
## 8. Recomandare
|
|
||||||
|
|
||||||
Varianta 1, aprobată de Marius pe 22.09.2026: ecranul de comenzi trece pe `AUTO_ISTORIC_COMENZI`
|
|
||||||
(cu `INCH_VALIDARE` adăugat), ecranul de facturi primește cele patru coloane în
|
|
||||||
`AUTO_FACTURI_EMISE`, cu garda `id_lucrare > 0`. `AUTO_NORMARE_COMENZI` rămâne neatins.
|
|
||||||
|
|
||||||
Este cel mai mic diff posibil care rezolvă cererea, reutilizează SQL deja rulat în producție și nu
|
|
||||||
adaugă niciun obiect nou în bază. Până la livrare, clientul poate folosi „Istoric comenzi"
|
|
||||||
(varianta 0).
|
|
||||||
Reference in New Issue
Block a user