La comparación abs(a - b) < 0.01 no era fiable por la coma flotante: el mismo
céntimo se aceptaba o rechazaba según el importe (431.41 contra 431.40 se
rechazaba y 624.39 contra 624.38 se aceptaba). pipeline_utils.importes_coinciden
redondea la diferencia a 2 decimales, lo que muestra un comprobante, y admite
hasta 1 céntimo. Se usa en la validación de precios y en la comparación del
valor referencial. Con datos reales de SAP (49 líneas) ningún resultado cambió.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- 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>
Las funciones anidadas de _procesar_un_correo pasan a funciones de módulo
con parámetros explícitos; pipeline.py queda solo como orquestador.
copiar_a_red lee las variables de entorno al ejecutarse. Se actualizan docs.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>