Feat Widgets
This commit is contained in:
@@ -1,113 +1,133 @@
|
||||
// src/components/AgrupacionesManager.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getAgrupaciones, updateAgrupacion } from '../services/apiService';
|
||||
import type { AgrupacionPolitica, UpdateAgrupacionData } from '../types';
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
import { getAgrupaciones, updateAgrupacion, getLogos, updateLogos } from '../services/apiService';
|
||||
import type { AgrupacionPolitica, LogoAgrupacionCategoria } from '../types';
|
||||
import './AgrupacionesManager.css';
|
||||
|
||||
const SENADORES_ID = 5;
|
||||
const DIPUTADOS_ID = 6;
|
||||
const CONCEJALES_ID = 7;
|
||||
|
||||
export const AgrupacionesManager = () => {
|
||||
const [agrupaciones, setAgrupaciones] = useState<AgrupacionPolitica[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [formData, setFormData] = useState<UpdateAgrupacionData>({
|
||||
nombreCorto: '',
|
||||
color: '#000000',
|
||||
logoUrl: '',
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const [editedAgrupaciones, setEditedAgrupaciones] = useState<Record<string, Partial<AgrupacionPolitica>>>({});
|
||||
const [editedLogos, setEditedLogos] = useState<LogoAgrupacionCategoria[]>([]);
|
||||
|
||||
// Query 1: Obtener agrupaciones
|
||||
const { data: agrupaciones = [], isLoading: isLoadingAgrupaciones } = useQuery<AgrupacionPolitica[]>({
|
||||
queryKey: ['agrupaciones'],
|
||||
queryFn: getAgrupaciones,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
fetchAgrupaciones();
|
||||
}, []);
|
||||
// Query 2: Obtener logos
|
||||
const { data: logos = [], isLoading: isLoadingLogos } = useQuery<LogoAgrupacionCategoria[]>({
|
||||
queryKey: ['logos'],
|
||||
queryFn: getLogos,
|
||||
});
|
||||
|
||||
const fetchAgrupaciones = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
const data = await getAgrupaciones();
|
||||
setAgrupaciones(data);
|
||||
} catch (err) {
|
||||
setError('No se pudieron cargar las agrupaciones.');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
// Usamos useEffect para reaccionar cuando los datos de 'logos' se cargan o cambian.
|
||||
useEffect(() => {
|
||||
if (logos) {
|
||||
setEditedLogos(logos);
|
||||
}
|
||||
}, [logos]);
|
||||
|
||||
// Usamos otro useEffect para reaccionar a los datos de 'agrupaciones'.
|
||||
useEffect(() => {
|
||||
if (agrupaciones) {
|
||||
const initialEdits = Object.fromEntries(agrupaciones.map(a => [a.id, {}]));
|
||||
setEditedAgrupaciones(initialEdits);
|
||||
}
|
||||
}, [agrupaciones]);
|
||||
|
||||
const handleInputChange = (id: string, field: 'nombreCorto' | 'color', value: string) => {
|
||||
setEditedAgrupaciones(prev => ({
|
||||
...prev,
|
||||
[id]: { ...prev[id], [field]: value }
|
||||
}));
|
||||
};
|
||||
|
||||
const handleEdit = (agrupacion: AgrupacionPolitica) => {
|
||||
setEditingId(agrupacion.id);
|
||||
setFormData({
|
||||
nombreCorto: agrupacion.nombreCorto || '',
|
||||
color: agrupacion.color || '#000000',
|
||||
logoUrl: agrupacion.logoUrl || '',
|
||||
const handleLogoChange = (agrupacionId: string, categoriaId: number, value: string) => {
|
||||
setEditedLogos(prev => {
|
||||
const newLogos = [...prev];
|
||||
const existing = newLogos.find(l => l.agrupacionPoliticaId === agrupacionId && l.categoriaId === categoriaId);
|
||||
if (existing) {
|
||||
existing.logoUrl = value;
|
||||
} else {
|
||||
newLogos.push({ id: 0, agrupacionPoliticaId: agrupacionId, categoriaId, logoUrl: value });
|
||||
}
|
||||
return newLogos;
|
||||
});
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setEditingId(null);
|
||||
};
|
||||
|
||||
const handleSave = async (id: string) => {
|
||||
const handleSaveAll = async () => {
|
||||
try {
|
||||
await updateAgrupacion(id, formData);
|
||||
setEditingId(null);
|
||||
fetchAgrupaciones(); // Recargar datos para ver los cambios
|
||||
const agrupacionPromises = Object.entries(editedAgrupaciones).map(([id, changes]) => {
|
||||
if (Object.keys(changes).length > 0) {
|
||||
const original = agrupaciones.find(a => a.id === id);
|
||||
if (original) { // Chequeo de seguridad
|
||||
return updateAgrupacion(id, { ...original, ...changes });
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
|
||||
const logoPromise = updateLogos(editedLogos);
|
||||
|
||||
await Promise.all([...agrupacionPromises, logoPromise]);
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ['agrupaciones'] });
|
||||
queryClient.invalidateQueries({ queryKey: ['logos'] });
|
||||
|
||||
alert('¡Todos los cambios han sido guardados!');
|
||||
} catch (err) {
|
||||
alert('Error al guardar los cambios.');
|
||||
console.error("Error al guardar todo:", err);
|
||||
alert("Ocurrió un error al guardar los cambios.");
|
||||
}
|
||||
};
|
||||
|
||||
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setFormData({ ...formData, [e.target.name]: e.target.value });
|
||||
const isLoading = isLoadingAgrupaciones || isLoadingLogos;
|
||||
|
||||
const getLogoUrl = (agrupacionId: string, categoriaId: number) => {
|
||||
return editedLogos.find(l => l.agrupacionPoliticaId === agrupacionId && l.categoriaId === categoriaId)?.logoUrl || '';
|
||||
};
|
||||
|
||||
if (loading) return <p>Cargando agrupaciones...</p>;
|
||||
if (error) return <p style={{ color: 'red' }}>{error}</p>;
|
||||
|
||||
return (
|
||||
<div className="admin-module">
|
||||
<h3>Gestión de Agrupaciones Políticas</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Nombre Corto</th>
|
||||
<th>Color</th>
|
||||
<th>Logo URL</th>
|
||||
<th>Acciones</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{agrupaciones.map((agrupacion) => (
|
||||
<tr key={agrupacion.id}>
|
||||
{editingId === agrupacion.id ? (
|
||||
<>
|
||||
<h3>Gestión de Agrupaciones y Logos</h3>
|
||||
{isLoading ? <p>Cargando...</p> : (
|
||||
<>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nombre</th>
|
||||
<th>Nombre Corto</th>
|
||||
<th>Color</th>
|
||||
<th>Logo Senadores</th>
|
||||
<th>Logo Diputados</th>
|
||||
<th>Logo Concejales</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{agrupaciones.map(agrupacion => (
|
||||
<tr key={agrupacion.id}>
|
||||
<td>{agrupacion.nombre}</td>
|
||||
<td><input type="text" name="nombreCorto" value={formData.nombreCorto || ''} onChange={handleChange} /></td>
|
||||
<td><input type="color" name="color" value={formData.color || '#000000'} onChange={handleChange} /></td>
|
||||
<td><input type="text" name="logoUrl" value={formData.logoUrl || ''} onChange={handleChange} /></td>
|
||||
<td>
|
||||
<button onClick={() => handleSave(agrupacion.id)}>Guardar</button>
|
||||
<button onClick={handleCancel}>Cancelar</button>
|
||||
</td>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<td>{agrupacion.nombre}</td>
|
||||
<td>{agrupacion.nombreCorto}</td>
|
||||
<td>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
|
||||
<div style={{ width: '20px', height: '20px', backgroundColor: agrupacion.color || 'transparent', border: '1px solid #ccc' }}></div>
|
||||
{agrupacion.color}
|
||||
</div>
|
||||
</td>
|
||||
<td>{agrupacion.logoUrl}</td>
|
||||
<td>
|
||||
<button onClick={() => handleEdit(agrupacion)}>Editar</button>
|
||||
</td>
|
||||
</>
|
||||
)}
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<td><input type="text" value={editedAgrupaciones[agrupacion.id]?.nombreCorto ?? agrupacion.nombreCorto ?? ''} onChange={(e) => handleInputChange(agrupacion.id, 'nombreCorto', e.target.value)} /></td>
|
||||
<td><input type="color" value={editedAgrupaciones[agrupacion.id]?.color ?? agrupacion.color ?? '#000000'} onChange={(e) => handleInputChange(agrupacion.id, 'color', e.target.value)} /></td>
|
||||
<td><input type="text" placeholder="URL de la imagen" value={getLogoUrl(agrupacion.id, SENADORES_ID)} onChange={(e) => handleLogoChange(agrupacion.id, SENADORES_ID, e.target.value)} /></td>
|
||||
<td><input type="text" placeholder="URL de la imagen" value={getLogoUrl(agrupacion.id, DIPUTADOS_ID)} onChange={(e) => handleLogoChange(agrupacion.id, DIPUTADOS_ID, e.target.value)} /></td>
|
||||
<td><input type="text" placeholder="URL de la imagen" value={getLogoUrl(agrupacion.id, CONCEJALES_ID)} onChange={(e) => handleLogoChange(agrupacion.id, CONCEJALES_ID, e.target.value)} /></td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
<button onClick={handleSaveAll} style={{ marginTop: '1rem' }}>
|
||||
Guardar Todos los Cambios
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -10,6 +10,8 @@ export const ConfiguracionGeneral = () => {
|
||||
const [agrupaciones, setAgrupaciones] = useState<AgrupacionPolitica[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [tickerCantidad, setTickerCantidad] = useState('3');
|
||||
const [concejalesCantidad, setConcejalesCantidad] = useState('5');
|
||||
|
||||
const [presidenciaSenadoId, setPresidenciaSenadoId] = useState<string>('');
|
||||
// Renombramos el estado para mayor claridad
|
||||
@@ -24,6 +26,8 @@ export const ConfiguracionGeneral = () => {
|
||||
setAgrupaciones(agrupacionesData);
|
||||
setPresidenciaSenadoId(configData.PresidenciaSenadores || '');
|
||||
setModoOficialActivo(configData.UsarDatosDeBancadasOficiales === 'true');
|
||||
setTickerCantidad(configData.TickerResultadosCantidad || '3');
|
||||
setConcejalesCantidad(configData.ConcejalesResultadosCantidad || '5');
|
||||
} catch (err) {
|
||||
console.error("Error al cargar datos de configuración:", err);
|
||||
setError("No se pudieron cargar los datos necesarios para la configuración.");
|
||||
@@ -36,7 +40,9 @@ export const ConfiguracionGeneral = () => {
|
||||
try {
|
||||
await updateConfiguracion({
|
||||
"PresidenciaSenadores": presidenciaSenadoId,
|
||||
"UsarDatosDeBancadasOficiales": modoOficialActivo.toString()
|
||||
"UsarDatosDeBancadasOficiales": modoOficialActivo.toString(),
|
||||
"TickerResultadosCantidad": tickerCantidad,
|
||||
"ConcejalesResultadosCantidad": concejalesCantidad
|
||||
});
|
||||
await queryClient.invalidateQueries({ queryKey: ['composicionCongreso'] });
|
||||
await queryClient.invalidateQueries({ queryKey: ['bancadasDetalle'] });
|
||||
@@ -89,7 +95,7 @@ export const ConfiguracionGeneral = () => {
|
||||
Seleccione el partido político al que pertenece el Vicegobernador. El asiento presidencial del Senado se pintará con el color de este partido.
|
||||
</p>
|
||||
</div>
|
||||
<div style={{ marginTop: '1rem' }}>
|
||||
<div style={{ marginTop: '1rem', borderBottom: '2px solid #eee' }}>
|
||||
<p style={{ fontWeight: 'bold', margin: 0 }}>
|
||||
Presidencia Cámara de Diputados
|
||||
</p>
|
||||
@@ -97,6 +103,19 @@ export const ConfiguracionGeneral = () => {
|
||||
Esta banca se asigna y colorea automáticamente según la agrupación política con la mayoría de bancas totales en la cámara.
|
||||
</p>
|
||||
</div>
|
||||
<div className="form-group" style={{ marginTop: '2rem' }}>
|
||||
<label htmlFor="ticker-cantidad">Cantidad en Ticker (Dip/Sen)</label>
|
||||
<input id="ticker-cantidad" type="number" value={tickerCantidad} onChange={e => setTickerCantidad(e.target.value)} />
|
||||
</div>
|
||||
<div className="form-group" style={{ marginTop: '2rem' }}>
|
||||
<label htmlFor="concejales-cantidad">Cantidad en Widget Concejales</label>
|
||||
<input
|
||||
id="concejales-cantidad"
|
||||
type="number"
|
||||
value={concejalesCantidad}
|
||||
onChange={e => setConcejalesCantidad(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<button onClick={handleSave} style={{ marginTop: '1.5rem' }}>
|
||||
Guardar Configuración
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// src/services/apiService.ts
|
||||
import axios from 'axios';
|
||||
import { triggerLogout } from '../context/authUtils';
|
||||
import type { AgrupacionPolitica, UpdateAgrupacionData, Bancada } from '../types';
|
||||
import type { AgrupacionPolitica, UpdateAgrupacionData, Bancada, LogoAgrupacionCategoria } from '../types';
|
||||
|
||||
const AUTH_API_URL = 'http://localhost:5217/api/auth';
|
||||
const ADMIN_API_URL = 'http://localhost:5217/api/admin';
|
||||
@@ -94,4 +94,13 @@ export const getConfiguracion = async (): Promise<ConfiguracionResponse> => {
|
||||
|
||||
export const updateConfiguracion = async (data: Record<string, string>): Promise<void> => {
|
||||
await adminApiClient.put('/configuracion', data);
|
||||
};
|
||||
|
||||
export const getLogos = async (): Promise<LogoAgrupacionCategoria[]> => {
|
||||
const response = await adminApiClient.get('/logos');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateLogos = async (data: LogoAgrupacionCategoria[]): Promise<void> => {
|
||||
await adminApiClient.put('/logos', data);
|
||||
};
|
||||
@@ -6,7 +6,6 @@ export interface AgrupacionPolitica {
|
||||
nombre: string;
|
||||
nombreCorto: string | null;
|
||||
color: string | null;
|
||||
logoUrl: string | null;
|
||||
ordenDiputados: number | null;
|
||||
ordenSenadores: number | null;
|
||||
}
|
||||
@@ -14,7 +13,6 @@ export interface AgrupacionPolitica {
|
||||
export interface UpdateAgrupacionData {
|
||||
nombreCorto: string | null;
|
||||
color: string | null;
|
||||
logoUrl: string | null;
|
||||
}
|
||||
|
||||
export const TipoCamara = {
|
||||
@@ -40,4 +38,11 @@ export interface Bancada {
|
||||
agrupacionPoliticaId: string | null;
|
||||
agrupacionPolitica: AgrupacionPolitica | null;
|
||||
ocupante: OcupanteBanca | null;
|
||||
}
|
||||
|
||||
export interface LogoAgrupacionCategoria {
|
||||
id: number;
|
||||
agrupacionPoliticaId: string;
|
||||
categoriaId: number;
|
||||
logoUrl: string | null;
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { CongresoWidget } from './components/CongresoWidget'
|
||||
import MapaBsAs from './components/MapaBsAs'
|
||||
import { TickerWidget } from './components/TickerWidget'
|
||||
import { TelegramaWidget } from './components/TelegramaWidget'
|
||||
import { ConcejalesWidget } from './components/ConcejalesWidget'
|
||||
|
||||
function App() {
|
||||
return (
|
||||
@@ -12,6 +13,7 @@ function App() {
|
||||
<h1>Resultados Electorales - Provincia de Buenos Aires</h1>
|
||||
<main>
|
||||
<TickerWidget />
|
||||
<ConcejalesWidget />
|
||||
<CongresoWidget />
|
||||
<BancasWidget />
|
||||
<MapaBsAs />
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
// src/apiService.ts
|
||||
import axios from 'axios';
|
||||
import type { ResumenProvincial, ProyeccionBancas, MunicipioSimple, TelegramaData, CatalogoItem } from './types/types';
|
||||
import type { ProyeccionBancas, MunicipioSimple, TelegramaData, CatalogoItem, CategoriaResumen, ResultadoTicker } from './types/types';
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5217/api';
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
interface PartidoData {
|
||||
id: string;
|
||||
@@ -47,14 +54,13 @@ export interface BancadaDetalle {
|
||||
ocupante: OcupanteBanca | null;
|
||||
}
|
||||
|
||||
const API_BASE_URL = 'http://localhost:5217/api';
|
||||
export interface ConfiguracionPublica {
|
||||
TickerResultadosCantidad?: string;
|
||||
ConcejalesResultadosCantidad?: string;
|
||||
// ... otras claves públicas que pueda añadir en el futuro
|
||||
}
|
||||
|
||||
const apiClient = axios.create({
|
||||
baseURL: API_BASE_URL,
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
|
||||
export const getResumenProvincial = async (): Promise<ResumenProvincial> => {
|
||||
export const getResumenProvincial = async (): Promise<CategoriaResumen[]> => {
|
||||
const response = await apiClient.get('/resultados/provincia/02');
|
||||
return response.data;
|
||||
};
|
||||
@@ -113,4 +119,14 @@ export const getComposicionCongreso = async (): Promise<ComposicionData> => {
|
||||
export const getBancadasDetalle = async (): Promise<BancadaDetalle[]> => {
|
||||
const response = await apiClient.get('/resultados/bancadas-detalle');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getConfiguracionPublica = async (): Promise<ConfiguracionPublica> => {
|
||||
const response = await apiClient.get('/resultados/configuracion-publica');
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const getResultadosConcejales = async (seccionId: string): Promise<ResultadoTicker[]> => {
|
||||
const response = await apiClient.get(`/resultados/concejales/${seccionId}`);
|
||||
return response.data;
|
||||
};
|
||||
103
Elecciones-Web/frontend/src/components/ConcejalesWidget.tsx
Normal file
103
Elecciones-Web/frontend/src/components/ConcejalesWidget.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
// src/components/ConcejalesWidget.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getSeccionesElectorales, getResultadosConcejales, getConfiguracionPublica } from '../apiService';
|
||||
import type { MunicipioSimple, ResultadoTicker } from '../types/types';
|
||||
import { ImageWithFallback } from './ImageWithFallback';
|
||||
import './TickerWidget.css'; // Reutilizamos los estilos del ticker
|
||||
|
||||
const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
||||
|
||||
export const ConcejalesWidget = () => {
|
||||
const [secciones, setSecciones] = useState<MunicipioSimple[]>([]);
|
||||
const [seccionActualId, setSeccionActualId] = useState<string>('');
|
||||
|
||||
// Query para la configuración (para saber cuántos resultados mostrar)
|
||||
const { data: configData } = useQuery({
|
||||
queryKey: ['configuracionPublica'],
|
||||
queryFn: getConfiguracionPublica,
|
||||
staleTime: 0,
|
||||
});
|
||||
|
||||
// Calculamos la cantidad a mostrar desde la configuración
|
||||
const cantidadAMostrar = parseInt(configData?.ConcejalesResultadosCantidad || '5', 10) + 1;
|
||||
|
||||
useEffect(() => {
|
||||
getSeccionesElectorales().then(seccionesData => {
|
||||
if (seccionesData && seccionesData.length > 0) {
|
||||
const orden = new Map([
|
||||
['Capital', 0], ['Primera', 1], ['Segunda', 2], ['Tercera', 3],
|
||||
['Cuarta', 4], ['Quinta', 5], ['Sexta', 6], ['Séptima', 7]
|
||||
]);
|
||||
const getOrden = (nombre: string) => {
|
||||
const match = nombre.match(/Capital|Primera|Segunda|Tercera|Cuarta|Quinta|Sexta|Séptima/);
|
||||
return match ? orden.get(match[0]) ?? 99 : 99;
|
||||
};
|
||||
seccionesData.sort((a, b) => getOrden(a.nombre) - getOrden(b.nombre));
|
||||
setSecciones(seccionesData);
|
||||
// Al estar los datos ya ordenados, el [0] será "Sección Capital"
|
||||
setSeccionActualId(seccionesData[0].id);
|
||||
}
|
||||
});
|
||||
}, []); // El array de dependencias vacío asegura que esto solo se ejecute una vez
|
||||
|
||||
// Query para obtener los resultados de la sección seleccionada
|
||||
const { data: resultados, isLoading } = useQuery<ResultadoTicker[]>({
|
||||
queryKey: ['resultadosConcejales', seccionActualId],
|
||||
queryFn: () => getResultadosConcejales(seccionActualId),
|
||||
enabled: !!seccionActualId,
|
||||
});
|
||||
|
||||
// --- INICIO DE LA LÓGICA DE PROCESAMIENTO "OTROS" ---
|
||||
let displayResults: ResultadoTicker[] = resultados || [];
|
||||
if (resultados && resultados.length > cantidadAMostrar) {
|
||||
const topParties = resultados.slice(0, cantidadAMostrar - 1);
|
||||
const otherParties = resultados.slice(cantidadAMostrar - 1);
|
||||
const otrosPorcentaje = otherParties.reduce((sum, party) => sum + (party.votosPorcentaje || 0), 0);
|
||||
|
||||
const otrosEntry: ResultadoTicker = {
|
||||
id: `otros-concejales-${seccionActualId}`,
|
||||
nombre: 'Otros',
|
||||
nombreCorto: 'Otros',
|
||||
color: '#888888',
|
||||
logoUrl: null,
|
||||
votos: 0, // No es relevante para la visualización del porcentaje
|
||||
votosPorcentaje: otrosPorcentaje,
|
||||
};
|
||||
displayResults = [...topParties, otrosEntry];
|
||||
} else if (resultados) {
|
||||
displayResults = resultados.slice(0, cantidadAMostrar);
|
||||
}
|
||||
// --- FIN DE LA LÓGICA DE PROCESAMIENTO "OTROS" ---
|
||||
|
||||
return (
|
||||
<div className="ticker-card" style={{ gridColumn: '1 / -1' }}>
|
||||
<div className="ticker-header">
|
||||
<h3>CONCEJALES - LA PLATA</h3>
|
||||
<select value={seccionActualId} onChange={e => setSeccionActualId(e.target.value)} disabled={secciones.length === 0}>
|
||||
{secciones.map(s => <option key={s.id} value={s.id}>{s.nombre}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
<div className="ticker-results">
|
||||
{isLoading ? <p>Cargando...</p> :
|
||||
displayResults.map(partido => (
|
||||
<div key={partido.id} className="ticker-party">
|
||||
<div className="party-logo">
|
||||
<ImageWithFallback src={partido.logoUrl || undefined} fallbackSrc="/default-avatar.png" alt={`Logo de ${partido.nombre}`} />
|
||||
</div>
|
||||
<div className="party-details">
|
||||
<div className="party-info">
|
||||
<span className="party-name">{partido.nombreCorto || partido.nombre}</span>
|
||||
<span className="party-percent">{formatPercent(partido.votosPorcentaje)}</span>
|
||||
</div>
|
||||
<div className="party-bar-background">
|
||||
<div className="party-bar-foreground" style={{ width: `${partido.votosPorcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -80,17 +80,13 @@ export const CongresoWidget = () => {
|
||||
{camaraActiva === 'diputados' ? (
|
||||
<ParliamentLayout
|
||||
seatData={seatFillData}
|
||||
// --- INICIO DE LA CORRECCIÓN ---
|
||||
// Solo pasamos la prop 'presidenteBancada' si NO estamos en modo oficial
|
||||
presidenteBancada={!esModoOficial ? datosCamaraActual.presidenteBancada : undefined}
|
||||
// --- FIN DE LA CORRECCIÓN ---
|
||||
/>
|
||||
) : (
|
||||
<SenateLayout
|
||||
seatData={seatFillData}
|
||||
// --- INICIO DE LA CORRECCIÓN ---
|
||||
presidenteBancada={!esModoOficial ? datosCamaraActual.presidenteBancada : undefined}
|
||||
// --- FIN DE LA CORRECCIÓN ---
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
28
Elecciones-Web/frontend/src/components/ImageWithFallback.tsx
Normal file
28
Elecciones-Web/frontend/src/components/ImageWithFallback.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
// src/components/ImageWithFallback.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
interface Props extends React.ImgHTMLAttributes<HTMLImageElement> {
|
||||
fallbackSrc: string;
|
||||
}
|
||||
|
||||
export const ImageWithFallback = ({ src, fallbackSrc, ...props }: Props) => {
|
||||
const [imgSrc, setImgSrc] = useState(src);
|
||||
const [error, setError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setError(false);
|
||||
setImgSrc(src);
|
||||
}, [src]);
|
||||
|
||||
const handleError = () => {
|
||||
setError(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<img
|
||||
src={error || !imgSrc ? fallbackSrc : imgSrc}
|
||||
onError={handleError}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
@@ -87,7 +87,7 @@ export const TelegramaWidget = () => {
|
||||
.finally(() => setLoading(false));
|
||||
}
|
||||
}, [selectedMesa]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="telegrama-container">
|
||||
<h4>Consulta de Telegramas por Ubicación</h4>
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
/* src/components/TickerWidget.css */
|
||||
.ticker-container {
|
||||
/* Se cambia a un fondo claro con borde y sombra sutil */
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e0e0e0;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
max-width: 800px;
|
||||
margin: 20px auto;
|
||||
font-family: "Public Sans", system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||
color: #333333; /* Color de texto por defecto */
|
||||
.ticker-wrapper {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
|
||||
gap: 1.5rem;
|
||||
width: 100%;
|
||||
max-width: 1280px;
|
||||
margin: 20px auto;
|
||||
}
|
||||
|
||||
.ticker-container.loading, .ticker-container.error {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
font-style: italic;
|
||||
color: #757575; /* Color de texto atenuado */
|
||||
.ticker-card {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid #e0e0e0;
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.05);
|
||||
padding: 15px 20px;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ticker-header {
|
||||
@@ -48,9 +46,9 @@
|
||||
}
|
||||
|
||||
.ticker-results {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||||
gap: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px; /* Espacio entre partidos */
|
||||
}
|
||||
|
||||
.ticker-party .party-info {
|
||||
@@ -84,4 +82,31 @@
|
||||
border-radius: 4px;
|
||||
transition: width 0.5s ease-in-out;
|
||||
/* El color de fondo se sigue aplicando desde el componente, esto es correcto */
|
||||
}
|
||||
|
||||
.ticker-results {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); /* Aumentamos el tamaño mínimo */
|
||||
gap: 20px;
|
||||
}
|
||||
.ticker-party {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px; /* Espacio entre logo y detalles */
|
||||
}
|
||||
.party-logo {
|
||||
flex-shrink: 0;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
}
|
||||
.party-logo img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
.party-details {
|
||||
flex-grow: 1;
|
||||
min-width: 0; /* Previene que el flex item se desborde */
|
||||
}
|
||||
@@ -1,78 +1,92 @@
|
||||
// src/components/TickerWidget.tsx
|
||||
import { useState, useEffect } from 'react';
|
||||
import { getResumenProvincial } from '../apiService';
|
||||
import type { ResumenProvincial } from '../types/types';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getResumenProvincial, getConfiguracionPublica } from '../apiService';
|
||||
import type { CategoriaResumen, ResultadoTicker } from '../types/types';
|
||||
import { ImageWithFallback } from './ImageWithFallback';
|
||||
import './TickerWidget.css';
|
||||
|
||||
const formatPercent = (num: number) => `${num.toFixed(2).replace('.', ',')}%`;
|
||||
const COLORS = [
|
||||
"#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd",
|
||||
"#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"
|
||||
];
|
||||
const formatPercent = (num: number) => `${(num || 0).toFixed(2).replace('.', ',')}%`;
|
||||
|
||||
export const TickerWidget = () => {
|
||||
const [data, setData] = useState<ResumenProvincial | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
// Se añade un nuevo estado para manejar errores de forma explícita
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const { data: categorias, isLoading, error } = useQuery<CategoriaResumen[]>({
|
||||
queryKey: ['resumenProvincial'],
|
||||
queryFn: getResumenProvincial,
|
||||
refetchInterval: 30000,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const fetchData = async () => {
|
||||
// Se resetea el error en cada intento de carga
|
||||
setError(null);
|
||||
try {
|
||||
const result = await getResumenProvincial();
|
||||
setData(result);
|
||||
} catch (err) {
|
||||
console.error("Error cargando resumen provincial:", err);
|
||||
// Se guarda el mensaje de error para mostrarlo en la UI
|
||||
setError("No se pudo conectar con el servidor para obtener el resumen provincial.");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
const { data: configData } = useQuery({
|
||||
queryKey: ['configuracionPublica'],
|
||||
queryFn: getConfiguracionPublica,
|
||||
staleTime: 0,
|
||||
});
|
||||
|
||||
fetchData(); // Carga inicial
|
||||
const intervalId = setInterval(fetchData, 30000); // Actualiza cada 30 segundos
|
||||
const cantidadAMostrar = parseInt(configData?.TickerResultadosCantidad || '5', 10) + 1;
|
||||
|
||||
return () => clearInterval(intervalId); // Limpia el intervalo al desmontar el componente
|
||||
}, []);
|
||||
if (isLoading) return <div className="ticker-wrapper loading">Cargando resumen...</div>;
|
||||
if (error || !categorias) return <div className="ticker-wrapper error">No hay datos disponibles.</div>;
|
||||
|
||||
if (loading) {
|
||||
return <div className="ticker-container loading">Cargando resultados provinciales...</div>;
|
||||
}
|
||||
|
||||
// Si hay un error, se muestra el mensaje correspondiente
|
||||
if (error) {
|
||||
return <div className="ticker-container error">{error}</div>;
|
||||
}
|
||||
|
||||
if (!data) {
|
||||
return <div className="ticker-container error">No hay datos disponibles.</div>;
|
||||
}
|
||||
const categoriasFiltradas = categorias.filter(c => c.categoriaId !== 7);
|
||||
|
||||
return (
|
||||
<div className="ticker-container">
|
||||
<div className="ticker-header">
|
||||
<h3>PROVINCIA BS. AS.</h3>
|
||||
<div className="ticker-stats">
|
||||
<span>Mesas Escrutadas: <strong>{formatPercent(data.porcentajeEscrutado)}</strong></span>
|
||||
<span>Participación Total: <strong>{formatPercent(data.porcentajeParticipacion)}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="ticker-results">
|
||||
{data.resultados.slice(0, 3).map((partido, index) => (
|
||||
<div key={`${partido.nombre}-${index}`} className="ticker-party">
|
||||
<div className="party-info">
|
||||
<span className="party-name">{partido.nombre}</span>
|
||||
<span className="party-percent">{formatPercent(partido.porcentaje)}</span>
|
||||
<div className="ticker-wrapper">
|
||||
{categoriasFiltradas.map(categoria => {
|
||||
|
||||
let displayResults: ResultadoTicker[] = categoria.resultados;
|
||||
|
||||
if (categoria.resultados.length > cantidadAMostrar) {
|
||||
const topParties = categoria.resultados.slice(0, cantidadAMostrar - 1);
|
||||
const otherParties = categoria.resultados.slice(cantidadAMostrar - 1);
|
||||
const otrosPorcentaje = otherParties.reduce((sum, party) => sum + party.votosPorcentaje, 0);
|
||||
|
||||
const otrosEntry: ResultadoTicker = {
|
||||
id: `otros-${categoria.categoriaId}`,
|
||||
nombre: 'Otros',
|
||||
nombreCorto: 'Otros',
|
||||
color: '#888888',
|
||||
logoUrl: null,
|
||||
votos: 0,
|
||||
votosPorcentaje: otrosPorcentaje,
|
||||
};
|
||||
|
||||
displayResults = [...topParties, otrosEntry];
|
||||
} else {
|
||||
displayResults = categoria.resultados.slice(0, cantidadAMostrar);
|
||||
}
|
||||
|
||||
return (
|
||||
<div key={categoria.categoriaId} className="ticker-card">
|
||||
<div className="ticker-header">
|
||||
<h3>{categoria.categoriaNombre}</h3>
|
||||
<div className="ticker-stats">
|
||||
<span>Mesas: <strong>{formatPercent(categoria.estadoRecuento?.mesasTotalizadasPorcentaje ?? 0)}</strong></span>
|
||||
<span>Part: <strong>{formatPercent(categoria.estadoRecuento?.participacionPorcentaje ?? 0)}</strong></span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="party-bar-background">
|
||||
<div className="party-bar-foreground" style={{ width: `${partido.porcentaje}%`, backgroundColor:COLORS[index % COLORS.length] }}></div>
|
||||
<div className="ticker-results">
|
||||
{displayResults.map(partido => (
|
||||
<div key={partido.id} className="ticker-party">
|
||||
<div className="party-logo">
|
||||
<ImageWithFallback
|
||||
src={partido.logoUrl || undefined}
|
||||
fallbackSrc="/default-avatar.png"
|
||||
alt={`Logo de ${partido.nombre}`}
|
||||
/>
|
||||
</div>
|
||||
<div className="party-details">
|
||||
<div className="party-info">
|
||||
<span className="party-name">{partido.nombreCorto || partido.nombre}</span>
|
||||
<span className="party-percent">{formatPercent(partido.votosPorcentaje)}</span>
|
||||
</div>
|
||||
<div className="party-bar-background">
|
||||
<div className="party-bar-foreground" style={{ width: `${partido.votosPorcentaje}%`, backgroundColor: partido.color || '#888' }}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -40,22 +40,46 @@ export interface GeographyObject {
|
||||
}
|
||||
|
||||
export interface MunicipioSimple { id: string; nombre: string; }
|
||||
export interface AgrupacionResultado { nombre: string; votos: number; porcentaje: number; }
|
||||
|
||||
export interface ResultadoTicker {
|
||||
id: string;
|
||||
nombre: string;
|
||||
nombreCorto: string | null;
|
||||
color: string | null;
|
||||
logoUrl: string | null;
|
||||
votos: number;
|
||||
votosPorcentaje: number;
|
||||
}
|
||||
|
||||
export interface EstadoRecuentoTicker {
|
||||
mesasTotalizadasPorcentaje: number;
|
||||
participacionPorcentaje: number;
|
||||
}
|
||||
|
||||
export interface CategoriaResumen {
|
||||
categoriaId: number;
|
||||
categoriaNombre: string;
|
||||
estadoRecuento: EstadoRecuentoTicker | null;
|
||||
resultados: ResultadoTicker[];
|
||||
}
|
||||
|
||||
export interface VotosAdicionales { enBlanco: number; nulos: number; recurridos: number; }
|
||||
|
||||
export interface MunicipioDetalle {
|
||||
municipioNombre: string;
|
||||
ultimaActualizacion: string;
|
||||
porcentajeEscrutado: number;
|
||||
porcentajeParticipacion: number;
|
||||
resultados: AgrupacionResultado[];
|
||||
resultados: CategoriaResumen[];
|
||||
votosAdicionales: VotosAdicionales;
|
||||
}
|
||||
|
||||
export interface ResumenProvincial {
|
||||
provinciaNombre: string;
|
||||
ultimaActualizacion: string;
|
||||
porcentajeEscrutado: number;
|
||||
porcentajeParticipacion: number;
|
||||
resultados: AgrupacionResultado[];
|
||||
resultados: CategoriaResumen[];
|
||||
votosAdicionales: VotosAdicionales;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ public class AdminController : ControllerBase
|
||||
// Actualizamos las propiedades de la entidad con los valores del DTO.
|
||||
agrupacion.NombreCorto = agrupacionDto.NombreCorto;
|
||||
agrupacion.Color = agrupacionDto.Color;
|
||||
agrupacion.LogoUrl = agrupacionDto.LogoUrl;
|
||||
|
||||
// Guardamos los cambios en la base de datos.
|
||||
await _dbContext.SaveChangesAsync();
|
||||
@@ -178,4 +177,32 @@ public class AdminController : ControllerBase
|
||||
|
||||
return NoContent();
|
||||
}
|
||||
|
||||
[HttpGet("logos")]
|
||||
public async Task<IActionResult> GetLogos()
|
||||
{
|
||||
return Ok(await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().ToListAsync());
|
||||
}
|
||||
|
||||
[HttpPut("logos")]
|
||||
public async Task<IActionResult> UpdateLogos([FromBody] List<LogoAgrupacionCategoria> logos)
|
||||
{
|
||||
// Lógica de "Upsert"
|
||||
foreach (var logo in logos)
|
||||
{
|
||||
var logoExistente = await _dbContext.LogosAgrupacionesCategorias
|
||||
.FirstOrDefaultAsync(l => l.AgrupacionPoliticaId == logo.AgrupacionPoliticaId && l.CategoriaId == logo.CategoriaId);
|
||||
|
||||
if (logoExistente != null)
|
||||
{
|
||||
logoExistente.LogoUrl = logo.LogoUrl;
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(logo.LogoUrl))
|
||||
{
|
||||
_dbContext.LogosAgrupacionesCategorias.Add(logo);
|
||||
}
|
||||
}
|
||||
await _dbContext.SaveChangesAsync();
|
||||
return NoContent();
|
||||
}
|
||||
}
|
||||
@@ -92,59 +92,69 @@ public class ResultadosController : ControllerBase
|
||||
[HttpGet("provincia/{distritoId}")]
|
||||
public async Task<IActionResult> GetResultadosProvinciales(string distritoId)
|
||||
{
|
||||
_logger.LogInformation("Solicitud de resultados para la provincia con distritoId: {DistritoId}", distritoId);
|
||||
|
||||
// PASO 1: Encontrar el ámbito geográfico de la provincia.
|
||||
var provincia = await _dbContext.AmbitosGeograficos.AsNoTracking()
|
||||
.FirstOrDefaultAsync(a => a.DistritoId == distritoId && a.NivelId == 10);
|
||||
|
||||
if (provincia == null)
|
||||
{
|
||||
_logger.LogWarning("No se encontró la provincia con distritoId: {DistritoId}", distritoId);
|
||||
return NotFound(new { message = $"No se encontró la provincia con distritoId {distritoId}" });
|
||||
}
|
||||
|
||||
// PASO 2: Obtener el estado general del recuento para la provincia.
|
||||
// Como las estadísticas generales (mesas, participación) son las mismas para todas las categorías,
|
||||
// simplemente tomamos la primera que encontremos para este ámbito.
|
||||
var estadoGeneral = await _dbContext.EstadosRecuentosGenerales.AsNoTracking()
|
||||
.FirstOrDefaultAsync(e => e.AmbitoGeograficoId == provincia.Id);
|
||||
|
||||
// PASO 3: Obtener el resumen de votos por agrupación para la provincia.
|
||||
// Hacemos un JOIN manual entre ResumenesVotos y AgrupacionesPoliticas para obtener los nombres.
|
||||
var resultados = await _dbContext.ResumenesVotos
|
||||
.AsNoTracking()
|
||||
.Where(r => r.AmbitoGeograficoId == provincia.Id)
|
||||
.Join(
|
||||
_dbContext.AgrupacionesPoliticas.AsNoTracking(),
|
||||
resumen => resumen.AgrupacionPoliticaId,
|
||||
agrupacion => agrupacion.Id,
|
||||
(resumen, agrupacion) => new AgrupacionResultadoDto
|
||||
{
|
||||
Nombre = agrupacion.Nombre,
|
||||
Votos = resumen.Votos,
|
||||
Porcentaje = resumen.VotosPorcentaje
|
||||
})
|
||||
.OrderByDescending(r => r.Votos)
|
||||
var todosLosResumenes = await _dbContext.ResumenesVotos.AsNoTracking()
|
||||
.Include(r => r.AgrupacionPolitica)
|
||||
.ToListAsync();
|
||||
|
||||
// PASO 4: Construir el objeto de respuesta (DTO).
|
||||
// Si no hay datos de recuento aún, usamos valores por defecto para evitar errores en el frontend.
|
||||
var respuestaDto = new ResumenProvincialDto
|
||||
{
|
||||
ProvinciaNombre = provincia.Nombre,
|
||||
UltimaActualizacion = estadoGeneral?.FechaTotalizacion ?? DateTime.UtcNow,
|
||||
PorcentajeEscrutado = estadoGeneral?.MesasTotalizadasPorcentaje ?? 0,
|
||||
PorcentajeParticipacion = estadoGeneral?.ParticipacionPorcentaje ?? 0,
|
||||
Resultados = resultados,
|
||||
// NOTA: Los votos adicionales (nulos, en blanco) no están en la tabla de resumen provincial.
|
||||
// Esto es una mejora pendiente en el Worker. Por ahora, devolvemos 0.
|
||||
VotosAdicionales = new VotosAdicionalesDto { EnBlanco = 0, Nulos = 0, Recurridos = 0 }
|
||||
};
|
||||
// OBTENER TODOS LOS LOGOS EN UNA SOLA CONSULTA
|
||||
var logosLookup = (await _dbContext.LogosAgrupacionesCategorias.AsNoTracking().ToListAsync())
|
||||
.ToLookup(l => $"{l.AgrupacionPoliticaId}-{l.CategoriaId}");
|
||||
|
||||
_logger.LogInformation("Devolviendo {NumResultados} resultados de agrupaciones para la provincia.", respuestaDto.Resultados.Count);
|
||||
if (provincia == null) return NotFound($"No se encontró la provincia con distritoId {distritoId}");
|
||||
|
||||
return Ok(respuestaDto);
|
||||
var estadosPorCategoria = await _dbContext.EstadosRecuentosGenerales.AsNoTracking()
|
||||
.Include(e => e.CategoriaElectoral)
|
||||
.Where(e => e.AmbitoGeograficoId == provincia.Id)
|
||||
.ToDictionaryAsync(e => e.CategoriaId);
|
||||
|
||||
var resultadosPorMunicipio = await _dbContext.ResultadosVotos
|
||||
.AsNoTracking()
|
||||
.Include(r => r.AgrupacionPolitica)
|
||||
.Where(r => r.AmbitoGeografico.NivelId == 30)
|
||||
.ToListAsync();
|
||||
|
||||
var resultadosAgrupados = resultadosPorMunicipio
|
||||
.GroupBy(r => r.CategoriaId)
|
||||
.Select(g => new
|
||||
{
|
||||
CategoriaId = g.Key,
|
||||
TotalVotosCategoria = g.Sum(r => r.CantidadVotos),
|
||||
// Agrupamos por el ID de la agrupación, no por el objeto
|
||||
Resultados = g.GroupBy(r => r.AgrupacionPoliticaId)
|
||||
.Select(partidoGroup => new
|
||||
{
|
||||
// El objeto Agrupacion lo tomamos del primer elemento del grupo
|
||||
Agrupacion = partidoGroup.First().AgrupacionPolitica,
|
||||
Votos = partidoGroup.Sum(r => r.CantidadVotos)
|
||||
})
|
||||
.ToList()
|
||||
})
|
||||
.Select(g => new
|
||||
{
|
||||
g.CategoriaId,
|
||||
CategoriaNombre = estadosPorCategoria.ContainsKey(g.CategoriaId) ? estadosPorCategoria[g.CategoriaId].CategoriaElectoral.Nombre : "Desconocido",
|
||||
EstadoRecuento = estadosPorCategoria.GetValueOrDefault(g.CategoriaId),
|
||||
Resultados = g.Resultados
|
||||
.Select(r => new
|
||||
{
|
||||
r.Agrupacion.Id,
|
||||
r.Agrupacion.Nombre,
|
||||
r.Agrupacion.NombreCorto,
|
||||
r.Agrupacion.Color,
|
||||
LogoUrl = logosLookup[$"{r.Agrupacion.Id}-{g.CategoriaId}"].FirstOrDefault()?.LogoUrl,
|
||||
r.Votos,
|
||||
VotosPorcentaje = g.TotalVotosCategoria > 0 ? ((decimal)r.Votos * 100 / g.TotalVotosCategoria) : 0
|
||||
})
|
||||
.OrderByDescending(r => r.Votos)
|
||||
.ToList()
|
||||
})
|
||||
.OrderBy(c => c.CategoriaId)
|
||||
.ToList();
|
||||
|
||||
return Ok(resultadosAgrupados);
|
||||
}
|
||||
|
||||
|
||||
@@ -503,4 +513,77 @@ public class ResultadosController : ControllerBase
|
||||
|
||||
return Ok(bancadasConOcupantes);
|
||||
}
|
||||
[HttpGet("configuracion-publica")]
|
||||
public async Task<IActionResult> GetConfiguracionPublica()
|
||||
{
|
||||
// Definimos una lista de las claves de configuración que son seguras para el público.
|
||||
// De esta manera, si en el futuro añadimos claves sensibles (como contraseñas de API, etc.),
|
||||
// nunca se expondrán accidentalmente.
|
||||
var clavesPublicas = new List<string>
|
||||
{
|
||||
"TickerResultadosCantidad",
|
||||
"ConcejalesResultadosCantidad"
|
||||
// "OtraClavePublica"
|
||||
};
|
||||
|
||||
var configuracionPublica = await _dbContext.Configuraciones
|
||||
.AsNoTracking()
|
||||
.Where(c => clavesPublicas.Contains(c.Clave))
|
||||
.ToDictionaryAsync(c => c.Clave, c => c.Valor);
|
||||
|
||||
return Ok(configuracionPublica);
|
||||
}
|
||||
|
||||
[HttpGet("concejales/{seccionId}")]
|
||||
public async Task<IActionResult> GetResultadosConcejalesPorSeccion(string seccionId)
|
||||
{
|
||||
// 1. Encontrar todos los municipios (Nivel 30) que pertenecen a la sección dada (Nivel 20)
|
||||
var municipiosDeLaSeccion = await _dbContext.AmbitosGeograficos
|
||||
.AsNoTracking()
|
||||
.Where(a => a.NivelId == 30 && a.SeccionProvincialId == seccionId)
|
||||
.Select(a => a.Id) // Solo necesitamos sus IDs
|
||||
.ToListAsync();
|
||||
|
||||
if (!municipiosDeLaSeccion.Any())
|
||||
{
|
||||
return Ok(new List<object>());
|
||||
}
|
||||
|
||||
// 2. Obtener todos los resultados de la categoría Concejales (ID 7) para esos municipios
|
||||
var resultadosMunicipales = await _dbContext.ResultadosVotos
|
||||
.AsNoTracking()
|
||||
.Include(r => r.AgrupacionPolitica)
|
||||
.Where(r => r.CategoriaId == 7 && municipiosDeLaSeccion.Contains(r.AmbitoGeograficoId))
|
||||
.ToListAsync();
|
||||
|
||||
var logosConcejales = await _dbContext.LogosAgrupacionesCategorias
|
||||
.AsNoTracking()
|
||||
.Where(l => l.CategoriaId == 7)
|
||||
.ToDictionaryAsync(l => l.AgrupacionPoliticaId);
|
||||
|
||||
// 3. Agrupar y sumar en memoria para obtener el total por partido para la sección
|
||||
var totalVotosSeccion = resultadosMunicipales.Sum(r => r.CantidadVotos);
|
||||
|
||||
var resultadosFinales = resultadosMunicipales
|
||||
.GroupBy(r => r.AgrupacionPolitica)
|
||||
.Select(g => new
|
||||
{
|
||||
Agrupacion = g.Key,
|
||||
Votos = g.Sum(r => r.CantidadVotos)
|
||||
})
|
||||
.OrderByDescending(r => r.Votos)
|
||||
.Select(r => new
|
||||
{
|
||||
r.Agrupacion.Id,
|
||||
r.Agrupacion.Nombre,
|
||||
r.Agrupacion.NombreCorto,
|
||||
r.Agrupacion.Color,
|
||||
LogoUrl = logosConcejales.GetValueOrDefault(r.Agrupacion.Id)?.LogoUrl,
|
||||
r.Votos,
|
||||
votosPorcentaje = totalVotosSeccion > 0 ? ((decimal)r.Votos * 100 / totalVotosSeccion) : 0
|
||||
})
|
||||
.ToList();
|
||||
|
||||
return Ok(resultadosFinales);
|
||||
}
|
||||
}
|
||||
@@ -141,6 +141,13 @@ using (var scope = app.Services.CreateScope())
|
||||
context.SaveChanges();
|
||||
Console.WriteLine("--> Seeded default configuration 'MostrarOcupantes'.");
|
||||
}
|
||||
if (!context.Configuraciones.Any(c => c.Clave == "TickerResultadosCantidad"))
|
||||
{
|
||||
context.Configuraciones.Add(new Configuracion { Clave = "TickerResultadosCantidad", Valor = "3" });
|
||||
context.Configuraciones.Add(new Configuracion { Clave = "ConcejalesResultadosCantidad", Valor = "5" });
|
||||
context.SaveChanges();
|
||||
Console.WriteLine("--> Seeded default configuration 'TickerResultadosCantidad'.");
|
||||
}
|
||||
}
|
||||
|
||||
// Configurar el pipeline de peticiones HTTP.
|
||||
|
||||
@@ -14,7 +14,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3b8c6bf754cff6ace486ae8fe850ed4d69233280")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","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=","BlOQCaw/bt9UsCnDEIqO6LwzwEh4i0OxBfeIZgKDR4U=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","2x9HRdaMF3CjEHo\u002BFx\u002BfhG7CTomq/ExTkOKw2bUeHms="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","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=","khGrM2Rl22MsVh9N6\u002B7todRrMuJ6o3ljuHxZF/aubqE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","6xYke/2SzNspypSwIgizeNUH7b\u002Bfoz3wYfKk6z1tMsw="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","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=","BlOQCaw/bt9UsCnDEIqO6LwzwEh4i0OxBfeIZgKDR4U=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","2x9HRdaMF3CjEHo\u002BFx\u002BfhG7CTomq/ExTkOKw2bUeHms="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"tJTBjV/i0Ihkc6XuOu69wxL8PBac9c9Kak6srMso4pU=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["BNGxWTPjjFD1Fj56FltRDUvsBzgMlQvuqV\u002BraH2IhwQ=","t631p0kaOa0gMRIcaPzz1ZVPZ1kuq4pq4kYPWQgoPcM=","PA/Beu9jJpOBY5r5Y1CiSyqrARA2j7LHeWYUnEZpQO8=","ywKm3DCyXg4YCbZAIx3JUlT8N4Irff3GswYUVDST\u002BjQ=","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=","khGrM2Rl22MsVh9N6\u002B7todRrMuJ6o3ljuHxZF/aubqE=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","6xYke/2SzNspypSwIgizeNUH7b\u002Bfoz3wYfKk6z1tMsw="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3b8c6bf754cff6ace486ae8fe850ed4d69233280")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
@@ -19,6 +19,7 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
|
||||
public DbSet<Configuracion> Configuraciones { get; set; }
|
||||
public DbSet<Bancada> Bancadas { get; set; }
|
||||
public DbSet<OcupanteBanca> OcupantesBancas { get; set; }
|
||||
public DbSet<LogoAgrupacionCategoria> LogosAgrupacionesCategorias { get; set; }
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
@@ -75,5 +76,9 @@ public class EleccionesDbContext(DbContextOptions<EleccionesDbContext> options)
|
||||
// Opcional: puede definir un índice
|
||||
entity.HasIndex(o => o.BancadaId).IsUnique();
|
||||
});
|
||||
modelBuilder.Entity<LogoAgrupacionCategoria>(entity =>
|
||||
{
|
||||
entity.HasIndex(l => new { l.AgrupacionPoliticaId, l.CategoriaId }).IsUnique();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -12,8 +12,6 @@ public class AgrupacionPolitica
|
||||
public string Nombre { get; set; } = null!;
|
||||
public string? NombreCorto { get; set; } // Para leyendas y gráficos
|
||||
public string? Color { get; set; } // Código hexadecimal, ej: "#1f77b4"
|
||||
public string? LogoUrl { get; set; } // URL a la imagen del logo
|
||||
// Puede ser nulo si una agrupación no tiene una posición definida.
|
||||
public int? OrdenDiputados { get; set; }
|
||||
public int? OrdenSenadores { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// src/Elecciones.Database/Entities/LogoAgrupacionCategoria.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Elecciones.Database.Entities;
|
||||
|
||||
public class LogoAgrupacionCategoria
|
||||
{
|
||||
[Key]
|
||||
public int Id { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AgrupacionPoliticaId { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
public int CategoriaId { get; set; }
|
||||
|
||||
public string? LogoUrl { get; set; }
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// src/Elecciones.Database/Entities/ResumenVoto.cs
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
@@ -9,11 +10,18 @@ public class ResumenVoto
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public int Id { get; set; }
|
||||
|
||||
// El ámbito donde se resume (siempre provincial en este caso)
|
||||
[Required]
|
||||
public int AmbitoGeograficoId { get; set; }
|
||||
|
||||
[Required]
|
||||
public string AgrupacionPoliticaId { get; set; } = null!;
|
||||
|
||||
[ForeignKey("AgrupacionPoliticaId")]
|
||||
public AgrupacionPolitica AgrupacionPolitica { get; set; } = null!;
|
||||
|
||||
[Required]
|
||||
public long Votos { get; set; }
|
||||
|
||||
[Required]
|
||||
public decimal VotosPorcentaje { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,555 @@
|
||||
// <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("20250901163255_AddLogoAgrupacionCategoriaTable")]
|
||||
partial class AddLogoAgrupacionCategoriaTable
|
||||
{
|
||||
/// <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>("LogoUrl")
|
||||
.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.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>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LogoUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId", "CategoriaId")
|
||||
.IsUnique();
|
||||
|
||||
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.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,79 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddLogoAgrupacionCategoriaTable : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos",
|
||||
type: "nvarchar(450)",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "nvarchar(max)");
|
||||
|
||||
migrationBuilder.CreateTable(
|
||||
name: "LogosAgrupacionesCategorias",
|
||||
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),
|
||||
LogoUrl = table.Column<string>(type: "nvarchar(max)", nullable: true)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_LogosAgrupacionesCategorias", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ResumenesVotos_AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos",
|
||||
column: "AgrupacionPoliticaId");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_LogosAgrupacionesCategorias_AgrupacionPoliticaId_CategoriaId",
|
||||
table: "LogosAgrupacionesCategorias",
|
||||
columns: new[] { "AgrupacionPoliticaId", "CategoriaId" },
|
||||
unique: true);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ResumenesVotos_AgrupacionesPoliticas_AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos",
|
||||
column: "AgrupacionPoliticaId",
|
||||
principalTable: "AgrupacionesPoliticas",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ResumenesVotos_AgrupacionesPoliticas_AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos");
|
||||
|
||||
migrationBuilder.DropTable(
|
||||
name: "LogosAgrupacionesCategorias");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ResumenesVotos_AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos");
|
||||
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "AgrupacionPoliticaId",
|
||||
table: "ResumenesVotos",
|
||||
type: "nvarchar(max)",
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "nvarchar(450)");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,552 @@
|
||||
// <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("20250901163521_RemoveLogoUrlFromAgrupacionPolitica")]
|
||||
partial class RemoveLogoUrlFromAgrupacionPolitica
|
||||
{
|
||||
/// <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.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>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LogoUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId", "CategoriaId")
|
||||
.IsUnique();
|
||||
|
||||
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.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,28 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Elecciones.Database.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class RemoveLogoUrlFromAgrupacionPolitica : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "LogoUrl",
|
||||
table: "AgrupacionesPoliticas");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "LogoUrl",
|
||||
table: "AgrupacionesPoliticas",
|
||||
type: "nvarchar(max)",
|
||||
nullable: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,9 +61,6 @@ namespace Elecciones.Database.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("LogoUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.Property<string>("Nombre")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
@@ -275,6 +272,32 @@ namespace Elecciones.Database.Migrations
|
||||
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>("CategoriaId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("LogoUrl")
|
||||
.HasColumnType("nvarchar(max)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId", "CategoriaId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("LogosAgrupacionesCategorias");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Elecciones.Database.Entities.OcupanteBanca", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
@@ -383,7 +406,7 @@ namespace Elecciones.Database.Migrations
|
||||
|
||||
b.Property<string>("AgrupacionPoliticaId")
|
||||
.IsRequired()
|
||||
.HasColumnType("nvarchar(max)");
|
||||
.HasColumnType("nvarchar(450)");
|
||||
|
||||
b.Property<int>("AmbitoGeograficoId")
|
||||
.HasColumnType("int");
|
||||
@@ -397,6 +420,8 @@ namespace Elecciones.Database.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AgrupacionPoliticaId");
|
||||
|
||||
b.ToTable("ResumenesVotos");
|
||||
});
|
||||
|
||||
@@ -503,6 +528,17 @@ namespace Elecciones.Database.Migrations
|
||||
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");
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+3b8c6bf754cff6ace486ae8fe850ed4d69233280")]
|
||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+608ae655bedf6c59be5fec1e14fc308871d2fd62")]
|
||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||
|
||||
Reference in New Issue
Block a user