se estan creando el registro de las tareas sin problemas
This commit is contained in:
@@ -1,68 +1,22 @@
|
||||
from http.client import HTTPException
|
||||
import base64
|
||||
import re
|
||||
import logging
|
||||
import os
|
||||
from typing import Any, Dict, Optional
|
||||
import xml.etree.ElementTree as ET
|
||||
from fastapi import HTTPException
|
||||
|
||||
from utils.helpers import soap_error
|
||||
from .controllers import edocs_rest_controller, edocs_vu_controller
|
||||
from ..common import create_service_response, create_error_response
|
||||
|
||||
# Logger para el módulo
|
||||
logger = logging.getLogger("app.api")
|
||||
|
||||
|
||||
|
||||
# --- FUNCIONES AUXILIARES ---
|
||||
|
||||
def _decode_base64_content(base64_content):
|
||||
try:
|
||||
cleaned_content = re.sub(r'&#x[0-9a-fA-F]+;', '', base64_content)
|
||||
cleaned_content = re.sub(r'&#[0-9]+;', '', cleaned_content)
|
||||
cleaned_content = re.sub(r'[\s\n\r\t]', '', cleaned_content)
|
||||
cleaned_content = re.sub(r'[^A-Za-z0-9+/=]', '', cleaned_content)
|
||||
|
||||
missing_padding = len(cleaned_content) % 4
|
||||
if missing_padding:
|
||||
cleaned_content += '=' * (4 - missing_padding)
|
||||
|
||||
return base64.b64decode(cleaned_content)
|
||||
except Exception as e:
|
||||
logger.error(f"Error al decodificar Base64: {e}")
|
||||
try:
|
||||
return base64.b64decode(cleaned_content, validate=False)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def _extract_edoc_data(soap_response_text: str) -> str:
|
||||
try:
|
||||
xml_start = soap_response_text.find('<?xml')
|
||||
if xml_start == -1:
|
||||
return None
|
||||
|
||||
xml_content = soap_response_text[xml_start:]
|
||||
boundary_end = xml_content.find('--uuid:')
|
||||
if boundary_end != -1:
|
||||
xml_content = xml_content[:boundary_end]
|
||||
|
||||
root = ET.fromstring(xml_content.strip())
|
||||
|
||||
namespaces = {
|
||||
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'ns3': 'http://www.ventanillaunica.gob.mx/ws/consulta/edocs/'
|
||||
}
|
||||
|
||||
edoc_elemento = root.find('.//ns3:responseConsultaEdocumento/documentoBase64', namespaces)
|
||||
if edoc_elemento is None:
|
||||
edoc_elemento = root.find('.//documentoBase64')
|
||||
|
||||
return edoc_elemento.text.strip() if edoc_elemento is not None and edoc_elemento.text else None
|
||||
except ET.ParseError as e:
|
||||
logger.error(f"Error parseando la respuesta SOAP para Edoc: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
logger.error(f"Error general en extracción de datos Edoc: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def _get_file_name(**kwargs) -> str:
|
||||
pedimento = kwargs.get('pedimento', {})
|
||||
@@ -89,25 +43,102 @@ async def obtener_edoc(**kwargs):
|
||||
data=soap_xml,
|
||||
headers=soap_headers
|
||||
)
|
||||
# Validar respuesta del servicio SOAP
|
||||
if response is None:
|
||||
raise Exception("No se obtuvo respuesta del servicio SOAP.")
|
||||
logger.error("No se obtuvo respuesta del servicio SOAP")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al contactar el servicio SOAP",
|
||||
errors=["No se obtuvo respuesta del servicio"],
|
||||
metadata={
|
||||
"edoc_number": numero_documento,
|
||||
"username": usuario
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Error en la solicitud SOAP: {response.status_code}")
|
||||
logger.error(f"Error en la solicitud SOAP: {response.status_code}")
|
||||
raise HTTPException(
|
||||
status_code=response.status_code,
|
||||
detail=create_error_response(
|
||||
message="Error en la solicitud SOAP",
|
||||
errors=[f"Código de estado: {response.status_code}"],
|
||||
data={"soap_response": response.text[:500]},
|
||||
metadata={
|
||||
"status_code": response.status_code,
|
||||
"edoc_number": numero_documento
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if soap_error(response):
|
||||
raise Exception("Respuesta SOAP contiene error de VUCEM.")
|
||||
logger.error("Respuesta SOAP contiene error de VUCEM")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error en la respuesta del servicio SOAP",
|
||||
errors=["La respuesta contiene un error de VUCEM"],
|
||||
data={"soap_response": response.text[:500]},
|
||||
metadata={"edoc_number": numero_documento}
|
||||
)
|
||||
)
|
||||
|
||||
try:
|
||||
edoc_base64 = extract_pdf_bytes_from_xml_content(response.text)
|
||||
except ValueError as ve:
|
||||
logger.error(f"Error extrayendo contenido del XML: {ve}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al procesar la respuesta SOAP",
|
||||
errors=[str(ve)],
|
||||
metadata={"edoc_number": numero_documento}
|
||||
)
|
||||
)
|
||||
|
||||
edoc_base64 = extract_pdf_bytes_from_xml_content(response.text)
|
||||
if edoc_base64 is None:
|
||||
raise Exception("No se pudo extraer el documento de la respuesta SOAP.")
|
||||
logger.error("No se pudo extraer el documento de la respuesta SOAP")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al extraer el documento",
|
||||
errors=["No se pudo encontrar el documento en la respuesta SOAP"],
|
||||
metadata={"edoc_number": numero_documento}
|
||||
)
|
||||
)
|
||||
|
||||
pdf_bytes = edoc_base64['pdf_bytes']
|
||||
if not pdf_bytes:
|
||||
raise HTTPException(status_code=500, detail="No se pudo decodificar el documento")
|
||||
logger.error("No se pudo decodificar el documento PDF")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al decodificar el documento",
|
||||
errors=["El contenido del documento está vacío o es inválido"],
|
||||
metadata={
|
||||
"edoc_number": numero_documento,
|
||||
"has_cadena_original": bool(edoc_base64.get('cadena_original')),
|
||||
"has_sello_digital": bool(edoc_base64.get('sello_digital'))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
# Validar formato PDF
|
||||
if not pdf_bytes.startswith(b'%PDF'):
|
||||
logger.warning("El contenido decodificado no parece ser un PDF válido")
|
||||
logger.error("El contenido decodificado no es un PDF válido")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="El documento recibido no es un PDF válido",
|
||||
errors=["El contenido no tiene el formato PDF esperado"],
|
||||
metadata={
|
||||
"edoc_number": numero_documento,
|
||||
"content_start": str(pdf_bytes[:20])
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
pedimento = kwargs.get('pedimento', {})
|
||||
numero_documento = kwargs['edoc'].get('numero_edocument', '')
|
||||
@@ -116,12 +147,8 @@ async def obtener_edoc(**kwargs):
|
||||
organizacion = pedimento.get("organizacion", None)
|
||||
pedimento_id = pedimento.get("id", None)
|
||||
|
||||
try:
|
||||
with open(_file_name, "wb") as f:
|
||||
f.write(pdf_bytes)
|
||||
logger.info(f"PDF guardado localmente en {_file_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error guardando el PDF localmente: {e}")
|
||||
# No guardaremos el archivo localmente por seguridad
|
||||
logger.debug(f"Procesando documento {numero_documento} para pedimento {pedimento_id}")
|
||||
|
||||
rest_response = await edocs_rest_controller.post_document(
|
||||
binary_content=pdf_bytes,
|
||||
@@ -132,26 +159,61 @@ async def obtener_edoc(**kwargs):
|
||||
)
|
||||
|
||||
if rest_response is None:
|
||||
raise Exception("No se pudo enviar el documento a la API interna.")
|
||||
logger.error("Error al enviar el documento a la API interna")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al guardar el documento en el sistema",
|
||||
errors=["No se pudo enviar el documento a la API interna"],
|
||||
metadata={
|
||||
"file_name": _file_name,
|
||||
"edoc_number": numero_documento
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
if rest_response.get("id") is None:
|
||||
raise Exception("La respuesta de la API interna no contiene un ID válido.")
|
||||
logger.error("Respuesta de API interna sin ID válido")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=create_error_response(
|
||||
message="Error al procesar la respuesta del sistema",
|
||||
errors=["La respuesta de la API no contiene un ID válido"],
|
||||
data={"api_response": rest_response}
|
||||
)
|
||||
)
|
||||
|
||||
logger.info("Documento enviado, actualizando status de Edoc")
|
||||
|
||||
edoc_status_response = await change_edocument_status(
|
||||
edoc=doc,
|
||||
status=True,
|
||||
pedimento=pedimento
|
||||
)
|
||||
|
||||
print(edoc_status_response)
|
||||
try:
|
||||
edoc_status_response = await change_edocument_status(
|
||||
edoc=doc,
|
||||
status=True,
|
||||
pedimento=pedimento
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Error al actualizar estado del documento: {e}")
|
||||
# No fallamos aquí porque el documento ya se guardó exitosamente
|
||||
|
||||
return {
|
||||
"document_response": rest_response,
|
||||
"file_name": _file_name,
|
||||
"numero_documento": numero_documento,
|
||||
"edoc_update_response": edoc_status_response if edoc_status_response else None
|
||||
}
|
||||
logger.info(f"E-document {numero_documento} procesado exitosamente")
|
||||
|
||||
return create_service_response(
|
||||
message=f"E-document {numero_documento} procesado exitosamente",
|
||||
data={
|
||||
"document_response": rest_response,
|
||||
"file_name": _file_name,
|
||||
"numero_documento": numero_documento,
|
||||
"edoc_update_response": edoc_status_response if edoc_status_response else None
|
||||
},
|
||||
metadata={
|
||||
"document_type": 5,
|
||||
"pedimento_app": pedimento.get('pedimento_app'),
|
||||
"organizacion": organizacion,
|
||||
"content_type": "application/pdf",
|
||||
"has_cadena_original": bool(edoc_base64.get('cadena_original')),
|
||||
"has_sello_digital": bool(edoc_base64.get('sello_digital'))
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def change_edocument_status(edoc: dict, status: bool, pedimento: dict):
|
||||
@@ -168,8 +230,6 @@ async def change_edocument_status(edoc: dict, status: bool, pedimento: dict):
|
||||
return response
|
||||
|
||||
|
||||
|
||||
|
||||
def extract_pdf_bytes_from_xml_content(xml_content: str):
|
||||
"""
|
||||
Extrae el PDF y metadatos desde un string XML.
|
||||
|
||||
Reference in New Issue
Block a user