Fix Bancas 2

This commit is contained in:
2025-08-20 17:51:26 -03:00
parent 43a967eac2
commit 1a6f7dd5a3

View File

@@ -248,51 +248,85 @@ public class LowPriorityDataWorker : BackgroundService
/// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral. /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral.
/// Esta versión recolecta todos los datos disponibles y los guarda en una única transacción. /// Esta versión recolecta todos los datos disponibles y los guarda en una única transacción.
/// </summary> /// </summary>
/// <summary>
/// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral.
/// Esta versión incluye logging detallado para diagnosticar problemas de deserialización
/// o respuestas inesperadas de la API, y guarda los datos en una transacción atómica.
/// </summary>
/// <param name="authToken">El token de autenticación válido para la sesión.</param>
/// <param name="stoppingToken">El token de cancelación para detener la operación.</param>
private async Task SondearProyeccionBancasAsync(string authToken, CancellationToken stoppingToken) private async Task SondearProyeccionBancasAsync(string authToken, CancellationToken stoppingToken)
{ {
try try
{ {
// Usamos un scope de DbContext para esta operación, asegurando una conexión limpia.
using var scope = _serviceProvider.CreateScope(); using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>(); var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
// 1. OBTENER DATOS DE CONFIGURACIÓN DE NUESTRA BD
// Buscamos las categorías que reparten bancas (Senadores y Diputados).
var categoriasDeBancas = await dbContext.CategoriasElectorales var categoriasDeBancas = await dbContext.CategoriasElectorales
.AsNoTracking() .AsNoTracking()
.Where(c => c.Nombre.Contains("SENADORES") || c.Nombre.Contains("DIPUTADOS")) .Where(c => c.Nombre.Contains("SENADORES") || c.Nombre.Contains("DIPUTADOS"))
.ToListAsync(stoppingToken); .ToListAsync(stoppingToken);
// Obtenemos el registro de la Provincia para hacer la consulta a nivel provincial.
var provincia = await dbContext.AmbitosGeograficos var provincia = await dbContext.AmbitosGeograficos
.AsNoTracking() .AsNoTracking()
.FirstOrDefaultAsync(a => a.NivelId == 10, stoppingToken); .FirstOrDefaultAsync(a => a.NivelId == 10, stoppingToken);
// Obtenemos todas las Secciones Electorales para hacer las consultas por sección.
var seccionesElectorales = await dbContext.AmbitosGeograficos var seccionesElectorales = await dbContext.AmbitosGeograficos
.AsNoTracking() .AsNoTracking()
.Where(a => a.NivelId == 20 && a.DistritoId != null && a.SeccionProvincialId != null) .Where(a => a.NivelId == 20 && a.DistritoId != null && a.SeccionProvincialId != null)
.ToListAsync(stoppingToken); .ToListAsync(stoppingToken);
// Si falta alguna configuración base, no podemos continuar.
if (!categoriasDeBancas.Any() || provincia == null) if (!categoriasDeBancas.Any() || provincia == null)
{ {
_logger.LogWarning("No se encontraron categorías de bancas o el ámbito provincial en la BD. Omitiendo sondeo."); _logger.LogWarning("No se encontraron categorías de bancas o el ámbito provincial en la BD. Omitiendo sondeo de bancas.");
return; return;
} }
_logger.LogInformation("Iniciando sondeo de Bancas a nivel Provincial y para {count} Secciones Electorales...", seccionesElectorales.Count); _logger.LogInformation("Iniciando sondeo de Bancas a nivel Provincial y para {count} Secciones Electorales...", seccionesElectorales.Count);
// --- LÓGICA CORREGIDA --- // 2. RECOLECTAR DATOS DE LA API
bool hasReceivedAnyNewData = false;
var todasLasProyecciones = new List<ProyeccionBanca>();
// 1. Bucle Provincial // Una lista para acumular todas las proyecciones que encontremos.
var todasLasProyecciones = new List<ProyeccionBanca>();
// Una bandera para saber si hemos recibido al menos una banca con datos.
bool hasReceivedAnyNewData = false;
// Bucle para el nivel Provincial
foreach (var categoria in categoriasDeBancas) foreach (var categoria in categoriasDeBancas)
{ {
if (stoppingToken.IsCancellationRequested) break; if (stoppingToken.IsCancellationRequested) break;
var repartoBancas = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, categoria.Id); var repartoBancas = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, categoria.Id);
// Comprobamos si la respuesta no es nula y si la lista de bancas TIENE ELEMENTOS. // --- Lógica de Verificación Explícita ---
if (repartoBancas?.RepartoBancas is { Count: > 0 } bancas) if (repartoBancas == null)
{ {
// Si encontramos datos, activamos la bandera. // Esto ocurriría si GetBancasAsync devuelve null (ej. por un error 500 o un JsonException).
hasReceivedAnyNewData = true; _logger.LogWarning("La respuesta para bancas provinciales (cat: {catId}) fue nula o inválida.", categoria.Id);
foreach (var banca in bancas) continue;
}
if (repartoBancas.RepartoBancas == null)
{
// Esto es por si la API devuelve un JSON válido pero sin la propiedad "repartoBancas".
_logger.LogWarning("La lista 'RepartoBancas' en la respuesta provincial (cat: {catId}) es nula.", categoria.Id);
continue;
}
if (repartoBancas.RepartoBancas.Count > 0)
{
// ¡Éxito! Hemos encontrado datos.
_logger.LogInformation("Se encontraron {count} registros de bancas a nivel provincial para la categoría {catId}.", repartoBancas.RepartoBancas.Count, categoria.Id);
hasReceivedAnyNewData = true; // Activamos la bandera.
foreach (var banca in repartoBancas.RepartoBancas)
{ {
todasLasProyecciones.Add(new ProyeccionBanca todasLasProyecciones.Add(new ProyeccionBanca
{ {
@@ -304,7 +338,7 @@ public class LowPriorityDataWorker : BackgroundService
} }
} }
// 2. Bucle por Sección // Bucle para el nivel de Sección Electoral
foreach (var seccion in seccionesElectorales) foreach (var seccion in seccionesElectorales)
{ {
if (stoppingToken.IsCancellationRequested) break; if (stoppingToken.IsCancellationRequested) break;
@@ -313,10 +347,10 @@ public class LowPriorityDataWorker : BackgroundService
if (stoppingToken.IsCancellationRequested) break; if (stoppingToken.IsCancellationRequested) break;
var repartoBancas = await _apiService.GetBancasAsync(authToken, seccion.DistritoId!, seccion.SeccionProvincialId!, categoria.Id); var repartoBancas = await _apiService.GetBancasAsync(authToken, seccion.DistritoId!, seccion.SeccionProvincialId!, categoria.Id);
if (repartoBancas?.RepartoBancas is { Count: > 0 } bancas) if (repartoBancas?.RepartoBancas?.Count > 0)
{ {
hasReceivedAnyNewData = true; hasReceivedAnyNewData = true;
foreach (var banca in bancas) foreach (var banca in repartoBancas.RepartoBancas)
{ {
todasLasProyecciones.Add(new ProyeccionBanca todasLasProyecciones.Add(new ProyeccionBanca
{ {
@@ -329,27 +363,31 @@ public class LowPriorityDataWorker : BackgroundService
} }
} }
// 3. Guardado Final // 3. GUARDAR DATOS EN LA BASE DE DATOS
// La lógica de guardado ahora depende de la bandera.
// Solo procedemos a escribir en la BD si la bandera se activó.
if (hasReceivedAnyNewData) if (hasReceivedAnyNewData)
{ {
_logger.LogInformation("Se recibieron {count} registros de proyección de bancas. Actualizando la tabla...", todasLasProyecciones.Count); _logger.LogInformation("Se recibieron datos válidos de bancas. Procediendo a actualizar la base de datos...");
await using var transaction = await dbContext.Database.BeginTransactionAsync(stoppingToken); await using var transaction = await dbContext.Database.BeginTransactionAsync(stoppingToken);
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ProyeccionesBancas", stoppingToken); await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ProyeccionesBancas", stoppingToken);
// Guardamos la lista completa, incluso los que tienen 0 bancas.
await dbContext.ProyeccionesBancas.AddRangeAsync(todasLasProyecciones, stoppingToken); await dbContext.ProyeccionesBancas.AddRangeAsync(todasLasProyecciones, stoppingToken);
await dbContext.SaveChangesAsync(stoppingToken); await dbContext.SaveChangesAsync(stoppingToken);
await transaction.CommitAsync(stoppingToken); await transaction.CommitAsync(stoppingToken);
_logger.LogInformation("Sondeo de Bancas completado. La tabla de proyecciones ha sido actualizada."); _logger.LogInformation("La tabla de proyecciones ha sido actualizada con {count} registros.", todasLasProyecciones.Count);
} }
else else
{ {
_logger.LogInformation("Sondeo de Bancas completado. No se encontraron datos nuevos de proyección, la tabla no fue modificada."); _logger.LogInformation("Sondeo de Bancas completado. No se encontraron datos nuevos de proyección, la tabla no fue modificada.");
} }
} }
catch (OperationCanceledException)
{
_logger.LogInformation("Sondeo de bancas cancelado.");
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Ocurrió un error CRÍTICO en el sondeo de Bancas."); _logger.LogError(ex, "Ocurrió un error CRÍTICO en el sondeo de Bancas.");