diff --git a/Back_comercial_iko/app/comercial/Main_comercial.py b/Back_comercial_iko/app/comercial/Main_comercial.py index 0d37323..33df482 100644 --- a/Back_comercial_iko/app/comercial/Main_comercial.py +++ b/Back_comercial_iko/app/comercial/Main_comercial.py @@ -3,6 +3,7 @@ from Back_comercial_iko.services.Comercial_service import ComercialService from Back_comercial_iko.core.Response import ApiResponse from Back_comercial_iko.core.HttpStatus import HttpStatus from Back_comercial_iko.core.AuthTokenDoli import TokenDoliManager +from Back_comercial_iko.core.ExceptionHandler import db_error_response router = APIRouter(prefix="/comercial", tags=["Comercial"]) @@ -14,4 +15,4 @@ def create_project(data: dict, token_data: dict = Depends(TokenDoliManager.verif result = service.create_project_commercial(data, token_data) return ApiResponse.success(result, "Proyecto creado", HttpStatus.CREATED) except Exception as e: - return ApiResponse.error(str(e), HttpStatus.NOT_FOUND) \ No newline at end of file + return db_error_response(e) \ No newline at end of file diff --git a/Back_comercial_iko/core/ExceptionHandler.py b/Back_comercial_iko/core/ExceptionHandler.py index 6647f5d..f6bdda7 100644 --- a/Back_comercial_iko/core/ExceptionHandler.py +++ b/Back_comercial_iko/core/ExceptionHandler.py @@ -2,15 +2,55 @@ from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from fastapi import Request from Back_comercial_iko.core.HttpStatus import HttpStatus +from sqlalchemy.exc import IntegrityError, SQLAlchemyError async def validation_exception_handler(request: Request, exc: RequestValidationError): - + print(f"Error de validación: {exc}") return JSONResponse( status_code=HttpStatus.BAD_REQUEST, content={ "success": False, "message": "Formato de request inválido", - "error_code": "INVALID_JSON" + "error_code": "INVALID_JSON", + "status_code": HttpStatus.BAD_REQUEST, + "data": None } - ) \ No newline at end of file + ) + + +def db_error_response(e: Exception): + """Convert any error to a friendly response""" + + response = { + "success": False, + "message": "Error interno del servidor", + "error_code": "INTERNAL_ERROR", + "status_code": HttpStatus.INTERNAL_SERVER_ERROR, + "data": None + } + + if isinstance(e, IntegrityError): + error_msg = str(e.orig) if e.orig else str(e) + response["status_code"] = HttpStatus.CONFLICT + print(f"Error en la base de datos: {error_msg}") + + if "Duplicate entry" in error_msg: + response["message"] = "Ya existe un registro con estos datos" + response["error_code"] = "DUPLICATE_ENTRY" + elif "foreign key constraint fails" in error_msg: + response["message"] = "Referencia a un registro que no existe" + response["error_code"] = "FOREIGN_KEY_ERROR" + elif "cannot be null" in error_msg: + response["message"] = "Faltan campos requeridos" + response["error_code"] = "REQUIRED_FIELD_NULL" + else: + response["message"] = "Error de integridad de datos" + response["error_code"] = "INTEGRITY_ERROR" + + elif isinstance(e, SQLAlchemyError): + response["message"] = "Error en la base de datos" + response["error_code"] = "DATABASE_ERROR" + response["status_code"] = HttpStatus.INTERNAL_SERVER_ERROR + + return response \ No newline at end of file diff --git a/Back_comercial_iko/core/MessageException.py b/Back_comercial_iko/core/MessageException.py new file mode 100644 index 0000000..653242e --- /dev/null +++ b/Back_comercial_iko/core/MessageException.py @@ -0,0 +1,14 @@ +class MessageException(Exception): + def __init__(self, societe_name=None, extra_msg=None): + base_message = "" + if societe_name: + base_message += f": '{societe_name}'" + if extra_msg: + base_message += f"{extra_msg}" + + self.message = base_message + super().__init__(self.message) + + @staticmethod + def raise_it(societe_name=None, extra_msg=None): + raise MessageException(societe_name, extra_msg) \ No newline at end of file diff --git a/Back_comercial_iko/core/SocieteNotFoundException.py b/Back_comercial_iko/core/SocieteNotFoundException.py deleted file mode 100644 index 0278f94..0000000 --- a/Back_comercial_iko/core/SocieteNotFoundException.py +++ /dev/null @@ -1,10 +0,0 @@ -class SocieteNotFoundException(Exception): - def __init__(self, societe_name=None, extra_msg=None): - base_message = "Societe not found" - if societe_name: - base_message += f": '{societe_name}'" - if extra_msg: - base_message += f" - {extra_msg}" - - self.message = base_message - super().__init__(self.message) \ No newline at end of file diff --git a/Back_comercial_iko/models/Projet_model.py b/Back_comercial_iko/models/Projet_model.py index ac37627..2869b07 100644 --- a/Back_comercial_iko/models/Projet_model.py +++ b/Back_comercial_iko/models/Projet_model.py @@ -47,6 +47,4 @@ class ProjetModel(Base): IP = Column(String(250), nullable=True) LAST_MAIN_DOC = Column(String(255), nullable=True) IMPORT_KEY = Column(String(14), nullable=True) - EXTRAPARAMS = Column(String(255), nullable=True) - CREATED_AT = Column(DateTime, default=datetime.utcnow) - UPDATED_AT = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) \ No newline at end of file + EXTRAPARAMS = Column(String(255), nullable=True) \ No newline at end of file diff --git a/Back_comercial_iko/models/Societe_model.py b/Back_comercial_iko/models/Societe_model.py index d7d2624..92bc109 100644 --- a/Back_comercial_iko/models/Societe_model.py +++ b/Back_comercial_iko/models/Societe_model.py @@ -94,6 +94,4 @@ class SocieteModel(Base): FK_USER_MODIF = Column(Integer, nullable=True) FK_MULTICURRENCY = Column(Integer, nullable=True) MULTICURRENCY_CODE = Column(String(3), nullable=True) - IMPORT_KEY = Column(String(14), nullable=True) - CREATED_AT = Column(DateTime, default=datetime.utcnow) - UPDATED_AT = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) \ No newline at end of file + IMPORT_KEY = Column(String(14), nullable=True) \ No newline at end of file diff --git a/Back_comercial_iko/services/Comercial_service.py b/Back_comercial_iko/services/Comercial_service.py index 66048c5..8462efa 100644 --- a/Back_comercial_iko/services/Comercial_service.py +++ b/Back_comercial_iko/services/Comercial_service.py @@ -1,7 +1,11 @@ from Back_comercial_iko.database.Database import Database from Back_comercial_iko.models.Societe_model import SocieteModel +from Back_comercial_iko.models.Projet_model import ProjetModel +from Back_comercial_iko.models.Projet_extrafields_model import ProjetExtrafieldsModel from Back_comercial_iko.core.validators.Field_validator import FieldValidator -from Back_comercial_iko.core.SocieteNotFoundException import SocieteNotFoundException +from Back_comercial_iko.core.MessageException import MessageException +from datetime import datetime + class ComercialService: @@ -9,18 +13,72 @@ class ComercialService: self.conn = Database() self.db = self.conn.setConnection() - def create_project_commercial(self, data: dict, token_data: dict): + + def new_ref(self): + ALIAS_REF = "PCom" + year = datetime.now().strftime("%y") + + result = self.db.query(ProjetModel.REF).filter( + ProjetModel.REF.like(f"%{ALIAS_REF}0%") + ).order_by(ProjetModel.REF.desc()).first() + + if result and result.REF: + ref_str = result.REF + start = ref_str.find(ALIAS_REF) + len(ALIAS_REF) + numero_str = ref_str[start:start + 4] + new_ref_num = int(numero_str) + 1 if numero_str.isdigit() else 1 + else: + new_ref_num = 1 + + return f"{ALIAS_REF}{str(new_ref_num).zfill(4)}-{year}" + + def create_project_commercial(self, data: dict, token_data: dict): + """Service to create a new commercial project""" data_session_login = token_data['data'] FieldValidator.required(data.get("ex_societe"), "ex_societe") - FieldValidator.required(data.get("nomUser"), "nomUser") - nombre_soc = data.get("ex_societe") - result_soc = (self.db.query(SocieteModel.ROWID, SocieteModel.NOM).filter(SocieteModel.NOM == nombre_soc).first()) - if not result_soc: - raise SocieteNotFoundException() + FieldValidator.required(data.get("description"), "description") + FieldValidator.required(data.get("date_o"), "date_o") + FieldValidator.required(data.get("date_e"), "date_e") + name_soc = data.get("ex_societe") + date_c = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + result_soc = (self.db.query(SocieteModel.ROWID, SocieteModel.NOM).filter(SocieteModel.NOM == name_soc).first()) + fk_soc = result_soc.ROWID if result_soc else None + id_user = data_session_login['id'] + description = data.get("description") + dateo = data.get("date_o") + datee = data.get("date_e") + last_contact = data.get("last_contact"), + agency = data.get("agency"), + advertiser = data.get("advertiser"), + status = data.get("status") + + if fk_soc is None: + new_societe = SocieteModel(NOM=name_soc, NAME_ALIAS=name_soc, ENTITY=1, CLIENT=1, FOURNISSEUR=0, DATEC=date_c) + self.db.add(new_societe) + self.db.flush() + self.db.commit() + fk_soc = new_societe.ROWID + + new_project = ProjetModel(TMS=date_c, DESCRIPTION=description, TITLE=description, DATEO=dateo, DATEE=datee, FK_STATUT=1, + FK_USER_CREAT=id_user, REF=self.new_ref(), DATEC=date_c, FK_SOC=fk_soc) + self.db.add(new_project) + self.db.flush() + self.db.commit() + rowid_project = new_project.ROWID if new_project.ROWID else MessageException.raise_it(extra_msg="No se pudo crea el proyecto") + + if rowid_project: + extrafields_project = ProjetExtrafieldsModel(FK_OBJECT=rowid_project, TIPO=2, LAST_CONTACT=last_contact, + AGENCIA=agency, ANUNCIANTE=advertiser, ESTADO=status) + self.db.add(extrafields_project) + self.db.flush() + self.db.commit() + rowid_extrafields = extrafields_project.ROWID if extrafields_project.ROWID else MessageException.raise_it(extra_msg="No se pudo crear el proyecto") return { - "fk_soc": result_soc.ROWID, - "nombre_soc": nombre_soc + "fk_soc": fk_soc, + "nombre_soc": name_soc, + "rowid_project": rowid_project, + "rowid_extrafields": rowid_extrafields, } \ No newline at end of file