Files
roaauto/docs/handoff_cost_materiale_manopera.md
2026-09-22 19:43:55 +03:00

157 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.**