feature/catalogo-pedimento

This commit is contained in:
2026-03-17 16:35:27 -06:00
parent e326ac0f0a
commit 3983c9e4b3
16 changed files with 355 additions and 70 deletions

View File

@@ -4,6 +4,7 @@
import { Input } from '$lib/components/ui/input';
import { Label } from '$lib/components/ui/label';
import * as Select from '$lib/components/ui/select';
import { getLocale } from '$lib/paraglide/runtime';
import { getExchangeRateByDate } from '$lib/api/dashboard/a76/exchange-rate';
import { companyStore } from '$lib/stores/company.svelte';
import type { Pedimento } from '$lib/api/dashboard/a76/pedimentos';
@@ -12,8 +13,6 @@
import type { CustomsBroker } from '$lib/api/dashboard/a76/customs-brokers';
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
import type { CodePedimentoRegimen } from '$lib/api/dashboard/reference_data/code_pedimento_regimens';
import type { TransportType } from '$lib/api/dashboard/reference_data/transport_types';
import type { TransportMode } from '$lib/api/dashboard/reference_data/transport_modes';
import IdentificadoresTabForm from './identifiers-tab-form.svelte';
import ExchangeRateDialog from '$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte';
import { Calendar, Clock } from 'lucide-svelte';
@@ -29,6 +28,13 @@
import { shortcutStore } from '$lib/stores/shortcut-store';
import { focusStore, interactionMode } from '$lib/stores/focus-store';
type PedimentoTransportCatalog = {
code: string;
transport_en: string;
transport_es: string;
payment_date_code: 'E' | 'P' | string;
};
let {
pedimento,
formData = $bindable(),
@@ -38,8 +44,7 @@
customsBrokers = [],
clients = [],
codePedimentoRegimens = [],
transportTypes = [],
transportModes = [],
pedimentoTransportCatalog = [],
isActive = false
}: {
pedimento: Pedimento | null;
@@ -50,8 +55,7 @@
customsBrokers?: CustomsBroker[];
clients?: ClientProvider[];
codePedimentoRegimens?: CodePedimentoRegimen[];
transportTypes?: TransportType[];
transportModes?: TransportMode[];
pedimentoTransportCatalog?: PedimentoTransportCatalog[];
isActive?: boolean;
} = $props();
@@ -352,27 +356,53 @@
let lastFetchedDate: string | null = null;
let lastCompanyId: number | null = null;
// Obtener automáticamente el tipo de cambio cuando cambie la fecha de entrada
function getTransportByCode(code: string | null | undefined): PedimentoTransportCatalog | undefined {
if (!code) return undefined;
return pedimentoTransportCatalog.find((m) => m.code === code);
}
function getTransportLabel(mode: PedimentoTransportCatalog | undefined): string {
if (!mode) return '';
const locale = getLocale();
return locale === 'en' ? mode.transport_en : mode.transport_es;
}
function getEffectiveExchangeDate(): string | null {
const entryMethod = getTransportByCode(formData?.pedimento_transport_means?.entry_exit);
const paymentCode = (entryMethod?.payment_date_code || 'E').toUpperCase();
if (paymentCode === 'P') {
return formData?.payment_date || null;
}
return formData?.entry_date || null;
}
function getEffectiveDateLabel(): string {
const entryMethod = getTransportByCode(formData?.pedimento_transport_means?.entry_exit);
const paymentCode = (entryMethod?.payment_date_code || 'E').toUpperCase();
return paymentCode === 'P' ? 'fecha de pago' : 'fecha de entrada';
}
// Obtener automáticamente el tipo de cambio cuando cambie la fecha efectiva
$effect(() => {
const entryDate = formData?.entry_date;
const effectiveDate = getEffectiveExchangeDate();
const companyId = companyStore.activeCompany?.id;
// Solo ejecutar si los valores clave cambiaron
if (
formData &&
entryDate &&
effectiveDate &&
companyId &&
(entryDate !== lastFetchedDate || companyId !== lastCompanyId)
(effectiveDate !== lastFetchedDate || companyId !== lastCompanyId)
) {
lastFetchedDate = entryDate;
lastFetchedDate = effectiveDate;
lastCompanyId = companyId;
getExchangeRateByDate(entryDate, companyId)
getExchangeRateByDate(effectiveDate, companyId)
.then((usdRate) => {
if (usdRate && formData) {
formData.exchange_rate = usdRate.value;
} else {
console.warn('⚠️ [TIPO CAMBIO] No encontrado para fecha:', entryDate);
console.warn('⚠️ [TIPO CAMBIO] No encontrado para fecha:', effectiveDate);
}
})
.catch((err) => {
@@ -397,13 +427,14 @@
];
export async function checkPaymentDateRate(date: string): Promise<boolean> {
if (!date || !companyStore.activeCompany?.id) return true;
const effectiveDate = date || getEffectiveExchangeDate();
if (!effectiveDate || !companyStore.activeCompany?.id) return true;
try {
const rate = await getExchangeRateByDate(date, companyStore.activeCompany.id);
const rate = await getExchangeRateByDate(effectiveDate, companyStore.activeCompany.id);
if (!rate) {
// Abrir modal preventivamente
missingExchangeRateDate = date;
missingExchangeRateDate = effectiveDate;
showExchangeRateDialog = true;
return false;
}
@@ -411,7 +442,7 @@
} catch (error) {
console.error('Error checking payment date rate:', error);
// Si hay error de red, asumimos que falta para forzar reintento/captura segura
missingExchangeRateDate = date;
missingExchangeRateDate = effectiveDate;
showExchangeRateDialog = true;
return false;
}
@@ -568,11 +599,16 @@
id="exchange_rate"
type="text"
value={formData.exchange_rate ? Number(formData.exchange_rate).toFixed(6) : ''}
placeholder="Se obtiene automáticamente de la fecha de entrada"
placeholder={`Se obtiene automáticamente de la ${getEffectiveDateLabel()}`}
readonly
disabled
class="cursor-not-allowed bg-muted"
/>
<p class="text-xs text-muted-foreground">
Tipo de fecha para TC: {getEffectiveDateLabel() === 'fecha de pago'
? 'FECHA PAGO'
: 'FECHA ENTRADA'}
</p>
</div>
</div>
@@ -829,18 +865,16 @@
>
<Select.Trigger id="entry_exit" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.entry_exit)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.entry_exit
)?.description ||
{getTransportLabel(
getTransportByCode(formData.pedimento_transport_means.entry_exit)
) ||
formData.pedimento_transport_means.entry_exit ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{#each pedimentoTransportCatalog as mode}
<Select.Item value={mode.code}>{mode.code} - {getTransportLabel(mode)}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
@@ -856,18 +890,14 @@
>
<Select.Trigger id="arrival" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.arrival)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.arrival
)?.description ||
{getTransportLabel(getTransportByCode(formData.pedimento_transport_means.arrival)) ||
formData.pedimento_transport_means.arrival ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{#each pedimentoTransportCatalog as mode}
<Select.Item value={mode.code}>{mode.code} - {getTransportLabel(mode)}</Select.Item>
{/each}
</Select.Content>
</Select.Root>
@@ -883,18 +913,14 @@
>
<Select.Trigger id="departure" class="w-full">
<span class="truncate">
{transportModes.find((m) => m.key === formData.pedimento_transport_means.departure)
?.name ||
transportTypes.find(
(t) => t.transport_code === formData.pedimento_transport_means.departure
)?.description ||
{getTransportLabel(getTransportByCode(formData.pedimento_transport_means.departure)) ||
formData.pedimento_transport_means.departure ||
'Seleccionar...'}
</span>
</Select.Trigger>
<Select.Content class="max-h-[300px]">
{#each transportModes as mode}
<Select.Item value={mode.key}>{mode.key} - {mode.name}</Select.Item>
{#each pedimentoTransportCatalog as mode}
<Select.Item value={mode.code}>{mode.code} - {getTransportLabel(mode)}</Select.Item>
{/each}
</Select.Content>
</Select.Root>

View File

@@ -41,6 +41,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
codePedimentoRegimens: [],
transportTypes: [],
transportModes: [],
pedimentoTransportCatalog: [],
error: 'Error al cargar catálogos. Verifique la conexión con el backend.'
};
}
@@ -57,7 +58,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
clients: data.clients || [],
codePedimentoRegimens: data.code_pedimento_regimens || [],
transportTypes: data.transport_types || [],
transportModes: data.transport_modes || []
transportModes: data.transport_modes || [],
pedimentoTransportCatalog: data.pedimento_transport_catalog || []
};
} catch (e) {
console.error('❌ Error loading new pedimento data:', e);
@@ -73,6 +75,7 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
codePedimentoRegimens: [],
transportTypes: [],
transportModes: [],
pedimentoTransportCatalog: [],
error: 'Error al cargar catálogos. Verifique la conexión con el backend.'
};
}
@@ -114,7 +117,8 @@ export const load: PageServerLoad = async ({ params, cookies, fetch }) => {
clients: data.clients || [],
codePedimentoRegimens: data.code_pedimento_regimens || [],
transportTypes: data.transport_types || [],
transportModes: data.transport_modes || []
transportModes: data.transport_modes || [],
pedimentoTransportCatalog: data.pedimento_transport_catalog || []
};
} catch (e) {
console.error('Error loading pedimento:', e);

View File

@@ -56,6 +56,12 @@
import type { CodePedimentoRegimen } from '$lib/api/dashboard/reference_data/code_pedimento_regimens';
import type { TransportType } from '$lib/api/dashboard/reference_data/transport_types';
import type { TransportMode } from '$lib/api/dashboard/reference_data/transport_modes';
type PedimentoTransportCatalog = {
code: string;
transport_en: string;
transport_es: string;
payment_date_code: 'E' | 'P' | string;
};
// Get sidebar context
const sidebar = useSidebar();
@@ -71,6 +77,7 @@
codePedimentoRegimens?: CodePedimentoRegimen[];
transportTypes?: TransportType[];
transportModes?: TransportMode[];
pedimentoTransportCatalog?: PedimentoTransportCatalog[];
user?: any;
companies?: any[];
authenticated?: boolean;
@@ -153,6 +160,18 @@
}
}
function getExchangeDateForPedimento(formData: any): { date: string | null; label: string } {
const catalog = (data.pedimentoTransportCatalog || []) as PedimentoTransportCatalog[];
const entryMethod = catalog.find(
(item) => item.code === formData?.pedimento_transport_means?.entry_exit
);
const paymentDateCode = (entryMethod?.payment_date_code || 'E').toUpperCase();
if (paymentDateCode === 'P') {
return { date: formData?.payment_date || null, label: 'fecha de pago' };
}
return { date: formData?.entry_date || null, label: 'fecha de entrada' };
}
// ID del pedimento
let pedimentoId = $state<number | null>(data.pedimentoId ?? null);
@@ -395,11 +414,10 @@
saving = true;
try {
// Verificar tipo de cambio antes de guardar si hay instancia del tab general y hay fecha de pago
if (generalTabInstance && generalFormData?.payment_date) {
const rateExists = await generalTabInstance.checkPaymentDateRate(
generalFormData.payment_date
);
// Verificar tipo de cambio según catalogo de transporte (E/P)
if (generalTabInstance && generalFormData) {
const exchangeRef = getExchangeDateForPedimento(generalFormData);
const rateExists = await generalTabInstance.checkPaymentDateRate(exchangeRef.date || '');
if (!rateExists) {
saving = false;
// Asegurar que se muestre el tab general
@@ -432,8 +450,9 @@
}
}
// Validar tipo de cambio en create y update
// Validar tipo de cambio en create y update segun fecha efectiva del metodo de transporte
if (generalFormData) {
const exchangeRef = getExchangeDateForPedimento(generalFormData);
const rate = generalFormData.exchange_rate;
if (
rate === null ||
@@ -443,11 +462,11 @@
) {
saving = false;
activeTab = 'general';
const date = generalFormData.entry_date || '';
const date = exchangeRef.date || '';
toast.error(
Number(rate) <= 0 && rate !== null && rate !== undefined
? 'El tipo de cambio debe ser mayor a 0. Registra el tipo de cambio para la fecha de entrada.'
: 'No hay tipo de cambio registrado para la fecha de entrada. Por favor, regístralo antes de guardar.'
? `El tipo de cambio debe ser mayor a 0. Registra el tipo de cambio para la ${exchangeRef.label}.`
: `No hay tipo de cambio registrado para la ${exchangeRef.label}. Por favor, regístralo antes de guardar.`
);
if (date) {
missingExchangeRateDate = date;
@@ -1129,8 +1148,7 @@
customsBrokers={data.customsBrokers}
clients={data.clients}
codePedimentoRegimens={data.codePedimentoRegimens}
transportTypes={data.transportTypes}
transportModes={data.transportModes}
pedimentoTransportCatalog={data.pedimentoTransportCatalog}
isActive={activeTab === 'general'}
/>
</Tabs.Content>