From fce8c9f9dd95fdf05b18be7e02c6c058dede4811 Mon Sep 17 00:00:00 2001 From: Kevin Rosales Date: Thu, 2 Oct 2025 21:59:22 -0600 Subject: [PATCH] se agrego modulo de partidas y sus filtros en el expediente --- src/index.css | 53 +++ src/pages/PedimentoDetail.jsx | 837 ++++++++++++++++++++++++++++------ src/pages/Reports.jsx | 223 +++++++-- 3 files changed, 938 insertions(+), 175 deletions(-) diff --git a/src/index.css b/src/index.css index 7450b59..c761c69 100644 --- a/src/index.css +++ b/src/index.css @@ -7,6 +7,59 @@ button:hover { border-color: #646cff; } +/* Estilos para el slicer de rango */ +.slider-thumb { + -webkit-appearance: none; + appearance: none; + background: transparent; + pointer-events: none; +} + +.slider-thumb::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + height: 20px; + width: 20px; + border-radius: 50%; + background: #3b82f6; + border: 2px solid white; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + cursor: pointer; + pointer-events: all; + position: relative; + z-index: 3; +} + +.slider-thumb::-moz-range-thumb { + height: 20px; + width: 20px; + border-radius: 50%; + background: #3b82f6; + border: 2px solid white; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); + cursor: pointer; + pointer-events: all; + border: none; +} + +.slider-thumb::-webkit-slider-thumb:hover { + background: #2563eb; +} + +.slider-thumb::-moz-range-thumb:hover { + background: #2563eb; +} + +/* Utility class to hide scrollbars */ +.scrollbar-hide { + -ms-overflow-style: none; /* Internet Explorer 10+ */ + scrollbar-width: none; /* Firefox */ +} + +.scrollbar-hide::-webkit-scrollbar { + display: none; /* Safari and Chrome */ +} + @media (prefers-color-scheme: light) { :root { color: #213547; diff --git a/src/pages/PedimentoDetail.jsx b/src/pages/PedimentoDetail.jsx index 6e84184..dad0e74 100644 --- a/src/pages/PedimentoDetail.jsx +++ b/src/pages/PedimentoDetail.jsx @@ -4,6 +4,7 @@ const fadeInSlideUp = `@keyframes fadein-slideup { 0% { opacity: 0; transform: translateY(40px); } 100% { opacity: 1; transform: translateY(0); } }`; + if (typeof document !== 'undefined' && !document.getElementById('fadein-slideup-pedimento')) { const style = document.createElement('style'); style.id = 'fadein-slideup-pedimento'; @@ -130,6 +131,8 @@ export default function PedimentoDetail() { document_type: '', extension: '', date: '', + created_at__gte: '', + created_at__lte: '', fuente: '', pedimento_numero: '' }); @@ -153,8 +156,8 @@ export default function PedimentoDetail() { numero_cove: '', cove_descargado: '', acuse_cove_descargado: '', - date_from: '', - date_to: '' + created_at__gte: '', + created_at__lte: '' }); // Estados para EDocs @@ -170,10 +173,64 @@ export default function PedimentoDetail() { descripcion: '', edocument_descargado: '', acuse_descargado: '', - date_from: '', - date_to: '' + created_at__gte: '', + created_at__lte: '' }); + // Estados para Partidas + const [partidas, setPartidas] = useState([]); + const [partidasCount, setPartidasCount] = useState(0); + const [partidasLoading, setPartidasLoading] = useState(false); + const [partidasError, setPartidasError] = useState(''); + const [partidasPage, setPartidasPage] = useState(1); + const [partidasPageSize, setPartidasPageSize] = useState(10); + const [partidasFilters, setPartidasFilters] = useState({ + numero_partida: '', + descargado: '', + numero_partida__gte: '', + numero_partida__lte: '', + created_at__gte: '', + created_at__lte: '' + }); + const [selectedPartidas, setSelectedPartidas] = useState([]); + const [downloadingPartidas, setDownloadingPartidas] = useState(false); + const [downloadingAllPartidas, setDownloadingAllPartidas] = useState(false); + + // Función para obtener partidas + const fetchPedimentoPartidas = async (page = 1, pageSize = 10, filters = {}) => { + console.log('fetchPedimentoPartidas called with:', { page, pageSize, filters }); + console.log('pedimento object:', pedimento); + console.log('pedimento.id:', pedimento?.id); + + if (!pedimento?.id) { + throw new Error('No hay ID de pedimento disponible'); + } + + const params = new URLSearchParams({ + pedimento: pedimento.id, + page: page.toString(), + page_size: pageSize.toString() + }); + + // Solo agregar filtros que tengan valores + Object.entries(filters).forEach(([key, value]) => { + if (value && value.toString().trim() !== '') { + params.append(key, value); + } + }); + + const finalUrl = `${API_URL}/customs/partidas/?${params}`; + console.log('Final URL:', finalUrl); + + const response = await fetchWithAuth(finalUrl); + if (!response.ok) { + throw new Error('Error al obtener las partidas'); + } + const result = await response.json(); + console.log('API Response:', result); + return result; + }; + // Estados para Procesos const [procesos, setProcesos] = useState([]); const [procesosCount, setProcesosCount] = useState(0); @@ -434,6 +491,8 @@ export default function PedimentoDetail() { if (filters.name) apiFilters.archivo__icontains = filters.name; if (filters.extension) apiFilters.extension = filters.extension; if (filters.date) apiFilters.created_at__date = filters.date; + if (filters.created_at__gte) apiFilters.created_at__gte = filters.created_at__gte; + if (filters.created_at__lte) apiFilters.created_at__lte = filters.created_at__lte; if (filters.fuente) apiFilters.fuente = filters.fuente; if (filters.pedimento_numero) apiFilters.pedimento_numero__icontains = filters.pedimento_numero; @@ -1022,6 +1081,46 @@ export default function PedimentoDetail() { } }; + // Fetch Partidas cuando sea necesario + useEffect(() => { + console.log('Partidas useEffect triggered:', { id, activeTab, pedimento: pedimento?.id, partidasPage, partidasPageSize, partidasFilters }); + + if (!id || activeTab !== 'partidas' || !pedimento) { + console.log('Skipping partidas fetch due to missing conditions:', { + hasId: !!id, + isPartidasTab: activeTab === 'partidas', + hasPedimento: !!pedimento + }); + return; + } + + console.log('Starting partidas fetch...'); + setPartidasLoading(true); + setPartidasError(''); + + fetchPedimentoPartidas(partidasPage, partidasPageSize, partidasFilters) + .then((data) => { + console.log('Partidas fetch success:', data); + setPartidas(data.results || []); + setPartidasCount(data.count || 0); + setPartidasLoading(false); + }) + .catch(err => { + console.error('Error fetching Partidas:', err); + if (err.message === 'SESSION_EXPIRED') { + showMessage('Tu sesión ha expirado, por favor inicia sesión de nuevo.', 'error'); + } else { + setPartidasError(err.message); + } + setPartidasLoading(false); + }); + }, [id, activeTab, partidasPage, partidasPageSize, partidasFilters, showMessage, pedimento]); + + // Resetear página de Partidas cuando cambien los filtros + useEffect(() => { + setPartidasPage(1); + }, [partidasFilters]); + // Fetch Procesos cuando sea necesario useEffect(() => { if (!id || activeTab !== 'procesos') return; @@ -1095,6 +1194,19 @@ export default function PedimentoDetail() { } }; + // Funciones para procesar peticiones + const handleCoveRequest = async (cove) => { + console.log('Request cove:', cove); + showMessage(`Procesando petición para COVE #${cove.numero_cove}...`, 'info'); + // Aquí implementarías la lógica de petición específica para COVEs + }; + + const handleEdocRequest = async (edoc) => { + console.log('Request edoc:', edoc); + showMessage(`Procesando petición para EDocs #${edoc.numero_edocument}...`, 'info'); + // Aquí implementarías la lógica de petición específica para EDocs + }; + const formatDate = (dateString) => { if (!dateString) return 'N/A'; return new Date(dateString).toLocaleDateString('es-ES', { @@ -1106,6 +1218,56 @@ export default function PedimentoDetail() { }); }; + // Funciones para Partidas + const handlePartidaPreview = async (partida) => { + // Pasar un objeto que simule un documento con el ID del pedimento + const partidaDoc = { ...partida, id: pedimento.id }; + await handlePreview(partidaDoc); + }; + + const handlePartidaDownload = async (partida) => { + const fileName = partida.archivo ? partida.archivo.split('/').pop() : `partida_${partida.numero_partida}_${partida.id}`; + await downloadFile(pedimento.id, fileName, showMessage); + }; + + const handlePartidaRequest = async (partida) => { + console.log('Request partida:', partida); + showMessage(`Procesando petición para partida #${partida.numero_partida}...`, 'info'); + // Aquí implementarías la lógica de petición específica para partidas + }; + + // Funciones de selección para partidas + const allPartidaIds = partidas.map(partida => partida.id); + const allPartidasSelected = selectedPartidas.length === allPartidaIds.length && allPartidaIds.length > 0; + + const handleSelectPartida = (id) => { + setSelectedPartidas(prev => prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id]); + }; + + const handleSelectAllPartidas = () => { + if (allPartidasSelected) setSelectedPartidas([]); + else setSelectedPartidas(allPartidaIds); + }; + + const handleBulkDownloadPartidas = async (ids) => { + setDownloadingPartidas(true); + await downloadBulkZip(ids, showMessage, `${pedimento?.pedimento}_partidas`); + setDownloadingPartidas(false); + }; + + const downloadAllPartidas = async () => { + setDownloadingAllPartidas(true); + try { + const allPartidaIds = partidas.map(partida => partida.id); + await handleBulkDownloadPartidas(allPartidaIds); + } catch (error) { + console.error('Error downloading all partidas:', error); + showMessage('Error al descargar todas las partidas', 'error'); + } finally { + setDownloadingAllPartidas(false); + } + }; + // Estados de carga if (loading) return (
@@ -1222,54 +1384,77 @@ export default function PedimentoDetail() { {/* Navegación de pestañas */}
-