Diseño de un AuditoriaController con un patrón para añadir endpoints de historial para diferentes entidades.
Implementación de la lógica de servicio y repositorio para obtener datos de las tablas _H para:
Usuarios (gral_Usuarios_H)
Pagos de Distribuidores (cue_PagosDistribuidor_H)
Notas de Crédito/Débito (cue_CreditosDebitos_H)
Entradas/Salidas de Distribuidores (dist_EntradasSalidas_H)
Entradas/Salidas de Canillitas (dist_EntradasSalidasCanillas_H)
Novedades de Canillitas (dist_dtNovedadesCanillas_H)
Ajustes Manuales de Saldo (cue_SaldoAjustesHistorial)
Tipos de Pago (cue_dtTipopago_H)
Canillitas (Maestro) (dist_dtCanillas_H)
Distribuidores (Maestro) (dist_dtDistribuidores_H)
Empresas (Maestro) (dist_dtEmpresas_H)
DTOs específicos para cada tipo de historial, incluyendo NombreUsuarioModifico.
Frontend:
Servicio auditoriaService.ts con métodos para llamar a cada endpoint de historial.
Página AuditoriaGeneralPage.tsx con:
Selector de "Tipo de Entidad a Auditar".
Filtros comunes (Fechas, Usuario Modificador, Tipo de Modificación, ID Entidad).
Un DataGrid que muestra las columnas dinámicamente según el tipo de entidad seleccionada.
Lógica para cargar los datos correspondientes.
DTOs de historial en TypeScript.
Actualizaciones en AppRoutes.tsx y MainLayout.tsx para la nueva sección de Auditoría (restringida a SuperAdmin).
This commit is contained in:
2025-06-09 19:37:07 -03:00
parent 35e24ab7d2
commit 437b1e8864
98 changed files with 3683 additions and 325 deletions

View File

@@ -0,0 +1,190 @@
import apiClient from '../apiClient';
import type { UsuarioHistorialDto } from '../../models/dtos/Usuarios/Auditoria/UsuarioHistorialDto';
import type { PagoDistribuidorHistorialDto } from '../../models/dtos/Auditoria/PagoDistribuidorHistorialDto';
import type { NotaCreditoDebitoHistorialDto } from '../../models/dtos/Auditoria/NotaCreditoDebitoHistorialDto';
import type { EntradaSalidaDistHistorialDto } from '../../models/dtos/Auditoria/EntradaSalidaDistHistorialDto';
import type { EntradaSalidaCanillaHistorialDto } from '../../models/dtos/Auditoria/EntradaSalidaCanillaHistorialDto';
import type { NovedadCanillaHistorialDto } from '../../models/dtos/Auditoria/NovedadCanillaHistorialDto';
import type { SaldoAjusteHistorialDto } from '../../models/dtos/Auditoria/SaldoAjusteHistorialDto';
import type { TipoPagoHistorialDto } from '../../models/dtos/Auditoria/TipoPagoHistorialDto';
import type { CanillaHistorialDto } from '../../models/dtos/Auditoria/CanillaHistorialDto';
import type { DistribuidorHistorialDto } from '../../models/dtos/Auditoria/DistribuidorHistorialDto';
import type { EmpresaHistorialDto } from '../../models/dtos/Auditoria/EmpresaHistorialDto';
interface HistorialParamsComunes {
fechaDesde?: string; // "yyyy-MM-dd"
fechaHasta?: string; // "yyyy-MM-dd"
idUsuarioModificador?: number; // Cambiado de idUsuarioModifico
tipoModificacion?: string; // Cambiado de tipoMod
}
interface HistorialEmpresasMaestroParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idEmpresaAfectada?: number;
}
interface HistorialDistribuidoresMaestroParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idDistribuidorAfectado?: number;
}
interface HistorialCanillitasMaestroParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idCanillaAfectado?: number;
}
interface HistorialTiposPagoParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idTipoPagoAfectado?: number;
}
interface HistorialAjustesSaldoParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
destino?: string;
idDestino?: number;
idEmpresa?: number;
}
interface HistorialNovedadesCanillaParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idNovedadAfectada?: number;
// idCanilla?: number; // Si quieres filtrar por canillita directamente aquí
}
interface HistorialEntradaSalidaDistParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idParteAfectada?: number; // ID del movimiento original
// Filtros adicionales si el backend los soporta para este historial específico
// idPublicacion?: number;
// idDistribuidor?: number;
}
interface HistorialNotasCDParams extends HistorialParamsComunes {
idNotaAfectada?: number; // ID de la nota original
// Podrías añadir más filtros específicos si fueran necesarios
}
interface HistorialUsuariosParams extends HistorialParamsComunes {
idUsuarioAfectado?: number;
}
interface HistorialPagosDistribuidorParams extends HistorialParamsComunes {
idPagoAfectado?: number; // ID del pago original
// Podría añadir filtros específicos para pagos si es necesario, como idDistribuidor, idEmpresa
}
interface HistorialEntradaSalidaCanillaParams extends HistorialParamsComunes { // << NUEVA INTERFAZ
idParteAfectada?: number;
// idPublicacion?: number; // Si quieres añadir más filtros específicos
// idCanilla?: number;
}
const getHistorialUsuarios = async (params: HistorialUsuariosParams): Promise<UsuarioHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador; // Renombrar para el backend si es diferente
const response = await apiClient.get<UsuarioHistorialDto[]>('/auditoria/usuarios', { params: queryParams });
return response.data;
};
const getHistorialPagosDistribuidor = async (params: HistorialPagosDistribuidorParams): Promise<PagoDistribuidorHistorialDto[]> => {
const queryParams: any = { ...params };
// Asegurar que los nombres de parámetros coincidan con el backend
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<PagoDistribuidorHistorialDto[]>('/auditoria/pagos-distribuidores', { params: queryParams });
return response.data;
};
const getHistorialNotasCD = async (params: HistorialNotasCDParams): Promise<NotaCreditoDebitoHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<NotaCreditoDebitoHistorialDto[]>('/auditoria/notas-credito-debito', { params: queryParams });
return response.data;
};
const getHistorialEntradasSalidasDist = async (params: HistorialEntradaSalidaDistParams): Promise<EntradaSalidaDistHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<EntradaSalidaDistHistorialDto[]>('/auditoria/entradas-salidas-dist', { params: queryParams });
return response.data;
};
const getHistorialEntradasSalidasCanilla = async (params: HistorialEntradaSalidaCanillaParams): Promise<EntradaSalidaCanillaHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<EntradaSalidaCanillaHistorialDto[]>('/auditoria/entradas-salidas-canilla', { params: queryParams });
return response.data;
};
const getHistorialNovedadesCanilla = async (params: HistorialNovedadesCanillaParams): Promise<NovedadCanillaHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<NovedadCanillaHistorialDto[]>('/auditoria/novedades-canilla', { params: queryParams });
return response.data;
};
const getHistorialAjustesSaldo = async (params: HistorialAjustesSaldoParams): Promise<SaldoAjusteHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
// Los otros filtros (destino, idDestino, idEmpresa) ya tienen los nombres correctos
const response = await apiClient.get<SaldoAjusteHistorialDto[]>('/auditoria/ajustes-saldo', { params: queryParams });
return response.data;
};
const getHistorialTiposPago = async (params: HistorialTiposPagoParams): Promise<TipoPagoHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<TipoPagoHistorialDto[]>('/auditoria/tipos-pago', { params: queryParams });
return response.data;
};
const getHistorialCanillitasMaestro = async (params: HistorialCanillitasMaestroParams): Promise<CanillaHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<CanillaHistorialDto[]>('/auditoria/canillitas-maestro', { params: queryParams });
return response.data;
};
const getHistorialDistribuidoresMaestro = async (params: HistorialDistribuidoresMaestroParams): Promise<DistribuidorHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<DistribuidorHistorialDto[]>('/auditoria/distribuidores-maestro', { params: queryParams });
return response.data;
};
const getHistorialEmpresasMaestro = async (params: HistorialEmpresasMaestroParams): Promise<EmpresaHistorialDto[]> => {
const queryParams: any = { ...params };
if (params.idUsuarioModificador) queryParams.idUsuarioModifico = params.idUsuarioModificador;
delete queryParams.idUsuarioModificador;
const response = await apiClient.get<EmpresaHistorialDto[]>('/auditoria/empresas-maestro', { params: queryParams });
return response.data;
};
const auditoriaService = {
getHistorialUsuarios,
getHistorialPagosDistribuidor,
getHistorialNotasCD,
getHistorialEntradasSalidasDist,
getHistorialEntradasSalidasCanilla,
getHistorialNovedadesCanilla,
getHistorialAjustesSaldo,
getHistorialTiposPago,
getHistorialCanillitasMaestro,
getHistorialDistribuidoresMaestro,
getHistorialEmpresasMaestro,
};
export default auditoriaService;

View File

@@ -0,0 +1,39 @@
import apiClient from '../apiClient';
import type { CambioParadaDto } from '../../models/dtos/Distribucion/CambioParadaDto';
import type { CreateCambioParadaDto } from '../../models/dtos/Distribucion/CreateCambioParadaDto';
import type { UpdateCambioParadaDto } from '../../models/dtos/Distribucion/UpdateCambioParadaDto';
// Obtiene todos los registros de cambio de parada para un canillita.
const getParadasPorCanilla = async (idCanilla: number): Promise<CambioParadaDto[]> => {
const response = await apiClient.get<CambioParadaDto[]>(`/canillas/${idCanilla}/paradas`);
return response.data;
};
// Crea un nuevo registro de cambio de parada (y cierra el anterior si aplica en backend).
const createParada = async (idCanilla: number, data: CreateCambioParadaDto): Promise<CambioParadaDto> => {
const response = await apiClient.post<CambioParadaDto>(`/canillas/${idCanilla}/paradas`, data);
return response.data;
};
// Cierra la vigencia de una parada específica (actualiza VigenciaH).
// Nota: La ruta podría ser /paradas/{idRegistroParada}/cerrar si el idRegistroParada es globalmente único.
// O /canillas/{idCanilla}/paradas/{idRegistroParada}/cerrar si necesitas el contexto del canillita.
// Asumiré la ruta que usaste en el controlador: /api/paradas/{idRegistroParada}/cerrar
const cerrarParada = async (idRegistroParada: number, data: UpdateCambioParadaDto): Promise<void> => {
await apiClient.put(`/paradas/${idRegistroParada}/cerrar`, data);
};
// Elimina un registro de cambio de parada (si se permite esta acción).
const deleteParada = async (idRegistroParada: number): Promise<void> => {
await apiClient.delete(`/paradas/${idRegistroParada}`);
};
const cambioParadaService = {
getParadasPorCanilla,
createParada,
cerrarParada,
deleteParada,
};
export default cambioParadaService;

View File

@@ -25,6 +25,34 @@ apiClient.interceptors.request.use(
}
);
apiClient.interceptors.response.use(
(response) => {
// Cualquier código de estado que este dentro del rango de 2xx causa la ejecución de esta función
return response;
},
(error) => {
// Cualquier código de estado que este fuera del rango de 2xx causa la ejecución de esta función
if (axios.isAxiosError(error) && error.response) {
if (error.response.status === 401) {
// Token inválido o expirado
console.warn("Error 401: Token inválido o expirado. Deslogueando...");
// Limpiar localStorage y recargar la página.
// AuthContext se encargará de redirigir a /login al recargar porque no encontrará token.
localStorage.removeItem('authToken');
localStorage.removeItem('authUser'); // Asegurar limpiar también el usuario
// Forzar un hard refresh para que AuthContext se reinicialice y redirija
// Esto también limpiará cualquier estado de React.
// --- Mostrar mensaje antes de redirigir ---
alert("Tu sesión ha expirado o no es válida. Serás redirigido a la página de inicio de sesión.");
window.location.href = '/login'; // Redirección más directa
}
}
// Es importante devolver el error para que el componente que hizo la llamada pueda manejarlo también si es necesario
return Promise.reject(error);
}
);
// Puedes añadir interceptores de respuesta para manejar errores globales (ej: 401 Unauthorized)
export default apiClient;