se responde al remitente con las plantillas de aceptado/rechazado

El sistema contesta a quien envió el correo con la plantilla que corresponda.
Por defecto (NOTIFICACION_MODO=prueba) la respuesta va solo al equipo con el
asunto "[PRUEBA → remitente]"; en modo real va al remitente con copia oculta
al equipo. El correo técnico (tablas de SAP, JSON) pasa a ir solo al equipo.

- respuesta_proveedor.py: contextos de las plantillas, envío y protecciones
  (remitente desconocido o sin dominio, propio buzón, no-reply, mensajes
  automáticos, respuestas a notificaciones, límite de 3 por remitente/24 h).
- observaciones.py: motivos de rechazo con título, filas y cómo corregir
  (borrador de textos); también para correos sin comprobante válido.
- Un error de SAP/HANA o un fallo inesperado no se le comunica al proveedor y
  ya no tumba el ciclo; "guía no encontrada" exige que HANA responda.
- outlook_utilities: es_mensaje_automatico y copia oculta en send_email.
- seguimiento: notificacion_destinatario (con migración) y
  contar_respuestas_correo.
- config_validator anuncia el modo activo; documentación y pruebas.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
GeorgeandClaude Sonnet 5.5 committed 2026-10-22 08:55:54 -05:00
1 parent af9e3961e5
commit 4deb9d4e4d
22 files changed
+1660 -146

No files matched your search

+63
View File
@@ -147,3 +147,66 @@ def test_la_tabla_emails_existente_no_se_modifica():
database_utilities.init_db()
assert seguimiento.registrar_correo("correo-1")["codigo_seguimiento"].startswith("ABR-")
def test_registrar_notificacion_guarda_el_destinatario():
r = seguimiento.registrar_comprobante("correo-1", *COMPROBANTE)
seguimiento.registrar_notificacion(r["codigo_seguimiento"], "enviada", destinatario="a@x.com, b@x.com")
assert seguimiento.obtener(r["codigo_seguimiento"])["notificacion_destinatario"] == "a@x.com, b@x.com"
def _correo_con_respuesta(email_id, sender, estado="enviada", comprobante=False):
database_utilities.save_emails([{"id": email_id, "fecha": "2026-10-14 10:00:00", "sender": sender,
"subject": "s", "has_attach": True}])
r = (seguimiento.registrar_comprobante(email_id, *COMPROBANTE[:2], "F002", email_id) if comprobante
else seguimiento.registrar_correo(email_id))
seguimiento.registrar_notificacion(r["codigo_seguimiento"], estado)
return r
def test_contar_respuestas_solo_cuenta_enviadas_a_correos_sin_comprobante_de_ese_remitente():
_correo_con_respuesta("e1", "Prov@Empresa.com") # cuenta (sin distinguir mayúsculas)
_correo_con_respuesta("e2", "prov@empresa.com") # cuenta
_correo_con_respuesta("e3", "prov@empresa.com", estado="omitida") # no: no se envió
_correo_con_respuesta("e4", "prov@empresa.com", estado="fallida") # no: no se envió
_correo_con_respuesta("e5", "otro@empresa.com") # no: otro remitente
_correo_con_respuesta("e6", "prov@empresa.com", comprobante=True) # no: tiene comprobante
assert seguimiento.contar_respuestas_correo("prov@empresa.com") == 2
assert seguimiento.contar_respuestas_correo("nadie@empresa.com") == 0
def test_contar_respuestas_ignora_las_anteriores_a_la_ventana():
r = _correo_con_respuesta("e1", "prov@empresa.com")
conn = sqlite3.connect(database_utilities.DB_NAME)
conn.execute("UPDATE comprobantes SET notificacion_fecha = '2020-01-01 00:00:00' WHERE codigo_seguimiento = ?",
(r["codigo_seguimiento"],))
conn.commit()
conn.close()
assert seguimiento.contar_respuestas_correo("prov@empresa.com", horas=24) == 0
assert seguimiento.contar_respuestas_correo("prov@empresa.com", horas=24 * 365 * 10) == 1
def test_init_db_agrega_la_columna_a_una_tabla_creada_antes():
conn = sqlite3.connect(database_utilities.DB_NAME)
conn.executescript("""
DROP TABLE comprobantes;
CREATE TABLE comprobantes (
id INTEGER PRIMARY KEY AUTOINCREMENT, codigo_seguimiento TEXT UNIQUE, email_id TEXT NOT NULL,
ruc_emisor TEXT, tipo TEXT, serie TEXT, numero TEXT, estado TEXT NOT NULL DEFAULT 'pendiente',
observaciones TEXT, doc_entry INTEGER, veces_recibido INTEGER NOT NULL DEFAULT 1,
notificacion_estado TEXT NOT NULL DEFAULT 'pendiente', notificacion_error TEXT, notificacion_fecha TEXT,
creado_en TEXT NOT NULL, actualizado_en TEXT NOT NULL);
INSERT INTO comprobantes (codigo_seguimiento, email_id, creado_en, actualizado_en)
VALUES ('ABR-261001-00001', 'viejo', '2026-10-01 10:00:00', '2026-10-01 10:00:00');
""")
conn.commit()
conn.close()
database_utilities.init_db()
assert seguimiento.obtener("ABR-261001-00001")["email_id"] == "viejo" # el dato se conserva
seguimiento.registrar_notificacion("ABR-261001-00001", "enviada", destinatario="a@x.com")
assert seguimiento.obtener("ABR-261001-00001")["notificacion_destinatario"] == "a@x.com"