diff --git a/examples/test_extract_file.py b/examples/test_extract_file.py
new file mode 100644
index 0000000..e0978f5
--- /dev/null
+++ b/examples/test_extract_file.py
@@ -0,0 +1,13 @@
+import os
+from utils.peticiones import extract_pdf_bytes_from_xml
+
+xml_path = os.path.abspath("./test.xml")
+
+result = extract_pdf_bytes_from_xml(xml_path)
+
+if result and result["pdf_bytes"]:
+ with open("output_test.pdf", "wb") as f:
+ f.write(result["pdf_bytes"])
+ print("PDF extraído y guardado como output_test.pdf")
+else:
+ print("No se pudo extraer el PDF del XML.")
diff --git a/main.py b/main.py
index 8bce169..79af994 100644
--- a/main.py
+++ b/main.py
@@ -5,40 +5,40 @@ from api.api_v1.api import api_router
from fastapi.middleware.cors import CORSMiddleware
# Configuración inicial del logging (debe estar al inicio del archivo)
-logging.config.dictConfig({
- "version": 1,
- "disable_existing_loggers": False,
- "formatters": {
- "default": {
- "()": "uvicorn.logging.DefaultFormatter",
- "fmt": "%(levelprefix)s %(asctime)s | %(name)s | %(message)s",
- "datefmt": "%Y-%m-%d %H:%M:%S",
- "use_colors": True,
- },
- "access": {
- "()": "uvicorn.logging.AccessFormatter",
- "fmt": '%(levelprefix)s %(asctime)s | %(client_addr)s | "%(request_line)s" %(status_code)s',
- "datefmt": "%Y-%m-%d %H:%M:%S",
- },
- },
- "handlers": {
- "default": {
- "formatter": "default",
- "class": "logging.StreamHandler",
- "stream": "ext://sys.stdout",
- },
- "access": {
- "formatter": "access",
- "class": "logging.StreamHandler",
- "stream": "ext://sys.stdout",
- },
- },
- "loggers": {
- "": {"handlers": ["default"], "level": "DEBUG"},
- "uvicorn.error": {"level": "DEBUG"},
- "uvicorn.access": {"handlers": ["access"], "level": "DEBUG", "propagate": False},
- },
-})
+# logging.config.dictConfig({
+# "version": 1,
+# "disable_existing_loggers": False,
+# "formatters": {
+# "default": {
+# "()": "uvicorn.logging.DefaultFormatter",
+# "fmt": "%(levelprefix)s %(asctime)s | %(name)s | %(message)s",
+# "datefmt": "%Y-%m-%d %H:%M:%S",
+# "use_colors": True,
+# },
+# "access": {
+# "()": "uvicorn.logging.AccessFormatter",
+# "fmt": '%(levelprefix)s %(asctime)s | %(client_addr)s | "%(request_line)s" %(status_code)s',
+# "datefmt": "%Y-%m-%d %H:%M:%S",
+# },
+# },
+# "handlers": {
+# "default": {
+# "formatter": "default",
+# "class": "logging.StreamHandler",
+# "stream": "ext://sys.stdout",
+# },
+# "access": {
+# "formatter": "access",
+# "class": "logging.StreamHandler",
+# "stream": "ext://sys.stdout",
+# },
+# },
+# "loggers": {
+# "": {"handlers": ["default"], "level": "DEBUG"},
+# "uvicorn.error": {"level": "DEBUG"},
+# "uvicorn.access": {"handlers": ["access"], "level": "DEBUG", "propagate": False},
+# },
+# })
def create_application() -> FastAPI:
"""Función factory para crear la aplicación FastAPI"""
diff --git a/test.xml b/test.xml
deleted file mode 100644
index 54335bb..0000000
--- a/test.xml
+++ /dev/null
@@ -1,439 +0,0 @@
-
-
-
-
-
- 2025-07-10T14:24:04Z
- 2025-07-10T14:25:04Z
-
-
-
-
-
- false
- 21277177344
-
- 2001238
-
-
- 1
- Importacion
-
-
- IN
- IMPORTACION TEMPORAL DE INSUMOS POR IMMEX
-
-
- 9
- INTERIOR DEL PAIS
-
-
- 230
- NOGALES, NOGALES, SONORA.
-
- 20.76130
- 6745.682
-
- 7
- CARRETERO
-
-
- 7
- CARRETERO
-
-
- 7
- CARRETERO
-
- GUMM710831HSRZRG08
- GLG1502247K9
- 0.00
- 1642523.00
- 1642523.00
-
-
-
- 230
- NOGALES, NOGALES, SONORA.
-
-
- 230
- NOGALES, NOGALES, SONORA.
-
-
- IN
- IMPORTACION TEMPORAL DE INSUMOS POR IMMEX
-
- 2022-07-25-06:00
- 2009506
- 1653
- 2022-07-15-06:00
-
-
- MTK861014317
- MAQUILAS TETA KAWI S.A. DE C.V.
-
- CARRETERA INTERNACIONAL GUADALAJARA-NOGALES
- KM 1969
- Empalme
- 85340
-
- 0.00
- 0.00
- 0.00
- 0.00
-
- 230
- NOGALES, NOGALES, SONORA.
-
-
- 2022-07-05-06:00
-
- 1
- FECHA DE ENTRADA A TERRITORIO NAL.
-
-
-
- 2022-07-15-06:00
-
- 2
- FECHA DE PAGO DE LAS CONTRIBUCIONES
-
-
- 1412.00
- 0
- 1412.00
-
- MEX
- MEXICO (ESTADOS UNIDOS MEXICANOS)
-
-
-
-
- 15
- PREVALIDAAAA
-
-
- 2
- ESPECIFICO
-
- 240.0000000000
-
- 0
- EFECTIVO
-
- 240.00
-
-
-
- 23
- IVA PREV
-
-
- 1
- PORCENTUAL
-
- 16.0000000000
-
- 0
- EFECTIVO
-
- 38.00
-
-
-
- 1
- DTA
-
-
- 4
- ESPECIFICO (CUOTA FIJA) DTA
-
- 378.0000000000
-
- 0
- EFECTIVO
-
- 1134.00
-
-
- 84-401607200
- LIBRA GUAYMAS LLC
- 0.000000
- 0.00
-
-
- 84-401607200
- LIBRA GUAYMAS LLC
- 0.000000
- 0.00
-
-
- 84-401607200
- LIBRA GUAYMAS LLC
- 0.000000
- 0.00
-
-
- COVE2258M9IT4
-
- FCA
- FRANCO TRANSPORTISTA (... LUGAR DESIGNADO)
-
- 0.00
- 0.000000
- 84-401607200
- LIBRA GUAYMAS LLC
-
-
- COVE2257S9033
-
- FCA
- FRANCO TRANSPORTISTA (... LUGAR DESIGNADO)
-
- 0.00
- 0.000000
- 84-401607200
- LIBRA GUAYMAS LLC
-
-
- COVE2257PY1Z4
-
- FCA
- FRANCO TRANSPORTISTA (... LUGAR DESIGNADO)
-
- 0.00
- 0.000000
- 84-401607200
- LIBRA GUAYMAS LLC
-
-
-
-
- PC
- PEDIMENTO CONSOLIDADO
-
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0170220NCKKN2
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0433220889CP2
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0436220ER86M4
-
-
-
- SO
- SOCIO COMERCIAL CERTIFICADO
-
- AA
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0436220ER86H4
-
-
-
- CI
- CERTIFICACION EN MATERIA DE IVA E IEPS
-
- AAA
-
-
-
- IM
- AUTORIZACION DE EMPRESA CON PROGRAMA IMMEX
-
- 45242006
-
-
-
- PP
- PROGRAMAS DE PROMOCIÓN SECTORIAL.
-
- 20011635
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0170220NG6SJ4
-
-
-
- RC
- REMESAS DE CONSOLIDADO
-
- 1-3
-
-
-
- ED
- E_DOCUMENT DOCUMENTO DIGITALIZADO
-
- 0436220ESLMS1
-
-
-
- IC
- IMPORTADOR CERTIFICADO
-
- O
-
-
- PEDIMENTO CONSOLIDADO DE IMPORTACION DE CONFORMIDAD CON LOS
- ARTICULOS 37, 37-A DE LA LEY ADUANERA Y REGLA DE COMERCIO EXTERIOR 1.9.19.,
- CORRESPONDIENTE A LA SEMANA DEL 04 DE JULIO AL 10 DE JULIO DEL 2022. DE
- CONFORMIDAD CON EL ARTICULO 89DE LA LEY ADUANERA SE REALIZA RECTIFICACION DE
- PEDIMENTO PARA MODIFICAR LO SIGUIENTE: SE RECTIFICA PEDIMENTO EN: VALOR
- COMERCIAL DICE: 73,817.52 DEBE DECIR: 79,114.63 PESO BRUTO DICE: 6695.390 DEBE
- DECIR: 6745.682 SE RECTIFICA COVE DE FACTURA LIBRA7902RM DICE: COVE2257X6DZ1
- DEBE DECIR: COVE2258M9IT4 SE CORRIGE PARTIDA # 81 EN CANTIDAD Y UNIDAD DE MEDIDA
- SE AGREGAN PARTIDAS # 93, 94, 95 y 96. SE DIGITALIZA FACTURA E DOCUMENT
- 0170220NG6SJ4 SE DIGITALIZA REGLA 8va E DOCUMENT 0436220ESLMS1 - - Relacion de
- facturas - - FACTR: LIBRA GUAYMAS
- LLC,84-401607200,LIBRA7896RM,05-07-2022,COVE2257PY1Z4,USD,26,664.250 FACTR:
- LIBRA GUAYMAS
- LLC,84-401607200,LIBRA7898RM,06-07-2022,COVE2257S9033,USD,5,422.700 FACTR: LIBRA
- GUAYMAS LLC,84-401607200,LIBRA7902RM,08-07-2022,COVE2258M9IT4,USD,47,027.680
- 96
- 56
- 7
- 69
- 43
- 95
- 64
- 70
- 8
- 65
- 16
- 79
- 20
- 48
- 26
- 18
- 27
- 54
- 34
- 93
- 44
- 17
- 90
- 37
- 9
- 11
- 51
- 73
- 36
- 66
- 63
- 40
- 88
- 19
- 59
- 15
- 2
- 94
- 68
- 78
- 32
- 39
- 89
- 62
- 4
- 47
- 74
- 41
- 80
- 6
- 42
- 28
- 92
- 49
- 12
- 13
- 84
- 10
- 31
- 87
- 50
- 76
- 22
- 30
- 53
- 71
- 38
- 3
- 33
- 45
- 23
- 25
- 21
- 67
- 85
- 14
- 46
- 29
- 35
- 91
- 24
- 72
- 82
- 61
- 86
- 83
- 77
- 75
- 58
- 81
- 55
- 57
- 5
- 52
- 60
- 1
-
-
- DTA
- 1
-
- 364.00
-
- 0
- EFECTIVO
-
-
-
-
-
-
\ No newline at end of file
diff --git a/utils/peticiones.py b/utils/peticiones.py
index cb20a33..d5310d0 100644
--- a/utils/peticiones.py
+++ b/utils/peticiones.py
@@ -129,36 +129,54 @@ def extract_acuse_documento_from_soap(soap_response_text): # Testeado
logger.error(f"Error extrayendo acuseDocumento: {e}")
return None
+
def extract_pdf_bytes_from_xml(xml_path):
- tree = ET.parse(xml_path)
- root = tree.getroot()
- # Busca el tag (ajusta el namespace si es necesario)
+ """
+ Igual que extract_pdf_bytes_from_xml_content pero recibe una ruta de archivo.
+ """
+ with open(xml_path, 'r', encoding='utf-8') as f:
+ xml_content = f.read()
+ return extract_pdf_bytes_from_xml_content(xml_content)
+
+def extract_pdf_bytes_from_xml_content(xml_content: str):
+ """
+ Extrae el PDF y metadatos desde un string XML.
+ """
+ root = ET.fromstring(xml_content)
file_elem = root.find('.//File')
- if file_elem is not None and file_elem.text:
- # Limpia el contenido base64
+ if file_elem is None:
+ for elem in root.iter():
+ if elem.tag.endswith('File') and elem.text:
+ file_elem = elem
+ break
+ if file_elem is not None and file_elem.text and file_elem.text.strip():
base64_data = file_elem.text.strip().replace('\n', '').replace('\r', '')
pdf_bytes = base64.b64decode(base64_data)
cadena_original = None
sello_digital = None
-
- # Buscar CadenaOriginal y SelloDigital en el XML
cadena_elem = root.find('.//CadenaOriginal')
+ if cadena_elem is None:
+ for elem in root.iter():
+ if elem.tag.endswith('CadenaOriginal') and elem.text:
+ cadena_elem = elem
+ break
if cadena_elem is not None and cadena_elem.text:
cadena_original = cadena_elem.text.strip()
-
sello_elem = root.find('.//SelloDigital')
+ if sello_elem is None:
+ for elem in root.iter():
+ if elem.tag.endswith('SelloDigital') and elem.text:
+ sello_elem = elem
+ break
if sello_elem is not None and sello_elem.text:
sello_digital = sello_elem.text.strip()
-
return {
"pdf_bytes": pdf_bytes,
"cadena_original": cadena_original,
"sello_digital": sello_digital
}
- return pdf_bytes
-
else:
- raise ValueError("No se encontró el tag con contenido válido.")
+ raise ValueError("No se encontró el tag con contenido válido. Verifique que el XML contiene el tag con datos base64.")
def decode_acuse_base64_content(base64_content): # Testeado
"""
@@ -846,32 +864,20 @@ async def get_soap_edocument(credenciales, response_service, soap_controller, ed
# Extraer contenido Base64 del acuse
logger.info("Extrayendo documento binario del edocument...")
- response = extract_pdf_bytes_from_xml(soap_response.text)
+ response = extract_pdf_bytes_from_xml_content(soap_response.text)
pdf_bytes = response.get('pdf_bytes')
# cadena_original = response.get('cadena_original')
# sello_digital = response.get('sello_digital')
- if not acuse_base64:
- logger.error("No se pudo extraer el contenido del acuseDocumento")
- raise HTTPException(status_code=500, detail="No se pudo extraer el documento del acuse")
-
- # Decodificar contenido Base64
-
- response_edoc = rest_controller.put_edocument(edocument_id=ide, data={
- "numero_edocument": edocument['numero_edocument'],
- "pedimento": response_service['pedimento'],
- # "cadena_original": cadena_original,
- # "sello_digital": sello_digital
- })
if not pdf_bytes:
- logger.error("No se pudo decodificar el contenido Base64 del acuse")
- raise HTTPException(status_code=500, detail="No se pudo decodificar el documento del acuse")
-
+ logger.error("No se pudo decodificar el contenido Base64 del documento e-document")
+ raise HTTPException(status_code=500, detail="No se pudo decodificar el documento del e-document")
+
# Verificar que es un PDF válido
if not pdf_bytes.startswith(b'%PDF'):
logger.warning("El contenido decodificado no parece ser un PDF válido")
# Continuar de todos modos, podría ser otro tipo de documento
-
+
# Generar nombre del archivo
remesas = 1 if response_service['pedimento'].get('remesas', 0) else 0
patente = response_service['pedimento'].get('patente', 'N/A')
@@ -880,7 +886,7 @@ async def get_soap_edocument(credenciales, response_service, soap_controller, ed
tipo_operacion = response_service['pedimento'].get('tipo_operacion', 'N/A')
pedimento = response_service['pedimento'].get('pedimento', 'N/A')
_file_name = f"vu_EDC_{remesas}{no_partidas}{tipo_operacion}_{aduana}_{patente}_{pedimento}_{idx}.pdf"
-
+
# Enviar el documento PDF usando binary_content
logger.info(f"Enviando documento PDF: {_file_name} ({len(pdf_bytes)} bytes)")
document_response = await rest_controller.post_document(
@@ -904,7 +910,7 @@ async def get_soap_edocument(credenciales, response_service, soap_controller, ed
logger.error(f"Error inesperado en get_acuse: {e}")
import traceback
logger.error(f"Traceback: {traceback.format_exc()}")
- raise HTTPException(status_code=500, detail=f"Error interno al procesar acuse: {str(e)}")
+ raise HTTPException(status_code=500, detail=f"Error interno al procesar acuse")
async def get_soap_cove(credenciales, response_service, soap_controller, cove, idx):
"""