Refactor code structure for improved readability and maintainability
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
import { api } from '$lib/api';
|
||||
import type { ApiResponse } from '$lib/api';
|
||||
|
||||
// Interfaces
|
||||
export interface DepreciationCatalog {
|
||||
id: number;
|
||||
tenant_id: number;
|
||||
company_id: number;
|
||||
fraction: string;
|
||||
description: string;
|
||||
depreciation_rate: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface DepreciationCatalogListResponse {
|
||||
items: DepreciationCatalog[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
pages: number;
|
||||
}
|
||||
|
||||
// API Functions
|
||||
export async function getDepreciationCatalog(
|
||||
page = 1,
|
||||
pageSize = 100,
|
||||
companyId: number,
|
||||
filters: Record<string, any> = {}
|
||||
): Promise<ApiResponse<DepreciationCatalogListResponse>> {
|
||||
const params = new URLSearchParams({
|
||||
company_id: companyId.toString(),
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
...filters
|
||||
});
|
||||
|
||||
return api.get<DepreciationCatalogListResponse>(
|
||||
`/v1/a76/depreciation-catalog/?${params.toString()}`
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import { api } from '$lib/api';
|
||||
|
||||
export interface FDACatalog {
|
||||
id: number;
|
||||
fda_key: string;
|
||||
description: string;
|
||||
fda_code?: string;
|
||||
requirements?: string;
|
||||
manufacturer_number?: string;
|
||||
country_of_production?: string;
|
||||
storage_status?: string;
|
||||
warehouse_code?: string;
|
||||
call_atl?: string;
|
||||
created_at?: string;
|
||||
updated_at?: string;
|
||||
}
|
||||
|
||||
export async function getFDACatalog(
|
||||
page: number,
|
||||
pageSize: number,
|
||||
companyId: number,
|
||||
filters: any = {}
|
||||
): Promise<any> {
|
||||
try {
|
||||
const queryParams = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
company_id: companyId.toString()
|
||||
});
|
||||
|
||||
if (filters.search) {
|
||||
queryParams.append('search', filters.search);
|
||||
}
|
||||
|
||||
const response = await api.get(`/v1/a76/fda-catalog/?${queryParams.toString()}`);
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Error fetching FDA catalog:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { api } from '$lib/api';
|
||||
import type { ApiResponse } from '$lib/api';
|
||||
|
||||
// Interfaces
|
||||
export interface TariffFraction {
|
||||
id: number;
|
||||
code: string;
|
||||
fraction: string;
|
||||
description: string | null;
|
||||
nico: string | null;
|
||||
umt: string | null;
|
||||
adv_impo: string | null;
|
||||
adv_expo: string | null;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface TariffFractionCreate {
|
||||
code: string;
|
||||
fraction: string;
|
||||
description?: string | null;
|
||||
nico?: string | null;
|
||||
umt?: string | null;
|
||||
adv_impo?: string | null;
|
||||
adv_expo?: string | null;
|
||||
}
|
||||
|
||||
export interface TariffFractionUpdate {
|
||||
fraction?: string;
|
||||
description?: string | null;
|
||||
nico?: string | null;
|
||||
umt?: string | null;
|
||||
adv_impo?: string | null;
|
||||
adv_expo?: string | null;
|
||||
}
|
||||
|
||||
export interface TariffFractionListResponse {
|
||||
items: TariffFraction[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
pages: number;
|
||||
}
|
||||
|
||||
// API Functions
|
||||
export async function getTariffFractions(
|
||||
page = 1,
|
||||
pageSize = 50,
|
||||
companyId: number,
|
||||
filters: Record<string, any> = {}
|
||||
): Promise<ApiResponse<TariffFractionListResponse>> {
|
||||
const queryParams = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
company_id: companyId.toString(),
|
||||
...filters
|
||||
});
|
||||
return await api.get(`/v1/a76/tariff-fractions/?${queryParams.toString()}`);
|
||||
}
|
||||
|
||||
export async function getTariffFractionById(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<TariffFraction>> {
|
||||
return await api.get(`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
export async function createTariffFraction(
|
||||
data: TariffFractionCreate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<TariffFraction>> {
|
||||
return await api.post(`/v1/a76/tariff-fractions/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function updateTariffFraction(
|
||||
id: number,
|
||||
data: TariffFractionUpdate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<TariffFraction>> {
|
||||
return await api.put(`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function deleteTariffFraction(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import { api } from '$lib/api';
|
||||
import type { ApiResponse } from '$lib/api';
|
||||
|
||||
// Interfaces
|
||||
export interface USTariffFraction {
|
||||
id: number;
|
||||
code: string;
|
||||
prefix: string | null;
|
||||
type_code: string | null;
|
||||
ad_valorem: number | null;
|
||||
fixed_cost: number | null;
|
||||
unit_of_measure: string | null;
|
||||
description: string | null;
|
||||
created_at: string | null;
|
||||
updated_at: string | null;
|
||||
}
|
||||
|
||||
export interface USTariffFractionCreate {
|
||||
code: string;
|
||||
prefix?: string | null;
|
||||
type_code?: string | null;
|
||||
ad_valorem?: number | null;
|
||||
fixed_cost?: number | null;
|
||||
unit_of_measure?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
export interface USTariffFractionUpdate {
|
||||
prefix?: string | null;
|
||||
type_code?: string | null;
|
||||
ad_valorem?: number | null;
|
||||
fixed_cost?: number | null;
|
||||
unit_of_measure?: string | null;
|
||||
description?: string | null;
|
||||
}
|
||||
|
||||
export interface USTariffFractionListResponse {
|
||||
items: USTariffFraction[];
|
||||
total: number;
|
||||
page: number;
|
||||
page_size: number;
|
||||
pages: number;
|
||||
}
|
||||
|
||||
// API Functions
|
||||
export async function getUSTariffFractions(
|
||||
page = 1,
|
||||
pageSize = 50,
|
||||
companyId: number,
|
||||
filters: Record<string, any> = {}
|
||||
): Promise<ApiResponse<USTariffFractionListResponse>> {
|
||||
const queryParams = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
company_id: companyId.toString(),
|
||||
...filters
|
||||
});
|
||||
return await api.get(`/v1/a76/us-tariff-fractions/?${queryParams.toString()}`);
|
||||
}
|
||||
|
||||
export async function getUSTariffFractionById(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.get(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
export async function createUSTariffFraction(
|
||||
data: USTariffFractionCreate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.post(`/v1/a76/us-tariff-fractions/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function updateUSTariffFraction(
|
||||
id: number,
|
||||
data: USTariffFractionUpdate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<USTariffFraction>> {
|
||||
return await api.put(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function deleteUSTariffFraction(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/us-tariff-fractions/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export function getSidebarData(): SidebarData {
|
||||
user: {
|
||||
name: "", // Se llena dinámicamente desde Keycloak
|
||||
email: "", // Se llena dinámicamente desde Keycloak
|
||||
// avatar: "/avatars/default.jpg", // Avatar por defecto
|
||||
avatar: "", // Se llena dinámicamente desde Keycloak
|
||||
},
|
||||
teams: [
|
||||
{
|
||||
@@ -366,6 +366,17 @@ export function getSidebarData(): SidebarData {
|
||||
icon: BadgeCheck,
|
||||
items: [],
|
||||
},
|
||||
{
|
||||
title: "Mercancías",
|
||||
url: "#",
|
||||
icon: Package,
|
||||
items: [
|
||||
{
|
||||
title: "Clase de Activo Fijo",
|
||||
url: "/dashboard/merchandise/fixed_asset_classes",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: m["sidebar.reference_data.configuracion"](),
|
||||
url: "#",
|
||||
|
||||
@@ -0,0 +1,211 @@
|
||||
<script lang="ts">
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import * as Card from '$lib/components/ui/card';
|
||||
import * as Table from '$lib/components/ui/table';
|
||||
import { Search, Loader2, Download } from 'lucide-svelte';
|
||||
import { getTariffFractions, type TariffFraction } from '$lib/api/dashboard/a76/general_catalogs/tariff-fractions';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let tariffFractions = $state<TariffFraction[]>([]);
|
||||
let filteredFractions = $state<TariffFraction[]>([]);
|
||||
let searchQuery = $state('');
|
||||
let isLoading = $state(false);
|
||||
let currentPage = $state(1);
|
||||
let totalPages = $state(1);
|
||||
let totalRecords = $state(0);
|
||||
const pageSize = 50;
|
||||
|
||||
onMount(() => {
|
||||
loadTariffFractions();
|
||||
});
|
||||
|
||||
// Filtrar fracciones cuando cambia la búsqueda
|
||||
$effect(() => {
|
||||
if (searchQuery.trim() === '') {
|
||||
filteredFractions = tariffFractions;
|
||||
} else {
|
||||
const query = searchQuery.toLowerCase();
|
||||
filteredFractions = tariffFractions.filter(
|
||||
(fraction) =>
|
||||
fraction.code.toLowerCase().includes(query) ||
|
||||
fraction.fraction.toLowerCase().includes(query) ||
|
||||
(fraction.description ?? '').toLowerCase().includes(query) ||
|
||||
(fraction.nico ?? '').toLowerCase().includes(query) ||
|
||||
(fraction.umt ?? '').toLowerCase().includes(query)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
async function loadTariffFractions(page: number = 1) {
|
||||
const companyId = companyStore.activeCompany?.id;
|
||||
if (!companyId) {
|
||||
console.error('No hay compañía activa');
|
||||
return;
|
||||
}
|
||||
|
||||
isLoading = true;
|
||||
try {
|
||||
const response = await getTariffFractions(page, pageSize, companyId);
|
||||
if (response.data) {
|
||||
tariffFractions = response.data.items;
|
||||
filteredFractions = response.data.items;
|
||||
totalPages = response.data.pages;
|
||||
totalRecords = response.data.total;
|
||||
currentPage = response.data.page;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error cargando fracciones arancelarias:', error);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function goToPage(page: number) {
|
||||
if (page >= 1 && page <= totalPages && page !== currentPage) {
|
||||
await loadTariffFractions(page);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container mx-auto p-6">
|
||||
<Card.Root>
|
||||
<Card.Header class="text-center border-b">
|
||||
<Card.Title class="text-2xl font-bold uppercase">
|
||||
Catálogo de Fracciones SITAR - SCAII
|
||||
</Card.Title>
|
||||
<p class="text-muted-foreground mt-2">
|
||||
Nomenclatura arancelaria mexicana completa
|
||||
</p>
|
||||
</Card.Header>
|
||||
|
||||
<Card.Content class="pt-6">
|
||||
<div class="space-y-6">
|
||||
<!-- Barra de búsqueda y acciones -->
|
||||
<div class="flex gap-4 items-center">
|
||||
<div class="flex-1 relative">
|
||||
<Search class="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
bind:value={searchQuery}
|
||||
placeholder="Buscar por código, fracción, descripción, NICO o UMT..."
|
||||
class="pl-9"
|
||||
/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" title="Exportar a CSV">
|
||||
<Download class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<!-- Información de registros -->
|
||||
<div class="flex items-center justify-between text-sm text-muted-foreground">
|
||||
<div>
|
||||
{#if isLoading}
|
||||
<div class="flex items-center gap-2">
|
||||
<Loader2 class="h-4 w-4 animate-spin" />
|
||||
<span>Cargando...</span>
|
||||
</div>
|
||||
{:else}
|
||||
Mostrando {filteredFractions.length} de {totalRecords} fracciones arancelarias
|
||||
{#if searchQuery}
|
||||
(filtrado)
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{#if !searchQuery && totalPages > 1}
|
||||
<div class="flex items-center gap-2">
|
||||
<span>Página {currentPage} de {totalPages}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Tabla de fracciones -->
|
||||
<div class="border rounded-md overflow-auto max-h-[600px]">
|
||||
<Table.Root>
|
||||
<Table.Header class="sticky top-0 bg-background z-10">
|
||||
<Table.Row>
|
||||
<Table.Head class="w-[100px]">Código</Table.Head>
|
||||
<Table.Head class="w-[120px]">Fracción</Table.Head>
|
||||
<Table.Head class="min-w-[350px]">Descripción</Table.Head>
|
||||
<Table.Head class="w-[80px]">NICO</Table.Head>
|
||||
<Table.Head class="w-[80px]">UMT</Table.Head>
|
||||
<Table.Head class="w-[100px]">Adv. Impo</Table.Head>
|
||||
<Table.Head class="w-[100px]">Adv. Expo</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#if filteredFractions.length === 0}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={7} class="text-center py-8 text-muted-foreground">
|
||||
{#if isLoading}
|
||||
Cargando fracciones arancelarias...
|
||||
{:else if searchQuery}
|
||||
No se encontraron fracciones que coincidan con la búsqueda
|
||||
{:else}
|
||||
No hay fracciones arancelarias disponibles
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
{#each filteredFractions as fraction (fraction.id)}
|
||||
<Table.Row class="hover:bg-muted/50">
|
||||
<Table.Cell class="font-mono text-sm">{fraction.code}</Table.Cell>
|
||||
<Table.Cell class="font-mono text-sm font-medium">{fraction.fraction}</Table.Cell>
|
||||
<Table.Cell class="text-sm">
|
||||
{fraction.description || '-'}
|
||||
</Table.Cell>
|
||||
<Table.Cell class="text-sm">{fraction.nico || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-sm">{fraction.umt || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-sm">{fraction.adv_impo || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-sm">{fraction.adv_expo || '-'}</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
{/if}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
<!-- Paginación -->
|
||||
{#if !searchQuery && totalPages > 1}
|
||||
<div class="flex items-center justify-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={currentPage === 1 || isLoading}
|
||||
onclick={() => goToPage(1)}
|
||||
>
|
||||
Primera
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={currentPage === 1 || isLoading}
|
||||
onclick={() => goToPage(currentPage - 1)}
|
||||
>
|
||||
Anterior
|
||||
</Button>
|
||||
<span class="px-4 text-sm">
|
||||
Página {currentPage} de {totalPages}
|
||||
</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={currentPage === totalPages || isLoading}
|
||||
onclick={() => goToPage(currentPage + 1)}
|
||||
>
|
||||
Siguiente
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
disabled={currentPage === totalPages || isLoading}
|
||||
onclick={() => goToPage(totalPages)}
|
||||
>
|
||||
Última
|
||||
</Button>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user