Fix Bacas - Itera Sobre Cada Provincia Y Categoría

This commit is contained in:
2025-10-22 11:21:48 -03:00
parent 5ef3eb1af2
commit db469ffba6

View File

@@ -71,12 +71,10 @@ public class LowPriorityDataWorker : BackgroundService
}
/// <summary>
/// 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).
/// </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)
{
try
@@ -84,94 +82,96 @@ public class LowPriorityDataWorker : BackgroundService
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
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<string> { "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<ProyeccionBanca>();
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);