import React, { useState, useEffect, useCallback } from 'react'; import { Box, Typography, TextField, Button, Paper, IconButton, Menu, MenuItem, Chip, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, TablePagination, CircularProgress, Alert, FormControl, InputLabel, Select, Tooltip } from '@mui/material'; import AddIcon from '@mui/icons-material/Add'; import MoreVertIcon from '@mui/icons-material/MoreVert'; import EditIcon from '@mui/icons-material/Edit'; import DeleteIcon from '@mui/icons-material/Delete'; import FilterListIcon from '@mui/icons-material/FilterList'; import entradaSalidaDistService from '../../services/Distribucion/entradaSalidaDistService'; import publicacionService from '../../services/Distribucion/publicacionService'; import distribuidorService from '../../services/Distribucion/distribuidorService'; import type { EntradaSalidaDistDto } from '../../models/dtos/Distribucion/EntradaSalidaDistDto'; import type { CreateEntradaSalidaDistDto } from '../../models/dtos/Distribucion/CreateEntradaSalidaDistDto'; import type { UpdateEntradaSalidaDistDto } from '../../models/dtos/Distribucion/UpdateEntradaSalidaDistDto'; import type { PublicacionDropdownDto } from '../../models/dtos/Distribucion/PublicacionDropdownDto'; import type { DistribuidorDropdownDto } from '../../models/dtos/Distribucion/DistribuidorDropdownDto'; import EntradaSalidaDistFormModal from '../../components/Modals/Distribucion/EntradaSalidaDistFormModal'; import { usePermissions } from '../../hooks/usePermissions'; import axios from 'axios'; const GestionarEntradasSalidasDistPage: React.FC = () => { const [movimientos, setMovimientos] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [apiErrorMessage, setApiErrorMessage] = useState(null); const [filtroFechaDesde, setFiltroFechaDesde] = useState(new Date().toISOString().split('T')[0]); const [filtroFechaHasta, setFiltroFechaHasta] = useState(new Date().toISOString().split('T')[0]); const [filtroIdPublicacion, setFiltroIdPublicacion] = useState(''); const [filtroIdDistribuidor, setFiltroIdDistribuidor] = useState(''); const [filtroTipoMov, setFiltroTipoMov] = useState<'Salida' | 'Entrada' | ''>(''); const [publicaciones, setPublicaciones] = useState([]); const [distribuidores, setDistribuidores] = useState([]); const [loadingFiltersDropdown, setLoadingFiltersDropdown] = useState(false); const [modalOpen, setModalOpen] = useState(false); const [editingMovimiento, setEditingMovimiento] = useState(null); const [page, setPage] = useState(0); const [rowsPerPage, setRowsPerPage] = useState(25); const [anchorEl, setAnchorEl] = useState(null); const [selectedRow, setSelectedRow] = useState(null); const { tienePermiso, isSuperAdmin } = usePermissions(); const puedeVer = isSuperAdmin || tienePermiso("MD001"); const puedeGestionar = isSuperAdmin || tienePermiso("MD002"); // CORREGIDO: Función para formatear la fecha const formatDate = (dateString?: string | null): string => { if (!dateString) return '-'; // Asumimos que dateString viene del backend como "YYYY-MM-DD" o "YYYY-MM-DDTHH:mm:ss..." const datePart = dateString.split('T')[0]; // Tomar solo la parte YYYY-MM-DD const parts = datePart.split('-'); if (parts.length === 3) { // parts[0] = YYYY, parts[1] = MM, parts[2] = DD return `${parts[2]}/${parts[1]}/${parts[0]}`; // Formato DD/MM/YYYY } return datePart; // Fallback si el formato no es el esperado }; const fetchFiltersDropdownData = useCallback(async () => { setLoadingFiltersDropdown(true); try { const [pubsData, distData] = await Promise.all([ publicacionService.getPublicacionesForDropdown(true), distribuidorService.getAllDistribuidoresDropdown() ]); setPublicaciones(pubsData); setDistribuidores(distData); } catch (err) { console.error(err); setError("Error al cargar opciones de filtro."); } finally { setLoadingFiltersDropdown(false); } }, []); useEffect(() => { fetchFiltersDropdownData(); }, [fetchFiltersDropdownData]); const cargarMovimientos = useCallback(async () => { if (!puedeVer) { setError("No tiene permiso."); setLoading(false); return; } setLoading(true); setError(null); setApiErrorMessage(null); try { const params = { fechaDesde: filtroFechaDesde || null, fechaHasta: filtroFechaHasta || null, idPublicacion: filtroIdPublicacion ? Number(filtroIdPublicacion) : null, idDistribuidor: filtroIdDistribuidor ? Number(filtroIdDistribuidor) : null, tipoMovimiento: filtroTipoMov || null, }; const data = await entradaSalidaDistService.getAllEntradasSalidasDist(params); setMovimientos(data); } catch (err) { console.error(err); setError('Error al cargar movimientos.'); } finally { setLoading(false); } }, [puedeVer, filtroFechaDesde, filtroFechaHasta, filtroIdPublicacion, filtroIdDistribuidor, filtroTipoMov]); useEffect(() => { cargarMovimientos(); }, [cargarMovimientos]); const handleOpenModal = (item?: EntradaSalidaDistDto) => { setEditingMovimiento(item || null); setApiErrorMessage(null); setModalOpen(true); }; const handleCloseModal = () => { setModalOpen(false); setEditingMovimiento(null); }; const handleSubmitModal = async (data: CreateEntradaSalidaDistDto | UpdateEntradaSalidaDistDto, idParte?: number) => { setApiErrorMessage(null); try { if (idParte && editingMovimiento) { await entradaSalidaDistService.updateEntradaSalidaDist(idParte, data as UpdateEntradaSalidaDistDto); } else { await entradaSalidaDistService.createEntradaSalidaDist(data as CreateEntradaSalidaDistDto); } cargarMovimientos(); } catch (err: any) { const message = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al guardar.'; setApiErrorMessage(message); throw err; } }; const handleDelete = async (idParte: number) => { if (window.confirm(`¿Seguro (ID: ${idParte})? Esto revertirá el saldo.`)) { setApiErrorMessage(null); try { await entradaSalidaDistService.deleteEntradaSalidaDist(idParte); cargarMovimientos(); } catch (err: any) { const msg = axios.isAxiosError(err) && err.response?.data?.message ? err.response.data.message : 'Error al eliminar.'; setApiErrorMessage(msg); } } handleMenuClose(); }; const handleMenuOpen = (event: React.MouseEvent, item: EntradaSalidaDistDto) => { setAnchorEl(event.currentTarget); setSelectedRow(item); }; const handleMenuClose = () => { setAnchorEl(null); setSelectedRow(null); }; const handleChangePage = (_event: unknown, newPage: number) => setPage(newPage); const handleChangeRowsPerPage = (event: React.ChangeEvent) => { setRowsPerPage(parseInt(event.target.value, 25)); setPage(0); }; const displayData = movimientos.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage); // La función formatDate ya está definida arriba. if (!loading && !puedeVer && !loadingFiltersDropdown) return {error || "Acceso denegado."}; return ( Entradas/Salidas a Distribuidores Filtros setFiltroFechaDesde(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 170 }} /> setFiltroFechaHasta(e.target.value)} InputLabelProps={{ shrink: true }} sx={{ minWidth: 170 }} /> Publicación Distribuidor Tipo {puedeGestionar && ()} {loading && } {error && !loading && {error}} {apiErrorMessage && {apiErrorMessage}} {!loading && !error && puedeVer && ( FechaPublicación (Empresa) DistribuidorTipo CantidadRemito Monto AfectadoObs. {puedeGestionar && Acciones} {displayData.length === 0 ? ( No se encontraron movimientos. ) : ( displayData.map((m) => ( {/* Usar la función formatDate aquí */} {formatDate(m.fecha)} {m.nombrePublicacion} {m.nombreDistribuidor} {m.cantidad} {m.remito} {(m.tipoMovimiento === 'Salida' ? '$' : '$-') + m.montoCalculado.toLocaleString('es-AR', { minimumFractionDigits: 2, maximumFractionDigits: 2 })} {m.observacion || '-'} {puedeGestionar && ( handleMenuOpen(e, m)} disabled={!puedeGestionar}> )} )))}
)} {puedeGestionar && selectedRow && ( { handleOpenModal(selectedRow); handleMenuClose(); }}> Modificar)} {puedeGestionar && selectedRow && ( handleDelete(selectedRow.idParte)}> Eliminar)} setApiErrorMessage(null)} />
); }; export default GestionarEntradasSalidasDistPage;