Files
descarga_factura_transporte/docs/seguimiento.md
T
GeorgeandClaude Sonnet 5.5 297cfde0e1 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>
2026-10-20 22:03:38 -05:00

4.1 KiB

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.