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>
41 lines
2.8 KiB
Markdown
41 lines
2.8 KiB
Markdown
# 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_attachments` solo guarda adjuntos tipo `fileAttachment` con 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_SSL` se respeta en `get_access_token`, `get_emails` y `download_attachments`, pero `send_email` tiene `verify_ssl = False` fijo 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_token` retorna `None` (sin lanzar error) si MSAL devuelve un resultado vacío.
|