feat(service-auto): phase 2 — comenzi browse, id_sucursala, cache, migrare SQL

Backend:
- GET /api/service-auto/comenzi cu paginare server-side, filtre dată/status
- ComandaRequest.id_sucursala (Optional) + FirmaItem.id_mama
- get_firme() expune id_mama din V_NOM_FIRME
- callproc SP_CREEAZA_COMANDA_PROTOTIP cu 7 argumente (+ p_id_sucursala)
- Cache TTL in-process: tip_deviz 24h, masini 5min

Frontend:
- ComenziBrowseView.vue — DataTable lazy + filtre + status badges
- ComandaNoua.vue — company store integration, idSucursala computed
- service-auto/stores/sharedStores.js (createCompaniesStore factory)
- HamburgerMenu: secțiune Service Auto (Comenzi + Comandă Nouă)
- router: /service-auto/comenzi

SQL:
- migrations/ff_2026_04_12_01_AUTO.sql — idempotent (COLUMNEXIST guard + CREATE OR REPLACE SP)
- onboarding_roa_web.sql — versioned, parametrizat cu :SCHEMA_NAME
- .claude/rules/oracle-migrations.md — convenție ff_YYYY_MM_DD_NN_MODULE.sql

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Agent
2026-04-12 22:25:32 +00:00
parent 574aca31e4
commit 0a880baef9
15 changed files with 694 additions and 12 deletions

View File

@@ -3,7 +3,8 @@ Lookup data for service_auto forms — tip deviz, masini, firme.
All three endpoints are read-only and infrequently changing.
"""
from typing import List
import time
from typing import List, Optional, Tuple
import oracledb
from fastapi import HTTPException
@@ -12,6 +13,23 @@ from shared.database.oracle_pool import oracle_pool
from ..schemas.comanda import FirmaItem, MasinaClientItem, TipDevizItem
from .. import logger
# In-memory TTL cache: key → (monotonic_timestamp, value)
_cache: dict = {}
_TTL_TIP_DEVIZ = 86400 # 24 h — tip deviz changes only via DB migration
_TTL_MASINI = 300 # 5 min — vehicle inventory changes regularly
def _cache_get(key: str, ttl: float):
entry: Optional[Tuple] = _cache.get(key)
if entry and (time.monotonic() - entry[0]) < ttl:
return entry[1]
return None
def _cache_set(key: str, value) -> None:
_cache[key] = (time.monotonic(), value)
class LookupService:
@@ -26,7 +44,7 @@ class LookupService:
placeholders = ", ".join(f":id{i}" for i in range(len(company_ids)))
query = f"""
SELECT id_firma, firma, schema
SELECT id_firma, firma, schema, id_mama
FROM CONTAFIN_ORACLE.V_NOM_FIRME
WHERE id_firma IN ({placeholders})
ORDER BY id_firma
@@ -43,7 +61,7 @@ class LookupService:
raise HTTPException(status_code=503, detail="Eroare la încărcarea firmelor")
return [
FirmaItem(id_firma=r[0], firma=r[1], schema_name=r[2] or "")
FirmaItem(id_firma=r[0], firma=r[1], schema_name=r[2] or "", id_mama=r[3])
for r in rows
]
@@ -51,8 +69,13 @@ class LookupService:
async def get_tip_deviz() -> List[TipDevizItem]:
"""
Returns all active tip deviz from MARIUSM_AUTO.DEV_TIP_DEVIZ.
Cached in-process for 24 h (changes only via DB migration).
ROA_WEB has SELECT grant on this view.
"""
cached = _cache_get("tip_deviz", _TTL_TIP_DEVIZ)
if cached is not None:
return cached
query = """
SELECT id_tip, denumire, inch_validare
FROM MARIUSM_AUTO.DEV_TIP_DEVIZ
@@ -67,18 +90,25 @@ class LookupService:
logger.error("get_tip_deviz Oracle error", exc_info=True)
raise HTTPException(status_code=503, detail="Eroare la încărcarea tipurilor de deviz")
return [
result = [
TipDevizItem(id_tip=r[0], denumire=r[1], inch_validare=r[2] or 0)
for r in rows
]
_cache_set("tip_deviz", result)
return result
@staticmethod
async def get_masini() -> List[MasinaClientItem]:
"""
Returns active masini from MARIUSM_AUTO.AUTO_VMASINICLIENTI.
Cached in-process for 5 min (vehicle inventory changes regularly).
ROA_WEB has SELECT grant on this view.
Label format: "PARTENER — MARCA MASINA, NRINMAT (ANFABRICATIE)"
"""
cached = _cache_get("masini", _TTL_MASINI)
if cached is not None:
return cached
query = """
SELECT id_masiniclient, nrinmat, marca, masina, anfabricatie, partener
FROM MARIUSM_AUTO.AUTO_VMASINICLIENTI
@@ -107,4 +137,5 @@ class LookupService:
label = f"{partener or '?'}{vehicul}, {nrinmat or '?'}{an_str}"
result.append(MasinaClientItem(id_masiniclient=int(id_mc), label=label))
_cache_set("masini", result)
return result