From a856262708280b34fa42772276ed5b18ed9859ca Mon Sep 17 00:00:00 2001 From: hreyes Date: Tue, 3 Mar 2026 08:16:50 -0700 Subject: [PATCH] feature/faltantes-csv --- frontend/src/lib/api.ts | 42 ++++++++++ .../csv-upload/UploadLauncherGrid.svelte | 3 +- frontend/src/lib/config/csv-upload.ts | 21 +++++ .../routes/dashboard/csv-upload/+page.svelte | 79 ++++++++++++++++++- 4 files changed, 142 insertions(+), 3 deletions(-) diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index d535507f..0e8b57f9 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -508,6 +508,48 @@ export const api = { api.post(`/v1/a76/transportation/trailers/imports/${jobId}/commit`, {}) }, + // CSV import for Transportistas (transporters/imports) + transporterImports: { + upload: (file: File, companyId: number) => { + const formData = new FormData(); + formData.append('file', file); + return fetchApi( + `/v1/a76/transporters/imports/upload?company_id=${companyId}`, + { method: 'POST', body: formData } + ); + }, + status: (jobId: string) => api.get(`/v1/a76/transporters/imports/${jobId}/status`), + commit: (jobId: string) => api.post(`/v1/a76/transporters/imports/${jobId}/commit`, {}) + }, + + // CSV import for Números de parte (parts/imports) + partNumberImports: { + upload: (file: File, companyId: number) => { + const formData = new FormData(); + formData.append('file', file); + return fetchApi( + `/v1/a76/parts/imports/upload?company_id=${companyId}`, + { method: 'POST', body: formData } + ); + }, + status: (jobId: string) => api.get(`/v1/a76/parts/imports/${jobId}/status`), + commit: (jobId: string) => api.post(`/v1/a76/parts/imports/${jobId}/commit`, {}) + }, + + // CSV import for BOMs (boms/imports) + bomImports: { + upload: (file: File, companyId: number) => { + const formData = new FormData(); + formData.append('file', file); + return fetchApi( + `/v1/a76/boms/imports/upload?company_id=${companyId}`, + { method: 'POST', body: formData } + ); + }, + status: (jobId: string) => api.get(`/v1/a76/boms/imports/${jobId}/status`), + commit: (jobId: string) => api.post(`/v1/a76/boms/imports/${jobId}/commit`, {}) + }, + // Generic request for custom needs (like file uploads) request: (endpoint: string, options: RequestInit = {}) => fetchApi(endpoint, options) }; diff --git a/frontend/src/lib/components/dashboard/csv-upload/UploadLauncherGrid.svelte b/frontend/src/lib/components/dashboard/csv-upload/UploadLauncherGrid.svelte index 62830c66..3f17fc78 100644 --- a/frontend/src/lib/components/dashboard/csv-upload/UploadLauncherGrid.svelte +++ b/frontend/src/lib/components/dashboard/csv-upload/UploadLauncherGrid.svelte @@ -93,10 +93,11 @@ e.preventDefault(); return; } - if (!item.templateUrl) return; e.preventDefault(); + if (!item.templateUrl) return; + const link = document.createElement('a'); link.href = item.templateUrl; link.download = item.templateUrl.split('/').pop() || 'plantilla.xls'; diff --git a/frontend/src/lib/config/csv-upload.ts b/frontend/src/lib/config/csv-upload.ts index 2deb6775..da79ab77 100644 --- a/frontend/src/lib/config/csv-upload.ts +++ b/frontend/src/lib/config/csv-upload.ts @@ -161,6 +161,20 @@ export const catalogosConfig: CsvUploadItem[] = [ modelTarget: 'MaterialClass', templateUrl: '/csv/EstructuraCatClasesAF.xls' }, + { + id: 'part_numbers', + title: 'Números de parte', + icon: Hash, + modelTarget: 'Part', + templateUrl: '/csv/EstructuraCatNumerosParte.xlsx', + }, + { + id: 'boms', + title: 'BOMs', + icon: Briefcase, + modelTarget: 'Bom', + templateUrl: '/csv/EstructuraBOMS.xlsx', + }, { id: 'items', title: 'Partidas (Permisos)', @@ -194,6 +208,13 @@ export const catalogosConfig: CsvUploadItem[] = [ ]; export const transportesConfig: CsvUploadItem[] = [ + { + id: 'transporters', + title: 'Transportistas', + icon: Ship, + modelTarget: 'Transporter', + templateUrl: '/csv/EstructuraCatTransportistas.xlsx', + }, { id: 'transports', title: 'Transportes', diff --git a/frontend/src/routes/dashboard/csv-upload/+page.svelte b/frontend/src/routes/dashboard/csv-upload/+page.svelte index c5ec47e8..5a1901f1 100644 --- a/frontend/src/routes/dashboard/csv-upload/+page.svelte +++ b/frontend/src/routes/dashboard/csv-upload/+page.svelte @@ -42,6 +42,12 @@ let useDriverImport = $state(false); // Cuando es true, usamos API de importación de Trailers y Cajas (trailers/imports) let useTrailerImport = $state(false); + // Cuando es true, usamos API de importación de Transportistas (transporters/imports) + let useTransporterImport = $state(false); + // Cuando es true, usamos API de importación de Números de parte (parts/imports) + let usePartNumbersImport = $state(false); + // Cuando es true, usamos API de importación de BOMs (boms/imports) + let useBomImport = $state(false); // Initialize settings for all tabs upfront to avoid reactivity loops let allSettings = $state>(() => { @@ -69,6 +75,9 @@ useVehicleImport = config.id === 'transports'; useDriverImport = config.id === 'drivers'; useTrailerImport = config.id === 'trailers'; + useTransporterImport = config.id === 'transporters'; + usePartNumbersImport = config.id === 'part_numbers'; + useBomImport = config.id === 'boms'; const companyId = companyStore.activeCompany?.id || 1; @@ -234,6 +243,60 @@ return; } + if (useTransporterImport) { + try { + const res = await api.transporterImports.upload(file, companyId); + if (res.data?.job_id) { + currentJobId = res.data.job_id; + pollStatus(); + } else { + toast.error(res.error || 'Error al subir el archivo'); + isUploading = false; + } + } catch (e) { + console.error('Upload exception', e); + toast.error('Error inesperado al subir el archivo'); + isUploading = false; + } + return; + } + + if (usePartNumbersImport) { + try { + const res = await api.partNumberImports.upload(file, companyId); + if (res.data?.job_id) { + currentJobId = res.data.job_id; + pollStatus(); + } else { + toast.error(res.error || 'Error al subir el archivo'); + isUploading = false; + } + } catch (e) { + console.error('Upload exception', e); + toast.error('Error inesperado al subir el archivo'); + isUploading = false; + } + return; + } + + if (useBomImport) { + try { + const res = await api.bomImports.upload(file, companyId); + if (res.data?.job_id) { + currentJobId = res.data.job_id; + pollStatus(); + } else { + toast.error(res.error || 'Error al subir el archivo'); + isUploading = false; + } + } catch (e) { + console.error('Upload exception', e); + toast.error('Error inesperado al subir el archivo'); + isUploading = false; + } + return; + } + const currentSettings = allSettings[activeTab] || {}; const footerConfig = { ...currentSettings }; if (activeTab === 'importacion') { @@ -286,7 +349,13 @@ ? await api.driverImports.status(currentJobId) : useTrailerImport ? await api.trailerImports.status(currentJobId) - : await api.imports.status(currentJobId); + : useTransporterImport + ? await api.transporterImports.status(currentJobId) + : usePartNumbersImport + ? await api.partNumberImports.status(currentJobId) + : useBomImport + ? await api.bomImports.status(currentJobId) + : await api.imports.status(currentJobId); console.log('Poll response', res); if (res.error && !res.data) { toast.error(res.error || 'Error al consultar el estado'); @@ -448,7 +517,13 @@ ? await api.driverImports.commit(currentJobId) : useTrailerImport ? await api.trailerImports.commit(currentJobId) - : await api.imports.commit(currentJobId, activeModelTarget || ''); + : useTransporterImport + ? await api.transporterImports.commit(currentJobId) + : usePartNumbersImport + ? await api.partNumberImports.commit(currentJobId) + : useBomImport + ? await api.bomImports.commit(currentJobId) + : await api.imports.commit(currentJobId, activeModelTarget || ''); if (res.data?.commit_job_id) { currentJobId = res.data.commit_job_id; pollStatus();