2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								//Elecciones.Worker/CriticalDataWorker.cs  
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Database ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Database.Entities ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Elecciones.Infrastructure.Services ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  Microsoft.EntityFrameworkCore ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								using  System.Collections.Concurrent ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								namespace  Elecciones.Worker ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								public  class  CriticalDataWorker  :  BackgroundService  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								{  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  ILogger < CriticalDataWorker >  _logger ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  SharedTokenService  _tokenService ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  readonly  IServiceProvider  _serviceProvider ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  readonly  IElectoralApiService  _apiService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  readonly  WorkerConfigService  _configService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  public  CriticalDataWorker ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ILogger < CriticalDataWorker >  logger , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      SharedTokenService  tokenService , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      IServiceProvider  serviceProvider , 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      IElectoralApiService  apiService , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      WorkerConfigService  configService ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _logger  =  logger ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _tokenService  =  tokenService ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _serviceProvider  =  serviceProvider ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    _apiService  =  apiService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    _configService  =  configService ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  protected  override  async  Task  ExecuteAsync ( CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    _logger . LogInformation ( "Worker de Datos Críticos iniciado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  Task . Delay ( TimeSpan . FromMinutes ( 2 ) ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    catch  ( TaskCanceledException )  {  return ;  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    int  cicloContador  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    while  ( ! stoppingToken . IsCancellationRequested ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  cicloInicio  =  DateTime . UtcNow ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      cicloContador + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "--- Iniciando Ciclo de Datos Críticos #{ciclo} ---" ,  cicloContador ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  authToken  =  await  _tokenService . GetValidAuthTokenAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( string . IsNullOrEmpty ( authToken ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogError ( "Ciclo Crítico: No se pudo obtener token. Reintentando en 30 segundos." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  Task . Delay ( TimeSpan . FromSeconds ( 30 ) ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        continue ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  settings  =  await  _configService . GetSettingsAsync ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( settings . Prioridad  = =  "Resultados"  & &  settings . ResultadosActivado ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Ejecutando tareas de Resultados en alta prioridad." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearResultadosMunicipalesAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearResumenProvincialAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearEstadoRecuentoGeneralAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else  if  ( settings . Prioridad  = =  "Telegramas"  & &  settings . BajasActivado ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Ejecutando tareas de Baja Prioridad en alta prioridad." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearProyeccionBancasAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  SondearNuevosTelegramasAsync ( authToken ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Worker de alta prioridad inactivo según la configuración." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  cicloFin  =  DateTime . UtcNow ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  duracionCiclo  =  cicloFin  -  cicloInicio ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "--- Ciclo de Datos Críticos #{ciclo} completado en {duration:N2} segundos. ---" ,  cicloContador ,  duracionCiclo . TotalSeconds ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  tiempoDeEspera  =  TimeSpan . FromSeconds ( 30 )  -  duracionCiclo ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( tiempoDeEspera  <  TimeSpan . Zero )  tiempoDeEspera  =  TimeSpan . Zero ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  Task . Delay ( tiempoDeEspera ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      catch  ( TaskCanceledException )  {  break ;  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Sondea la proyección de bancas a nivel Provincial y por Sección Electoral. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Esta versión es completamente robusta: maneja respuestas de API vacías o con fechas mal formadas, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// guarda la CategoriaId y usa una transacción atómica para la escritura en base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="authToken">El token de autenticación válido para la sesión.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <param name="stoppingToken">El token de cancelación para detener la operación.</param> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearProyeccionBancasAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasDeBancas  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( c  = >  c . Nombre . Contains ( "SENADORES" )  | |  c . Nombre . Contains ( "DIPUTADOS" ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  provincia  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . FirstOrDefaultAsync ( a  = >  a . NivelId  = =  10 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  seccionesElectorales  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  20  & &  a . DistritoId  ! =  null  & &  a . SeccionProvincialId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      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." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Bancas a nivel Provincial y para {count} Secciones Electorales..." ,  seccionesElectorales . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  todasLasProyecciones  =  new  List < ProyeccionBanca > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      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 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( repartoBancasDto ? . RepartoBancas  is  {  Count :  >  0  }  bancas ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          hasReceivedAnyNewData  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // --- 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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              AmbitoGeograficoId  =  provincia . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              AgrupacionPoliticaId  =  banca . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              NroBancas  =  banca . NroBancas , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              CategoriaId  =  categoria . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              FechaTotalizacion  =  fechaTotalizacion 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Bucle para el nivel de Sección Electoral 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  seccion  in  seccionesElectorales ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categoriasDeBancas ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  repartoBancasDto  =  await  _apiService . GetBancasAsync ( authToken ,  seccion . DistritoId ! ,  seccion . SeccionProvincialId ! ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( repartoBancasDto ? . RepartoBancas  is  {  Count :  >  0  }  bancas ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            hasReceivedAnyNewData  =  true ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // --- APLICAMOS LA MISMA 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 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                AmbitoGeograficoId  =  seccion . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                AgrupacionPoliticaId  =  banca . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                NroBancas  =  banca . NroBancas , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                CategoriaId  =  categoria . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                FechaTotalizacion  =  fechaTotalizacion 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      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 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . ProyeccionesBancas . AddRangeAsync ( todasLasProyecciones ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  transaction . CommitAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "La tabla de proyecciones ha sido actualizada con {count} registros." ,  todasLasProyecciones . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogInformation ( "Sondeo de Bancas completado. No se encontraron datos nuevos de proyección, la tabla no fue modificada." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de bancas cancelado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Bancas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Busca y descarga nuevos telegramas de forma masiva y concurrente. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Este método crea una lista de todas las combinaciones de Partido/Categoría, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// las consulta a la API con un grado de paralelismo controlado, y cada tarea concurrente 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// maneja su propia lógica de descarga y guardado en la 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  SondearNuevosTelegramasAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "--- Iniciando sondeo de Nuevos Telegramas (modo de bajo perfil) ---" ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // La obtención de partidos y categorías no cambia 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  partidos  =  await  dbContext . AmbitosGeograficos . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  30  & &  a . DistritoId  ! =  null  & &  a . SeccionId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  categorias  =  await  dbContext . CategoriasElectorales . AsNoTracking ( ) . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! partidos . Any ( )  | |  ! categorias . Any ( ) )  return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  partido  in  partidos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  categorias ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  listaTelegramasApi  =  await  _apiService . GetTelegramasTotalizadosAsync ( authToken ,  partido . DistritoId ! ,  partido . SeccionId ! ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( listaTelegramasApi  is  {  Count :  >  0  } ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // Creamos el DbContext para la operación de guardado 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            using  var  innerScope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  innerDbContext  =  innerScope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  idsYaEnDb  =  await  innerDbContext . Telegramas 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . Where ( t  = >  listaTelegramasApi . Contains ( t . Id ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                . Select ( t  = >  t . Id ) . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  nuevosTelegramasIds  =  listaTelegramasApi . Except ( idsYaEnDb ) . ToList ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            if  ( nuevosTelegramasIds . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              _logger . LogInformation ( "Se encontraron {count} telegramas nuevos en '{partido}' para '{cat}'. Descargando..." ,  nuevosTelegramasIds . Count ,  partido . Nombre ,  categoria . Nombre ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              var  originalTimeout  =  innerDbContext . Database . GetCommandTimeout ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              try 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                innerDbContext . Database . SetCommandTimeout ( 180 ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogDebug ( "Timeout de BD aumentado a 180s para descarga de telegramas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                int  contadorLote  =  0 ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                const  int  tamanoLote  =  100 ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                foreach  ( var  mesaId  in  nuevosTelegramasIds ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  if  ( stoppingToken . IsCancellationRequested )  return ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  var  telegramaFile  =  await  _apiService . GetTelegramaFileAsync ( authToken ,  mesaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  if  ( telegramaFile  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    var  ambitoMesa  =  await  innerDbContext . AmbitosGeograficos . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        . FirstOrDefaultAsync ( a  = >  a . MesaId  = =  mesaId ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    if  ( ambitoMesa  ! =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                      var  nuevoTelegrama  =  new  Telegrama 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        Id  =  telegramaFile . NombreArchivo , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        AmbitoGeograficoId  =  ambitoMesa . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        ContenidoBase64  =  telegramaFile . Imagen , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        FechaEscaneo  =  DateTime . Parse ( telegramaFile . FechaEscaneo ) . ToUniversalTime ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                        FechaTotalizacion  =  DateTime . Parse ( telegramaFile . FechaTotalizacion ) . ToUniversalTime ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      await  innerDbContext . Telegramas . AddAsync ( nuevoTelegrama ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      contadorLote + + ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    else 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                      _logger . LogWarning ( "No se encontró un ámbito geográfico para la mesa con MesaId {MesaId}. El telegrama no será guardado." ,  mesaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  await  Task . Delay ( 250 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  if  ( contadorLote  > =  tamanoLote ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                    await  innerDbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    _logger . LogInformation ( "Guardado un lote de {count} telegramas." ,  contadorLote ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                    contadorLote  =  0 ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 10:22:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                if  ( contadorLote  >  0 ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 10:22:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                  await  innerDbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                  _logger . LogInformation ( "Guardado el último lote de {count} telegramas." ,  contadorLote ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 10:22:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              finally 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 10:22:51 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								                innerDbContext . Database . SetCommandTimeout ( originalTimeout ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                _logger . LogDebug ( "Timeout de BD restaurado a su valor original ({timeout}s)." ,  originalTimeout ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								              } 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-08 14:25:19 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            }  // Fin del if (nuevosTelegramasIds.Any()) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Movemos el delay aquí para que solo se ejecute si hubo telegramas en la respuesta de la API 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  Task . Delay ( 100 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          }  // Fin del if (listaTelegramasApi is not null) 
							 
						 
					
						
							
								
									
										
										
										
											2025-09-06 21:44:52 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Telegramas completado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de telegramas cancelado." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Telegramas." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearResultadosMunicipalesAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  municipiosASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  30  & &  a . DistritoId  ! =  null  & &  a . SeccionId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  todasLasCategorias  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      if  ( ! municipiosASondear . Any ( )  | |  ! todasLasCategorias . Any ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron Partidos (NivelId 30) o Categorías para sondear resultados." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de resultados para {m} municipios y {c} categorías..." ,  municipiosASondear . Count ,  todasLasCategorias . Count ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      foreach  ( var  municipio  in  municipiosASondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        var  tareasCategoria  =  todasLasCategorias . Select ( async  categoria  = > 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          var  resultados  =  await  _apiService . GetResultadosAsync ( authToken ,  municipio . DistritoId ! ,  municipio . SeccionId ! ,  null ,  categoria . Id ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( resultados  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            using  var  innerScope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            var  innerDbContext  =  innerScope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // --- LLAMADA CORRECTA --- 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  GuardarResultadosDeAmbitoAsync ( innerDbContext ,  municipio . Id ,  categoria . Id ,  resultados ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        await  Task . WhenAll ( tareasCategoria ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error inesperado durante el sondeo de resultados municipales." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  private  async  Task  GuardarResultadosDeAmbitoAsync ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      EleccionesDbContext  dbContext ,  int  ambitoId ,  int  categoriaId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      Elecciones . Core . DTOs . ResultadosDto  resultadosDto ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    var  estadoRecuento  =  await  dbContext . EstadosRecuentos . FindAsync ( new  object [ ]  {  ambitoId ,  categoriaId  } ,  stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( estadoRecuento  = =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      estadoRecuento  =  new  EstadoRecuento  {  AmbitoGeograficoId  =  ambitoId ,  CategoriaId  =  categoriaId  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      dbContext . EstadosRecuentos . Add ( estadoRecuento ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    estadoRecuento . FechaTotalizacion  =  DateTime . Parse ( resultadosDto . FechaTotalizacion ) . ToUniversalTime ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasEsperadas  =  resultadosDto . EstadoRecuento . MesasEsperadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasTotalizadas  =  resultadosDto . EstadoRecuento . MesasTotalizadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . MesasTotalizadasPorcentaje  =  resultadosDto . EstadoRecuento . MesasTotalizadasPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . CantidadElectores  =  resultadosDto . EstadoRecuento . CantidadElectores ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . CantidadVotantes  =  resultadosDto . EstadoRecuento . CantidadVotantes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    estadoRecuento . ParticipacionPorcentaje  =  resultadosDto . EstadoRecuento . ParticipacionPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( resultadosDto . ValoresTotalizadosOtros  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosEnBlanco  =  resultadosDto . ValoresTotalizadosOtros . VotosEnBlanco ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosEnBlancoPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosEnBlancoPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosNulos  =  resultadosDto . ValoresTotalizadosOtros . VotosNulos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosNulosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosNulosPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosRecurridos  =  resultadosDto . ValoresTotalizadosOtros . VotosRecurridos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosRecurridosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosRecurridosPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-15 11:44:22 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      estadoRecuento . VotosComando  =  resultadosDto . ValoresTotalizadosOtros . VotosComando ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosComandoPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosComandoPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosImpugnados  =  resultadosDto . ValoresTotalizadosOtros . VotosImpugnados ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      estadoRecuento . VotosImpugnadosPorcentaje  =  resultadosDto . ValoresTotalizadosOtros . VotosImpugnadosPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    foreach  ( var  votoPositivoDto  in  resultadosDto . ValoresTotalizadosPositivos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-16 15:34:12 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      // PASO 1: VERIFICAR SI LA AGRUPACIÓN YA EXISTE EN NUESTRA BD 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  agrupacion  =  await  dbContext . AgrupacionesPoliticas . FindAsync ( votoPositivoDto . IdAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 2: SI NO EXISTE, LA CREAMOS "SOBRE LA MARCHA" 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( agrupacion  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "Agrupación con ID {AgrupacionId} ('{Nombre}') no encontrada en el catálogo local. Creándola desde los datos de resultados." , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            votoPositivoDto . IdAgrupacion ,  votoPositivoDto . NombreAgrupacion ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        agrupacion  =  new  AgrupacionPolitica 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          Id  =  votoPositivoDto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          Nombre  =  votoPositivoDto . NombreAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // El IdTelegrama puede ser nulo, usamos el operador '??' para asignar un string vacío si es así. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          IdTelegrama  =  votoPositivoDto . IdAgrupacionTelegrama  ? ?  string . Empty 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        await  dbContext . AgrupacionesPoliticas . AddAsync ( agrupacion ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // No es necesario llamar a SaveChangesAsync aquí, se hará al final. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 3: CONTINUAR CON LA LÓGICA DE GUARDADO DEL VOTO 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  resultadoVoto  =  await  dbContext . ResultadosVotos . FirstOrDefaultAsync ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          rv  = >  rv . AmbitoGeograficoId  = =  ambitoId  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                rv . CategoriaId  = =  categoriaId  & & 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                rv . AgrupacionPoliticaId  = =  votoPositivoDto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          stoppingToken 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( resultadoVoto  = =  null ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        resultadoVoto  =  new  ResultadoVoto 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          AmbitoGeograficoId  =  ambitoId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          CategoriaId  =  categoriaId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          AgrupacionPoliticaId  =  votoPositivoDto . IdAgrupacion 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        dbContext . ResultadosVotos . Add ( resultadoVoto ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      resultadoVoto . CantidadVotos  =  votoPositivoDto . Votos ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      resultadoVoto . PorcentajeVotos  =  votoPositivoDto . VotosPorcentaje ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 11:01:54 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( DbUpdateException  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "DbUpdateException al guardar resultados para AmbitoId {ambitoId} y CategoriaId {categoriaId}" ,  ambitoId ,  categoriaId ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  /// Obtiene y actualiza el resumen de votos y el estado del recuento a nivel provincial para CADA categoría. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Este método itera sobre todas las provincias y categorías, obteniendo sus resultados consolidados 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// y guardándolos en las tablas 'ResumenesVotos' y 'EstadosRecuentosGenerales'. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  /// </summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  private  async  Task  SondearResumenProvincialAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Resúmenes Provinciales..." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  provinciasASondear  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          . Where ( a  = >  a . NivelId  = =  10  & &  a . DistritoId  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      var  todasLasCategorias  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! provinciasASondear . Any ( )  | |  ! todasLasCategorias . Any ( ) ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontraron Provincias o Categorías para sondear resúmenes." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      foreach  ( var  provincia  in  provinciasASondear ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        foreach  ( var  categoria  in  todasLasCategorias ) 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          // Usamos GetResultados sin seccionId/municipioId para obtener el resumen del distrito. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  resultadosDto  =  await  _apiService . GetResultadosAsync ( authToken ,  provincia . DistritoId ! ,  null ,  null ,  categoria . Id ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								          if  ( resultadosDto ? . ValoresTotalizadosPositivos  is  {  Count :  >  0  }  nuevosVotos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Usamos una transacción para asegurar que el borrado y la inserción sean atómicos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  using  var  transaction  =  await  dbContext . Database . BeginTransactionAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // A. Borrar los resúmenes viejos SOLO para esta provincia y categoría. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  dbContext . ResumenesVotos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . Where ( rv  = >  rv . AmbitoGeograficoId  = =  provincia . Id  & &  rv . CategoriaId  = =  categoria . Id ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                . ExecuteDeleteAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // B. Añadir los nuevos resúmenes. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            foreach  ( var  voto  in  nuevosVotos ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              dbContext . ResumenesVotos . Add ( new  ResumenVoto 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                AmbitoGeograficoId  =  provincia . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                CategoriaId  =  categoria . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                AgrupacionPoliticaId  =  voto . IdAgrupacion , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                Votos  =  voto . Votos , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								                VotosPorcentaje  =  voto . VotosPorcentaje 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // C. Guardar los cambios en la tabla ResumenesVotos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            // No es necesario actualizar EstadosRecuentosGenerales aquí, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // ya que el método SondearEstadoRecuentoGeneralAsync se encarga de eso 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // de forma más específica y eficiente. 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								            await  transaction . CommitAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        }  // Fin bucle categorías 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  // Fin bucle provincias 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Resúmenes Provinciales completado." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    catch  ( OperationCanceledException ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de resúmenes provinciales cancelado." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-23 13:19:35 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
									
										
										
										
											2025-10-14 16:00:55 -03:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Resúmenes Provinciales." ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2025-08-20 16:58:18 -03:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// <summary> 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Obtiene y actualiza el estado general del recuento a nivel provincial para CADA categoría electoral. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// Esta versión es robusta: consulta dinámicamente las categorías, usa la clave primaria compuesta 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// de la base de datos y guarda todos los cambios en una única transacción al final. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  /// </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  SondearEstadoRecuentoGeneralAsync ( string  authToken ,  CancellationToken  stoppingToken ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    try 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 1: Crear un "scope" para obtener una instancia fresca de DbContext. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Esto es una práctica recomendada para servicios de larga duración para evitar problemas de concurrencia. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      using  var  scope  =  _serviceProvider . CreateScope ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  dbContext  =  scope . ServiceProvider . GetRequiredService < EleccionesDbContext > ( ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 2: Obtener el ámbito geográfico de la Provincia. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Necesitamos este objeto para obtener su 'DistritoId' ("02"), que es requerido por la API. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  provincia  =  await  dbContext . AmbitosGeograficos 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( )  // Optimización: Solo necesitamos leer datos, no modificarlos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . FirstOrDefaultAsync ( a  = >  a . NivelId  = =  10 ,  stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Comprobación de seguridad: Si la sincronización inicial falló y no tenemos el registro de la provincia, 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // no podemos continuar. Registramos una advertencia y salimos del método. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( provincia  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No se encontró el ámbito 'Provincia' (NivelId 10) en la BD. Omitiendo sondeo de estado general." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 3: Obtener todas las categorías electorales disponibles desde nuestra base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Esto hace que el método sea dinámico y no dependa de IDs fijos en el código. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      var  categoriasParaSondear  =  await  dbContext . CategoriasElectorales 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . AsNoTracking ( ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          . ToListAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( ! categoriasParaSondear . Any ( ) ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        _logger . LogWarning ( "No hay categorías en la BD para sondear el estado general del recuento." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Iniciando sondeo de Estado Recuento General para {count} categorías..." ,  categoriasParaSondear . Count ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 4: Iterar sobre cada categoría para obtener su estado de recuento individual. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      foreach  ( var  categoria  in  categoriasParaSondear ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Salimos limpiamente del bucle si la aplicación se está deteniendo. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( stoppingToken . IsCancellationRequested )  break ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Llamamos a la API con el distrito y la CATEGORÍA ACTUAL del bucle. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        var  estadoDto  =  await  _apiService . GetEstadoRecuentoGeneralAsync ( authToken ,  provincia . DistritoId ! ,  categoria . Id ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        // Solo procedemos si la API devolvió datos válidos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( estadoDto  ! =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Lógica "Upsert" (Update or Insert): 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Buscamos un registro existente usando la CLAVE PRIMARIA COMPUESTA. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          var  registroDb  =  await  dbContext . EstadosRecuentosGenerales . FindAsync ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              new  object [ ]  {  provincia . Id ,  categoria . Id  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              cancellationToken :  stoppingToken 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Si no se encuentra (FindAsync devuelve null), es un registro nuevo. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          if  ( registroDb  = =  null ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Creamos una nueva instancia de la entidad. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            registroDb  =  new  EstadoRecuentoGeneral 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              AmbitoGeograficoId  =  provincia . Id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								              CategoriaId  =  categoria . Id  // Asignamos ambas partes de la clave primaria. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            // Y la añadimos al ChangeTracker de EF para que la inserte en la BD. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								            dbContext . EstadosRecuentosGenerales . Add ( registroDb ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Mapeamos los datos del DTO de la API a nuestra entidad de base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          // Esto se hace tanto para registros nuevos como para los existentes que se van a actualizar. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . MesasEsperadas  =  estadoDto . MesasEsperadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . MesasTotalizadas  =  estadoDto . MesasTotalizadas ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . MesasTotalizadasPorcentaje  =  estadoDto . MesasTotalizadasPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . CantidadElectores  =  estadoDto . CantidadElectores ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . CantidadVotantes  =  estadoDto . CantidadVotantes ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          registroDb . ParticipacionPorcentaje  =  estadoDto . ParticipacionPorcentaje ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // PASO 5: Guardar todos los cambios en la base de datos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Al llamar a SaveChangesAsync UNA SOLA VEZ fuera del bucle, EF Core agrupa 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // todas las inserciones y actualizaciones en una única transacción eficiente. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  dbContext . SaveChangesAsync ( stoppingToken ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogInformation ( "Sondeo de Estado Recuento General completado para todas las categorías." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    catch  ( Exception  ex ) 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      // Capturamos cualquier excepción inesperada para que no detenga el worker y la registramos. 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      _logger . LogError ( ex ,  "Ocurrió un error CRÍTICO en el sondeo de Estado Recuento General." ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}