Fix fecha totalizados nivel provincia
This commit is contained in:
@@ -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+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+13c6accd156385dfc057e9dd765349535f494139")]
|
||||
[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":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","\u002B1WVFC1fp/70404bSmvblp/iQiRDfBqAK2zILDLIK04=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","NjY7JdiCu55MOnreQavF53Y5DhSnDcSEpiAcbi6UO60="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/dERIyc1JOhwFtrVKNy7mb/2h9NWmiwO1FwPtFm4Im0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","yTq/Ml6GIPmYajoAWVY9apLuQ9\u002B9//ZN/AKmDBmwvBg="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","\u002B1WVFC1fp/70404bSmvblp/iQiRDfBqAK2zILDLIK04=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","NjY7JdiCu55MOnreQavF53Y5DhSnDcSEpiAcbi6UO60="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["Dji\u002Bta/0e7zUKw3oe\u002BriV3kbWxZ93FP2z2QIYsHXTl4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/dERIyc1JOhwFtrVKNy7mb/2h9NWmiwO1FwPtFm4Im0=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","yTq/Ml6GIPmYajoAWVY9apLuQ9\u002B9//ZN/AKmDBmwvBg="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -3,17 +3,25 @@ using System.Collections.Generic;
|
||||
|
||||
namespace Elecciones.Core.DTOs;
|
||||
|
||||
// DTO para la respuesta del endpoint /resultados/getResumen
|
||||
public class ResumenDto
|
||||
{
|
||||
[JsonPropertyName("fechaTotalizacion")]
|
||||
public string FechaTotalizacion { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("estadoRecuento")]
|
||||
public EstadoRecuentoDto EstadoRecuento { get; set; } = new();
|
||||
|
||||
[JsonPropertyName("valoresTotalizadosPositivos")]
|
||||
public List<ResumenPositivoDto> ValoresTotalizadosPositivos { get; set; } = [];
|
||||
public List<ResumenVotosPositivosDto> ValoresTotalizadosPositivos { get; set; } = [];
|
||||
}
|
||||
|
||||
public class ResumenPositivoDto
|
||||
// DTO específico para los objetos dentro de la lista "valoresTotalizadosPositivos" de /getResumen
|
||||
public class ResumenVotosPositivosDto
|
||||
{
|
||||
[JsonPropertyName("idAgrupacion")]
|
||||
public string IdAgrupacion { get; set; } = null!;
|
||||
|
||||
public string IdAgrupacion { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("votos")]
|
||||
public long Votos { get; set; }
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+13c6accd156385dfc057e9dd765349535f494139")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -8,6 +8,7 @@ public class EstadoRecuentoGeneral
|
||||
{
|
||||
public int AmbitoGeograficoId { get; set; }
|
||||
public int CategoriaId { get; set; }
|
||||
public DateTime FechaTotalizacion { get; set; }
|
||||
public int MesasEsperadas { get; set; }
|
||||
public int MesasTotalizadas { get; set; }
|
||||
public decimal MesasTotalizadasPorcentaje { get; set; }
|
||||
|
||||
@@ -0,0 +1,380 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Elecciones.Database;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
[DbContext(typeof(EleccionesDbContext))]
|
||||
[Migration("20250823160853_AddFechaTotalizacionToEstadoGeneral")]
|
||||
partial class AddFechaTotalizacionToEstadoGeneral
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "9.0.8")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.AgrupacionPolitica", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<string>("IdTelegrama")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AgrupacionesPoliticas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.AmbitoGeografico", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("CircuitoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("DistritoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("EstablecimientoId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("MesaId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("MunicipioId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("NivelId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SeccionId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("SeccionProvincialId")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("AmbitosGeograficos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("Orden")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("CategoriasElectorales");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||
{
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadElectores")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadVotantes")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("MesasEsperadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MesasTotalizadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<decimal>("ParticipacionPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<long>("VotosEnBlanco")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosEnBlancoPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.Property<long>("VotosNulos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosNulosPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.Property<long>("VotosRecurridos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosRecurridosPorcentaje")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||
|
||||
b.ToTable("EstadosRecuentos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||
{
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadElectores")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CantidadVotantes")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("MesasEsperadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("MesasTotalizadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.Property<decimal>("ParticipacionPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||
|
||||
b.HasIndex("CategoriaId");
|
||||
|
||||
b.ToTable("EstadosRecuentosGenerales");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("NroBancas")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId");
|
||||
|
||||
b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ProyeccionesBancas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||
{
|
||||
b.Property<long>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("bigint");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("CantidadVotos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<int>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<decimal>("PorcentajeVotos")
|
||||
.HasPrecision(18, 4)
|
||||
.HasColumnType("decimal(18,4)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId");
|
||||
|
||||
b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("ResultadosVotos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<long>("Votos")
|
||||
.HasColumnType("bigint");
|
||||
|
||||
b.Property<decimal>("VotosPorcentaje")
|
||||
.HasPrecision(5, 2)
|
||||
.HasColumnType("decimal(5,2)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("ResumenesVotos");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.Telegrama", b =>
|
||||
{
|
||||
b.Property<string>("Id")
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("ContenidoBase64")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<DateTime>("FechaEscaneo")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Telegramas");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral")
|
||||
.WithMany()
|
||||
.HasForeignKey("CategoriaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("CategoriaElectoral");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||
.WithMany()
|
||||
.HasForeignKey("AgrupacionPoliticaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AgrupacionPolitica");
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||
{
|
||||
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||
.WithMany()
|
||||
.HasForeignKey("AgrupacionPoliticaId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||
.WithMany()
|
||||
.HasForeignKey("AmbitoGeograficoId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("AgrupacionPolitica");
|
||||
|
||||
b.Navigation("AmbitoGeografico");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddFechaTotalizacionToEstadoGeneral : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "FechaTotalizacion",
|
||||
table: "EstadosRecuentosGenerales",
|
||||
type: "datetime2",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "FechaTotalizacion",
|
||||
table: "EstadosRecuentosGenerales");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,6 +169,9 @@ namespace Elecciones.Database.Migrations
|
||||
b.Property<int>("CantidadVotantes")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("FechaTotalizacion")
|
||||
.HasColumnType("datetime2");
|
||||
|
||||
b.Property<int>("MesasEsperadas")
|
||||
.HasColumnType("int");
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+13c6accd156385dfc057e9dd765349535f494139")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+13c6accd156385dfc057e9dd765349535f494139")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -184,59 +184,119 @@ public class CriticalDataWorker : BackgroundService
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Obtiene y actualiza el resumen de votos a nivel provincial.
|
||||
/// Esta versión mejorada utiliza una transacción para garantizar la consistencia de los datos.
|
||||
/// Obtiene y actualiza el resumen de votos y el estado del recuento a nivel provincial.
|
||||
/// Esta versión actualizada guarda tanto los votos por agrupación (en ResumenesVotos)
|
||||
/// como el estado general del recuento, incluyendo la fecha de totalización (en EstadosRecuentosGenerales),
|
||||
/// asegurando que toda la operación sea atómica mediante una transacción de base de datos.
|
||||
/// </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 SondearResumenProvincialAsync(string authToken, CancellationToken stoppingToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Creamos un scope de DbContext para esta operación.
|
||||
using var scope = _serviceProvider.CreateScope();
|
||||
var dbContext = scope.ServiceProvider.GetRequiredService<EleccionesDbContext>();
|
||||
|
||||
var provincia = await dbContext.AmbitosGeograficos.AsNoTracking().FirstOrDefaultAsync(a => a.NivelId == 10, stoppingToken);
|
||||
if (provincia == null) return;
|
||||
// Obtenemos el registro de la Provincia (NivelId 10).
|
||||
var provincia = await dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.FirstOrDefaultAsync(a => a.NivelId == 10, stoppingToken);
|
||||
|
||||
var resumen = await _apiService.GetResumenAsync(authToken, provincia.DistritoId!);
|
||||
|
||||
// --- CAMBIO CLAVE: Lógica de actualización robusta ---
|
||||
// Solo procedemos si la respuesta de la API es válida Y contiene datos de votos positivos.
|
||||
if (resumen?.ValoresTotalizadosPositivos is { Count: > 0 } nuevosVotos)
|
||||
// Si no encontramos el ámbito de la provincia, no podemos continuar.
|
||||
if (provincia == null)
|
||||
{
|
||||
// Usamos una transacción explícita para asegurar que la operación sea atómica:
|
||||
// O se completa todo (borrado e inserción), o no se hace nada.
|
||||
_logger.LogWarning("No se encontró el ámbito 'Provincia' (NivelId 10) para el sondeo de resumen.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Llamamos a la API para obtener el resumen de datos provincial.
|
||||
var resumenDto = await _apiService.GetResumenAsync(authToken, provincia.DistritoId!);
|
||||
|
||||
// Solo procedemos si la API devolvió una respuesta válida y no nula.
|
||||
if (resumenDto != null)
|
||||
{
|
||||
// Iniciamos una transacción explícita. Esto garantiza que todas las operaciones de base de datos
|
||||
// dentro de este bloque (el DELETE, los INSERTs y los UPDATEs) se completen con éxito,
|
||||
// o si algo falla, se reviertan todas, manteniendo la consistencia de los datos.
|
||||
await using var transaction = await dbContext.Database.BeginTransactionAsync(stoppingToken);
|
||||
|
||||
// 1. Borramos los datos viejos.
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ResumenesVotos", stoppingToken);
|
||||
// --- 1. ACTUALIZAR LA TABLA 'ResumenesVotos' ---
|
||||
|
||||
// 2. Insertamos los nuevos datos.
|
||||
foreach (var voto in nuevosVotos)
|
||||
// Verificamos si la respuesta contiene una lista de votos positivos.
|
||||
if (resumenDto.ValoresTotalizadosPositivos is { Count: > 0 } nuevosVotos)
|
||||
{
|
||||
dbContext.ResumenesVotos.Add(new ResumenVoto
|
||||
// Estrategia "Borrar y Reemplazar": vaciamos la tabla antes de insertar los nuevos datos.
|
||||
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ResumenesVotos", stoppingToken);
|
||||
|
||||
// Añadimos cada nuevo registro de voto al DbContext.
|
||||
foreach (var voto in nuevosVotos)
|
||||
{
|
||||
AmbitoGeograficoId = provincia.Id,
|
||||
AgrupacionPoliticaId = voto.IdAgrupacion,
|
||||
Votos = voto.Votos,
|
||||
VotosPorcentaje = voto.VotosPorcentaje
|
||||
});
|
||||
dbContext.ResumenesVotos.Add(new ResumenVoto
|
||||
{
|
||||
AmbitoGeograficoId = provincia.Id,
|
||||
AgrupacionPoliticaId = voto.IdAgrupacion,
|
||||
Votos = voto.Votos,
|
||||
VotosPorcentaje = voto.VotosPorcentaje
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Guardamos los cambios y confirmamos la transacción.
|
||||
// --- 2. ACTUALIZAR LA TABLA 'EstadosRecuentosGenerales' ---
|
||||
|
||||
// El endpoint de Resumen no especifica una categoría, por lo que aplicamos sus datos de estado de recuento
|
||||
// a todas las categorías que tenemos en nuestra base de datos.
|
||||
var todasLasCategorias = await dbContext.CategoriasElectorales.AsNoTracking().ToListAsync(stoppingToken);
|
||||
foreach (var categoria in todasLasCategorias)
|
||||
{
|
||||
// Buscamos el registro existente usando la clave primaria compuesta.
|
||||
var registroDb = await dbContext.EstadosRecuentosGenerales.FindAsync(new object[] { provincia.Id, categoria.Id }, stoppingToken);
|
||||
|
||||
// Si no existe, lo creamos.
|
||||
if (registroDb == null)
|
||||
{
|
||||
registroDb = new EstadoRecuentoGeneral { AmbitoGeograficoId = provincia.Id, CategoriaId = categoria.Id };
|
||||
dbContext.EstadosRecuentosGenerales.Add(registroDb);
|
||||
}
|
||||
|
||||
// Parseamos la fecha de forma segura para evitar errores con cadenas vacías o nulas.
|
||||
if (DateTime.TryParse(resumenDto.FechaTotalizacion, out var parsedDate))
|
||||
{
|
||||
registroDb.FechaTotalizacion = parsedDate.ToUniversalTime();
|
||||
}
|
||||
|
||||
// Mapeamos el resto de los datos del estado del recuento.
|
||||
registroDb.MesasEsperadas = resumenDto.EstadoRecuento.MesasEsperadas;
|
||||
registroDb.MesasTotalizadas = resumenDto.EstadoRecuento.MesasTotalizadas;
|
||||
registroDb.MesasTotalizadasPorcentaje = resumenDto.EstadoRecuento.MesasTotalizadasPorcentaje;
|
||||
registroDb.CantidadElectores = resumenDto.EstadoRecuento.CantidadElectores;
|
||||
registroDb.CantidadVotantes = resumenDto.EstadoRecuento.CantidadVotantes;
|
||||
registroDb.ParticipacionPorcentaje = resumenDto.EstadoRecuento.ParticipacionPorcentaje;
|
||||
}
|
||||
|
||||
// 3. CONFIRMAR Y GUARDAR
|
||||
// Guardamos todos los cambios preparados (DELETEs, INSERTs, UPDATEs) en la base de datos.
|
||||
await dbContext.SaveChangesAsync(stoppingToken);
|
||||
// Confirmamos la transacción para hacer los cambios permanentes.
|
||||
await transaction.CommitAsync(stoppingToken);
|
||||
|
||||
_logger.LogInformation("Sondeo de Resumen Provincial completado. La tabla ha sido actualizada.");
|
||||
_logger.LogInformation("Sondeo de Resumen Provincial completado. Las tablas han sido actualizadas.");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Si la API no devuelve datos de votos, no hacemos NADA en la base de datos.
|
||||
_logger.LogInformation("Sondeo de Resumen Provincial completado. No se recibieron datos nuevos, la tabla no fue modificada.");
|
||||
// Si la API no devolvió datos (ej. devuelve null), no hacemos nada en la BD.
|
||||
_logger.LogInformation("Sondeo de Resumen Provincial completado. No se recibieron datos nuevos.");
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
_logger.LogInformation("Sondeo de resumen provincial cancelado.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "Ocurrió un error en el sondeo de Resumen Provincial.");
|
||||
// Capturamos cualquier otro error inesperado para que el worker no se detenga.
|
||||
_logger.LogError(ex, "Ocurrió un error CRÍTICO en el sondeo de Resumen Provincial.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user