# Tabele + SP-uri Service Auto — MARIUSM_AUTO ground truth (v3) > **Status:** v3 complet rescris 2026-04-11 pe baza sursă producție. > > **Surse (toate din `docs/service-auto/`):** > - `mariusm_ddl_export.sql` — DDL exportat din producție (tabele, views, triggere) > - `pack_auto.pck` — pachet principal service auto > - `PACK_FACTURARE.pck` — pachet facturare > - `PACK_SESIUNE.pck` — session state (dev_idLucrare, dev_idOrdl, getAn/getLuna) > - `PACK_CONTAFIN.pck` — financial utilities (getCotaTVAStandard, get_idFact) > - `PACK_COMENZI.pck` — **pentru ROA ERP base comenzi**, NU service auto > > **Versiuni anterioare invalidate:** > - v1/v2 a referit `vfp_roaauto/Scripturi_instalare/packages.sql` → acel fișier era pentru > **alt produs** ("devize producție"), NU service auto. > - v2 a presupus că tabela e `comenzi`/`vcomenzi` → view-ul `VCOMENZI` din MARIUSM_AUTO > **nu e pentru service auto** (e pentru ROA ERP base, tabela sursă `comenzi` + `nom_masini` + > `id_codclient` + field `interna` cu valori `INTERNA/EXTERNA/GESTIUNE/SECTIE`). > - Service auto = **`DEV_ORDL` + `NOM_LUCRARI`** (pattern de inheritance), cu view-uri > dedicate prefixate `AUTO_*`. --- ## 1. Model de entități — ierarhie ROA + extensie ROAAUTO ``` ┌──────────────────────────────────────────────────────────────────────────┐ │ NOM_LUCRARI (ROA ERP base — header generic al oricărei "lucrări"/comenzi) │ │ id_lucrare PK, nrord, id_mod, facturata, id_fact, id_tata │ │ TRIGGER TRG_NOM_LUCRARI_BEFOINS: NEXTVAL → id_lucrare │ │ pack_sesiune.dev_idLucrare := ID │ └────────────────────────────────┬─────────────────────────────────────────┘ │ FK id_lucrare (FK_DEV_ORDL_002) ▼ ┌──────────────────────────────────────────────────────────────────────────┐ │ DEV_ORDL (ROAAUTO — extensie service auto) │ │ id_ordl PK, id_lucrare FK, id_tip FK, id_masiniclient FK, │ │ id_inspector, id_asigurator, id_part, id_part_ref, id_agent, │ │ validat, inchis_fortat, proc_tvav, kmint, ore_functionare, │ │ solicitari_client CLOB, observatii, defectiuni, nr_dosar, ... │ │ TRIGGER TRG_DEV_ORDL_BEFOINS: NEXTVAL → id_ordl │ │ pack_sesiune.dev_idOrdl := ID │ └──┬───────────────────────────────────────────────┬───────────────────────┘ │ │ │ FK id_ordl │ id_lucrare (NU FK direct, ▼ │ tag logic prin coloană) ┌─────────────────────────────────────┐ ┌─────────────────────────────┐ │ DEV_OPER │ │ RUL (ROA generic warehouse) │ │ (NUMAI manoperă pentru service auto)│ │ id_rul PK, id_lucrare, │ │ id_oper PK, id_ordl FK, │ │ id_articol, cante, pretv, │ │ id_norme FK → DEV_NOM_NORME, │ │ id_set, id_fact, ... │ │ timpn, pret, validat, │ │ │ │ id_util, dataora, sters, nou │ │ Populat de "Bon consum" │ │ │ │ (ointroduceri.prg tip=3) │ │ Coloane id_articol / id_rul_aux: │ │ cu ID_LUCRARE tag. │ │ EXISTĂ în DDL (pentru alt produs │ └─────────────────────────────┘ │ "producție" care partajează schema),│ │ dar NU sunt populate de service auto│ └────┬────────────────────────────────┘ │ FK id_oper ▼ ┌──────────────────────────────────────────────────────────────────────────┐ │ DEV_OPER_MECANICI — distribuția timpului pe mecanici │ │ id_opermecanic PK, id_oper FK, id_mecanic FK, ore │ └──────────────────────────────────────────────────────────────────────────┘ ``` **Materialele consumate pe o comandă NU sunt în `DEV_OPER`.** Sunt în **`RUL`** (tabela generică ROA de rulaje / mișcări de stoc), legate de comandă prin coloana `RUL.ID_LUCRARE`. Flow-ul e: 1. User face "Bon consum" în `ointroduceri.prg` (tip=3) → selectează articole din stoc + tag-uiește comandă (id_lucrare) → salvare 2. Generic ROA warehouse scrie rânduri în `RUL` cu `ID_LUCRARE = X`, `SCD = '3xx'`, `SCC = '6xx'` (consum de stoc) 3. La afișarea devizului și la facturare, materialele se citesc ca `SUM(cante * pretv) FROM RUL WHERE id_lucrare = X` **Notă business Marius 2026-04-11:** este posibil ca `DEV_OPER` să fie folosit de alt program de producție care are și materiale în DEV_OPER (cu `id_articol` + `id_rul_aux` populate), dar **pentru service auto ROAAUTO, `DEV_OPER` conține doar operații de manoperă** — fiecare linie are `id_norme` non-NULL și `id_articol` NULL. **Separat, deviz estimativ (pre-sale, ofertă către client):** ``` DEV_ESTIMARI_REP (deviz estimativ — ofertă pentru client înainte de a începe lucrarea) id_dev_estimare_rep PK, id_lucrare FK, id_norme (manoperă estimată) SAU id_articol (material estimat), cantitate, pret, pret_cu_tva, cota_tva, id_sectie, id_valuta, ... ``` **Cele trei flux-uri paralele și independente pe o lucrare (`id_lucrare`):** | # | Tabel | Ce conține | Când se populează | |---|---|---|---| | 1 | `DEV_ESTIMARI_REP` | Deviz estimativ (manoperă + materiale estimate) dat ca ofertă clientului | **Înainte** de a începe lucrarea | | 2 | `DEV_OPER` | Manopera **reală** executată (doar `id_norme`, service auto) | **În timpul** lucrării | | 3 | `RUL` cu `id_lucrare` | Materialele **reale** consumate (bonuri de consum din stoc) | **În timpul** lucrării | Nu există sincronizare automată: estimarea e doar o ofertă pre-sale, iar lucrarea reală (manoperă + materiale) poate devia de la ea. Comparațiile estimat vs. real se fac în rapoarte analitice, nu în flux-ul operațional. --- ## 2. DEV_ORDL — schema reală producție Exportat via `DBMS_METADATA.GET_DDL` pe 2026-04-11 din MARIUSM_AUTO. **37 coloane**, FK-uri active: | Coloană | Tip | Null | Note | |---|---|---|---| | `id_ordl` | `NUMBER(10)` | NN | PK, alocat de trigger din `SEQ_DEV_ORDL` | | `luna` | `NUMBER(2)` | NN | Luna contabilă (0 default) | | `an` | `NUMBER(4)` | NN | Anul contabil (0 default) | | `id_inspector` | `NUMBER(5)` | Y | FK → `DEV_NOM_INSPECTORI` | | `id_lucrare` | `NUMBER(10)` | NN | **FK → `NOM_LUCRARI` (FK_DEV_ORDL_002)** | | `termen` | `DATE` | Y | Termen execuție (default `SYSDATE + gnTermenZileService`, de obicei +10 zile) | | `datai` | `DATE` | Y | Data intrării | | `orai` / `orae` | `NUMBER(5)` | Y | Ora intrare/ieșire | | `datae` | `DATE` | Y | Data ieșirii | | `validat` | `NUMBER(1)` | NN | 0/1 | | `id_util_ad` | `NUMBER(5)` | NN | User creator | | `id_util_valid` | `NUMBER(5)` | Y | User care a validat | | `dataoraad` | `DATE` | Y | Audit: momentul creării | | `dataoravalid` | `DATE` | Y | Audit: momentul validării | | `id_utils` / `dataoras` | | Y | Audit: ștergere logică | | `id_masiniclient` | `NUMBER(5)` | Y | **FK → `DEV_MASINICLIENTI`** | | `id_asigurator` | `NUMBER(5)` | Y | FK → `DEV_NOM_ASIGURATORI` | | `sters` | `NUMBER(1)` | NN | Soft delete | | `id_tip` | `NUMBER(5)` | NN | **FK → `DEV_TIP_DEVIZ`** (default 1) | | `inchis_fortat` | `NUMBER(1)` | NN | 0/1 — arhivat fără validare | | `kmint` | `NUMBER(10)` | Y | Km la bord intrare | | `nr_dosar` | `VARCHAR2(40)` | Y | Nr. dosar daună (pentru garanție asigurator) | | `solicitari_client` | `CLOB` | Y | Text denormalizat: numele normelor solicitate (agregat prin `STRINGAGG` din `DEV_NOM_NORME` la crearea comenzii) | | `proc_tvav` | `NUMBER(10,4)` | Y | Procent TVA (citit din `pack_contafin.getCotaTVAStandard(luna, an)` la creare) | | `id_part` | `NUMBER(10)` | Y | **FK → `NOM_PARTENERI`** — clientul **direct pe comandă** (nu doar prin mașină) | | `coada_deviz` | `NUMBER(1)` | NN | Flag "în coada devizelor" | | `observatii` | `VARCHAR2(1000)` | Y | | | `data_curs` | `DATE` | Y | Pentru comenzi în valută | | `in_lucru` | `NUMBER(1)` | NN | Flag "comanda în lucru" | | `id_valuta_deviz` | `NUMBER(10)` | Y | FK → `NOM_VALUTE` | | `facturezmix` | `NUMBER(1)` | NN | Flag "facturare mixtă" | | `data_in_lucru` / `dataorainlucru` | `DATE` | Y | Audit trecere în lucru | | `id_agent` | `NUMBER(10)` | Y | FK → `NOM_PARTENERI` (agent vânzări) | | `id_util_inchis` / `dataorainchis` | | Y | Audit "închidere forțată" (arhivare) | | `id_part_ref` | `NUMBER(10)` | Y | FK → `NOM_PARTENERI` (partener referent) | | `ore_functionare` | `NUMBER(10)` | Y | Pentru vehicule utilitare (ore motor în loc de km) | | `defectiuni` | `VARCHAR2(200)` | Y | | **PK:** `PK_DEV_ORDL` pe `id_ordl`. **FK active în producție:** - `FK_DEV_ORDL_001` → `DEV_NOM_INSPECTORI(id_inspector)` ENABLE - `FK_DEV_ORDL_002` → `NOM_LUCRARI(id_lucrare)` **ENABLE** ← constraint critic - `FK_DEV_ORDL_003` → `NOM_PARTENERI(id_part)` ENABLE (client direct) - `FK_DEV_ORDL_004` → `NOM_VALUTE(id_valuta)` ENABLE - `FK_DEV_ORDL_005` → `NOM_PARTENERI(id_agent)` ENABLE - `FK_DEV_ORDL_006` → `NOM_PARTENERI(id_part_ref)` ENABLE **Nu există FK pe `id_masiniclient`** (probabil pentru a permite comenzi pentru mașini temporare sau fără înmatriculare persistentă). **Coloane `AVANS`, `VALCTVA`, `TIP_INCAS`, `ID_CTR`, `ID_FACT`, `ID_CONTRACT`** care apăreau în v2 DDL **NU există** în producție reală. Sunt artefacte ale scripturilor de instalare vechi care au fost abandonate. --- ## 3. NOM_LUCRARI — header parent (ROA ERP base) ```sql NOM_LUCRARI ( id_lucrare NUMBER(10) NN PK, nrord VARCHAR2(50), sters NUMBER(1) NN default 0, id_mod NUMBER(20) NN default 0, -- 1200 pentru service auto inactiv NUMBER(1) NN default 0, facturata NUMBER(1) NN default 0, id_tata NUMBER(10), -- parent hierarchy id_fact NUMBER(20) -- populat la facturare ) ``` **Trigger `TRG_NOM_LUCRARI_BEFOINS`:** ```sql select SEQ_NOM_LUCRARI.NEXTVAL into :new.ID_LUCRARE from dual; pack_sesiune.dev_idLucrare := :new.id_lucrare; -- <-- session state pentru pack_auto ``` **Implicație pentru roa2web:** după `INSERT INTO nom_lucrari ... RETURNING id_lucrare INTO v_local`, ai id-ul în două locuri simultan — în `v_local` (prin RETURNING) și în `pack_sesiune.dev_idLucrare` (prin trigger). Poți folosi oricare. `pack_auto.dev_adauga_lucrare` folosește intern `pack_sesiune.dev_idLucrare` pentru step-ul 2 (INSERT în `DEV_ORDL`). **Trigger `TRG_NOM_LUCRARI_BEFOUPD`:** cheamă `pack_audit.verifica_val(...)` pentru fiecare câmp modificat → toate UPDATE-urile pe `NOM_LUCRARI` sunt **audit trail-uite automat** într-un pachet separat `pack_audit` (nu am încă sursa, nu e în scope imediat). --- ## 4. DEV_OPER — liniile de operații manoperă (doar) **Important:** pentru service auto ROAAUTO, `DEV_OPER` conține **numai operații de manoperă**. Deși schema fizică are coloanele `id_articol`, `id_rul_aux`, `id_dev_estimare_rep` (probabil pentru compatibilitate cu alt produs de producție care partajează aceeași tabelă), **SP-urile `pack_auto.*` pentru service auto nu le populează**. Verificare în body-ul `dev_adauga_operatie` și `dev_adauga_oper_fact`: ambele inserează doar `id_norme`, nu `id_articol`. ```sql DEV_OPER ( id_oper NUMBER(10) NN PK, id_ordl NUMBER(10) NN FK → DEV_ORDL, id_norme NUMBER(10) FK → DEV_NOM_NORME -- SERVICE AUTO: mereu non-NULL timpn NUMBER(8,3) NN default 0, -- ore manoperă pret NUMBER(17,4) NN default 0, -- preț oră (lei/oră) datai DATE NN default SYSDATE, id_sectie NUMBER(5) FK → NOM_SECTII, id_util NUMBER(5), -- validator (populat la validare) dataora DATE, -- momentul validării id_utili NUMBER(5), -- creator (introducător) id_utils NUMBER(5), -- user care a șters dataoras DATE, sters NUMBER(1) NN default 0, validat NUMBER(1) NN default 0, nou NUMBER(1) NN default 0, -- flag heritage-currency RON/ROL id_fact NUMBER(20) FK → DOCUMENTE -- populat la facturare -- Coloanele următoare există în DDL dar NU sunt folosite de service auto: -- id_articol NUMBER(20) FK → NOM_ARTICOLE (pentru alt produs: producție) -- id_dev_estimare_rep NUMBER(20) FK → DEV_ESTIMARI_REP (pentru alt produs) -- id_rul_aux NUMBER(20) FK → RUL_AUXILIAR (pentru alt produs) ) ``` **Materialele consumate NU sunt aici.** Sunt în **`RUL.id_lucrare`** (vezi secțiunea 8 pentru flux-ul de bon consum). **Câmpul `nou`** = flag heritage-currency (RON denominat 2005+ vs vechiul ROL). Setat automat în SP-uri pe baza comparației lună curentă vs `pack_sesiune.GET_ANRON()` / `GET_LUNARON()`. Pentru orice lucrare modernă (post-2005) → mereu `nou = 1`. View-urile `AUTO_VOPER` conțin un `CASE` care împarte `pret` la 10000 pentru valorile ROL vechi. Artefact istoric, zero impact asupra prototype-ului nou. **Trigger `TRG_DEV_OPER_BEFOINS`:** ```sql select SEQ_dev_oper.NEXTVAL into :new.id_oper from dual; ``` (Nu populează session state — deosebire față de DEV_ORDL.) --- ## 5. DEV_ESTIMARI_REP — deviz estimativ pentru client (pre-sale) **Rol:** deviz estimativ pe care service-ul îl oferă clientului **înainte** ca lucrarea să înceapă — o "ofertă" care conține estimarea de manoperă și materiale pentru o reparație propusă. **Este complet separat de lucrarea reală.** ``` DEV_ESTIMARI_REP ≠ DEV_OPER ≠ RUL (id_lucrare) (deviz estimativ (manopera reală (bonuri consum materiale către client, cronometrată pe reale pe comandă, din stoc, manopera + materiale) comandă) din warehouse generic ROA) ``` Cele **trei flux-uri sunt independente**: 1. **DEV_ESTIMARI_REP** — înainte de lucrare, utilizatorul face o estimare pentru client cu linii mixte (manoperă estimată + materiale estimate). Clientul primește devizul, decide dacă aprobă lucrarea. 2. **DEV_OPER** — în timpul lucrării, se înregistrează manopera efectiv executată (doar operații cu `id_norme`, timp real, preț manoperă). 3. **RUL cu `id_lucrare`** — în paralel, bonurile de consum reale scot materiale din stoc tag-uite pe comandă. **Nu există sincronizare automată** între estimare și real — un client poate aproba un deviz estimativ de 1000 lei, dar lucrarea reală să se termine la 1200 lei (fie pentru că s-a găsit ceva în plus, fie pentru că au fost piese mai scumpe decât s-a estimat). Comparația real vs. estimat se face probabil la facturare sau în raporte. **Schema:** fiecare linie e fie manoperă estimată (`id_norme` NN) fie material estimat (`id_articol` NN): ```sql DEV_ESTIMARI_REP ( id_dev_estimare_rep NUMBER(20) NN PK, id_lucrare NUMBER(20) NN FK → NOM_LUCRARI, id_norme NUMBER(20) FK → DEV_NOM_NORME, id_articol NUMBER(20) FK → NOM_ARTICOLE, cantitate NUMBER(20,4) NN, pret NUMBER(20,4) NN default 0, pret_cu_tva NUMBER(1) NN default 0, cota_tva NUMBER(10), id_sectie NUMBER(10) FK → NOM_SECTII, id_pol NUMBER(20) FK → CRM_POLITICI_PRETURI, id_dev_estimare_prod NUMBER(20) FK → DEV_ESTIMARI_PRODUSE, id_articol_grupare NUMBER(20), cu_pierderi NUMBER(1) NN default 0, id_valuta NUMBER(10), semifabricat_ales / semifabricat_id NUMBER(10), id_util / dataora, id_utils / dataoras, sters ) ``` **View-ul UI:** `AUTO_VESTIMARI_REP` — denormalizează `dev_estimari_rep` cu `dev_nom_norme` + `nom_articole`, calculează `pretftva` / `pretctva` / `valftva` / `valtva` / `valoare` prin `pack_sesiune.calculeaza_pret_*` + `calculeaza_total_*`. **SP-uri pentru estimare** (din `pack_auto`): - `adauga_manopera_de(id_lucrare, id_norme, cantitate, pret, pret_cu_tva, cota_tva, id_util)` - `adauga_material_de(id_lucrare, id_articol, cantitate, pret, pret_cu_tva, cota_tva, id_util)` - `modifica_pret_de`, `modifica_cota_tva_de`, `modifica_cantitate_de`, `sterge_articol_de` **NOT IN SCOPE pentru prototype** — estimarea e un sub-flux pre-sale dedicat. --- ## 6. DEV_TIP_DEVIZ — enum tip comandă (cu flag închidere prin validare) ```sql DEV_TIP_DEVIZ ( id_tip NUMBER(5) NN PK, denumire VARCHAR2(50) NN, sters NUMBER(1) NN default 0, inch_validare NUMBER(1) NN default 1 -- 1 = închidere prin validare, 0 = alt mod ) ``` **Coloana `inch_validare`** e cheia pentru a înțelege flux-ul post-validare. Default = 1 (închidere implicită prin validare). Setată per tip-comandă prin `pack_auto.setOptiuneInchidere(v_tip, v_inchidere_validare)` și citită prin `pack_auto.getOptiuneInchidere(v_tip) RETURN NUMBER`. **Valori live confirmate 2026-04-11 de Marius (`SELECT id_tip, denumire, sters, inch_validare FROM MARIUSM_AUTO.DEV_TIP_DEVIZ ORDER BY id_tip`):** | id_tip | denumire | prefix | sters | inch_validare | Natura comenzii | Închidere reală | |---|---|---|---|---|---|---| | 1 | POST GARANTIE | *(fără)* | 0 | **0** | Se facturează client direct | prin factură (`pack_facturare.*`) → `facturat=1` | | 2 | GARANTIE | G | 0 | **0** | Se facturează asigurator prin dosar daună | prin factură → `facturat=1` | | 3 | REGIE | R | 0 | **1** | Auto proprii — NU se facturează | **validare directă** — `validat=1` suficient | | 4 | PREGATIRE | P | 0 | **0** | Se facturează | prin factură → `facturat=1` | | 5 | REGIE 2 | *(fără)* | 0 | **0** | Se facturează | prin factură → `facturat=1` | | 6 | PRODUCTIE | PR | 0 | **1** | Producție internă — NU se facturează | **validare directă** — `validat=1` suficient | | 7 | CONSTATARE | C | 0 | **1** | Doar diagnostic — NU se facturează | **validare directă** — `validat=1` suficient | Prefixele sunt construite în VFP la `oproceduri_devize.prg:108-120` (hardcodate în client, nu în DB). **Semantica `inch_validare` (corectată 2026-04-11 după clarificare iterativă Marius):** Flag-ul decide **dacă validarea comenzii e suficientă pentru a o considera închisă, sau e necesară încă o notă contabilă suplimentară**. - **`inch_validare = 1`** → **Validarea ESTE închiderea.** Comanda se consideră închisă prin simplul fapt că `DEV_ORDL.VALIDAT = 1`. **NU** se generează nicio notă contabilă suplimentară. Folosit tipic pentru comenzi interne (REGIE = auto proprii, PRODUCTIE, CONSTATARE) unde nu se facturează nimic și nu se dorește impact contabil la închidere. - **`inch_validare = 0`** → **Validarea NU e închiderea.** Comanda rămâne "deschisă" contabil chiar și după `VALIDAT = 1`. E nevoie de o notă contabilă suplimentară pentru a o închide real: - Pentru tipuri **facturabile** (GARANTIE, POST GARANTIE, PREGATIRE, REGIE 2) → nota vine prin **facturare** (`pack_facturare.*`), care setează și `facturat = 1` pe flux-ul de agregate. - Pentru tipuri **nefacturabile** (teoretic REGIE/PRODUCTIE dacă ar fi configurate așa) → se generează o notă contabilă `711 = 332` care recunoaște venitul intern și închide stocul "servicii în curs de execuție". **Dovada în cod — view-urile `AUTO_LISTARE_MAN_TOT_COM` și `AUTO_LISTARE_MAN_TOT_DESF`** (`mariusm_ddl_export.sql:1795-1800` și `:1842-1847`) au condiția **exactă** pentru "comandă închisă în luna curentă": ```sql WHERE a.sters = 0 AND ( (extract(month from a.dataoravalid) = pack_sesiune.getluna() AND extract(year from a.dataoravalid) = pack_sesiune.getan() AND a.validat = 1 AND e.inch_validare = 1) -- inchis prin validare singura OR (extract(month from b.dataact) = pack_sesiune.getluna() AND extract(year from b.dataact) = pack_sesiune.getan() AND b.facturat = 1 AND e.inch_validare = 0)) -- inchis prin facturare/nota ``` Cu alte cuvinte, view-ul consideră o comandă "închisă" DOAR dacă: - **`inch_validare = 1` + `VALIDAT = 1`** (calea A: validarea închide) **SAU** - **`inch_validare = 0` + `FACTURAT = 1`** (calea B: trebuie factură/notă de închidere) **Configurare live MARIUSM_AUTO (2026-04-11):** | Tip comandă | Configurare | Efect | |---|---|---| | REGIE, PRODUCTIE, CONSTATARE | `inch_validare = 1` | Validarea **e** închiderea. Zero notă contabilă. | | POST GARANTIE, GARANTIE, PREGATIRE, REGIE 2 | `inch_validare = 0` | Validarea nu e suficientă. Trebuie factură. | Marius poate schimba configurarea per tip — ex: dacă schimbă REGIE la `inch_validare = 0`, atunci comenzile REGIE nu se mai consideră închise la validare, ci necesită o notă contabilă `711 = 332` suplimentară înainte ca `FACTURAT = 1` să apară în agregat. **`dev_arhiveaza_comanda` este o procedură complet separată** (setează `INCHIS_FORTAT = 1`), apelată doar pentru a abandona forțat o comandă — nu e legată de `inch_validare`. Folosit doar pentru cazuri excepționale (client a renunțat, constatare fără urmare tehnică, etc.). **Implicație pentru prototype (creare only):** irelevant pentru scope wall. **Critic pentru phase 2+** când se implementează închiderea comenzii: UI-ul trebuie să știe că validarea singură NU închide în toate cazurile, și să navigheze la facturare sau notă contabilă de închidere în funcție de `tip.inch_validare`. --- ## 7. Pachetul principal `pack_auto` — map procedure → tabel Map complet (din `docs/service-auto/pack_auto.pck`): ### 7.1. Create comandă | Procedură | Operație | |---|---| | `dev_adauga_lucrare` (15 params, overload scurt) | Wrapper peste versiunea lungă. Apelează versiunea cu 17 params cu defaults pe `pnOreFct`, `pcObservatii`, `pcDefectiuni`. | | `dev_adauga_lucrare` (17 params, overload lung) | **Flux real:** (1) INSERT `NOM_LUCRARI(nrord, id_mod=1200)`; (2) agregă `solicitari_client` din `DEV_NOM_NORME.DENOP` pentru id-urile din CSV; (3) INSERT `DEV_ORDL` cu toate câmpurile; (4) UPDATE `DEV_MASINICLIENTI` SET `kmint`, `ore_functionare`. Verifică mai întâi că `NRORD` nu e duplicat pe `NOM_LUCRARI` (aruncă `ORA-20000`). | **Dependențe runtime ale versiunii lungi:** - `pack_sesiune.dev_idLucrare` — populat de `TRG_NOM_LUCRARI_BEFOINS`, citit intern la step 3 - `pack_contafin.getCotaTVAStandard(luna, an)` — pentru `proc_tvav` (citit din `CALENDAR` / config lunar) - `STRINGAGG(DENOP)` agregat peste `DEV_NOM_NORME.ID_NORME IN (...)` unde `...` provine din parsarea CSV - (Oracle 19c+ are `STRINGAGG` ca user-defined aggregate; verifică dacă există în MARIUSM_AUTO) ### 7.2. Normare operații | Procedură | Operație | |---|---| | `dev_adauga_operatie(v_gcs, id_sectie, id_ordl, pret, id_util, timpn, id_norme, csv_id_mecanic, an?, luna?)` | **(1)** Citește `DEV_ORDL.VALIDAT` → dacă = 1, aruncă `ORA-20000 Comanda validata nu se mai poate modifica`. **(2)** INSERT `DEV_OPER` cu `validat=0, nou=1`. **(3)** Sparge `csv_id_mecanic` pe `;` → insert multiplu în `DEV_OPER_MECANICI` cu `ore = timpn / count(mecanici)`. | | `dev_actualizeaza_operatie(v_gcs, camp, valoare_noua, id_oper, luna, an)` | Verifică `VALIDAT=0`. Actualizează `PRET` sau `TIMPN`. Suportă tranziția RON/ROL: dacă `DATAI < get_lunaron()` și luna-țintă ≥ get_lunaron() atunci `valoare_noua * 10000`. | | `dev_valideaza_operatii(v_gcs, id_ordl, id_util)` | Verifică mai întâi `DEV_ORDL.VALIDAT = 0`. Setează `VALIDAT=1, ID_UTIL, DATAORA=SYSDATE` pe toate liniile din `DEV_OPER WHERE id_ordl = X AND sters=0 AND validat=0`. | | `valideaza_operatie(schema, validat, id_oper, id_util)` | Setează manual `VALIDAT` pe o singură operație. | | `sterge_operatie(schema, id_oper, id_util)` | Soft delete: `sters=1, dataoras=SYSDATE`. | | `modifica_sectie(schema, id_sectie, id_oper, id_util)` | UPDATE secție pe operație. | | `dev_distribuie_timp_n(v_luna, v_an)` | **MERGE** peste `DEV_OPER_MECANICI`: pentru operațiile unde `sum(ore_mecanici) <> timpn`, redistribuie uniform. Folosit ca housekeeping periodic. | **View-ul UI pentru normare:** `AUTO_NORMARE_COMENZI` — filtrat pe `inchis_fortat = 0 AND validat = 0` (din `AUTO_COMENZI_VALIDATE`). ### 7.3. Validare comandă | Procedură | Operație | |---|---| | `dev_valideaza_comanda(v_gcs, id_ordl, id_util, an?, luna?)` | **(1)** Verifică `DEV_OPER WHERE id_ordl = X AND sters=0 AND validat=0` → dacă există, aruncă `ORA-20000 Mai sunt operatii nevalidate`. **(2)** Calculează `ldData` = SYSDATE sau ultima zi a lunii vechi. **(3)** Verifică `CALENDAR` că luna e deschisă. **(4)** UPDATE `DEV_ORDL SET VALIDAT=1, ID_UTIL_VALID, DATAORAVALID=ldData, PROC_TVAV = pack_contafin.getCotaTVAStandard(luna, an)`. | | `dev_invalideaza_comanda(v_gcs, id_ordl, id_utils)` | Reverse: `VALIDAT=0, DATAORAVALID=NULL`, recalculează `PROC_TVAV` din luna/an curentă a comenzii. | | `dev_arhiveaza_comanda(id_ordl, id_util)` | **Alternativă la validare** — pentru tipuri cu `inch_validare=0`. Verifică `CALENDAR` luna deschisă, setează `INCHIS_FORTAT=1, ID_UTIL_INCHIS, DATAORAINCHIS = SYSDATE`. | | `dev_dezarhiveaza_comanda(id_ordl)` | Reverse: `INCHIS_FORTAT=0`. | | `dev_sterge_comanda(schema, id_util, id_ordl, id_lucrare)` | Verifică că `RUL WHERE id_lucrare = X AND sters=0` e gol la sum(cante*pretv). Verifică `DEV_OPER WHERE id_ordl = X AND sters=0` = 0. Setează `sters=1` pe `DEV_ORDL` și `inactiv=1` pe `NOM_LUCRARI`. | **View-ul UI:** `AUTO_VALIDARE_COMENZI` — JOIN peste `AUTO_COMENZI_VALIDATE` + `AUTO_VORDL_MAN` (manoperă agregată) + `AUTO_VORDL_MAT` (materiale agregate) + `AUTO_VORDL_FACTURI` (info factură emisă). **Flux de validare condiționat:** tipul comenzii (`dev_tip_deviz.inch_validare`) decide care dintre `dev_valideaza_comanda` (dacă `inch_validare=1`) sau `dev_arhiveaza_comanda` (dacă `inch_validare=0`) se apelează la închiderea comenzii. View-ul `AUTO_COMENZI_VALIDATE` are chiar o logică "time-aware": consideră o comandă validată **doar dacă** `dataoravalid` e ≤ luna curentă din `pack_sesiune.getluna() + pack_sesiune.getan() * 12`. Validările în viitor apar ca `validat=0` în view, ceea ce e intenționat pentru izolare contabilă pe lună. ### 7.4. Facturare | Procedură | Operație | |---|---| | `dev_adauga_oper_fact(schema, id_ordl, id_sectie, id_norme, total_f_tva, timpn, ore, id_util, id_mecanic)` | Folosit pentru tipuri speciale ITP/SPALARE/DIVERSE unde se adaugă o operație "sintetică" direct la facturare. Setează `DEV_ORDL.VALIDAT=1` + INSERT în `DEV_OPER` + `DEV_OPER_MECANICI`. `V_PRET = total_f_tva / timpn` (calcul reverse pentru a păstra total exact). | | `actualizeaza_deviz(proc_tvav, csv_id_ordl, id_set)` | **Apelat la final de facturare**. (1) Ia ultimul `ID_FACT` din `ACT WHERE cod = current_cod AND scd NOT LIKE '5%'`. (2) UPDATE `DEV_ORDL SET PROC_TVAV` pentru id-urile din CSV. (3) UPDATE `RUL SET ID_FACT = v_id_fact WHERE id_set <> 229 AND id_lucrare IN (...)` (index hint `IDX_RUL_001`). (4) Pentru `id_set` în (31003-31011), UPDATE și `NOM_LUCRARI SET ID_FACT`. | | `citeste_sume_stornare(csv_id_lucrare, delim, cursor OUT)` | Citește sume storno avans pentru listele CSV de lucrări. | | `citeste_date_avans(csv_id_lucrare, delim, cursor OUT)` | Citește avansurile pentru facturare. | | `citeste_discount_contract / salveaza_discount_contract` | Citește / salvează discount-uri contract per partener + sucursală. | **Flux facturare real (VFP `factureaza_comanda` → `factureaza_deviz` → `pack_facturare.*`):** ``` 1. [pack_auto.dev_adauga_lucrare] — uneori se creează o comandă ad-hoc pentru facturi ITP/SPALARE/DIVERSE (altfel se pleacă de la o comandă existentă) 2. User completează date factură (client, valoare, TVA, incasare) în VFP form 3. [lans(lnIdSet, ...)] — VFP generează note contabile pentru factură în cursor actactan 4. [verificare_note_contabile()] — validare locală VFP 5. [pack_auto.dev_adauga_oper_fact] — pentru tipuri ITP/SPALARE/DIVERSE, adaugă operația sintetică 6. [factureaza_deviz]: a. [pack_facturare.initializeaza_date_factura(...)] → INSERT în VANZARI header (20+ param) b. pentru fiecare articol în crsvanztemp: [pack_facturare.adauga_articol_factura_deviz(...)] → INSERT în VANZARI_DETALII c. [oscrie_in_fisiere(...)] — scrie cursor actactan în ACT (registrul jurnal) d. [pack_facturare.scrie_in_vanzari(...)] → finalizare VANZARI (incasare, discount, delegat) apelează în aceeași tranzacție: [pack_auto.actualizeaza_deviz(proc_tvav, csv_id_ordl, id_set)] → UPDATE DEV_ORDL.PROC_TVAV + RUL.ID_FACT + NOM_LUCRARI.ID_FACT (pentru id_set specifice) e. MERGE INTO vanzari SET id_fact FROM act WHERE cod=v.cod AND scd='4111' 7. COMMIT sau ROLLBACK ``` **Tabele atinse la facturare:** `VANZARI`, `VANZARI_DETALII`, `ACT`, `DEV_ORDL.PROC_TVAV`, `RUL.ID_FACT` (pentru materiale consumate), `NOM_LUCRARI.ID_FACT`, `ACT.ID_FACT` (prin pack_facturare). **IN SCOPE abia pentru phase 3-4**, după ce prototype-ul probează crearea unei comenzi simple. ### 7.5. Alte operații - `modifica_date_comanda(id_ordl, id_tip, kmint, ore_functionare, id_util)` — edit rapid - `modifica_tip_comanda(schema, id_tip, id_ordl, id_util)` — schimbă tip - `modifica_client_comanda(schema, id_ordl, id_masiniclient, id_util)` — schimbă mașina --- ## 8. Bonuri consum = **flow generic ROA, în `RUL.id_lucrare`** `pack_auto` **nu are** nicio procedură pentru bonuri consum. Materialele consumate pe comandă sunt **100% în tabela generică `RUL`** (rulaje ROA), tag-uite prin `RUL.ID_LUCRARE = X`. Flux-ul: 1. VFP `ointroduceri.prg` cu `tip=3` (BON CONSUM) deschide un form de introducere articole din stoc → user selectează linii + alege comanda (id_lucrare) → salvare. 2. Generic ROA warehouse SP generează rânduri în `RUL` cu: - `ID_LUCRARE = X` (tag-ul comenzii) - `SCD = '3xx'` (contul de stoc), `SCC = '6xx'` sau `'332'` (contul de destinație) - `CANTE`, `PRETV` (cantitate + preț unitar) - `ID_SET` care tipizează operațiunea de stoc 3. **La afișarea devizului** (view-urile `AUTO_VORDL_MAT`, `AUTO_VALIDARE_COMENZI`), materialele se citesc ca agregat din `MV_ORDL_MAT` (materialized view peste `RUL`) pe `id_lucrare`. 4. **La facturare**, `factureaza_deviz` citește suma materialelor din cursoarele `actactan` + `vanzari` (generate de `lans(lnIdSet...)` local în VFP), apoi `pack_auto.actualizeaza_deviz` face `UPDATE RUL SET ID_FACT = :v_id_fact WHERE ID_LUCRARE IN (...) AND ID_SET <> 229` — marchează materialele ca facturate. **Impact asupra DEV_OPER:** zero. Pentru service auto, `DEV_OPER` conține **doar manoperă**; materialele nu intră în DEV_OPER deloc. **Implicație pentru prototype:** Bonul de consum este **out of scope**. Flux-ul atinge pachete generice ROA (neauditate) + tabela `RUL` (nu e în scheme ROAAUTO dedicate). Dacă phase 2 cere "service auto complet", bonul de consum va fi un sub-modul separat cu propriul audit asupra pachetului generic ROA `pack_intrari_iesiri` (sau similar). **Observație specială pentru tipurile nefacturabile (`inch_validare = 1` în live MARIUSM_AUTO):** REGIE/PRODUCTIE/CONSTATARE se închid **prin simpla validare** — zero notă contabilă. Bonurile de consum materiale rămân în `RUL` cu `ID_FACT = NULL` permanent (fără a fi legate de vreo factură), dar comanda e considerată "închisă" în agregatele de raportare. Impactul contabil al materialelor consumate pe aceste comenzi se face prin flux-ul generic ROA de rulaje (stocul e deja scăzut prin `scd='3xx', scc='6xx'` la momentul bonului de consum). **Dacă Marius ar schimba REGIE la `inch_validare = 0`** (scenariu teoretic), atunci pentru a închide o comandă REGIE ar trebui: 1. Validare (`VALIDAT = 1`) — doar un pas intermediar 2. O notă contabilă suplimentară `711 = 332` (care recunoaște venitul intern aferent materialelor deja consumate) — această notă trebuie să seteze `facturat = 1` sau un mecanism echivalent ca să apară în agregatele view-ului 3. Abia atunci view-ul `AUTO_LISTARE_MAN_TOT_COM` consideră comanda "închisă" Acest scenariu nu e activ în configurarea curentă, dar e permis de schema. --- ## 9. View-uri cheie pentru UI service auto Toate definite în `mariusm_ddl_export.sql` (secțiunea VIEWS). Cele relevante pentru ecrane: | View | Rol | JOIN-uri principale | |---|---|---| | `AUTO_COMENZI_VALIDATE` | Base view — "comenzi cu time-aware validat flag" (validat = 1 doar dacă `dataoravalid` ≤ luna curentă session) | `dev_ordl` + `syn_utilizatori` + `nom_lucrari` | | `AUTO_NORMARE_COMENZI` | Listare comenzi care așteaptă normare operații. **Filtru tipic:** `inchis_fortat=0 AND validat=0` | `auto_comenzi_validate` + `auto_vordl_facturi` + `dev_masiniclienti` + `nom_parteneri` + `dev_tip_deviz` | | `AUTO_VALIDARE_COMENZI` | Listare comenzi în curs de validare + manopera/materiale agregate | `auto_comenzi_validate` + `auto_vordl_man` + `auto_vordl_mat` + `auto_vordl_facturi` + lookup-uri | | `AUTO_ORDL_FACTURARE` | Listare comenzi pregătite pentru facturare | `dev_ordl` + `nom_lucrari` + `dev_masiniclienti` + `nom_parteneri` + `dev_nom_masini` + `dev_nom_marci` + `dev_nom_asiguratori` + `dev_nom_inspectori` WHERE `sters = 0` | | `AUTO_VORDL` | Listare completă comandă (toate câmpurile expuse) | ~10 JOIN-uri | | `AUTO_VORDL_MAN` | Agregat manoperă pe comandă (sum după `pack_sesiune` RON/ROL) | derivat | | `AUTO_VORDL_MAT` | Agregat materiale pe comandă — **folosește `MV_ORDL_MAT` (materialized view)** cu pack_sesiune currency logic | `MV_ORDL_MAT` grupat pe `id_lucrare` | | `AUTO_VORDL_FACTURI` | Facturile emise per `id_lucrare` | derivat | | `AUTO_VESTIMARI_REP` | Linii estimare pentru un deviz pre-sale | `dev_estimari_rep` + `dev_nom_norme` + `nom_articole` + `syn_utilizatori` | | `AUTO_VOPER` | Liniile de operație cu lookup norme + ansamblu + mașină + secție + mecanic | `dev_oper` + `dev_nom_norme` + `dev_nom_ansamble` + `dev_nom_masini` + `nom_sectii` + `syn_utilizatori` | | `AUTO_VOPER_DETALII_M` | Detalii mecanici per operație | `dev_oper_mecanici` + `dev_mecanici` + `nom_parteneri` | | `AUTO_VMASINICLIENTI` | Lista mașini + clienți pentru dropdown-uri | `dev_masiniclienti` + `dev_nom_masini` + `dev_nom_marci` + `nom_parteneri` | | `AUTO_VNORME` | Catalog norme manoperă pentru picker | `dev_nom_norme` + `dev_nom_masini` + `dev_nom_ansamble` | **Notă `pack_sesiune` currency logic:** multe view-uri (`AUTO_VOPER`, `AUTO_VORDL_MAT`) conțin `CASE WHEN pack_sesiune.getAn()*12 + getLuna() >= GET_ANRON()*12 + GET_LUNARON() THEN ron ELSE rol END`. Acesta e un heritage-currency switch (RON denominat 2005 vs vechiul ROL) — după 2005 toate înregistrările noi sunt RON, deci în practică întotdeauna se ia branch-ul RON. **Pentru prototype modern, acest CASE e un artefact istoric** care nu trebuie replicat — noi inserăm direct RON fără switch. --- ## 10. Flux end-to-end real (VFP → DB) ### 10.1. Creare comandă ``` [VFP: frm_gencom] Submit ↓ VFP SQL: begin pack_auto.dev_adauga_lucrare( gcS, gnAn, gnLuna, gnIdUtil, pcNr, -- 'G12345' / 'R...' pnIdInsp, pnIdAsig, pcNrDosar, pnIdMC, pnKmInt, pnOreFct, to_date(pdTermen, 'DD/MM/YYYY'), pntipcom, pcSirIDOperatiiClient, pcObservatii, pcDefectiuni, pnIdPartRef, ?@pnIdOrdl); end; ↓ PACK_AUTO.DEV_ADAUGA_LUCRARE (overload 17 params): 1. SELECT COUNT(*) FROM NOM_LUCRARI WHERE sters=0 AND nrord=pcNr → IF > 0 THEN RAISE ORA-20000 'Mai exista o lucrare...' 2. INSERT INTO NOM_LUCRARI (nrord, id_mod) VALUES (pcNr, 1200) → TRG_NOM_LUCRARI_BEFOINS populează :new.id_lucrare din SEQ_NOM_LUCRARI + pack_sesiune.dev_idLucrare := :new.id_lucrare 3. IF pcSirIdOperatii IS NOT NULL THEN SELECT STRINGAGG(DENOP) INTO v_solicitari_client FROM DEV_NOM_NORME WHERE id_norme IN () 4. INSERT INTO DEV_ORDL (an, luna, id_inspector, id_lucrare, datai, id_util_ad, id_masiniclient, id_asigurator, id_tip, kmint, ore_functionare, termen, nr_dosar, dataoraad, solicitari_client, observatii, defectiuni, proc_tvav, id_part_ref) VALUES (tnAn, tnLuna, pnIdInsp, pack_sesiune.dev_idLucrare, -- <-- citit din session state populat la pasul 2 SYSDATE, tnIdUtil, pnIdMC, pnIdAsig, pnTipCom, pnKmInt, pnOreFct, pdTermen, pcNrDosar, SYSDATE, v_solicitari_client, pcObservatii, pcDefectiuni, pack_contafin.getCotaTVAStandard(tnLuna, tnAn), decode(pnIdPartRef, 0, NULL, pnIdPartRef)) RETURNING id_ordl INTO pnIdOrdl → TRG_DEV_ORDL_BEFOINS populează :new.id_ordl din SEQ_DEV_ORDL + pack_sesiune.dev_idOrdl := :new.id_ordl 5. UPDATE DEV_MASINICLIENTI SET kmint, ore_functionare WHERE id_masiniclient=pnIdMC ``` **Nu touch-uiește ACT, nici RUL, nici VANZARI.** Facturare e un flux separat. ### 10.2. Normare operații (adaugă manoperă pe o comandă existentă) ``` [VFP: normare_comanda()] deschide FRM_NOM_COM cu cursor AUTO_NORMARE_COMENZI ↓ User selectează o comandă + alege norme din AUTO_VNORME + alocă mecanici ↓ VFP SQL: begin pack_auto.dev_adauga_operatie( gcS, pnid_sectie, pnIdOrdl, pnpret, gnIdUtil, pntimpn, pnid_norme, pcsir_idmecanic); end; ↓ PACK_AUTO.DEV_ADAUGA_OPERATIE: 1. SELECT VALIDAT FROM DEV_ORDL WHERE id_ordl = X → IF validat=1 THEN RAISE ORA-20000 'Comanda validata nu mai poate fi modificata' 2. INSERT INTO DEV_OPER (id_ordl, id_sectie, timpn, pret, id_norme, id_utili, nou, datai, dataora) VALUES (..., 1, SYSDATE, SYSDATE) RETURNING id_oper INTO v_id_oper → TRG_DEV_OPER_BEFOINS populează :new.id_oper din SEQ_dev_oper 3. PARSE csv_id_mecanic pe ';' → FOR i IN 1..count LOOP INSERT INTO DEV_OPER_MECANICI (id_oper, id_mecanic, ore) VALUES (v_id_oper, id_mec_i, timpn / count) ``` ### 10.3. Validare operații (marchează fiecare operație ca "gata") ``` [VFP user click "Valideaza operatii"] pe o comandă ↓ VFP SQL: begin pack_auto.dev_valideaza_operatii(gcS, pnIdOrdl, gnIdUtil); end; ↓ PACK_AUTO.DEV_VALIDEAZA_OPERATII: 1. SELECT VALIDAT FROM DEV_ORDL WHERE id_ordl = X → IF validat=1 THEN RAISE ORA-20000 'Comanda validata...' 2. UPDATE DEV_OPER SET validat=1, id_util, dataora=SYSDATE WHERE id_ordl = X AND sters=0 AND validat=0 ``` **Alternativ, linie cu linie:** ``` begin pack_auto.dev_valideaza_operatie(gcS, pn_id_oper, gnIdUtil); end; → UPDATE DEV_OPER SET VALIDAT=1 WHERE id_oper=X ``` ### 10.4. Validare comandă (finalizează comanda după ce toate operațiile sunt validate) ``` [VFP user click "Valideaza comanda"] ↓ VFP SQL: begin pack_auto.dev_valideaza_comanda(gcS, pnIdOrdl, gnIdUtil, an?, luna?); end; ↓ PACK_AUTO.DEV_VALIDEAZA_COMANDA: 1. SELECT COUNT(*) FROM DEV_OPER WHERE id_ordl = X AND sters=0 AND validat=0 → IF > 0 THEN RAISE ORA-20000 'Mai sunt operatii nevalidate' 2. Calculează ldData: SYSDATE dacă luna curentă = luna_comandă, else LAST_DAY 3. SELECT COUNT(*) FROM CALENDAR WHERE an=.. AND luna=.. → IF 0 THEN RAISE ORA-20000 'Nu puteti valida deoarece nu este deschisa luna' 4. UPDATE DEV_ORDL SET VALIDAT=1, ID_UTIL_VALID, DATAORAVALID=ldData, PROC_TVAV = pack_contafin.getCotaTVAStandard(luna, an) WHERE id_ordl = X ``` ### 10.5. Închidere forțată (arhivare — pentru tipuri cu `inch_validare=0`) ``` [VFP user click "Inchide comanda" pe tip POST_GARANTIE/etc.] ↓ VFP SQL: begin pack_auto.dev_arhiveaza_comanda(pnIdOrdl, gnIdUtil); end; ↓ PACK_AUTO.DEV_ARHIVEAZA_COMANDA: 1. Verifică CALENDAR luna curentă deschisă 2. UPDATE DEV_ORDL SET INCHIS_FORTAT=1, ID_UTIL_INCHIS, DATAORAINCHIS=SYSDATE ``` ### 10.6. Facturare Vezi secțiunea 7.4 de mai sus. IN SCOPE abia pentru phase 3-4. ### 10.7. Bonuri consum Vezi secțiunea 8. Out of scope — e flux generic ROA. --- ## 11. Labelurile UI (Romanian) | Câmp DB | Label UI (din VFP ground truth) | |---|---| | `id_tip` | **Tip comandă** | | `nrinmat` (via masiniclienti) | **Număr înmatriculare** / **Mașină** | | `id_part` (via masiniclienti.id_partener) | **Client** | | `solicitari_client` (derivat din norme) | **Operații solicitate** | | `kmint` | **Km la bord** | | `ore_functionare` | **Ore funcționare** (pt utilitare) | | `termen` | **Termen execuție** | | `observatii` | **Observații** | | `defectiuni` | **Defecțiuni** | | `nr_dosar` | **Nr. dosar** (doar pentru tip=garanție) | | `id_inspector` | **Inspector** | | `id_asigurator` | **Asigurator** | | `id_part_ref` | **Partener referent** | | `id_agent` | **Agent vânzări** | **Toast-uri (convenție ROA2WEB din `ReceiptCreateUnifiedView.vue`):** - Success: `summary="Comandă creată"`, `detail="Nr ${nr_comanda}"` - Business error: `summary="Validare"`, `detail=` - Infra: `summary="Eroare conexiune"` (503) / `"Eroare internă"` (500) --- ## 12. Implicații pentru prototype-ul roa2web ### 12.1. Scope wall reconfirmat Prototype-ul scrie **1 SP minimal pentru 1 acțiune = creare comandă**. Tot restul (normare, validare operații/comandă, arhivare, facturare, bonuri consum, estimare) e **out of scope**. ### 12.2. Opțiunea 3 (SP nou minimal) — actualizată Față de v2, acum știm **exact** ce face `pack_auto.dev_adauga_lucrare` versiunea lungă. Versiunea minimală a SP-ului nostru va: ```sql CREATE OR REPLACE PROCEDURE MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP( p_id_tip IN NUMBER, -- FK dev_tip_deviz.id_tip p_id_masiniclient IN NUMBER, -- FK dev_masiniclienti.id_masiniclient p_kmint IN NUMBER, p_termen IN DATE, p_id_util IN NUMBER, p_nr_comanda IN VARCHAR2, -- generat în Python cu prefix (G/R/P/PR/C) p_id_ordl OUT NUMBER, p_numar_out OUT VARCHAR2 ) AS v_id_lucrare NUMBER; v_nr_existent NUMBER; v_now DATE := SYSDATE; BEGIN -- 1. Duplicate-check (paritate cu pack_auto) SELECT COUNT(*) INTO v_nr_existent FROM MARIUSM_AUTO.NOM_LUCRARI WHERE sters = 0 AND nrord = p_nr_comanda; IF v_nr_existent > 0 THEN RAISE_APPLICATION_ERROR(-20001, 'Mai exista o comanda cu numarul ' || p_nr_comanda); END IF; -- 2. Parent INSERT (trigger-ul alocă id_lucrare + populează pack_sesiune.dev_idLucrare) INSERT INTO MARIUSM_AUTO.NOM_LUCRARI (nrord, id_mod) VALUES (p_nr_comanda, 1200) RETURNING id_lucrare INTO v_id_lucrare; -- 3. Child INSERT minimal — doar coloane obligatorii + clientul (prin masiniclient) INSERT INTO MARIUSM_AUTO.DEV_ORDL ( an, luna, id_lucrare, datai, dataoraad, id_util_ad, id_masiniclient, id_tip, kmint, termen ) VALUES ( EXTRACT(YEAR FROM v_now), EXTRACT(MONTH FROM v_now), v_id_lucrare, v_now, v_now, p_id_util, p_id_masiniclient, p_id_tip, p_kmint, p_termen ) RETURNING id_ordl INTO p_id_ordl; p_numar_out := p_nr_comanda; END; / ``` **~30 linii PL/SQL, două INSERT-uri, zero dependency pe `pack_contafin` / `STRINGAGG` / `pack_sesiune`** — minim absolut ca să probeze ipoteza #1 (Python + oracledb + OUT params + PL/SQL procedure call pe un INSERT dual cu RETURNING). **Trigger-ele rulează oricum** — `pack_sesiune.dev_idLucrare` și `dev_idOrdl` vor fi populate, dar nu le citim. E trivial de demonstrat că e safe: pattern-ul Oracle `RETURNING INTO` e standard. **Coloane SĂRITE pe care SP-ul real le are:** - `id_inspector`, `id_asigurator` — folosite doar pentru service cu asigurator - `nr_dosar`, `pcNrDosar` — dosar daună - `ore_functionare`, `pnOreFct` — pentru utilitare - `solicitari_client` (agregat din STRINGAGG) — derivat din CSV, dispensabil pentru prototype - `observatii`, `defectiuni` — free text opțional - `id_part_ref` — referent - `proc_tvav` (via `pack_contafin.getCotaTVAStandard`) — dacă e NOT NULL vor primi default implicit (NULL); dacă schema real e NOT NULL, adăugăm valoarea 19 hardcodat **De verificat în săpt 3:** rulează `DESC MARIUSM_AUTO.DEV_ORDL` sau din `mariusm_ddl_export.sql` linia 565 — `PROC_TVAV` e `NUMBER(10,4)` nullable, deci OK. ### 12.3. GRANTS pentru ROA_WEB user ```sql CREATE USER ROA_WEB IDENTIFIED BY "..."; GRANT CONNECT, CREATE SESSION TO ROA_WEB; GRANT EXECUTE ON MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP TO ROA_WEB; -- Pentru read-only selectors (ipoteza #3 = grants model funcționează) GRANT SELECT ON MARIUSM_AUTO.AUTO_VMASINICLIENTI TO ROA_WEB; GRANT SELECT ON MARIUSM_AUTO.DEV_TIP_DEVIZ TO ROA_WEB; ``` ### 12.4. Test negativ pentru ipoteza #3 ```sql -- Connected as ROA_WEB: INSERT INTO MARIUSM_AUTO.DEV_ORDL ... ; -- așteptat: ORA-00942 SELECT * FROM MARIUSM_AUTO.DEV_ORDL WHERE ROWNUM < 2; -- așteptat: ORA-00942 EXEC MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP(...); -- așteptat: succes + row inserted ``` --- ## 13. Gap-uri rămase (de acoperit după sapt 3) - `PACK_SESIUNE.pck` citit — de confirmat că `dev_idLucrare`, `dev_idOrdl`, `getAn`, `getLuna`, `GET_ANRON`, `GET_LUNARON`, `get_cod`, `get_id_util` sunt toate exported și nu ascund ceva surprinzător (nu am citit încă body-ul, doar referințe). - `PACK_CONTAFIN.pck` citit — de confirmat `getCotaTVAStandard(luna, an)` și `get_idFact()`. - `PACK_FACTURARE.pck` citit — necesar doar când intrăm în flux-ul de facturare (phase 3-4). - `DEV_TIP_DEVIZ.inch_validare` per rând — rulează query-ul de verificare: ```sql SELECT id_tip, denumire, sters, inch_validare FROM MARIUSM_AUTO.DEV_TIP_DEVIZ ORDER BY id_tip; ``` - `MV_ORDL_MAT` materialized view — de verificat refresh schedule; dacă refresh e "on commit" atunci UPDATE-urile pe RUL sunt imediate în AUTO_VORDL_MAT; dacă e "on demand" cu DBMS_JOB atunci e latency în UI. - `pack_audit.verifica_val` — folosit de toate trigger-ele `_BEFOUPD`. E dependency ascuns pentru orice UPDATE pe `NOM_LUCRARI`, `DEV_ORDL`, `DEV_OPER`, etc. Nu e folosit la INSERT, deci prototype-ul (care doar inserează) nu-l atinge. --- ## 14. Referințe - **Ground truth DDL:** `docs/service-auto/mariusm_ddl_export.sql` (5127 linii) - **Pachete production:** `pack_auto.pck`, `PACK_FACTURARE.pck`, `PACK_SESIUNE.pck`, `PACK_CONTAFIN.pck`, `PACK_COMENZI.pck` (toate în `docs/service-auto/`) - **VFP consumer code:** `gitea.romfast.ro/romfast/vfp_roaauto/Programe/oproceduri_devize.prg` (`generare_com`, `normare_comanda`, `factureaza_comanda`, `factureaza_deviz`) - **Manual utilizator:** `docs/service-auto/manual_ROAAUTO.pdf` - **Plan master:** `docs/service-auto/claude-main-design-20260411-rethink.md`