sync SVN r18196
This commit is contained in:
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