# 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 (<parsed CSV>)
  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=<mesaj SP după strip prefix ORA-20xxx>`
- 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`
