diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
index 8e3c38c..551752b 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/Elecciones.Api.AssemblyInfo.cs
@@ -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+8bb8a5dede4317ced11cea3a8f94c60f52aae18e")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
index 30e056e..a20a2b0 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmcshtml.dswa.cache.json
@@ -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=","RHA7Sn\u002BBPhg/0ggRGaPs3zisENV95kflY7QYn6W0Zh4=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","FRMUpBvV6x/7QVk3Omkda30ILFYfD05f5dk1HcnqQW0="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
+{"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":{}}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
index b4a842a..58b0034 100644
--- a/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
+++ b/Elecciones-Web/src/Elecciones.Api/obj/Debug/net9.0/rjsmrazor.dswa.cache.json
@@ -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=","RHA7Sn\u002BBPhg/0ggRGaPs3zisENV95kflY7QYn6W0Zh4=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","FRMUpBvV6x/7QVk3Omkda30ILFYfD05f5dk1HcnqQW0="],"CachedAssets":{},"CachedCopyCandidates":{}}
\ No newline at end of file
+{"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":{}}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
index aca2029..28a3576 100644
--- a/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Core/obj/Debug/net9.0/Elecciones.Core.AssemblyInfo.cs
@@ -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+8bb8a5dede4317ced11cea3a8f94c60f52aae18e")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Database/Entities/ProyeccionBanca.cs b/Elecciones-Web/src/Elecciones.Database/Entities/ProyeccionBanca.cs
index 48373ed..0b8d7af 100644
--- a/Elecciones-Web/src/Elecciones.Database/Entities/ProyeccionBanca.cs
+++ b/Elecciones-Web/src/Elecciones.Database/Entities/ProyeccionBanca.cs
@@ -23,4 +23,5 @@ public class ProyeccionBanca
// Cantidad de bancas obtenidas
public int NroBancas { get; set; }
+ public DateTime FechaTotalizacion { get; set; }
}
\ No newline at end of file
diff --git a/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.Designer.cs b/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.Designer.cs
new file mode 100644
index 0000000..23f5125
--- /dev/null
+++ b/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.Designer.cs
@@ -0,0 +1,377 @@
+//
+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("20250823155053_AddFechaTotalizacionToProyeccionesBancas")]
+ partial class AddFechaTotalizacionToProyeccionesBancas
+ {
+ ///
+ 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("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("IdTelegrama")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Nombre")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AgrupacionesPoliticas");
+ });
+
+ modelBuilder.Entity("Elecciones.Database.Entities.AmbitoGeografico", b =>
+ {
+ b.Property("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("CircuitoId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("DistritoId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("EstablecimientoId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("MesaId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("MunicipioId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("NivelId")
+ .HasColumnType("int");
+
+ b.Property("Nombre")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("SeccionId")
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("SeccionProvincialId")
+ .HasColumnType("nvarchar(max)");
+
+ b.HasKey("Id");
+
+ b.ToTable("AmbitosGeograficos");
+ });
+
+ modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("int");
+
+ b.Property("Nombre")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("Orden")
+ .HasColumnType("int");
+
+ b.HasKey("Id");
+
+ b.ToTable("CategoriasElectorales");
+ });
+
+ modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
+ {
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("CategoriaId")
+ .HasColumnType("int");
+
+ b.Property("CantidadElectores")
+ .HasColumnType("int");
+
+ b.Property("CantidadVotantes")
+ .HasColumnType("int");
+
+ b.Property("FechaTotalizacion")
+ .HasColumnType("datetime2");
+
+ b.Property("MesasEsperadas")
+ .HasColumnType("int");
+
+ b.Property("MesasTotalizadas")
+ .HasColumnType("int");
+
+ b.Property("MesasTotalizadasPorcentaje")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.Property("ParticipacionPorcentaje")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.Property("VotosEnBlanco")
+ .HasColumnType("bigint");
+
+ b.Property("VotosEnBlancoPorcentaje")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("VotosNulos")
+ .HasColumnType("bigint");
+
+ b.Property("VotosNulosPorcentaje")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.Property("VotosRecurridos")
+ .HasColumnType("bigint");
+
+ b.Property("VotosRecurridosPorcentaje")
+ .HasPrecision(18, 4)
+ .HasColumnType("decimal(18,4)");
+
+ b.HasKey("AmbitoGeograficoId", "CategoriaId");
+
+ b.ToTable("EstadosRecuentos");
+ });
+
+ modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
+ {
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("CategoriaId")
+ .HasColumnType("int");
+
+ b.Property("CantidadElectores")
+ .HasColumnType("int");
+
+ b.Property("CantidadVotantes")
+ .HasColumnType("int");
+
+ b.Property("MesasEsperadas")
+ .HasColumnType("int");
+
+ b.Property("MesasTotalizadas")
+ .HasColumnType("int");
+
+ b.Property("MesasTotalizadasPorcentaje")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AgrupacionPoliticaId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("CategoriaId")
+ .HasColumnType("int");
+
+ b.Property("FechaTotalizacion")
+ .HasColumnType("datetime2");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AgrupacionPoliticaId")
+ .IsRequired()
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("CantidadVotos")
+ .HasColumnType("bigint");
+
+ b.Property("CategoriaId")
+ .HasColumnType("int");
+
+ b.Property("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("Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"));
+
+ b.Property("AgrupacionPoliticaId")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("Votos")
+ .HasColumnType("bigint");
+
+ b.Property("VotosPorcentaje")
+ .HasPrecision(5, 2)
+ .HasColumnType("decimal(5,2)");
+
+ b.HasKey("Id");
+
+ b.ToTable("ResumenesVotos");
+ });
+
+ modelBuilder.Entity("Elecciones.Database.Entities.Telegrama", b =>
+ {
+ b.Property("Id")
+ .HasColumnType("nvarchar(450)");
+
+ b.Property("AmbitoGeograficoId")
+ .HasColumnType("int");
+
+ b.Property("ContenidoBase64")
+ .IsRequired()
+ .HasColumnType("nvarchar(max)");
+
+ b.Property("FechaEscaneo")
+ .HasColumnType("datetime2");
+
+ b.Property("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
+ }
+ }
+}
diff --git a/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.cs b/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.cs
new file mode 100644
index 0000000..93254e1
--- /dev/null
+++ b/Elecciones-Web/src/Elecciones.Database/Migrations/20250823155053_AddFechaTotalizacionToProyeccionesBancas.cs
@@ -0,0 +1,30 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Elecciones.Database.Migrations
+{
+ ///
+ public partial class AddFechaTotalizacionToProyeccionesBancas : Migration
+ {
+ ///
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "FechaTotalizacion",
+ table: "ProyeccionesBancas",
+ type: "datetime2",
+ nullable: false,
+ defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
+ }
+
+ ///
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "FechaTotalizacion",
+ table: "ProyeccionesBancas");
+ }
+ }
+}
diff --git a/Elecciones-Web/src/Elecciones.Database/Migrations/EleccionesDbContextModelSnapshot.cs b/Elecciones-Web/src/Elecciones.Database/Migrations/EleccionesDbContextModelSnapshot.cs
index 2252200..1aedc84 100644
--- a/Elecciones-Web/src/Elecciones.Database/Migrations/EleccionesDbContextModelSnapshot.cs
+++ b/Elecciones-Web/src/Elecciones.Database/Migrations/EleccionesDbContextModelSnapshot.cs
@@ -208,6 +208,9 @@ namespace Elecciones.Database.Migrations
b.Property("CategoriaId")
.HasColumnType("int");
+ b.Property("FechaTotalizacion")
+ .HasColumnType("datetime2");
+
b.Property("NroBancas")
.HasColumnType("int");
diff --git a/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
index 3742647..28ce639 100644
--- a/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Database/obj/Debug/net9.0/Elecciones.Database.AssemblyInfo.cs
@@ -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+8bb8a5dede4317ced11cea3a8f94c60f52aae18e")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs b/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
index 22d8dbc..120a79a 100644
--- a/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
+++ b/Elecciones-Web/src/Elecciones.Infrastructure/obj/Debug/net9.0/Elecciones.Infrastructure.AssemblyInfo.cs
@@ -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+8bb8a5dede4317ced11cea3a8f94c60f52aae18e")]
+[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+303a469c57fa05bb9274569591bd4dc9aeb9f240")]
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
diff --git a/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs b/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs
index 3a3ace3..008db13 100644
--- a/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs
+++ b/Elecciones-Web/src/Elecciones.Worker/LowPriorityDataWorker.cs
@@ -239,26 +239,10 @@ public class LowPriorityDataWorker : BackgroundService
- ///
- /// Sondea la proyección de bancas. Este método ahora es más completo:
- /// 1. Consulta el reparto de bancas a nivel PROVINCIAL para cada categoría.
- /// 2. Consulta el reparto de bancas desglosado por SECCIÓN ELECTORAL para cada categoría.
- ///
///
/// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral.
- /// Esta versión recolecta todos los datos disponibles y los guarda en una única transacción.
- ///
- ///
- /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral.
- /// Esta versión incluye logging detallado para diagnosticar problemas de deserialización
- /// o respuestas inesperadas de la API, y guarda los datos en una transacción atómica.
- ///
- /// El token de autenticación válido para la sesión.
- /// El token de cancelación para detener la operación.
- ///
- /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral.
- /// Esta versión guarda la CategoriaId junto con cada proyección para poder distinguir
- /// entre diferentes elecciones (ej. Senadores vs. Diputados).
+ /// 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.
///
/// El token de autenticación válido para la sesión.
/// El token de cancelación para detener la operación.
@@ -266,30 +250,23 @@ public class LowPriorityDataWorker : BackgroundService
{
try
{
- // Usamos un scope de DbContext para esta operación, asegurando una conexión limpia.
using var scope = _serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService();
- // 1. OBTENER DATOS DE CONFIGURACIÓN DE NUESTRA BD
-
- // Buscamos las categorías que reparten bancas (Senadores y Diputados).
var categoriasDeBancas = await dbContext.CategoriasElectorales
.AsNoTracking()
.Where(c => c.Nombre.Contains("SENADORES") || c.Nombre.Contains("DIPUTADOS"))
.ToListAsync(stoppingToken);
- // Obtenemos el registro de la Provincia para hacer la consulta a nivel provincial.
var provincia = await dbContext.AmbitosGeograficos
.AsNoTracking()
.FirstOrDefaultAsync(a => a.NivelId == 10, stoppingToken);
- // Obtenemos todas las Secciones Electorales para hacer las consultas por sección.
var seccionesElectorales = await dbContext.AmbitosGeograficos
.AsNoTracking()
.Where(a => a.NivelId == 20 && a.DistritoId != null && a.SeccionProvincialId != null)
.ToListAsync(stoppingToken);
- // Si falta alguna configuración base, no podemos continuar.
if (!categoriasDeBancas.Any() || provincia == null)
{
_logger.LogWarning("No se encontraron categorías de bancas o el ámbito provincial en la BD. Omitiendo sondeo de bancas.");
@@ -298,25 +275,32 @@ public class LowPriorityDataWorker : BackgroundService
_logger.LogInformation("Iniciando sondeo de Bancas a nivel Provincial y para {count} Secciones Electorales...", seccionesElectorales.Count);
- // 2. RECOLECTAR DATOS DE LA API
-
- // Una lista para acumular todas las proyecciones que encontremos.
var todasLasProyecciones = new List();
- // Una bandera para saber si hemos recibido al menos una banca con datos.
bool hasReceivedAnyNewData = false;
// Bucle para el nivel Provincial
foreach (var categoria in categoriasDeBancas)
{
if (stoppingToken.IsCancellationRequested) break;
+ var repartoBancasDto = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, categoria.Id);
- var repartoBancas = await _apiService.GetBancasAsync(authToken, provincia.DistritoId!, null, categoria.Id);
-
- if (repartoBancas?.RepartoBancas is { Count: > 0 } bancas)
+ if (repartoBancasDto?.RepartoBancas is { Count: > 0 } bancas)
{
- _logger.LogInformation("Se encontraron {count} registros de bancas a nivel provincial para la categoría {catId}.", bancas.Count, categoria.Id);
hasReceivedAnyNewData = true;
+ // --- CORRECCIÓN DE SEGURIDAD: Usar TryParse para la fecha ---
+ DateTime fechaTotalizacion;
+ if (!DateTime.TryParse(repartoBancasDto.FechaTotalizacion, out var parsedDate))
+ {
+ // Si la fecha es inválida (nula, vacía, mal formada), lo registramos y usamos la hora actual como respaldo.
+ _logger.LogWarning("No se pudo parsear FechaTotalizacion ('{dateString}') para bancas provinciales. Usando la hora actual.", repartoBancasDto.FechaTotalizacion);
+ fechaTotalizacion = DateTime.UtcNow;
+ }
+ else
+ {
+ fechaTotalizacion = parsedDate.ToUniversalTime();
+ }
+
foreach (var banca in bancas)
{
todasLasProyecciones.Add(new ProyeccionBanca
@@ -324,7 +308,8 @@ public class LowPriorityDataWorker : BackgroundService
AmbitoGeograficoId = provincia.Id,
AgrupacionPoliticaId = banca.IdAgrupacion,
NroBancas = banca.NroBancas,
- CategoriaId = categoria.Id // <-- CORRECCIÓN: Se guarda la CategoriaId
+ CategoriaId = categoria.Id,
+ FechaTotalizacion = fechaTotalizacion
});
}
}
@@ -337,11 +322,24 @@ public class LowPriorityDataWorker : BackgroundService
foreach (var categoria in categoriasDeBancas)
{
if (stoppingToken.IsCancellationRequested) break;
- var repartoBancas = await _apiService.GetBancasAsync(authToken, seccion.DistritoId!, seccion.SeccionProvincialId!, categoria.Id);
+ var repartoBancasDto = await _apiService.GetBancasAsync(authToken, seccion.DistritoId!, seccion.SeccionProvincialId!, categoria.Id);
- if (repartoBancas?.RepartoBancas is { Count: > 0 } bancas)
+ if (repartoBancasDto?.RepartoBancas is { Count: > 0 } bancas)
{
hasReceivedAnyNewData = true;
+
+ // --- APLICAMOS LA MISMA CORRECCIÓN DE SEGURIDAD AQUÍ ---
+ DateTime fechaTotalizacion;
+ if (!DateTime.TryParse(repartoBancasDto.FechaTotalizacion, out var parsedDate))
+ {
+ _logger.LogWarning("No se pudo parsear FechaTotalizacion ('{dateString}') para bancas de sección. Usando la hora actual.", repartoBancasDto.FechaTotalizacion);
+ fechaTotalizacion = DateTime.UtcNow;
+ }
+ else
+ {
+ fechaTotalizacion = parsedDate.ToUniversalTime();
+ }
+
foreach (var banca in bancas)
{
todasLasProyecciones.Add(new ProyeccionBanca
@@ -349,20 +347,17 @@ public class LowPriorityDataWorker : BackgroundService
AmbitoGeograficoId = seccion.Id,
AgrupacionPoliticaId = banca.IdAgrupacion,
NroBancas = banca.NroBancas,
- CategoriaId = categoria.Id // <-- CORRECCIÓN: Se guarda la CategoriaId
+ CategoriaId = categoria.Id,
+ FechaTotalizacion = fechaTotalizacion
});
}
}
}
}
- // 3. GUARDAR DATOS EN LA BASE DE DATOS
-
- // Solo procedemos a escribir en la BD si la bandera se activó.
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);
await dbContext.Database.ExecuteSqlRawAsync("DELETE FROM ProyeccionesBancas", stoppingToken);