Files
microservice/api/api_v2/modules/pedimentos/services.py
2025-10-04 10:08:26 -06:00

357 lines
13 KiB
Python

"""Servicios para el manejo de pedimentos completos."""
import logging
from typing import Any, Dict, List, Optional
from fastapi import HTTPException
# Importar controladores (nota: el archivo se llama controllers,py con coma)
import sys
import os
sys.path.append(os.path.dirname(__file__))
from .controllers import pedimento_rest_controller, pedimento_vu_controller, pedimento_xml_scraper
from utils.helpers import soap_error
# Logger configurado para el módulo
logger = logging.getLogger("app.api")
async def consume_ws_get_pedimento_completo(**kwargs) -> Dict[str, Any]:
"""
Consume el servicio web para obtener pedimento completo.
Args:
**kwargs: Debe contener 'credencial' y 'pedimento' con sus respectivos campos
Returns:
Dict con 'documento' y 'xml_content'
Raises:
HTTPException: Si hay errores en la petición o datos faltantes
"""
# Validar datos de entrada
credencial = kwargs.get('credencial', {})
pedimento_data = kwargs.get('pedimento', {})
if not credencial.get('user') or not credencial.get('password'):
raise HTTPException(status_code=400, detail="Credenciales incompletas")
required_fields = ['aduana', 'patente', 'pedimento', 'id', 'organizacion']
missing_fields = [f for f in required_fields if not pedimento_data.get(f)]
if missing_fields:
raise HTTPException(
status_code=400,
detail=f"Datos de pedimento incompletos: {missing_fields}"
)
logger.info(f"Iniciando consulta SOAP para pedimento: {pedimento_data.get('pedimento')}")
try:
# Generar XML SOAP
soap_xml = pedimento_vu_controller.generate_pedimento_completo_template(
username=credencial.get('user'),
password=credencial.get('password'),
aduana=pedimento_data.get('aduana'),
patente=pedimento_data.get('patente'),
pedimento=pedimento_data.get('pedimento')
)
soap_headers = {
'Content-Type': 'text/xml; charset=utf-8'
}
# Realizar petición SOAP
soap_response = await pedimento_vu_controller.make_request_async(
"ventanilla-ws-pedimentos/ConsultarPedimentoCompletoService?wsdl",
data=soap_xml,
headers=soap_headers
)
if not soap_response:
raise HTTPException(status_code=500, detail="No se recibió respuesta del servicio SOAP")
if soap_error(soap_response):
logger.error(f"Error en respuesta SOAP: {soap_response.text if hasattr(soap_response, 'text') else 'Sin detalles'}")
raise HTTPException(status_code=500, detail="Error en la respuesta del servicio SOAP")
# Extraer datos del XML
try:
data = pedimento_xml_scraper.extract_data(soap_response.text)
except Exception as e:
logger.error(f"Error al extraer datos XML: {e}")
raise HTTPException(status_code=500, detail="Error al procesar respuesta XML")
# Generar nombre de archivo
file_name = f"vu_PC_{pedimento_data.get('pedimento_app', 'unknown')}.xml"
# Enviar documento
try:
if soap_error(soap_response):
document_response = await pedimento_rest_controller.post_document(
soap_response=None,
organizacion=pedimento_data.get('organizacion'),
pedimento=pedimento_data.get('id'),
file_name=f"vu_PC_{pedimento_data.get('pedimento_app', 'unknown')}_ERROR.xml",
document_type=10,
)
raise HTTPException(status_code=500, detail="Error en la respuesta del servicio SOAP")
else:
document_response = await pedimento_rest_controller.post_document(
soap_response=soap_response,
organizacion=pedimento_data.get('organizacion'),
pedimento=pedimento_data.get('id'),
file_name=file_name,
document_type=2,
)
except Exception as e:
logger.error(f"Error al enviar documento: {e}")
raise HTTPException(status_code=500, detail="Error al guardar documento")
# Enriquecer datos con información del pedimento
data['organizacion'] = pedimento_data.get('organizacion')
data['id'] = pedimento_data.get('id')
logger.info(f"Pedimento completo procesado exitosamente: {pedimento_data.get('pedimento')}")
return {
"documento": document_response,
"xml_content": data
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error inesperado en consume_ws_get_pedimento_completo: {e}")
raise HTTPException(status_code=500, detail=f"Error interno: {str(e)}")
async def put_pedimento_data(**kwargs) -> Dict[str, Any]:
"""
Actualiza la información del pedimento en el sistema REST.
Args:
**kwargs: Datos de credencial y pedimento
Returns:
Dict con resultados del procesamiento
Raises:
HTTPException: Si hay errores críticos en el procesamiento
"""
# Inicializar variables de respuesta
result = {
"documento": None,
"pedimento_actualizado": None,
"coves_procesados": None,
"coves_error": None,
"edocuments_procesados": None,
"edocuments_error": None,
"xml_content": None
}
# Obtener datos del servicio web
try:
ws_data = await consume_ws_get_pedimento_completo(**kwargs)
result["documento"] = ws_data.get("documento", None)
xml_content = ws_data.get('xml_content', {})
result["xml_content"] = xml_content
if not xml_content:
logger.warning("No se obtuvo contenido XML del servicio web")
return result
except HTTPException:
raise # Re-lanzar HTTPExceptions
except Exception as e:
logger.error(f"Error inesperado al consumir servicio web: {e}")
raise HTTPException(status_code=500, detail=f"Error al obtener datos del pedimento: {str(e)}")
# Actualizar información del pedimento (crítico)
try:
result["pedimento_actualizado"] = await _update_pedimento_info(kwargs, xml_content)
except Exception as e:
logger.error(f"Error crítico al actualizar pedimento: {e}")
raise HTTPException(status_code=500, detail=f"Error al actualizar el pedimento: {str(e)}")
# Procesar COVEs (no crítico)
try:
result["coves_procesados"] = await _process_coves_safely(kwargs, xml_content)
except Exception as e:
logger.warning(f"Error al procesar COVEs: {e}")
result["coves_error"] = str(e)
# Procesar documentos digitalizados (no crítico)
try:
result["edocuments_procesados"] = await _process_edocuments_safely(kwargs, xml_content)
except Exception as e:
logger.warning(f"Error al procesar documentos digitalizados: {e}")
result["edocuments_error"] = str(e)
logger.info("Procesamiento de pedimento completo finalizado")
return result
async def _update_pedimento_info(kwargs: Dict[str, Any], xml_content: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""
Actualiza la información del pedimento.
Args:
kwargs: Datos originales
xml_content: Contenido XML extraído
Returns:
Respuesta del servicio de actualización
"""
if not xml_content:
logger.info("No hay contenido XML para actualizar el pedimento")
return None
# Preparar datos para actualización (excluir identificadores_ed)
update_content = {k: v for k, v in xml_content.items() if k != 'identificadores_ed'}
update_content['existe_expediente'] = True
pedimento_id = kwargs.get('pedimento', {}).get('id')
if not pedimento_id:
raise ValueError("ID de pedimento no encontrado para actualización")
response = await pedimento_rest_controller.put_pedimento(pedimento_id, update_content)
logger.info(f"Pedimento {pedimento_id} actualizado exitosamente")
return response
async def _process_coves_safely(kwargs: Dict[str, Any], xml_content: Dict[str, Any]) -> Optional[List[Dict[str, Any]]]:
"""
Procesa los COVEs de manera segura.
"""
coves = xml_content.get('coves', [])
if not coves:
logger.info("No se encontraron COVEs para procesar")
return None
logger.info(f"Procesando {len(coves)} COVEs encontrados")
result = await _post_coves(kwargs.get('pedimento', {}), coves)
logger.info(f"Se procesaron exitosamente {len(result)} COVEs")
return result
async def _process_edocuments_safely(kwargs: Dict[str, Any], xml_content: Dict[str, Any]) -> Optional[List[Dict[str, Any]]]:
"""
Procesa los documentos digitalizados de manera segura.
"""
identificadores_ed = xml_content.get('identificadores_ed', [])
if not identificadores_ed:
logger.info("No se encontraron documentos digitalizados (identificadores ED)")
return None
logger.info(f"Procesando {len(identificadores_ed)} documentos digitalizados...")
result = await _post_edocuments(kwargs.get('pedimento', {}), identificadores_ed)
logger.info(f"Se procesaron exitosamente {len(result)} documentos digitalizados")
return result
async def _post_coves(pedimento_data: Dict[str, Any], coves: List[str]) -> List[Dict[str, Any]]:
"""
Envía COVEs al sistema REST.
Args:
pedimento_data: Datos del pedimento
coves: Lista de números de COVE
Returns:
Lista de respuestas exitosas
Raises:
HTTPException: Si no se pudo procesar ningún COVE
"""
if not coves:
return []
responses = []
errors = []
for cove in coves:
document_data = {
'numero_cove': cove,
'organizacion': pedimento_data.get('organizacion'),
'pedimento': pedimento_data.get('id')
}
try:
response = await pedimento_rest_controller.post_cove(document_data)
if response:
responses.append(response)
logger.debug(f"COVE {cove} procesado exitosamente")
except Exception as e:
error_msg = f"Error al procesar COVE {cove}: {str(e)}"
logger.warning(error_msg)
errors.append(error_msg)
if not responses and coves:
error_detail = f"No se pudo procesar ningún COVE. Errores: {'; '.join(errors)}"
logger.error(error_detail)
raise HTTPException(status_code=500, detail=error_detail)
if errors:
logger.warning(f"Se procesaron {len(responses)}/{len(coves)} COVEs. Errores: {len(errors)}")
return responses
async def _post_edocuments(pedimento_data: Dict[str, Any], identificadores_ed: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
"""
Envía documentos digitalizados al sistema REST.
Args:
pedimento_data: Datos del pedimento
identificadores_ed: Lista de identificadores de documentos
Returns:
Lista de respuestas exitosas
Raises:
HTTPException: Si no se pudo procesar ningún documento
"""
if not identificadores_ed:
return []
responses = []
errors = []
for identificador in identificadores_ed:
try:
# Validar campos requeridos
if not identificador.get('clave') or not identificador.get('complemento1'):
logger.warning(f"Documento con datos incompletos omitido: {identificador}")
continue
document_data = {
'clave': identificador.get('clave'),
'descripcion': identificador.get('descripcion', ''),
'numero_edocument': identificador.get('complemento1'),
'organizacion': pedimento_data.get('organizacion'),
'pedimento': pedimento_data.get('id')
}
response = await pedimento_rest_controller.post_edocument(document_data)
if response:
responses.append(response)
logger.debug(f"Documento {identificador.get('clave')} procesado exitosamente")
except Exception as e:
error_msg = f"Error al procesar documento {identificador.get('clave', 'unknown')}: {str(e)}"
logger.warning(error_msg)
errors.append(error_msg)
if not responses and identificadores_ed:
error_detail = f"No se pudo procesar ningún documento digitalizado. Errores: {'; '.join(errors)}"
logger.error(error_detail)
raise HTTPException(status_code=500, detail=error_detail)
if errors:
logger.warning(f"Se procesaron {len(responses)}/{len(identificadores_ed)} documentos. Errores: {len(errors)}")
return responses