sync SVN r18196
This commit is contained in:
72
docs/handoff_comenzi_luna_curenta.md
Normal file
72
docs/handoff_comenzi_luna_curenta.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# 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.
|
||||
156
docs/handoff_cost_materiale_manopera.md
Normal file
156
docs/handoff_cost_materiale_manopera.md
Normal file
@@ -0,0 +1,156 @@
|
||||
# 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.**
|
||||
371
docs/propuneri_coloane_manopera_piese_viz.md
Normal file
371
docs/propuneri_coloane_manopera_piese_viz.md
Normal file
@@ -0,0 +1,371 @@
|
||||
# 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 — predare către o sesiune nouă
|
||||
|
||||
**Acesta este fișierul de implementat.** Planul e la §5, aprobat de Marius pe 22.09.2026.
|
||||
|
||||
- **Nimic implementat.** Zero fișiere de cod atinse, zero scripturi rulate pe Oracle, zero commit-uri.
|
||||
`git status` are doar fișiere noi în `docs/`.
|
||||
- **Nimic într-o stare periculoasă**: fără editări de binar fără write-back, fără tranzacții deschise,
|
||||
fără procese rămase vii, fără date de test consumate.
|
||||
- **Primul pas într-o sesiune nouă**: `git_sync.ps1` (obligatoriu la început de sesiune), apoi §5 pas 1.
|
||||
- **Decizii deja luate, nu le relua**: §4 varianta 1 (ecranul de comenzi trece pe
|
||||
`AUTO_ISTORIC_COMENZI`, nu se modifică `AUTO_NORMARE_COMENZI`); manopera se livrează în ambele
|
||||
forme (deviz + facturat); costul se ia din `RUL.PRET`, nu din `VANZARI_DETALII.PRET_ACHIZITIE`.
|
||||
- **Interzis**: să atingi `AUTO_NORMARE_COMENZI` (§4); să inserezi coloane noi la mijlocul gridurilor
|
||||
(§6.1); să rulezi scriptul de bază fără cererea explicită a lui Marius (§5 pas 1); să dai commit
|
||||
fără ca Marius să vadă întâi diff-ul complet.
|
||||
- **Rămâne de aflat de la client** (§7.1-7.3): rânduri + timp actual pe luna curentă la baza cea mai
|
||||
mare, dimensiunile `RUL`/`ACT`/`DEV_OPER`, existența `IDX_RUL_001`. Nu blochează pașii 1-3.
|
||||
- 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.
|
||||
|
||||
## 7. De verificat înainte de implementare
|
||||
|
||||
1. **La clientul cu cea mai mare bază**: câte rânduri întoarce azi „Vizualizare comenzi" pe luna
|
||||
curentă, și cât durează deschiderea acum. Fără numărul ăsta, procentele de la 3.4 nu spun nimic
|
||||
despre experiența reală.
|
||||
2. Dimensiunile reale ale `RUL`, `ACT`, `DEV_OPER` la acel client.
|
||||
3. Există `IDX_RUL_001 (ID_LUCRARE, STERS)` și la client? Aproape sigur da (creat în 2009, folosit
|
||||
cu hint în `pack_auto` în 2026), dar merită confirmat cu o interogare pe `USER_INDEXES` la
|
||||
clientul respectiv. Dacă lipsește, ăsta e **singurul** caz în care apare cu adevărat scanarea pe
|
||||
toată baza de care te temeai — și se rezolvă cu un `CREATE INDEX`, nu cu rescrierea logicii.
|
||||
4. ~~Poate o lucrare să aibă mai multe `dev_ordl`?~~ **Închis**: Marius a confirmat — o
|
||||
`NOM_LUCRARI` are exact un `DEV_ORDL`. Deschide varianta 2 ca optimizare ulterioară.
|
||||
5. ~~„Valoare manoperă" = deviz sau facturat?~~ **Închis**: se livrează amândouă, ca în „Istoric
|
||||
comenzi" — `VAL_MANOPERA` (din `DEV_OPER`, `timpn*pret`) și `VAL_MANOPERA_FACTURA` (cont 704 din
|
||||
`ACT`), respectiv `VAL_MATERIALE_VZ` și `VAL_MATERIALE_FACTURA`. La comenzile încă nefacturate
|
||||
există doar prima; la cele facturate, diferența dintre ele e chiar semnalul util.
|
||||
|
||||
## 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