diff --git a/backend/api/v1/modules/a76/general_catalogs/exchange_rate/dto.py b/backend/api/v1/modules/a76/general_catalogs/exchange_rate/dto.py index 3dbe23d3..ce0ddea8 100644 --- a/backend/api/v1/modules/a76/general_catalogs/exchange_rate/dto.py +++ b/backend/api/v1/modules/a76/general_catalogs/exchange_rate/dto.py @@ -1,10 +1,11 @@ +from datetime import datetime from typing import Optional from pydantic import BaseModel, Field class ExchangeRateBaseDTO(BaseModel): - date: int = Field(..., description="Exchange rate date") + date: datetime = Field(..., description="Exchange rate date") value: Optional[float] = Field(None, description="Exchange rate value") local_currency: Optional[str] = Field(None, max_length=7, description="Local currency code") foreign_currency: Optional[str] = Field(None, max_length=7, description="Foreign currency code") @@ -17,7 +18,7 @@ class ExchangeRateCreateDTO(ExchangeRateBaseDTO): class ExchangeRateUpdateDTO(ExchangeRateBaseDTO): """Schema for updating an exchange rate""" - date: Optional[int] = Field(None, description="Exchange rate date") + date: Optional[datetime] = Field(None, description="Exchange rate date") class ExchangeRateResponseDTO(ExchangeRateBaseDTO): diff --git a/backend/api/v1/modules/a76/general_catalogs/exchange_rate/models.py b/backend/api/v1/modules/a76/general_catalogs/exchange_rate/models.py index 9832e756..3aeb5aeb 100644 --- a/backend/api/v1/modules/a76/general_catalogs/exchange_rate/models.py +++ b/backend/api/v1/modules/a76/general_catalogs/exchange_rate/models.py @@ -1,3 +1,4 @@ +from datetime import datetime from decimal import Decimal from typing import Optional @@ -33,7 +34,7 @@ class ExchangeRate(Base, TenantScopedMixin): id: Mapped[int] = mapped_column(Integer, primary_key=True) - date: Mapped[int] = mapped_column(DateTime) + date: Mapped[datetime] = mapped_column(DateTime) value: Mapped[Optional[Decimal]] = mapped_column(DECIMAL(13, 6)) local_currency: Mapped[Optional[str]] = mapped_column(String(7)) foreign_currency: Mapped[Optional[str]] = mapped_column(String(7)) diff --git a/backend/api/v1/modules/a76/general_catalogs/packages/dto.py b/backend/api/v1/modules/a76/general_catalogs/packages/dto.py index 3d1e153b..09e421df 100644 --- a/backend/api/v1/modules/a76/general_catalogs/packages/dto.py +++ b/backend/api/v1/modules/a76/general_catalogs/packages/dto.py @@ -2,6 +2,7 @@ DTOs for Packages (GBultos). """ +from datetime import datetime from typing import Optional from pydantic import BaseModel, Field @@ -33,8 +34,8 @@ class PackageResponseDTO(PackageBaseDTO): id: int company_id: int tenant_id: int - created_at: Optional[str] = None - updated_at: Optional[str] = None + created_at: Optional[datetime] = None + updated_at: Optional[datetime] = None class Config: from_attributes = True diff --git a/backend/api/v1/modules/a76/general_catalogs/packages/routes.py b/backend/api/v1/modules/a76/general_catalogs/packages/routes.py index 0622a247..88a6eba4 100644 --- a/backend/api/v1/modules/a76/general_catalogs/packages/routes.py +++ b/backend/api/v1/modules/a76/general_catalogs/packages/routes.py @@ -13,11 +13,11 @@ router = TenantCRUDRoutes( create_schema=PackageCreateDTO, update_schema=PackageUpdateDTO, response_schema=PackageResponseDTO, - prefix="/package", - tags=[], + prefix="/packages", + tags=["a76 / packages"], resource_name="Package", - id_name="id", # Using numeric ID - enable_list=True, # Enable GET /package with pagination + id_name="package_id", + enable_list=True, # Enable GET /packages with pagination enable_filters=True, # Enable filtering by key and description_es default_page_size=50, max_page_size=100, diff --git a/backend/api/v1/modules/a76/general_catalogs/seal/services.py b/backend/api/v1/modules/a76/general_catalogs/seal/services.py index a6843b9e..f29fcb2f 100644 --- a/backend/api/v1/modules/a76/general_catalogs/seal/services.py +++ b/backend/api/v1/modules/a76/general_catalogs/seal/services.py @@ -75,8 +75,8 @@ class SealService: db: Session, seal_id: int, tenant_id: int, - company_id: int, seal_data: dto.SealUpdateDTO, + company_id: int, ) -> Optional[models.Seal]: """Update a seal""" seal = SealService.get_by_id(db, seal_id, tenant_id, company_id) diff --git a/backend/api/v1/modules/a76/router.py b/backend/api/v1/modules/a76/router.py index 8f758c2a..be3a8b78 100644 --- a/backend/api/v1/modules/a76/router.py +++ b/backend/api/v1/modules/a76/router.py @@ -46,7 +46,7 @@ router.include_router(parts_router, prefix="/a76", tags=["a76 / parts"]) router.include_router( permission_rule_oct_router, prefix="/a76", tags=["a76 / permission_rule_oct"] ) -router.include_router(package_router, prefix="/a76", tags=["a76 / package"]) +router.include_router(package_router, prefix="/a76") router.include_router(seal_router, prefix="/a76", tags=["a76 / seal"]) router.include_router( fraction_rule_octave_router, prefix="/a76", tags=["a76 / fraction_rule_octave"] diff --git a/frontend/src/lib/api/dashboard/a76/exchange-rate.ts b/frontend/src/lib/api/dashboard/a76/exchange-rate.ts new file mode 100644 index 00000000..b8b94a40 --- /dev/null +++ b/frontend/src/lib/api/dashboard/a76/exchange-rate.ts @@ -0,0 +1,91 @@ +import type { PaginatedResponse } from '$lib/types'; +import { api } from '$lib/api'; + +export interface ExchangeRate { + id: number; + date: string; + value: number | null; + local_currency: string | null; + foreign_currency: string | null; + company_id: number; + tenant_id: number; +} + +export interface ExchangeRateCreate { + date: string; + value?: number | null; + local_currency?: string | null; + foreign_currency?: string | null; +} + +export interface ExchangeRateUpdate { + date?: string; + value?: number | null; + local_currency?: string | null; + foreign_currency?: string | null; +} + +export interface ExchangeRateListResponse extends PaginatedResponse { + items: ExchangeRate[]; +} + +export interface ExchangeRateFilters { + date?: string; + local_currency?: string; + foreign_currency?: string; + page?: number; + page_size?: number; +} + +export async function getExchangeRates( + companyId: number, + filters?: ExchangeRateFilters +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + + if (filters) { + if (filters.date) params.append('date', filters.date); + if (filters.local_currency) params.append('local_currency', filters.local_currency); + if (filters.foreign_currency) params.append('foreign_currency', filters.foreign_currency); + if (filters.page) params.append('page', filters.page.toString()); + if (filters.page_size) params.append('page_size', filters.page_size.toString()); + } + + return api.get(`/v1/a76/exchange-rate/?${params.toString()}`); +} + +export async function getExchangeRate( + exchangeRateId: number, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.get(`/v1/a76/exchange-rate/${exchangeRateId}?${params.toString()}`); +} + +export async function createExchangeRate( + data: ExchangeRateCreate, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.post(`/v1/a76/exchange-rate/?${params.toString()}`, data); +} + +export async function updateExchangeRate( + exchangeRateId: number, + data: ExchangeRateUpdate, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.put( + `/v1/a76/exchange-rate/${exchangeRateId}?${params.toString()}`, + data + ); +} + +export async function deleteExchangeRate( + exchangeRateId: number, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.delete(`/v1/a76/exchange-rate/${exchangeRateId}?${params.toString()}`); +} diff --git a/frontend/src/lib/api/dashboard/a76/index.ts b/frontend/src/lib/api/dashboard/a76/index.ts index f070b9dd..84029759 100644 --- a/frontend/src/lib/api/dashboard/a76/index.ts +++ b/frontend/src/lib/api/dashboard/a76/index.ts @@ -2,3 +2,5 @@ * Exportaciones de APIs para módulo A76 */ export * from './classes'; +export * from './packages'; +export * from './exchange-rate'; diff --git a/frontend/src/lib/api/dashboard/a76/packages.ts b/frontend/src/lib/api/dashboard/a76/packages.ts new file mode 100644 index 00000000..8fb8d682 --- /dev/null +++ b/frontend/src/lib/api/dashboard/a76/packages.ts @@ -0,0 +1,122 @@ +/** + * API para gestión de Packages (Bultos/Embalajes A76) + */ +import { api } from '$lib/api'; +import type { ApiResponse } from '$lib/api'; + +export interface Package { + id: number; + tenant_id: number; + company_id: number; + key: string; + description_es: string | null; + description_en: string | null; + weight_unit: number | null; + plurals: string | null; + plural_in: string | null; + code_ace: string | null; + code_aamex: string | null; + created_at: string | null; + updated_at: string | null; +} + +export interface PackageCreate { + key: string; + description_es?: string | null; + description_en?: string | null; + weight_unit?: number | null; + plurals?: string | null; + plural_in?: string | null; + code_ace?: string | null; + code_aamex?: string | null; +} + +export interface PackageUpdate { + key?: string; + description_es?: string | null; + description_en?: string | null; + weight_unit?: number | null; + plurals?: string | null; + plural_in?: string | null; + code_ace?: string | null; + code_aamex?: string | null; +} + +export interface PackageListResponse { + items: Package[]; + total: number; + page: number; + page_size: number; + pages: number; +} + +export interface PackageFilters { + key?: string; + description_es?: string; +} + +/** + * Obtener lista de packages con paginación + */ +export async function getPackages( + companyId: number, + page: number = 1, + pageSize: number = 50, + filters?: PackageFilters +): Promise> { + const params = new URLSearchParams({ + company_id: companyId.toString(), + page: page.toString(), + page_size: pageSize.toString() + }); + + if (filters?.key) { + params.append('key', filters.key); + } + if (filters?.description_es) { + params.append('description_es', filters.description_es); + } + + return api.get(`/v1/a76/packages/?${params.toString()}`); +} + +/** + * Obtener un package por ID + */ +export async function getPackage( + packageId: number, + companyId: number +): Promise> { + return api.get(`/v1/a76/packages/${packageId}?company_id=${companyId}`); +} + +/** + * Crear un nuevo package + */ +export async function createPackage( + data: PackageCreate, + companyId: number +): Promise> { + return api.post(`/v1/a76/packages/?company_id=${companyId}`, data); +} + +/** + * Actualizar un package existente + */ +export async function updatePackage( + packageId: number, + data: PackageUpdate, + companyId: number +): Promise> { + return api.put(`/v1/a76/packages/${packageId}?company_id=${companyId}`, data); +} + +/** + * Eliminar un package + */ +export async function deletePackage( + packageId: number, + companyId: number +): Promise> { + return api.delete(`/v1/a76/packages/${packageId}?company_id=${companyId}`); +} diff --git a/frontend/src/lib/api/dashboard/a76/seal.ts b/frontend/src/lib/api/dashboard/a76/seal.ts new file mode 100644 index 00000000..e0d848d9 --- /dev/null +++ b/frontend/src/lib/api/dashboard/a76/seal.ts @@ -0,0 +1,95 @@ +/** + * API client for Seal operations + */ +import { api } from '$lib/api'; + +export interface Seal { + id: number; + seal: string; + company_id: number; + tenant_id: number; +} + +export interface SealListResponse { + items: Seal[]; + total: number; + page: number; + page_size: number; + pages: number; +} + +export interface SealCreateRequest { + seal: string; +} + +export interface SealUpdateRequest { + seal?: string; +} + +/** + * Get all seals with pagination and filters + */ +export async function getSeals( + companyId: number, + filters?: { + page?: number; + page_size?: number; + seal?: string; + } +): Promise<{ data: SealListResponse; status: number }> { + const params = new URLSearchParams(); + params.append('company_id', companyId.toString()); + + if (filters?.page) params.append('page', filters.page.toString()); + if (filters?.page_size) params.append('page_size', filters.page_size.toString()); + if (filters?.seal) params.append('seal', filters.seal); + + const response = await api.get(`/v1/a76/seals?${params.toString()}`); + + return response; +} + +/** + * Get a single seal by ID + */ +export async function getSeal( + id: number, + companyId: number +): Promise<{ data: Seal; status: number }> { + const response = await api.get(`/v1/a76/seals/${id}?company_id=${companyId}`); + return response; +} + +/** + * Create a new seal + */ +export async function createSeal( + data: SealCreateRequest, + companyId: number +): Promise<{ data: Seal; status: number }> { + const response = await api.post(`/v1/a76/seals?company_id=${companyId}`, data); + return response; +} + +/** + * Update an existing seal + */ +export async function updateSeal( + id: number, + data: SealUpdateRequest, + companyId: number +): Promise<{ data: Seal; status: number }> { + const response = await api.put(`/v1/a76/seals/${id}?company_id=${companyId}`, data); + return response; +} + +/** + * Delete a seal + */ +export async function deleteSeal( + id: number, + companyId: number +): Promise<{ data: any; status: number }> { + const response = await api.delete(`/v1/a76/seals/${id}?company_id=${companyId}`); + return response; +} diff --git a/frontend/src/lib/components/dashboard/exchange-rate/columns.ts b/frontend/src/lib/components/dashboard/exchange-rate/columns.ts new file mode 100644 index 00000000..4b3e3ead --- /dev/null +++ b/frontend/src/lib/components/dashboard/exchange-rate/columns.ts @@ -0,0 +1,48 @@ +import type { ColumnDef } from '@tanstack/table-core'; +import type { ExchangeRate } from '$lib/api/dashboard/a76/exchange-rate'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'date', + header: 'Fecha', + cell: ({ row }) => { + const dateStr = row.original.date; + if (!dateStr) return 'N/A'; + const date = new Date(dateStr); + return date.toLocaleDateString('es-MX'); + } + }, + { + accessorKey: 'value', + header: 'Tipo de Cambio', + cell: ({ row }) => { + const value = row.original.value; + if (value === null || value === undefined) return 'N/A'; + return value.toFixed(6); + } + }, + { + accessorKey: 'local_currency', + header: 'Moneda Local', + cell: ({ row }) => row.original.local_currency ?? 'N/A' + }, + { + accessorKey: 'foreign_currency', + header: 'Moneda Extranjera', + cell: ({ row }) => row.original.foreign_currency ?? 'N/A' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} \ No newline at end of file diff --git a/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte new file mode 100644 index 00000000..22fa8202 --- /dev/null +++ b/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte @@ -0,0 +1,164 @@ + + + + + + {isEdit ? 'Editar' : 'Crear'} Tipo de Cambio + + +
+
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + {#if error} +

{error}

+ {/if} + +
+ + +
+
+
+
diff --git a/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte b/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte new file mode 100644 index 00000000..ef912f89 --- /dev/null +++ b/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte @@ -0,0 +1,99 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + + + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte b/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte new file mode 100644 index 00000000..ef98de23 --- /dev/null +++ b/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte @@ -0,0 +1,123 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + + {#if hasMore} + + +
+ {#if loading} +
+
+ Cargando más... +
+ {:else} +
+ Desplázate para cargar más +
+ {/if} +
+
+
+ {/if} +
+
+
+
diff --git a/frontend/src/lib/components/dashboard/packages/columns.ts b/frontend/src/lib/components/dashboard/packages/columns.ts new file mode 100644 index 00000000..ae0838bd --- /dev/null +++ b/frontend/src/lib/components/dashboard/packages/columns.ts @@ -0,0 +1,71 @@ +/** + * Definición de columnas para la tabla de Packages + */ +import type { Package } from '$lib/api/dashboard/a76/packages'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'key', + header: 'Clave', + cell: ({ row }) => { + return row.original.key; + } + }, + { + accessorKey: 'description_es', + header: 'Descripción (ES)', + cell: ({ row }) => { + return row.original.description_es || '-'; + } + }, + { + accessorKey: 'description_en', + header: 'Descripción (EN)', + cell: ({ row }) => { + return row.original.description_en || '-'; + } + }, + { + accessorKey: 'weight_unit', + header: 'Peso Unitario', + cell: ({ row }) => { + return row.original.weight_unit ? row.original.weight_unit.toString() : '-'; + } + }, + { + accessorKey: 'plurals', + header: 'Plural', + cell: ({ row }) => { + return row.original.plurals || '-'; + } + }, + { + accessorKey: 'code_ace', + header: 'Código ACE', + cell: ({ row }) => { + return row.original.code_ace || '-'; + } + }, + { + accessorKey: 'code_aamex', + header: 'Código AAMEX', + cell: ({ row }) => { + return row.original.code_aamex || '-'; + } + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/packages/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/packages/create-edit-dialog.svelte new file mode 100644 index 00000000..ae48414f --- /dev/null +++ b/frontend/src/lib/components/dashboard/packages/create-edit-dialog.svelte @@ -0,0 +1,260 @@ + + + + + + {title} + + {isEdit ? 'Modifica los datos del bulto' : 'Completa los datos para crear un nuevo bulto'} + + + +
{ e.preventDefault(); handleSubmit(); }} class="space-y-4"> + {#if error} +
+ {error} +
+ {/if} + +
+ +
+ + +

+ Máximo 5 caracteres. {isEdit ? 'No se puede modificar en edición.' : ''} +

+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+ + +

+ Peso unitario del bulto (hasta 8 decimales) +

+
+ + +
+
+ + +
+ +
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+
+
+ + + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte b/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte new file mode 100644 index 00000000..bf4ce8be --- /dev/null +++ b/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte @@ -0,0 +1,111 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + + + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/packages/data-table.svelte b/frontend/src/lib/components/dashboard/packages/data-table.svelte new file mode 100644 index 00000000..ef98de23 --- /dev/null +++ b/frontend/src/lib/components/dashboard/packages/data-table.svelte @@ -0,0 +1,123 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + + {#if hasMore} + + +
+ {#if loading} +
+
+ Cargando más... +
+ {:else} +
+ Desplázate para cargar más +
+ {/if} +
+
+
+ {/if} +
+
+
+
diff --git a/frontend/src/lib/components/dashboard/seal/columns.ts b/frontend/src/lib/components/dashboard/seal/columns.ts new file mode 100644 index 00000000..cf354c75 --- /dev/null +++ b/frontend/src/lib/components/dashboard/seal/columns.ts @@ -0,0 +1,27 @@ +/** + * Column definitions for Seal table + */ +import type { ColumnDef } from '@tanstack/table-core'; +import type { Seal } from '$lib/api/dashboard/a76/seal'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'seal', + header: 'Sello', + cell: ({ row }) => row.original.seal + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/seal/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/seal/create-edit-dialog.svelte new file mode 100644 index 00000000..3b525222 --- /dev/null +++ b/frontend/src/lib/components/dashboard/seal/create-edit-dialog.svelte @@ -0,0 +1,132 @@ + + + + + + {title} + + {#if isEdit} + Modifica los datos del sello + {:else} + Ingresa los datos del nuevo sello + {/if} + + + +
+
+ + +

+ Máximo 15 caracteres +

+
+ + {#if error} +
+

{error}

+
+ {/if} + + + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/seal/data-table-actions.svelte b/frontend/src/lib/components/dashboard/seal/data-table-actions.svelte new file mode 100644 index 00000000..8a821ef3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/seal/data-table-actions.svelte @@ -0,0 +1,98 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + + + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/seal/data-table.svelte b/frontend/src/lib/components/dashboard/seal/data-table.svelte new file mode 100644 index 00000000..7f02c1cc --- /dev/null +++ b/frontend/src/lib/components/dashboard/seal/data-table.svelte @@ -0,0 +1,112 @@ + + +
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + {#if loading} + + + Cargando... + + + {/if} + + +
+
diff --git a/frontend/src/lib/components/dashboard/seal/index.ts b/frontend/src/lib/components/dashboard/seal/index.ts new file mode 100644 index 00000000..5d54605b --- /dev/null +++ b/frontend/src/lib/components/dashboard/seal/index.ts @@ -0,0 +1,7 @@ +/** + * Seal components + */ +export { default as DataTable } from './data-table.svelte'; +export { default as DataTableActions } from './data-table-actions.svelte'; +export { default as CreateEditDialog } from './create-edit-dialog.svelte'; +export { createColumns } from './columns'; diff --git a/frontend/src/lib/components/sidebar/modules.ts b/frontend/src/lib/components/sidebar/modules.ts index 1992cae5..e5806eeb 100644 --- a/frontend/src/lib/components/sidebar/modules.ts +++ b/frontend/src/lib/components/sidebar/modules.ts @@ -159,7 +159,7 @@ export function getSidebarData(): SidebarData { }, { title: m["sidebar.general_catalogs.packages"](), - url: "#", + url: "/dashboard/general_catalogs/packages", }, { title: m["sidebar.general_catalogs.concepts"](), @@ -187,7 +187,7 @@ export function getSidebarData(): SidebarData { }, { title: m["sidebar.general_catalogs.seals"](), - url: "#", + url: "/dashboard/general_catalogs/seal", }, { title: m["sidebar.general_catalogs.valuation_methods"](), @@ -231,7 +231,7 @@ export function getSidebarData(): SidebarData { }, { title: m["sidebar.general_catalogs.exchange_rates"](), - url: "#", + url: "/dashboard/general_catalogs/exchange-rate", }, { title: m["sidebar.general_catalogs.currency_types"](), diff --git a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte new file mode 100644 index 00000000..e375caf3 --- /dev/null +++ b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte @@ -0,0 +1,219 @@ + + + + Tipos de Cambio - Anexo 76 + + +
+
+
+

Tipos de Cambio

+

Gestiona los tipos de cambio del sistema

+
+ +
+ + + + Filtros + + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+
+ + {#if error} + + Error + {error} + + {/if} + + +
+ + (dialogOpen = open)} + onSuccess={handleSuccess} +/> diff --git a/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte new file mode 100644 index 00000000..695c231b --- /dev/null +++ b/frontend/src/routes/dashboard/general_catalogs/packages/+page.svelte @@ -0,0 +1,326 @@ + + + + Bultos / Embalajes - Catálogos Generales + + +
+ +
+
+

Bultos / Embalajes

+

+ Gestiona los tipos de bultos y embalajes utilizados en tus operaciones +

+
+ +
+ + + + +
+ + + Filtros + + +
+
+ + {#if showFilters} + +
{ e.preventDefault(); handleApplyFilters(); }} class="space-y-4"> +
+
+ + +
+ +
+ + +
+
+ +
+ + + +
+
+
+ {/if} +
+ + + {#if error} + + +
+ + + +

{error}

+
+
+
+ {/if} + + + + +
+
+ Lista de Bultos + + Total: {totalItems} bulto{totalItems !== 1 ? 's' : ''} | + Mostrando: {allItems.length} + +
+
+
+ + + +
+
+ + + diff --git a/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte new file mode 100644 index 00000000..0bbc2509 --- /dev/null +++ b/frontend/src/routes/dashboard/general_catalogs/seal/+page.svelte @@ -0,0 +1,192 @@ + + + + Sellos - Anexo 76 + + +
+
+
+

Sellos

+

Gestiona los sellos de tu empresa

+
+ +
+ + {#if error} +
+

{error}

+
+ {/if} + + + +
+
+ Lista de Sellos + + Total: {allItems.length} sello{allItems.length !== 1 ? 's' : ''} + +
+
+ + +
+
+ + +
+ +
+
+ + + +
+
+ +