280 lines
9.5 KiB
Python
280 lines
9.5 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 remesa_rest_controller, remesa_vu_controller, remesa_xml_scraper
|
|
|
|
|
|
from utils.helpers import soap_error
|
|
from ..common import create_service_response, create_error_response
|
|
|
|
# Logger configurado para el módulo
|
|
logger = logging.getLogger("app.api")
|
|
|
|
|
|
async def obtener_remesa(**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 = remesa_vu_controller.generate_remesas_template(
|
|
username=credencial.get('user'),
|
|
password=credencial.get('password'),
|
|
aduana=pedimento_data.get('aduana'),
|
|
patente=pedimento_data.get('patente'),
|
|
pedimento=pedimento_data.get('pedimento'),
|
|
numero_operacion=pedimento_data.get('numero_operacion', '')
|
|
)
|
|
|
|
# Enviar documento EFC
|
|
try:
|
|
|
|
file_name_request = f"vu_RM_{pedimento_data.get('pedimento_app', 'unknown')}_REQUEST.xml"
|
|
document_response = await remesa_rest_controller.post_document(
|
|
soap_response=soap_xml,
|
|
organizacion=pedimento_data.get('organizacion'),
|
|
pedimento=pedimento_data.get('id'),
|
|
file_name=file_name_request,
|
|
document_type=15,
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error al enviar documento de solicitud: {e}")
|
|
|
|
soap_headers = {
|
|
'Content-Type': 'text/xml; charset=utf-8'
|
|
}
|
|
|
|
# Realizar petición SOAP
|
|
soap_response = await remesa_vu_controller.make_request_async(
|
|
"ventanilla-ws-pedimentos/ConsultarRemesasService?wsdl",
|
|
data=soap_xml,
|
|
headers=soap_headers
|
|
)
|
|
# Generar nombre de archivo
|
|
file_name = f"vu_RM_{pedimento_data.get('pedimento_app', 'unknown')}.xml"
|
|
if soap_error(soap_response):
|
|
file_name = f"vu_RM_{pedimento_data.get('pedimento_app', 'unknown')}_ERROR.xml"
|
|
document_response = await remesa_rest_controller.post_document(
|
|
soap_response=soap_response,
|
|
organizacion=pedimento_data.get('organizacion'),
|
|
pedimento=pedimento_data.get('id'),
|
|
file_name=file_name,
|
|
document_type=16,
|
|
)
|
|
raise HTTPException(status_code=500, detail="Error en la respuesta del servicio SOAP")
|
|
# Enviar documento
|
|
try:
|
|
|
|
document_response = await remesa_rest_controller.post_document(
|
|
soap_response=soap_response,
|
|
organizacion=pedimento_data.get('organizacion'),
|
|
pedimento=pedimento_data.get('id'),
|
|
file_name=file_name,
|
|
document_type=5,
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error al enviar documento: {e}")
|
|
raise HTTPException(status_code=500, detail="Error al guardar documento")
|
|
|
|
# Extraer datos del XML
|
|
try:
|
|
remesas_data = remesa_xml_scraper.extract_remesas(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")
|
|
|
|
|
|
logger.info(f"Remesa procesada exitosamente: {pedimento_data.get('pedimento')}")
|
|
|
|
return create_service_response(
|
|
message="Remesa procesada exitosamente",
|
|
data={
|
|
"documento": document_response,
|
|
"xml_content": remesas_data
|
|
},
|
|
metadata={
|
|
"file_name": file_name,
|
|
"document_type": 3,
|
|
"pedimento_app": pedimento_data.get('pedimento_app'),
|
|
"organizacion": pedimento_data.get('organizacion')
|
|
}
|
|
)
|
|
|
|
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 post_remesa_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,
|
|
"coves_procesados": None,
|
|
"coves_error": None,
|
|
"xml_content": None
|
|
|
|
}
|
|
|
|
# Obtener datos del servicio web
|
|
try:
|
|
ws_data = await obtener_remesa(**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)}")
|
|
|
|
|
|
|
|
# Procesar COVEs (crítico)
|
|
try:
|
|
# print(xml_content.get('coves', []))
|
|
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)
|
|
|
|
|
|
logger.info("Procesamiento de pedimento completo finalizado")
|
|
|
|
# Crear respuesta estandarizada
|
|
return create_service_response(
|
|
success=True,
|
|
message="Procesamiento de remesa completado",
|
|
data=result,
|
|
warnings=[result["coves_error"]] if result.get("coves_error") else None,
|
|
metadata={
|
|
"total_coves_procesados": len(result.get("coves_procesados", [])) if result.get("coves_procesados") else 0
|
|
}
|
|
)
|
|
|
|
|
|
|
|
async def _process_coves_safely(kwargs: Dict[str, Any], xml_content) -> Optional[List[Dict[str, Any]]]:
|
|
"""
|
|
Procesa los COVEs de manera segura.
|
|
"""
|
|
coves = xml_content
|
|
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 _post_coves(pedimento_data: Dict[str, Any], coves: List[Dict[str, str]]) -> List[Dict[str, Any]]:
|
|
"""
|
|
Envía COVEs al sistema REST.
|
|
|
|
Args:
|
|
pedimento_data: Datos del pedimento
|
|
coves: Lista de diccionarios con datos de COVE (comprobanteVE, remesaAgente, remesaSA)
|
|
|
|
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:
|
|
# Extraer el número de COVE del diccionario
|
|
numero_cove = cove.get('comprobanteVE')
|
|
if not numero_cove:
|
|
logger.warning(f"COVE sin comprobanteVE encontrado: {cove}")
|
|
continue
|
|
|
|
document_data = {
|
|
'numero_cove': numero_cove,
|
|
'organizacion': pedimento_data.get('organizacion'),
|
|
'pedimento': pedimento_data.get('id')
|
|
}
|
|
|
|
try:
|
|
response = await remesa_rest_controller.post_cove(document_data)
|
|
if response:
|
|
responses.append(response)
|
|
logger.debug(f"COVE {numero_cove} procesado exitosamente")
|
|
except Exception as e:
|
|
error_msg = f"Error al procesar COVE {numero_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
|
|
|
|
|