Feat Widgets
Se añade la tabla CandidatosOverrides Se añade el Overrides de Candidatos al panel de administrador Se Añade el nombre de los candidatos a los Widgets de categorias por municipio
This commit is contained in:
@@ -0,0 +1,86 @@
|
|||||||
|
import { useState, useMemo, useEffect } from 'react';
|
||||||
|
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import Select from 'react-select';
|
||||||
|
import { getMunicipiosForAdmin, getAgrupaciones, getCandidatos, updateCandidatos } from '../services/apiService';
|
||||||
|
import type { MunicipioSimple, AgrupacionPolitica, CandidatoOverride } from '../types';
|
||||||
|
|
||||||
|
// Las categorías son las mismas que para los logos
|
||||||
|
const CATEGORIAS_OPTIONS = [
|
||||||
|
{ value: 5, label: 'Senadores' },
|
||||||
|
{ value: 6, label: 'Diputados' },
|
||||||
|
{ value: 7, label: 'Concejales' }
|
||||||
|
];
|
||||||
|
|
||||||
|
export const CandidatoOverridesManager = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
const { data: municipios = [] } = useQuery<MunicipioSimple[]>({ queryKey: ['municipiosForAdmin'], queryFn: getMunicipiosForAdmin });
|
||||||
|
const { data: agrupaciones = [] } = useQuery<AgrupacionPolitica[]>({ queryKey: ['agrupaciones'], queryFn: getAgrupaciones });
|
||||||
|
// --- Usar la query para candidatos ---
|
||||||
|
const { data: candidatos = [] } = useQuery<CandidatoOverride[]>({ queryKey: ['candidatos'], queryFn: getCandidatos });
|
||||||
|
|
||||||
|
const [selectedCategoria, setSelectedCategoria] = useState<{ value: number; label: string } | null>(null);
|
||||||
|
const [selectedMunicipio, setSelectedMunicipio] = useState<{ value: string; label: string } | null>(null);
|
||||||
|
const [selectedAgrupacion, setSelectedAgrupacion] = useState<{ value: string; label: string } | null>(null);
|
||||||
|
// --- El estado es para el nombre del candidato ---
|
||||||
|
const [nombreCandidato, setNombreCandidato] = useState('');
|
||||||
|
|
||||||
|
const municipioOptions = useMemo(() => municipios.map(m => ({ value: m.id, label: m.nombre })), [municipios]);
|
||||||
|
const agrupacionOptions = useMemo(() => agrupaciones.map(a => ({ value: a.id, label: a.nombre })), [agrupaciones]);
|
||||||
|
|
||||||
|
// --- Lógica para encontrar el nombre del candidato actual ---
|
||||||
|
const currentCandidato = useMemo(() => {
|
||||||
|
if (!selectedMunicipio || !selectedAgrupacion || !selectedCategoria) return '';
|
||||||
|
return candidatos.find(c =>
|
||||||
|
c.ambitoGeograficoId === parseInt(selectedMunicipio.value) &&
|
||||||
|
c.agrupacionPoliticaId === selectedAgrupacion.value &&
|
||||||
|
c.categoriaId === selectedCategoria.value
|
||||||
|
)?.nombreCandidato || '';
|
||||||
|
}, [candidatos, selectedMunicipio, selectedAgrupacion, selectedCategoria]);
|
||||||
|
|
||||||
|
useEffect(() => { setNombreCandidato(currentCandidato) }, [currentCandidato]);
|
||||||
|
|
||||||
|
const handleSave = async () => {
|
||||||
|
if (!selectedMunicipio || !selectedAgrupacion || !selectedCategoria) return;
|
||||||
|
|
||||||
|
// --- Construir el objeto CandidatoOverride ---
|
||||||
|
const newCandidatoEntry: CandidatoOverride = {
|
||||||
|
id: 0, // El backend no necesita el ID para un upsert
|
||||||
|
agrupacionPoliticaId: selectedAgrupacion.value,
|
||||||
|
categoriaId: selectedCategoria.value,
|
||||||
|
ambitoGeograficoId: parseInt(selectedMunicipio.value),
|
||||||
|
nombreCandidato: nombreCandidato
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
await updateCandidatos([newCandidatoEntry]);
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['candidatos'] });
|
||||||
|
alert('Override de candidato guardado.');
|
||||||
|
} catch { alert('Error al guardar.'); }
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="admin-module">
|
||||||
|
<h3>Overrides de Nombres de Candidatos</h3>
|
||||||
|
<p>Configure un nombre de candidato específico para un partido en un municipio y categoría determinados.</p>
|
||||||
|
<div style={{ display: 'flex', gap: '1rem', alignItems: 'flex-end' }}>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<label>Categoría</label>
|
||||||
|
<Select options={CATEGORIAS_OPTIONS} value={selectedCategoria} onChange={setSelectedCategoria} isClearable placeholder="Seleccione..."/>
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<label>Municipio</label>
|
||||||
|
<Select options={municipioOptions} value={selectedMunicipio} onChange={setSelectedMunicipio} isClearable placeholder="Seleccione..."/>
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
<label>Agrupación</label>
|
||||||
|
<Select options={agrupacionOptions} value={selectedAgrupacion} onChange={setSelectedAgrupacion} isClearable placeholder="Seleccione..."/>
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 2 }}>
|
||||||
|
<label>Nombre del Candidato</label>
|
||||||
|
<input type="text" value={nombreCandidato} onChange={e => setNombreCandidato(e.target.value)} style={{ width: '100%' }} disabled={!selectedMunicipio || !selectedAgrupacion || !selectedCategoria} />
|
||||||
|
</div>
|
||||||
|
<button onClick={handleSave} disabled={!selectedMunicipio || !selectedAgrupacion || !selectedCategoria}>Guardar</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -6,6 +6,7 @@ import { OrdenSenadoresManager } from './OrdenSenadoresManager';
|
|||||||
import { ConfiguracionGeneral } from './ConfiguracionGeneral';
|
import { ConfiguracionGeneral } from './ConfiguracionGeneral';
|
||||||
import { BancasManager } from './BancasManager';
|
import { BancasManager } from './BancasManager';
|
||||||
import { LogoOverridesManager } from './LogoOverridesManager';
|
import { LogoOverridesManager } from './LogoOverridesManager';
|
||||||
|
import { CandidatoOverridesManager } from './CandidatoOverridesManager';
|
||||||
|
|
||||||
export const DashboardPage = () => {
|
export const DashboardPage = () => {
|
||||||
const { logout } = useAuth();
|
const { logout } = useAuth();
|
||||||
@@ -16,9 +17,14 @@ export const DashboardPage = () => {
|
|||||||
<h1>Panel de Administración Electoral</h1>
|
<h1>Panel de Administración Electoral</h1>
|
||||||
<button onClick={logout}>Cerrar Sesión</button>
|
<button onClick={logout}>Cerrar Sesión</button>
|
||||||
</header>
|
</header>
|
||||||
<main style={{ marginTop: '2rem' }}>
|
<main style={{ marginTop: '2rem' }}>
|
||||||
<AgrupacionesManager />
|
<AgrupacionesManager />
|
||||||
<LogoOverridesManager />
|
<div style={{ flex: '1 1 800px' }}>
|
||||||
|
<LogoOverridesManager />
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: '1 1 800px' }}>
|
||||||
|
<CandidatoOverridesManager />
|
||||||
|
</div>
|
||||||
<div style={{ display: 'flex', gap: '2rem', flexWrap: 'wrap', marginTop: '2rem' }}>
|
<div style={{ display: 'flex', gap: '2rem', flexWrap: 'wrap', marginTop: '2rem' }}>
|
||||||
<div style={{ flex: '1 1 400px' }}>
|
<div style={{ flex: '1 1 400px' }}>
|
||||||
<OrdenDiputadosManager />
|
<OrdenDiputadosManager />
|
||||||
@@ -27,7 +33,7 @@ export const DashboardPage = () => {
|
|||||||
<OrdenSenadoresManager />
|
<OrdenSenadoresManager />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ConfiguracionGeneral />
|
<ConfiguracionGeneral />
|
||||||
<BancasManager />
|
<BancasManager />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// src/services/apiService.ts
|
// src/services/apiService.ts
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { triggerLogout } from '../context/authUtils';
|
import { triggerLogout } from '../context/authUtils';
|
||||||
import type { AgrupacionPolitica, UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria, MunicipioSimple } from '../types';
|
import type { CandidatoOverride, AgrupacionPolitica, UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria, MunicipioSimple } from '../types';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* URL base para las llamadas a la API.
|
* URL base para las llamadas a la API.
|
||||||
@@ -125,4 +125,14 @@ export const getMunicipiosForAdmin = async (): Promise<MunicipioSimple[]> => {
|
|||||||
// La URL final será /api/admin/catalogos/municipios
|
// La URL final será /api/admin/catalogos/municipios
|
||||||
const response = await adminApiClient.get('/catalogos/municipios');
|
const response = await adminApiClient.get('/catalogos/municipios');
|
||||||
return response.data;
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 6. Overrides de Candidatos
|
||||||
|
export const getCandidatos = async (): Promise<CandidatoOverride[]> => {
|
||||||
|
const response = await adminApiClient.get('/candidatos');
|
||||||
|
return response.data;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateCandidatos = async (data: CandidatoOverride[]): Promise<void> => {
|
||||||
|
await adminApiClient.put('/candidatos', data);
|
||||||
};
|
};
|
||||||
@@ -48,4 +48,12 @@ export interface LogoAgrupacionCategoria {
|
|||||||
ambitoGeograficoId: number | null;
|
ambitoGeograficoId: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MunicipioSimple { id: string; nombre: string; }
|
export interface MunicipioSimple { id: string; nombre: string; }
|
||||||
|
|
||||||
|
export interface CandidatoOverride {
|
||||||
|
id: number;
|
||||||
|
agrupacionPoliticaId: string;
|
||||||
|
categoriaId: number;
|
||||||
|
ambitoGeograficoId: number | null;
|
||||||
|
nombreCandidato: string;
|
||||||
|
}
|
||||||
@@ -27,11 +27,11 @@ export const ConcejalesWidget = () => {
|
|||||||
|
|
||||||
// 2. Query para la lista de municipios
|
// 2. Query para la lista de municipios
|
||||||
const { data: municipios = [], isLoading: isLoadingMunicipios } = useQuery<MunicipioSimple[]>({
|
const { data: municipios = [], isLoading: isLoadingMunicipios } = useQuery<MunicipioSimple[]>({
|
||||||
// Usamos una clave genérica porque siempre pedimos la lista completa.
|
// Usamos una clave genérica porque siempre pedimos la lista completa.
|
||||||
queryKey: ['municipios'],
|
queryKey: ['municipios'],
|
||||||
// Llamamos a la función sin argumentos para obtener todos los municipios.
|
// Llamamos a la función sin argumentos para obtener todos los municipios.
|
||||||
queryFn: () => getMunicipios(),
|
queryFn: () => getMunicipios(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const cantidadAMostrar = parseInt(configData?.ConcejalesResultadosCantidad || '5', 10);
|
const cantidadAMostrar = parseInt(configData?.ConcejalesResultadosCantidad || '5', 10);
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export const ConcejalesWidget = () => {
|
|||||||
municipios
|
municipios
|
||||||
.map(m => ({ value: m.id, label: m.nombre }))
|
.map(m => ({ value: m.id, label: m.nombre }))
|
||||||
.sort((a, b) => a.label.localeCompare(b.label)),
|
.sort((a, b) => a.label.localeCompare(b.label)),
|
||||||
[municipios]);
|
[municipios]);
|
||||||
|
|
||||||
const { data: resultados, isLoading: isLoadingResultados } = useQuery<ResultadoTicker[]>({
|
const { data: resultados, isLoading: isLoadingResultados } = useQuery<ResultadoTicker[]>({
|
||||||
queryKey: ['resultadosPorMunicipio', selectedMunicipio?.value, CATEGORIA_ID],
|
queryKey: ['resultadosPorMunicipio', selectedMunicipio?.value, CATEGORIA_ID],
|
||||||
@@ -92,7 +92,7 @@ export const ConcejalesWidget = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="ticker-results">
|
<div className="ticker-results">
|
||||||
{(isLoadingMunicipios || (isLoadingResultados && selectedMunicipio)) && <p>Cargando...</p>}
|
{(isLoadingMunicipios || (isLoadingResultados && selectedMunicipio)) && <p>Cargando...</p>}
|
||||||
{!selectedMunicipio && !isLoadingMunicipios && <p style={{textAlign: 'center', color: '#666'}}>Seleccione un municipio.</p>}
|
{!selectedMunicipio && !isLoadingMunicipios && <p style={{ textAlign: 'center', color: '#666' }}>Seleccione un municipio.</p>}
|
||||||
{displayResults.map(partido => (
|
{displayResults.map(partido => (
|
||||||
<div key={partido.id} className="ticker-party">
|
<div key={partido.id} className="ticker-party">
|
||||||
<div className="party-logo">
|
<div className="party-logo">
|
||||||
@@ -106,6 +106,9 @@ export const ConcejalesWidget = () => {
|
|||||||
<div className="party-bar-background">
|
<div className="party-bar-background">
|
||||||
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="party-candidate-name">
|
||||||
|
{partido.nombreCandidato}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export const DiputadosWidget = () => {
|
|||||||
municipios
|
municipios
|
||||||
.map(m => ({ value: m.id, label: m.nombre }))
|
.map(m => ({ value: m.id, label: m.nombre }))
|
||||||
.sort((a, b) => a.label.localeCompare(b.label)),
|
.sort((a, b) => a.label.localeCompare(b.label)),
|
||||||
[municipios]);
|
[municipios]);
|
||||||
|
|
||||||
const { data: resultados, isLoading: isLoadingResultados } = useQuery<ResultadoTicker[]>({
|
const { data: resultados, isLoading: isLoadingResultados } = useQuery<ResultadoTicker[]>({
|
||||||
queryKey: ['resultadosMunicipio', selectedMunicipio?.value, CATEGORIA_ID],
|
queryKey: ['resultadosMunicipio', selectedMunicipio?.value, CATEGORIA_ID],
|
||||||
@@ -94,7 +94,7 @@ export const DiputadosWidget = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="ticker-results">
|
<div className="ticker-results">
|
||||||
{(isLoadingMunicipios || (isLoadingResultados && selectedMunicipio)) && <p>Cargando...</p>}
|
{(isLoadingMunicipios || (isLoadingResultados && selectedMunicipio)) && <p>Cargando...</p>}
|
||||||
{!selectedMunicipio && !isLoadingMunicipios && <p style={{textAlign: 'center', color: '#666'}}>Seleccione un municipio.</p>}
|
{!selectedMunicipio && !isLoadingMunicipios && <p style={{ textAlign: 'center', color: '#666' }}>Seleccione un municipio.</p>}
|
||||||
{displayResults.map(partido => (
|
{displayResults.map(partido => (
|
||||||
<div key={partido.id} className="ticker-party">
|
<div key={partido.id} className="ticker-party">
|
||||||
<div className="party-logo">
|
<div className="party-logo">
|
||||||
@@ -108,6 +108,9 @@ export const DiputadosWidget = () => {
|
|||||||
<div className="party-bar-background">
|
<div className="party-bar-background">
|
||||||
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="party-candidate-name">
|
||||||
|
{partido.nombreCandidato}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -107,6 +107,9 @@ export const SenadoresWidget = () => {
|
|||||||
<div className="party-bar-background">
|
<div className="party-bar-background">
|
||||||
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="party-candidate-name">
|
||||||
|
{partido.nombreCandidato}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -133,4 +133,13 @@
|
|||||||
.ticker-party .party-name {
|
.ticker-party .party-name {
|
||||||
white-space: normal;
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.party-candidate-name {
|
||||||
|
font-size: 0.8rem;
|
||||||
|
color: #555;
|
||||||
|
margin-top: 4px; /* Espacio entre la barra y el nombre */
|
||||||
|
font-weight: 500;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: 0.5px;
|
||||||
}
|
}
|
||||||
@@ -49,6 +49,7 @@ export interface ResultadoTicker {
|
|||||||
logoUrl: string | null;
|
logoUrl: string | null;
|
||||||
votos: number;
|
votos: number;
|
||||||
porcentaje: number;
|
porcentaje: number;
|
||||||
|
nombreCandidato?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EstadoRecuentoTicker {
|
export interface EstadoRecuentoTicker {
|
||||||
|
|||||||
@@ -235,4 +235,77 @@ public class AdminController : ControllerBase
|
|||||||
|
|
||||||
return Ok(municipios);
|
return Ok(municipios);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Obtiene todos los overrides de candidatos configurados.
|
||||||
|
/// </summary>
|
||||||
|
[HttpGet("candidatos")]
|
||||||
|
public async Task<IActionResult> GetCandidatos()
|
||||||
|
{
|
||||||
|
var candidatos = await _dbContext.CandidatosOverrides
|
||||||
|
.AsNoTracking()
|
||||||
|
.ToListAsync();
|
||||||
|
return Ok(candidatos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Guarda (actualiza o crea) una lista de overrides de candidatos.
|
||||||
|
/// </summary>
|
||||||
|
[HttpPut("candidatos")]
|
||||||
|
public async Task<IActionResult> UpdateCandidatos([FromBody] List<CandidatoOverride> candidatos)
|
||||||
|
{
|
||||||
|
foreach (var candidatoDto in candidatos)
|
||||||
|
{
|
||||||
|
// Buscamos un override existente basado en la combinación única
|
||||||
|
var candidatoExistente = await _dbContext.CandidatosOverrides
|
||||||
|
.FirstOrDefaultAsync(c =>
|
||||||
|
c.AgrupacionPoliticaId == candidatoDto.AgrupacionPoliticaId &&
|
||||||
|
c.CategoriaId == candidatoDto.CategoriaId &&
|
||||||
|
c.AmbitoGeograficoId == candidatoDto.AmbitoGeograficoId);
|
||||||
|
|
||||||
|
if (candidatoExistente != null)
|
||||||
|
{
|
||||||
|
// Si existe y el nombre es diferente, lo actualizamos.
|
||||||
|
if (candidatoExistente.NombreCandidato != candidatoDto.NombreCandidato)
|
||||||
|
{
|
||||||
|
candidatoExistente.NombreCandidato = candidatoDto.NombreCandidato;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Si no se encontró un registro exacto, lo añadimos a la base de datos,
|
||||||
|
// pero solo si el nombre del candidato no está vacío.
|
||||||
|
if (!string.IsNullOrWhiteSpace(candidatoDto.NombreCandidato))
|
||||||
|
{
|
||||||
|
_dbContext.CandidatosOverrides.Add(new CandidatoOverride
|
||||||
|
{
|
||||||
|
AgrupacionPoliticaId = candidatoDto.AgrupacionPoliticaId,
|
||||||
|
CategoriaId = candidatoDto.CategoriaId,
|
||||||
|
AmbitoGeograficoId = candidatoDto.AmbitoGeograficoId,
|
||||||
|
NombreCandidato = candidatoDto.NombreCandidato
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// También necesitamos manejar los casos donde se borra un nombre (se envía un string vacío)
|
||||||
|
var overridesAEliminar = await _dbContext.CandidatosOverrides
|
||||||
|
.Where(c => candidatos.Any(dto =>
|
||||||
|
dto.AgrupacionPoliticaId == c.AgrupacionPoliticaId &&
|
||||||
|
dto.CategoriaId == c.CategoriaId &&
|
||||||
|
dto.AmbitoGeograficoId == c.AmbitoGeograficoId &&
|
||||||
|
string.IsNullOrWhiteSpace(dto.NombreCandidato)
|
||||||
|
))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
if (overridesAEliminar.Any())
|
||||||
|
{
|
||||||
|
_dbContext.CandidatosOverrides.RemoveRange(overridesAEliminar);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
await _dbContext.SaveChangesAsync();
|
||||||
|
_logger.LogInformation("Se procesaron {Count} overrides de candidatos.", candidatos.Count);
|
||||||
|
return NoContent(); // Respuesta estándar para un PUT exitoso
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -22,7 +22,7 @@ public class ResultadosController : ControllerBase
|
|||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("partido/{municipioId}")] // Renombramos el parámetro para mayor claridad
|
[HttpGet("partido/{municipioId}")]
|
||||||
public async Task<IActionResult> GetResultadosPorPartido(string municipioId, [FromQuery] int categoriaId)
|
public async Task<IActionResult> GetResultadosPorPartido(string municipioId, [FromQuery] int categoriaId)
|
||||||
{
|
{
|
||||||
var ambito = await _dbContext.AmbitosGeograficos.AsNoTracking()
|
var ambito = await _dbContext.AmbitosGeograficos.AsNoTracking()
|
||||||
@@ -51,6 +51,11 @@ public class ResultadosController : ControllerBase
|
|||||||
.Where(rv => rv.AmbitoGeograficoId == ambito.Id && rv.CategoriaId == categoriaId)
|
.Where(rv => rv.AmbitoGeograficoId == ambito.Id && rv.CategoriaId == categoriaId)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
|
var candidatosRelevantes = await _dbContext.CandidatosOverrides.AsNoTracking()
|
||||||
|
.Where(c => c.CategoriaId == categoriaId && agrupacionIds.Contains(c.AgrupacionPoliticaId) &&
|
||||||
|
(c.AmbitoGeograficoId == null || c.AmbitoGeograficoId == ambito.Id))
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos);
|
long totalVotosPositivos = resultadosVotos.Sum(r => r.CantidadVotos);
|
||||||
|
|
||||||
var respuestaDto = new MunicipioResultadosDto
|
var respuestaDto = new MunicipioResultadosDto
|
||||||
@@ -64,6 +69,9 @@ public class ResultadosController : ControllerBase
|
|||||||
var logoUrl = logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == ambito.Id)?.LogoUrl
|
var logoUrl = logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == ambito.Id)?.LogoUrl
|
||||||
?? logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == null)?.LogoUrl;
|
?? logosRelevantes.FirstOrDefault(l => l.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && l.AmbitoGeograficoId == null)?.LogoUrl;
|
||||||
|
|
||||||
|
var nombreCandidato = candidatosRelevantes.FirstOrDefault(c => c.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && c.AmbitoGeograficoId == ambito.Id)?.NombreCandidato
|
||||||
|
?? candidatosRelevantes.FirstOrDefault(c => c.AgrupacionPoliticaId == rv.AgrupacionPoliticaId && c.AmbitoGeograficoId == null)?.NombreCandidato;
|
||||||
|
|
||||||
return new AgrupacionResultadoDto
|
return new AgrupacionResultadoDto
|
||||||
{
|
{
|
||||||
Id = rv.AgrupacionPolitica.Id,
|
Id = rv.AgrupacionPolitica.Id,
|
||||||
@@ -72,6 +80,7 @@ public class ResultadosController : ControllerBase
|
|||||||
Color = rv.AgrupacionPolitica.Color,
|
Color = rv.AgrupacionPolitica.Color,
|
||||||
LogoUrl = logoUrl,
|
LogoUrl = logoUrl,
|
||||||
Votos = rv.CantidadVotos,
|
Votos = rv.CantidadVotos,
|
||||||
|
NombreCandidato = nombreCandidato,
|
||||||
Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0
|
Porcentaje = totalVotosPositivos > 0 ? (rv.CantidadVotos * 100.0m / totalVotosPositivos) : 0
|
||||||
};
|
};
|
||||||
}).OrderByDescending(r => r.Votos).ToList(),
|
}).OrderByDescending(r => r.Votos).ToList(),
|
||||||
@@ -557,27 +566,18 @@ public class ResultadosController : ControllerBase
|
|||||||
|
|
||||||
if (!municipiosDeLaSeccion.Any())
|
if (!municipiosDeLaSeccion.Any())
|
||||||
{
|
{
|
||||||
return Ok(new List<object>());
|
return Ok(new { UltimaActualizacion = DateTime.UtcNow, Resultados = new List<object>() });
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- INICIO DE LA CORRECCIÓN ---
|
// --- INICIO DE LA CORRECCIÓN DE LOGOS ---
|
||||||
|
|
||||||
// 1. Obtenemos TODOS los logos para la categoría, sin convertirlos a diccionario todavía.
|
// 1. Buscamos logos que sean para esta categoría Y que sean generales (ámbito null).
|
||||||
var todosLosLogos = await _dbContext.LogosAgrupacionesCategorias
|
var logosGenerales = await _dbContext.LogosAgrupacionesCategorias
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(l => l.CategoriaId == categoriaId)
|
.Where(l => l.CategoriaId == categoriaId && l.AmbitoGeograficoId == null)
|
||||||
.ToListAsync();
|
.ToDictionaryAsync(l => l.AgrupacionPoliticaId);
|
||||||
|
|
||||||
// 2. Procesamos los logos en memoria para manejar duplicados, priorizando los que tienen ámbito.
|
// --- FIN DE LA CORRECCIÓN DE LOGOS ---
|
||||||
// El resultado es un diccionario limpio sin claves duplicadas.
|
|
||||||
var logos = todosLosLogos
|
|
||||||
.GroupBy(l => l.AgrupacionPoliticaId) // Agrupamos por la clave que causa el problema
|
|
||||||
.ToDictionary(
|
|
||||||
g => g.Key, // La clave del diccionario es AgrupacionPoliticaId
|
|
||||||
g => g.OrderByDescending(l => l.AmbitoGeograficoId).First() // Para cada grupo, tomamos el logo más específico (el que tiene un AmbitoId) o el general si es el único.
|
|
||||||
);
|
|
||||||
|
|
||||||
// --- FIN DE LA CORRECCIÓN ---
|
|
||||||
|
|
||||||
var resultadosMunicipales = await _dbContext.ResultadosVotos
|
var resultadosMunicipales = await _dbContext.ResultadosVotos
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
@@ -601,7 +601,8 @@ public class ResultadosController : ControllerBase
|
|||||||
r.Agrupacion.Nombre,
|
r.Agrupacion.Nombre,
|
||||||
r.Agrupacion.NombreCorto,
|
r.Agrupacion.NombreCorto,
|
||||||
r.Agrupacion.Color,
|
r.Agrupacion.Color,
|
||||||
LogoUrl = logos.GetValueOrDefault(r.Agrupacion.Id)?.LogoUrl,
|
// 2. Usamos el diccionario de logos generales para buscar la URL.
|
||||||
|
LogoUrl = logosGenerales.GetValueOrDefault(r.Agrupacion.Id)?.LogoUrl,
|
||||||
Votos = r.Votos,
|
Votos = r.Votos,
|
||||||
Porcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0
|
Porcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ce5e2e2c9bd6b64a7ea8629eeef35d204013a33")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+479c2c60f214472aeffd4404b482ffb940c3049e")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","hGxHNQ\u002B1azEK\u002Bi1edq5HWPFILZgOw/WtDwYY8eIiOpE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DJ\u002BouDXt6xAa6457U4R5nMU/5dFpuSVR7W9oUVdiomg="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","/hrHm\u002B3v8DuHSlyFsxHPCFUvDW\u002BZsLR4kaMxNwUHl2M=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","v\u002BEjGaN1m59e9gwl3kXTpjNw\u002B3kwhJD2SLKx38/opjM="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
@@ -1 +1 @@
|
|||||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","hGxHNQ\u002B1azEK\u002Bi1edq5HWPFILZgOw/WtDwYY8eIiOpE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DJ\u002BouDXt6xAa6457U4R5nMU/5dFpuSVR7W9oUVdiomg="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["TyIJk/eQMWjmB5LsDE\u002BZIJC9P9ciVxd7bnzRiTZsGt4=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","E2ODTAlJxzsXY1iP1eB/02NIUK\u002BnQveGlWAOHY1cpgA=","6WTvWQ72AaZBYOVSmaxaci9tc1dW5p7IK9Kscjj2cb0=","vAy46VJ9Gp8QqG/Px4J1mj8jL6ws4/A01UKRmMYfYek=","cdgbHR/E4DJsddPc\u002BTpzoUMOVNaFJZm33Pw7AxU9Ees=","4r4JGR4hS5m4rsLfuCSZxzrknTBxKFkLQDXc\u002B2KbqTU=","yVoZ4UnBcSOapsJIi046hnn7ylD3jAcEBUxQ\u002Brkvj/4=","/GfbpJthEWmsuz0uFx1QLHM7gyM1wLLeQgAIl4SzUD4=","i5\u002B5LcfxQD8meRAkQbVf4wMvjxSE4\u002BjCd2/FdPtMpms=","AvSkxVPIg0GjnB1RJ4hDNyo9p9GONrzDs8uVuixH\u002BOE=","IgT9pOgRnK37qfILj2QcjFoBZ180HMt\u002BScgje2iYOo4=","ezUlOMzNZmyKDIe1wwXqvX\u002BvhwfB992xNVts7r2zcTc=","y2BV4WpkQuLfqQhfOQBtmuzh940c3s4LAopGKfztfTE=","lHTUEsMkDu8nqXtfTwl7FRfgocyyc7RI5O/edTHN1\u002B0=","A7nz7qgOtQ1CwZZLvNnr0b5QZB3fTi3y4i6y7rBIcxQ=","znnuRi2tsk7AACuYo4WSgj7NcLriG4PKVaF4L35SvDk=","GelE32odx/vTului267wqi6zL3abBnF9yvwC2Q66LoM=","TEsXImnzxFKTIq2f5fiDu7i6Ar/cbecW5MZ3z8Wb/a4=","5WogJu\u002BUPlF\u002BE5mq/ILtDXpVwqwmhHtsEB13nmT5JJk=","dcHQRkttjMjo2dvhL7hA9t4Pg\u002B7OnjZpkFmakT4QR9U=","/hrHm\u002B3v8DuHSlyFsxHPCFUvDW\u002BZsLR4kaMxNwUHl2M=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","v\u002BEjGaN1m59e9gwl3kXTpjNw\u002B3kwhJD2SLKx38/opjM="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
@@ -8,6 +8,7 @@ public class AgrupacionResultadoDto
|
|||||||
public string? NombreCorto { get; set; } = null!;
|
public string? NombreCorto { get; set; } = null!;
|
||||||
public string? Color { get; set; } = null!;
|
public string? Color { get; set; } = null!;
|
||||||
public string? LogoUrl { get; set; } = null!;
|
public string? LogoUrl { get; set; } = null!;
|
||||||
|
public string? NombreCandidato { get; set; } = null!;
|
||||||
public long Votos { get; set; }
|
public long Votos { get; set; }
|
||||||
public decimal Porcentaje { get; set; }
|
public decimal Porcentaje { get; set; }
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ce5e2e2c9bd6b64a7ea8629eeef35d204013a33")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+479c2c60f214472aeffd4404b482ffb940c3049e")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
|
|||||||
public DbSet<Bancada> Bancadas { get; set; }
|
public DbSet<Bancada> Bancadas { get; set; }
|
||||||
public DbSet<OcupanteBanca> OcupantesBancas { get; set; }
|
public DbSet<OcupanteBanca> OcupantesBancas { get; set; }
|
||||||
public DbSet<LogoAgrupacionCategoria> LogosAgrupacionesCategorias { get; set; }
|
public DbSet<LogoAgrupacionCategoria> LogosAgrupacionesCategorias { get; set; }
|
||||||
|
public DbSet<CandidatoOverride> CandidatosOverrides { get; set; }
|
||||||
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
@@ -81,5 +82,12 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
|
|||||||
// La combinación de las tres columnas debe ser única.
|
// La combinación de las tres columnas debe ser única.
|
||||||
entity.HasIndex(l => new { l.AgrupacionPoliticaId, l.CategoriaId, l.AmbitoGeograficoId }).IsUnique();
|
entity.HasIndex(l => new { l.AgrupacionPoliticaId, l.CategoriaId, l.AmbitoGeograficoId }).IsUnique();
|
||||||
});
|
});
|
||||||
|
modelBuilder.Entity<CandidatoOverride>(entity =>
|
||||||
|
{
|
||||||
|
// La combinación de agrupación, categoría y ámbito debe ser única
|
||||||
|
// para evitar tener dos nombres de candidato diferentes para la misma situación.
|
||||||
|
entity.HasIndex(c => new { c.AgrupacionPoliticaId, c.CategoriaId, c.AmbitoGeograficoId })
|
||||||
|
.IsUnique();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
|
namespace Elecciones.Database.Entities;
|
||||||
|
|
||||||
|
public class CandidatoOverride
|
||||||
|
{
|
||||||
|
[Key]
|
||||||
|
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||||
|
public int Id { get; set; }
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public string AgrupacionPoliticaId { get; set; } = null!;
|
||||||
|
|
||||||
|
[ForeignKey("AgrupacionPoliticaId")]
|
||||||
|
public AgrupacionPolitica AgrupacionPolitica { get; set; } = null!;
|
||||||
|
|
||||||
|
[Required]
|
||||||
|
public int CategoriaId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("CategoriaId")]
|
||||||
|
public CategoriaElectoral CategoriaElectoral { get; set; } = null!;
|
||||||
|
|
||||||
|
// El AmbitoGeograficoId es opcional. Si es null, el override es general.
|
||||||
|
public int? AmbitoGeograficoId { get; set; }
|
||||||
|
|
||||||
|
[ForeignKey("AmbitoGeograficoId")]
|
||||||
|
public AmbitoGeografico? AmbitoGeografico { get; set; }
|
||||||
|
|
||||||
|
// El nombre del candidato que queremos mostrar.
|
||||||
|
[Required]
|
||||||
|
[MaxLength(255)]
|
||||||
|
public string NombreCandidato { get; set; } = null!;
|
||||||
|
}
|
||||||
617
Elecciones-Web/src/Elecciones.Database/Migrations/20250905134421_AddCandidatosOverridesTable.Designer.cs
generated
Normal file
617
Elecciones-Web/src/Elecciones.Database/Migrations/20250905134421_AddCandidatosOverridesTable.Designer.cs
generated
Normal file
@@ -0,0 +1,617 @@
|
|||||||
|
// <auto-generated />
|
||||||
|
using System;
|
||||||
|
using Elecciones.Database;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Metadata;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Elecciones.Database.Migrations
|
||||||
|
{
|
||||||
|
[DbContext(typeof(EleccionesDbContext))]
|
||||||
|
[Migration("20250905134421_AddCandidatosOverridesTable")]
|
||||||
|
partial class AddCandidatosOverridesTable
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||||
|
{
|
||||||
|
#pragma warning disable 612, 618
|
||||||
|
modelBuilder
|
||||||
|
.UseCollation("Modern_Spanish_CI_AS")
|
||||||
|
.HasAnnotation("ProductVersion", "9.0.8")
|
||||||
|
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||||
|
|
||||||
|
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.AdminUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("PasswordHash")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("PasswordSalt")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Username")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("AdminUsers");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.AgrupacionPolitica", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<string>("Color")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("IdTelegrama")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Nombre")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("NombreCorto")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int?>("OrdenDiputados")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int?>("OrdenSenadores")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("AgrupacionesPoliticas");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.AmbitoGeografico", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("CircuitoId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("DistritoId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("EstablecimientoId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("MesaId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("MunicipioId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int>("NivelId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Nombre")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("SeccionId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("SeccionProvincialId")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("AmbitosGeograficos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("Camara")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("NumeroBanca")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId");
|
||||||
|
|
||||||
|
b.ToTable("Bancadas");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.CandidatoOverride", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int?>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("NombreCandidato")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(255)
|
||||||
|
.HasColumnType("nvarchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AmbitoGeograficoId");
|
||||||
|
|
||||||
|
b.HasIndex("CategoriaId");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[AmbitoGeograficoId] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("CandidatosOverrides");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("Nombre")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<int>("Orden")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("CategoriasElectorales");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.Configuracion", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Clave")
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.Property<string>("Valor")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(100)
|
||||||
|
.HasColumnType("nvarchar(100)");
|
||||||
|
|
||||||
|
b.HasKey("Clave");
|
||||||
|
|
||||||
|
b.ToTable("Configuraciones");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CantidadElectores")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CantidadVotantes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FechaTotalizacion")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<int>("MesasEsperadas")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("MesasTotalizadas")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||||
|
.HasPrecision(5, 2)
|
||||||
|
.HasColumnType("decimal(5,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("ParticipacionPorcentaje")
|
||||||
|
.HasPrecision(5, 2)
|
||||||
|
.HasColumnType("decimal(5,2)");
|
||||||
|
|
||||||
|
b.Property<long>("VotosEnBlanco")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<decimal>("VotosEnBlancoPorcentaje")
|
||||||
|
.HasPrecision(18, 4)
|
||||||
|
.HasColumnType("decimal(18,4)");
|
||||||
|
|
||||||
|
b.Property<long>("VotosNulos")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<decimal>("VotosNulosPorcentaje")
|
||||||
|
.HasPrecision(18, 4)
|
||||||
|
.HasColumnType("decimal(18,4)");
|
||||||
|
|
||||||
|
b.Property<long>("VotosRecurridos")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<decimal>("VotosRecurridosPorcentaje")
|
||||||
|
.HasPrecision(18, 4)
|
||||||
|
.HasColumnType("decimal(18,4)");
|
||||||
|
|
||||||
|
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||||
|
|
||||||
|
b.ToTable("EstadosRecuentos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CantidadElectores")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CantidadVotantes")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FechaTotalizacion")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<int>("MesasEsperadas")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("MesasTotalizadas")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("MesasTotalizadasPorcentaje")
|
||||||
|
.HasPrecision(5, 2)
|
||||||
|
.HasColumnType("decimal(5,2)");
|
||||||
|
|
||||||
|
b.Property<decimal>("ParticipacionPorcentaje")
|
||||||
|
.HasPrecision(5, 2)
|
||||||
|
.HasColumnType("decimal(5,2)");
|
||||||
|
|
||||||
|
b.HasKey("AmbitoGeograficoId", "CategoriaId");
|
||||||
|
|
||||||
|
b.HasIndex("CategoriaId");
|
||||||
|
|
||||||
|
b.ToTable("EstadosRecuentosGenerales");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.LogoAgrupacionCategoria", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int?>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("LogoUrl")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[AmbitoGeograficoId] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("LogosAgrupacionesCategorias");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.OcupanteBanca", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<int>("BancadaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("FotoUrl")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("NombreOcupante")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<string>("Periodo")
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BancadaId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("OcupantesBancas");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FechaTotalizacion")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<int>("NroBancas")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId");
|
||||||
|
|
||||||
|
b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ProyeccionesBancas");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||||
|
{
|
||||||
|
b.Property<long>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<long>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("CantidadVotos")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<decimal>("PorcentajeVotos")
|
||||||
|
.HasPrecision(18, 4)
|
||||||
|
.HasColumnType("decimal(18,4)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId");
|
||||||
|
|
||||||
|
b.HasIndex("AmbitoGeograficoId", "CategoriaId", "AgrupacionPoliticaId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("ResultadosVotos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<long>("Votos")
|
||||||
|
.HasColumnType("bigint");
|
||||||
|
|
||||||
|
b.Property<decimal>("VotosPorcentaje")
|
||||||
|
.HasPrecision(5, 2)
|
||||||
|
.HasColumnType("decimal(5,2)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId");
|
||||||
|
|
||||||
|
b.ToTable("ResumenesVotos");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.Telegrama", b =>
|
||||||
|
{
|
||||||
|
b.Property<string>("Id")
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("ContenidoBase64")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(max)");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FechaEscaneo")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.Property<DateTime>("FechaTotalizacion")
|
||||||
|
.HasColumnType("datetime2");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Telegramas");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId");
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.CandidatoOverride", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AmbitoGeograficoId");
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoriaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
|
||||||
|
b.Navigation("AmbitoGeografico");
|
||||||
|
|
||||||
|
b.Navigation("CategoriaElectoral");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AmbitoGeograficoId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AmbitoGeografico");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuentoGeneral", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoriaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("CategoriaElectoral");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.OcupanteBanca", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.Bancada", "Bancada")
|
||||||
|
.WithOne("Ocupante")
|
||||||
|
.HasForeignKey("Elecciones.Database.Entities.OcupanteBanca", "BancadaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("Bancada");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ProyeccionBanca", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AmbitoGeograficoId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
|
||||||
|
b.Navigation("AmbitoGeografico");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ResultadoVoto", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AmbitoGeograficoId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
|
||||||
|
b.Navigation("AmbitoGeografico");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.ResumenVoto", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.Bancada", b =>
|
||||||
|
{
|
||||||
|
b.Navigation("Ocupante");
|
||||||
|
});
|
||||||
|
#pragma warning restore 612, 618
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
#nullable disable
|
||||||
|
|
||||||
|
namespace Elecciones.Database.Migrations
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
public partial class AddCandidatosOverridesTable : Migration
|
||||||
|
{
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "CandidatosOverrides",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(type: "int", nullable: false)
|
||||||
|
.Annotation("SqlServer:Identity", "1, 1"),
|
||||||
|
AgrupacionPoliticaId = table.Column<string>(type: "nvarchar(450)", nullable: false),
|
||||||
|
CategoriaId = table.Column<int>(type: "int", nullable: false),
|
||||||
|
AmbitoGeograficoId = table.Column<int>(type: "int", nullable: true),
|
||||||
|
NombreCandidato = table.Column<string>(type: "nvarchar(255)", maxLength: 255, nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_CandidatosOverrides", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CandidatosOverrides_AgrupacionesPoliticas_AgrupacionPoliticaId",
|
||||||
|
column: x => x.AgrupacionPoliticaId,
|
||||||
|
principalTable: "AgrupacionesPoliticas",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CandidatosOverrides_AmbitosGeograficos_AmbitoGeograficoId",
|
||||||
|
column: x => x.AmbitoGeograficoId,
|
||||||
|
principalTable: "AmbitosGeograficos",
|
||||||
|
principalColumn: "Id");
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CandidatosOverrides_CategoriasElectorales_CategoriaId",
|
||||||
|
column: x => x.CategoriaId,
|
||||||
|
principalTable: "CategoriasElectorales",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Cascade);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CandidatosOverrides_AgrupacionPoliticaId_CategoriaId_AmbitoGeograficoId",
|
||||||
|
table: "CandidatosOverrides",
|
||||||
|
columns: new[] { "AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId" },
|
||||||
|
unique: true,
|
||||||
|
filter: "[AmbitoGeograficoId] IS NOT NULL");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CandidatosOverrides_AmbitoGeograficoId",
|
||||||
|
table: "CandidatosOverrides",
|
||||||
|
column: "AmbitoGeograficoId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CandidatosOverrides_CategoriaId",
|
||||||
|
table: "CandidatosOverrides",
|
||||||
|
column: "CategoriaId");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "CandidatosOverrides");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -144,6 +144,42 @@ namespace Elecciones.Database.Migrations
|
|||||||
b.ToTable("Bancadas");
|
b.ToTable("Bancadas");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.CandidatoOverride", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("Id"));
|
||||||
|
|
||||||
|
b.Property<string>("AgrupacionPoliticaId")
|
||||||
|
.IsRequired()
|
||||||
|
.HasColumnType("nvarchar(450)");
|
||||||
|
|
||||||
|
b.Property<int?>("AmbitoGeograficoId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<int>("CategoriaId")
|
||||||
|
.HasColumnType("int");
|
||||||
|
|
||||||
|
b.Property<string>("NombreCandidato")
|
||||||
|
.IsRequired()
|
||||||
|
.HasMaxLength(255)
|
||||||
|
.HasColumnType("nvarchar(255)");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("AmbitoGeograficoId");
|
||||||
|
|
||||||
|
b.HasIndex("CategoriaId");
|
||||||
|
|
||||||
|
b.HasIndex("AgrupacionPoliticaId", "CategoriaId", "AmbitoGeograficoId")
|
||||||
|
.IsUnique()
|
||||||
|
.HasFilter("[AmbitoGeograficoId] IS NOT NULL");
|
||||||
|
|
||||||
|
b.ToTable("CandidatosOverrides");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
|
modelBuilder.Entity("Elecciones.Database.Entities.CategoriaElectoral", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@@ -461,6 +497,31 @@ namespace Elecciones.Database.Migrations
|
|||||||
b.Navigation("AgrupacionPolitica");
|
b.Navigation("AgrupacionPolitica");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("Elecciones.Database.Entities.CandidatoOverride", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AgrupacionPolitica", "AgrupacionPolitica")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AgrupacionPoliticaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("AmbitoGeograficoId");
|
||||||
|
|
||||||
|
b.HasOne("Elecciones.Database.Entities.CategoriaElectoral", "CategoriaElectoral")
|
||||||
|
.WithMany()
|
||||||
|
.HasForeignKey("CategoriaId")
|
||||||
|
.OnDelete(DeleteBehavior.Cascade)
|
||||||
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Navigation("AgrupacionPolitica");
|
||||||
|
|
||||||
|
b.Navigation("AmbitoGeografico");
|
||||||
|
|
||||||
|
b.Navigation("CategoriaElectoral");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
modelBuilder.Entity("Elecciones.Database.Entities.EstadoRecuento", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
b.HasOne("Elecciones.Database.Entities.AmbitoGeografico", "AmbitoGeografico")
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ce5e2e2c9bd6b64a7ea8629eeef35d204013a33")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+479c2c60f214472aeffd4404b482ffb940c3049e")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+0ce5e2e2c9bd6b64a7ea8629eeef35d204013a33")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+479c2c60f214472aeffd4404b482ffb940c3049e")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
Reference in New Issue
Block a user