fase 1: registro de comprobantes con código de seguimiento
Nueva tabla comprobantes (creada en init_db) y módulo seguimiento.py: cada comprobante recibe un código ABR-AAMMDD-NNNNN que conserva si reaparece en otro correo, más su resultado (aceptado/rechazado/error) y el estado de la notificación. El pipeline lo registra por factura sin bloquear el flujo si el seguimiento falla. Las pruebas usan una BD temporal para no tocar emails.db. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1d6d869111
commit
30e9b160f8
9 files changed
+563
-6
No files matched your search
+4
-3
@@ -5,7 +5,7 @@
|
||||
| Archivo | Líneas | Rol |
|
||||
|---------|--------|-----|
|
||||
| `main.py` | 137 | Demonio orquestador (loop de horarios) |
|
||||
| `pipeline.py` | 233 | Orquestador del pipeline (autenticar, descargar correos, procesar un correo) |
|
||||
| `pipeline.py` | 272 | Orquestador del pipeline (autenticar, descargar correos, procesar un correo) |
|
||||
| `pipeline_utils.py` | 27 | `log()` (logging con indentación de árbol y `severity`) y `ruta_carpeta()` |
|
||||
| `adjuntos.py` | 82 | Descarga de adjuntos (Graph) y filtrado PDF/XML |
|
||||
| `documentos.py` | 372 | Extracción PDF/XML, asignación de guías, copia a red |
|
||||
@@ -17,14 +17,15 @@
|
||||
| `sapb1_manager.py` | 401 | Comunicación con SAP B1 Service Layer |
|
||||
| `outlook_utilities.py` | 249 | Comunicación con Microsoft Graph |
|
||||
| `hana_manager.py` | 141 | Comunicación con SAP HANA directa (fallback de `sapb1_manager` y valor referencial) |
|
||||
| `database_utilities.py` | 117 | SQLite local (cache de correos) |
|
||||
| `database_utilities.py` | 150 | SQLite local (cache de correos) |
|
||||
| `tools/*_prueba.py`, `tools/completar_guias_pipeline.py`, `tools/explorar_notes_xml.py` | — | Scripts manuales sobre `tests/fixtures/correos_prueba/` (anteriores a la suite pytest) |
|
||||
| `tools/consulta_rapida.py` | 120 | Script auxiliar para reprocesar correos por ID (sets en `tools/ids_prueba.json`) |
|
||||
| `seguimiento.py` | 187 | Códigos de seguimiento y resultado por comprobante (tabla `comprobantes`) |
|
||||
| `config_validator.py` | 83 | Valida el `.env` al arrancar (obligatorias, ruta de red, avisos de SSL) |
|
||||
| `email_utilities.py` | 55 | Utilitarios de adjuntos (ZIP, filtrado) |
|
||||
| `logger_manager.py` | 150 | Logging a archivo rotado (30 días) + consola + captura de `print()` |
|
||||
|
||||
Documentación por módulo: `outlook_utilities.py` → [outlook_utilities.md](outlook_utilities.md), `hana_manager.py` → [hana_manager.md](hana_manager.md), validación y draft → [validar_precios.md](validar_precios.md) y [construir_draft.md](construir_draft.md).
|
||||
Documentación por módulo: `seguimiento.py` → [seguimiento.md](seguimiento.md), `outlook_utilities.py` → [outlook_utilities.md](outlook_utilities.md), `hana_manager.py` → [hana_manager.md](hana_manager.md), validación y draft → [validar_precios.md](validar_precios.md) y [construir_draft.md](construir_draft.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# seguimiento.py — Códigos de seguimiento y resultado por comprobante
|
||||
|
||||
Cada comprobante que llega por correo recibe un **código de seguimiento** (`ABR-AAMMDD-NNNNN`, por ejemplo `ABR-261019-00042`) que se le comunicará al proveedor y que permite reconocer el comprobante si lo reenvía. El registro también guarda el resultado del proceso y el estado de la notificación.
|
||||
|
||||
Los datos viven en la tabla `comprobantes` de `emails.db`. El esquema lo crea `database_utilities.init_db()` con `CREATE TABLE IF NOT EXISTS`, por lo que una base existente se actualiza sola sin tocar la tabla `emails`.
|
||||
|
||||
## Identidad
|
||||
|
||||
- Un comprobante se identifica por **(RUC emisor, tipo, serie, número)**. Si vuelve a llegar, en el mismo correo o en otro, conserva su código.
|
||||
- Un correo que no trae ningún comprobante identificable (sin adjuntos, sin XML válido…) se registra aparte con `registrar_correo`: una fila por correo, con RUC, serie y número en `NULL`.
|
||||
- El código sale del `id` de la fila (`ABR-` + fecha + `id` con 5 dígitos), así que es único por construcción, sin reintentos ni contadores aparte.
|
||||
|
||||
## Tabla `comprobantes`
|
||||
|
||||
| Columna | Contenido |
|
||||
|---------|-----------|
|
||||
| `codigo_seguimiento` | Código único del comprobante |
|
||||
| `email_id` | Último correo en el que llegó |
|
||||
| `ruc_emisor`, `tipo`, `serie`, `numero` | Identidad del comprobante (`NULL` en las filas de correo sin comprobante) |
|
||||
| `estado` | `pendiente`, `aceptado`, `rechazado` o `error` |
|
||||
| `observaciones` | JSON con los motivos de rechazo o el detalle del error |
|
||||
| `doc_entry` | DocEntry del draft creado en SAP |
|
||||
| `veces_recibido` | Cuántos correos distintos trajeron este comprobante |
|
||||
| `notificacion_estado`, `notificacion_error`, `notificacion_fecha` | `pendiente`, `enviada`, `fallida` u `omitida`, y su motivo |
|
||||
| `creado_en`, `actualizado_en` | Marcas de tiempo |
|
||||
|
||||
## Funciones
|
||||
|
||||
| Función | Qué hace |
|
||||
|---------|----------|
|
||||
| `registrar_comprobante(email_id, ruc_emisor, tipo, serie, numero)` | Crea el registro o recupera el existente. Devuelve la fila más `reenvio` (True si ya había llegado en **otro** correo). Reprocesar el mismo correo no cambia nada. |
|
||||
| `registrar_correo(email_id)` | Igual, para un correo sin comprobante. Idempotente por correo. |
|
||||
| `obtener(codigo)` | Devuelve el registro o `None`. |
|
||||
| `actualizar_resultado(codigo, estado, observaciones=None, doc_entry=None)` | Guarda el resultado. `ValueError` si el estado no es válido, `LookupError` si no existe el código. |
|
||||
| `registrar_notificacion(codigo, estado, error=None)` | Guarda el estado de la notificación. Mismas excepciones. |
|
||||
|
||||
## Uso en el pipeline
|
||||
|
||||
En `pipeline._procesar_un_correo`, cada factura se registra al empezar (`_registrar_comprobante`) y su resultado se guarda al terminar (`_registrar_resultado`):
|
||||
|
||||
| Resultado del proceso | `estado` | Detalle guardado |
|
||||
|-----------------------|----------|------------------|
|
||||
| Draft creado en SAP | `aceptado` | `doc_entry` |
|
||||
| Precios no coinciden con SAP | `rechazado` | `[{"codigo": "precios_no_coinciden"}]` |
|
||||
| Error al crear el draft | `error` | `[{"codigo": "error_sap", "detalle": "..."}]` |
|
||||
|
||||
El seguimiento **nunca impide procesar la factura**: si falla la base de datos, se registra un `WARNING` y el flujo continúa. Si el comprobante ya había llegado antes, se registra un `WARNING` con las veces recibidas y el estado anterior, pero **no se bloquea** la creación de otro draft.
|
||||
|
||||
## Estado actual y pendiente
|
||||
|
||||
- Los `observaciones` guardados hoy son mínimos. Se reemplazarán por observaciones estructuradas (título, filas, cómo corregir) cuando se definan las validaciones de rechazo.
|
||||
- `registrar_correo` y `registrar_notificacion` están implementados y probados, pero el pipeline todavía no los llama: los usarán las notificaciones al proveedor.
|
||||
|
||||
## Notas
|
||||
|
||||
- `database_utilities.DB_NAME` es `"emails.db"`, una ruta **relativa al directorio de trabajo**. Si el demonio se lanza desde otra carpeta, usará (y creará) otra base y los códigos ya emitidos no se encontrarían. Hoy funciona porque se ejecuta desde la raíz del proyecto.
|
||||
- Las pruebas redirigen `DB_NAME` a una base temporal (fixture automático en `tests/conftest.py`) para no escribir en `emails.db`.
|
||||
Reference in new issue
Block a user