diff --git a/backend/api/v1/modules/a76/invoices/routes.py b/backend/api/v1/modules/a76/invoices/routes.py
index a2160a6b..e81706a1 100644
--- a/backend/api/v1/modules/a76/invoices/routes.py
+++ b/backend/api/v1/modules/a76/invoices/routes.py
@@ -150,6 +150,7 @@ def get_invoice_details(
status_code=201,
summary="Add sales detail to an invoice",
)
+
def create_invoice_detail(
invoice_id: int = Path(..., description="Invoice ID"),
detail_data: schemas.InvoiceSalesDetailsCreate = ...,
diff --git a/frontend/src/lib/components/dashboard/invoices/data-table-actions.svelte b/frontend/src/lib/components/dashboard/invoices/data-table-actions.svelte
index 13367343..4b5f2e65 100644
--- a/frontend/src/lib/components/dashboard/invoices/data-table-actions.svelte
+++ b/frontend/src/lib/components/dashboard/invoices/data-table-actions.svelte
@@ -3,6 +3,7 @@
import { Button } from '$lib/components/ui/button';
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
import { Ellipsis, Eye, Pencil, Trash2 } from 'lucide-svelte';
+ import { goto } from '$app/navigation';
interface Props {
invoice: Invoice;
@@ -14,13 +15,14 @@
window.dispatchEvent(new CustomEvent('invoiceView', { detail: invoice }));
}
- function dispatchEdit() {
- window.dispatchEvent(new CustomEvent('invoiceEdit', { detail: invoice }));
- }
-
function dispatchDelete() {
window.dispatchEvent(new CustomEvent('invoiceDelete', { detail: invoice }));
}
+
+ function dispatchEdit() {
+ window.dispatchEvent(new CustomEvent('invoiceEdit', { detail: invoice }));
+ }
+
@@ -35,18 +37,21 @@
Acciones
+
Ver Detalles
+
Editar
+
Eliminar
-
+
\ No newline at end of file
diff --git a/frontend/src/lib/components/sidebar/modules.ts b/frontend/src/lib/components/sidebar/modules.ts
index cbc38c14..328f53dc 100644
--- a/frontend/src/lib/components/sidebar/modules.ts
+++ b/frontend/src/lib/components/sidebar/modules.ts
@@ -323,19 +323,23 @@ export function getSidebarData(): SidebarData {
items: [
{
title: m["sidebar.import_invoices.temporary"](),
- url: "/dashboard/invoices?operation_type=imp&invoice_type=TEM",
+ //url: "/dashboard/invoices?operation_type=imp&invoice_type=TEM"
+ url: "/dashboard/invoices/importacion/temporal",
},
{
title: m["sidebar.import_invoices.definitive"](),
- url: "/dashboard/invoices?operation_type=imp&invoice_type=DEF",
+ //url: "/dashboard/invoices?operation_type=imp&invoice_type=DEF",
+ url: "/dashboard/invoices/importacion/definitiva",
},
{
title: m["sidebar.import_invoices.mexican_purchases"](),
- url: "/dashboard/invoices?operation_type=imp&invoice_type=MEX",
+ //url: "/dashboard/invoices?operation_type=imp&invoice_type=MEX",
+ url: "/dashboard/invoices/importacion/compras_mexicanas",
},
{
title: m["sidebar.import_invoices.regime_change"](),
- url: "/dashboard/invoices?operation_type=imp&invoice_type=CR",
+ //url: "/dashboard/invoices?operation_type=imp&invoice_type=CR",
+ url: "/dashboard/invoices/importacion/cambio_regimen",
}
],
},
@@ -346,11 +350,13 @@ export function getSidebarData(): SidebarData {
items: [
{
title: m["sidebar.export_invoices.exportation"](),
- url: "/dashboard/invoices?operation_type=exp",
+ //url: "/dashboard/invoices?operation_type=exp",
+ url: "/dashboard/invoices/exportacion/exportacion",
},
{
title: m["sidebar.export_invoices.repair"](),
- url: "/dashboard/invoices?operation_type=exp&invoice_type=REPAR",
+ //url: "/dashboard/invoices?operation_type=exp&invoice_type=REPAR",
+ url: "/dashboard/invoices/exportacion/reparacion",
},
],
},
diff --git a/frontend/src/routes/dashboard/invoices/+page.server.ts b/frontend/src/routes/dashboard/invoices/exportacion/exportacion/+page.server.ts
similarity index 94%
rename from frontend/src/routes/dashboard/invoices/+page.server.ts
rename to frontend/src/routes/dashboard/invoices/exportacion/exportacion/+page.server.ts
index 4e3b8795..54f3eb0b 100644
--- a/frontend/src/routes/dashboard/invoices/+page.server.ts
+++ b/frontend/src/routes/dashboard/invoices/exportacion/exportacion/+page.server.ts
@@ -1,4 +1,4 @@
-import type { PageServerLoad } from './$types';
+import type { PageServerLoad } from '../$types';
import { redirect } from '@sveltejs/kit';
import {
getAuthTokens,
@@ -43,8 +43,8 @@ export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
}
// Obtener filtro de tipo de operación
- const operationType = url.searchParams.get('operation_type');
- const invoiceType = url.searchParams.get('invoice_type');
+ const operationType = 'exp'
+ const invoiceType = 'exp'
// Construir parámetros de consulta
const params = new URLSearchParams({
diff --git a/frontend/src/routes/dashboard/invoices/+page.svelte b/frontend/src/routes/dashboard/invoices/exportacion/exportacion/+page.svelte
similarity index 100%
rename from frontend/src/routes/dashboard/invoices/+page.svelte
rename to frontend/src/routes/dashboard/invoices/exportacion/exportacion/+page.svelte
diff --git a/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.server.ts b/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.server.ts
new file mode 100644
index 00000000..4feb09c2
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.server.ts
@@ -0,0 +1,114 @@
+import type { PageServerLoad } from '../$types';
+import { redirect } from '@sveltejs/kit';
+import {
+ getAuthTokens,
+ authenticatedFetch
+} from '$lib/server/api';
+
+export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
+ // Esperar a que el layout padre valide/refresque el token
+ const parentData = await parent();
+
+ // Verificar autenticación
+ const { accessToken } = getAuthTokens(cookies);
+
+ if (!accessToken) {
+ throw redirect(302, '/login');
+ }
+
+ try {
+ // Obtener company_id de múltiples fuentes (en orden de prioridad):
+ // 1. URL query param (permite cambiar vía navegación)
+ // 2. Cookie active_company_id (setted por el team-switcher)
+ // 3. Primera compañía del usuario (fallback)
+ const companyIdParam = url.searchParams.get('company_id');
+ const cookieCompanyId = cookies.get('active_company_id');
+
+ const companyId = companyIdParam
+ ? parseInt(companyIdParam)
+ : cookieCompanyId
+ ? parseInt(cookieCompanyId)
+ : parentData.companies?.[0]?.id;
+
+ // Si aún no hay companyId, mostrar error
+ if (!companyId) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'No se encontró una compañía seleccionada',
+ companies: parentData.companies || []
+ };
+ }
+
+ // Obtener filtro de tipo de operación
+ const operationType = 'exp'
+ const invoiceType = 'REPAR'
+
+ // Construir parámetros de consulta
+ const params = new URLSearchParams({
+ company_id: companyId.toString(),
+ page: '1',
+ page_size: '50'
+ });
+
+ // Agregar filtro de tipo si existe y no es 'all'
+ if (operationType && operationType !== 'all') {
+ params.append('operation_type', operationType);
+ }
+
+ // Agregar filtro de invoice_type si existe
+ if (invoiceType) {
+ params.append('invoice_type', invoiceType);
+ }
+
+ // Usar authenticatedFetch para manejar automáticamente el refresh de tokens
+ const response = await authenticatedFetch(
+ `v1/a76/invoices?${params.toString()}`,
+ {},
+ cookies,
+ fetch,
+ '/login'
+ );
+
+ if (!response.ok) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ }
+
+ const data = await response.json();
+
+ return {
+ items: data.items || [],
+ total: data.total || 0,
+ page: data.page || 1,
+ page_size: data.page_size || 50,
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ } catch (error) {
+ console.error('Error loading invoices:', error);
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ operationType: 'all',
+ invoiceType: null
+ };
+ }
+};
diff --git a/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.svelte b/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.svelte
new file mode 100644
index 00000000..0a837d10
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/exportacion/reparacion/+page.svelte
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
Facturas
+
+ Gestiona las facturas de importación y exportación
+
+
+
+
+
+
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
+
+
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+ {#if companyStore.activeCompany}
+ - Compañía: {companyStore.activeCompany.name}
+ {/if}
+
+
+
+
+
+ {selectedType === 'all' ? 'Todas' : selectedType === 'imp' ? 'Importación' : 'Exportación'}
+
+
+ Todas
+ Importación
+ Exportación
+
+
+
+ {#if selectedType !== 'all' && availableInvoiceTypes.length > 0}
+
+
+
+ {#if loadingInvoiceTypes}
+ Cargando...
+ {:else if selectedInvoiceType}
+ {(() => {
+ const found = availableInvoiceTypes.find(t => t.key === selectedInvoiceType);
+ return found ? `${found.key} - ${found.description}` : selectedInvoiceType;
+ })()}
+ {:else}
+ Todos los tipos
+ {/if}
+
+
+
+ Todos los tipos
+ {#each availableInvoiceTypes as invType}
+
+
+ {invType.key} - {invType.description}
+
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.server.ts b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.server.ts
new file mode 100644
index 00000000..fb3159d9
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.server.ts
@@ -0,0 +1,114 @@
+import type { PageServerLoad } from '../../$types';
+import { redirect } from '@sveltejs/kit';
+import {
+ getAuthTokens,
+ authenticatedFetch
+} from '$lib/server/api';
+
+export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
+ // Esperar a que el layout padre valide/refresque el token
+ const parentData = await parent();
+
+ // Verificar autenticación
+ const { accessToken } = getAuthTokens(cookies);
+
+ if (!accessToken) {
+ throw redirect(302, '/login');
+ }
+
+ try {
+ // Obtener company_id de múltiples fuentes (en orden de prioridad):
+ // 1. URL query param (permite cambiar vía navegación)
+ // 2. Cookie active_company_id (setted por el team-switcher)
+ // 3. Primera compañía del usuario (fallback)
+ const companyIdParam = url.searchParams.get('company_id');
+ const cookieCompanyId = cookies.get('active_company_id');
+
+ const companyId = companyIdParam
+ ? parseInt(companyIdParam)
+ : cookieCompanyId
+ ? parseInt(cookieCompanyId)
+ : parentData.companies?.[0]?.id;
+
+ // Si aún no hay companyId, mostrar error
+ if (!companyId) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'No se encontró una compañía seleccionada',
+ companies: parentData.companies || []
+ };
+ }
+
+ // Obtener filtro de tipo de operación
+ const operationType = 'imp'
+ const invoiceType = 'CR'
+
+ // Construir parámetros de consulta
+ const params = new URLSearchParams({
+ company_id: companyId.toString(),
+ page: '1',
+ page_size: '50'
+ });
+
+ // Agregar filtro de tipo si existe y no es 'all'
+ if (operationType && operationType !== 'all') {
+ params.append('operation_type', operationType);
+ }
+
+ // Agregar filtro de invoice_type si existe
+ if (invoiceType) {
+ params.append('invoice_type', invoiceType);
+ }
+
+ // Usar authenticatedFetch para manejar automáticamente el refresh de tokens
+ const response = await authenticatedFetch(
+ `v1/a76/invoices?${params.toString()}`,
+ {},
+ cookies,
+ fetch,
+ '/login'
+ );
+
+ if (!response.ok) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ }
+
+ const data = await response.json();
+
+ return {
+ items: data.items || [],
+ total: data.total || 0,
+ page: data.page || 1,
+ page_size: data.page_size || 50,
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ } catch (error) {
+ console.error('Error loading invoices:', error);
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ operationType: 'all',
+ invoiceType: null
+ };
+ }
+};
diff --git a/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.svelte
new file mode 100644
index 00000000..c0d0b0cf
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/+page.svelte
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
Facturas
+
+ Gestiona las facturas de importación y exportación
+
+
+
+
+
+
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
+
+
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+ {#if companyStore.activeCompany}
+ - Compañía: {companyStore.activeCompany.name}
+ {/if}
+
+
+
+
+
+ {selectedType === 'all' ? 'Todas' : selectedType === 'imp' ? 'Importación' : 'Exportación'}
+
+
+ Todas
+ Importación
+ Exportación
+
+
+
+ {#if selectedType !== 'all' && availableInvoiceTypes.length > 0}
+
+
+
+ {#if loadingInvoiceTypes}
+ Cargando...
+ {:else if selectedInvoiceType}
+ {(() => {
+ const found = availableInvoiceTypes.find(t => t.key === selectedInvoiceType);
+ return found ? `${found.key} - ${found.description}` : selectedInvoiceType;
+ })()}
+ {:else}
+ Todos los tipos
+ {/if}
+
+
+
+ Todos los tipos
+ {#each availableInvoiceTypes as invType}
+
+
+ {invType.key} - {invType.description}
+
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/new/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/new/+page.svelte
new file mode 100644
index 00000000..76f88411
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/cambio_regimen/new/+page.svelte
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
Nueva Factura Cambio Regimen
+
Ingresa los datos para registrar la importación.
+
+
+
+ {#if error}
+
+ ⚠️ {error}
+
+ {/if}
+
+
+
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.server.ts b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.server.ts
new file mode 100644
index 00000000..a8794bcf
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.server.ts
@@ -0,0 +1,114 @@
+import type { PageServerLoad } from '../../$types';
+import { redirect } from '@sveltejs/kit';
+import {
+ getAuthTokens,
+ authenticatedFetch
+} from '$lib/server/api';
+
+export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
+ // Esperar a que el layout padre valide/refresque el token
+ const parentData = await parent();
+
+ // Verificar autenticación
+ const { accessToken } = getAuthTokens(cookies);
+
+ if (!accessToken) {
+ throw redirect(302, '/login');
+ }
+
+ try {
+ // Obtener company_id de múltiples fuentes (en orden de prioridad):
+ // 1. URL query param (permite cambiar vía navegación)
+ // 2. Cookie active_company_id (setted por el team-switcher)
+ // 3. Primera compañía del usuario (fallback)
+ const companyIdParam = url.searchParams.get('company_id');
+ const cookieCompanyId = cookies.get('active_company_id');
+
+ const companyId = companyIdParam
+ ? parseInt(companyIdParam)
+ : cookieCompanyId
+ ? parseInt(cookieCompanyId)
+ : parentData.companies?.[0]?.id;
+
+ // Si aún no hay companyId, mostrar error
+ if (!companyId) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'No se encontró una compañía seleccionada',
+ companies: parentData.companies || []
+ };
+ }
+
+ // Obtener filtro de tipo de operación
+ const operationType = 'imp'
+ const invoiceType = 'MEX'
+
+ // Construir parámetros de consulta
+ const params = new URLSearchParams({
+ company_id: companyId.toString(),
+ page: '1',
+ page_size: '50'
+ });
+
+ // Agregar filtro de tipo si existe y no es 'all'
+ if (operationType && operationType !== 'all') {
+ params.append('operation_type', operationType);
+ }
+
+ // Agregar filtro de invoice_type si existe
+ if (invoiceType) {
+ params.append('invoice_type', invoiceType);
+ }
+
+ // Usar authenticatedFetch para manejar automáticamente el refresh de tokens
+ const response = await authenticatedFetch(
+ `v1/a76/invoices?${params.toString()}`,
+ {},
+ cookies,
+ fetch,
+ '/login'
+ );
+
+ if (!response.ok) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ }
+
+ const data = await response.json();
+
+ return {
+ items: data.items || [],
+ total: data.total || 0,
+ page: data.page || 1,
+ page_size: data.page_size || 50,
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ } catch (error) {
+ console.error('Error loading invoices:', error);
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ operationType: 'all',
+ invoiceType: null
+ };
+ }
+};
diff --git a/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.svelte
new file mode 100644
index 00000000..87cdb207
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/+page.svelte
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
Facturas
+
+ Gestiona las facturas de importación y exportación
+
+
+
+
+
+
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
+
+
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+ {#if companyStore.activeCompany}
+ - Compañía: {companyStore.activeCompany.name}
+ {/if}
+
+
+
+
+
+ {selectedType === 'all' ? 'Todas' : selectedType === 'imp' ? 'Importación' : 'Exportación'}
+
+
+ Todas
+ Importación
+ Exportación
+
+
+
+ {#if selectedType !== 'all' && availableInvoiceTypes.length > 0}
+
+
+
+ {#if loadingInvoiceTypes}
+ Cargando...
+ {:else if selectedInvoiceType}
+ {(() => {
+ const found = availableInvoiceTypes.find(t => t.key === selectedInvoiceType);
+ return found ? `${found.key} - ${found.description}` : selectedInvoiceType;
+ })()}
+ {:else}
+ Todos los tipos
+ {/if}
+
+
+
+ Todos los tipos
+ {#each availableInvoiceTypes as invType}
+
+
+ {invType.key} - {invType.description}
+
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/new/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/new/+page.svelte
new file mode 100644
index 00000000..488312d0
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/compras_mexicanas/new/+page.svelte
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
Nueva Factura
+
Ingresa los datos para registrar la importación.
+
+
+
+ {#if error}
+
+ ⚠️ {error}
+
+ {/if}
+
+
+
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.server.ts b/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.server.ts
new file mode 100644
index 00000000..d00d94fe
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.server.ts
@@ -0,0 +1,114 @@
+import type { PageServerLoad } from '../../$types';
+import { redirect } from '@sveltejs/kit';
+import {
+ getAuthTokens,
+ authenticatedFetch
+} from '$lib/server/api';
+
+export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
+ // Esperar a que el layout padre valide/refresque el token
+ const parentData = await parent();
+
+ // Verificar autenticación
+ const { accessToken } = getAuthTokens(cookies);
+
+ if (!accessToken) {
+ throw redirect(302, '/login');
+ }
+
+ try {
+ // Obtener company_id de múltiples fuentes (en orden de prioridad):
+ // 1. URL query param (permite cambiar vía navegación)
+ // 2. Cookie active_company_id (setted por el team-switcher)
+ // 3. Primera compañía del usuario (fallback)
+ const companyIdParam = url.searchParams.get('company_id');
+ const cookieCompanyId = cookies.get('active_company_id');
+
+ const companyId = companyIdParam
+ ? parseInt(companyIdParam)
+ : cookieCompanyId
+ ? parseInt(cookieCompanyId)
+ : parentData.companies?.[0]?.id;
+
+ // Si aún no hay companyId, mostrar error
+ if (!companyId) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'No se encontró una compañía seleccionada',
+ companies: parentData.companies || []
+ };
+ }
+
+ // Obtener filtro de tipo de operación
+ const operationType = 'imp'
+ const invoiceType = 'DEF'
+
+ // Construir parámetros de consulta
+ const params = new URLSearchParams({
+ company_id: companyId.toString(),
+ page: '1',
+ page_size: '50'
+ });
+
+ // Agregar filtro de tipo si existe y no es 'all'
+ if (operationType && operationType !== 'all') {
+ params.append('operation_type', operationType);
+ }
+
+ // Agregar filtro de invoice_type si existe
+ if (invoiceType) {
+ params.append('invoice_type', invoiceType);
+ }
+
+ // Usar authenticatedFetch para manejar automáticamente el refresh de tokens
+ const response = await authenticatedFetch(
+ `v1/a76/invoices?${params.toString()}`,
+ {},
+ cookies,
+ fetch,
+ '/login'
+ );
+
+ if (!response.ok) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ }
+
+ const data = await response.json();
+
+ return {
+ items: data.items || [],
+ total: data.total || 0,
+ page: data.page || 1,
+ page_size: data.page_size || 50,
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ } catch (error) {
+ console.error('Error loading invoices:', error);
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ operationType: 'all',
+ invoiceType: null
+ };
+ }
+};
diff --git a/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.svelte
new file mode 100644
index 00000000..17f52848
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/definitiva/+page.svelte
@@ -0,0 +1,390 @@
+
+
+
+
+
+
+
Facturas
+
+ Gestiona las facturas de importación y exportación
+
+
+
+
+
+
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
+
+
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+ {#if companyStore.activeCompany}
+ - Compañía: {companyStore.activeCompany.name}
+ {/if}
+
+
+
+
+
+ {selectedType === 'all' ? 'Todas' : selectedType === 'imp' ? 'Importación' : 'Exportación'}
+
+
+ Todas
+ Importación
+ Exportación
+
+
+
+ {#if selectedType !== 'all' && availableInvoiceTypes.length > 0}
+
+
+
+ {#if loadingInvoiceTypes}
+ Cargando...
+ {:else if selectedInvoiceType}
+ {(() => {
+ const found = availableInvoiceTypes.find(t => t.key === selectedInvoiceType);
+ return found ? `${found.key} - ${found.description}` : selectedInvoiceType;
+ })()}
+ {:else}
+ Todos los tipos
+ {/if}
+
+
+
+ Todos los tipos
+ {#each availableInvoiceTypes as invType}
+
+
+ {invType.key} - {invType.description}
+
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/importacion/definitiva/new/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/definitiva/new/+page.svelte
new file mode 100644
index 00000000..57e4fc64
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/definitiva/new/+page.svelte
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
Nueva Factura Definitiva
+
Ingresa los datos para registrar la importación.
+
+
+
+ {#if error}
+
+ ⚠️ {error}
+
+ {/if}
+
+
+
\ No newline at end of file
diff --git a/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.server.ts b/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.server.ts
new file mode 100644
index 00000000..83708beb
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.server.ts
@@ -0,0 +1,114 @@
+import type { PageServerLoad } from '../$types';
+import { redirect } from '@sveltejs/kit';
+import {
+ getAuthTokens,
+ authenticatedFetch
+} from '$lib/server/api';
+
+export const load: PageServerLoad = async ({ fetch, cookies, url, parent }) => {
+ // Esperar a que el layout padre valide/refresque el token
+ const parentData = await parent();
+
+ // Verificar autenticación
+ const { accessToken } = getAuthTokens(cookies);
+
+ if (!accessToken) {
+ throw redirect(302, '/login');
+ }
+
+ try {
+ // Obtener company_id de múltiples fuentes (en orden de prioridad):
+ // 1. URL query param (permite cambiar vía navegación)
+ // 2. Cookie active_company_id (setted por el team-switcher)
+ // 3. Primera compañía del usuario (fallback)
+ const companyIdParam = url.searchParams.get('company_id');
+ const cookieCompanyId = cookies.get('active_company_id');
+
+ const companyId = companyIdParam
+ ? parseInt(companyIdParam)
+ : cookieCompanyId
+ ? parseInt(cookieCompanyId)
+ : parentData.companies?.[0]?.id;
+
+ // Si aún no hay companyId, mostrar error
+ if (!companyId) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'No se encontró una compañía seleccionada',
+ companies: parentData.companies || []
+ };
+ }
+
+ // Obtener filtro de tipo de operación
+ const operationType = 'imp'
+ const invoiceType = 'TEM'
+
+ // Construir parámetros de consulta
+ const params = new URLSearchParams({
+ company_id: companyId.toString(),
+ page: '1',
+ page_size: '50'
+ });
+
+ // Agregar filtro de tipo si existe y no es 'all'
+ if (operationType && operationType !== 'all') {
+ params.append('operation_type', operationType);
+ }
+
+ // Agregar filtro de invoice_type si existe
+ if (invoiceType) {
+ params.append('invoice_type', invoiceType);
+ }
+
+ // Usar authenticatedFetch para manejar automáticamente el refresh de tokens
+ const response = await authenticatedFetch(
+ `v1/a76/invoices?${params.toString()}`,
+ {},
+ cookies,
+ fetch,
+ '/login'
+ );
+
+ if (!response.ok) {
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ }
+
+ const data = await response.json();
+
+ return {
+ items: data.items || [],
+ total: data.total || 0,
+ page: data.page || 1,
+ page_size: data.page_size || 50,
+ companies: parentData.companies || [],
+ currentCompanyId: companyId,
+ operationType: operationType || 'all',
+ invoiceType: invoiceType || null
+ };
+ } catch (error) {
+ console.error('Error loading invoices:', error);
+ return {
+ items: [],
+ total: 0,
+ page: 1,
+ page_size: 50,
+ error: 'Error al cargar facturas',
+ companies: parentData.companies || [],
+ operationType: 'all',
+ invoiceType: null
+ };
+ }
+};
diff --git a/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.svelte
new file mode 100644
index 00000000..d9a1ca87
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/temporal/+page.svelte
@@ -0,0 +1,382 @@
+
+
+
+
+
+
+
Facturas
+
+ Gestiona las facturas de importación y exportación
+
+
+
+
+
+
+ {#if error}
+
+
+ Error
+ {error}
+
+
+ {/if}
+
+
+
+
+
+
+ Listado de Facturas
+
+ Mostrando {allItems.length} de {totalItems} registros
+ {#if companyStore.activeCompany}
+ - Compañía: {companyStore.activeCompany.name}
+ {/if}
+
+
+
+
+
+ {selectedType === 'all' ? 'Todas' : selectedType === 'imp' ? 'Importación' : 'Exportación'}
+
+
+ Todas
+ Importación
+ Exportación
+
+
+
+ {#if selectedType !== 'all' && availableInvoiceTypes.length > 0}
+
+
+
+ {#if loadingInvoiceTypes}
+ Cargando...
+ {:else if selectedInvoiceType}
+ {(() => {
+ const found = availableInvoiceTypes.find(t => t.key === selectedInvoiceType);
+ return found ? `${found.key} - ${found.description}` : selectedInvoiceType;
+ })()}
+ {:else}
+ Todos los tipos
+ {/if}
+
+
+
+ Todos los tipos
+ {#each availableInvoiceTypes as invType}
+
+
+ {invType.key} - {invType.description}
+
+
+ {/each}
+
+
+ {/if}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/routes/dashboard/invoices/importacion/temporal/new/+page.svelte b/frontend/src/routes/dashboard/invoices/importacion/temporal/new/+page.svelte
new file mode 100644
index 00000000..fae289e8
--- /dev/null
+++ b/frontend/src/routes/dashboard/invoices/importacion/temporal/new/+page.svelte
@@ -0,0 +1,320 @@
+
+
+
+
+
+
+
+
Nueva Factura Temporal
+
Ingresa los datos para registrar la importación.
+
+
+
+ {#if error}
+
+ ⚠️ {error}
+
+ {/if}
+
+
+
\ No newline at end of file