feature/catalogo-pedimento
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user