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.", )