From 8e1b8d232611fa163d89803ec79e74c98212b758 Mon Sep 17 00:00:00 2001 From: dmolinari Date: Thu, 27 Nov 2025 13:49:46 -0300 Subject: [PATCH] feat: DataGrid y filtro por Fechas en Stock Bobinas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend: - Se reemplazó el componente Table por DataGrid para habilitar ordenamiento y filtrado nativo en cliente. - Se agregó la UI para filtrar por rango de "Fecha de Estado". - Se corrigió el tipado de columnas de fecha (`type: 'date'`) implementando un `valueGetter` personalizado que parsea año/mes/día localmente para evitar errores de filtrado por diferencia de Zona Horaria (UTC vs Local). - Se actualizó `stockBobinaService` para enviar los parámetros `fechaEstadoDesde` y `fechaEstadoHasta`. Backend: - Se actualizó `StockBobinasController` para recibir los nuevos parámetros de fecha. - Se modificó `StockBobinaRepository` implementando la lógica SQL para los nuevos filtros. --- .../Impresion/StockBobinasController.cs | 16 +- .../Impresion/IStockBobinaRepository.cs | 4 +- .../Impresion/StockBobinaRepository.cs | 12 +- Backend/GestionIntegral.Api/Program.cs | 2 +- .../Services/Impresion/IStockBobinaService.cs | 2 +- .../Services/Impresion/StockBobinaService.cs | 10 +- .../Impresion/GestionarStockBobinasPage.tsx | 319 ++++++++++-------- .../services/Impresion/stockBobinaService.ts | 4 + 8 files changed, 214 insertions(+), 155 deletions(-) diff --git a/Backend/GestionIntegral.Api/Controllers/Impresion/StockBobinasController.cs b/Backend/GestionIntegral.Api/Controllers/Impresion/StockBobinasController.cs index 6df07a6..b24d11d 100644 --- a/Backend/GestionIntegral.Api/Controllers/Impresion/StockBobinasController.cs +++ b/Backend/GestionIntegral.Api/Controllers/Impresion/StockBobinasController.cs @@ -41,6 +41,7 @@ namespace GestionIntegral.Api.Controllers.Impresion return null; } + // GET: api/stockbobinas // GET: api/stockbobinas [HttpGet] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] @@ -48,12 +49,23 @@ namespace GestionIntegral.Api.Controllers.Impresion public async Task GetAllStockBobinas( [FromQuery] int? idTipoBobina, [FromQuery] string? nroBobina, [FromQuery] int? idPlanta, [FromQuery] int? idEstadoBobina, [FromQuery] string? remito, - [FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta) + [FromQuery] DateTime? fechaDesde, [FromQuery] DateTime? fechaHasta, + [FromQuery] DateTime? fechaEstadoDesde, [FromQuery] DateTime? fechaEstadoHasta) // <--- Nuevos parámetros agregados { if (!TienePermiso(PermisoVerStock)) return Forbid(); try { - var bobinas = await _stockBobinaService.ObtenerTodosAsync(idTipoBobina, nroBobina, idPlanta, idEstadoBobina, remito, fechaDesde, fechaHasta); + var bobinas = await _stockBobinaService.ObtenerTodosAsync( + idTipoBobina, + nroBobina, + idPlanta, + idEstadoBobina, + remito, + fechaDesde, + fechaHasta, + fechaEstadoDesde, + fechaEstadoHasta + ); return Ok(bobinas); } catch (Exception ex) diff --git a/Backend/GestionIntegral.Api/Data/Repositories/Impresion/IStockBobinaRepository.cs b/Backend/GestionIntegral.Api/Data/Repositories/Impresion/IStockBobinaRepository.cs index e4490b2..50c9235 100644 --- a/Backend/GestionIntegral.Api/Data/Repositories/Impresion/IStockBobinaRepository.cs +++ b/Backend/GestionIntegral.Api/Data/Repositories/Impresion/IStockBobinaRepository.cs @@ -15,7 +15,9 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, - DateTime? fechaHasta); + DateTime? fechaHasta, + DateTime? fechaEstadoDesde, + DateTime? fechaEstadoHasta); Task GetByIdAsync(int idBobina); Task GetByNroBobinaAsync(string nroBobina); // Para validar unicidad de NroBobina diff --git a/Backend/GestionIntegral.Api/Data/Repositories/Impresion/StockBobinaRepository.cs b/Backend/GestionIntegral.Api/Data/Repositories/Impresion/StockBobinaRepository.cs index c872b4f..a05c201 100644 --- a/Backend/GestionIntegral.Api/Data/Repositories/Impresion/StockBobinaRepository.cs +++ b/Backend/GestionIntegral.Api/Data/Repositories/Impresion/StockBobinaRepository.cs @@ -23,7 +23,7 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion public async Task> GetAllAsync( int? idTipoBobina, string? nroBobinaFilter, int? idPlanta, - int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta) + int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaEstadoDesde, DateTime? fechaEstadoHasta) { var sqlBuilder = new StringBuilder(@" SELECT @@ -69,6 +69,16 @@ namespace GestionIntegral.Api.Data.Repositories.Distribucion sqlBuilder.Append(" AND sb.FechaRemito <= @FechaHastaParam"); parameters.Add("FechaHastaParam", fechaHasta.Value.Date); } + if (fechaEstadoDesde.HasValue) + { + sqlBuilder.Append(" AND sb.FechaEstado >= @FechaEstadoDesdeParam"); + parameters.Add("FechaEstadoDesdeParam", fechaEstadoDesde.Value.Date); + } + if (fechaEstadoHasta.HasValue) + { + sqlBuilder.Append(" AND sb.FechaEstado <= @FechaEstadoHastaParam"); + parameters.Add("FechaEstadoHastaParam", fechaEstadoHasta.Value.Date); + } sqlBuilder.Append(" ORDER BY sb.FechaRemito DESC, sb.NroBobina;"); diff --git a/Backend/GestionIntegral.Api/Program.cs b/Backend/GestionIntegral.Api/Program.cs index 064ad81..0815017 100644 --- a/Backend/GestionIntegral.Api/Program.cs +++ b/Backend/GestionIntegral.Api/Program.cs @@ -187,7 +187,7 @@ builder.Services.AddCors(options => policy => { policy.WithOrigins( - "http://localhost:5173", // Para desarrollo local + "http://localhost:5174", // Para desarrollo local "https://gestion.eldiaservicios.com" // Para producción ) .AllowAnyHeader() diff --git a/Backend/GestionIntegral.Api/Services/Impresion/IStockBobinaService.cs b/Backend/GestionIntegral.Api/Services/Impresion/IStockBobinaService.cs index 33f8dd8..a79eb18 100644 --- a/Backend/GestionIntegral.Api/Services/Impresion/IStockBobinaService.cs +++ b/Backend/GestionIntegral.Api/Services/Impresion/IStockBobinaService.cs @@ -10,7 +10,7 @@ namespace GestionIntegral.Api.Services.Impresion { Task> ObtenerTodosAsync( int? idTipoBobina, string? nroBobinaFilter, int? idPlanta, - int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta); + int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaEstadoDesde, DateTime? fechaEstadoHasta); Task ObtenerPorIdAsync(int idBobina); Task<(StockBobinaDto? Bobina, string? Error)> IngresarBobinaAsync(CreateStockBobinaDto createDto, int idUsuario); diff --git a/Backend/GestionIntegral.Api/Services/Impresion/StockBobinaService.cs b/Backend/GestionIntegral.Api/Services/Impresion/StockBobinaService.cs index ff685e7..e5aa91e 100644 --- a/Backend/GestionIntegral.Api/Services/Impresion/StockBobinaService.cs +++ b/Backend/GestionIntegral.Api/Services/Impresion/StockBobinaService.cs @@ -85,9 +85,9 @@ namespace GestionIntegral.Api.Services.Impresion public async Task> ObtenerTodosAsync( int? idTipoBobina, string? nroBobinaFilter, int? idPlanta, - int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta) + int? idEstadoBobina, string? remitoFilter, DateTime? fechaDesde, DateTime? fechaHasta, DateTime? fechaEstadoDesde, DateTime? fechaEstadoHasta) { - var bobinas = await _stockBobinaRepository.GetAllAsync(idTipoBobina, nroBobinaFilter, idPlanta, idEstadoBobina, remitoFilter, fechaDesde, fechaHasta); + var bobinas = await _stockBobinaRepository.GetAllAsync(idTipoBobina, nroBobinaFilter, idPlanta, idEstadoBobina, remitoFilter, fechaDesde, fechaHasta, fechaEstadoDesde, fechaEstadoHasta); var dtos = new List(); foreach (var bobina in bobinas) { @@ -390,7 +390,7 @@ namespace GestionIntegral.Api.Services.Impresion DateTime? fechaDesde = fechaRemito?.Date; DateTime? fechaHasta = fechaRemito?.Date; - var bobinas = await _stockBobinaRepository.GetAllAsync(null, null, idPlanta, null, remito, fechaDesde, fechaHasta); + var bobinas = await _stockBobinaRepository.GetAllAsync(null, null, idPlanta, null, remito, fechaDesde, fechaHasta, null, null); var dtos = new List(); foreach (var bobina in bobinas) @@ -410,7 +410,9 @@ namespace GestionIntegral.Api.Services.Impresion idEstadoBobina: null, remitoFilter: dto.Remito, fechaDesde: dto.FechaRemitoActual.Date, - fechaHasta: dto.FechaRemitoActual.Date + fechaHasta: dto.FechaRemitoActual.Date, + fechaEstadoDesde: null, + fechaEstadoHasta: null ); if (!bobinasAActualizar.Any()) diff --git a/Frontend/src/pages/Impresion/GestionarStockBobinasPage.tsx b/Frontend/src/pages/Impresion/GestionarStockBobinasPage.tsx index 2536862..b1a5df8 100644 --- a/Frontend/src/pages/Impresion/GestionarStockBobinasPage.tsx +++ b/Frontend/src/pages/Impresion/GestionarStockBobinasPage.tsx @@ -1,9 +1,11 @@ -import React, { useState, useEffect, useCallback, useRef } from 'react'; +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, - CircularProgress, Alert, FormControl, InputLabel, Select, FormControlLabel, Checkbox + Alert, FormControl, InputLabel, Select, FormControlLabel, Checkbox } from '@mui/material'; +import { DataGrid, type GridColDef, type GridRenderCellParams } from '@mui/x-data-grid'; +import { esES } from '@mui/x-data-grid/locales'; + import AddIcon from '@mui/icons-material/Add'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import EditIcon from '@mui/icons-material/Edit'; @@ -26,8 +28,8 @@ import type { TipoBobinaDto } from '../../models/dtos/Impresion/TipoBobinaDto'; import type { PlantaDto } from '../../models/dtos/Impresion/PlantaDto'; import type { EstadoBobinaDto } from '../../models/dtos/Impresion/EstadoBobinaDto'; import type { UpdateFechaRemitoLoteDto } from '../../models/dtos/Impresion/UpdateFechaRemitoLoteDto'; -import StockBobinaFechaRemitoModal from '../../components/Modals/Impresion/StockBobinaFechaRemitoModal'; +import StockBobinaFechaRemitoModal from '../../components/Modals/Impresion/StockBobinaFechaRemitoModal'; import StockBobinaIngresoFormModal from '../../components/Modals/Impresion/StockBobinaIngresoFormModal'; import StockBobinaEditFormModal from '../../components/Modals/Impresion/StockBobinaEditFormModal'; import StockBobinaCambioEstadoModal from '../../components/Modals/Impresion/StockBobinaCambioEstadoModal'; @@ -46,16 +48,23 @@ const GestionarStockBobinasPage: React.FC = () => { const [error, setError] = useState(null); const [apiErrorMessage, setApiErrorMessage] = useState(null); - // Estados de los filtros + // --- Estados de los filtros --- const [filtroTipoBobina, setFiltroTipoBobina] = useState(''); const [filtroNroBobina, setFiltroNroBobina] = useState(''); const [filtroPlanta, setFiltroPlanta] = useState(''); const [filtroEstadoBobina, setFiltroEstadoBobina] = useState(''); const [filtroRemito, setFiltroRemito] = useState(''); + + // Filtro Fechas Remito const [filtroFechaHabilitado, setFiltroFechaHabilitado] = useState(false); const [filtroFechaDesde, setFiltroFechaDesde] = useState(new Date().toISOString().split('T')[0]); const [filtroFechaHasta, setFiltroFechaHasta] = useState(new Date().toISOString().split('T')[0]); + // Nuevo Filtro: Fechas Estado + const [filtroFechaEstadoHabilitado, setFiltroFechaEstadoHabilitado] = useState(false); + const [filtroFechaEstadoDesde, setFiltroFechaEstadoDesde] = useState(new Date().toISOString().split('T')[0]); + const [filtroFechaEstadoHasta, setFiltroFechaEstadoHasta] = useState(new Date().toISOString().split('T')[0]); + // Estados para datos de dropdowns const [tiposBobina, setTiposBobina] = useState([]); const [plantas, setPlantas] = useState([]); @@ -69,9 +78,7 @@ const GestionarStockBobinasPage: React.FC = () => { const [loteModalOpen, setLoteModalOpen] = useState(false); const [fechaRemitoModalOpen, setFechaRemitoModalOpen] = useState(false); - // Estados para la paginación y el menú de acciones - const [page, setPage] = useState(0); - const [rowsPerPage, setRowsPerPage] = useState(25); + // Menú de acciones const [anchorEl, setAnchorEl] = useState(null); const [selectedBobinaForRowMenu, setSelectedBobinaForRowMenu] = useState(null); @@ -82,8 +89,6 @@ const GestionarStockBobinasPage: React.FC = () => { const puedeModificarDatos = isSuperAdmin || tienePermiso("IB004"); const puedeEliminar = isSuperAdmin || tienePermiso("IB005"); - const lastOpenedMenuButtonRef = useRef(null); - const fetchFiltersDropdownData = useCallback(async () => { setLoadingFiltersDropdown(true); try { @@ -123,13 +128,18 @@ const GestionarStockBobinasPage: React.FC = () => { idPlanta: filtroPlanta ? Number(filtroPlanta) : null, idEstadoBobina: filtroEstadoBobina ? Number(filtroEstadoBobina) : null, remitoFilter: filtroRemito || null, + // Fechas Remito fechaDesde: filtroFechaHabilitado ? filtroFechaDesde : null, fechaHasta: filtroFechaHabilitado ? filtroFechaHasta : null, + // Fechas Estado (Nuevos parametros, asegurar que el backend los reciba) + fechaEstadoDesde: filtroFechaEstadoHabilitado ? filtroFechaEstadoDesde : null, + fechaEstadoHasta: filtroFechaEstadoHabilitado ? filtroFechaEstadoHasta : null, }; const data = await stockBobinaService.getAllStockBobinas(params); setStock(data); if (data.length === 0) { - setError("No se encontraron resultados con los filtros aplicados."); + // No setteamos error bloqueante, solo aviso visual si se desea, o dejar tabla vacía. + // setError("No se encontraron resultados con los filtros aplicados."); } } catch (err) { console.error(err); @@ -137,10 +147,14 @@ const GestionarStockBobinasPage: React.FC = () => { } finally { setLoading(false); } - }, [puedeVer, filtroTipoBobina, filtroNroBobina, filtroPlanta, filtroEstadoBobina, filtroRemito, filtroFechaHabilitado, filtroFechaDesde, filtroFechaHasta]); + }, [ + puedeVer, + filtroTipoBobina, filtroNroBobina, filtroPlanta, filtroEstadoBobina, filtroRemito, + filtroFechaHabilitado, filtroFechaDesde, filtroFechaHasta, + filtroFechaEstadoHabilitado, filtroFechaEstadoDesde, filtroFechaEstadoHasta + ]); const handleBuscarClick = () => { - setPage(0); cargarStock(); }; @@ -150,21 +164,26 @@ const GestionarStockBobinasPage: React.FC = () => { setFiltroPlanta(''); setFiltroEstadoBobina(''); setFiltroRemito(''); + setFiltroFechaHabilitado(false); setFiltroFechaDesde(new Date().toISOString().split('T')[0]); setFiltroFechaHasta(new Date().toISOString().split('T')[0]); + + setFiltroFechaEstadoHabilitado(false); + setFiltroFechaEstadoDesde(new Date().toISOString().split('T')[0]); + setFiltroFechaEstadoHasta(new Date().toISOString().split('T')[0]); + setStock([]); setError(null); }; - //const handleOpenIngresoModal = () => { setApiErrorMessage(null); setIngresoModalOpen(true); }; const handleCloseIngresoModal = () => setIngresoModalOpen(false); const handleSubmitIngresoModal = async (data: CreateStockBobinaDto) => { setApiErrorMessage(null); try { await stockBobinaService.ingresarBobina(data); cargarStock(); } catch (err: any) { const msg = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al ingresar bobina.'; setApiErrorMessage(msg); throw err; } }; - + const handleLoteModalClose = (refrescar: boolean) => { setLoteModalOpen(false); if (refrescar) { @@ -177,7 +196,7 @@ const GestionarStockBobinasPage: React.FC = () => { try { await stockBobinaService.updateDatosBobinaDisponible(idBobina, data); cargarStock(); } catch (err: any) { const msg = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al actualizar bobina.'; setApiErrorMessage(msg); throw err; } }; - + const handleSubmitCambioEstadoModal = async (idBobina: number, data: CambiarEstadoBobinaDto) => { setApiErrorMessage(null); try { await stockBobinaService.cambiarEstadoBobina(idBobina, data); cargarStock(); } @@ -203,90 +222,128 @@ const GestionarStockBobinasPage: React.FC = () => { } handleMenuClose(); }; - + const handleSubmitFechaRemitoModal = async (data: UpdateFechaRemitoLoteDto) => { setApiErrorMessage(null); try { await stockBobinaService.actualizarFechaRemitoLote(data); - cargarStock(); // Recargar la grilla para ver el cambio + cargarStock(); } catch (err: any) { const msg = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al actualizar la fecha del remito.'; setApiErrorMessage(msg); - throw err; + throw err; } }; + // --- Handlers Menú Acciones --- const handleMenuOpen = (event: React.MouseEvent, bobina: StockBobinaDto) => { + event.stopPropagation(); // Evitar selección de fila al abrir menú setAnchorEl(event.currentTarget); setSelectedBobinaForRowMenu(bobina); - lastOpenedMenuButtonRef.current = event.currentTarget; }; - - // 1. handleMenuClose ahora solo cierra el menú. No limpia el estado de la bobina seleccionada. + const handleMenuClose = () => { setAnchorEl(null); }; - - // 2. Handlers para abrir modales. Abren el modal y cierran el menú. - const handleOpenEditModal = () => { - setEditModalOpen(true); - handleMenuClose(); - }; - - const handleOpenCambioEstadoModal = () => { - setCambioEstadoModalOpen(true); - handleMenuClose(); - }; - - const handleOpenFechaRemitoModal = () => { - setFechaRemitoModalOpen(true); - handleMenuClose(); - }; - - // 3. Handlers para cerrar modales. Cierran el modal y AHORA limpian el estado de la bobina seleccionada. - const handleCloseEditModal = () => { - setEditModalOpen(false); - setSelectedBobinaForRowMenu(null); - }; - - const handleCloseCambioEstadoModal = () => { - setCambioEstadoModalOpen(false); - setSelectedBobinaForRowMenu(null); - }; - - const handleCloseFechaRemitoModal = () => { - setFechaRemitoModalOpen(false); - setSelectedBobinaForRowMenu(null); - }; - const handleChangePage = (_event: unknown, newPage: number) => setPage(newPage); - const handleChangeRowsPerPage = (event: React.ChangeEvent) => { - setRowsPerPage(parseInt(event.target.value, 10)); setPage(0); - }; - - const displayData = stock.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage); - - const formatDate = (dateString?: string | null) => { - if (!dateString) return '-'; - const date = new Date(dateString); - if (isNaN(date.getTime())) return '-'; + const handleOpenEditModal = () => { setEditModalOpen(true); handleMenuClose(); }; + const handleOpenCambioEstadoModal = () => { setCambioEstadoModalOpen(true); handleMenuClose(); }; + const handleOpenFechaRemitoModal = () => { setFechaRemitoModalOpen(true); handleMenuClose(); }; - const options: Intl.DateTimeFormatOptions = { - year: 'numeric', - month: '2-digit', - day: '2-digit', - timeZone: 'UTC' - }; - return new Intl.DateTimeFormat('es-AR', options).format(date); - }; + const handleCloseEditModal = () => { setEditModalOpen(false); setSelectedBobinaForRowMenu(null); }; + const handleCloseCambioEstadoModal = () => { setCambioEstadoModalOpen(false); setSelectedBobinaForRowMenu(null); }; + const handleCloseFechaRemitoModal = () => { setFechaRemitoModalOpen(false); setSelectedBobinaForRowMenu(null); }; + + // --- Definición de Columnas DataGrid --- + const columns = useMemo[]>(() => [ + { field: 'nroBobina', headerName: 'Nro. Bobina', width: 130 }, + { field: 'nombreTipoBobina', headerName: 'Tipo', width: 200, flex: 1 }, + { field: 'peso', headerName: 'Peso (Kg)', width: 100, align: 'right', headerAlign: 'right', type: 'number' }, + { field: 'nombrePlanta', headerName: 'Planta', width: 120 }, + { + field: 'nombreEstadoBobina', + headerName: 'Estado', + width: 130, + renderCell: (params) => { + const idEstado = params.row.idEstadoBobina; + let color: "success" | "primary" | "error" | "default" = "default"; + if (idEstado === ID_ESTADO_DISPONIBLE) color = "success"; + else if (idEstado === ID_ESTADO_UTILIZADA) color = "primary"; + else if (idEstado === ID_ESTADO_DANADA) color = "error"; + + return ; + } + }, + { field: 'remito', headerName: 'Remito', width: 120 }, + { + field: 'fechaRemito', + headerName: 'F. Remito', + width: 110, + type: 'date', + valueGetter: (value: string) => { + if (!value) return null; + const datePart = value.toString().split('T')[0]; + const [year, month, day] = datePart.split('-'); + return new Date(parseInt(year), parseInt(month) - 1, parseInt(day)); + }, + valueFormatter: (value: Date) => { + return value ? value.toLocaleDateString('es-AR') : '-'; + } + }, + { + field: 'fechaEstado', + headerName: 'F. Estado', + width: 110, + type: 'date', + valueGetter: (value: string) => { + if (!value) return null; + const datePart = value.toString().split('T')[0]; + const [year, month, day] = datePart.split('-'); + return new Date(parseInt(year), parseInt(month) - 1, parseInt(day)); + }, + valueFormatter: (value: Date) => { + return value ? value.toLocaleDateString('es-AR') : '-'; + } + }, + + { field: 'nombrePublicacion', headerName: 'Publicación', width: 150 }, + { field: 'nombreSeccion', headerName: 'Sección', width: 120 }, + { field: 'obs', headerName: 'Obs.', width: 200, flex: 1 }, + { + field: 'acciones', + headerName: 'Acciones', + width: 80, + sortable: false, + filterable: false, + align: 'right', + renderCell: (params: GridRenderCellParams) => { + const b = params.row; + const disabled = !(puedeModificarDatos) && + !(puedeCambiarEstado) && + !((b.idEstadoBobina === ID_ESTADO_DISPONIBLE || b.idEstadoBobina === ID_ESTADO_DANADA) && puedeEliminar); + + if (disabled) return null; + + return ( + handleMenuOpen(e, b)} size="small"> + + + ); + } + } + ], [puedeModificarDatos, puedeCambiarEstado, puedeEliminar]); if (!puedeVer) return {error || "Acceso denegado."}; return ( - + Stock de Bobinas + + {/* Panel de Filtros */} Filtros + + {/* Fila 1: Filtros generales */} Tipo Bobina @@ -312,24 +369,32 @@ const GestionarStockBobinasPage: React.FC = () => { setFiltroRemito(e.target.value)} sx={{ minWidth: 150, flexGrow: 1 }} /> - - setFiltroFechaHabilitado(e.target.checked)} />} - label="Filtrar por Fechas de Remitos" - /> - setFiltroFechaDesde(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 170 }} disabled={!filtroFechaHabilitado} /> - setFiltroFechaHasta(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 170 }} disabled={!filtroFechaHabilitado} /> + + {/* Fila 2: Filtros de Fechas */} + + {/* Fechas Remito */} + + setFiltroFechaHabilitado(e.target.checked)} />} + label="Filtrar por Fecha Remito" + /> + setFiltroFechaDesde(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 140 }} disabled={!filtroFechaHabilitado} /> + setFiltroFechaHasta(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 140 }} disabled={!filtroFechaHabilitado} /> + + + {/* Fechas Estado (Nuevo) */} + + setFiltroFechaEstadoHabilitado(e.target.checked)} />} + label="Filtrar por Fecha Estado" + /> + setFiltroFechaEstadoDesde(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 140 }} disabled={!filtroFechaEstadoHabilitado} /> + setFiltroFechaEstadoHasta(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 140 }} disabled={!filtroFechaEstadoHabilitado} /> + - + + {/* Botones de acción del filtro */} + - */} @@ -353,59 +413,28 @@ const GestionarStockBobinasPage: React.FC = () => { - {loading && } {error && !loading && {error}} {apiErrorMessage && {apiErrorMessage}} - {!loading && !error && ( - - - - Nro. BobinaTipoPeso (Kg) - PlantaEstadoRemito - F. RemitoF. Estado - PublicaciónSección - Obs. - {(puedeModificarDatos || puedeCambiarEstado || puedeEliminar) && Acciones} - - - {displayData.length === 0 ? ( - No se encontraron bobinas con los filtros aplicados. Haga clic en "Buscar" para iniciar una consulta. - ) : ( - displayData.map((b) => ( - - {b.nroBobina}{b.nombreTipoBobina} - {b.peso}{b.nombrePlanta} - - {b.remito}{formatDate(b.fechaRemito)} - {formatDate(b.fechaEstado)} - {b.nombrePublicacion || '-'}{b.nombreSeccion || '-'} - {b.obs || '-'} - {(puedeModificarDatos || puedeCambiarEstado || puedeEliminar) && ( - - handleMenuOpen(e, b)} - disabled={ - !(puedeModificarDatos) && // Simplificado, ya que todas las opciones requieren este permiso - !(puedeCambiarEstado) && - !((b.idEstadoBobina === ID_ESTADO_DISPONIBLE || b.idEstadoBobina === ID_ESTADO_DANADA) && puedeEliminar) - } - > - - )} - - )))} - -
- -
- )} + {/* Tabla DataGrid */} + + row.idBobina} // Importante: especificar el ID único + loading={loading} + localeText={esES.components.MuiDataGrid.defaultProps.localeText} + density="compact" + disableRowSelectionOnClick + initialState={{ + pagination: { paginationModel: { pageSize: 25 } }, + }} + pageSizeOptions={[25, 50, 100]} + sx={{ border: 0 }} + /> + + {/* Menú Contextual de Fila */} {selectedBobinaForRowMenu && puedeModificarDatos && ( diff --git a/Frontend/src/services/Impresion/stockBobinaService.ts b/Frontend/src/services/Impresion/stockBobinaService.ts index a02e4ea..f35d1a2 100644 --- a/Frontend/src/services/Impresion/stockBobinaService.ts +++ b/Frontend/src/services/Impresion/stockBobinaService.ts @@ -14,6 +14,8 @@ interface GetAllStockBobinasParams { remitoFilter?: string | null; fechaDesde?: string | null; // "yyyy-MM-dd" fechaHasta?: string | null; // "yyyy-MM-dd" + fechaEstadoDesde?: string | null; // "yyyy-MM-dd" + fechaEstadoHasta?: string | null; // "yyyy-MM-dd" } const getAllStockBobinas = async (filters: GetAllStockBobinasParams): Promise => { @@ -25,6 +27,8 @@ const getAllStockBobinas = async (filters: GetAllStockBobinasParams): Promise('/stockbobinas', { params }); return response.data;