Implementación AnomalIA - Fix de dropdowns y permisos.
All checks were successful
Optimized Build and Deploy / remote-build-and-deploy (push) Successful in 5m17s

This commit is contained in:
2025-06-30 15:26:14 -03:00
parent 95aa09d62a
commit c96d259892
59 changed files with 1430 additions and 337 deletions

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react'; // << Añadido useMemo
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import {
Box, Typography, TextField, Button, Paper, IconButton, Menu, MenuItem, Chip,
Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination,
@@ -21,7 +21,7 @@ import canillaService from '../../services/Distribucion/canillaService';
import type { EntradaSalidaCanillaDto } from '../../models/dtos/Distribucion/EntradaSalidaCanillaDto';
import type { UpdateEntradaSalidaCanillaDto } from '../../models/dtos/Distribucion/UpdateEntradaSalidaCanillaDto';
import type { PublicacionDropdownDto } from '../../models/dtos/Distribucion/PublicacionDropdownDto';
import type { CanillaDto } from '../../models/dtos/Distribucion/CanillaDto';
import type { CanillaDropdownDto } from '../../models/dtos/Distribucion/CanillaDropdownDto';
import type { LiquidarMovimientosCanillaRequestDto } from '../../models/dtos/Distribucion/LiquidarMovimientosCanillaDto';
import EntradaSalidaCanillaFormModal from '../../components/Modals/Distribucion/EntradaSalidaCanillaFormModal';
@@ -44,8 +44,8 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
const [loadingTicketPdf, setLoadingTicketPdf] = useState(false);
const [publicaciones, setPublicaciones] = useState<PublicacionDropdownDto[]>([]);
const [destinatariosDropdown, setDestinatariosDropdown] = useState<CanillaDto[]>([]);
const [loadingFiltersDropdown, setLoadingFiltersDropdown] = useState(false);
const [destinatariosDropdown, setDestinatariosDropdown] = useState<CanillaDropdownDto[]>([]);
const [loadingFiltersDropdown, setLoadingFiltersDropdown] = useState(false)
const [modalOpen, setModalOpen] = useState(false);
const [editingMovimiento, setEditingMovimiento] = useState<EntradaSalidaCanillaDto | null>(null);
@@ -81,29 +81,40 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
};
useEffect(() => {
const fetchPublicaciones = async () => {
const fetchDropdownData = async () => {
if (!puedeVer) {
setError("No tiene permiso para ver esta sección.");
setLoading(false); // Detiene el spinner principal
setLoadingFiltersDropdown(false); // Detiene el spinner de los filtros
return;
}
setLoadingFiltersDropdown(true);
setError(null);
try {
const pubsData = await publicacionService.getPublicacionesForDropdown(true);
setPublicaciones(pubsData);
// La carga de destinatarios se hará en el otro useEffect
} catch (err) {
console.error("Error cargando publicaciones para filtro:",err);
console.error("Error cargando publicaciones para filtro:", err);
setError("Error al cargar publicaciones.");
} finally {
// No setLoadingFiltersDropdown(false) acá, esperar a la otra carga
// La carga finaliza cuando se cargan los destinatarios también.
}
};
fetchPublicaciones();
}, []);
fetchDropdownData();
}, [puedeVer]); // << CAMBIO: Añadir `puedeVer` como dependencia
const fetchDestinatariosParaDropdown = useCallback(async () => {
if (!puedeVer) { return; }
setLoadingFiltersDropdown(true);
setFiltroIdCanillitaSeleccionado('');
setDestinatariosDropdown([]);
setError(null);
try {
const esAccionistaFilter = filtroTipoDestinatario === 'accionistas';
const data = await canillaService.getAllCanillas(undefined, undefined, true, esAccionistaFilter);
const data = await canillaService.getAllDropdownCanillas(true, esAccionistaFilter);
setDestinatariosDropdown(data);
} catch (err) {
console.error("Error cargando destinatarios para filtro:", err);
@@ -111,21 +122,23 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
} finally {
setLoadingFiltersDropdown(false);
}
}, [filtroTipoDestinatario]);
}, [filtroTipoDestinatario, puedeVer]);
useEffect(() => {
fetchDestinatariosParaDropdown();
}, [fetchDestinatariosParaDropdown]);
const cargarMovimientos = useCallback(async () => {
if (!puedeVer) { setError("No tiene permiso para ver esta sección."); setLoading(false); return; }
if (!puedeVer) {
setError("No tiene permiso para ver esta sección.");
setLoading(false);
return;
}
if (!filtroFecha || !filtroIdCanillitaSeleccionado) {
if (loading) setLoading(false);
setMovimientos([]);
return;
}
setLoading(true); setError(null); setApiErrorMessage(null);
try {
const params = {
@@ -148,6 +161,7 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
}
}, [puedeVer, filtroFecha, filtroIdPublicacion, filtroIdCanillitaSeleccionado]);
useEffect(() => {
if (filtroFecha && filtroIdCanillitaSeleccionado) {
cargarMovimientos();
@@ -156,8 +170,7 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
if (loading) setLoading(false);
}
}, [cargarMovimientos, filtroFecha, filtroIdCanillitaSeleccionado]);
const handleOpenModal = (item?: EntradaSalidaCanillaDto) => {
if (!puedeCrear && !item) {
setApiErrorMessage("No tiene permiso para registrar nuevos movimientos.");
@@ -195,7 +208,6 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
}
handleMenuClose();
};
const handleMenuOpen = (event: React.MouseEvent<HTMLElement>, item: EntradaSalidaCanillaDto) => {
event.currentTarget.setAttribute('data-rowid', item.idParte.toString());
setAnchorEl(event.currentTarget);
@@ -258,17 +270,15 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
await entradaSalidaCanillaService.liquidarMovimientos(liquidarDto);
setOpenLiquidarDialog(false);
const primerIdParteLiquidado = Array.from(selectedIdsParaLiquidar)[0];
// Necesitamos encontrar el movimiento en la lista ANTES de recargar
const movimientoParaTicket = movimientos.find(m => m.idParte === primerIdParteLiquidado);
await cargarMovimientos(); // Recargar la lista para reflejar el estado liquidado
await cargarMovimientos();
// Usar la fecha del movimiento original para el ticket
if (movimientoParaTicket && !movimientoParaTicket.canillaEsAccionista) {
console.log("Liquidación exitosa, generando ticket para canillita NO accionista:", movimientoParaTicket.idCanilla);
await handleImprimirTicketLiquidacion(
movimientoParaTicket.idCanilla,
movimientoParaTicket.fecha, // Usar la fecha del movimiento
movimientoParaTicket.fecha,
false
);
} else if (movimientoParaTicket && movimientoParaTicket.canillaEsAccionista) {
@@ -328,7 +338,6 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
} finally { setLoadingTicketPdf(false); }
}, []);
const handleChangePage = (_event: unknown, newPage: number) => setPage(newPage);
const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
setRowsPerPage(parseInt(event.target.value, 10)); setPage(0);
@@ -339,8 +348,14 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
displayData.filter(m => !m.liquidado).reduce((sum, item) => sum + item.montoARendir, 0)
, [displayData]);
if (!loading && !puedeVer && !loadingFiltersDropdown && movimientos.length === 0 && !filtroFecha && !filtroIdCanillitaSeleccionado ) {
return <Box sx={{ p: 2 }}><Alert severity="error">{error || "Acceso denegado."}</Alert></Box>;
if (!puedeVer) {
return (
<Box sx={{ p: 2 }}>
<Alert severity="error">
{error || "No tiene permiso para acceder a esta sección."}
</Alert>
</Box>
);
}
const numSelectedToLiquidate = selectedIdsParaLiquidar.size;
@@ -352,7 +367,6 @@ const GestionarEntradasSalidasCanillaPage: React.FC = () => {
<Paper sx={{ p: 2, mb: 2 }}>
<Typography variant="h6" gutterBottom>Filtros <FilterListIcon fontSize="small" /></Typography>
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2, alignItems: 'center', mb: 2 }}>
{/* ... (Filtros sin cambios) ... */}
<TextField label="Fecha" type="date" size="small" value={filtroFecha}
onChange={(e) => setFiltroFecha(e.target.value)}
InputLabelProps={{ shrink: true }} sx={{ minWidth: 170 }}