from core.config import settings from dataclasses import dataclass import requests import httpx import datetime import time class SOAPController: """ Controlador para manejar las peticiones SOAP. """ def __init__(self): self.base_url = settings.SOAP_SERVICE_URL self.timeout = settings.TIMEOUT # Timeout por default import ssl # Contexto SSL personalizado para permitir claves DH pequeñas ssl_context = ssl.create_default_context() ssl_context.set_ciphers('DEFAULT@SECLEVEL=1') ssl_context.check_hostname = False ssl_context.verify_mode = ssl.CERT_NONE async def make_request(self, endpoint, data=None, headers=None, max_retries=5): intento = 0 while intento < settings.MAX_RETRIES: try: with httpx.Client(verify=self.ssl_context, timeout=self.timeout) as client: content = data.encode('utf-8') if data else None response = client.post( f"{self.base_url}/{endpoint}", content=content, headers=headers ) response.raise_for_status() return response # ✅ éxito except Exception as e: intento += 1 wait_time = 0 print(f"[{endpoint}] Error intento {intento}: {e}. Reintentando en {settings.WAIT_TIME}s...") time.sleep(settings.WAIT_TIME) print(f"[{endpoint}] Fallo tras {settings.MAX_RETRIES} intentos.") return None async def make_request_async(self, endpoint, data=None, headers=None, max_retries=5): """ Método asíncrono para hacer peticiones SOAP sin bloquear el event loop Args: endpoint: El endpoint al que se va a hacer la petición data: Los datos a enviar en la petición headers: Los headers HTTP a incluir en la petición max_retries: Número máximo de reintentos en caso de fallo Returns: La respuesta de la petición, o None si falla tras los reintentos """ import asyncio intento = 0 while intento < settings.MAX_RETRIES: try: async with httpx.AsyncClient(verify=self.ssl_context, timeout=self.timeout) as client: content = data.encode('utf-8') if data else None response = await client.post( f"{self.base_url}/{endpoint}", content=content, headers=headers ) response.raise_for_status() return response # ✅ éxito except Exception as e: intento += 1 print(f"[{endpoint}] Error intento {intento}: {e}. Reintentando en {settings.WAIT_TIME}s...") if intento < settings.MAX_RETRIES: await asyncio.sleep(settings.WAIT_TIME) # ASYNC SLEEP! print(f"[{endpoint}] Fallo tras {settings.MAX_RETRIES} intentos.") return None def generate_remesas_template(self, username: str, password: str, aduana: str, patente: str, numero_operacion: str, pedimento: str) -> str: """ Genera el template SOAP para consultar remesas Args: username: Usuario de VUCEM password: Contraseña de VUCEM aduana: Código de aduana patente: Número de patente Returns: str: Template SOAP XML completo """ soap_template = f''' {username} {password} {numero_operacion} {aduana} {patente} {pedimento} ''' return soap_template def generate_pedimento_completo_template(self, username: str, password: str, aduana: str, patente: str, pedimento: str) -> str: """ Genera el template SOAP para consultar pedimento completo Args: username: Usuario de VUCEM password: Contraseña de VUCEM aduana: Código de aduana patente: Número de patente pedimento: Número de pedimento Returns: str: Template SOAP XML completo """ soap_template = f''' {username} {password} {aduana} {patente} {pedimento} ''' return soap_template def generate_partidas_template(self, username: str, password: str, aduana: str, patente: str, pedimento: str, numero_operacion: str, partida: str) -> str: """ Genera el template SOAP para consultar partidas de un pedimento Args: username: Usuario de VUCEM password: Contraseña de VUCEM aduana: Código de aduana patente: Número de patente pedimento: Número de pedimento Returns: str: Template SOAP XML completo """ soap_template = f''' {username} {password} {aduana} {patente} {pedimento} {numero_operacion} {partida} ''' return soap_template def generate_acuse_template(self, username: str, password: str, idEDocument: str) -> str: soap_template = f''' {username} {password} {idEDocument} ''' return soap_template def generate_estado_pedimento_template(self, username: str, password: str, aduana: str, patente: str, pedimento: str, numero_operacion: str) -> str: soap_template = f''' {username} {password} {numero_operacion} {aduana} {patente} {pedimento} ''' return soap_template def generate_edocument_template(self, username: str, password: str, idEDocument: str) -> str: """ Genera el template SOAP para consultar un EDocument específico Args: username: Usuario de VUCEM password: Contraseña de VUCEM idEDocument: ID del EDocument Returns: str: Template SOAP XML completo """ soap_template = f''' {username} {password} {idEDocument} 1 ''' return soap_template def generate_cove_template(self, username: str, password: str, certificado: str, firma: str, cove: str) -> str: """ Genera el template SOAP para consultar un COVE específico Args: username: Usuario de VUCEM password: Contraseña de VUCEM certificado: certificado base 64 firma: firma a base de cadena original base 64 cove: COVE Returns: str: Template SOAP XML completo """ soap_template = f''' {username} {password} {certificado} |{username}|{cove}| {firma} {cove} ''' return soap_template soap_controller = SOAPController() # Instancia global del controlador SOAP