diff --git a/frontend/src/lib/config/shortcuts.ts b/frontend/src/lib/config/shortcuts.ts
index cb2ab56a..16249465 100644
--- a/frontend/src/lib/config/shortcuts.ts
+++ b/frontend/src/lib/config/shortcuts.ts
@@ -18,6 +18,10 @@ export const GLOBAL_NAV = {
'r': '/dashboard/reference_data/pedimento_regimens',
'e': '/dashboard/reference_data/customs_sections#',
'd': '/dashboard/reference_data/customs_sections',
+
+ // Invoices
+ 'i': '/dashboard/invoices',
+
// Common Actions
'b': 'SEARCH_FOCUS', // Special case for generic focus
'h': '/', // Home
diff --git a/frontend/src/lib/config/shortcuts/goods-edit-shortcuts.ts b/frontend/src/lib/config/shortcuts/goods-edit-shortcuts.ts
index 572ef494..98044a3f 100644
--- a/frontend/src/lib/config/shortcuts/goods-edit-shortcuts.ts
+++ b/frontend/src/lib/config/shortcuts/goods-edit-shortcuts.ts
@@ -6,12 +6,9 @@ export const obtenerAtajosFormularioMercancia = (acciones: {
manejarRegresar: () => void;
}): ShortcutDef[] => [
// Pestañas
- { key: 'Alt+G', description: 'Tab General', action: () => acciones.cambiarPestana('general') },
- { key: 'Alt+I', description: 'Tab Imágenes', action: () => acciones.cambiarPestana('cont1') },
- { key: 'Alt+E', description: 'Tab Exportación', action: () => acciones.cambiarPestana('cont2') },
- { key: 'Alt+O', description: 'Tab Opciones', action: () => acciones.cambiarPestana('opciones') },
- { key: 'Alt+S', description: 'Tab Sanitarias', action: () => acciones.cambiarPestana('opcionales2') },
- { key: 'Alt+X', description: 'Tab Otros', action: () => acciones.cambiarPestana('otros') },
+ { key: 'Alt+Digit1', description: 'Tab General', action: () => acciones.cambiarPestana('general') },
+ { key: 'Alt+Digit2', description: 'Tab Imágenes', action: () => acciones.cambiarPestana('cont1') },
+ { key: 'Alt+Digit3', description: 'Tab Exportación', action: () => acciones.cambiarPestana('cont2') },
// Acciones Globales
{ key: 'Ctrl+S', description: 'Guardar cambios', action: acciones.manejarGuardar },
diff --git a/frontend/src/lib/config/shortcuts/goods-shortcuts.ts.bak b/frontend/src/lib/config/shortcuts/goods-shortcuts.ts.bak
deleted file mode 100644
index 5ef7e93e..00000000
--- a/frontend/src/lib/config/shortcuts/goods-shortcuts.ts.bak
+++ /dev/null
@@ -1,73 +0,0 @@
-import type { ShortcutDef } from '../../stores/shortcut-store';
-
-export const obtenerAtajosListaPartes = (acciones: {
- manejarNuevo: () => void;
- manejarActualizar: () => void;
- manejarBorrar: () => void;
-}): ShortcutDef[] => [
- {
- key: 'Alt+Shift+N',
- description: 'Nueva Parte',
- action: acciones.manejarNuevo
- },
- {
- key: 'Alt+Shift+R',
- description: 'Actualizar Lista',
- action: acciones.manejarActualizar
- },
- {
- key: 'Alt+Shift+D',
- description: 'Borrar Seleccionado',
- action: acciones.manejarBorrar
- }
- ];
-
-export const obtenerAtajosListaClasesActivoFijo = (acciones: {
- manejarNuevo: () => void;
- manejarActualizar: () => void;
- manejarBorrar: () => void;
-}): ShortcutDef[] => [
- {
- key: 'Alt+Shift+N',
- description: 'Nueva Clase',
- action: acciones.manejarNuevo
- },
- {
- key: 'Alt+Shift+R',
- description: 'Actualizar Lista',
- action: acciones.manejarActualizar
- },
- {
- key: 'Alt+Shift+D',
- description: 'Borrar Seleccionado',
- action: acciones.manejarBorrar
- }
- ];
-
-export const obtenerAtajosFormularioParte = (acciones: {
- cambiarPestana: (pestana: string) => void;
- manejarGuardar: () => void;
- manejarCancelar: () => void;
- esActivoFijo: boolean;
-}): ShortcutDef[] => {
- const common = [
- { key: 'Alt+Digit1', description: 'Pest. General', action: () => acciones.cambiarPestana('general') },
- { key: 'Ctrl+S', description: 'Guardar cambios', action: acciones.manejarGuardar },
- { key: 'Escape', description: 'Cancelar / Regresar', action: acciones.manejarCancelar }
- ];
-
- if (acciones.esActivoFijo) {
- return [
- ...common,
- { key: 'Alt+Digit2', description: 'Pest. Continuación 1', action: () => acciones.cambiarPestana('cont1') },
- { key: 'Alt+Digit3', description: 'Pest. Continuación 2', action: () => acciones.cambiarPestana('cont2') }
- ];
- }
-
- return [
- ...common,
- { key: 'Alt+Digit2', description: 'Pest. Opciones', action: () => acciones.cambiarPestana('opciones') },
- { key: 'Alt+Digit3', description: 'Pest. Opcionales 2', action: () => acciones.cambiarPestana('opcionales2') },
- { key: 'Alt+Digit4', description: 'Pest. Otros', action: () => acciones.cambiarPestana('otros') }
- ];
-};
diff --git a/frontend/src/lib/config/shortcuts/invoice-edit-shortcuts.ts b/frontend/src/lib/config/shortcuts/invoice-edit-shortcuts.ts
new file mode 100644
index 00000000..2f7c71c5
--- /dev/null
+++ b/frontend/src/lib/config/shortcuts/invoice-edit-shortcuts.ts
@@ -0,0 +1,15 @@
+import type { ShortcutDef } from '$lib/stores/shortcut-store';
+
+export const obtenerAtajosEdicionFactura = (acciones: {
+ cambiarPestana: (pestana: string) => void;
+ manejarGuardar: () => void;
+ manejarRegresar: () => void;
+}): ShortcutDef[] => [
+ { key: 'Alt+Q', description: 'Tab General', action: () => acciones.cambiarPestana('general') },
+ { key: 'Alt+O', description: 'Tab Observ.', action: () => acciones.cambiarPestana('observations') },
+ { key: 'Alt+A', description: 'Tab Partidas (Artículos)', action: () => acciones.cambiarPestana('items') },
+ { key: 'Alt+X', description: 'Tab Otros', action: () => acciones.cambiarPestana('others') },
+ { key: 'Alt+K', description: 'Tab Cont.', action: () => acciones.cambiarPestana('continuation') },
+ { key: 'Ctrl+S', description: 'Guardar cambios', action: acciones.manejarGuardar },
+ { key: 'Escape', description: 'Regresar / Cancelar', action: acciones.manejarRegresar }
+ ];
diff --git a/frontend/src/lib/config/shortcuts/invoice-list-shortcuts.ts b/frontend/src/lib/config/shortcuts/invoice-list-shortcuts.ts
new file mode 100644
index 00000000..b9f9778e
--- /dev/null
+++ b/frontend/src/lib/config/shortcuts/invoice-list-shortcuts.ts
@@ -0,0 +1,48 @@
+import type { ShortcutDef } from '$lib/stores/shortcut-store';
+
+export const obtenerAtajosListaFacturas = (acciones: {
+ manejarCrear: () => void;
+ manejarActualizar: () => void;
+ manejarEditar: () => void;
+ manejarDescargarPdf: () => void;
+ manejarDescargarConsolidado: () => void;
+ // Filtros de navegación
+ irTemporal: () => void;
+ irDefinitiva: () => void;
+ irNacional: () => void;
+ irCambioRegimen: () => void;
+ irExportacion: () => void;
+ irReparacion: () => void;
+}): ShortcutDef[] => [
+ { key: 'Alt+V', description: 'Ver Temporales', action: acciones.irTemporal },
+ { key: 'Alt+F', description: 'Ver Definitivas', action: acciones.irDefinitiva },
+ { key: 'Alt+N', description: 'Ver Nacionales', action: acciones.irNacional },
+ { key: 'Alt+Z', description: 'Ver Cambio Régimen', action: acciones.irCambioRegimen },
+ { key: 'Alt+L', description: 'Ver Exportaciones', action: acciones.irExportacion },
+ { key: 'Alt+Y', description: 'Ver Reparaciones', action: acciones.irReparacion },
+ {
+ key: 'Alt+Shift+N',
+ description: 'Nueva Factura',
+ action: acciones.manejarCrear
+ },
+ {
+ key: 'Alt+Shift+R',
+ description: 'Actualizar Lista',
+ action: acciones.manejarActualizar
+ },
+ {
+ key: 'Alt+Shift+E',
+ description: 'Editar Seleccionada',
+ action: acciones.manejarEditar
+ },
+ {
+ key: 'Alt+Shift+P',
+ description: 'Descargar PDF',
+ action: acciones.manejarDescargarPdf
+ },
+ {
+ key: 'Alt+Shift+C',
+ description: 'Descargar Consolidado',
+ action: acciones.manejarDescargarConsolidado
+ }
+ ];
diff --git a/frontend/src/routes/dashboard/invoices/+page.svelte b/frontend/src/routes/dashboard/invoices/+page.svelte
index 61138a73..5835dbcd 100644
--- a/frontend/src/routes/dashboard/invoices/+page.svelte
+++ b/frontend/src/routes/dashboard/invoices/+page.svelte
@@ -1,634 +1,687 @@
-
-
-
Facturas
-
- Gestiona las facturas del sistema
-
-
-
-
+
+
+
Facturas
+
Gestiona las facturas del sistema
+
+
+
-
-
- Filtros
- Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente)
-
-
-
-
-
-
-
+
+
+ Filtros
+ Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente)
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
- {#if error}
-
-
- Error
- {error}
-
-
- {/if}
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
-
-
-
-
- Listado de Facturas
-
- Mostrando {allItems.length} de {totalItems} registros
-
-
-
-
-
-
-
-
-
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
\ No newline at end of file
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte b/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte
index 9567cb94..a28a8c3f 100644
--- a/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte
+++ b/frontend/src/routes/dashboard/invoices/edit/[id]/+page.svelte
@@ -2,29 +2,29 @@
import { onMount } from 'svelte';
import { browser } from '$app/environment';
import { goto } from '$app/navigation';
- import { page } from '$app/stores';
+ import { page } from '$app/stores';
import * as Tabs from '$lib/components/ui/tabs';
import { Button } from '$lib/components/ui/button';
import { Badge } from '$lib/components/ui/badge';
import { Separator } from '$lib/components/ui/separator';
import { toast } from 'svelte-sonner';
- import {
- ArrowLeft,
- FileText,
- DollarSign,
- Truck,
- Package,
+ import {
+ ArrowLeft,
+ FileText,
+ DollarSign,
+ Truck,
+ Package,
Eye,
- LoaderCircle,
- Save
- } from 'lucide-svelte';
-
+ LoaderCircle,
+ Save
+ } from 'lucide-svelte';
+
// Importar los componentes de cada pestaña
import GeneralTabForm from '$lib/components/dashboard/invoices/edit/general-tab-form.svelte';
import ObservationsTabForm from '$lib/components/dashboard/invoices/edit/observations-tab-form.svelte';
import ItemsTabForm from '$lib/components/dashboard/invoices/edit/items/items-tab-form.svelte';
import OthersTabForm from '$lib/components/dashboard/invoices/edit/others-tab-form.svelte';
- import InvoiceTopFields from '$lib/components/dashboard/invoices/edit/invoice-top-fields.svelte';
+ import InvoiceTopFields from '$lib/components/dashboard/invoices/edit/invoice-top-fields.svelte';
import ContinuationTabForm from '$lib/components/dashboard/invoices/edit/continuation-tab-form.svelte';
// Importar la API de facturas
@@ -35,11 +35,13 @@
import { getExchangeRateByDate } from '$lib/api/dashboard/a76/exchange-rate';
import { getExchangeRates } from '$lib/api/dashboard/a76/general_catalogs/exchange-rate';
import ExchangeRateDialog from '$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte';
-
+ import { useShortcuts } from '$lib/hooks/use-shortcuts';
+ import { obtenerAtajosEdicionFactura } from '$lib/config/shortcuts/invoice-edit-shortcuts';
+
// Cargar companyStore solo en el cliente - no usamos sidebar en esta página
let companyStore: any = $state(undefined);
let mounted = $state(false);
-
+
onMount(async () => {
try {
const companyStoreModule = await import('$lib/stores/company.svelte');
@@ -85,7 +87,7 @@
let activeTab = $state('general');
let saving = $state(false);
-
+
// ID de la factura
let invoiceId = $state(data.invoiceId ?? null);
@@ -103,10 +105,12 @@
let othersExists = $state(false);
let continuationExists = $state(false);
- let calculatedExchangeRate = $state(data.invoice?.financials?.exchange_rate ?? null);
-
+ let calculatedExchangeRate = $state(
+ data.invoice?.financials?.exchange_rate ?? null
+ );
+
let showExchangeRateDialog = $state(false);
- let missingExchangeRateDate = $state("");
+ let missingExchangeRateDate = $state('');
async function checkExchangeRate(date: string): Promise {
if (!date || !companyStore?.activeCompany?.id) return true;
@@ -120,10 +124,10 @@
date: date,
page_size: 1
});
-
+
const actualResponse = response as any;
const items = actualResponse.data?.items || [];
-
+
if (items.length === 0) {
console.log('No exchange rate found for', date);
missingExchangeRateDate = date;
@@ -139,7 +143,7 @@
// Por seguridad, abrimos modal.
missingExchangeRateDate = date;
showExchangeRateDialog = true;
- return false;
+ return false;
}
}
@@ -147,14 +151,14 @@
$effect(() => {
if (mounted && companyStore?.activeCompany?.id && InvoiceTopFieldsFormData?.invoice_date) {
getExchangeRateByDate(InvoiceTopFieldsFormData.invoice_date, companyStore.activeCompany.id)
- .then(rate => {
+ .then((rate) => {
if (rate) {
- calculatedExchangeRate = rate.value;
+ calculatedExchangeRate = rate.value;
} else {
calculatedExchangeRate = 0;
}
})
- .catch(err => console.error('Error auto-updating exchange rate:', err));
+ .catch((err) => console.error('Error auto-updating exchange rate:', err));
}
});
@@ -173,7 +177,7 @@
try {
// Validar ID si es edición
if (!data.isCreate && !invoiceId) {
- toast.error("Error interrrno: No se encuentra el ID de la factura para actualizar.");
+ toast.error('Error interrrno: No se encuentra el ID de la factura para actualizar.');
saving = false;
return;
}
@@ -199,7 +203,7 @@
othersFormData,
continuationFormData
}
- });
+ });
if (!result.success) {
// Crear un error con validationErrors si existen
@@ -212,8 +216,8 @@
toast.success('Todos los cambios se guardaron correctamente');
} catch (e) {
- console.error('Error saving all:', e);
-
+ console.error('Error saving all:', e);
+
if (e instanceof Error && e.message.includes('401')) {
toast.error('Sesión expirada. Recargando página...');
setTimeout(() => {
@@ -221,26 +225,34 @@
}, 1500);
} else {
const errorMessage = e instanceof Error ? e.message : 'Error al guardar los cambios';
-
+
// Intercept exchange rate error
- if (errorMessage.includes('No existe un Tipo de Cambio registrado') || errorMessage.includes('financials.exchange_rate')) {
- console.log("Interceptor: Exchange rate missing error caught (Invoice Page).");
-
+ if (
+ errorMessage.includes('No existe un Tipo de Cambio registrado') ||
+ errorMessage.includes('financials.exchange_rate')
+ ) {
+ console.log('Interceptor: Exchange rate missing error caught (Invoice Page).');
+
const dateMatch = errorMessage.match(/(\d{4}-\d{2}-\d{2})/);
- const missingDate = dateMatch ? dateMatch[0] : (InvoiceTopFieldsFormData?.invoice_date || "");
-
+ const missingDate = dateMatch
+ ? dateMatch[0]
+ : InvoiceTopFieldsFormData?.invoice_date || '';
+
missingExchangeRateDate = missingDate;
showExchangeRateDialog = true;
return;
}
// Si hay errores de validación, mostrarlos en detalle
- if (e && typeof e === 'object' && 'validationErrors' in e && Array.isArray((e as any).validationErrors)) {
- const validationErrors = (e as any).validationErrors;
- const errorList = validationErrors.map((err: any) =>
- `• ${err.message}`
- ).join('\n');
-
+ if (
+ e &&
+ typeof e === 'object' &&
+ 'validationErrors' in e &&
+ Array.isArray((e as any).validationErrors)
+ ) {
+ const validationErrors = (e as any).validationErrors;
+ const errorList = validationErrors.map((err: any) => `• ${err.message}`).join('\n');
+
toast.error(errorMessage, {
description: errorList
});
@@ -254,6 +266,15 @@
saving = false;
}
}
+
+ useShortcuts(
+ 'Invoice Edit',
+ obtenerAtajosEdicionFactura({
+ cambiarPestana: (pestana) => (activeTab = pestana),
+ manejarGuardar: handleSaveAll,
+ manejarRegresar: handleBack
+ })
+ );
@@ -267,7 +288,9 @@
{#if data.isCreate}
{@const invoiceType = generalFormData?.invoice_type || data.filters?.invoice_type}
- {@const invoiceTypeInfo = invoiceType ? data.invoiceTypes?.find(t => t.key === invoiceType) : null}
+ {@const invoiceTypeInfo = invoiceType
+ ? data.invoiceTypes?.find((t) => t.key === invoiceType)
+ : null}
Nueva Factura
{#if invoiceTypeInfo}
@@ -301,18 +324,18 @@
-
-
-
+
-
-
-
-
+
- {
// Actualizar el tipo de cambio mostrado
if (InvoiceTopFieldsFormData.invoice_date && companyStore?.activeCompany?.id) {
- getExchangeRateByDate(InvoiceTopFieldsFormData.invoice_date, companyStore.activeCompany.id)
- .then(rate => {
+ getExchangeRateByDate(
+ InvoiceTopFieldsFormData.invoice_date,
+ companyStore.activeCompany.id
+ ).then((rate) => {
if (rate) calculatedExchangeRate = rate.value;
});
}
}}
/>
-