feat(Worker): Adaptación integral para la API de Elecciones Nacionales
Este commit refactoriza por completo el sistema de recolección de datos para asegurar la compatibilidad con la nueva API nacional, pasando de un modelo de distrito único a uno multi-distrito. Cambios principales: - **Refactorización de `SondearResumenProvincialAsync`:** - Se elimina la dependencia del endpoint obsoleto `/getResumen`. - El método ahora itera sobre todas las provincias (`NivelId=10`) y categorías, utilizando `GetResultadosAsync` para obtener los datos agregados. - **Expansión de `SondearResultadosMunicipalesAsync`:** - Se renombra a `SondearResultadosPorAmbitosAsync` para reflejar su nueva responsabilidad. - La lógica ahora sondea múltiples niveles jerárquicos (`NivelId` 10, 20, 30), capturando resultados detallados para Provincias, Secciones Electorales y Municipios. - **Modificación del Modelo de Datos:** - Se añade la columna `CategoriaId` a la entidad y tabla `ResumenVoto`. - Se crea la migración de base de datos `AddCategoriaIdToResumenVoto` para aplicar el cambio. - **Ajustes de Nulabilidad en API Service:** - Se actualizan las firmas de `GetResultadosAsync` en `IElectoralApiService` y `ElectoralApiService` para permitir que `seccionId` y `municipioId` sean nulables (`string?`), resolviendo errores de compilación CS8625. - **Deshabilitación de Seeders de Ejemplo:** - Se introduce una bandera `generarDatosDeEjemplo` en `Program.cs` de la API, establecida en `false`, para prevenir la ejecución de código de simulación en entornos de producción o pruebas.
This commit is contained in:
		| @@ -167,6 +167,9 @@ using (var scope = app.Services.CreateScope()) | ||||
|     var logger = services.GetRequiredService<ILogger<Program>>(); | ||||
|     var hasher = services.GetRequiredService<IPasswordHasher>(); | ||||
|  | ||||
|     // --- PASO 1: Añadir esta bandera de control --- | ||||
|     bool generarDatosDeEjemplo = false; // <-- Poner en 'false' para deshabilitar | ||||
|  | ||||
|     // --- SEEDER 1: DATOS ESTRUCTURALES BÁSICOS (se ejecutan una sola vez si la BD está vacía) --- | ||||
|     // Estos son los datos maestros que NUNCA cambian. | ||||
|  | ||||
| @@ -218,169 +221,171 @@ using (var scope = app.Services.CreateScope()) | ||||
|     await context.SaveChangesAsync(); | ||||
|     logger.LogInformation("--> Default configurations verified/seeded."); | ||||
|  | ||||
|  | ||||
|     // --- SEEDER 2: DATOS DE EJEMPLO PARA ELECCIÓN NACIONAL (se ejecuta solo si faltan sus votos) --- | ||||
|     const int eleccionNacionalId = 2; | ||||
|     if (!await context.ResultadosVotos.AnyAsync(r => r.EleccionId == eleccionNacionalId)) | ||||
|     // --- PASO 2: Envolver todo el bloque del Seeder 2 en esta condición --- | ||||
|     if (generarDatosDeEjemplo) | ||||
|     { | ||||
|         logger.LogInformation("--> No se encontraron datos de votos para la elección nacional ID {EleccionId}. Generando datos de simulación...", eleccionNacionalId); | ||||
|         // --- SEEDER 2: DATOS DE EJEMPLO PARA ELECCIÓN NACIONAL (se ejecuta solo si faltan sus votos) --- | ||||
|         const int eleccionNacionalId = 2; | ||||
|         if (!await context.ResultadosVotos.AnyAsync(r => r.EleccionId == eleccionNacionalId)) | ||||
|         { | ||||
|             logger.LogInformation("--> No se encontraron datos de votos para la elección nacional ID {EleccionId}. Generando datos de simulación...", eleccionNacionalId); | ||||
|  | ||||
|         // PASO A: VERIFICAR/CREAR DEPENDENCIAS (Ámbitos, Categorías) | ||||
|         if (!await context.CategoriasElectorales.AnyAsync(c => c.Id == 1)) | ||||
|             context.CategoriasElectorales.Add(new CategoriaElectoral { Id = 1, Nombre = "SENADORES NACIONALES", Orden = 2 }); | ||||
|         if (!await context.CategoriasElectorales.AnyAsync(c => c.Id == 2)) | ||||
|             context.CategoriasElectorales.Add(new CategoriaElectoral { Id = 2, Nombre = "DIPUTADOS NACIONALES", Orden = 3 }); | ||||
|             // PASO A: VERIFICAR/CREAR DEPENDENCIAS (Ámbitos, Categorías) | ||||
|             if (!await context.CategoriasElectorales.AnyAsync(c => c.Id == 1)) | ||||
|                 context.CategoriasElectorales.Add(new CategoriaElectoral { Id = 1, Nombre = "SENADORES NACIONALES", Orden = 2 }); | ||||
|             if (!await context.CategoriasElectorales.AnyAsync(c => c.Id == 2)) | ||||
|                 context.CategoriasElectorales.Add(new CategoriaElectoral { Id = 2, Nombre = "DIPUTADOS NACIONALES", Orden = 3 }); | ||||
|  | ||||
|         var provinciasMaestras = new Dictionary<string, string> { | ||||
|             var provinciasMaestras = new Dictionary<string, string> { | ||||
|             { "01", "CIUDAD AUTONOMA DE BUENOS AIRES" }, { "02", "BUENOS AIRES" }, { "03", "CATAMARCA" }, { "04", "CORDOBA" }, { "05", "CORRIENTES" }, | ||||
|             { "06", "CHACO" }, { "07", "CHUBUT" }, { "08", "ENTRE RIOS" }, { "09", "FORMOSA" }, { "10", "JUJUY" }, { "11", "LA PAMPA" }, | ||||
|             { "12", "LA RIOJA" }, { "13", "MENDOZA" }, { "14", "MISIONES" }, { "15", "NEUQUEN" }, { "16", "RIO NEGRO" }, { "17", "SALTA" }, | ||||
|             { "18", "SAN JUAN" }, { "19", "SAN LUIS" }, { "20", "SANTA CRUZ" }, { "21", "SANTA FE" }, { "22", "SANTIAGO DEL ESTERO" }, | ||||
|             { "23", "TIERRA DEL FUEGO" }, { "24", "TUCUMAN" } | ||||
|         }; | ||||
|         foreach (var p in provinciasMaestras) | ||||
|         { | ||||
|             if (!await context.AmbitosGeograficos.AnyAsync(a => a.NivelId == 10 && a.DistritoId == p.Key)) | ||||
|                 context.AmbitosGeograficos.Add(new AmbitoGeografico { Nombre = p.Value, NivelId = 10, DistritoId = p.Key }); | ||||
|         } | ||||
|         await context.SaveChangesAsync(); | ||||
|  | ||||
|         var provinciasEnDb = await context.AmbitosGeograficos.AsNoTracking().Where(a => a.NivelId == 10).ToListAsync(); | ||||
|         foreach (var provincia in provinciasEnDb) | ||||
|         { | ||||
|             if (!await context.AmbitosGeograficos.AnyAsync(a => a.NivelId == 30 && a.DistritoId == provincia.DistritoId)) | ||||
|             foreach (var p in provinciasMaestras) | ||||
|             { | ||||
|                 for (int i = 1; i <= 5; i++) | ||||
|                     context.AmbitosGeograficos.Add(new AmbitoGeografico { Nombre = $"{provincia.Nombre} - Depto. {i}", NivelId = 30, DistritoId = provincia.DistritoId }); | ||||
|                 if (!await context.AmbitosGeograficos.AnyAsync(a => a.NivelId == 10 && a.DistritoId == p.Key)) | ||||
|                     context.AmbitosGeograficos.Add(new AmbitoGeografico { Nombre = p.Value, NivelId = 10, DistritoId = p.Key }); | ||||
|             } | ||||
|         } | ||||
|         await context.SaveChangesAsync(); | ||||
|         logger.LogInformation("--> Datos maestros para Elección Nacional (Ámbitos, Categorías) verificados/creados."); | ||||
|             await context.SaveChangesAsync(); | ||||
|  | ||||
|         // PASO B: GENERAR DATOS TRANSACCIONALES (Votos, Recuentos, etc.) | ||||
|         var todosLosPartidos = await context.AgrupacionesPoliticas.Take(5).ToListAsync(); | ||||
|         if (!todosLosPartidos.Any()) | ||||
|         { | ||||
|             logger.LogWarning("--> No hay partidos en la BD, no se pueden generar votos de ejemplo."); | ||||
|             return; // Salir si no hay partidos para evitar errores | ||||
|         } | ||||
|  | ||||
|         // (La lógica interna de generación de votos y recuentos que ya tenías y funcionaba) | ||||
|         // ... (el código de generación de `nuevosResultados` y `nuevosEstados` va aquí, sin cambios) | ||||
|         var nuevosResultados = new List<ResultadoVoto>(); | ||||
|         var nuevosEstados = new List<EstadoRecuentoGeneral>(); | ||||
|         var rand = new Random(); | ||||
|         var provinciasQueRenuevanSenadores = new HashSet<string> { "01", "06", "08", "15", "16", "17", "22", "23" }; | ||||
|         var categoriaDiputadosNac = await context.CategoriasElectorales.FindAsync(2); | ||||
|         var categoriaSenadoresNac = await context.CategoriasElectorales.FindAsync(1); | ||||
|  | ||||
|         long totalVotosNacionalDip = 0, totalVotosNacionalSen = 0; | ||||
|         int totalMesasNacionalDip = 0, totalMesasNacionalSen = 0; | ||||
|         int totalMesasEscrutadasNacionalDip = 0, totalMesasEscrutadasNacionalSen = 0; | ||||
|  | ||||
|         foreach (var provincia in provinciasEnDb) | ||||
|         { | ||||
|             var municipiosDeProvincia = await context.AmbitosGeograficos.AsNoTracking().Where(a => a.NivelId == 30 && a.DistritoId == provincia.DistritoId).ToListAsync(); | ||||
|             if (!municipiosDeProvincia.Any()) continue; | ||||
|  | ||||
|             var categoriasParaProcesar = new List<CategoriaElectoral> { categoriaDiputadosNac! }; | ||||
|             if (provinciasQueRenuevanSenadores.Contains(provincia.DistritoId!)) | ||||
|                 categoriasParaProcesar.Add(categoriaSenadoresNac!); | ||||
|  | ||||
|             foreach (var categoria in categoriasParaProcesar) | ||||
|             var provinciasEnDb = await context.AmbitosGeograficos.AsNoTracking().Where(a => a.NivelId == 10).ToListAsync(); | ||||
|             foreach (var provincia in provinciasEnDb) | ||||
|             { | ||||
|                 long totalVotosProvinciaCategoria = 0; | ||||
|                 int partidoIndex = rand.Next(todosLosPartidos.Count); | ||||
|                 foreach (var municipio in municipiosDeProvincia) | ||||
|                 if (!await context.AmbitosGeograficos.AnyAsync(a => a.NivelId == 30 && a.DistritoId == provincia.DistritoId)) | ||||
|                 { | ||||
|                     var partidoGanador = todosLosPartidos[partidoIndex++ % todosLosPartidos.Count]; | ||||
|                     var votosGanador = rand.Next(25000, 70000); | ||||
|                     nuevosResultados.Add(new ResultadoVoto { EleccionId = eleccionNacionalId, AmbitoGeograficoId = municipio.Id, CategoriaId = categoria.Id, AgrupacionPoliticaId = partidoGanador.Id, CantidadVotos = votosGanador }); | ||||
|                     totalVotosProvinciaCategoria += votosGanador; | ||||
|                     var otrosPartidos = todosLosPartidos.Where(p => p.Id != partidoGanador.Id).OrderBy(p => rand.Next()).Take(rand.Next(3, todosLosPartidos.Count)); | ||||
|                     foreach (var competidor in otrosPartidos) | ||||
|                     for (int i = 1; i <= 5; i++) | ||||
|                         context.AmbitosGeograficos.Add(new AmbitoGeografico { Nombre = $"{provincia.Nombre} - Depto. {i}", NivelId = 30, DistritoId = provincia.DistritoId }); | ||||
|                 } | ||||
|             } | ||||
|             await context.SaveChangesAsync(); | ||||
|             logger.LogInformation("--> Datos maestros para Elección Nacional (Ámbitos, Categorías) verificados/creados."); | ||||
|  | ||||
|             // PASO B: GENERAR DATOS TRANSACCIONALES (Votos, Recuentos, etc.) | ||||
|             var todosLosPartidos = await context.AgrupacionesPoliticas.Take(5).ToListAsync(); | ||||
|             if (!todosLosPartidos.Any()) | ||||
|             { | ||||
|                 logger.LogWarning("--> No hay partidos en la BD, no se pueden generar votos de ejemplo."); | ||||
|                 return; // Salir si no hay partidos para evitar errores | ||||
|             } | ||||
|  | ||||
|             // (La lógica interna de generación de votos y recuentos que ya tenías y funcionaba) | ||||
|             // ... (el código de generación de `nuevosResultados` y `nuevosEstados` va aquí, sin cambios) | ||||
|             var nuevosResultados = new List<ResultadoVoto>(); | ||||
|             var nuevosEstados = new List<EstadoRecuentoGeneral>(); | ||||
|             var rand = new Random(); | ||||
|             var provinciasQueRenuevanSenadores = new HashSet<string> { "01", "06", "08", "15", "16", "17", "22", "23" }; | ||||
|             var categoriaDiputadosNac = await context.CategoriasElectorales.FindAsync(2); | ||||
|             var categoriaSenadoresNac = await context.CategoriasElectorales.FindAsync(1); | ||||
|  | ||||
|             long totalVotosNacionalDip = 0, totalVotosNacionalSen = 0; | ||||
|             int totalMesasNacionalDip = 0, totalMesasNacionalSen = 0; | ||||
|             int totalMesasEscrutadasNacionalDip = 0, totalMesasEscrutadasNacionalSen = 0; | ||||
|  | ||||
|             foreach (var provincia in provinciasEnDb) | ||||
|             { | ||||
|                 var municipiosDeProvincia = await context.AmbitosGeograficos.AsNoTracking().Where(a => a.NivelId == 30 && a.DistritoId == provincia.DistritoId).ToListAsync(); | ||||
|                 if (!municipiosDeProvincia.Any()) continue; | ||||
|  | ||||
|                 var categoriasParaProcesar = new List<CategoriaElectoral> { categoriaDiputadosNac! }; | ||||
|                 if (provinciasQueRenuevanSenadores.Contains(provincia.DistritoId!)) | ||||
|                     categoriasParaProcesar.Add(categoriaSenadoresNac!); | ||||
|  | ||||
|                 foreach (var categoria in categoriasParaProcesar) | ||||
|                 { | ||||
|                     long totalVotosProvinciaCategoria = 0; | ||||
|                     int partidoIndex = rand.Next(todosLosPartidos.Count); | ||||
|                     foreach (var municipio in municipiosDeProvincia) | ||||
|                     { | ||||
|                         var votosCompetidor = rand.Next(1000, 24000); | ||||
|                         nuevosResultados.Add(new ResultadoVoto { EleccionId = eleccionNacionalId, AmbitoGeograficoId = municipio.Id, CategoriaId = categoria.Id, AgrupacionPoliticaId = competidor.Id, CantidadVotos = votosCompetidor }); | ||||
|                         totalVotosProvinciaCategoria += votosCompetidor; | ||||
|                         var partidoGanador = todosLosPartidos[partidoIndex++ % todosLosPartidos.Count]; | ||||
|                         var votosGanador = rand.Next(25000, 70000); | ||||
|                         nuevosResultados.Add(new ResultadoVoto { EleccionId = eleccionNacionalId, AmbitoGeograficoId = municipio.Id, CategoriaId = categoria.Id, AgrupacionPoliticaId = partidoGanador.Id, CantidadVotos = votosGanador }); | ||||
|                         totalVotosProvinciaCategoria += votosGanador; | ||||
|                         var otrosPartidos = todosLosPartidos.Where(p => p.Id != partidoGanador.Id).OrderBy(p => rand.Next()).Take(rand.Next(3, todosLosPartidos.Count)); | ||||
|                         foreach (var competidor in otrosPartidos) | ||||
|                         { | ||||
|                             var votosCompetidor = rand.Next(1000, 24000); | ||||
|                             nuevosResultados.Add(new ResultadoVoto { EleccionId = eleccionNacionalId, AmbitoGeograficoId = municipio.Id, CategoriaId = categoria.Id, AgrupacionPoliticaId = competidor.Id, CantidadVotos = votosCompetidor }); | ||||
|                             totalVotosProvinciaCategoria += votosCompetidor; | ||||
|                         } | ||||
|                     } | ||||
|                     var mesasEsperadasProvincia = municipiosDeProvincia.Count * rand.Next(15, 30); | ||||
|                     var mesasTotalizadasProvincia = (int)(mesasEsperadasProvincia * (rand.Next(75, 99) / 100.0)); | ||||
|                     var cantidadElectoresProvincia = mesasEsperadasProvincia * 350; | ||||
|                     var participacionProvincia = (decimal)(rand.Next(65, 85) / 100.0); | ||||
|                     nuevosEstados.Add(new EstadoRecuentoGeneral | ||||
|                     { | ||||
|                         EleccionId = eleccionNacionalId, | ||||
|                         AmbitoGeograficoId = provincia.Id, | ||||
|                         CategoriaId = categoria.Id, | ||||
|                         FechaTotalizacion = DateTime.UtcNow, | ||||
|                         MesasEsperadas = mesasEsperadasProvincia, | ||||
|                         MesasTotalizadas = mesasTotalizadasProvincia, | ||||
|                         MesasTotalizadasPorcentaje = mesasEsperadasProvincia > 0 ? (decimal)mesasTotalizadasProvincia * 100 / mesasEsperadasProvincia : 0, | ||||
|                         CantidadElectores = cantidadElectoresProvincia, | ||||
|                         CantidadVotantes = (int)(cantidadElectoresProvincia * participacionProvincia), | ||||
|                         ParticipacionPorcentaje = participacionProvincia * 100 | ||||
|                     }); | ||||
|                     if (categoriaDiputadosNac != null && categoria.Id == categoriaDiputadosNac.Id) | ||||
|                     { | ||||
|                         totalVotosNacionalDip += totalVotosProvinciaCategoria; totalMesasNacionalDip += mesasEsperadasProvincia; totalMesasEscrutadasNacionalDip += mesasTotalizadasProvincia; | ||||
|                     } | ||||
|                     else | ||||
|                     { | ||||
|                         totalVotosNacionalSen += totalVotosProvinciaCategoria; totalMesasNacionalSen += mesasEsperadasProvincia; totalMesasEscrutadasNacionalSen += mesasTotalizadasProvincia; | ||||
|                     } | ||||
|                 } | ||||
|                 var mesasEsperadasProvincia = municipiosDeProvincia.Count * rand.Next(15, 30); | ||||
|                 var mesasTotalizadasProvincia = (int)(mesasEsperadasProvincia * (rand.Next(75, 99) / 100.0)); | ||||
|                 var cantidadElectoresProvincia = mesasEsperadasProvincia * 350; | ||||
|                 var participacionProvincia = (decimal)(rand.Next(65, 85) / 100.0); | ||||
|             } | ||||
|             var ambitoNacional = await context.AmbitosGeograficos.AsNoTracking().FirstOrDefaultAsync(a => a.NivelId == 0); | ||||
|             if (ambitoNacional != null && categoriaDiputadosNac != null && categoriaSenadoresNac != null) | ||||
|             { | ||||
|                 var participacionNacionalDip = (decimal)(rand.Next(70, 88) / 100.0); | ||||
|                 nuevosEstados.Add(new EstadoRecuentoGeneral | ||||
|                 { | ||||
|                     EleccionId = eleccionNacionalId, | ||||
|                     AmbitoGeograficoId = provincia.Id, | ||||
|                     CategoriaId = categoria.Id, | ||||
|                     AmbitoGeograficoId = ambitoNacional.Id, | ||||
|                     CategoriaId = categoriaDiputadosNac.Id, | ||||
|                     FechaTotalizacion = DateTime.UtcNow, | ||||
|                     MesasEsperadas = mesasEsperadasProvincia, | ||||
|                     MesasTotalizadas = mesasTotalizadasProvincia, | ||||
|                     MesasTotalizadasPorcentaje = mesasEsperadasProvincia > 0 ? (decimal)mesasTotalizadasProvincia * 100 / mesasEsperadasProvincia : 0, | ||||
|                     CantidadElectores = cantidadElectoresProvincia, | ||||
|                     CantidadVotantes = (int)(cantidadElectoresProvincia * participacionProvincia), | ||||
|                     ParticipacionPorcentaje = participacionProvincia * 100 | ||||
|                     MesasEsperadas = totalMesasNacionalDip, | ||||
|                     MesasTotalizadas = totalMesasEscrutadasNacionalDip, | ||||
|                     MesasTotalizadasPorcentaje = totalMesasNacionalDip > 0 ? (decimal)totalMesasEscrutadasNacionalDip * 100 / totalMesasNacionalDip : 0, | ||||
|                     CantidadElectores = totalMesasNacionalDip * 350, | ||||
|                     CantidadVotantes = (int)((totalMesasNacionalDip * 350) * participacionNacionalDip), | ||||
|                     ParticipacionPorcentaje = participacionNacionalDip * 100 | ||||
|                 }); | ||||
|                 if (categoriaDiputadosNac != null && categoria.Id == categoriaDiputadosNac.Id) | ||||
|                 var participacionNacionalSen = (decimal)(rand.Next(70, 88) / 100.0); | ||||
|                 nuevosEstados.Add(new EstadoRecuentoGeneral | ||||
|                 { | ||||
|                     totalVotosNacionalDip += totalVotosProvinciaCategoria; totalMesasNacionalDip += mesasEsperadasProvincia; totalMesasEscrutadasNacionalDip += mesasTotalizadasProvincia; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     totalVotosNacionalSen += totalVotosProvinciaCategoria; totalMesasNacionalSen += mesasEsperadasProvincia; totalMesasEscrutadasNacionalSen += mesasTotalizadasProvincia; | ||||
|                 } | ||||
|                     EleccionId = eleccionNacionalId, | ||||
|                     AmbitoGeograficoId = ambitoNacional.Id, | ||||
|                     CategoriaId = categoriaSenadoresNac.Id, | ||||
|                     FechaTotalizacion = DateTime.UtcNow, | ||||
|                     MesasEsperadas = totalMesasNacionalSen, | ||||
|                     MesasTotalizadas = totalMesasEscrutadasNacionalSen, | ||||
|                     MesasTotalizadasPorcentaje = totalMesasNacionalSen > 0 ? (decimal)totalMesasEscrutadasNacionalSen * 100 / totalMesasNacionalSen : 0, | ||||
|                     CantidadElectores = totalMesasNacionalSen * 350, | ||||
|                     CantidadVotantes = (int)((totalMesasNacionalSen * 350) * participacionNacionalSen), | ||||
|                     ParticipacionPorcentaje = participacionNacionalSen * 100 | ||||
|                 }); | ||||
|             } | ||||
|         } | ||||
|         var ambitoNacional = await context.AmbitosGeograficos.AsNoTracking().FirstOrDefaultAsync(a => a.NivelId == 0); | ||||
|         if (ambitoNacional != null && categoriaDiputadosNac != null && categoriaSenadoresNac != null) | ||||
|         { | ||||
|             var participacionNacionalDip = (decimal)(rand.Next(70, 88) / 100.0); | ||||
|             nuevosEstados.Add(new EstadoRecuentoGeneral | ||||
|             else | ||||
|             { | ||||
|                 EleccionId = eleccionNacionalId, | ||||
|                 AmbitoGeograficoId = ambitoNacional.Id, | ||||
|                 CategoriaId = categoriaDiputadosNac.Id, | ||||
|                 FechaTotalizacion = DateTime.UtcNow, | ||||
|                 MesasEsperadas = totalMesasNacionalDip, | ||||
|                 MesasTotalizadas = totalMesasEscrutadasNacionalDip, | ||||
|                 MesasTotalizadasPorcentaje = totalMesasNacionalDip > 0 ? (decimal)totalMesasEscrutadasNacionalDip * 100 / totalMesasNacionalDip : 0, | ||||
|                 CantidadElectores = totalMesasNacionalDip * 350, | ||||
|                 CantidadVotantes = (int)((totalMesasNacionalDip * 350) * participacionNacionalDip), | ||||
|                 ParticipacionPorcentaje = participacionNacionalDip * 100 | ||||
|             }); | ||||
|             var participacionNacionalSen = (decimal)(rand.Next(70, 88) / 100.0); | ||||
|             nuevosEstados.Add(new EstadoRecuentoGeneral | ||||
|                 logger.LogWarning("--> No se encontró el ámbito nacional (NivelId == 0) o las categorías electorales nacionales. No se agregaron estados nacionales."); | ||||
|             } | ||||
|  | ||||
|             if (nuevosResultados.Any()) | ||||
|             { | ||||
|                 EleccionId = eleccionNacionalId, | ||||
|                 AmbitoGeograficoId = ambitoNacional.Id, | ||||
|                 CategoriaId = categoriaSenadoresNac.Id, | ||||
|                 FechaTotalizacion = DateTime.UtcNow, | ||||
|                 MesasEsperadas = totalMesasNacionalSen, | ||||
|                 MesasTotalizadas = totalMesasEscrutadasNacionalSen, | ||||
|                 MesasTotalizadasPorcentaje = totalMesasNacionalSen > 0 ? (decimal)totalMesasEscrutadasNacionalSen * 100 / totalMesasNacionalSen : 0, | ||||
|                 CantidadElectores = totalMesasNacionalSen * 350, | ||||
|                 CantidadVotantes = (int)((totalMesasNacionalSen * 350) * participacionNacionalSen), | ||||
|                 ParticipacionPorcentaje = participacionNacionalSen * 100 | ||||
|             }); | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             logger.LogWarning("--> No se encontró el ámbito nacional (NivelId == 0) o las categorías electorales nacionales. No se agregaron estados nacionales."); | ||||
|         } | ||||
|                 await context.ResultadosVotos.AddRangeAsync(nuevosResultados); | ||||
|                 await context.EstadosRecuentosGenerales.AddRangeAsync(nuevosEstados); | ||||
|                 await context.SaveChangesAsync(); | ||||
|                 logger.LogInformation("--> Se generaron {Votos} registros de votos y {Estados} de estados de recuento.", nuevosResultados.Count, nuevosEstados.Count); | ||||
|             } | ||||
|  | ||||
|         if (nuevosResultados.Any()) | ||||
|         { | ||||
|             await context.ResultadosVotos.AddRangeAsync(nuevosResultados); | ||||
|             await context.EstadosRecuentosGenerales.AddRangeAsync(nuevosEstados); | ||||
|             await context.SaveChangesAsync(); | ||||
|             logger.LogInformation("--> Se generaron {Votos} registros de votos y {Estados} de estados de recuento.", nuevosResultados.Count, nuevosEstados.Count); | ||||
|         } | ||||
|  | ||||
|         // PASO C: GENERAR BANCAS PREVIAS Y PROYECCIONES | ||||
|         if (!await context.BancasPrevias.AnyAsync(b => b.EleccionId == eleccionNacionalId)) | ||||
|         { | ||||
|             var bancasPrevias = new List<BancaPrevia> { | ||||
|             // PASO C: GENERAR BANCAS PREVIAS Y PROYECCIONES | ||||
|             if (!await context.BancasPrevias.AnyAsync(b => b.EleccionId == eleccionNacionalId)) | ||||
|             { | ||||
|                 var bancasPrevias = new List<BancaPrevia> { | ||||
|                 new() { EleccionId = eleccionNacionalId, Camara = TipoCamara.Diputados, AgrupacionPoliticaId = todosLosPartidos[0].Id, Cantidad = 40 }, | ||||
|                 new() { EleccionId = eleccionNacionalId, Camara = TipoCamara.Diputados, AgrupacionPoliticaId = todosLosPartidos[1].Id, Cantidad = 35 }, | ||||
|                 new() { EleccionId = eleccionNacionalId, Camara = TipoCamara.Diputados, AgrupacionPoliticaId = todosLosPartidos[2].Id, Cantidad = 30 }, | ||||
| @@ -392,9 +397,10 @@ using (var scope = app.Services.CreateScope()) | ||||
|                 new() { EleccionId = eleccionNacionalId, Camara = TipoCamara.Senadores, AgrupacionPoliticaId = todosLosPartidos[3].Id, Cantidad = 4 }, | ||||
|                 new() { EleccionId = eleccionNacionalId, Camara = TipoCamara.Senadores, AgrupacionPoliticaId = todosLosPartidos[4].Id, Cantidad = 3 }, | ||||
|             }; | ||||
|             await context.BancasPrevias.AddRangeAsync(bancasPrevias); | ||||
|             await context.SaveChangesAsync(); | ||||
|             logger.LogInformation("--> Seeded Bancas Previas para la Elección Nacional."); | ||||
|                 await context.BancasPrevias.AddRangeAsync(bancasPrevias); | ||||
|                 await context.SaveChangesAsync(); | ||||
|                 logger.LogInformation("--> Seeded Bancas Previas para la Elección Nacional."); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -14,7 +14,7 @@ using System.Reflection; | ||||
| [assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] | ||||
| [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+a316e5dd0876a581437b08d9980b658cc714da90")] | ||||
| [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+84f764390766e1d9716a38464ee478f3d0b75f96")] | ||||
| [assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")] | ||||
| [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] | ||||
|   | ||||
| @@ -1 +1 @@ | ||||
| {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","M5oop6AzAA5LmqkUXPrT16q3xF0Jty6n7nfGWkjXG94="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| {"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","Zf7uND\u002BRw1vwmlJX6vYl9l2j52U48b1N59mSoDoOeFU=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","ViGA16LZjzGiizSwwZApo6OQjv5hBNvl3QW/ISbKUWM="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| @@ -1 +1 @@ | ||||
| {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","M5oop6AzAA5LmqkUXPrT16q3xF0Jty6n7nfGWkjXG94="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
| {"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["YB39loxHH43S4MF8aTOiogcIbBAIq5Qj3dlJkIfYVxI=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","Of8nTYw5l\u002BgiAJo7z6XYIntG2tUtCFcILzHbTiiXn\u002Bw=","PDy\u002BTiayvNAoXXBEgwC/kCojpgOOMI6RQOIoSXs3LJc=","ePXrkee3hv3wHUr8S7aYmRVvXUTxQf76zApKGv3/l3o=","DXx5dQywLo3UsY2zQaUG\u002BbW4ObiYbybxPBWxeJD2bhk=","muVh5sjH3sgdvuz4TbuTwTggX1uDnsWXgoosMKST/r4=","nrP5gSIA5vzgp8v12CAOr943QYLxU4Til6oiCcWSNI8=","yMd45U9BK07I3b3fBQ627PWTYyZ2ZjrmFc5VD\u002BQVx1Q=","xKskvcoJU0RVRN1a5dRqKRM7IP5vmmbraUaPFYjhnCc=","p7BjQw7aSZjfOCqmKm7/kPO9qegEQZBfirMjlOx/I1I=","MI0hVVLYavEhzHq/Z1UbajfrxanA1aET19aOH8G2ImI=","2dY8CqW9fAY8yN0foa\u002BZp2gc0RfPoPmB/tKSj1QoTw0=","79rfGLH4UjfTPvc//\u002BZjnBqdz585pUtYZ0/hwE2iEic=","PUqgvMdfTQkF5lpBVtHv2teQLV5WaEH0xMKTmINe2YQ=","\u002BFI0b4ppdxel/pby/y/xKImHrtdxo2g83OhskdREyIg=","jEESu6\u002BhbDvNMjLt/6OufuK\u002B9cHmzx\u002BTCIn4fWa9nSc=","UaCPJEvR4nVxxGCB5CUnRlJiw4drDW3Q3Nss\u002Bya2cv4=","ZqF13CT3rok/Gzl\u002BMsw3q9X1nf65bwEVD670efE3k\u002Bk=","gH3W7phPzBCY1DAVn4YnP4SA8Uaq73TpctS0yFSvzNM=","u5F4J4\u002BLHUIOCz5ze5NSF42mDeAaAfi\u002BKN3Ay3rKLY8=","GeUUID0ymF5rrBWdX7YHzWA5GiGkNWCNUog4sp4xL3c=","3BxX4I0JXoDqmE8m0BrRZhixBRlHEueS3jAlmUXE/I8=","IlET7uqumshgFxIEvfKRskON\u002BeAKZ7OfD/kCeAwn0PM=","NN2rS\u002B89ZAITWlNODPcF/lHIh3ZNmAHvUX4EjqSkX4s=","OE89N/FsYhRU1Dy5Ne83ehzSwlNc/RcxHrJpHxPHfqY=","QI7IL4TkYEqfUiIEXQiVCaZx4vrM9/wZlvOrhnUd4jQ=","UIntj4QoiyGr7bnJN8KK5PGrhQd89m\u002BLfh4T8VKPxAk=","Zf7uND\u002BRw1vwmlJX6vYl9l2j52U48b1N59mSoDoOeFU=","BY4GeeFiQbYpWuSzb2XIY4JatmLNOZ6dhKs4ZT92nsM=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","ViGA16LZjzGiizSwwZApo6OQjv5hBNvl3QW/ISbKUWM="],"CachedAssets":{},"CachedCopyCandidates":{}} | ||||
		Reference in New Issue
	
	Block a user