- sapb1_manager.buscar_factura_existente busca la factura (proveedor, tipo, serie, número) en facturas de compra no anuladas y en drafts; si existe no se crea otro draft y se responde "ya está registrada" sin pisar el registro de una aceptación anterior. - SapNoDisponible (subclase de ConnectionError) distingue una caída (timeout, sin conexión, HTTP 5xx) de un rechazo normal de SAP (HTTP 4xx). Una caída de Service Layer con HANA sin resultados ya no se lee como "guía no existe". - Con SAP o HANA caídos se avisa una sola vez al proveedor con la plantilla "En cola" y el correo se reintenta en los ciclos siguientes (hasta 24), sin repetir avisos; al agotarse se avisa al equipo. - La lógica por factura pasa a _procesar_factura; lo ya resuelto dentro de un correo no se repite al reintentarlo. - seguimiento: columna intentos (con migración), registrar_intento y el estado de notificación en_espera. - database_utilities.DB_NAME pasa a ser absoluto (junto al código). Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
descarga_factura_transporte
Demonio que descarga las facturas de transporte (PDF/XML SUNAT) recibidas en un buzón de Office 365, valida sus precios contra SAP Business One y crea el borrador (Draft) de la factura de compra. Al terminar, notifica el resultado por correo al remitente.
Qué hace con cada correo
Bandeja de entrada (Microsoft Graph)
→ descarga adjuntos, descomprime ZIP, se queda con PDF/XML
→ extrae datos de PDF y XML y asigna las guías de remisión por línea
→ valida precios de cada guía contra SAP (Service Layer, con fallback a HANA)
→ crea el Draft en SAP B1 si todos los precios coinciden
→ responde a quien envió el correo con la plantilla de aceptado o rechazado
(por defecto en modo prueba: la respuesta va al equipo; ver docs/respuesta_proveedor.md)
Cada correo se registra en una base SQLite (emails.db) y no se vuelve a procesar. Detalle del flujo en docs/pipeline.md.
Requisitos
- Python 3.11 o superior.
- Acceso a: Microsoft Graph (app registrada en Azure AD), SAP B1 Service Layer y SAP HANA.
Instalación
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env # y completar los valores
El .env nunca se sube a git. Todas las variables están documentadas en .env.example. Al arrancar, config_validator termina con un error claro si falta alguna obligatoria.
Uso
python main.py # demonio; consulta los últimos 2 días (--dias 2)
python main.py --dias 5 # ventana de búsqueda de 5 días
python tools/consulta_rapida.py --set <nombre> # reprocesar correos por ID (sets en tools/ids_prueba.json)
El demonio trabaja por bloques horarios (cada 1, 5, 30 o 60 minutos según la hora) y duerme fuera de ellos. Los bloques están en HORARIOS de main.py y se explican en docs/main.md.
Pruebas
pip install -e ".[dev]" # instala pytest
pytest # ~95 pruebas, unos 3 segundos; no tocan SAP, HANA ni Outlook
- Extracción (
tests/test_extraccion_correos.py): corre la extracción real sobre cada correo detests/fixtures/correos_prueba/y la compara contests/golden/<caso>.json. Esos resultados esperados fijan el comportamiento actual; no prueban que sea correcto. Si cambias la extracción a propósito, revisa el diff y regenéralos conUPDATE_GOLDEN=1 pytest tests/test_extraccion_correos.py. - Unitarias: validación de precios, construcción del draft, notificaciones, guías, copia a red, filtrado de adjuntos y validación del
.env. - Flujo completo (
tests/test_pipeline_flujo.py):_procesar_un_correocon SAP, HANA, Outlook y la BD simulados.
Los scripts de tools/ (procesar_pdfs_prueba.py, procesar_xmls_prueba.py, etc.) son anteriores a la suite: escriben xml_resultado_*.json y pdf_resultado_*.json dentro de cada carpeta de tests/fixtures/correos_prueba/. Esos archivos no los usa ninguna prueba y pueden estar desactualizados. tools/descargar_correos_prueba.py borra y vuelve a descargar toda esa carpeta de correos reales.
Carpetas de salida (ignoradas por git)
| Ruta | Contenido |
|---|---|
adjuntos/ |
PDF/XML descargados (DOWNLOAD_FOLDER) |
resultado/ |
JSON de datos extraídos y de drafts, para depuración (OUTPUT_FOLDER) |
logs/ |
Log con rotación diaria y 30 días de historial. LOG_LEVEL controla el nivel |
emails.db |
Correos ya procesados y comprobantes con su código de seguimiento |
Estructura del proyecto
| Módulo | Rol |
|---|---|
main.py |
Demonio y horarios |
pipeline.py |
Orquesta el proceso de cada correo |
adjuntos.py, documentos.py, persistencia.py |
Descarga de adjuntos, extracción de PDF/XML, guardado de JSON |
draft_sap.py, notificaciones.py |
Validación de precios y construcción del Draft; correo técnico para el equipo |
respuesta_proveedor.py, observaciones.py, plantillas.py |
Respuesta de aceptado/rechazado al remitente con las plantillas HTML (plantilla/) |
outlook_utilities.py, sapb1_manager.py, hana_manager.py |
Clientes de Microsoft Graph, SAP Service Layer y SAP HANA |
sunat_schema.py, pdf_utilities.py |
Lectura de XML SUNAT y de PDF |
database_utilities.py, seguimiento.py, email_utilities.py |
SQLite local; códigos de seguimiento y resultado por comprobante; ZIP y filtrado de adjuntos |
logger_manager.py, config_validator.py, pipeline_utils.py |
Logging, validación del .env, utilidades |
tools/ |
Scripts manuales: reprocesar correos, regenerar/inspeccionar los correos de prueba, aberio.http |
tests/ |
Suite pytest, correos de ejemplo (tests/fixtures/) y resultados esperados (tests/golden/) |
Documentación
| Documento | Tema |
|---|---|
docs/inventario.md |
Archivos, dependencias, flujo de datos y bugs corregidos |
docs/main.md |
Demonio y horarios |
docs/pipeline.md |
Flujo por correo y funciones por módulo |
docs/procesar_pdfs.md / docs/procesar_xmls.md |
Extracción de datos de PDF y XML |
docs/validar_precios.md |
Validación de precios contra SAP |
docs/construir_draft.md |
Construcción del Draft SAP B1 |
docs/respuesta_proveedor.md |
Respuesta de aceptado/rechazado al proveedor: modos, protecciones y observaciones |
docs/seguimiento.md |
Códigos de seguimiento y resultado por comprobante |
docs/configurar_msal.md |
Cómo obtener CLIENT_ID, TENANT_ID y CLIENT_SECRET en Azure |
docs/outlook_utilities.md |
Cliente de Microsoft Graph |
docs/hana_manager.md |
Consultas directas a SAP HANA |