Backend: - service_auto module complet: router, service, schemas, 5 teste suites (22/22 passed) - 5 endpoints: GET /ping, /firme, /tip-deviz, /masini, POST /comenzi - SP_CREEAZA_COMANDA_PROTOTIP creat în MARIUSM_AUTO (VALID, 5.9ms) - oracle_pool.py: session_callback backward-compat patch - ROA_WEB user: grants SP-only confirmate (H3), mariusm_test pool switchat - pyproject.toml: integration pytest marker înregistrat Frontend: - ComandaNoua.vue: date reale din Oracle (firme/tip-deviz/masini), nu hardcodate - src/modules/service-auto/services/api.js: axios service cu Bearer token - src/router/index.js: rută /service-auto/comanda-noua Docs: - decision-log.md: verdict MERGE, toate 6 ipoteze CONFIRMED - learnings.md: 7 patterns reutilizabile - grants-audit.md: arhitectura multi-tenant + proxy auth analysis + V_NOM_FIRME loop - template-modul-oracle.md: rețetă completă pentru module Oracle noi - TODO-phase2.md: 7 items concrete Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
111 lines
3.9 KiB
Python
111 lines
3.9 KiB
Python
"""
|
|
Lookup data for service_auto forms — tip deviz, masini, firme.
|
|
|
|
All three endpoints are read-only and infrequently changing.
|
|
"""
|
|
from typing import List
|
|
|
|
import oracledb
|
|
from fastapi import HTTPException
|
|
from shared.database.oracle_pool import oracle_pool
|
|
|
|
from ..schemas.comanda import FirmaItem, MasinaClientItem, TipDevizItem
|
|
from .. import logger
|
|
|
|
|
|
class LookupService:
|
|
|
|
@staticmethod
|
|
async def get_firme(company_ids: List[str]) -> List[FirmaItem]:
|
|
"""
|
|
Returns firma names for the company IDs in the user's JWT.
|
|
Uses 'central' pool (CONTAFIN_ORACLE) to query V_NOM_FIRME.
|
|
"""
|
|
if not company_ids:
|
|
return []
|
|
|
|
placeholders = ", ".join(f":id{i}" for i in range(len(company_ids)))
|
|
query = f"""
|
|
SELECT id_firma, firma, schema
|
|
FROM CONTAFIN_ORACLE.V_NOM_FIRME
|
|
WHERE id_firma IN ({placeholders})
|
|
ORDER BY id_firma
|
|
"""
|
|
params = {f"id{i}": int(cid) for i, cid in enumerate(company_ids)}
|
|
|
|
try:
|
|
async with oracle_pool.get_connection("central") as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(query, params)
|
|
rows = cur.fetchall()
|
|
except oracledb.DatabaseError:
|
|
logger.error("get_firme Oracle error", exc_info=True)
|
|
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 "")
|
|
for r in rows
|
|
]
|
|
|
|
@staticmethod
|
|
async def get_tip_deviz() -> List[TipDevizItem]:
|
|
"""
|
|
Returns all active tip deviz from MARIUSM_AUTO.DEV_TIP_DEVIZ.
|
|
ROA_WEB has SELECT grant on this view.
|
|
"""
|
|
query = """
|
|
SELECT id_tip, denumire, inch_validare
|
|
FROM MARIUSM_AUTO.DEV_TIP_DEVIZ
|
|
ORDER BY id_tip
|
|
"""
|
|
try:
|
|
async with oracle_pool.get_connection("mariusm_test") as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(query)
|
|
rows = cur.fetchall()
|
|
except oracledb.DatabaseError:
|
|
logger.error("get_tip_deviz Oracle error", exc_info=True)
|
|
raise HTTPException(status_code=503, detail="Eroare la încărcarea tipurilor de deviz")
|
|
|
|
return [
|
|
TipDevizItem(id_tip=r[0], denumire=r[1], inch_validare=r[2] or 0)
|
|
for r in rows
|
|
]
|
|
|
|
@staticmethod
|
|
async def get_masini() -> List[MasinaClientItem]:
|
|
"""
|
|
Returns active masini from MARIUSM_AUTO.AUTO_VMASINICLIENTI.
|
|
ROA_WEB has SELECT grant on this view.
|
|
Label format: "PARTENER — MARCA MASINA, NRINMAT (ANFABRICATIE)"
|
|
"""
|
|
query = """
|
|
SELECT id_masiniclient, nrinmat, marca, masina, anfabricatie, partener
|
|
FROM MARIUSM_AUTO.AUTO_VMASINICLIENTI
|
|
WHERE inactiv = 0
|
|
ORDER BY partener, nrinmat
|
|
"""
|
|
try:
|
|
async with oracle_pool.get_connection("mariusm_test") as conn:
|
|
with conn.cursor() as cur:
|
|
cur.execute(query)
|
|
rows = cur.fetchall()
|
|
except oracledb.DatabaseError:
|
|
logger.error("get_masini Oracle error", exc_info=True)
|
|
raise HTTPException(status_code=503, detail="Eroare la încărcarea mașinilor")
|
|
|
|
result = []
|
|
for r in rows:
|
|
id_mc, nrinmat, marca, masina, an, partener = r
|
|
parts = []
|
|
if marca:
|
|
parts.append(marca)
|
|
if masina:
|
|
parts.append(masina)
|
|
vehicul = " ".join(parts) if parts else "?"
|
|
an_str = f" ({int(an)})" if an else ""
|
|
label = f"{partener or '?'} — {vehicul}, {nrinmat or '?'}{an_str}"
|
|
result.append(MasinaClientItem(id_masiniclient=int(id_mc), label=label))
|
|
|
|
return result
|