feat: enhance pedimento date validation and update date handling in forms
This commit is contained in:
@@ -13,6 +13,14 @@
|
||||
import type { ClientProvider } from '$lib/api/dashboard/a76/clients-providers';
|
||||
import type { CodePedimentoRegimen } from '$lib/api/dashboard/refrence_data/code_pedimento_regimens';
|
||||
import IdentificadoresTabForm from './identifiers-tab-form.svelte';
|
||||
import { Calendar, Clock } from 'lucide-svelte';
|
||||
import {
|
||||
loadServerDate,
|
||||
addDaysLocal,
|
||||
getCurrentLocalYear,
|
||||
getCurrentLocalDate,
|
||||
getCurrentLocalTime
|
||||
} from '$lib/date-utils';
|
||||
|
||||
let {
|
||||
pedimento,
|
||||
@@ -204,40 +212,44 @@
|
||||
}
|
||||
});
|
||||
|
||||
// Obtener el año actual (últimos 2 dígitos)
|
||||
const now = new Date();
|
||||
const currentYear = String(now.getFullYear()).slice(-2);
|
||||
const currentDate = now.toISOString().substring(0, 10); // YYYY-MM-DD
|
||||
const currentTime = now.toTimeString().substring(0, 5); // HH:MM
|
||||
// --- Inicialización ---
|
||||
const currentYear = getCurrentLocalYear();
|
||||
const currentDate = getCurrentLocalDate();
|
||||
const currentTime = getCurrentLocalTime();
|
||||
|
||||
const end_date = addDaysLocal(currentDate, 4);
|
||||
const payment_date = addDaysLocal(end_date, 2);
|
||||
|
||||
|
||||
// Inicializar formData con los valores del pedimento (o vacío si es null)
|
||||
if (!formData) {
|
||||
const datesData = pedimento?.pedimento_dates;
|
||||
formData = {
|
||||
year: pedimento?.year || currentYear,
|
||||
customs_office: pedimento?.customs_office || '',
|
||||
license: pedimento?.license || '',
|
||||
pedimento_number: pedimento?.pedimento_number || '',
|
||||
client_id: pedimento?.client_id ?? null,
|
||||
operation_type: pedimento?.operation_type ?? null,
|
||||
pedimento_type: pedimento?.pedimento_type || '',
|
||||
pedimento_code: pedimento?.pedimento_code || '',
|
||||
regime: pedimento?.regime || '',
|
||||
status: pedimento?.status || '',
|
||||
usd_value: pedimento?.usd_value ?? null,
|
||||
paid_price: pedimento?.paid_price ?? null,
|
||||
gross_weight: pedimento?.gross_weight ?? null,
|
||||
year: pedimento?.year || currentYear,
|
||||
customs_office: pedimento?.customs_office || '',
|
||||
license: pedimento?.license || '',
|
||||
pedimento_number: pedimento?.pedimento_number || '',
|
||||
client_id: pedimento?.client_id ?? null,
|
||||
operation_type: pedimento?.operation_type ?? null,
|
||||
pedimento_type: pedimento?.pedimento_type || 'consolidated',
|
||||
pedimento_code: pedimento?.pedimento_code || '',
|
||||
regime: pedimento?.regime || '',
|
||||
status: pedimento?.status || 'MODIFICABLE',
|
||||
usd_value: pedimento?.usd_value ?? null,
|
||||
paid_price: pedimento?.paid_price ?? null,
|
||||
gross_weight: pedimento?.gross_weight ?? null,
|
||||
exchange_rate: pedimento?.exchange_rate ?? null,
|
||||
// Date fields
|
||||
entry_date: datesData?.entry_date ? datesData.entry_date.substring(0, 10) : '',
|
||||
pedimento_date: datesData?.pedimento_date ? datesData.pedimento_date.substring(0, 10) : '',
|
||||
extraction_date: datesData?.extraction_date ? datesData.extraction_date.substring(0, 10) : '',
|
||||
rectification_payment_date: datesData?.rectification_payment_date ? datesData.rectification_payment_date.substring(0, 10) : '',
|
||||
original_date: datesData?.original_date ? datesData.original_date.substring(0, 10) : '',
|
||||
payment_date: datesData?.payment_date ? datesData.payment_date.substring(0, 10) : '',
|
||||
// Campos de captura automática
|
||||
fecha_captura: currentDate,
|
||||
hora_captura: currentTime
|
||||
// Date fields - Cargamos convirtiendo a local para el usuario
|
||||
entry_date: loadServerDate(datesData?.entry_date) || currentDate,
|
||||
end_date: loadServerDate(datesData?.end_date) || end_date,
|
||||
payment_date: loadServerDate(datesData?.payment_date) || payment_date,
|
||||
pedimento_date: loadServerDate(datesData?.pedimento_date),
|
||||
extraction_date: loadServerDate(datesData?.extraction_date),
|
||||
rectification_payment_date: loadServerDate(datesData?.rectification_payment_date),
|
||||
original_date: loadServerDate(datesData?.original_date),
|
||||
// Campos de captura automática (Local)
|
||||
fecha_captura: currentDate,
|
||||
hora_captura: currentTime
|
||||
};
|
||||
}
|
||||
|
||||
@@ -265,24 +277,6 @@
|
||||
}
|
||||
});
|
||||
|
||||
const statusOptions = [
|
||||
{ value: 'MODIFICABLE', label: 'Modificable' },
|
||||
{ value: 'ESPERA FIRMA PREVIO', label: 'Espera de firma previo' },
|
||||
{ value: 'ESPERA VALIDACION', label: 'Espera validacion' },
|
||||
{ value: 'VALIDADO', label: 'Validado' },
|
||||
{ value: 'ESPERA BORRAR FIRMA PREVIO', label: 'Espera borrar firma previo' },
|
||||
{ value: 'ESPERA BORRAR FIRMA VALIDACION', label: 'Espera borrar firma validacion ' },
|
||||
{ value: 'ESPERA PAGO', label: 'Espera pago' },
|
||||
{ value: 'CON FIRMA DE PREVIO', label: 'Con firma de previo' },
|
||||
{ value: 'F DE PREVIO BORRADA', label: 'Forma de previo borrada' },
|
||||
{ value: 'F VALIDACION BORRADA', label: 'Forma validacion borrada' },
|
||||
{ value: 'PAGADO', label: 'Pagado' },
|
||||
{ value: 'DESISTIO', label: 'Desistio' },
|
||||
{ value: 'ESPERA CARTA CUPO', label: 'Espera carta cupo' },
|
||||
{ value: 'CARTA CUPO', label: 'Carta cupo' },
|
||||
{ value: 'ESPERA CANCELAR CARTA CUPO', label: 'Espera cancelar carta cupo' }
|
||||
];
|
||||
|
||||
const pedimentoTypeOptions = [
|
||||
{ value: 'automobile', label: 'Automóvil' },
|
||||
{ value: 'complementary', label: 'Complementario' },
|
||||
@@ -301,10 +295,27 @@
|
||||
|
||||
<Card.Root>
|
||||
<Card.Header>
|
||||
<Card.Title>Información General</Card.Title>
|
||||
<Card.Description>
|
||||
Edita los datos principales del pedimento
|
||||
</Card.Description>
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<div class="space-y-1">
|
||||
<Card.Title>Información General</Card.Title>
|
||||
<Card.Description>
|
||||
Edita los datos principales del pedimento
|
||||
</Card.Description>
|
||||
</div>
|
||||
|
||||
<!-- Captura Info Badge -->
|
||||
<div class="flex flex-row items-center gap-4 text-sm text-muted-foreground bg-secondary/50 px-3 py-2 rounded-md border border-border/40">
|
||||
<div class="flex items-center gap-2" title="Fecha de Captura">
|
||||
<Calendar class="h-4 w-4 text-primary/70" />
|
||||
<span class="font-medium tabular-nums">{formData.fecha_captura}</span>
|
||||
</div>
|
||||
<div class="w-px h-4 bg-border"></div>
|
||||
<div class="flex items-center gap-2" title="Hora de Captura">
|
||||
<Clock class="h-4 w-4 text-primary/70" />
|
||||
<span class="font-medium tabular-nums">{formData.hora_captura}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Card.Header>
|
||||
<Card.Content>
|
||||
<div class="space-y-6">
|
||||
@@ -457,7 +468,7 @@
|
||||
|
||||
<!-- Tipo de Operación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="operation_type">Tipo de Operación</Label>
|
||||
<Label for="operation_type">Tipo de Operación <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type || ''}
|
||||
@@ -564,27 +575,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
|
||||
<!-- Estado -->
|
||||
<div class="space-y-2">
|
||||
<Label for="status">Estado <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.status || ''}
|
||||
onValueChange={(v: string) => formData.status = v ?? ''}
|
||||
>
|
||||
<Select.Trigger class="w-full">
|
||||
{statusOptions.find(o => o.value === formData.status)?.label || 'Seleccionar...'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
{#each statusOptions as option}
|
||||
<Select.Item value={option.value} label={option.label} />
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<!-- Valor USD -->
|
||||
@@ -654,33 +645,7 @@
|
||||
bind:value={formData.es}
|
||||
placeholder="0"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Captura -->
|
||||
<div class="space-y-2">
|
||||
<Label for="fecha_captura">Fecha de Captura</Label>
|
||||
<Input
|
||||
id="fecha_captura"
|
||||
type="date"
|
||||
bind:value={formData.fecha_captura}
|
||||
readonly
|
||||
disabled
|
||||
class="bg-muted cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Hora de Captura -->
|
||||
<div class="space-y-2">
|
||||
<Label for="hora_captura">Hora de Captura</Label>
|
||||
<Input
|
||||
id="hora_captura"
|
||||
type="time"
|
||||
bind:value={formData.hora_captura}
|
||||
readonly
|
||||
disabled
|
||||
class="bg-muted cursor-not-allowed"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Lista de navegación rápida -->
|
||||
@@ -751,6 +716,28 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha Fin (Solo Consolidado) -->
|
||||
{#if formData.pedimento_type === 'consolidated'}
|
||||
<div class="space-y-2">
|
||||
<Label for="end_date">Fecha Fin <span class="text-red-500">*</span></Label>
|
||||
<Input
|
||||
id="end_date"
|
||||
type="date"
|
||||
bind:value={formData.end_date}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Fecha de Pago -->
|
||||
<div class="space-y-2">
|
||||
<Label for="payment_date">Fecha de Pago <span class="text-red-500">*</span></Label>
|
||||
<Input
|
||||
id="payment_date"
|
||||
type="date"
|
||||
bind:value={formData.payment_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Presentación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="pedimento_date">Fecha de Presentación</Label>
|
||||
@@ -771,15 +758,17 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago Rectificación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="rectification_payment_date">Fecha de Pago R1</Label>
|
||||
<Input
|
||||
id="rectification_payment_date"
|
||||
type="date"
|
||||
bind:value={formData.rectification_payment_date}
|
||||
/>
|
||||
</div>
|
||||
{#if formData.pedimento_code === 'R1'}
|
||||
<!-- Fecha de Pago Rectificación -->
|
||||
<div class="space-y-2">
|
||||
<Label for="rectification_payment_date">Fecha de Pago R1</Label>
|
||||
<Input
|
||||
id="rectification_payment_date"
|
||||
type="date"
|
||||
bind:value={formData.rectification_payment_date}
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<!-- Fecha Original -->
|
||||
<div class="space-y-2">
|
||||
@@ -789,17 +778,7 @@
|
||||
type="date"
|
||||
bind:value={formData.original_date}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Fecha de Pago -->
|
||||
<div class="space-y-2">
|
||||
<Label for="payment_date">Fecha de Pago <span class="text-red-500">*</span></Label>
|
||||
<Input
|
||||
id="payment_date"
|
||||
type="date"
|
||||
bind:value={formData.payment_date}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{:else if activeSection === 'incrementables'}
|
||||
<!-- Incrementables -->
|
||||
|
||||
75
frontend/src/lib/date-utils.ts
Normal file
75
frontend/src/lib/date-utils.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
import {
|
||||
getLocalTimeZone,
|
||||
parseDate,
|
||||
parseTime,
|
||||
toCalendarDateTime,
|
||||
fromDate,
|
||||
now,
|
||||
today
|
||||
} from '@internationalized/date';
|
||||
|
||||
const localTimeZone = getLocalTimeZone();
|
||||
|
||||
/**
|
||||
* Convierte fecha local (string input YYYY-MM-DD) + hora (HH:MM) a UTC ISO string.
|
||||
* Útil para enviar datos al backend que espera timestamps absolutos.
|
||||
*/
|
||||
export function prepareDateForBackend(dateStr: string, timeStr: string = '00:00'): string | null {
|
||||
if (!dateStr) return null;
|
||||
try {
|
||||
const date = parseDate(dateStr);
|
||||
const time = parseTime(timeStr);
|
||||
// Combinar fecha y hora usando la zona horaria local
|
||||
const dateTime = toCalendarDateTime(date, time);
|
||||
const zonedDateTime = dateTime.toDate(localTimeZone);
|
||||
return zonedDateTime.toISOString();
|
||||
} catch (e) {
|
||||
console.error('Error parsing date:', e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convertir fechas que vienen del servidor (ISO UTC) a fecha local del calendario (YYYY-MM-DD string).
|
||||
* Útil para poblar inputs type="date".
|
||||
*/
|
||||
export function loadServerDate(isoStr: string | null | undefined): string {
|
||||
if (!isoStr) return '';
|
||||
try {
|
||||
// Si incluye T es ISO completo, convertir a zona local
|
||||
if (isoStr.includes('T')) {
|
||||
const dateObj = new Date(isoStr);
|
||||
return fromDate(dateObj, localTimeZone).toString();
|
||||
}
|
||||
// Si no, asumir fecha plana YYYY-MM-DD
|
||||
return isoStr.substring(0, 10);
|
||||
} catch {
|
||||
return isoStr || '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sumar días de forma segura con calendario y devolver string YYYY-MM-DD.
|
||||
*/
|
||||
export function addDaysLocal(dateStr: string, days: number): string {
|
||||
if (!dateStr) return '';
|
||||
try {
|
||||
return parseDate(dateStr).add({ days }).toString();
|
||||
} catch {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
export function getCurrentLocalYear(): string {
|
||||
const nowZoned = now(localTimeZone);
|
||||
return String(nowZoned.year).slice(-2);
|
||||
}
|
||||
|
||||
export function getCurrentLocalDate(): string {
|
||||
return today(localTimeZone).toString();
|
||||
}
|
||||
|
||||
export function getCurrentLocalTime(): string {
|
||||
const nowZoned = now(localTimeZone);
|
||||
return `${String(nowZoned.hour).padStart(2, '0')}:${String(nowZoned.minute).padStart(2, '0')}`;
|
||||
}
|
||||
Reference in New Issue
Block a user