README en la raíz con instalación, uso, estructura e índice de docs. Nuevos docs/hana_manager.md y docs/outlook_utilities.md. Se renombran los .mkd a .md y se corrigen construir_draft y validar_precios, que describían lógica ya inexistente (CUADRO_VALOR_REFERENCIAL, use_sap_prices). Se actualizan los docstrings obsoletos y las cifras de líneas del inventario. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2.8 KiB
2.8 KiB
outlook_utilities.py — Microsoft Graph (Outlook)
Cliente mínimo de Microsoft Graph para leer la bandeja de entrada, bajar adjuntos y enviar las notificaciones. Autenticación con MSAL (client credentials, permisos de aplicación).
Estructura
outlook_utilities.py
├── CONFIG (.env): CLIENT_ID, CLIENT_SECRET, TENANT_ID, VERIFY_SSL (false por defecto)
├── get_access_token() → str
├── get_emails(user_email, token, fecha_inicio, fecha_fin) → list[dict]
├── download_attachments(user_email, message_id, token, download_path) → list[str]
└── send_email(access_token, from_email, to_recipients, subject, html_body,
attachment_paths=None, cc_recipients=None) → bool
Funciones
| Función | Endpoint Graph | Qué hace |
|---|---|---|
get_access_token |
login.microsoftonline.com/{TENANT_ID} (scope .default) |
Obtiene el token de aplicación. Lanza Exception si MSAL devuelve error. |
get_emails |
GET /users/{user}/mailFolders/Inbox/messages |
Correos de la bandeja de entrada del rango, con paginación ($top=50, sigue @odata.nextLink). Devuelve id, fecha, sender, subject, has_attach. Lanza Exception si el status no es 200. |
download_attachments |
GET /users/{user}/messages/{id}/attachments |
Guarda en download_path los adjuntos tipo archivo y devuelve sus nombres. Crea la carpeta si no existe. |
send_email |
POST /users/{from}/sendMail |
Envía HTML con adjuntos y CC; guarda copia en Enviados. Devuelve True si Graph responde 202; False (con ERROR en el log) en cualquier otro caso. No lanza excepciones. |
Zona horaria
get_emails asume UTC-5 (Perú, sin horario de verano): el rango fecha_inicio–fecha_fin se convierte a UTC sumando 5 h (el fin incluye todo el día), y el campo fecha devuelto resta 5 h a receivedDateTime.
Adjuntos de send_email
Los adjuntos se leen de las rutas indicadas. Una ruta inexistente se omite con un WARNING. El contentType se deduce de la extensión (.pdf, .xml, .json; cualquier otra, application/octet-stream).
Notas
download_attachmentssolo guarda adjuntos tipofileAttachmentcon contenido; los adjuntos de tipo mensaje o referencia se ignoran.- Dos correos con un adjunto del mismo nombre se sobrescriben entre sí si comparten
download_path(el pipeline usa una única carpeta,DOWNLOAD_FOLDER). VERIFY_SSLse respeta enget_access_token,get_emailsydownload_attachments, perosend_emailtieneverify_ssl = Falsefijo y lo ignora.- El módulo ejecuta
warnings.filterwarnings("ignore"), lo que silencia todas las advertencias de Python del proceso (incluidas las de certificado SSL). get_access_tokenretornaNone(sin lanzar error) si MSAL devuelve un resultado vacío.