Fix: Conteo y Clasificación de Eventos y Docker Compose Puerto
This commit is contained in:
@@ -37,6 +37,12 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
|
||||
public async Task EjecutarProcesoAsync(DateTime fechaDesde)
|
||||
{
|
||||
// Contadores inicializados AL PRINCIPIO
|
||||
int copiadas = 0;
|
||||
int omitidas = 0;
|
||||
int errores = 0;
|
||||
// No declarar 'int procesadas = 0' porque es redundante con copiadas/omitidas
|
||||
|
||||
var config = await _context.Configuraciones.FirstOrDefaultAsync(c => c.Id == 1);
|
||||
if (config == null)
|
||||
{
|
||||
@@ -44,7 +50,6 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
return;
|
||||
}
|
||||
|
||||
// Actualizamos la fecha de ejecución
|
||||
config.UltimaEjecucion = DateTime.Now;
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
@@ -64,20 +69,27 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
|
||||
await RegistrarEventoAsync($"Se encontraron {facturas.Count} facturas para procesar", TipoEvento.Info);
|
||||
|
||||
int procesadas = 0;
|
||||
int errores = 0;
|
||||
List<FacturaParaProcesar> pendientes = new();
|
||||
List<string> detallesErroresParaMail = new();
|
||||
|
||||
// Lista para rastrear las entidades de Evento y actualizar su flag 'Enviado' luego
|
||||
List<Evento> eventosDeErrorParaActualizar = new();
|
||||
|
||||
// --- 1. Primer intento ---
|
||||
foreach (var factura in facturas)
|
||||
{
|
||||
bool exito = await ProcesarFacturaAsync(factura, config);
|
||||
if (exito) procesadas++;
|
||||
else pendientes.Add(factura);
|
||||
var resultado = await ProcesarFacturaAsync(factura, config);
|
||||
|
||||
switch (resultado)
|
||||
{
|
||||
case ResultadoProceso.Copiado:
|
||||
copiadas++;
|
||||
break;
|
||||
case ResultadoProceso.Omitido:
|
||||
omitidas++;
|
||||
break;
|
||||
case ResultadoProceso.Error:
|
||||
pendientes.Add(factura);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// --- 2. Sistema de Reintentos ---
|
||||
@@ -93,11 +105,14 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
|
||||
foreach (var factura in pendientes)
|
||||
{
|
||||
bool exito = await ProcesarFacturaAsync(factura, config);
|
||||
if (exito)
|
||||
var resultado = await ProcesarFacturaAsync(factura, config);
|
||||
|
||||
if (resultado != ResultadoProceso.Error)
|
||||
{
|
||||
procesadas++;
|
||||
_logger.LogInformation("Archivo encontrado en reintento {intento}: {archivo}", intento, factura.NombreArchivoOrigen);
|
||||
if (resultado == ResultadoProceso.Copiado) copiadas++;
|
||||
if (resultado == ResultadoProceso.Omitido) omitidas++;
|
||||
|
||||
_logger.LogInformation("Archivo recuperado en reintento {intento}: {archivo}", intento, factura.NombreArchivoOrigen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,7 +125,7 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
// --- 3. Registro de Errores Finales ---
|
||||
if (pendientes.Count > 0)
|
||||
{
|
||||
errores = pendientes.Count;
|
||||
errores = pendientes.Count; // Aquí usamos la variable ya declarada arriba
|
||||
foreach (var factura in pendientes)
|
||||
{
|
||||
string msgError = $"El archivo NO EXISTE después de {MAX_REINTENTOS} intentos: {factura.NombreArchivoOrigen}";
|
||||
@@ -124,8 +139,6 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
};
|
||||
|
||||
_context.Eventos.Add(eventoError);
|
||||
|
||||
// Guardamos referencias
|
||||
eventosDeErrorParaActualizar.Add(eventoError);
|
||||
detallesErroresParaMail.Add(factura.NombreArchivoOrigen);
|
||||
}
|
||||
@@ -151,40 +164,31 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
catch { }
|
||||
|
||||
// --- 6. Evento Final ---
|
||||
var mensajeFinal = $"Proceso finalizado. Procesadas: {procesadas}, Errores: {errores}";
|
||||
var mensajeFinal = $"Proceso finalizado. Nuevas: {copiadas}, Verificadas: {omitidas}, Errores: {errores}";
|
||||
await RegistrarEventoAsync(mensajeFinal, errores > 0 ? TipoEvento.Warning : TipoEvento.Info);
|
||||
|
||||
// --- 7. Envío de Mail Inteligente (Solo 1 vez por archivo) ---
|
||||
// --- 7. Envío de Mail Inteligente ---
|
||||
if (errores > 0 && config.AvisoMail && !string.IsNullOrEmpty(config.SMTPDestinatario))
|
||||
{
|
||||
// 1. Buscamos en la historia de la DB si estos archivos ya fueron reportados previamente.
|
||||
// Buscamos en TODOS los logs disponibles (que suelen ser los últimos 30 días según la limpieza).
|
||||
// Filtramos por Tipo Error y Enviado=true.
|
||||
var historialErroresEnviados = await _context.Eventos
|
||||
.Where(e => e.Tipo == TipoEvento.Error.ToString() && e.Enviado == true)
|
||||
.Select(e => e.Mensaje)
|
||||
.ToListAsync();
|
||||
|
||||
// 2. Filtramos la lista actual:
|
||||
// Solo queremos los archivos que NO aparezcan en ningún mensaje del historial.
|
||||
var archivosNuevosParaNotificar = detallesErroresParaMail.Where(archivoFallido =>
|
||||
{
|
||||
// El mensaje en BD es: "El archivo NO EXISTE...: nombre_archivo.pdf"
|
||||
// Chequeamos si el nombre del archivo está contenido en algún mensaje viejo.
|
||||
bool yaFueNotificado = historialErroresEnviados.Any(msgHistorico => msgHistorico.Contains(archivoFallido));
|
||||
return !yaFueNotificado;
|
||||
}).ToList();
|
||||
|
||||
// 3. Decidir si enviar mail
|
||||
bool mailEnviado = false;
|
||||
|
||||
if (archivosNuevosParaNotificar.Count > 0)
|
||||
{
|
||||
// Si hay archivos NUEVOS, enviamos mail SOLO con esos.
|
||||
// Nota: Pasamos 'errores' (total técnico) y 'archivosNuevosParaNotificar' (detalle visual)
|
||||
// Pasamos 'copiadas' en lugar de 'procesadas' para el mail, o la suma de ambas si prefieres
|
||||
mailEnviado = await EnviarNotificacionErroresAsync(
|
||||
config.SMTPDestinatario,
|
||||
procesadas,
|
||||
copiadas + omitidas,
|
||||
errores,
|
||||
archivosNuevosParaNotificar
|
||||
);
|
||||
@@ -196,14 +200,10 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogInformation("Se omitió el envío de correo: Los {count} errores ya fueron notificados anteriormente.", errores);
|
||||
// Simulamos que se "envió" (se gestionó) para marcar los flags en BD
|
||||
_logger.LogInformation("Se omitió el envío de correo por errores repetidos.");
|
||||
mailEnviado = true;
|
||||
}
|
||||
|
||||
// 4. Actualizar flag en BD (CRÍTICO)
|
||||
// Si gestionamos la notificación correctamente (ya sea enviándola o detectando que ya estaba enviada),
|
||||
// marcamos los eventos actuales como Enviado=true para que pasen al historial y no se vuelvan a procesar.
|
||||
if (mailEnviado && eventosDeErrorParaActualizar.Count > 0)
|
||||
{
|
||||
foreach (var evento in eventosDeErrorParaActualizar)
|
||||
@@ -296,7 +296,7 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
return facturas;
|
||||
}
|
||||
|
||||
private async Task<bool> ProcesarFacturaAsync(FacturaParaProcesar factura, Configuracion config)
|
||||
private async Task<ResultadoProceso> ProcesarFacturaAsync(FacturaParaProcesar factura, Configuracion config)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -306,7 +306,8 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
string rutaOrigen = Path.Combine(rutaBaseOrigen, factura.NombreArchivoOrigen);
|
||||
string carpetaDestinoFinal = Path.Combine(rutaBaseDestino, factura.CarpetaDestino);
|
||||
|
||||
if (!File.Exists(rutaOrigen)) return false;
|
||||
// Si no existe origen, es un error (para reintento)
|
||||
if (!File.Exists(rutaOrigen)) return ResultadoProceso.Error;
|
||||
|
||||
if (!Directory.Exists(carpetaDestinoFinal))
|
||||
{
|
||||
@@ -319,16 +320,21 @@ public class ProcesadorFacturasService : IProcesadorFacturasService
|
||||
|
||||
if (infoDestino.Exists)
|
||||
{
|
||||
if (infoDestino.Length == infoOrigen.Length) return true;
|
||||
// Si ya existe y es igual, lo OMITIMOS
|
||||
if (infoDestino.Length == infoOrigen.Length)
|
||||
{
|
||||
return ResultadoProceso.Omitido;
|
||||
}
|
||||
}
|
||||
|
||||
// Si llegamos acá, copiamos
|
||||
File.Copy(rutaOrigen, rutaDestinoCompleta, overwrite: true);
|
||||
return true;
|
||||
return ResultadoProceso.Copiado;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogDebug(ex, "Fallo al copiar {archivo}", factura.NombreArchivoOrigen);
|
||||
return false;
|
||||
return ResultadoProceso.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,3 +487,10 @@ public class FacturaParaProcesar
|
||||
public string NombreArchivoDestino { get; set; } = string.Empty;
|
||||
public string CarpetaDestino { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public enum ResultadoProceso
|
||||
{
|
||||
Copiado, // Era nuevo y se copió
|
||||
Omitido, // Ya existía y estaba bien
|
||||
Error // No se encontró o falló
|
||||
}
|
||||
Reference in New Issue
Block a user