Files
descarga_factura_transporte/tools/procesar_xmls_prueba.py
T
GeorgeandClaude Sonnet 5.5 1d6d869111 se reorganiza tests/ y se agrega suite pytest
Los scripts manuales pasan a tools/ y los correos de ejemplo a
tests/fixtures/. Suite de 95 pruebas: caracterización de la extracción sobre
los 46 correos (resultados esperados en tests/golden/, fuera de la carpeta
que descargar_correos_prueba borra), unitarias de draft_sap, notificaciones,
documentos, adjuntos y config_validator, y flujo completo de
_procesar_un_correo con SAP/HANA/Outlook simulados. pytest como dependencia
dev y configuración en pyproject.toml.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 22:03:38 -05:00

118 lines
5.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import os
import sys
import json
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from sunat_schema import extraer_datos_xml
def renombrar_xml(ruta_actual: str, data: dict, carpeta: str) -> str | None:
"""Renombra el XML a {prefijo}{ruc}-{tipo}-{serie}-{numero}.xml y retorna la nueva ruta.
Si es un CDR (ApplicationResponse), el prefijo es 'CDR-'."""
if not data:
return None
prefijo = "CDR-" if data.get("es_cdr") else ""
nombre = f"{prefijo}{data.get('ruc_emisor', '')}-{data.get('tipo', '')}-{data.get('serie', '')}-{data.get('numero', '')}.xml"
destino = os.path.join(carpeta, nombre)
if destino != ruta_actual:
if os.path.exists(destino):
os.remove(destino)
os.rename(ruta_actual, destino)
return destino
CARPETA_BASE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "tests", "fixtures", "correos_prueba")
def procesar_carpetas():
carpetas = sorted(
[d for d in os.listdir(CARPETA_BASE) if os.path.isdir(os.path.join(CARPETA_BASE, d))]
)
total = 0
for carpeta in carpetas:
ruta_carpeta = os.path.join(CARPETA_BASE, carpeta)
archivos_xml = sorted(
os.path.join(ruta_carpeta, f) for f in os.listdir(ruta_carpeta)
if f.lower().endswith(".xml") and os.path.isfile(os.path.join(ruta_carpeta, f))
)
if not archivos_xml:
continue
correlativo = carpeta.split("_")[0]
documentos = []
for xml_path in archivos_xml:
print(f"📄 {carpeta}/{os.path.basename(xml_path)}")
data = extraer_datos_xml(xml_path)
if data:
ruta_xml = renombrar_xml(xml_path, data, ruta_carpeta)
data["ruta_xml"] = ruta_xml or xml_path
data["ruta_pdf"] = None
if data.get("es_cdr"):
print(f" ├── ℹ️ {data.get('serie','?')}-{data.get('numero','?')} (CDR) — omitido del resultado")
continue
documentos.append(data)
print(f" ├── ✅ {data.get('serie','?')}-{data.get('numero','?')} ({data.get('tipo_descripcion','?')})")
else:
print(f" ├── ℹ️ No es factura 01 ni guía 31")
if documentos:
# Post-procesamiento
# 1. Distribuir documentos_referencia (tipo 09 y 31) a cada línea
for doc in documentos:
if doc.get("tipo") != "01":
continue
refs_09 = [r for r in doc.get("documentos_referencia", []) if r.get("tipo") == "09"]
refs_31 = [r for r in doc.get("documentos_referencia", []) if r.get("tipo") == "31"]
for i, linea in enumerate(doc.get("lineas", [])):
if linea.get("guias_remision"):
continue
if i < len(refs_09):
es_ultima = i == len(doc["lineas"]) - 1
if es_ultima:
linea["guias_remision"] = [dict(r) for r in refs_09[i:]]
else:
linea["guias_remision"] = [dict(refs_09[i])]
if not linea.get("guia_transportista") and i < len(refs_31):
linea["guia_transportista"] = dict(refs_31[i])
# 2. Resolver GREs desde guías de transporte (tipo 31 → tipo 09)
guia_lookup = {}
for doc in documentos:
if doc.get("tipo") in ("31", "09"):
guia_lookup[(doc["tipo"], doc["serie"], doc["numero"])] = doc
for doc in documentos:
if doc.get("tipo") != "01":
continue
for ref in doc.get("documentos_referencia", []):
if ref["tipo"] == "31":
guia_doc = guia_lookup.get(("31", ref["serie"], ref["numero"]))
if guia_doc:
gre_list = [g for g in guia_doc.get("documentos_referencia", []) if g.get("tipo") == "09"]
if gre_list:
for i, linea in enumerate(doc.get("lineas", [])):
if not linea.get("guias_remision"):
es_ultima = i == len(doc["lineas"]) - 1
if es_ultima:
linea["guias_remision"] = gre_list[i:]
elif i < len(gre_list):
linea["guias_remision"] = [gre_list[i]]
if not linea.get("guia_transportista"):
linea["guia_transportista"] = dict(ref)
ruta_json = os.path.join(ruta_carpeta, f"xml_resultado_{correlativo}.json")
with open(ruta_json, "w", encoding="utf-8") as f:
json.dump(documentos, f, ensure_ascii=False, indent=2)
print(f" └── 💾 Guardado: xml_resultado_{correlativo}.json ({len(documentos)} doc(s))")
total += len(documentos)
print(f"\n{'='*60}")
print(f"📊 Total documentos XML procesados: {total}")
if __name__ == "__main__":
procesar_carpetas()