Saltar a contenido

Email y PDF

El backend genera el PDF de la factura y lo envía por email al cliente final. En el legacy esto vivía sobre Seam Mail (Facelets .xhtml) y Seam PDF/Renderer; la migración a Spring Boot lo reescribe sobre Thymeleaf + JavaMailSender (email) y PDFBox + Flying Saucer (PDF). Estas dos piezas están especificadas en SPEC-012 (email) y SPEC-013 (pdf).

Estado: PENDIENTE de implementación

A diferencia del Cockpit y los jobs Quartz —que ya están en código— el email y el PDF todavía no están portados. Verificado contra el repo: no existen las clases EmailHome, TrxToPdfHome, DynamicMailSender ni plantillas en resources/templates/, y en pom.xml los bloques de dependencias de SPEC-012 y SPEC-013 están comentados:

<!-- [SPEC-012] Email
    <artifactId>spring-boot-starter-mail</artifactId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
...
<!-- [SPEC-013] PDF (PDFBox nativo + Flying Saucer + iText5 + ZXing)

Las versiones ya están fijadas como properties (pdfbox 2.0.31, flyingsaucer 9.1.22, itext 5.5.13.3, zxing 3.5.3), listas para descomentar cuando se implemente. Lo que sigue describe el diseño previsto por las SPECs, no código existente. Tratalo como plan, no como referencia de runtime.

Email — SPEC-012

Objetivo

Reemplazar el envío del legacy (EmailHome.send()renderer.render("email/X.xhtml") + mail:mail-session de Seam) por Thymeleaf + JavaMailSender, construido dinámicamente desde la configuración en la tabla Parametro, preservando exactamente destinatarios, asunto, cuerpo y adjunto (el PDF).

Config dinámica desde Parametro

La config de mail NO vive en application.yml

Es una invariante del proyecto (§5.10): host/puerto/TLS/usuario/clave/from/baseUrl de mail salen de la tabla Parametro vía ParametroList, no del application.yml. El motivo: el cliente cambia esos valores en caliente sin redeploy. El application.yml lo dice explícito: "mail/URLs/flags operativos NO van acá: siguen saliendo de la tabla Parametro". Ver Configuración y perfiles.

El plan (SPEC-012) es un DynamicMailSender que arma un JavaMailSenderImpl por envío con los parámetros actuales de ParametroList (getMailHost, getMailPort, getMailUsuario, getMailClave, getMailTls, etc.). El flag TLS legacy se modela como mail.smtp.starttls.enable y vale true cuando el parámetro es "1".

Lo que se preserva (contrato con el cliente final)

  • Plantillas por comercio: el legacy resuelve la plantilla por enteFacturador.getEmailPath() (default simple); hay variantes simple/factura/dino/ferniplast. Se portan a HTML Thymeleaf en resources/templates/email/, modelando solo el cuerpo (from/to/subject/adjunto pasan a ser parámetros del envío, no de la plantilla).
  • Destinatarios múltiples: to/cc separados por ; (getToInList()/getCCInList()).
  • Imagen de pie embebida: el PNG de footer por comercio (addInline).
  • Asunto y nombre del adjunto: se replican exactos del .xhtml legacy (suelen incluir tipo de comprobante, PV y número) — es contrato con el cliente.
  • Misma API pública de EmailHome (setIdTrx/setTo/setCC/send/getPath/…) para no tocar el caller TiFacturaOnlineManagerWS.

Criterios de aceptación (SPEC-012)

  • EmailHome.send() produce un correo con el mismo from/to/cc/asunto/cuerpo/adjunto que el legacy, comparado contra un correo viejo del golden set.
  • Cambiar el host en la tabla Parametro cambia el envío sin redeploy.
  • to/cc con varios destinatarios separados por ; funcionan.

PDF — SPEC-013

Objetivo

Mantener la generación del PDF de la factura. En el legacy TrxToPdfHome tiene dos caminos, y la SPEC los trata distinto:

Path Legacy Plan en la migración
A — PDFBox nativo createPDF() + Paginator/Pagina/Linea, fuentes, barcodes ZXing Se preserva (port de API PDFBox 1.8 → 2.0)
B — Seam Renderer renderer.render("email/factura.xhtml") + DocumentStore (Seam PDF → iText) Se reemplaza por Thymeleaf + Flying Saucer, o se elimina si no se usa en prod

Path A — PDFBox nativo (se preserva)

La lógica de layout (Paginator, Pagina, Linea, fuentes, barcodes ZXing Code128/QR) no cambia. Lo que cambia es el port de PDFBox 1.8 → 2.0 (los renombres de API: PDPageContentStream de paquete, fuentes como instancias estáticas, PDImageXObject/LosslessFactory, document.save(out) lanzando IOException, PDType0Font.load para TTF, etc.).

Decisión de riesgo abierta (PDFBox 2.0 vs pinear 1.8)

SPEC-013 deja explícito que si el upgrade a 2.0 introduce diferencias de render (posiciones, kerning), la alternativa de mínimo riesgo es pinear pdfbox:1.8.17 y diferir el upgrade. La decisión se toma según el diff visual del golden set. Hoy la property apunta a 2.0.31, pero la implementación final debe validar paridad antes de cerrar esto.

Path B — Seam Renderer (se reemplaza)

El plan es portar factura.xhtml a una plantilla HTML Thymeleaf y renderizarla a PDF con Flying Saucer (ITextRenderer → iText 5, flying-saucer-pdf-itext5). SPEC-013 también plantea eliminarlo en vez de portarlo si un grep confirma que B solo servía para preview web y el adjunto productivo siempre salió del path A (menos superficie).

Lo que se preserva

  • Barcodes Code128/QR presentes y escaneables, con el mismo dato (CAE/CAE barcode).
  • ORIGINAL/DUPLICADO según enteFacturador.getLayout() (esa lógica no se toca).
  • Misma API pública de TrxToPdfHome (setIdTrx/getTrx/createPDF/…) para no tocar EmailHome.

Validación de paridad

SPEC-013 pide un tools/pdf-compare que genere el PDF de N facturas del golden set con el sistema nuevo y lo compare contra el viejo: texto extraído idéntico (PDFBox PDFTextStripper) como gate obligatorio, más diff visual por render a imagen bajo un umbral acordado.

Relación email ↔ PDF

El email depende del PDF: SPEC-012 declara que necesita SPEC-013, porque el adjunto del correo es el PDF que produce TrxToPdfHome.createPDF(). Cuando se implementen, deben usar la misma fuente de PDF (coordinar el path A/B para que el adjunto del correo coincida con el documento que ve el cliente).

Por dónde seguir