+
-
{completeMessage}
+
+ {#if lastResult?.cove_number}
+ COVE generado
+ {:else if lastResult?.status === 'validation_error'}
+ Se encontraron errores de validación
+ {:else}
+ {completeMessage}
+ {/if}
+
+
+ {#if lastResult?.cove_number}
+
+ COVE: {lastResult.cove_number}
+
+ {/if}
+ {#if taskId}
+
+ Task ID: {taskId}
+
+ {/if}
+
+
+ {#if lastResult?.status === 'validation_error' && externalBody}
+
+ {externalBody.mensaje || 'Datos inválidos en el servicio COVE.'}
+
+ {#if externalErrors && externalErrors.length}
+
+ {#each externalErrors as e}
+ {e.campo}: {e.mensaje}
+ {/each}
+
+ {/if}
+ {:else if lastResult?.message}
+
+ {lastResult.message}
+
+ {/if}
{:else if hasError}
- {#if hasError}
- Cerrar
+ {#if isComplete || hasError}
+ (open = false)}>Cerrar
{/if}
diff --git a/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts
index e7df9728..b57dde05 100644
--- a/frontend/src/lib/utils.ts
+++ b/frontend/src/lib/utils.ts
@@ -7,8 +7,8 @@ export function cn(...inputs: ClassValue[]) {
/**
* Convierte una ruta relativa del backend en una URL completa
- * @param path Ruta relativa (ej: "/uploads/avatars/file.png")
- * @returns URL completa del backend (ej: "http://localhost:8000/uploads/avatars/file.png")
+ * @param path Ruta relativa (ej: "/uploads/avatars/file.png") o absoluta API (ej: "/api/v1/...")
+ * @returns URL completa del backend
*/
export function getBackendAssetUrl(path: string | null | undefined): string {
if (!path) return '';
@@ -18,16 +18,49 @@ export function getBackendAssetUrl(path: string | null | undefined): string {
return path;
}
- // Eliminar la / inicial si existe para evitar //
- const cleanPath = path.startsWith('/') ? path.slice(1) : path;
+ const normalized = path.startsWith('/') ? path : `/${path}`;
// Obtener la base URL del API y limpiar el / final si existe
let baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000';
- baseUrl = baseUrl.replace(/\/+$/, ''); // Eliminar todas las / del final
+ baseUrl = baseUrl.replace(/\/+$/, '');
+ // VITE_API_URL suele ser .../api; las rutas del backend a veces vienen como /api/v1/...
+ // Evitar http://host/api/api/v1/...
+ if (normalized.startsWith('/api/') && baseUrl.endsWith('/api')) {
+ const origin = baseUrl.slice(0, -'/api'.length);
+ return `${origin}${normalized}`;
+ }
+
+ const cleanPath = normalized.startsWith('/') ? normalized.slice(1) : normalized;
return `${baseUrl}/${cleanPath}`;
}
+/**
+ * Obtiene únicamente el nombre del archivo a partir de una ruta/URL.
+ */
+export function getFileNameFromPath(filePath: string | null | undefined): string {
+ if (!filePath) return '';
+
+ const withoutQuery = filePath.split('?')[0].split('#')[0];
+ const normalizedPath = withoutQuery.replace(/\\/g, '/');
+ return normalizedPath.split('/').filter(Boolean).pop() || withoutQuery;
+}
+
+/**
+ * Formatea el texto de visualización para archivos evitando mostrar rutas completas.
+ */
+export function getFileDisplayName(
+ filePath: string | null | undefined,
+ fileType?: string,
+ defaultLabel = 'Seleccionar archivo'
+): string {
+ if (!filePath) return defaultLabel;
+
+ const fileName = getFileNameFromPath(filePath);
+ if (!fileName) return defaultLabel;
+ return fileType ? `${fileName} (${fileType.toUpperCase()})` : fileName;
+}
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type WithoutChild = T extends { child?: any } ? Omit : T;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
diff --git a/frontend/src/routes/dashboard/audit_logs/+page.svelte b/frontend/src/routes/dashboard/audit_logs/+page.svelte
index 7de90e27..6d41408e 100644
--- a/frontend/src/routes/dashboard/audit_logs/+page.svelte
+++ b/frontend/src/routes/dashboard/audit_logs/+page.svelte
@@ -2,10 +2,11 @@
import { afterNavigate, goto } from '$app/navigation';
import { page } from '$app/state';
import * as Tabs from '$lib/components/ui/tabs';
- import { ScrollText, ListTodo } from 'lucide-svelte';
+ import { ScrollText, ListTodo, FolderTree } from 'lucide-svelte';
import * as m from '$lib/paraglide/messages.js';
import BitacoraTab from './bitacora-tab.svelte';
import TasksTab from './tasks-tab.svelte';
+ import FilesTab from './files-tab.svelte';
import type { PageData } from './$types';
let { data }: { data: PageData } = $props();
@@ -17,17 +18,19 @@
});
afterNavigate(() => {
- const t = page.url.searchParams.get('tab') === 'tasks' ? 'tasks' : 'bitacora';
+ const raw = page.url.searchParams.get('tab');
+ const t = raw === 'tasks' || raw === 'files' ? raw : 'bitacora';
tabValue = t;
});
function onTabValueChange(v: string) {
- const fromUrl = page.url.searchParams.get('tab') === 'tasks' ? 'tasks' : 'bitacora';
+ const raw = page.url.searchParams.get('tab');
+ const fromUrl = raw === 'tasks' || raw === 'files' ? raw : 'bitacora';
if (v === fromUrl) return;
const u = new URL(page.url.href);
- if (v === 'tasks') {
- u.searchParams.set('tab', 'tasks');
+ if (v === 'tasks' || v === 'files') {
+ u.searchParams.set('tab', v);
} else {
u.searchParams.delete('tab');
}
@@ -53,7 +56,7 @@
onValueChange={onTabValueChange}
class="flex min-h-0 w-full flex-1 flex-col"
>
-
+
{m['sidebar.audit_logs_tab_bitacora']()}
@@ -62,6 +65,10 @@
{m['sidebar.audit_logs_tab_tasks']()}
+
+
+ {m['sidebar.audit_logs_tab_files']()}
+
@@ -74,5 +81,10 @@
{/if}
+
+ {#if tabValue === 'files'}
+
+ {/if}
+
diff --git a/frontend/src/routes/dashboard/audit_logs/+page.ts b/frontend/src/routes/dashboard/audit_logs/+page.ts
index 1bf476b2..a653eef6 100644
--- a/frontend/src/routes/dashboard/audit_logs/+page.ts
+++ b/frontend/src/routes/dashboard/audit_logs/+page.ts
@@ -2,6 +2,6 @@ import type { PageLoad } from './$types';
export const load: PageLoad = ({ url }) => {
const tab = url.searchParams.get('tab');
- const initialTab = tab === 'tasks' ? 'tasks' : 'bitacora';
+ const initialTab = tab === 'tasks' || tab === 'files' ? tab : 'bitacora';
return { initialTab };
};
diff --git a/frontend/src/routes/dashboard/audit_logs/files-tab.svelte b/frontend/src/routes/dashboard/audit_logs/files-tab.svelte
new file mode 100644
index 00000000..051df209
--- /dev/null
+++ b/frontend/src/routes/dashboard/audit_logs/files-tab.svelte
@@ -0,0 +1,205 @@
+
+
+
+
+
+
{m['sidebar.audit_logs_files_title']()}
+
{displayPath || m['sidebar.audit_logs_files_root']()}
+
+
void loadPath(currentPath)} disabled={loading}>
+
+ {m['sidebar.audit_logs_files_refresh']()}
+
+
+
+
+
+
+ {#each breadcrumbs as crumb, idx}
+ {#if idx > 0}
+ /
+ {/if}
+ {#if idx === breadcrumbs.length - 1}
+
+ {crumb.display_name}
+
+ {:else}
+ void loadPath(crumb.path)}
+ disabled={loading}
+ >
+ {crumb.display_name}
+
+ {/if}
+ {/each}
+
+
+
+
+
+
+ {m['sidebar.audit_logs_files_list_title']()}
+
+
+ {#if error}
+
+ {m['sidebar.audit_logs_files_error_prefix']()} {error}
+
+ {/if}
+
+
+
+
+
+ {m['sidebar.audit_logs_files_col_name']()}
+
+
+ {m['sidebar.audit_logs_files_col_size']()}
+
+
+ {m['sidebar.audit_logs_files_col_modified']()}
+
+
+ {m['sidebar.audit_logs_files_col_actions']()}
+
+
+
+
+ {#if loading}
+
+
+ {m['sidebar.audit_logs_files_loading']()}
+
+
+ {:else if folders.length === 0 && files.length === 0}
+
+
+ {m['sidebar.audit_logs_files_empty']()}
+
+
+ {:else}
+ {#each folders as folder}
+ void loadPath(folder.path)}
+ >
+
+
+
+ {folder.display_name}
+
+
+ —
+ —
+ —
+
+ {/each}
+ {#each files as file}
+
+
+ {file.display_name}
+
+ {formatSize(file.size)}
+ {formatDate(file.last_modified)}
+
+ void downloadFile(file.path, file.display_name)}
+ >
+
+
+
+
+ {/each}
+ {/if}
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/customs_brokers/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/customs_brokers/edit/[[id]]/+page.svelte
index 0c001f08..43de3704 100644
--- a/frontend/src/routes/dashboard/customs_brokers/edit/[[id]]/+page.svelte
+++ b/frontend/src/routes/dashboard/customs_brokers/edit/[[id]]/+page.svelte
@@ -4,6 +4,7 @@
import { companyStore } from '$lib/stores/company.svelte';
import {
customsBrokersApi,
+ uploadCustomsBrokerVuFile,
type CreateCustomsBrokerData
} from '$lib/api/dashboard/a76/customs-brokers';
@@ -41,6 +42,7 @@
ShieldCheck
} from 'lucide-svelte';
import { toast } from 'svelte-sonner';
+ import { getFileDisplayName } from '$lib/utils';
import { useShortcuts } from '$lib/hooks/use-shortcuts';
import { obtenerAtajosEdicionAgente } from '$lib/config/shortcuts/dashboard/customs_brokers/edit';
@@ -100,6 +102,15 @@
archive_path: ''
});
+ let pendingVuFiles = $state<{
+ certificate?: File;
+ key?: File;
+ cove?: File;
+ dodaCertificate?: File;
+ dodaKey?: File;
+ dodaCove?: File;
+ }>({});
+
let brokerKeyError = $state(false);
let licenseError = $state(false);
let brokerKeyTimeout: ReturnType
;
@@ -121,10 +132,88 @@
const file = input.files?.[0];
if (file) {
vuData[targetKey] = file.name;
+ if (targetKey === 'certificate_path') pendingVuFiles.certificate = file;
+ if (targetKey === 'key_path') pendingVuFiles.key = file;
+ if (targetKey === 'xml_files_path') pendingVuFiles.cove = file;
+ if (targetKey === 'doda_certificate_path') pendingVuFiles.dodaCertificate = file;
+ if (targetKey === 'doda_key_path') pendingVuFiles.dodaKey = file;
+ if (targetKey === 'doda_xml_files_path') pendingVuFiles.dodaCove = file;
toast.success(`Archivo ${file.name} seleccionado`);
}
}
+ async function uploadPendingVuFiles(companyId: string, brokerKey: string) {
+ if (pendingVuFiles.certificate) {
+ const res = await uploadCustomsBrokerVuFile(
+ brokerKey,
+ companyId,
+ 'certificate',
+ pendingVuFiles.certificate
+ );
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir certificado VU (.cer)');
+ }
+ vuData.certificate_path = (res as any).data.path;
+ }
+
+ if (pendingVuFiles.key) {
+ const res = await uploadCustomsBrokerVuFile(brokerKey, companyId, 'key', pendingVuFiles.key);
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir llave VU (.key)');
+ }
+ vuData.key_path = (res as any).data.path;
+ }
+
+ if (pendingVuFiles.cove) {
+ const res = await uploadCustomsBrokerVuFile(brokerKey, companyId, 'cove', pendingVuFiles.cove);
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir archivo COVE');
+ }
+ vuData.xml_files_path = (res as any).data.path;
+ }
+
+ if (pendingVuFiles.dodaCertificate) {
+ const res = await uploadCustomsBrokerVuFile(
+ brokerKey,
+ companyId,
+ 'doda_certificate',
+ pendingVuFiles.dodaCertificate
+ );
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir certificado DODA (.cer)');
+ }
+ vuData.doda_certificate_path = (res as any).data.path;
+ }
+
+ if (pendingVuFiles.dodaKey) {
+ const res = await uploadCustomsBrokerVuFile(
+ brokerKey,
+ companyId,
+ 'doda_key',
+ pendingVuFiles.dodaKey
+ );
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir llave DODA (.key)');
+ }
+ vuData.doda_key_path = (res as any).data.path;
+ }
+
+ if (pendingVuFiles.dodaCove) {
+ const res = await uploadCustomsBrokerVuFile(
+ brokerKey,
+ companyId,
+ 'doda_cove',
+ pendingVuFiles.dodaCove
+ );
+ if ((res as any).error || !(res as any).data?.path) {
+ throw new Error((res as any).error || 'Error al subir archivo DODA');
+ }
+ vuData.doda_xml_files_path = (res as any).data.path;
+ }
+
+ pendingVuFiles = {};
+ }
+
async function loadBrokerData(key: string, cId: string) {
if (!key || key === 'undefined') return;
loading = true;
@@ -279,6 +368,9 @@
if ((res as any).error) throw new Error((res as any).error);
+ // Primero sube archivos CER/KEY/COVE al bucket y guarda la ruta real en vuData.
+ await uploadPendingVuFiles(cId, formData.broker_key);
+
// UPSERT VU
try {
const vuRes = await customsBrokersApi.updateVU(formData.broker_key, vuData, cId);
@@ -694,15 +786,20 @@
Ruta de archivo .cer Archivo .cer
@@ -726,15 +823,20 @@
Ruta de archivo .key Archivo .key
@@ -836,8 +938,13 @@
>
@@ -950,15 +1057,20 @@
Ruta archivo .cer Archivo .cer
@@ -982,15 +1094,20 @@
Ruta archivo .key Archivo .key
@@ -1039,8 +1156,13 @@
>
diff --git a/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte
index 09f7ced6..1401d421 100644
--- a/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte
+++ b/frontend/src/routes/dashboard/general_catalogs/company_information/edit/[[id]]/+page.svelte
@@ -16,7 +16,7 @@
type Company
} from '$lib/api/dashboard/a76/general_catalogs/company';
import { companyStore } from '$lib/stores/company.svelte';
- import { getBackendAssetUrl } from '$lib/utils';
+ import { getBackendAssetUrl, getFileDisplayName } from '$lib/utils';
import {
ArrowLeft,
LoaderCircle,
@@ -498,7 +498,7 @@
successMessage = null;
try {
- const response = await uploadCompanyCertificate(Number(id), file, type);
+ const response = await uploadCompanyCertificate(Number(id), type, file);
if (response.error) {
throw new Error(response.error);
@@ -1614,9 +1614,7 @@
>
- {formData.fiel_cer
- ? formData.fiel_cer.split('/').pop()
- : 'Seleccionar archivo .cer'}
+ {getFileDisplayName(formData.fiel_cer, 'CER', 'Seleccionar archivo .cer')}
@@ -1638,9 +1636,7 @@
>
- {formData.fiel_key
- ? formData.fiel_key.split('/').pop()
- : 'Seleccionar archivo .key'}
+ {getFileDisplayName(formData.fiel_key, 'KEY', 'Seleccionar archivo .key')}
@@ -1688,9 +1684,11 @@
>
- {formData.cfdi_cert_cer
- ? formData.cfdi_cert_cer.split('/').pop()
- : 'Seleccionar archivo .cer'}
+ {getFileDisplayName(
+ formData.cfdi_cert_cer,
+ 'CER',
+ 'Seleccionar archivo .cer'
+ )}
@@ -1712,9 +1710,11 @@
>
- {formData.cfdi_cert_key
- ? formData.cfdi_cert_key.split('/').pop()
- : 'Seleccionar archivo .key'}
+ {getFileDisplayName(
+ formData.cfdi_cert_key,
+ 'KEY',
+ 'Seleccionar archivo .key'
+ )}
@@ -1774,9 +1774,7 @@
>
- {formData.cancel_cer
- ? formData.cancel_cer.split('/').pop()
- : 'Seleccionar archivo .cer'}
+ {getFileDisplayName(formData.cancel_cer, 'CER', 'Seleccionar archivo .cer')}
@@ -1798,9 +1796,7 @@
>
- {formData.cancel_key
- ? formData.cancel_key.split('/').pop()
- : 'Seleccionar archivo .key'}
+ {getFileDisplayName(formData.cancel_key, 'KEY', 'Seleccionar archivo .key')}
diff --git a/frontend/src/routes/dashboard/help-center/editor/[uuid]/+page.svelte b/frontend/src/routes/dashboard/help-center/editor/[uuid]/+page.svelte
index 2455fea8..d8ea7064 100644
--- a/frontend/src/routes/dashboard/help-center/editor/[uuid]/+page.svelte
+++ b/frontend/src/routes/dashboard/help-center/editor/[uuid]/+page.svelte
@@ -26,6 +26,7 @@
import { toast } from 'svelte-sonner';
import { marked } from 'marked';
import DOMPurify from 'dompurify';
+ import { getFileNameFromPath } from '$lib/utils';
// Helper to resolve an API path from the DB (e.g., /api/uploads/...) to a full URL pointing to the local backend.
function resolveAssetUrl(url: string | undefined): string {
@@ -439,7 +440,9 @@
Archivo Cargado
-
{file_url}
+
+ {getFileNameFromPath(file_url)}
+
{mime_type} • {file_size ? (file_size / 1024 / 1024).toFixed(2) : '??'} MB
diff --git a/frontend/src/routes/dashboard/invoices/+page.svelte b/frontend/src/routes/dashboard/invoices/+page.svelte
index 7823be87..85d94657 100644
--- a/frontend/src/routes/dashboard/invoices/+page.svelte
+++ b/frontend/src/routes/dashboard/invoices/+page.svelte
@@ -417,6 +417,7 @@
let currentTaskId = $state
(null);
let currentStatusFunction = $state<((taskId: string) => Promise) | null>(null);
let progressDialogTitle = $state('Generando documento');
+ let progressDialogSteps = $state<{ label: string; percent: number }[] | null>(null);
// Utilidad para convertir Base64 a Blob
function base64ToBlob(base64: string, type: string) {
@@ -614,11 +615,27 @@
window.URL.revokeObjectURL(url);
document.body.removeChild(a);
toast.success('PDF Descargado exitosamente');
+ } else if (result.cove_number) {
+ // Resultado de generación de COVE
+ const baseMsg = `COVE generado correctamente: ${result.cove_number}`;
+ const opMsg = result.vucem_operation_num
+ ? ` (Operación VUCEM: ${result.vucem_operation_num})`
+ : '';
+ toast.success(baseMsg + opMsg);
+ reloadData();
} else {
- // Resultado de procesamiento de factura
+ // Resultado de procesamiento de factura (import process/revert)
toast.success('Factura procesada correctamente');
reloadData();
}
+ } else if (result.status === 'external_queued') {
+ // Caso especial: VU aceptó la factura y la dejó en cola, pero devuelve
+ // un mensaje tipo "Factura COVE iniciada para: ... Use el task_id para consultar el estado."
+ const baseMsg =
+ result.message ||
+ 'Factura COVE iniciada en Ventanilla Única. Use el task_id para consultar el estado.';
+ const taskInfo = result.external_task_id ? ` (task_id: ${result.external_task_id})` : '';
+ toast.success(baseMsg + taskInfo);
} else if (result.status === 'validation_error') {
const errors: any[] = result.errors || [];
const preview = errors
@@ -627,18 +644,21 @@
.join('\n');
const extra = errors.length > 3 ? `\n...y ${errors.length - 3} más` : '';
toast.error(`${errors.length} error(es) de validación:\n${preview}${extra}`);
+ } else if (
+ typeof result.message === 'string' &&
+ result.message.includes('Factura COVE iniciada para')
+ ) {
+ // Salvaguarda: si por alguna razón el status no vino como external_queued
+ // pero el mensaje es el de "Factura COVE iniciada...", lo tratamos también
+ // como éxito/en cola y no como error.
+ const taskInfo = result.external_task_id ? ` (task_id: ${result.external_task_id})` : '';
+ toast.success(result.message + taskInfo);
} else {
toast.error('El worker reportó un error: ' + (result.message || 'Desconocido'));
}
} catch (e) {
console.error('Error al procesar resultado:', e);
toast.error('Error al procesar el resultado de la tarea');
- } finally {
- // Cerrar diálogo después de un breve momento
- setTimeout(() => {
- showProgressDialog = false;
- currentTaskId = null;
- }, 1000);
}
}
@@ -743,6 +763,7 @@
currentTaskId = response.data!.task_id;
currentStatusFunction = invoicesApi.getProcessStatus;
progressDialogTitle = 'Procesando factura';
+ progressDialogSteps = invoiceProcessSteps;
showProgressDialog = true;
} catch (e) {
console.error('Error al iniciar proceso de factura:', e);
@@ -768,6 +789,7 @@
currentTaskId = response.data!.task_id;
currentStatusFunction = invoicesApi.getRevertStatus;
progressDialogTitle = 'Des-actualizando factura';
+ progressDialogSteps = invoiceRevertSteps;
showProgressDialog = true;
} catch (e) {
console.error('Error al iniciar des-actualización de factura:', e);
@@ -775,6 +797,58 @@
}
}
+ async function handleGenerateCove() {
+ if (!selectedInvoice || !companyStore.activeCompany) {
+ toast.info('Selecciona una factura para generar COVE');
+ return;
+ }
+
+ const companyId = companyStore.activeCompany.id;
+
+ // Paso 1: Checar elegibilidad antes de disparar la tarea
+ try {
+ const elig = await invoicesApi.checkCoveEligibility(selectedInvoice.id, companyId);
+ if (elig.error) {
+ toast.error(`No se pudo validar elegibilidad COVE: ${elig.error}`);
+ return;
+ }
+ if (elig.data && !elig.data.can_generate) {
+ const msg =
+ elig.data.reasons
+ ?.map((r) => `• ${r.message}`)
+ .join('\n') ||
+ 'La factura no cumple los requisitos para generar COVE';
+ toast.error(msg);
+ return;
+ }
+ } catch (e) {
+ console.error('Error verificando elegibilidad COVE:', e);
+ toast.error('No se pudo verificar si la factura puede generar COVE');
+ return;
+ }
+
+ // Paso 2: Disparar tarea Celery de COVE
+ try {
+ const response = await invoicesApi.generateCove(selectedInvoice.id, companyId);
+
+ if (response.error) {
+ toast.error(`Error al iniciar generación de COVE: ${response.error}`);
+ return;
+ }
+
+ currentTaskId = response.data!.task_id;
+ currentStatusFunction = invoicesApi.getCoveStatus;
+ progressDialogTitle = 'Validando datos para COVE';
+ // Para COVE queremos UNA sola barra de progreso que refleje
+ // directamente el porcentaje reportado por VU, sin pasos fijos.
+ progressDialogSteps = null;
+ showProgressDialog = true;
+ } catch (e) {
+ console.error('Error al iniciar generación de COVE:', e);
+ toast.error('No se pudo iniciar la generación de COVE');
+ }
+ }
+
// Pasos del procesamiento de factura (deben coincidir con el backend)
const invoiceProcessSteps = [
{ label: 'Cargando factura', percent: 5 },
@@ -793,6 +867,14 @@
{ label: 'Confirmando cambios', percent: 95 }
];
+ const invoiceCoveSteps = [
+ { label: 'Validando factura para COVE', percent: 10 },
+ { label: 'Validando configuración VU', percent: 30 },
+ { label: 'Validando emisor/destinatario', percent: 50 },
+ { label: 'Validando mercancías para COVE', percent: 80 },
+ { label: 'Finalizando validaciones de COVE', percent: 95 }
+ ];
+
// Opciones de tipo de operación para el filtro
const operationTypeOptions = [
{ value: '', label: 'Todas' },
@@ -829,6 +911,7 @@
showProgressDialog = false;
currentTaskId = null;
currentStatusFunction = null;
+ progressDialogSteps = null;
}
// --- AQUÍ PASAMOS LA FUNCIÓN DE DESCARGA A LAS COLUMNAS ---
@@ -991,18 +1074,22 @@
onClose={closeProgressDialog}
title={progressDialogTitle}
steps={
- progressDialogTitle === 'Procesando factura'
- ? invoiceProcessSteps
- : progressDialogTitle === 'Des-actualizando factura'
- ? invoiceRevertSteps
- : []
+ progressDialogSteps
+ ? progressDialogSteps
+ : progressDialogTitle === 'Procesando factura'
+ ? invoiceProcessSteps
+ : progressDialogTitle === 'Des-actualizando factura'
+ ? invoiceRevertSteps
+ : []
}
completeMessage={
progressDialogTitle === 'Procesando factura'
? 'Factura procesada correctamente'
: progressDialogTitle === 'Des-actualizando factura'
? 'Factura des-actualizada correctamente'
- : 'Listo para descargar'
+ : progressDialogTitle === 'Validando datos para COVE'
+ ? 'Validación de COVE completada'
+ : 'Proceso completado'
}
/>
@@ -1137,7 +1224,7 @@
Transferencia Electrónica
- toast.info('Interface VU - Próximamente')}>
+
Interface VU
@@ -1232,6 +1319,7 @@
Eliminar
+