Fix bancas widget
This commit is contained in:
@@ -1,73 +1,68 @@
|
|||||||
// src/components/ConfiguracionGeneral.tsx
|
// src/components/ConfiguracionGeneral.tsx
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
import { getAgrupaciones, getConfiguracion, updateConfiguracion } from '../services/apiService';
|
import { getAgrupaciones, getConfiguracion, updateConfiguracion } from '../services/apiService';
|
||||||
import type { AgrupacionPolitica } from '../types';
|
import type { AgrupacionPolitica } from '../types';
|
||||||
import './AgrupacionesManager.css'; // Reutilizamos los estilos para mantener la consistencia
|
import './AgrupacionesManager.css';
|
||||||
|
|
||||||
export const ConfiguracionGeneral = () => {
|
export const ConfiguracionGeneral = () => {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const [agrupaciones, setAgrupaciones] = useState<AgrupacionPolitica[]>([]);
|
const [agrupaciones, setAgrupaciones] = useState<AgrupacionPolitica[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
// Estado específico para la configuración de la presidencia del Senado
|
|
||||||
const [presidenciaSenadoId, setPresidenciaSenadoId] = useState<string>('');
|
const [presidenciaSenadoId, setPresidenciaSenadoId] = useState<string>('');
|
||||||
const [usarDatosOficiales, setUsarDatosOficiales] = useState(false);
|
// Renombramos el estado para mayor claridad
|
||||||
|
const [modoOficialActivo, setModoOficialActivo] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadInitialData = async () => {
|
const loadInitialData = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
setError(null);
|
setError(null);
|
||||||
|
const [agrupacionesData, configData] = await Promise.all([getAgrupaciones(), getConfiguracion()]);
|
||||||
// Hacemos ambas llamadas a la API en paralelo para más eficiencia
|
|
||||||
const [agrupacionesData, configData] = await Promise.all([
|
|
||||||
getAgrupaciones(),
|
|
||||||
getConfiguracion()
|
|
||||||
]);
|
|
||||||
|
|
||||||
setAgrupaciones(agrupacionesData);
|
setAgrupaciones(agrupacionesData);
|
||||||
|
setPresidenciaSenadoId(configData.PresidenciaSenadores || '');
|
||||||
// Asignamos el valor guardado, si existe
|
setModoOficialActivo(configData.UsarDatosDeBancadasOficiales === 'true');
|
||||||
if (configData && configData.PresidenciaSenadores) {
|
|
||||||
setPresidenciaSenadoId(configData.PresidenciaSenadores);
|
|
||||||
}
|
|
||||||
setUsarDatosOficiales(configData.UsarDatosDeBancadasOficiales === 'true');
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error al cargar datos de configuración:", err);
|
console.error("Error al cargar datos de configuración:", err);
|
||||||
setError("No se pudieron cargar los datos necesarios para la configuración.");
|
setError("No se pudieron cargar los datos necesarios para la configuración.");
|
||||||
} finally {
|
} finally { setLoading(false); }
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
loadInitialData();
|
loadInitialData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
try {
|
try {
|
||||||
await updateConfiguracion({ "PresidenciaSenadores": presidenciaSenadoId, "UsarDatosDeBancadasOficiales": usarDatosOficiales.toString() });
|
await updateConfiguracion({
|
||||||
alert('Configuración guardada con éxito.');
|
"PresidenciaSenadores": presidenciaSenadoId,
|
||||||
} catch (err) {
|
"UsarDatosDeBancadasOficiales": modoOficialActivo.toString()
|
||||||
console.error("Error al guardar la configuración:", err);
|
});
|
||||||
alert('Error al guardar la configuración.');
|
await queryClient.invalidateQueries({ queryKey: ['composicionCongreso'] });
|
||||||
|
await queryClient.invalidateQueries({ queryKey: ['bancadasDetalle'] });
|
||||||
|
alert('Configuración guardada.');
|
||||||
|
} catch {
|
||||||
|
alert('Error al guardar.');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (loading) return <div className="admin-module"><p>Cargando configuración...</p></div>;
|
if (loading) return <div className="admin-module"><p>Cargando...</p></div>;
|
||||||
if (error) return <div className="admin-module"><p style={{ color: 'red' }}>{error}</p></div>;
|
if (error) return <div className="admin-module"><p style={{ color: 'red' }}>{error}</p></div>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="admin-module">
|
<div className="admin-module">
|
||||||
<h3>Configuración General de Cámaras</h3>
|
<h3>Configuración General de Visualización</h3>
|
||||||
<div className="form-group">
|
<div className="form-group">
|
||||||
<label>
|
<label>
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
checked={usarDatosOficiales}
|
checked={modoOficialActivo}
|
||||||
onChange={e => setUsarDatosOficiales(e.target.checked)}
|
onChange={e => setModoOficialActivo(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
Activar Modo "Resultados Oficiales"
|
**Activar Modo "Resultados Oficiales"**
|
||||||
</label>
|
</label>
|
||||||
<p style={{ fontSize: '0.8rem', color: '#666', margin: '0.5rem 0 0 0' }}>
|
<p style={{ fontSize: '0.8rem', color: '#666' }}>
|
||||||
Si está activo, el widget del Congreso mostrará la composición gestionada manualmente en esta página. Si está inactivo, mostrará la proyección en tiempo real de las elecciones.
|
Si está activo, el sitio público mostrará la composición de bancas y los ocupantes definidos manualmente en este panel. Si está inactivo, mostrará la proyección en tiempo real de la elección.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginTop: '1rem', paddingBottom: '1rem', borderBottom: '1px solid #eee' }}>
|
<div style={{ marginTop: '1rem', paddingBottom: '1rem', borderBottom: '1px solid #eee' }}>
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
// src/components/LoginPage.tsx
|
// src/components/LoginPage.tsx
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useAuth } from '../context/AuthContext';
|
import { useAuth } from '../context/AuthContext';
|
||||||
|
import { useQueryClient } from '@tanstack/react-query';
|
||||||
|
|
||||||
export const LoginPage = () => {
|
export const LoginPage = () => {
|
||||||
const [username, setUsername] = useState('');
|
const [username, setUsername] = useState('');
|
||||||
const [password, setPassword] = useState('');
|
const [password, setPassword] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
const queryClient = useQueryClient();
|
||||||
const { login } = useAuth();
|
const { login } = useAuth();
|
||||||
|
|
||||||
const handleSubmit = async (e: React.FormEvent) => {
|
const handleSubmit = async (e: React.FormEvent) => {
|
||||||
@@ -14,6 +16,9 @@ export const LoginPage = () => {
|
|||||||
const success = await login({ username, password });
|
const success = await login({ username, password });
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setError('Usuario o contraseña incorrectos.');
|
setError('Usuario o contraseña incorrectos.');
|
||||||
|
} else {
|
||||||
|
// Si el login es exitoso, invalidamos todo para empezar de cero
|
||||||
|
await queryClient.invalidateQueries();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ export interface ComposicionData {
|
|||||||
export interface OcupanteBanca {
|
export interface OcupanteBanca {
|
||||||
id: number;
|
id: number;
|
||||||
nombreOcupante: string;
|
nombreOcupante: string;
|
||||||
fotoUrl: string;
|
fotoUrl: string | null;
|
||||||
periodo: string;
|
periodo: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PartidoData {
|
interface PartidoData {
|
||||||
@@ -35,7 +35,6 @@ interface PartidoData {
|
|||||||
nombre: string;
|
nombre: string;
|
||||||
nombreCorto: string | null;
|
nombreCorto: string | null;
|
||||||
bancasTotales: number;
|
bancasTotales: number;
|
||||||
bancasEnJuego: number;
|
|
||||||
color: string | null;
|
color: string | null;
|
||||||
ocupantes: OcupanteBanca[];
|
ocupantes: OcupanteBanca[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ export const CongresoWidget = () => {
|
|||||||
const { data: composicionData, isLoading: isLoadingComposicion, error: errorComposicion } = useQuery<ComposicionData>({
|
const { data: composicionData, isLoading: isLoadingComposicion, error: errorComposicion } = useQuery<ComposicionData>({
|
||||||
queryKey: ['composicionCongreso'],
|
queryKey: ['composicionCongreso'],
|
||||||
queryFn: getComposicionCongreso,
|
queryFn: getComposicionCongreso,
|
||||||
|
// Vuelve a buscar los datos cada 20 segundos
|
||||||
|
refetchInterval: 20000,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: bancadasDetalle = [] } = useQuery<BancadaDetalle[]>({
|
const { data: bancadasDetalle = [] } = useQuery<BancadaDetalle[]>({
|
||||||
@@ -29,12 +31,18 @@ export const CongresoWidget = () => {
|
|||||||
|
|
||||||
// --- LÓGICA DE SEATFILLDATA ---
|
// --- LÓGICA DE SEATFILLDATA ---
|
||||||
const seatFillData = useMemo(() => {
|
const seatFillData = useMemo(() => {
|
||||||
if (!datosCamaraActual || !bancadasDetalle.length) return [];
|
if (!datosCamaraActual) return [];
|
||||||
|
|
||||||
|
// --- LÓGICA DEL INTERRUPTOR ---
|
||||||
|
// Verificamos si la respuesta de la API contiene datos de ocupantes.
|
||||||
|
// Si bancadasDetalle tiene elementos, significa que el modo "Oficial" está activo en el backend.
|
||||||
|
const modoOficialActivo = bancadasDetalle.length > 0;
|
||||||
|
|
||||||
|
if (modoOficialActivo) {
|
||||||
|
// --- MODO OFICIAL: Construir desde las bancas físicas ---
|
||||||
const camaraId = camaraActiva === 'diputados' ? 0 : 1;
|
const camaraId = camaraActiva === 'diputados' ? 0 : 1;
|
||||||
const bancadasDeCamara = bancadasDetalle.filter(b => b.camara === camaraId);
|
const bancadasDeCamara = bancadasDetalle.filter(b => b.camara === camaraId);
|
||||||
|
|
||||||
// Creamos un mapa de AgrupacionId -> Color para un acceso rápido
|
|
||||||
const colorMap = new Map<string, string>();
|
const colorMap = new Map<string, string>();
|
||||||
datosCamaraActual.partidos.forEach(p => {
|
datosCamaraActual.partidos.forEach(p => {
|
||||||
if (p.id && p.color) {
|
if (p.id && p.color) {
|
||||||
@@ -42,16 +50,23 @@ export const CongresoWidget = () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 1. Aseguramos que la lista de bancas esté en orden físico (por su ID).
|
|
||||||
const bancadasOrdenadas = bancadasDeCamara.sort((a, b) => a.id - b.id);
|
const bancadasOrdenadas = bancadasDeCamara.sort((a, b) => a.id - b.id);
|
||||||
|
|
||||||
// 2. Mapeamos cada banca física a un objeto SeatFillData.
|
|
||||||
// El índice del array corresponderá al asiento visual.
|
|
||||||
return bancadasOrdenadas.map(bancada => ({
|
return bancadasOrdenadas.map(bancada => ({
|
||||||
color: bancada.agrupacionPoliticaId ? colorMap.get(bancada.agrupacionPoliticaId) || DEFAULT_COLOR : DEFAULT_COLOR,
|
color: bancada.agrupacionPoliticaId ? colorMap.get(bancada.agrupacionPoliticaId) || DEFAULT_COLOR : DEFAULT_COLOR,
|
||||||
ocupante: bancada.ocupante
|
ocupante: bancada.ocupante
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// --- MODO PROYECCIÓN: Construir desde los totales de los partidos ---
|
||||||
|
// Esta es la lógica original que teníamos para el modo proyección.
|
||||||
|
return datosCamaraActual.partidos.flatMap(party => {
|
||||||
|
const seatColor = party.color || DEFAULT_COLOR;
|
||||||
|
// En modo proyección, no hay ocupantes individuales.
|
||||||
|
return Array(party.bancasTotales).fill({ color: seatColor, ocupante: null });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}, [datosCamaraActual, bancadasDetalle, camaraActiva]);
|
}, [datosCamaraActual, bancadasDetalle, camaraActiva]);
|
||||||
|
|
||||||
if (isLoadingComposicion) return <div className="congreso-container loading">Cargando...</div>;
|
if (isLoadingComposicion) return <div className="congreso-container loading">Cargando...</div>;
|
||||||
|
|||||||
@@ -127,28 +127,29 @@ export const ParliamentLayout: React.FC<ParliamentLayoutProps> = ({
|
|||||||
|
|
||||||
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
||||||
if (presidenteBancada && presidenteBancada.color) {
|
if (presidenteBancada && presidenteBancada.color) {
|
||||||
// Encontramos el índice del último asiento que pertenece al partido del presidente.
|
|
||||||
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
||||||
|
|
||||||
if (lastSeatIndex !== -1) {
|
if (lastSeatIndex !== -1) {
|
||||||
// Eliminamos ese asiento de la lista de asientos electorales.
|
|
||||||
finalSeatData.splice(lastSeatIndex, 1);
|
finalSeatData.splice(lastSeatIndex, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderedElements = seatElements.map((child, index) => {
|
const renderedElements = seatElements.map((child, index) => {
|
||||||
// El asiento presidencial sigue siendo un caso especial
|
// --- CASO ESPECIAL: ASIENTO PRESIDENCIAL ---
|
||||||
if (index === PRESIDENTE_SEAT_INDEX) {
|
if (index === PRESIDENTE_SEAT_INDEX) {
|
||||||
return React.cloneElement(child, {
|
return React.cloneElement(child, {
|
||||||
fill: presidenteBancada?.color || '#A9A9A9',
|
fill: presidenteBancada?.color || '#A9A9A9',
|
||||||
stroke: '#000000',
|
stroke: '#000000',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
|
// Le damos un tooltip genérico al presidente
|
||||||
|
'data-tooltip-id': 'seat-tooltip',
|
||||||
|
'data-tooltip-html': `<div class="seat-tooltip"><p>Presidencia de la Cámara</p></div>`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// La lógica ahora es simple: el asiento en el índice X del SVG
|
// --- LÓGICA NORMAL PARA EL RESTO DE ASIENTOS ---
|
||||||
// corresponde al asiento en el índice X de los datos.
|
// Usamos la copia modificada 'finalSeatData'. Como este array es más corto,
|
||||||
const seat = seatData[index];
|
// el último asiento electoral no encontrará datos y quedará gris, lo cual es correcto.
|
||||||
|
const seat = finalSeatData[index];
|
||||||
|
|
||||||
if (!seat) {
|
if (!seat) {
|
||||||
return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 });
|
return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 });
|
||||||
|
|||||||
@@ -81,28 +81,29 @@ export const SenateLayout: React.FC<SenateLayoutProps> = ({
|
|||||||
|
|
||||||
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
// Si hay un presidente y su partido tiene bancas, le quitamos una para asignarla.
|
||||||
if (presidenteBancada && presidenteBancada.color) {
|
if (presidenteBancada && presidenteBancada.color) {
|
||||||
// Encontramos el índice del último asiento que pertenece al partido del presidente.
|
|
||||||
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
const lastSeatIndex = finalSeatData.map(s => s.color).lastIndexOf(presidenteBancada.color);
|
||||||
|
|
||||||
if (lastSeatIndex !== -1) {
|
if (lastSeatIndex !== -1) {
|
||||||
// Eliminamos ese asiento de la lista de asientos electorales.
|
|
||||||
finalSeatData.splice(lastSeatIndex, 1);
|
finalSeatData.splice(lastSeatIndex, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderedElements = seatElements.map((child, index) => {
|
const renderedElements = seatElements.map((child, index) => {
|
||||||
// El asiento presidencial sigue siendo un caso especial
|
// --- CASO ESPECIAL: ASIENTO PRESIDENCIAL ---
|
||||||
if (index === PRESIDENTE_SEAT_INDEX) {
|
if (index === PRESIDENTE_SEAT_INDEX) {
|
||||||
return React.cloneElement(child, {
|
return React.cloneElement(child, {
|
||||||
fill: presidenteBancada?.color || '#A9A9A9',
|
fill: presidenteBancada?.color || '#A9A9A9',
|
||||||
stroke: '#000000',
|
stroke: '#000000',
|
||||||
strokeWidth: 2,
|
strokeWidth: 2,
|
||||||
|
// Le damos un tooltip genérico al presidente
|
||||||
|
'data-tooltip-id': 'seat-tooltip',
|
||||||
|
'data-tooltip-html': `<div class="seat-tooltip"><p>Presidencia de la Cámara</p></div>`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// La lógica ahora es simple: el asiento en el índice X del SVG
|
// --- LÓGICA NORMAL PARA EL RESTO DE ASIENTOS ---
|
||||||
// corresponde al asiento en el índice X de los datos.
|
// Usamos la copia modificada 'finalSeatData'. Como este array es más corto,
|
||||||
const seat = seatData[index];
|
// el último asiento electoral no encontrará datos y quedará gris, lo cual es correcto.
|
||||||
|
const seat = finalSeatData[index];
|
||||||
|
|
||||||
if (!seat) {
|
if (!seat) {
|
||||||
return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 });
|
return React.cloneElement(child, { fill: '#E0E0E0', stroke: '#ffffff', strokeWidth: 1.5 });
|
||||||
|
|||||||
@@ -295,57 +295,33 @@ public class ResultadosController : ControllerBase
|
|||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.ToDictionaryAsync(c => c.Clave, c => c.Valor);
|
.ToDictionaryAsync(c => c.Clave, c => c.Valor);
|
||||||
|
|
||||||
|
// Aquí está el interruptor
|
||||||
config.TryGetValue("UsarDatosDeBancadasOficiales", out var usarDatosOficialesValue);
|
config.TryGetValue("UsarDatosDeBancadasOficiales", out var usarDatosOficialesValue);
|
||||||
bool usarDatosOficiales = usarDatosOficialesValue == "true";
|
bool usarDatosOficiales = usarDatosOficialesValue == "true";
|
||||||
|
|
||||||
if (usarDatosOficiales)
|
if (usarDatosOficiales)
|
||||||
{
|
{
|
||||||
|
// Si el interruptor está en 'true', llama a este método
|
||||||
return await GetComposicionDesdeBancadasOficiales(config);
|
return await GetComposicionDesdeBancadasOficiales(config);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Si está en 'false' o no existe, llama a este otro
|
||||||
return await GetComposicionDesdeProyecciones(config);
|
return await GetComposicionDesdeProyecciones(config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<IActionResult> GetComposicionDesdeBancadasOficiales(Dictionary<string, string> config)
|
private async Task<IActionResult> GetComposicionDesdeBancadasOficiales(Dictionary<string, string> config)
|
||||||
{
|
{
|
||||||
config.TryGetValue("MostrarOcupantes", out var mostrarOcupantesValue);
|
var bancadas = await _dbContext.Bancadas.AsNoTracking()
|
||||||
bool mostrarOcupantes = mostrarOcupantesValue == "true";
|
.Include(b => b.AgrupacionPolitica)
|
||||||
|
.Include(b => b.Ocupante)
|
||||||
// Se declara la variable explícitamente como IQueryable<Bancada>
|
.ToListAsync();
|
||||||
IQueryable<Bancada> bancadasQuery = _dbContext.Bancadas.AsNoTracking()
|
|
||||||
.Include(b => b.AgrupacionPolitica);
|
|
||||||
|
|
||||||
if (mostrarOcupantes)
|
|
||||||
{
|
|
||||||
// Ahora sí podemos añadir otro .Include() sin problemas de tipo
|
|
||||||
bancadasQuery = bancadasQuery.Include(b => b.Ocupante);
|
|
||||||
}
|
|
||||||
|
|
||||||
var bancadas = await bancadasQuery.ToListAsync();
|
|
||||||
|
|
||||||
// --- CAMBIO 2: Eliminar la carga manual de Ocupantes ---
|
|
||||||
// Ya no necesitamos 'ocupantesLookup'. Se puede borrar todo este bloque:
|
|
||||||
/*
|
|
||||||
var ocupantesLookup = new Dictionary<int, OcupanteBanca>();
|
|
||||||
if (mostrarOcupantes)
|
|
||||||
{
|
|
||||||
ocupantesLookup = (await _dbContext.OcupantesBancas.AsNoTracking()
|
|
||||||
.ToListAsync())
|
|
||||||
.ToDictionary(o => o.BancadaId);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
var bancasPorAgrupacion = bancadas
|
var bancasPorAgrupacion = bancadas
|
||||||
.Where(b => b.AgrupacionPoliticaId != null)
|
.Where(b => b.AgrupacionPolitica != null)
|
||||||
.GroupBy(b => new { b.AgrupacionPoliticaId, b.Camara })
|
.GroupBy(b => b.AgrupacionPolitica)
|
||||||
.Select(g => new
|
.Select(g => new { Agrupacion = g.Key!, Camara = g.First().Camara, BancasTotales = g.Count() })
|
||||||
{
|
|
||||||
Agrupacion = g.First().AgrupacionPolitica,
|
|
||||||
g.Key.Camara,
|
|
||||||
BancasTotales = g.Count()
|
|
||||||
})
|
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
var presidenteDiputados = bancasPorAgrupacion
|
var presidenteDiputados = bancasPorAgrupacion
|
||||||
@@ -356,25 +332,14 @@ public class ResultadosController : ControllerBase
|
|||||||
config.TryGetValue("PresidenciaSenadores", out var idPartidoPresidenteSenadores);
|
config.TryGetValue("PresidenciaSenadores", out var idPartidoPresidenteSenadores);
|
||||||
var presidenteSenadores = await _dbContext.AgrupacionesPoliticas.FindAsync(idPartidoPresidenteSenadores);
|
var presidenteSenadores = await _dbContext.AgrupacionesPoliticas.FindAsync(idPartidoPresidenteSenadores);
|
||||||
|
|
||||||
object MapearPartidos(Core.Enums.TipoCamara camara)
|
object MapearPartidosOficial(Core.Enums.TipoCamara camara)
|
||||||
{
|
{
|
||||||
// 1. Filtramos las bancadas que nos interesan (por cámara y que tengan partido).
|
// 1. Filtramos las bancadas que nos interesan (por cámara y que tengan partido).
|
||||||
var bancadasDeCamara = bancadas
|
var partidosDeCamara = bancasPorAgrupacion.Where(b => b.Camara == camara);
|
||||||
.Where(b => b.Camara == camara && b.AgrupacionPolitica != null);
|
|
||||||
|
|
||||||
// 2. --- ¡EL CAMBIO CLAVE ESTÁ AQUÍ! ---
|
// 2. --- ¡EL CAMBIO CLAVE ESTÁ AQUÍ! ---
|
||||||
// Agrupamos por el ID de la Agrupación, no por el objeto.
|
// Agrupamos por el ID de la Agrupación, no por el objeto.
|
||||||
// Esto garantiza que todas las bancadas del mismo partido terminen en el MISMO grupo.
|
// Esto garantiza que todas las bancadas del mismo partido terminen en el MISMO grupo.
|
||||||
var partidosDeCamara = bancadasDeCamara
|
|
||||||
.GroupBy(b => b.AgrupacionPolitica!.Id)
|
|
||||||
.Select(g => new
|
|
||||||
{
|
|
||||||
// La Agrupacion la podemos tomar del primer elemento del grupo,
|
|
||||||
// ya que todas las bancadas del grupo pertenecen al mismo partido.
|
|
||||||
Agrupacion = g.First().AgrupacionPolitica!,
|
|
||||||
// g ahora contiene la lista COMPLETA de bancadas para esta agrupación.
|
|
||||||
BancasDelPartido = g.ToList()
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. Ordenamos, como antes, pero ahora sobre una lista de grupos correcta.
|
// 3. Ordenamos, como antes, pero ahora sobre una lista de grupos correcta.
|
||||||
var partidosOrdenados = (camara == Core.Enums.TipoCamara.Diputados)
|
var partidosOrdenados = (camara == Core.Enums.TipoCamara.Diputados)
|
||||||
@@ -382,27 +347,18 @@ public class ResultadosController : ControllerBase
|
|||||||
: partidosDeCamara.OrderBy(p => p.Agrupacion.OrdenSenadores ?? 999);
|
: partidosDeCamara.OrderBy(p => p.Agrupacion.OrdenSenadores ?? 999);
|
||||||
|
|
||||||
// 4. Mapeamos al resultado final.
|
// 4. Mapeamos al resultado final.
|
||||||
return partidosOrdenados
|
return partidosDeCamara.Select(p => new
|
||||||
.ThenByDescending(p => p.BancasDelPartido.Count)
|
|
||||||
.Select(p =>
|
|
||||||
{
|
|
||||||
// Ahora 'p.BancasDelPartido' contiene TODAS las bancadas del partido (en tu caso, las 2).
|
|
||||||
// Cuando hagamos el .Select() aquí, recorrerá ambas y encontrará a los ocupantes.
|
|
||||||
var ocupantesDelPartido = p.BancasDelPartido
|
|
||||||
.Select(b => b.Ocupante)
|
|
||||||
.Where(o => o != null)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
return new
|
|
||||||
{
|
{
|
||||||
p.Agrupacion.Id,
|
p.Agrupacion.Id,
|
||||||
p.Agrupacion.Nombre,
|
p.Agrupacion.Nombre,
|
||||||
p.Agrupacion.NombreCorto,
|
p.Agrupacion.NombreCorto,
|
||||||
p.Agrupacion.Color,
|
p.Agrupacion.Color,
|
||||||
BancasTotales = p.BancasDelPartido.Count,
|
p.BancasTotales,
|
||||||
// ¡Esta lista ahora debería contener a tus 2 ocupantes!
|
// Adjuntamos la lista de ocupantes para este partido
|
||||||
Ocupantes = mostrarOcupantes ? ocupantesDelPartido : new List<OcupanteBanca?>()
|
Ocupantes = bancadas
|
||||||
};
|
.Where(b => b.AgrupacionPoliticaId == p.Agrupacion.Id && b.Camara == p.Camara && b.Ocupante != null)
|
||||||
|
.Select(b => b.Ocupante)
|
||||||
|
.ToList()
|
||||||
}).ToList();
|
}).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,7 +368,7 @@ public class ResultadosController : ControllerBase
|
|||||||
CamaraNombre = "Cámara de Diputados",
|
CamaraNombre = "Cámara de Diputados",
|
||||||
TotalBancas = 92,
|
TotalBancas = 92,
|
||||||
BancasEnJuego = 0,
|
BancasEnJuego = 0,
|
||||||
Partidos = MapearPartidos(Core.Enums.TipoCamara.Diputados),
|
Partidos = MapearPartidosOficial(Core.Enums.TipoCamara.Diputados),
|
||||||
PresidenteBancada = presidenteDiputados != null ? new { presidenteDiputados.Color } : null
|
PresidenteBancada = presidenteDiputados != null ? new { presidenteDiputados.Color } : null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -421,7 +377,7 @@ public class ResultadosController : ControllerBase
|
|||||||
CamaraNombre = "Cámara de Senadores",
|
CamaraNombre = "Cámara de Senadores",
|
||||||
TotalBancas = 46,
|
TotalBancas = 46,
|
||||||
BancasEnJuego = 0,
|
BancasEnJuego = 0,
|
||||||
Partidos = MapearPartidos(Core.Enums.TipoCamara.Senadores),
|
Partidos = MapearPartidosOficial(Core.Enums.TipoCamara.Senadores),
|
||||||
PresidenteBancada = presidenteSenadores != null ? new { presidenteSenadores.Color } : null
|
PresidenteBancada = presidenteSenadores != null ? new { presidenteSenadores.Color } : null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -472,7 +428,8 @@ public class ResultadosController : ControllerBase
|
|||||||
b.Agrupacion.Nombre,
|
b.Agrupacion.Nombre,
|
||||||
b.Agrupacion.NombreCorto,
|
b.Agrupacion.NombreCorto,
|
||||||
b.Agrupacion.Color,
|
b.Agrupacion.Color,
|
||||||
b.Bancas.BancasTotales
|
b.Bancas.BancasTotales,
|
||||||
|
Ocupantes = new List<object>() // <-- Siempre vacío en modo proyección
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
}
|
}
|
||||||
@@ -502,24 +459,20 @@ public class ResultadosController : ControllerBase
|
|||||||
public async Task<IActionResult> GetBancadasConOcupantes()
|
public async Task<IActionResult> GetBancadasConOcupantes()
|
||||||
{
|
{
|
||||||
var config = await _dbContext.Configuraciones.AsNoTracking().ToDictionaryAsync(c => c.Clave, c => c.Valor);
|
var config = await _dbContext.Configuraciones.AsNoTracking().ToDictionaryAsync(c => c.Clave, c => c.Valor);
|
||||||
config.TryGetValue("MostrarOcupantes", out var mostrarOcupantesValue);
|
|
||||||
if (mostrarOcupantesValue != "true")
|
config.TryGetValue("UsarDatosDeBancadasOficiales", out var usarDatosOficialesValue);
|
||||||
|
if (usarDatosOficialesValue != "true")
|
||||||
{
|
{
|
||||||
// Si la opción está desactivada, devolvemos un array vacío.
|
// Si el modo oficial no está activo, SIEMPRE devolvemos un array vacío.
|
||||||
return Ok(new List<object>());
|
return Ok(new List<object>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Si el modo oficial SÍ está activo, devolvemos los detalles.
|
||||||
var bancadasConOcupantes = await _dbContext.Bancadas
|
var bancadasConOcupantes = await _dbContext.Bancadas
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Include(b => b.Ocupante)
|
.Include(b => b.Ocupante)
|
||||||
.Where(b => b.Ocupante != null) // Solo las que tienen un ocupante asignado
|
.Select(b => new { b.Id, b.Camara, b.AgrupacionPoliticaId, Ocupante = b.Ocupante })
|
||||||
.Select(b => new
|
.OrderBy(b => b.Id)
|
||||||
{
|
|
||||||
b.Id,
|
|
||||||
b.Camara,
|
|
||||||
b.AgrupacionPoliticaId,
|
|
||||||
Ocupante = b.Ocupante
|
|
||||||
})
|
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
return Ok(bancadasConOcupantes);
|
return Ok(bancadasConOcupantes);
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+55954e18a797dce22f76f00b645832f361d97362")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1ed9a49a5373209c105168d721df4c77b6c1f329")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Api")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"GlobalPropertiesHash":"b5T/+ta4fUd8qpIzUTm3KyEwAYYUsU5ASo+CSFM3ByE=","FingerprintPatternsHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["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=","GeIeP3tog3JZwKJCFe6prPm1MG/MSEFptilJTMpLZdk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DfeTw\u002BIdhmMK9IhKuwlSfgckGaIOiGMaYzhCKVkysII="],"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=","XNJwPCDHDCECwfNSMw\u002B6U9bmP9Oc1zMcX0NwP0k5bF8=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","T1/vt/jpzUAMkv7\u002BVei1e0uBlnnKJZz40wzx6s2b4L0="],"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=","GeIeP3tog3JZwKJCFe6prPm1MG/MSEFptilJTMpLZdk=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","DfeTw\u002BIdhmMK9IhKuwlSfgckGaIOiGMaYzhCKVkysII="],"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=","XNJwPCDHDCECwfNSMw\u002B6U9bmP9Oc1zMcX0NwP0k5bF8=","P8JRhYPpULTLMAydvl3Ky\u002B92/tYDIjui0l66En4aXuQ=","T1/vt/jpzUAMkv7\u002BVei1e0uBlnnKJZz40wzx6s2b4L0="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+55954e18a797dce22f76f00b645832f361d97362")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1ed9a49a5373209c105168d721df4c77b6c1f329")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Core")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+55954e18a797dce22f76f00b645832f361d97362")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1ed9a49a5373209c105168d721df4c77b6c1f329")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Database")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ using System.Reflection;
|
|||||||
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyCompanyAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
|
||||||
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
|
||||||
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+55954e18a797dce22f76f00b645832f361d97362")]
|
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+1ed9a49a5373209c105168d721df4c77b6c1f329")]
|
||||||
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyProductAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
[assembly: System.Reflection.AssemblyTitleAttribute("Elecciones.Infrastructure")]
|
||||||
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
|
||||||
|
|||||||
Reference in New Issue
Block a user