Se agregaron los moduloes de api_v2
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
from http.client import HTTPException
|
||||
import base64
|
||||
import re
|
||||
from .controllers import acuse_vu_controller, acuse_rest_controller
|
||||
from utils.helpers import soap_error
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
soap_headers = {
|
||||
'Content-Type': 'text/xml; charset=utf-8',
|
||||
'SOAPAction': 'http://www.ventanillaunica.gob.mx/ventanilla/ConsultaAcusesService/consultarAcuseEdocument',# AcuseCove
|
||||
'Accept-Encoding': 'gzip,deflate',
|
||||
}
|
||||
|
||||
|
||||
async def obtener_acuse(**kwargs):
|
||||
soap_xml = acuse_vu_controller.generate_acuse_template(**kwargs)
|
||||
|
||||
response = await acuse_vu_controller.make_request_async(
|
||||
"ventanilla-acuses-HA/ConsultaAcusesServiceWS?wsdl",
|
||||
data=soap_xml,
|
||||
headers=soap_headers
|
||||
)
|
||||
|
||||
if response is None:
|
||||
raise Exception("No se obtuvo respuesta del servicio SOAP.")
|
||||
|
||||
if response.status_code != 200:
|
||||
raise Exception(f"Error en la solicitud SOAP: {response.status}")
|
||||
|
||||
if (response) and (not soap_error(response)):
|
||||
acuse_base64 = _extract_acuse_data(response.text)
|
||||
|
||||
if acuse_base64 is None:
|
||||
raise Exception("No se pudo extraer el acuse del documento de la respuesta SOAP.")
|
||||
|
||||
|
||||
pdf_bytes = _decode_acuse_base64_content(acuse_base64)
|
||||
|
||||
if not pdf_bytes:
|
||||
raise HTTPException(status_code=500, detail="No se pudo decodificar el documento del acuse")
|
||||
|
||||
# Validar que el PDF sea válido
|
||||
if not pdf_bytes.startswith(b'%PDF'):
|
||||
import logging
|
||||
logger = logging.getLogger("app.api")
|
||||
logger.warning("El contenido decodificado no parece ser un PDF válido")
|
||||
|
||||
|
||||
# Mejorar el nombre del archivo usando todos los datos relevantes
|
||||
pedimento = kwargs.get('pedimento', {})
|
||||
pedimento_num = pedimento.get('pedimento','')
|
||||
_file_name = _get_file_name(**kwargs)
|
||||
|
||||
# Validar que organización y pedimento no sean None
|
||||
organizacion = pedimento.get("organizacion", None)
|
||||
pedimento_id = pedimento.get("id", None)
|
||||
|
||||
rest_response = await acuse_rest_controller.post_document(
|
||||
binary_content=pdf_bytes,
|
||||
organizacion=organizacion,
|
||||
pedimento=pedimento_id,
|
||||
file_name=_file_name,
|
||||
document_type=4
|
||||
)
|
||||
|
||||
if rest_response is None:
|
||||
raise Exception("No se pudo enviar el acuse a la API interna.")
|
||||
if rest_response.get("id") is None:
|
||||
raise Exception("La respuesta de la API interna no contiene un ID válido.")
|
||||
|
||||
acuse_update_response = await change_edocument_status(
|
||||
edoc=kwargs.get('edoc'),
|
||||
status=True,
|
||||
pedimento=pedimento
|
||||
)
|
||||
return {
|
||||
"document_response": rest_response,
|
||||
"file_name": _file_name,
|
||||
"pedimento": pedimento_num,
|
||||
"acuse_update_response": acuse_update_response
|
||||
}
|
||||
|
||||
async def change_edocument_status(edoc: dict, status: bool, pedimento: dict):
|
||||
data = {
|
||||
"id": edoc.get("id"),
|
||||
"edocument_descargado": status,
|
||||
"numero_edocument": edoc.get("numero_edocument"),
|
||||
"pedimento": pedimento.get("id"),
|
||||
"organizacion": pedimento.get("organizacion"),
|
||||
}
|
||||
|
||||
response = await acuse_rest_controller.put_edocument(edocument_id=edoc.get("id"), data=data)
|
||||
|
||||
return response
|
||||
|
||||
def _decode_acuse_base64_content(base64_content): # Testeado
|
||||
"""
|
||||
Decodifica el contenido Base64 del acuse y limpia caracteres especiales.
|
||||
|
||||
Args:
|
||||
base64_content (str): Contenido codificado en Base64
|
||||
|
||||
Returns:
|
||||
bytes: Contenido decodificado o None si hay error
|
||||
"""
|
||||
try:
|
||||
# Limpiar el contenido Base64 de manera exhaustiva
|
||||
cleaned_content = base64_content
|
||||
|
||||
# Remover entidades HTML/XML como 
, 
, etc.
|
||||
cleaned_content = re.sub(r'&#x[0-9a-fA-F]+;', '', cleaned_content)
|
||||
cleaned_content = re.sub(r'&#[0-9]+;', '', cleaned_content)
|
||||
|
||||
# Remover espacios en blanco, saltos de línea, etc.
|
||||
cleaned_content = re.sub(r'[\s\n\r\t]', '', cleaned_content)
|
||||
|
||||
# Remover caracteres no válidos para Base64
|
||||
cleaned_content = re.sub(r'[^A-Za-z0-9+/=]', '', cleaned_content)
|
||||
|
||||
|
||||
# Agregar padding si es necesario
|
||||
missing_padding = len(cleaned_content) % 4
|
||||
if missing_padding:
|
||||
cleaned_content += '=' * (4 - missing_padding)
|
||||
|
||||
# Decodificar Base64
|
||||
decoded_content = base64.b64decode(cleaned_content)
|
||||
|
||||
return decoded_content
|
||||
|
||||
except Exception as e:
|
||||
|
||||
# Intentar con validación estricta deshabilitada
|
||||
try:
|
||||
decoded_content = base64.b64decode(cleaned_content, validate=False)
|
||||
return decoded_content
|
||||
except Exception as e2:
|
||||
return None
|
||||
|
||||
def _extract_acuse_data(soap_response_text: str) -> dict:
|
||||
try:
|
||||
# Primero, extraer la parte XML del contenido multipart
|
||||
xml_start = soap_response_text.find('<?xml')
|
||||
if xml_start == -1:
|
||||
return None
|
||||
|
||||
# Extraer solo la parte XML
|
||||
xml_content = soap_response_text[xml_start:]
|
||||
|
||||
# Si hay más contenido multipart después, cortarlo
|
||||
boundary_end = xml_content.find('--uuid:')
|
||||
if boundary_end != -1:
|
||||
xml_content = xml_content[:boundary_end]
|
||||
|
||||
# Parsear el XML
|
||||
root = ET.fromstring(xml_content.strip())
|
||||
|
||||
# Buscar el elemento acuseDocumento con namespaces
|
||||
namespaces = {
|
||||
'S': 'http://schemas.xmlsoap.org/soap/envelope/',
|
||||
'ns3': 'http://www.ventanillaunica.gob.mx/ws/consulta/acuses/'
|
||||
}
|
||||
|
||||
# Buscar el elemento acuseDocumento
|
||||
acuse_elemento = root.find('.//ns3:responseConsultaAcuses/acuseDocumento', namespaces)
|
||||
|
||||
if acuse_elemento is None:
|
||||
# Intentar sin namespace
|
||||
acuse_elemento = root.find('.//acuseDocumento')
|
||||
|
||||
if acuse_elemento is not None and acuse_elemento.text:
|
||||
return acuse_elemento.text.strip()
|
||||
else:
|
||||
return None
|
||||
|
||||
except ET.ParseError as e:
|
||||
return None
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def _get_file_name(**kwargs) -> dict:
|
||||
pedimento = kwargs.get('pedimento', {})
|
||||
pedimento_app = pedimento.get('pedimento_app', 'N/A')
|
||||
idEdocument = kwargs['edoc'].get('numero_edocument', 'N/A')
|
||||
_file_name = f"vu_AC_{pedimento_app}_{idEdocument}.pdf"
|
||||
return _file_name
|
||||
|
||||
|
||||
Reference in New Issue
Block a user