Files
roa2web-service-auto/backend/modules/service_auto/services/comanda_service.py
Claude Agent 32aca55c78 feat(service-auto): săpt 3-phase2 — toate ipotezele confirmate + modul funcțional
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>
2026-06-05 09:37:09 +00:00

110 lines
3.9 KiB
Python

import re
from typing import NoReturn
import oracledb
from fastapi import HTTPException
from shared.database.oracle_pool import oracle_pool
from ..schemas.comanda import ComandaRequest, ComandaResponse
from .. import logger
def _handle_oracle_error(e: Exception) -> NoReturn:
"""
Map Oracle error codes to FastAPI HTTPExceptions. Always raises.
Code ranges:
20001-20999 → 422 Unprocessable (business rule errors from RAISE_APPLICATION_ERROR)
12541/12170/12154/12560 → 503 Service Unavailable (Oracle unreachable / network)
1017 → 500 + CRITICAL log (bad credentials — config error)
942 → 500 + CRITICAL log (missing object/grant — deployment error)
* → 500 + ERROR log (unexpected)
"""
err = e.args[0]
code = getattr(err, "code", 0)
raw_message = getattr(err, "message", str(e))
if 20001 <= code <= 20999:
# Strip "ORA-2xxxx: " prefix injected by Oracle; expose the business message only
clean = re.sub(r"^ORA-\d+:\s*", "", raw_message).strip()
raise HTTPException(status_code=422, detail=clean)
if code in (12541, 12170, 12154, 12560):
raise HTTPException(
status_code=503,
detail="Serviciul bazei de date e temporar indisponibil",
)
if code == 1017:
logger.critical("Oracle credentials rejected (ORA-01017)", exc_info=True)
raise HTTPException(
status_code=500,
detail="Eroare de configurare. Contactați administratorul.",
)
if code == 942:
logger.critical("Oracle object not found or grant missing (ORA-00942)", exc_info=True)
raise HTTPException(
status_code=500,
detail="Eroare internă. Contactați administratorul.",
)
logger.error("Unexpected Oracle error ORA-%05d", code, exc_info=True)
raise HTTPException(status_code=500, detail="Eroare internă neașteptată")
class ComandaService:
@staticmethod
async def creeaza_comanda(
data: ComandaRequest,
username: str,
) -> ComandaResponse:
logger.info(
"service_auto.create_comanda START",
extra={
"user": username,
"tip": data.tip_id,
"client_id": data.id_masiniclient,
"id_firma": data.id_firma,
},
)
async with oracle_pool.get_connection("mariusm_test") as connection:
try:
with connection.cursor() as cursor:
out_id_ordl = cursor.var(oracledb.NUMBER)
out_nrord = cursor.var(oracledb.STRING)
cursor.callproc(
"MARIUSM_AUTO.SP_CREEAZA_COMANDA_PROTOTIP",
[
data.tip_id, # p_tip IN NUMBER
data.id_masiniclient, # p_id_masiniclient IN NUMBER
data.solicitari, # p_solicitari IN VARCHAR2
data.id_firma, # p_id_firma IN NUMBER
out_id_ordl, # p_id_ordl OUT NUMBER
out_nrord, # p_nrord OUT VARCHAR2
],
)
connection.commit()
id_ordl = int(out_id_ordl.getvalue())
nrord = out_nrord.getvalue() or ""
except oracledb.DatabaseError as e:
try:
connection.rollback()
except Exception:
pass # connection may be dead on network errors; ignore
_handle_oracle_error(e)
logger.info(
"service_auto.create_comanda OK",
extra={"user": username, "id_ordl": id_ordl, "nrord": nrord},
)
return ComandaResponse(
id_ordl=id_ordl,
nrord=nrord,
mesaj=f"Comanda {nrord} creata cu succes.",
)