<!-- /autoplan restore point: ~/.gstack/projects/romfast-roaauto/main-autoplan-restore-20260709-223553.md -->
# PRD ROAAUTO-1.0 — Transmitere operatii service la RAR AUTOPASS

**Stare**: aprobat (review /autoplan complet, 2026-07-09); **revizuit 2026-07-09** —
eliminat orice tabel nou Oracle (decizia lui Marius): configurarea sta in tabelul standard
`optiuni`, iar situatia transmiterilor se citeste din gateway intr-un **cursor temporar**
(gateway-ul e singura sursa de adevar; ROAAUTO nu persista nimic local).

> Feature ROAAUTO (VFP9/Oracle): buton/fereastra pentru transmiterea operatiilor de service
> din comenzile **inchise (validate) si facturate intr-o perioada** catre gateway-ul
> **autopass.romfast.ro** (`POST /v1/prezentari`, auth `X-API-Key`).
> Contract API (sursa de adevar): repo `rar-autopass` — `app/models.py` (`PrezentareIn`),
> `app/api/v1/router.py`, `docs/api-rar-contract.md`. Maparea cod operatie ROAAUTO → cod
> prestatie RAR se face **server-side** in gateway (`operations_mapping`), NU in ROAAUTO.

## 1. Obiectiv

Legea 142/2023 + OM 210/2024 obliga service-urile sa declare la RAR, la finalul fiecarei
lucrari, datele obligatorii (VIN, nr. inmatriculare, kilometraj, prestatii). ROAAUTO detine
deja toate datele; livrabila adauga o fereastra cu **filtru pe perioada (data facturii)**
care listeaza comenzile inchise+facturate si le transmite in lot la gateway-ul AUTOPASS.
Gateway-ul preia validarea de continut, maparea codurilor, coada, retry, declararea
efectiva la RAR **si evidenta a ce s-a transmis** — ROAAUTO ramane un **client subtire,
fara stocare locala**.

Fereastra pe perioada are doua roluri: (a) **stingerea backlog-ului** — obligatia e activa
din 01.12.2024, deci prima utilizare recupereaza lucrarile nedeclarate de la start; si
(b) transmiterea periodica curenta, pana cand ROAAUTO-1.1 adauga transmiterea automata
la inchiderea comenzii (fereastra ramane atunci UI de review/exceptii).

## 2. Non-Goals (anti scope-creep)

- **NU se creeaza NICIUN tabel/secventa nou(a) in schema Oracle** — configurarea sta in
  tabelul standard `optiuni` (mecanism existent), evidenta transmiterilor sta in gateway
  si se consulta prin API intr-un cursor temporar. Zero scripturi de instalare.
- NU se apeleaza API-ul RAR direct — doar gateway-ul autopass.romfast.ro.
- NU se face maparea cod operatie → cod prestatie RAR in ROAAUTO (exista in gateway;
  operatiile nemapate se rezolva in dashboard-ul web AUTOPASS, tab Mapari).
- NU se implementeaza management de cont/credentiale RAR in ROAAUTO (se face pe web).
- NU se transmit piese/materiale — doar operatiile de manopera (`DEV_OPER`).
- NU se construieste transmitere automata pe timer in aceasta livrabila (poate deveni
  ROAAUTO-1.1 dupa ce fluxul manual e verificat in productie).
- NU se modifica fluxul de inchidere/facturare a comenzilor.

## 3. Date sursa (ROAAUTO / Oracle)

Filtru: `validat = 1 AND facturat = 1 AND id_tip IN (1,2) AND datafact BETWEEN :d1 AND :d2`
pe view-ul **`auto_istoric_comenzi`** (coloanele complete:
`Programe\oproceduri_vizualizare.prg:447`). **Decis**: TOATE comenzile facturate —
POST GARANTIE (`ID_TIP=1`) si GARANTIE (`ID_TIP=2`), conform nomenclatorului
`DEV_TIP_DEVIZ` (`Scripturi_instalare\initializari.sql:199-208`). REGIE (3),
PREGATIRE (4), REGIE 2 (5), PRODUCTIE si constatarile NU se transmit
(`id_tip >= 3` exclus; oricum majoritatea nu au factura → cad la `facturat=1`).

| Camp payload AUTOPASS | Sursa ROAAUTO | Observatii |
|---|---|---|
| `vin` | `auto_istoric_comenzi.SERIES` | VARCHAR2(17), serie sasiu |
| `nr_inmatriculare` | `auto_istoric_comenzi.NRINMAT` | VARCHAR2(10) |
| `data_prestatie` | `DATAORAVALID` (data inchiderii/validarii) | format `YYYY-MM-DD`; **decis** — perioada de filtrare ramane pe `DATAFACT` |
| `odometru_final` | `DEV_ORDL.KMINT` (km la primire, snapshot pe comanda) | string numeric; **decis** — singura citire disponibila |
| `prestatii[]` | `DEV_OPER` (sters=0) JOIN `DEV_NOM_NORME` | per operatie: `{cod_op_service: CODOP, denumire: DENOP}` |
| `obs` | `NRORD` + `NRFACT` (ex. `Comanda 1234 / Factura 5678`) | **cheia de corelare** comanda ↔ prezentare in gateway (vezi US-005) |

Comenzile fara operatii (doar piese) nu se transmit (gateway respinge `PRESTATII_GOALE`).

## 4. Stories atomice

### US-001: Configurare conexiune AUTOPASS (tabelul `optiuni`)
**Ca** administrator **vreau** sa configurez URL-ul gateway-ului, cheia API si mediul RAR
(`test`/`prod`) **pentru ca** transmiterea sa functioneze per societate, fara valori hardcodate
si **fara tabele noi**.

- **Depinde de**: —
- **Fisiere**: `Programe\oproceduri_autopass.prg` (citire config); NIMIC in `Scripturi_instalare\`
- **Mecanism (existent, refolosit)**: tabelul `optiuni` (varname/vartype/varvalue/vardesc/programe)
  + procedurile din `COMUN\programe\oinit_optiuni.prg`:
  - la pornirea aplicatiei, `optiuni_firma` creeaza variabilele globale din `optiuni`
    (CHARACTER → prefix `gc`, ex. `gcAUTOPASS_URL`);
  - la runtime, `citeste_optiune('<VARNAME>')` citeste din cursorul `crsOptiuni`
    (incarcat la pornire de `actualizeaza_optiuni`), `scrie_optiune()` scrie prin
    `PACK_SESIUNE.SetOptiune` (merge: randul se creeaza la prima scriere — deci
    NU e nevoie de niciun script de seed);
  - **UI de configurare (decis)**: valorile se editeaza DIRECT din fereastra de
    transmitere (US-004) — panou "Configurare" in aceeasi forma, un singur formular,
    fara fereastra separata. (Fiind tot tabelul `optiuni`, raman vizibile si in
    fereastra standard Optiuni, dar acela nu e fluxul principal.)
- **Optiuni noi** (toate CHARACTER):
  | varname | global | continut |
  |---|---|---|
  | `AUTOPASS_URL` | `gcAUTOPASS_URL` | URL gateway, implicit `https://autopass.romfast.ro` |
  | `AUTOPASS_KEY` | `gcAUTOPASS_KEY` | cheia API (`X-API-Key`) |
  | `AUTOPASS_ENV` | `gcAUTOPASS_ENV` | `test` / `prod` / gol = default cont |
- **Acceptance criteria**:
  - [ ] `autopass_get_config()` citeste cele 3 valori prin `citeste_optiune()` (fallback pe
        variabilele globale `gcAUTOPASS_*` daca exista); la prima rulare, daca `AUTOPASS_URL`
        lipseste, se scrie valoarea implicita cu `scrie_optiune('AUTOPASS_URL',
        'https://autopass.romfast.ro', 'URL gateway RAR AUTOPASS')`.
  - [ ] `autopass_salveaza_config(tcUrl, tcKey, tcEnv)` scrie cele 3 valori prin
        `scrie_optiune()` — apelata de panoul Configurare din fereastra (US-004).
  - [ ] Panoul **Configurare** din fereastra de transmitere: URL gateway, cheie API
        (textbox cu `PasswordChar` + buton arata/ascunde), mediu RAR (combo:
        `Testare`/`Productie`/`implicit cont`), butoanele **Test conexiune** si
        **Salveaza**. Test conexiune apeleaza `GET /v1/ping` si afiseaza `mediu`,
        `autentificat_cu_cheie`, `are_creds_test/prod`.
  - [ ] `AUTOPASS_KEY` goala → fereastra se deschide direct cu panoul Configurare extins
        + mesaj clar; gridul si Transmite raman dezactivate pana exista cheie salvata.
  - [ ] Dupa **Salveaza**: config-ul se reciteste, ping-ul se reia automat, badge-ul de
        mediu si starea butoanelor se actualizeaza fara a inchide fereastra.
- **Verificare E2E**: completare cheie in panou → Salveaza → `GET /v1/ping` intoarce
  `autentificat_cu_cheie: true`; valorile apar in tabelul `optiuni`.

### US-002: Extragere comenzi + operatii pe perioada
**Ca** utilizator **vreau** lista comenzilor inchise si facturate in perioada aleasa, cu
operatiile lor, **pentru ca** sa vad exact ce urmeaza sa se transmita.

- **Depinde de**: —
- **Fisiere**: `Programe\oproceduri_autopass.prg` — proceduri cursor header + detaliu
- **Acceptance criteria**:
  - [ ] Cursor header din `auto_istoric_comenzi`: `id_ordl, nrord, dataoravalid, datafact, nrfact, nrinmat, series, kmint, nume, tip_comanda`, filtrat `validat=1 AND facturat=1 AND id_tip IN (1,2) AND datafact BETWEEN d1 AND d2` (+ `sters=0` unde e cazul).
  - [ ] Cursor detaliu: `SELECT o.id_ordl, n.codop, n.denop FROM dev_oper o JOIN dev_nom_norme n ON o.id_norme=n.id_norme WHERE o.sters=0 AND o.id_ordl IN (…)`.
  - [ ] Pre-validare locala pe rand (aceleasi reguli ca `app/validation.py`): VIN 17 caractere fara O/I/Q, NRINMAT ≤10 alfanumeric, `data_prestatie ≥ 2024-12-01` si ≤ azi, km numeric — randurile invalide se marcheaza vizual cu motivul si nu se pot bifa.
  - [ ] `CODOP` gol/NULL in `DEV_NOM_NORME` → operatia se marcheaza pe rand (motiv "operatie fara cod"); operatiile identice duplicate in aceeasi comanda se deduplica inainte de trimitere.
- **Verificare E2E**: perioada cu comenzi cunoscute → numarul de randuri corespunde cu istoricul comenzilor.

### US-003: Client HTTP + serializare JSON (`POST /v1/prezentari`)
**Ca** sistem **vreau** o clasa VFP care construieste JSON-ul si face POST cu `X-API-Key`
**pentru ca** transmiterea sa fie robusta si raspunsul parsabil.

- **Depinde de**: US-001
- **Fisiere**: `Programe\oproceduri_autopass.prg` (clasa `AutopassClient`); biblioteca JSON
  `nfjsoncreate.prg`/`nfjsonread.prg` din `COMUN\utile\nfjson\`
- **Acceptance criteria**:
  - [ ] POST via `winHTTP.winHTTPrequest.5.1` (pattern `D:\ROA\ems_trimite_facturi_spv.prg` → `SendeFactura`), headere `Content-Type: application/json` + `X-API-Key`, body UTF-8.
  - [ ] Body: `{"prezentari": [...], "rar_env": <din config, optional>}` — prestatii cu `cod_op_service` + `denumire` (maparea ramane in gateway); `raspuns` implicit `minim`.
  - [ ] Transmitere in loturi de max 50 prezentari per request; corelarea raspunsului
        se face pe `index` **per lot** (index e relativ la cererea curenta, nu global) —
        clientul tine maparea `index lot → id_ordl` explicit.
  - [ ] Encoding **verificat empiric, nu presupus**: intai se testeaza ce emite
        `nfjsoncreate` pentru ă/â/î/ș/ț (escape `\uXXXX` ASCII vs bytes locale). Daca
        escapeaza in ASCII → NU se aplica STRCONV (l-ar corupe); daca emite bytes
        cp1250 → conversie UTF-8 (`STRCONV(...,9)`) SAU Send pe byte-array cu
        `charset=utf-8`. Criteriu: round-trip pe mediul test cu diacritice, verificat
        in dashboard.
  - [ ] Datele Oracle (DATAORAVALID) → `YYYY-MM-DD` construit explicit
        (`STR(YEAR())+'-'+PADL(MONTH(),2,'0')+'-'+PADL(DAY(),2,'0')`), NICIODATA
        DTOC/DTOS (depind de SET DATE). Valabil si pentru CSV (US-006).
  - [ ] Parametrii de perioada in SQL pass-through ca literali
        `TO_DATE('YYYY-MM-DD','YYYY-MM-DD')` — elimina ambiguitatea DMY/MDY.
  - [ ] Timeout-uri explicite pe WinHTTP — semnatura reala e
        `SetTimeouts(resolve, connect, send, receive)` in ms (ex. 30000 fiecare);
        FARA retry automat in client — retrimiterea e manuala si sigura (idempotenta
        server-side). Statusul/eroarea WinHTTP bruta intra in contextul logat
        (diagnoza proxy-uri client).
  - [ ] `DOEVENTS` + verificare Renunta/ESC intre loturi (Send e sincron si blocheaza
        UI-ul); peste ~200 comenzi bifate, dialog suplimentar de confirmare.
  - [ ] **Cheia API nu se logheaza niciodata** (nici header-ele complete); raspunsurile
        logate in LOG.txt contin VIN/nr. inmatriculare → se trateaza ca date personale
        (trunchiate la strictul necesar diagnosticului).
  - [ ] Clientul ramane **transport pur**: primeste obiecte/cursoare si intoarce
        `{index, submission_id, status, motiv, id_prezentare}`; corelarea cu id_ordl si
        actualizarea gridului raman in proceduri/forma → testabil dintr-un driver .prg
        fara forma.
  - [ ] Parsare raspuns minim per element: `index, submission_id, vehicul, status, motiv, id_prezentare`; HTTP ≠ 200 (401/422/5xx) → mesaj cu detaliul din body, fara crash.
  - [ ] Erorile HTTP/parse se scriu si in `LOG.txt` (logul runtime existent), cu context:
        actiune, lot, cod HTTP, primele 500 caractere din raspuns.
  - [ ] Retrimiterea aceluiasi continut e sigura (idempotenta server-side → `deduped`); statusul intors se afiseaza onest (inclusiv `needs_mapping`/`needs_data`/`held`).
- **Verificare E2E**: POST pe mediul RAR **test** cu o comanda reala → `status: queued` si submission vizibil in dashboardul web.

### US-004: Fereastra "Transmitere AUTOPASS" + buton
**Ca** utilizator **vreau** o fereastra cu perioada, grid cu bife si butonul **Transmite la
AUTOPASS** **pentru ca** sa controlez ce se declara si sa vad rezultatul per comanda.

- **Depinde de**: US-002, US-003, US-005
- **Fisiere**: `Ferestre\frm_autopass.scx` (forma noua, in VFP IDE), lansata din procedura
  `trimitere_autopass` in `oproceduri_autopass.prg`; **punct de intrare (decis)**: butonul
  existent "Export" — `Clase\ofundal_dev.vcx`, clasa `pg_meniu_princ`,
  `Page2.Cw8.do_actiune()` (azi: `DO export_comanda_xml IN oproceduri_devize.prg`) devine
  meniu contextual, dupa pattern-ul `Page5.Cw3.do_actiune`:
  ```foxpro
  lnOptiune = xmenu("Export \<xml;Export operatii facturate \<csv;\<Trimitere operatii facturate in autopass.romfast.ro")
  DO CASE
  CASE lnOptiune = 1
      DO export_comanda_xml IN oproceduri_devize.prg
  CASE lnOptiune = 2
      DO export_operatii_csv IN oproceduri_autopass.prg    && US-006
  CASE lnOptiune = 3
      DO trimitere_autopass IN oproceduri_autopass.prg     && fereastra US-004
  ENDCASE
  ```
  (`ofundal_dev.vcx` e binar — modificarea se face in VFP IDE, apoi se regenereaza cache-ul text)
- **Layout (ierarhia informatiei — ce vede utilizatorul intai)**:
  ```
  +--------------------------------------------------------------------------+
  | [MEDIU: PRODUCTIE ● rosu]   Perioada: [01.07.2026]-[09.07.2026] [Actualiz.]|  <- 1: unde trimit + ce perioada
  |                                                          [Configurare >>] |
  +- Configurare (panou pliabil, extins automat cand lipseste cheia) ---------+
  |  URL gateway: [https://autopass.romfast.ro          ]                     |
  |  Cheie API:   [************************] [arata]                          |
  |  Mediu RAR:   [Testare v]        [Test conexiune] [Salveaza]              |
  +--------------------------------------------------------------------------+
  | [x] | NrCmd | DataInch | Factura | NrInmat | VIN | Km | Client | Op | Status | Motiv |
  |  x  | 1234  | 02.07    | 5678    | B99XYZ  | ... | .. | ...    | 3  | sent   |       |  <- 2: ce se trimite
  |     | 1235  | 03.07    | 5679    | (gri — fara operatii / VIN invalid)     |       |
  +--------------------------------------------------------------------------+
  | [Bifeaza tot] [Debifeaza]   [Valideaza (dry-run)] [TRANSMITE] [Statusuri] |  <- 3: actiuni
  | [Deschide dashboard AUTOPASS]                          n bifate / m total |
  +--------------------------------------------------------------------------+
  ```
  **Un singur formular**: configurarea (US-001) traieste in acelasi `frm_autopass.scx`,
  ca panou pliabil sub bara de perioada — implicit strans cand config-ul e valid, extins
  automat (cu focus pe cheie) cand `AUTOPASS_KEY` lipseste sau ping-ul intoarce 401.
  Grid dens, limbaj utilitar (conventiile aplicatiei, pattern `frm_istoric_comenzi`);
  butonul TRANSMITE e cel mai proeminent, dar la dreapta actiunilor de verificare.
- **Acceptance criteria**:
  - [ ] Filtru perioada (implicit luna curenta) pe **data facturii** + buton Actualizeaza.
  - [ ] Grid: bifa, nr. comanda, data inchidere, nr./data factura, nr. inmatriculare, VIN, km, client, nr. operatii, **status transmitere** (din situatia gateway-ului, US-005) + motiv.
  - [ ] Bifeaza tot / debifeaza tot; comenzile regasite in situatia gateway-ului cu status ne-esuat (`queued`/`sent`/`deduped`/`held`/`needs_*`) vin implicit nebifate.
  - [ ] Badge vizibil de mediu: `PRODUCTIE` (rosu) / `Testare` (gri) — regula "rosu = real"; pe `prod`, confirmare explicita inainte de trimitere cu numarul de comenzi.
  - [ ] Dupa trimitere, statusul si motivul se actualizeaza pe fiecare rand fara a inchide fereastra (din raspunsul POST, direct in cursorul gridului — nu se persista nimic).
  - [ ] Butonul Transmite se dezactiveaza pe durata transmiterii (guard dubla-apasare);
        progres vizibil (ex. "lot 2/5...").
  - [ ] Stare goala: perioada fara comenzi → mesaj clar in grid + buton Transmite dezactivat.
  - [ ] **Indicator de acoperire** vizibil permanent: "Declarabile in perioada: N |
        Transmise (sent): M | Blocate/nedeclarabile: K" — singura metrica ce raspunde
        la "suntem conformi?"; K > 0 e evidentiat. (M/K calculate din situatia US-005 +
        pre-validarea US-002, la fiecare refresh.)
  - [ ] Comenzile fara operatii apar in grid (gri, nebifabile) cu motivul "fara operatii de manopera" — vizibile, nu ascunse tacit.
  - [ ] La deschiderea ferestrei se apeleaza `GET /v1/ping`: mediul si starea creds RAR
        apar in bara de titlu/status; cheie lipsa/invalida → gridul si actiunile raman
        dezactivate, panoul Configurare se extinde automat cu mesaj (US-001) — utilizatorul
        corecteaza si salveaza fara sa inchida fereastra.
  - [ ] Schimbarea mediului RAR din panoul Configurare + Salveaza → badge-ul si situatia
        (US-005) se reincarca imediat (statusurile difera intre test si prod).
  - [ ] Buton **Valideaza (dry-run)**: `POST /v1/prezentari/valideaza` pe selectie —
        arata verdictul per comanda (status_estimat, erori, coduri nemapate) FARA enqueue;
        recomandat inainte de prima trimitere pe Productie.
  - [ ] Buton/link **Deschide dashboard AUTOPASS** (browser, URL-ul din config).
  - [ ] **Vocabular statusuri** (gateway → eticheta romaneasca + culoare + pasul urmator;
        NU se afiseaza tokenii englezesti bruti):
        | Gateway | Eticheta | Culoare | Pas urmator afisat |
        |---|---|---|---|
        | `queued` | In asteptare la RAR | galben | se actualizeaza cu butonul Statusuri |
        | `sent` | Transmis | verde | — (afiseaza nr. prezentare) |
        | `needs_mapping` | Cod fara mapare RAR | portocaliu | rezolva in dashboardul AUTOPASS, tab Mapari |
        | `needs_data` | Date incomplete | portocaliu | corecteaza comanda si retrimite |
        | `held` | Retinut (Auto OFF) | rosu | elibereaza din dashboard sau activeaza Auto |
        | `error` | Eroare | rosu | vezi motivul; corecteaza si retrimite |
        | `deduped` | Deja transmis | gri | nimic de facut |
        | *(negasit in situatie)* | Netransmis | alb | bifeaza si transmite |
  - [ ] **Fail-closed la deschidere**: pana raspunde ping-ul, badge = "Se verifica mediul...",
        Transmite si Valideaza dezactivate; wait cursor pe apelurile sincrone.
  - [ ] Badge-ul de mediu = banda plina in partea de sus a formei (nu doar title bar) +
        cuvantul PRODUCTIE/TESTARE si langa butonul Transmite; niciodata doar culoare.
        Dialogul de confirmare repeta cuvantul mediului + numarul de comenzi bifate valide.
  - [ ] Verdictul dry-run se afiseaza pe **canal separat** (coloana "Verdict validare" +
        banner sumar "Validare: 12 OK, 2 coduri nemapate") — NU suprascrie coloana de
        status transmitere.
  - [ ] **Sumar la final de transmitere**: dialog/linie "18 transmise, 3 in asteptare,
        1 cod fara mapare — vezi randurile portocalii."
  - [ ] Textbox read-only sub grid cu status+motiv complet al randului curent
        (motivele lungi nu incap in celula de grid).
  - [ ] "Bifeaza tot" selecteaza DOAR randurile eligibile (valide si netransmise).
  - [ ] Buton **Renunta** onorat intre loturi (WinHTTP e sincron — singurul punct de anulare).
  - [ ] Nota implementare VFP: randuri invalide = `DynamicBackColor`/`DynamicForeColor` +
        `When() = .F.` pe coloana de bifa (gridul VFP nu are readonly per celula).
- **Verificare E2E**: flux complet pe mediul test — filtrare, bifare, transmitere, statusuri corecte in grid.

### US-005: Situatia prezentarilor din gateway (cursor temporar, FARA stocare locala)
**Ca** utilizator **vreau** sa vad, per comanda din perioada, ce s-a transmis deja si cu ce
status **pentru ca** sa nu retransmit inutil si sa pot proba conformarea — **fara** ca ROAAUTO
sa tina vreo evidenta locala.

- **Depinde de**: US-003
- **Fisiere**: `Programe\oproceduri_autopass.prg` — procedura `autopass_situatie(d1, d2)`
  → cursor temporar `crs_autopass_situatie`. NICIUN tabel, NICIO secventa, NICIUN script.
- **Principiu**: gateway-ul este **singura evidenta** a transmiterilor (are deja submissions,
  statusuri, istoricul complet si dashboardul web). ROAAUTO doar interogheaza si coreleaza
  in memorie, la fiecare refresh; la inchiderea ferestrei totul dispare.
- **Acceptance criteria**:
  - [ ] `autopass_situatie(d1, d2)` apeleaza endpoint-ul de listare al gateway-ului
        (`GET /v1/prezentari?data_de=YYYY-MM-DD&data_pana=YYYY-MM-DD`, filtrat pe
        `data_prestatie` si pe cheia API a societatii) si construieste cursorul temporar
        `crs_autopass_situatie`: `submission_id, vin, nr_inmatriculare, data_prestatie,
        status, motiv, id_prezentare, obs`.
        **Dependenta gateway**: daca endpoint-ul de listare pe perioada nu exista inca in
        `rar-autopass`, se adauga INTAI acolo (produs propriu) — blocheaza US-005, nu se
        ocoleste cu stocare locala.
  - [ ] **Corelare** prezentare ↔ comanda: primar pe `obs` (`Comanda NRORD / Factura NRFACT`
        — string determinist generat de ROAAUTO la trimitere); fallback pe
        `vin + data_prestatie`. Rezultatul populeaza coloanele status/motiv din gridul US-004.
  - [ ] Comanda negasita in situatie = "Netransmis" (eligibila la bifare); comanda gasita
        cu orice status ne-esuat vine implicit nebifata (protectie la retransmitere, pe
        langa idempotenta server-side).
  - [ ] Buton **Actualizeaza statusuri** = re-apeleaza `autopass_situatie()` pe perioada
        afisata si reimprospateaza gridul (aduce `queued` → `sent` + `id_prezentare` dupa
        ce workerul gateway proceseaza).
  - [ ] Acelasi refresh ruleaza **automat la deschiderea ferestrei** (decizia 6, poarta
        /autoplan) si dupa fiecare transmitere, cu wait cursor.
  - [ ] Situatia indisponibila (endpoint picat / eroare) → gridul afiseaza "Status
        necunoscut — situatia gateway indisponibila" pe toate randurile, transmiterea
        ramane posibila DOAR cu confirmare explicita (idempotenta face retrimiterea sigura);
        eroarea se logheaza in LOG.txt.
- **Verificare E2E**: dupa ce workerul gateway proceseaza, Actualizeaza statusuri aduce
  `sent` + `id_prezentare` in grid; cazul 2 comenzi / acelasi VIN / aceeasi zi se coreleaza
  corect pe `obs` (chei de idempotenta diferite prin NRORD).

### US-006: Export operatii facturate CSV (canal alternativ + mod degradat oficial)
**Ca** utilizator **vreau** sa export operatiile facturate din perioada intr-un CSV compatibil
cu importul web AUTOPASS **pentru ca** sa pot incarca manual lucrarile in dashboard cand
prefer canalul de import — si ca **fallback desemnat** cand API-ul e indisponibil sau
neconfigurat (exportul functioneaza si cu config-ul API gol; obligatia legala nu depinde
de un singur canal).

- **Depinde de**: US-002
- **Fisiere**: `Programe\oproceduri_autopass.prg` — procedura `export_operatii_csv`
- **Acceptance criteria**:
  - [ ] Cere perioada (data facturii), refoloseste cursoarele din US-002 (acelasi filtru `validat=1, facturat=1, id_tip IN (1,2)`).
  - [ ] Format acceptat de `POST /v1/import` / upload web (vezi `rar-autopass/exemple/prezentari_test.csv`): separator `;`, antet `VIN;Numar inmatriculare;Data prestatie;Odometru initial;Odometru final;Operatie;Observatii`, **un rand per operatie** (aceeasi comanda se repeta pe mai multe randuri — importul le grupeaza pe vehicul+data).
  - [ ] `Data prestatie` = `DATAORAVALID` in format `YYYY-MM-DD`; `Odometru final` = `KMINT`; `Operatie` = `CODOP` (sau `DENOP` — coloana `Operatie` accepta text liber, maparea o face gateway-ul); `Observatii` = `Comanda NRORD / Factura NRFACT`.
  - [ ] Fisier salvat cu PUTFILE/GETDIR, encoding compatibil (diacriticele din denumiri nu sparg importul).
- **Verificare E2E**: CSV-ul exportat se incarca in dashboardul web AUTOPASS si coloanele se auto-mapeaza corect.

## 5. Riscuri

- **Calitatea datelor istorice** (VIN gol/invalid, NRINMAT cu spatii/cratime, km 0):
  mitigat prin pre-validarea din US-002 (randuri marcate, netransmisibile) + statusul onest
  `needs_data` intors de gateway.
- **Dubla declarare la RAR**: mitigat dublu — idempotenta server-side (dedup pe continut) +
  situatia din gateway (US-005: comenzile regasite vin nebifate).
- **Corelarea pe `obs`** depinde de formatul fix `Comanda NRORD / Factura NRFACT`:
  formatul se genereaza dintr-un singur loc (functie dedicata, folosita si la POST, si la
  corelare, si la CSV) — nu se construieste ad-hoc in doua locuri.
- **Trimitere accidentala pe Productie** (ireversibila conform Legii 142): badge rosu +
  dialog de confirmare cu mediul si numarul de comenzi (US-004).
- **Operatii nemapate in gateway**: primele loturi vor produce `needs_mapping`; se rezolva
  o singura data per cod in dashboardul web (sau bulk cu `tools/import_dbf.py` din
  `legacy-vfp/mapare_prestatii.DBF`, care contine deja mapari ROAAUTO).
- **VFP + TLS**: `winHTTP` pe Windows vechi poate esua pe TLS 1.2; pattern-ul e deja folosit
  in productie pentru ANAF SPV (`ems_trimite_facturi_spv.prg`), deci riscul e cunoscut/mic.
- **Endpoint de listare in gateway**: US-005 presupune `GET /v1/prezentari` cu filtru pe
  perioada; daca lipseste, se implementeaza intai in `rar-autopass` (blocant asumat —
  NU se compenseaza cu tabel local).

## 6. Intrebari deschise

> Se rezolva cu utilizatorul INAINTE de executie.

Decizii luate (fost intrebari 1-4):

1. **DECIS** — `data_prestatie` = `DATAORAVALID` (data validarii/inchiderii comenzii);
   perioada de filtrare ramane pe `DATAFACT`.
2. **DECIS (confirmat la poarta /autoplan, dupa contestarea ambelor voci independente)** —
   `odometru_final` = `KMINT`. Justificare asumata: e singura citire de bord existenta in
   date, e o citire reala a vehiculului in perioada lucrarii, iar contractul RAR cere
   `odometruFinal` obligatoriu (a trimite doar `initial` ar fi respins). Semantic, KMINT
   e km la primire — decizie documentata, de revizuit doar daca RAR o conteste.
3. **DECIS** (revizuit la review-ul CEO) — TOATE comenzile facturate: post-garantie
   (`ID_TIP=1`) si garantie (`ID_TIP=2`). Regie/pregatire/productie/constatare
   (`id_tip >= 3`) NU se transmit.
4. **DECIS** — punct de intrare: butonul "Export" din `Clase\ofundal_dev.vcx`
   (`pg_meniu_princ.Page2.Cw8.do_actiune`) devine `xmenu` cu 3 optiuni:
   Export xml (existent) / Export operatii facturate csv (US-006) /
   Trimitere operatii facturate in autopass.romfast.ro (US-004).

5. **DECIS** — o singura cheie API per baza de date (societate); optiunile `AUTOPASS_*`
   din tabelul `optiuni` tin o singura configurare. Context (poarta /autoplan): clientii
   actuali au un singur service auto per firma; daca apar clienti cu mai multe
   service-uri/conturi RAR, config-ul se extinde atunci.
6. **DECIS (poarta /autoplan)** — la deschiderea ferestrei, pe langa ping, se
   actualizeaza automat situatia prezentarilor (US-005) pentru perioada afisata;
   butonul "Actualizeaza statusuri" ramane pentru refresh manual.
7. **DECIS (revizie 2026-07-09, Marius)** — **ZERO tabele noi**: configurarea in tabelul
   `optiuni` (mecanismul existent `oinit_optiuni.prg`), evidenta transmiterilor NUMAI in
   gateway, consultata prin API intr-un cursor temporar. Fostele `AUTO_AUTOPASS_CONFIG`,
   `AUTO_AUTOPASS_TRIMITERI`, `SEQ_AUTOPASS_TRIMITERI` sunt eliminate din plan (si
   revertate din `Scripturi_instalare\`).
8. **DECIS (revizie 2026-07-10, Marius)** — **un singur formular**: URL-ul, cheia API si
   mediul RAR se editeaza direct din fereastra de transmitere (panou Configurare pliabil
   in `frm_autopass.scx`), nu dintr-o fereastra separata; salvarea trece prin
   `scrie_optiune()` (`autopass_salveaza_config`).
9. **DECIS (revizie 2026-07-10, Marius)** — **normalizare NRINMAT aprobata**: eliminarea
   spatiilor, cratimelor si punctelor din numarul de inmatriculare inainte de validare se
   aplica consecvent pe cele 3 canale: gateway `rar-autopass` (validare + idempotency),
   clientul VFP (`autopass_valideaza_rand` din `oproceduri_autopass.prg`) si spike-ul SQL de
   calitate a datelor (`docs\spike_calitate_date_autopass_v2.sql`, versiune noua fata de
   spike-ul v1 rulat initial). Motivatie: spike-ul v1 a aratat doar 13,8% NRINMAT valide din
   cauza formatelor reale cu spatii/cratime (ex. "B 99 XYZ"), regula stricta anterioara
   (doar strip+upper) fiind prea restrictiva fata de datele istorice reale.

Nu mai exista intrebari deschise — PRD aprobat prin poarta /autoplan (2026-07-09),
revizuit conform deciziilor 7-9 (decizia 9 e o completare post-aprobare, 2026-07-10).

## 7. Valuri de executie

```
Val 0: [SPIKE calitate date]     ← un singur SQL, INAINTE de orice implementare:
                                    din comenzile facturate (id_tip 1,2) de la 01.12.2024,
                                    ce procent au VIN valid 17 car., NRINMAT si KMINT > 0?
                                    Rezultatul calibreaza asteptarile si decide daca e
                                    nevoie si de un proiect de remediere a datelor.
       [VERIF gateway]           ← exista GET /v1/prezentari (listare pe perioada)?
                                    daca nu → se adauga intai in rar-autopass.
Val 1: [US-001] [US-002]         ← independente, zone distincte → paralel
Val 2: [US-003] [US-005] [US-006]← US-003 dupa config; US-005 dupa client HTTP; US-006 dupa cursoare
Val 3: [US-004]                  ← forma finala + xmenu in ofundal_dev.vcx (VFP IDE)
```

---

## Anexa review /autoplan (CEO + Design + Eng, 2026-07-09)

### NOT in scope (considerat si amanat explicit)
- **Transmitere automata la validarea comenzii** (hook in `validare_comenzi`) — ROAAUTO-1.1,
  dupa ce fluxul manual e verificat in productie.
- **Vizualizare/rezolvare mapari pending in ROAAUTO** (`GET /v1/mapari/pending`) — se face
  in dashboardul web AUTOPASS; duplicarea editorului in VFP nu aduce valoare.
- **Listare/tiparire jurnal transmiteri** (raport FRX) — gridul + dashboardul web acopera
  nevoia; raport doar la cerere ulterioara.
- **Actualizare automata a statusurilor pe timer** — refresh-ul la deschidere + butonul
  manual "Actualizeaza statusuri" sunt suficiente in v1.0.
- **Criptarea cheii API** — cheia sta in clar in `optiuni.varvalue` (AUTOPASS_KEY), ca
  restul configurarilor din schema; acces limitat la schema aplicatiei. Se poate cripta ulterior.

### What already exists (refolosit, nu reconstruit)
- `auto_istoric_comenzi` — view-ul cu tot header-ul necesar (comanda+factura+vehicul+km).
- `DEV_OPER` + `DEV_NOM_NORME` — operatiile cu CODOP/DENOP.
- **Tabelul `optiuni` + `oinit_optiuni.prg`** (`optiuni_firma`, `citeste_optiune`,
  `scrie_optiune`, fereastra standard Optiuni) — configurarea AUTOPASS fara tabele noi.
- `D:\ROA\ems_trimite_facturi_spv.prg` (`SendeFactura`) — pattern-ul WinHTTP + header auth,
  deja folosit in productie pentru ANAF SPV (inclusiv TLS pe Windows-urile clientilor).
- `nfjsoncreate/nfjsonread` — biblioteca JSON VFP (vendored din rar-autopass/legacy-vfp).
- Gateway-ul insusi: validare continut, mapare coduri, idempotenta, coada, retry, dashboard
  **si evidenta completa a transmiterilor** (motivul pentru care ROAAUTO nu mai tine jurnal).
- Pattern-ul `xmenu` + `do_actiune` din `ofundal_dev.vcx` (Page5.Cw3) pentru punctul de intrare.

### Error & Rescue Registry (US-003 `AutopassClient` + fereastra)
| Codepath | Ce poate esua | Tratare | Utilizatorul vede |
|---|---|---|---|
| WinHTTP Send | timeout / DNS / TLS / gateway down | catch `loEx`, log LOG.txt, opreste lotul curent | "Gateway indisponibil: <detaliu>. Reincearca mai tarziu." |
| HTTP 401 | cheie API invalida/lipsa | opreste tot, nu continua loturile; panoul Configurare se extinde | "Cheie API respinsa — corecteaza cheia in panoul Configurare." |
| HTTP 422 | mediu RAR indisponibil / limita plan / JSON invalid | afiseaza `detail`-ul din body per lot | mesajul gateway-ului, netradus |
| HTTP 5xx | eroare interna gateway | log + mesaj, lotul se poate retrimite (idempotent) | "Eroare gateway (500). Retrimiterea e sigura." |
| Parse JSON raspuns | raspuns malformat/gol | catch nfjsonread, log body brut in LOG.txt | "Raspuns neasteptat de la gateway — vezi LOG.txt" |
| SQL pass-through Oracle | conexiune cazuta / view lipsa | pattern-ul standard al aplicatiei (verificare cursor) | eroarea standard a aplicatiei |
| GET situatie (US-005) | endpoint picat / raspuns invalid | statusuri "necunoscut" in grid, transmitere doar cu confirmare explicita; log | "Situatia gateway indisponibila — statusurile nu au putut fi citite" |
| Rand `needs_data`/`needs_mapping` | date incomplete / cod nemapat | status onest in grid, motiv afisat | motivul exact (ex. "Coduri fara mapare RAR: ...") |

**Reguli**: fara catch-all mut — orice Catch scrie context in LOG.txt; niciun esec nu e silentios
(fiecare rand bifat primeste un status vizibil sau un motiv de esec).

### Failure Modes Registry
| Codepath | Failure mode | Tratat? | Vizibil? |
|---|---|---|---|
| Transmitere lot | crash intre loturi (lot 2/5 trimis, 3 nu) | gateway-ul are submissions-urile trimise; refresh-ul situatiei (US-005) le arata; retrimiterea e idempotenta | DA — statusuri per rand la urmatorul refresh |
| Dubla transmitere | acelasi continut retrimis | dedup server-side → `deduped` | DA — status "deja transmis" |
| KMINT=0 / VIN gol | date istorice proaste | pre-validare US-002 → rand marcat, nebifabil | DA — motiv pe rand |
| Diacritice corupte | encoding gresit in JSON | encoding verificat empiric (US-003) | test E2E cu denumiri cu diacritice |
| IN (...) > 1000 elemente | perioada mare, Oracle ORA-01795 | detaliul se citeste pe chunk-uri de max 500 id-uri | transparent |
| Situatie indisponibila | GET listare esueaza | statusuri necunoscute + confirmare explicita la transmitere | DA — mesaj pe grid |
| Trimitere pe prod din greseala | mediu gresit | badge rosu + dialog de confirmare cu mediu si numar | DA — confirmare explicita |

### Decizii auto-luate (audit trail — principiile /autoplan)
| # | Faza | Decizie | Clasificare | Principiu |
|---|------|---------|-------------|-----------|
| 1 | CEO 0C-bis | Client subtire → gateway (vs CSV-only vs API RAR direct in VFP) | mecanic | P1 completeness, P4 DRY |
| 2 | CEO 0D | Accept: buton "Deschide dashboard AUTOPASS" | auto-accept | P2 blast radius, S |
| 3 | CEO 0D | Accept: ping + badge mediu la deschiderea ferestrei | auto-accept | P2, era partial in US-004 |
| 4 | CEO 0D | Accept: buton Valideaza (dry-run) via `/v1/prezentari/valideaza` | auto-accept | P1 — verificare fara efecte |
| 5 | CEO 0D | Defer: auto-send la validare, mapari pending, listare jurnal, timer statusuri | auto-defer | P3 — in afara blast radius |
| 6 | CEO S2 | Timeout-uri explicite + fara retry client (idempotenta server) | mecanic | P5 explicit |
| 7 | CEO S4 | Encoding UTF-8 verificat + test diacritice | mecanic | P1 |
| 8 | CEO S7 | Chunk-uri de max 500 id-uri la detaliul operatiilor | mecanic | corectitudine Oracle |
| 9 | Premise gate | Scope: toate comenzile facturate (id_tip 1,2), fara regie/productie | decizia utilizatorului | — |
| 10 | Design P2 | Tabel stari interactiune adaugat in US-004 (loading/empty/error/success) | mecanic | P1 |
| 11 | Eng S1 | Corelare index→id_ordl per lot, explicit in US-003 | mecanic | P5 |
| 12 | Design voice #1 | Vocabular statusuri RO (fara tokeni englezesti in grid) | mecanic | P1 — utilizatorul e consilier service, nu dev |
| 13 | Design voice #2/#3 | Banda de mediu + fail-closed pana la ping | mecanic | P1 — actiune ireversibila |
| 14 | Design voice #4 | Verdict dry-run pe canal separat de statusul real | mecanic | P5 — evita retrimiterile accidentale |
| 15 | Design voice #5-#9 | Sumar final, textbox motiv, Bifeaza-tot doar eligibile, Renunta intre loturi, nota DynamicBackColor | mecanic | P1/P5 |
| 16 | CEO voice #2 | Reframe: v1.0 = stingere backlog (obligatie din 01.12.2024) + transmitere curenta | mecanic | P6 |
| 17 | CEO voice #4 | Val 0: SPIKE SQL calitate date (procent comenzi declarabile) inainte de implementare | auto-accept | P1 — un singur SQL |
| 18 | CEO voice #5 | Indicator de acoperire (declarabile/transmise/blocate) in fereastra | auto-accept | P1 — metrica de conformare |
| 19 | CEO voice #7 | CSV US-006 desemnat mod degradat oficial (functioneaza fara config API) | mecanic | P3 |
| 20 | Eng voice #2 | Encoding verificat empiric (nfjsoncreate) inainte de STRCONV | mecanic | P5 — nu pe incredere |
| 21 | Eng voice #3/#12 | Date YYYY-MM-DD construite explicit + TO_DATE in SQL | mecanic | P5 |
| 22 | Eng voice #4 | DOEVENTS + Renunta intre loturi + prag confirmare 200 | mecanic | P1 |
| 23 | ~~Eng voice #5~~ | ~~Jurnal append-only cu PK secventa~~ **ANULAT de decizia 7 (Marius): fara jurnal local — evidenta e in gateway, consultata prin API** | decizia utilizatorului | — |
| 24 | Eng voice #6-#9 | Dedup VIN+zi verificat in E2E, cheia API nelogata, CODOP gol marcat, client transport pur | mecanic | P1/P5 |
| 25 | Revizie Marius | Config in `optiuni` (mecanism existent), zero tabele noi, situatie in cursor temporar | decizia utilizatorului | — |
| 26 | Revizie Marius | Un singur formular: panou Configurare (URL/cheie/mediu) direct in fereastra de transmitere | decizia utilizatorului | — |

Contestari NEauto-decise (poarta finala): C1 enqueue-on-close vs manual (CEO voice #1);
C2 KMINT ca odometru_final (CEO #3 + Eng #1 — ambele voci independente); C3 multi-CUI (CEO #6);
T1 auto-refresh statusuri la deschiderea ferestrei (taste).

### Arhitectura (Eng S1, revizuita — zero tabele noi)
```
ofundal_dev.vcx (Page2.Cw8 xmenu)
   |1 Export xml            -> export_comanda_xml (existent, oproceduri_devize.prg)
   |2 Export CSV            -> export_operatii_csv  \
   |3 Trimitere AUTOPASS    -> trimitere_autopass    } oproceduri_autopass.prg (NOU)
                                   |
                              frm_autopass.scx (NOU)
                               |            |
                     cursoare Oracle    AutopassClient (WinHTTP, JSON UTF-8)
                     (auto_istoric_comenzi,      |
                      dev_oper+dev_nom_norme)    +--> https://autopass.romfast.ro
                               |                      /v1/ping /v1/prezentari
                     config: tabel `optiuni`          /v1/prezentari/valideaza
                     (AUTOPASS_URL/KEY/ENV via        /v1/prezentari?perioada (situatie)
                      citeste_optiune/gc*)                 |
                                                  crs_autopass_situatie (cursor temporar,
                                                   corelat pe `obs` cu gridul — NU se
                                                   persista nimic local)
```
Cuplaj: fereastra depinde doar de procedurile din `oproceduri_autopass.prg`; clientul HTTP
nu stie de Oracle (primeste/intoarce cursoare/obiecte) → reutilizabil pentru auto-send 1.1.

### Acoperire de test (Eng S3 — verificare manuala E2E, VFP nu are framework de teste)
```
CODEPATHS                                      VERIFICARE
AUTOPASS_KEY goala -> panou Configurare extins E2E: goleste cheia, redeschide fereastra
salvare config din panou -> ping + badge       E2E: schimba mediul test<->prod, Salveaza
GET /v1/ping ok/401                            E2E: cheie buna / cheie gresita
cursor header (perioada cu/fara comenzi)       E2E: 2 perioade cunoscute
pre-validare (VIN invalid, km 0, fara operatii)E2E: comenzi istorice reale
dry-run /valideaza                             E2E: verdictele = trimiterea reala
POST lot ok / 422 / 5xx                        E2E pe mediul RAR TEST
dedup (retrimitere aceleasi comenzi)           E2E: a doua trimitere -> deduped
diacritice in DENOP                            E2E: comanda cu operatii cu s,t,a,i
situatie: corelare obs + refresh statusuri     E2E: queued -> sent + id_prezentare in grid
situatie indisponibila                         E2E: URL gresit -> statusuri necunoscute + confirmare
CSV export -> import web                       E2E: upload in dashboard, automap coloane
xmenu (3 optiuni, Esc)                         E2E: fiecare ramura + anulare
driver .prg fara forma (1 comanda hand-built)  E2E: acopera encoding/headers/timeouts izolat
2 comenzi, acelasi VIN, aceeasi zi             E2E: corelare corecta pe obs (NRORD diferit)
```
Toate pe mediul RAR **test** inainte de orice trimitere pe prod.

### Dream state delta
12 luni: declararea RAR e zero-touch — la validarea comenzii, transmiterea pleaca automat,
statusul apare pe comanda, iar utilizatorul intervine doar la `needs_mapping`/`needs_data`.
Planul v1.0 construieste exact fundatia reutilizabila (config in optiuni, client HTTP,
situatie din gateway, fereastra); 1.1 adauga hook-ul de auto-send. Nicio piesa din v1.0
nu se arunca.

## Raport VERIFY

> Se completeaza la faza VERIFY: PASS/FAIL per criteriu, cu dovezi (ping, POST pe RAR test,
> capturi grid + dashboard web). Lipseste pana la VERIFY.

## GSTACK REVIEW REPORT

| Review | Trigger | Why | Runs | Status | Findings |
|--------|---------|-----|------|--------|----------|
| CEO Review | `/plan-ceo-review` | Scope & strategy | 1 | CLEAN (PLAN via /autoplan) | 6 propuneri, 3 acceptate, 4 amanate; contestarile C1-C3 rezolvate la poarta |
| Codex Review | `/codex review` | Independent 2nd opinion | 0 | — (Codex neinstalat, voci = subagent-only) | — |
| Eng Review | `/plan-eng-review` | Architecture & tests (required) | 1 | CLEAN (PLAN via /autoplan) | 12 constatari, 0 critical gaps, toate incorporate |
| Design Review | `/plan-design-review` | UI/UX gaps | 1 | CLEAN (FULL via /autoplan) | scor 5/10 → 9/10, 9 decizii adaugate |
| DX Review | `/plan-devex-review` | Developer experience gaps | 0 | SKIPPED | fara scope developer-facing |

- **VERDICT:** CEO + ENG + DESIGN CLEARED — gata de implementare. Decizii poarta finala:
  C1=A (manual v1.0, auto-send in 1.1), C2=A (KMINT ca odometru_final, documentat),
  C3=A (o cheie/BD; multi-service se revizuieste la nevoie), T1=A (auto-refresh la deschidere).
- **Revizie post-aprobare (2026-07-09, Marius)**: decizia 7 — zero tabele noi; US-001
  rescris pe tabelul `optiuni`, US-005 rescris pe situatia din gateway (cursor temporar);
  scripturile SQL revertate.
- **Revizie post-aprobare (2026-07-10, Marius)**: decizia 9 — normalizare NRINMAT (strip
  spatii/cratime/puncte) aprobata pe cele 3 canale (gateway, client VFP, spike SQL v2);
  motivata de rata scazuta de valid (13,8%) gasita in spike-ul v1.

NO UNRESOLVED DECISIONS
