From 7c4027538161d2ee61a0b6b985881fb1b2044305 Mon Sep 17 00:00:00 2001 From: Luis Date: Thu, 29 Jan 2026 08:07:52 -0700 Subject: [PATCH] =?UTF-8?q?fix:=20se=20agrega=20nueva=20pesta=C3=B1a=20par?= =?UTF-8?q?a=20visualizar=20los=20archivos=20de=20error=20que=20devuelve?= =?UTF-8?q?=20vucem=20en=20detalle=20pedimento.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/PedimentoDetail.jsx | 680 +++++++++++++++++++++++++++++++++- 1 file changed, 677 insertions(+), 3 deletions(-) diff --git a/src/pages/PedimentoDetail.jsx b/src/pages/PedimentoDetail.jsx index 7a7e55b..0d5f40e 100644 --- a/src/pages/PedimentoDetail.jsx +++ b/src/pages/PedimentoDetail.jsx @@ -2827,6 +2827,237 @@ const handleDeleteSelectedPedimentoDocuments = async () => { const isPartida = selectedDocumentForUpload?.tab === 'partida'; const isCove = selectedDocumentForUpload?.tab === 'cove'; const isEdoc = selectedDocumentForUpload?.tab === 'edoc'; + + // Estados para documentos de errores VU +const [errorDocuments, setErrorDocuments] = useState([]); +const [errorDocsCount, setErrorDocsCount] = useState(0); +const [errorDocsLoading, setErrorDocsLoading] = useState(true); +const [errorDocsError, setErrorDocsError] = useState(''); +const [errorDocsPage, setErrorDocsPage] = useState(1); +const [errorDocsPageSize, setErrorDocsPageSize] = useState(10); +const [selectedErrorDocuments, setSelectedErrorDocuments] = useState([]); +const [isSelectAllErrorDocs, setIsSelectAllErrorDocs] = useState(false); +const [downloadingAllErrors, setDownloadingAllErrors] = useState(false); + + // Filtros para errores VU + const [errorFilters, setErrorFilters] = useState({ + name: '', + document_type: '', + extension: '', + date: '', + created_at__gte: '', + created_at__lte: '', + fuente: '', + pedimento_numero: '', + tipo_error: '' + }); + +// Estado para mostrar filtros de errores +const [showErrorFilters, setShowErrorFilters] = useState(false); + +// Efecto para cargar documentos de errores VU +useEffect(() => { + // Función para obtener documentos de errores VU usando el endpoint específico + const fetchErrorDocuments = async (pedimentoId,page = 1, pageSize = 10, filters = {}) => { + try { + if (!id || !pedimento?.pedimento_app) return; + + // Construir parámetros de filtros + const params = new URLSearchParams({ + pedimento: pedimento.pedimento_app, // Usar pedimento_app como requiere el endpoint + pedimentoId: pedimentoId, + // document_type_id: [14,16,18,20,22,24,26], IDs de tipos de documentos de error VU + page: page, + page_size: pageSize + }); + + // Solo agregar filtros que tengan valores + Object.entries(filters).forEach(([key, value]) => { + if (value && value.toString().trim() !== '') { + params.append(key, value); + } + }); + + // Usar el endpoint específico para documentos de error VU + const response = await fetchWithAuth( + `${API_URL}/record/documents/vu-documentos-errores/?${params}` + ); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.error || `Error ${response.status} al obtener documentos de error VU`); + } + + const data = await response.json(); + + // El endpoint devuelve un array directo, no un objeto paginado + // Aplicamos paginación manualmente en el frontend + if (Array.isArray(data)) { + const startIndex = (page - 1) * pageSize; + const endIndex = startIndex + pageSize; + const paginatedResults = data.slice(startIndex, endIndex); + + return { + results: paginatedResults, + count: data.length, + next: endIndex < data.length ? page + 1 : null, + previous: page > 1 ? page - 1 : null + }; + } + + // Si por alguna razón devuelve un objeto paginado + return data; + + } catch (error) { + console.error('Error fetching error documents:', error); + throw error; + } + }; + + if (!id || !pedimento || activeTab !== 'errores') return; + + console.log('Fetching error documents for pedimento:', pedimento.pedimento_app); + setErrorDocsLoading(true); + setErrorDocsError(''); + + // Construir parámetros de filtros + const apiFilters = {}; + if (errorFilters.name) apiFilters.archivo__icontains = errorFilters.name; + if (errorFilters.extension) apiFilters.extension = errorFilters.extension; + if (errorFilters.date) apiFilters.created_at__date = errorFilters.date; + if (errorFilters.created_at__gte) apiFilters.created_at__gte = errorFilters.created_at__gte; + if (errorFilters.created_at__lte) apiFilters.created_at__lte = errorFilters.created_at__lte; + if (errorFilters.fuente) apiFilters.fuente = errorFilters.fuente; + if (errorFilters.tipo_error) { + apiFilters.tipo_error = errorFilters.tipo_error; + }else{ + apiFilters.tipo_error = [14,16,18,20,22,24,26]; + } + + // NOTA: No necesitamos document_type porque el endpoint ya filtra por documentos de error VU + // Tampoco necesitamos pedimento_numero porque ya estamos filtrando por pedimento + + fetchErrorDocuments(id,errorDocsPage, errorDocsPageSize, apiFilters) + .then((data) => { + console.log('Error documents data:', data); + setErrorDocuments(data.results || []); + setErrorDocsCount(data.count || 0); + setErrorDocsLoading(false); + }) + .catch(err => { + console.error('Error fetching error documents:', err); + if (err.message === 'SESSION_EXPIRED') { + showMessage('Tu sesión ha expirado, por favor inicia sesión de nuevo.', 'error'); + } else { + setErrorDocsError(err.message || 'Error al cargar documentos de error VU'); + } + setErrorDocsLoading(false); + }); +}, [id, activeTab, errorDocsPage, errorDocsPageSize, errorFilters, showMessage, pedimento]); + + // Resetear página cuando cambien los filtros de errores + useEffect(() => { + setErrorDocsPage(1); + }, [errorFilters]); + + // Efecto para actualizar isSelectAllErrorDocs cuando cambia la selección + useEffect(() => { + if (errorDocuments.length > 0) { + const allSelected = errorDocuments.every(doc => selectedErrorDocuments.includes(doc.id)); + setIsSelectAllErrorDocs(allSelected && selectedErrorDocuments.length > 0); + } + }, [selectedErrorDocuments, errorDocuments]); + + + // Efecto para limpiar selección cuando cambia de página + useEffect(() => { + setSelectedErrorDocuments([]); + setIsSelectAllErrorDocs(false); + }, [errorDocsPage]); + + // Funciones para manejo de selección múltiple de documentos de error + const handleSelectErrorDocument = (documentId) => { + const isSelected = selectedErrorDocuments.includes(documentId); + if (isSelected) { + setSelectedErrorDocuments(prev => prev.filter(id => id !== documentId)); + } else { + setSelectedErrorDocuments(prev => [...prev, documentId]); + } + }; + + const handleSelectAllErrorDocuments = () => { + if (isSelectAllErrorDocs) { + setSelectedErrorDocuments([]); + setIsSelectAllErrorDocs(false); + } else { + const allDocumentIds = errorDocuments.map(doc => doc.id); + setSelectedErrorDocuments(allDocumentIds); + setIsSelectAllErrorDocs(true); + } + }; + + // Función para eliminar documentos de error seleccionados + const handleDeleteSelectedErrorDocuments = async () => { + if (selectedErrorDocuments.length === 0) { + showMessage('No hay documentos seleccionados para eliminar', 'warning'); + return; + } + + try { + showMessage(`Eliminando ${selectedErrorDocuments.length} documento(s) de error...`, 'info'); + + const response = await fetchWithAuth(`${API_URL}/record/documents/bulk-delete/`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + ids: selectedErrorDocuments + }) + }); + + if (!response.ok) { + const errorData = await response.json().catch(() => null); + throw new Error(errorData?.detail || errorData?.message || `Error ${response.status}: ${response.statusText}`); + } + + const result = await response.json(); + + showMessage( + `${result.deleted_count || selectedErrorDocuments.length} documento(s) de error eliminado(s) exitosamente`, + 'success' + ); + + setSelectedErrorDocuments([]); + setIsSelectAllErrorDocs(false); + + // Forzar recarga de documentos + const currentPage = errorDocsPage; + setErrorDocsPage(0); + setTimeout(() => setErrorDocsPage(currentPage), 100); + } catch (error) { + console.error('Error durante la eliminación masiva de documentos de error:', error); + showMessage(`Error durante la eliminación: ${error.message}`, 'error'); + } + }; + + // Función para descargar todos los documentos de error + const downloadAllErrors = async () => { + setDownloadingAllErrors(true); + try { + const allErrorDocIds = errorDocuments.map(doc => doc.id); + await handleBulkDownload(allErrorDocIds); + } catch (error) { + console.error('Error downloading all error documents:', error); + showMessage('Error al descargar todos los documentos de error', 'error'); + } finally { + setDownloadingAllErrors(false); + } + }; + + + + //----------------------------------------// // Estados de carga @@ -3044,7 +3275,29 @@ const isEdoc = selectedDocumentForUpload?.tab === 'edoc'; )} - + {/* Pestaña Errores VU */} + + {/* Pestaña Auditor */} + + + + )} + + + + {/* Filtros expandibles para errores */} + {showErrorFilters && ( +
+
+ + setErrorFilters(prev => ({ ...prev, name: e.target.value }))} + placeholder="Nombre del archivo..." + className="w-full px-3 py-2 placeholder-gray-400 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-red-500 focus:border-red-500 sm:text-sm" + /> +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + {/*
+ + setErrorFilters(prev => ({ ...prev, date: e.target.value }))} + className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-red-500 focus:border-red-500 sm:text-sm" + /> +
*/} + +
+ +
+
+ )} + + + {/* Área de acciones para documentos de error seleccionados */} + {selectedErrorDocuments.length > 0 && ( +
+
+
+
+
+ + + +
+
+

+ {selectedErrorDocuments.length} documento{selectedErrorDocuments.length !== 1 ? 's' : ''} de error seleccionado{selectedErrorDocuments.length !== 1 ? 's' : ''} +

+

Selecciona una acción para continuar

+
+
+ +
+
+
+
+ +
+
+
+ )} + + {errorDocsLoading ? ( +
+
+ Cargando documentos de error... +
+ ) : errorDocsError ? ( +
+
+ + + +
+

Error al cargar documentos de error

+

{errorDocsError}

+
+ ) : errorDocuments.length === 0 ? ( +
+ + + +

No hay documentos de error

+

+ No se encontraron documentos de error VU para este pedimento. +

+
+ ) : ( +
+ {/* Tabla de documentos de error */} +
+
+ + + + + + + + + + + + + + + {errorDocuments.map((doc, index) => ( + + + + + + + + + + + ))} + +
+ + + Documento + + Tipo + + Extensión + + Tamaño + + Fuente + + Fecha de Creación + + Acciones +
+ handleSelectErrorDocument(doc.id)} + className="w-4 h-4 text-red-600 border-gray-300 rounded focus:ring-red-500" + /> + +
+
+
+ + + +
+
+
+
+ {doc.archivo ? doc.archivo.split('/').pop() : 'Sin nombre'} +
+
+ Pedimento: {doc.pedimento_numero || 'N/A'} +
+
+
+
+ + {getDocumentTypeName(doc.document_type)} + + + + {doc.extension ? doc.extension.toUpperCase() : 'N/A'} + + + {formatFileSize(doc.size)} + + + {doc.fuente_nombre} + + + {formatDate(doc.created_at)} + +
+ + +
+
+
+
+
+ )} + + {/* Paginación para documentos de error */} + {errorDocsCount > 0 && ( +
+
+ + Mostrando + {((errorDocsPage - 1) * errorDocsPageSize) + 1}- + {Math.min(errorDocsPage * errorDocsPageSize, errorDocsCount)} + de + / + {errorDocsCount} + documentos + + +
+ +
+ + + + Página {errorDocsPage} de {Math.ceil(errorDocsCount / errorDocsPageSize)} + + + +
+
+ )} + + )} +