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

+92
View File
@@ -0,0 +1,92 @@
# respuesta_proveedor.py — Respuesta al proveedor
Cuando alguien envía un correo con el XML y el PDF de una factura, el sistema valida y **responde a esa misma dirección** con la plantilla de **aceptado** o de **rechazado** (`plantilla/plantilla-aceptado.html` y `plantilla-rechazado.html`). Aparte, el equipo recibe un correo técnico (tablas de SAP, JSON adjuntos).
Piezas: `respuesta_proveedor.py` (contexto, protecciones, envío), `observaciones.py` (motivos de rechazo y sus textos), `plantillas.py` (renderizador) y `seguimiento.py` (código de seguimiento y registro).
## Qué se responde
| Situación | Respuesta al remitente |
|-----------|------------------------|
| Draft creado en SAP | **Aceptado** |
| Precios que no coinciden, guía inexistente, línea sin guía, cantidad cero | **Rechazado** con una observación por motivo |
| Correo con adjuntos pero sin PDF ni XML válido, o con PDF y sin XML, o sin ninguna factura (tipo 01) | **Rechazado** sin comprobante: no muestra proveedor, número ni tabla de guías |
| Error de SAP o de HANA, o un fallo inesperado | **Nada**: es una falla nuestra. Solo se avisa al equipo |
| Correo sin adjuntos | **Nada** |
Una respuesta por comprobante: un correo con 3 facturas genera 3 respuestas. La aceptación significa "draft creado en SAP". La diferencia de valor referencial XML vs SAP es solo informativa y no rechaza.
> **Guía "no encontrada" y caídas de HANA.** `get_delivery_notes` devuelve lista vacía tanto si la guía no existe como si SAP/HANA fallan. Antes de rechazar por guía no encontrada se comprueba que HANA responde; si no, se trata como error interno y no se le dice nada al proveedor.
## Modo prueba y modo real
`NOTIFICACION_MODO` en el `.env`:
| Modo | A quién va la respuesta | Asunto |
|------|-------------------------|--------|
| `prueba` (**por defecto**) | Al equipo (`NOTIFICACION_EQUIPO`), **nunca** al remitente | `[PRUEBA → remitente] Aceptado · Factura F002-486 · ABR-…` |
| `real` | Al remitente, con **copia oculta** al equipo | `Aceptado · Factura F002-486 · ABR-…` |
Cualquier otro valor se trata como `prueba`. Al arrancar, `config_validator` deja en el log una advertencia con el modo activo. Pasar a `real` es una decisión explícita: no ocurre solo.
## Protecciones: cuándo NO se responde
El sistema contesta solo y a terceros, así que no responde a:
| Caso | Motivo registrado |
|------|-------------------|
| Remitente vacío o desconocido | remitente desconocido |
| Dirección sin dominio válido (por ejemplo `test@local`) | dirección no válida |
| El propio buzón del sistema | el remitente es el propio buzón |
| `no-reply`, `noreply`, `do-not-reply`, `no-responder`, `mailer-daemon`, `postmaster`, `bounce` | dirección automática |
| Mensajes automáticos (respuestas automáticas, rebotes, listas) | mensaje automático |
| En correos **sin comprobante**: asunto con `Re:`/`RV:` o que cita un código `ABR-…` | parece una respuesta a una notificación nuestra |
| En correos sin comprobante: más de 3 respuestas al mismo remitente en 24 h | límite de respuestas |
Cada omisión queda en `comprobantes` como `notificacion_estado = omitida`, con el motivo.
## Qué ve el proveedor
- **Importe por guía:** el importe de la línea aparece una vez, en su primera guía; las demás dicen "incluida en la línea". Todas las guías de una línea llevan el mismo resultado, porque la validación es por línea.
- **Rechazo por precio:** se muestran "Importe en su factura" e "Importe esperado" (el de SAP).
- **Pago estimado:** solo si hay condición de pago (fecha de vencimiento posterior a la de contabilización).
- **Sin adjuntos internos:** la respuesta no lleva archivos.
## Observaciones (`observaciones.py`)
Los textos son un **borrador para revisar**; se cambian en ese archivo sin tocar la lógica.
| Código | Cuándo |
|--------|--------|
| `precio_no_coincide` | El total de la línea del XML no coincide con la suma de SAP |
| `guia_no_encontrada` | SAP no devuelve datos para la guía |
| `linea_sin_guia` | Una línea no indica su guía de remisión |
| `cantidad_cero` | Una línea tiene cantidad cero |
| `sin_pdf_xml` | El correo trae adjuntos, pero ninguno es PDF ni XML |
| `falta_xml` | Hay PDF y ningún XML |
| `sin_factura` | El XML no contiene una factura electrónica (tipo 01) |
## Configuración (`.env`)
| Variable | Para qué | Por defecto |
|----------|----------|-------------|
| `NOTIFICACION_MODO` | `prueba` o `real` | `prueba` |
| `NOTIFICACION_EQUIPO` | Direcciones internas (coma o `;`): correo técnico, y respuestas en modo prueba | `jlopez@aberio.com.pe`, `gcalle@pucp.pe` |
| `NOTIFICACION_CONTACTO` | Dirección del botón "Escribir a Aberio" | el buzón `EMAIL` |
| `LOGO_URL` | URL pública (https) del logo | vacío: sin logo |
El buzón `EMAIL` es también el `envio_correo` al que se pide reenviar el comprobante corregido.
## Cómo probar
1. **Vista previa y envío de ejemplos:** `python tools/previsualizar_plantillas.py` (ver su ayuda). Los ejemplos están en `plantilla/ejemplos.json`.
2. **Piloto en modo prueba:** con `NOTIFICACION_MODO=prueba` el flujo completo corre y las respuestas llegan solo al equipo, indicando en el asunto a quién habrían ido. El correo técnico también.
3. **Pasar a real:** cuando el equipo valide los correos, cambiar a `NOTIFICACION_MODO=real`. Revisar antes que `LOGO_URL` tenga valor.
## Limitaciones conocidas
- **Un fallo de envío no se reintenta.** Queda `fallida` en `comprobantes`, pero el correo ya está marcado como procesado.
- **Si SAP está caído, el correo tampoco se reintenta.** Se avisa al equipo y el correo queda procesado (con estado `error`).
- **Un comprobante ya aceptado que se reenvía** genera otro draft y otra respuesta "Aceptado"; hoy solo se advierte en el log.
- La respuesta va a la dirección `from` del mensaje. Si alguien reenvía la factura de un proveedor, la respuesta le llega a quien reenvió.
- No se prueba contra el logo real ni contra Outlook de escritorio: hay que revisar los correos a mano.