Fix Bacas - Itera Sobre Cada Provincia Y Categoría
This commit is contained in:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user