Refactor code structure for improved readability and maintainability

This commit is contained in:
Galindo97
2026-01-07 08:44:10 -06:00
parent 7e72b559ef
commit 7c9c295c5c
33 changed files with 11963 additions and 1 deletions

View File

@@ -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()}`
);
}

View File

@@ -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;
}
}

View File

@@ -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}`);
}

View File

@@ -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}`);
}

View File

@@ -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: "#",

View File

@@ -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