From db469ffba62d32561de4078cab7a268fbe61609e Mon Sep 17 00:00:00 2001 From: dmolinari Date: Wed, 22 Oct 2025 11:21:48 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20Bacas=20-=20Itera=20Sobre=20Cada=20Provin?= =?UTF-8?q?cia=20Y=20Categor=C3=ADa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../LowPriorityDataWorker.cs | 110 +++++++++--------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs b/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs index 68429bd..e937b9e 100644 --- a/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs +++ b/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs @@ -71,12 +71,10 @@ public class LowPriorityDataWorker : BackgroundService } /// - /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral. - /// Esta versión es completamente robusta: maneja respuestas de API vacías o con fechas mal formadas, - /// guarda la CategoriaId y usa una transacción atómica para la escritura en base de datos. + /// Sondea la proyección de bancas a nivel Provincial. + /// Esta versión corregida itera sobre cada provincia y consulta las categorías específicas + /// (Diputados para todas, Senadores solo para las que renuevan). /// - /// El token de autenticación válido para la sesión. - /// El token de cancelación para detener la operación. private async Task SondearProyeccionBancasAsync(string authToken, CancellationToken stoppingToken) { try @@ -84,94 +82,96 @@ public class LowPriorityDataWorker : BackgroundService using var scope = _serviceProvider.CreateScope(); var dbContext = scope.ServiceProvider.GetRequiredService(); - var categoriasDeBancas = await dbContext.CategoriasElectorales - .AsNoTracking() - .Where(c => c.Nombre.Contains("SENADORES") || c.Nombre.Contains("DIPUTADOS")) - .ToListAsync(stoppingToken); + // 1. Definimos las constantes y la lista de provincias que renuevan senadores. + const int catDiputadosNac = 3; + const int catSenadoresNac = 2; + var provinciasQueRenuevanSenadores = new HashSet { "01", "06", "08", "15", "16", "17", "22", "24" }; - var ambitosASondear = await dbContext.AmbitosGeograficos + // 2. Obtenemos las provincias (ámbitos de Nivel 10) de nuestra base de datos. + var ambitosProvinciales = await dbContext.AmbitosGeograficos .AsNoTracking() .Where(a => a.NivelId == 10 && a.DistritoId != null) .ToListAsync(stoppingToken); - if (!categoriasDeBancas.Any() || !ambitosASondear.Any()) + if (!ambitosProvinciales.Any()) { - _logger.LogWarning("No se encontraron categorías de bancas o ámbitos provinciales en la BD. Omitiendo sondeo de bancas."); + _logger.LogWarning("No se encontraron ámbitos provinciales en la BD. Omitiendo sondeo de bancas."); return; } - _logger.LogInformation("Iniciando sondeo de Bancas a nivel Provincial para {count} provincias...", ambitosASondear.Count); + _logger.LogInformation("Iniciando sondeo de Bancas a nivel Provincial para {count} provincias...", ambitosProvinciales.Count); var todasLasProyecciones = new List(); bool hasReceivedAnyNewData = false; var agrupacionesEnDb = await dbContext.AgrupacionesPoliticas.ToDictionaryAsync(a => a.Id, a => a, stoppingToken); - foreach (var ambito in ambitosASondear) + // 3. Iteramos sobre CADA provincia para hacer las llamadas específicas. + foreach (var provincia in ambitosProvinciales) { if (stoppingToken.IsCancellationRequested) break; - foreach (var categoria in categoriasDeBancas) + + // Función auxiliar para no repetir código. Procesa la respuesta de la API. + async Task ProcesarRespuestaApi(Core.DTOs.RepartoBancasDto? dto, int categoriaId) { - if (stoppingToken.IsCancellationRequested) break; + if (dto?.RepartoBancas is not { Count: > 0 } bancas) return; - var repartoBancasDto = await _apiService.GetBancasAsync(authToken, ambito.DistritoId!, ambito.SeccionProvincialId, categoria.Id); - if (repartoBancasDto?.RepartoBancas is { Count: > 0 } bancas) + hasReceivedAnyNewData = true; + DateTime fechaTotalizacion = DateTime.TryParse(dto.FechaTotalizacion, out var parsedDate) ? parsedDate : DateTime.UtcNow; + + foreach (var banca in bancas) { - hasReceivedAnyNewData = true; - DateTime fechaTotalizacion; - if (!DateTime.TryParse(repartoBancasDto.FechaTotalizacion, out var parsedDate)) + if (!agrupacionesEnDb.ContainsKey(banca.IdAgrupacion)) { - fechaTotalizacion = DateTime.Now; - } - else - { - fechaTotalizacion = parsedDate; - } - - foreach (var banca in bancas) - { - if (!agrupacionesEnDb.ContainsKey(banca.IdAgrupacion)) + var nuevaAgrupacion = new AgrupacionPolitica { - var nuevaAgrupacion = new AgrupacionPolitica - { - Id = banca.IdAgrupacion, - Nombre = banca.NombreAgrupacion, - IdTelegrama = banca.IdAgrupacionTelegrama ?? string.Empty - }; - await dbContext.AgrupacionesPoliticas.AddAsync(nuevaAgrupacion, stoppingToken); - agrupacionesEnDb.Add(nuevaAgrupacion.Id, nuevaAgrupacion); - } - todasLasProyecciones.Add(new ProyeccionBanca - { - EleccionId = EleccionId, - AmbitoGeograficoId = ambito.Id, - AgrupacionPoliticaId = banca.IdAgrupacion, - NroBancas = banca.NroBancas, - CategoriaId = categoria.Id, - FechaTotalizacion = fechaTotalizacion - }); + Id = banca.IdAgrupacion, + Nombre = banca.NombreAgrupacion, + IdTelegrama = banca.IdAgrupacionTelegrama ?? string.Empty + }; + await dbContext.AgrupacionesPoliticas.AddAsync(nuevaAgrupacion, stoppingToken); + agrupacionesEnDb.Add(nuevaAgrupacion.Id, nuevaAgrupacion); } + todasLasProyecciones.Add(new ProyeccionBanca + { + EleccionId = EleccionId, + AmbitoGeograficoId = provincia.Id, + AgrupacionPoliticaId = banca.IdAgrupacion, + NroBancas = banca.NroBancas, + CategoriaId = categoriaId, // Usamos la categoría correcta + FechaTotalizacion = fechaTotalizacion + }); } } + + // 4. Siempre consultamos por Diputados (Categoría 3) para la provincia actual. + // Pasamos 'null' en seccionProvincialId para obtener el total provincial. + var diputadosDto = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, catDiputadosNac); + await ProcesarRespuestaApi(diputadosDto, catDiputadosNac); + + if (stoppingToken.IsCancellationRequested) break; + + // 5. SOLO si la provincia está en la lista, consultamos por Senadores (Categoría 2). + if (provinciasQueRenuevanSenadores.Contains(provincia.DistritoId!)) + { + var senadoresDto = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, catSenadoresNac); + await ProcesarRespuestaApi(senadoresDto, catSenadoresNac); + } } + // La lógica para guardar en la base de datos se mantiene, ya que es robusta. if (hasReceivedAnyNewData) { _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); - // Guardar nuevas agrupaciones si las hay if (dbContext.ChangeTracker.HasChanges()) { await dbContext.SaveChangesAsync(stoppingToken); } - // --- LÍNEA CORREGIDA --- - // Se reemplaza ExecuteSqlRawAsync por ExecuteDeleteAsync, que es type-safe - // y maneja correctamente el CancellationToken. await dbContext.ProyeccionesBancas - .Where(p => p.EleccionId == EleccionId) + .Where(p => p.EleccionId == EleccionId && (p.CategoriaId == catDiputadosNac || p.CategoriaId == catSenadoresNac)) .ExecuteDeleteAsync(stoppingToken); - // --- FIN DE LA CORRECCIÓN --- await dbContext.ProyeccionesBancas.AddRangeAsync(todasLasProyecciones, stoppingToken); await dbContext.SaveChangesAsync(stoppingToken);