Feat: Implementa auditoría de envíos de email y mejora la UX

Se introduce un sistema completo de logging para todas las comunicaciones por correo electrónico y se realizan mejoras significativas en la experiencia del usuario, tanto en la retroalimentación del sistema como en la estética de los emails enviados al cliente.

###  Nuevas Características

- **Auditoría y Log de Envíos de Email:**
    - Se ha creado una nueva tabla `com_EmailLogs` en la base de datos para registrar cada intento de envío de correo.
    - El `EmailService` ahora centraliza toda la lógica de logging, registrando automáticamente la fecha, destinatario, asunto, estado (`Enviado` o `Fallido`), y mensajes de error detallados.
    - Se implementó un nuevo `EmailLogService` y `EmailLogRepository` para gestionar estos registros.

- **Historial de Envíos en la Interfaz de Usuario:**
    - Se añade un nuevo ícono de "Historial" (<span style="color: #607d8b;">&#x1F4E7;</span>) junto a cada factura en la página de "Consulta de Facturas".
    - Al hacer clic, se abre un modal que muestra una tabla detallada con todos los intentos de envío para esa factura, incluyendo el estado y el motivo del error (si lo hubo).
    - Esto proporciona una trazabilidad completa y una herramienta de diagnóstico para el usuario final.

### 🔄 Refactorización y Mejoras

- **Mensajes de Éxito Dinámicos:**
    - Se ha mejorado la retroalimentación al enviar una factura por PDF. El sistema ahora muestra un mensaje de éxito específico, como "El email... se ha enviado correctamente a suscriptor@email.com", en lugar de un mensaje técnico genérico.
    - Se ajustó la cadena de llamadas (`Controller` -> `Service`) para que el email del destinatario esté disponible para la respuesta de la API.

- **Diseño Unificado de Emails:**
    - Se ha rediseñado el template HTML para el "Aviso de Cuenta Mensual" para que coincida con la estética del email de "Envío de Factura PDF".
    - Ambos correos ahora presentan un diseño profesional y consistente, con cabecera, logo y pie de página, reforzando la imagen de marca.

- **Manejo de Errores de Email Mejorado:**
    - El `EmailService` ahora captura excepciones específicas de la librería `MailKit` (ej. `SmtpCommandException`).
    - Esto permite registrar en el log errores mucho más precisos y útiles, como rechazos de destinatarios por parte del servidor (`User unknown`), fallos de autenticación, etc., que ahora son visibles en el `Tooltip` del historial.
This commit is contained in:
2025-08-09 21:12:11 -03:00
parent 5a806eda38
commit 7dc0940001
17 changed files with 647 additions and 197 deletions

View File

@@ -1,4 +1,6 @@
using GestionIntegral.Api.Dtos.Comunicaciones;
using GestionIntegral.Api.Dtos.Suscripciones;
using GestionIntegral.Api.Services.Comunicaciones;
using GestionIntegral.Api.Services.Suscripciones;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@@ -13,13 +15,15 @@ namespace GestionIntegral.Api.Controllers.Suscripciones
{
private readonly IFacturacionService _facturacionService;
private readonly ILogger<FacturacionController> _logger;
private readonly IEmailLogService _emailLogService;
private const string PermisoGestionarFacturacion = "SU006";
private const string PermisoEnviarEmail = "SU009";
public FacturacionController(IFacturacionService facturacionService, ILogger<FacturacionController> logger)
public FacturacionController(IFacturacionService facturacionService, ILogger<FacturacionController> logger, IEmailLogService emailLogService)
{
_facturacionService = facturacionService;
_logger = logger;
_emailLogService = emailLogService;
}
private bool TienePermiso(string codAcc) => User.IsInRole("SuperAdmin") || User.HasClaim(c => c.Type == "permission" && c.Value == codAcc);
@@ -55,14 +59,17 @@ namespace GestionIntegral.Api.Controllers.Suscripciones
public async Task<IActionResult> EnviarFacturaPdf(int idFactura)
{
if (!TienePermiso("SU009")) return Forbid();
var (exito, error) = await _facturacionService.EnviarFacturaPdfPorEmail(idFactura);
var userId = GetCurrentUserId();
if (userId == null) return Unauthorized();
var (exito, error, emailDestino) = await _facturacionService.EnviarFacturaPdfPorEmail(idFactura, userId.Value);
if (!exito)
{
return BadRequest(new { message = error });
}
return Ok(new { message = "Email con factura PDF enviado a la cola de procesamiento." });
var mensajeExito = $"El email con la factura PDF se ha enviado correctamente a {emailDestino}.";
return Ok(new { message = mensajeExito });
}
// POST: api/facturacion/{anio}/{mes}/suscriptor/{idSuscriptor}/enviar-aviso
@@ -116,5 +123,13 @@ namespace GestionIntegral.Api.Controllers.Suscripciones
if (!exito) return StatusCode(StatusCodes.Status500InternalServerError, new { message = mensaje });
return Ok(new { message = mensaje, facturasGeneradas });
}
[HttpGet("{idFactura:int}/historial-envios")]
[ProducesResponseType(typeof(IEnumerable<EmailLogDto>), StatusCodes.Status200OK)]
public async Task<IActionResult> GetHistorialEnvios(int idFactura)
{
var historial = await _emailLogService.ObtenerHistorialPorReferencia("Factura-" + idFactura);
return Ok(historial);
}
}
}