Se mejoro el disenio de agentes y clientes-proveedores
This commit is contained in:
@@ -33,22 +33,50 @@
|
||||
|
||||
// Cargar datos al abrir
|
||||
$effect(() => {
|
||||
if (open && !loaded) {
|
||||
if (open) {
|
||||
loadCountries();
|
||||
}
|
||||
});
|
||||
|
||||
async function loadCountries() {
|
||||
loading = true;
|
||||
console.log("Cargando países...");
|
||||
try {
|
||||
const response = await countriesApi.list(1, 300);
|
||||
console.log("Respuesta países FULL:", response);
|
||||
|
||||
if (response.data?.items) {
|
||||
// Caso 1: Estructura esperada { data: { items: [...] } }
|
||||
if (response.data?.items && Array.isArray(response.data.items)) {
|
||||
items = response.data.items;
|
||||
loaded = true;
|
||||
} else {
|
||||
console.warn("No se encontraron países:", response);
|
||||
}
|
||||
// Caso 2: El backend devuelve el array directamente en data { data: [...] }
|
||||
else if (Array.isArray(response.data)) {
|
||||
items = response.data;
|
||||
loaded = true;
|
||||
}
|
||||
// Caso 3: La respuesta en sí es el array (poco probable con el wrapper actual pero posible si algo falla antes)
|
||||
else if (Array.isArray(response)) {
|
||||
items = response;
|
||||
loaded = true;
|
||||
}
|
||||
// Caso 4: data es el objeto paginado pero sin la propiedad items correcta o vacía
|
||||
else if (response.data && typeof response.data === 'object') {
|
||||
// Intentar buscar alguna propiedad que sea array
|
||||
const possibleArray = Object.values(response.data).find(val => Array.isArray(val));
|
||||
if (possibleArray) {
|
||||
items = possibleArray as Country[];
|
||||
loaded = true;
|
||||
} else {
|
||||
console.warn("Estructura de datos no reconocida en countriesApi.list:", response.data);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.warn("No se encontraron países o formato incorrecto:", response);
|
||||
}
|
||||
|
||||
console.log(`Países cargados: ${items.length}`);
|
||||
|
||||
} catch (e) {
|
||||
console.error("Error cargando países:", e);
|
||||
} finally {
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
import {
|
||||
ArrowLeft, LoaderCircle, Save, Package, DollarSign,
|
||||
FileText, Settings, Image as ImageIcon, FolderSearch,
|
||||
UserCheck, CheckCircle2, XCircle, Tag, Layers, Scale, Info, Briefcase, ShieldCheck
|
||||
UserCheck, CheckCircle2, XCircle, Tag, Layers, Scale, Info, Briefcase, ShieldCheck, Globe
|
||||
} from 'lucide-svelte';
|
||||
|
||||
// Stores & APIs
|
||||
@@ -141,7 +141,6 @@
|
||||
alternate_unit_measure: d.inv_data?.alternate_uom || '',
|
||||
part_photo: d.part_photo || '',
|
||||
is_active: d.is_active ?? true,
|
||||
// Cargar datos FA si existen
|
||||
sector: d.fa_data?.sector || '',
|
||||
fraction_type: d.fa_data?.fraction_type || ''
|
||||
};
|
||||
@@ -193,7 +192,7 @@
|
||||
function handleUOMSelect(item: any) { formData.unit_of_measure = item.code; }
|
||||
function handleAltUOMSelect(item: any) { formData.alternate_unit_measure = item.code; }
|
||||
function handleCurrencySelect(currency: any) {
|
||||
formData.currency_type = ''; // Catálogo no usa currency_type
|
||||
formData.currency_type = '';
|
||||
formData.currency_key = currency.currency_type_code;
|
||||
selectedCurrencyName = currency.currency_type_code;
|
||||
}
|
||||
@@ -210,52 +209,35 @@
|
||||
|
||||
loading = true;
|
||||
try {
|
||||
// Construimos el payload.
|
||||
let commonData: any = { ...formData };
|
||||
|
||||
// Si currency_key está vacío o es el default, ponerlo en null
|
||||
if (!commonData.currency_key || commonData.currency_key === 'USD') {
|
||||
commonData.currency_key = null;
|
||||
}
|
||||
|
||||
if (formType === 'fa') {
|
||||
// Crear fa_data con los campos específicos de FA
|
||||
commonData.fa_data = {
|
||||
sector: formData.sector,
|
||||
fraction_type: formData.fraction_type,
|
||||
origin_country: formData.origin_country
|
||||
};
|
||||
// IMPORTANTE: Eliminar estos campos del nivel raíz para evitar duplicados
|
||||
delete commonData.sector;
|
||||
delete commonData.fraction_type;
|
||||
delete commonData.origin_country;
|
||||
}
|
||||
|
||||
// DEBUG: Ver qué se está enviando
|
||||
console.log('Payload que se enviará:', JSON.stringify(commonData, null, 2));
|
||||
console.log('client_id:', formData.client_id);
|
||||
console.log('selectedClientName:', selectedClientName);
|
||||
|
||||
if (isEdit && partId) {
|
||||
await partsApi.update(partId, commonData, activeCompanyId);
|
||||
} else {
|
||||
const result = await partsApi.create({ ...commonData, company_id: activeCompanyId }, activeCompanyId);
|
||||
console.log('Resultado de creación:', result);
|
||||
if (result.error) {
|
||||
console.error('Error del backend:', result.error);
|
||||
error = result.error;
|
||||
return;
|
||||
}
|
||||
if (result.error) { error = result.error; return; }
|
||||
}
|
||||
goto('/dashboard/goods/parts');
|
||||
} catch (e: any) {
|
||||
console.error('Error completo:', e);
|
||||
error = e.message || 'Error al guardar';
|
||||
} finally { loading = false; }
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="space-y-3">
|
||||
<div class="space-y-4">
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="space-y-1">
|
||||
<div class="flex items-center gap-3">
|
||||
@@ -267,8 +249,8 @@
|
||||
{isEdit ? "Editar" : "Nueva"}
|
||||
</Badge>
|
||||
</div>
|
||||
<p class="text-muted-foreground">
|
||||
{formType === 'fa' ? 'Activo Fijo' : 'Inventario'}
|
||||
<p class="text-muted-foreground ml-11">
|
||||
{formType === 'fa' ? 'Gestión de Activo Fijo' : 'Gestión de Inventario'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -276,7 +258,7 @@
|
||||
<Separator />
|
||||
|
||||
{#if error}
|
||||
<div class="p-4 rounded-md bg-destructive/10 text-destructive border border-destructive/20 text-sm font-medium">
|
||||
<div class="p-4 rounded-md bg-destructive/10 text-destructive border border-destructive/20 text-sm font-medium animate-in slide-in-from-top-2">
|
||||
⚠️ {error}
|
||||
</div>
|
||||
{/if}
|
||||
@@ -285,101 +267,114 @@
|
||||
|
||||
{#if formType === 'fa'}
|
||||
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-6">
|
||||
<Card.Root>
|
||||
<Card.Root class="shadow-sm">
|
||||
<Card.Content class="p-6">
|
||||
<Tabs.Root bind:value={activeTab} class="w-full">
|
||||
|
||||
<div class="min-h-[500px]">
|
||||
|
||||
<Tabs.Content value="general" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<Tabs.Content value="general" class="space-y-8 pt-6 animate-in fade-in duration-300">
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_pn" class="text-base font-semibold required">Número de Parte</Label>
|
||||
<Input id="fa_pn" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="text-lg font-mono" placeholder="Ej: MAQ-001"/>
|
||||
<div class="relative">
|
||||
<Package class="absolute left-3 top-2.5 h-5 w-5 text-muted-foreground" />
|
||||
<Input id="fa_pn" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="pl-10 text-lg font-mono bg-muted/20" placeholder="Ej: MAQ-001"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_client" class="required">Cliente Asignado</Label>
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_client" class="text-base font-semibold required">Cliente Asignado</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_client" bind:value={selectedClientName} readonly onclick={() => showClientModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showClientModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<div class="relative w-full">
|
||||
<UserCheck class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="fa_client" bind:value={selectedClientName} readonly onclick={() => showClientModal = true} class="pl-9 cursor-pointer hover:bg-muted/50 transition-colors" placeholder="Seleccione un cliente..."/>
|
||||
</div>
|
||||
<Button variant="secondary" size="icon" type="button" onclick={() => showClientModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_desc_es">Descripción Español</Label>
|
||||
<Textarea id="fa_desc_es" bind:value={formData.description_spanish} rows={2}/>
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_desc_es" class="flex items-center gap-2">Descripción Español <span class="text-xs text-muted-foreground font-normal">(Requerido)</span></Label>
|
||||
<Textarea id="fa_desc_es" bind:value={formData.description_spanish} rows={3} class="resize-none" placeholder="Descripción detallada en español..."/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_desc_en">Descripción Inglés</Label>
|
||||
<Textarea id="fa_desc_en" bind:value={formData.description_english} rows={2}/>
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_desc_en" class="flex items-center gap-2">Descripción Inglés</Label>
|
||||
<Textarea id="fa_desc_en" bind:value={formData.description_english} rows={3} class="resize-none" placeholder="English description..."/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4 p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/30">
|
||||
<div class="grid gap-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="fa_class" class="required">Clase</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_class" bind:value={formData.part_class} readonly onclick={() => showClassModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showClassModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<Input id="fa_class" bind:value={formData.part_class} readonly onclick={() => showClassModal = true} class="cursor-pointer font-mono" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showClassModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
{#if selectedClassDesc}<div class="text-xs text-muted-foreground">{selectedClassDesc}</div>{/if}
|
||||
{#if selectedClassDesc}<p class="text-[11px] text-muted-foreground truncate px-1">{selectedClassDesc}</p>{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="fa_uom" class="required">Unidad Medida</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_uom" bind:value={formData.unit_of_measure} readonly onclick={() => showUOMModal = true} class="cursor-pointer" placeholder="PZ"/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showUOMModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<div class="relative w-full">
|
||||
<Scale class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="fa_uom" bind:value={formData.unit_of_measure} readonly onclick={() => showUOMModal = true} class="pl-9 cursor-pointer font-mono" placeholder="PZ"/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showUOMModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_origin">País Origen (ISO)</Label>
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="fa_origin">País Origen</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_origin" bind:value={selectedCountryName} readonly onclick={() => showCountryModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showCountryModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<div class="relative w-full">
|
||||
<Globe class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="fa_origin" bind:value={selectedCountryName} readonly onclick={() => showCountryModal = true} class="pl-9 cursor-pointer" placeholder="Seleccione..."/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showCountryModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg bg-green-50/50 dark:bg-green-900/10 space-y-4">
|
||||
<h3 class="font-medium text-sm text-green-800 dark:text-green-300 flex items-center gap-2"><DollarSign class="h-4 w-4"/> Costos y Pesos</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<div class="p-5 border rounded-xl bg-slate-50 dark:bg-slate-900/30 space-y-4">
|
||||
<h3 class="font-semibold text-sm text-primary flex items-center gap-2">
|
||||
<DollarSign class="h-4 w-4"/> Información Financiera y Pesos
|
||||
</h3>
|
||||
<Separator class="bg-primary/10" />
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 pt-2">
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="fa_cost">Costo Unitario</Label>
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground">$</span>
|
||||
<Input type="number" step="0.0001" id="fa_cost" bind:value={formData.unit_cost} class="pl-7" />
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground font-semibold">$</span>
|
||||
<Input type="number" step="0.0001" id="fa_cost" bind:value={formData.unit_cost} class="pl-7" placeholder="0.0000" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label>Moneda</Label>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="fa_currency_type" value="NA" bind:group={formData.currency_type} class="h-4 w-4" />
|
||||
<span class="text-sm">Nacional</span>
|
||||
<div class="space-y-2">
|
||||
<div class="flex gap-4 mb-2">
|
||||
<label class="text-sm flex items-center gap-2 cursor-pointer hover:text-primary transition-colors">
|
||||
<input type="radio" name="fa_currency_type" value="NA" bind:group={formData.currency_type} class="accent-primary" /> Nacional
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="fa_currency_type" value="EX" bind:group={formData.currency_type} class="h-4 w-4" />
|
||||
<span class="text-sm">Extranjera</span>
|
||||
<label class="text-sm flex items-center gap-2 cursor-pointer hover:text-primary transition-colors">
|
||||
<input type="radio" name="fa_currency_type" value="EX" bind:group={formData.currency_type} class="accent-primary" /> Extranjera
|
||||
</label>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" type="button" onclick={() => { formData.currency_type = 'CATALOG'; showCurrencyModal = true; }} class="w-full">
|
||||
<FolderSearch class="h-4 w-4 mr-2" />
|
||||
{selectedCurrencyName || 'Seleccionar del Catálogo'}
|
||||
<Button variant="outline" size="sm" type="button" onclick={() => { formData.currency_type = 'CATALOG'; showCurrencyModal = true; }} class="w-full justify-between font-normal">
|
||||
<span class="flex items-center gap-2"><FolderSearch class="h-3.5 w-3.5" /> {selectedCurrencyName || 'Catálogo'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="fa_weight">Peso Unitario</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input type="number" step="0.0001" id="fa_weight" bind:value={formData.unit_weight} placeholder="0.0000" />
|
||||
<Select.Root type="single" bind:value={formData.weight_type}>
|
||||
<Select.Trigger class="w-[80px]">{formData.weight_type}</Select.Trigger>
|
||||
<Select.Trigger class="w-[85px]">{formData.weight_type}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="KG">KG</Select.Item>
|
||||
<Select.Item value="LB">LB</Select.Item>
|
||||
@@ -390,88 +385,102 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 p-4 border rounded-lg">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2"><Briefcase class="h-4 w-4"/> Datos Aduaneros</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<div class="p-5 border rounded-xl space-y-4">
|
||||
<h3 class="font-semibold text-sm text-muted-foreground flex items-center gap-2">
|
||||
<Briefcase class="h-4 w-4"/> Clasificación Aduanera
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_fraction">Fracción UMT (MX)</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_fraction" bind:value={formData.fraction} readonly onclick={() => showFractionModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showFractionModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<Input id="fa_fraction" bind:value={formData.fraction} readonly onclick={() => showFractionModal = true} class="cursor-pointer font-mono" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showFractionModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_us_fraction">Fracción Americana</Label>
|
||||
<Input id="fa_us_fraction" bind:value={formData.us_fraction} maxlength={10} class="font-mono" placeholder="HTS Code"/>
|
||||
</div>
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_sector">Sector</Label>
|
||||
<Input id="fa_sector" bind:value={formData.sector} placeholder="Ej: Automotriz"/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="fa_fraction_type">Tipo Tarifa</Label>
|
||||
<Input id="fa_fraction_type" bind:value={formData.fraction_type} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_us_fraction">Fracción Americana</Label>
|
||||
<Input id="fa_us_fraction" bind:value={formData.us_fraction} maxlength={10} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center gap-3 pt-2">
|
||||
<div class="flex items-center gap-3 pt-2 pl-1">
|
||||
<Switch id="fa_is_active" bind:checked={formData.is_active} />
|
||||
<Label for="fa_is_active">Activo en sistema</Label>
|
||||
<Label for="fa_is_active" class="cursor-pointer">Parte activa en sistema</Label>
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="cont1" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<div class="p-6 border rounded-lg space-y-4">
|
||||
<div class="grid gap-4 max-w-lg mx-auto">
|
||||
<Label for="fa_photo" class="text-left flex items-center gap-2">
|
||||
<ImageIcon class="h-4 w-4"/> URL Imagen de la parte
|
||||
<Tabs.Content value="cont1" class="space-y-6 pt-6 animate-in fade-in duration-300">
|
||||
<div class="p-6 border rounded-xl space-y-4">
|
||||
<div class="max-w-2xl mx-auto space-y-4">
|
||||
<Label for="fa_photo" class="flex items-center gap-2 text-base">
|
||||
<ImageIcon class="h-5 w-5"/> URL Imagen de la parte
|
||||
</Label>
|
||||
<Input id="fa_photo" bind:value={formData.part_photo} maxlength={255} placeholder="https://ejemplo.com/imagen.jpg" />
|
||||
<div class="flex gap-2">
|
||||
<Input id="fa_photo" bind:value={formData.part_photo} maxlength={255} placeholder="https://ejemplo.com/imagen.jpg" />
|
||||
<Button variant="outline" class="shrink-0">Vista Previa</Button>
|
||||
</div>
|
||||
{#if formData.part_photo}
|
||||
<div class="mt-4 aspect-video rounded-lg bg-muted flex items-center justify-center border overflow-hidden">
|
||||
<img src={formData.part_photo} alt="Vista previa" class="h-full w-full object-contain" />
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="cont2" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="space-y-4 p-4 border rounded-lg">
|
||||
<Tabs.Content value="cont2" class="space-y-6 pt-6 animate-in fade-in duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div class="p-5 border rounded-xl space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2"><ShieldCheck class="h-4 w-4"/> Control de Exportación</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_lic">License Code</Label>
|
||||
<Input id="fa_lic" bind:value={formData.license_code} maxlength={3} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_exp">Export Code</Label>
|
||||
<Input id="fa_exp" bind:value={formData.export_code} maxlength={2} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_eccn">ECCN</Label>
|
||||
<Input id="fa_eccn" bind:value={formData.eccn} maxlength={20} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_exc">Símbolo Excepción Licencia</Label>
|
||||
<Input id="fa_exc" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
<div class="grid gap-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_lic">License Code</Label>
|
||||
<Input id="fa_lic" bind:value={formData.license_code} maxlength={3} class="font-mono" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_exp">Export Code</Label>
|
||||
<Input id="fa_exp" bind:value={formData.export_code} maxlength={2} class="font-mono" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_eccn">ECCN</Label>
|
||||
<Input id="fa_eccn" bind:value={formData.eccn} maxlength={20} class="font-mono" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_exc">Símbolo Excepción Licencia</Label>
|
||||
<Input id="fa_exc" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4 p-4 border rounded-lg">
|
||||
<div class="p-5 border rounded-xl space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2"><Info class="h-4 w-4"/> Regulaciones Adicionales</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_fda">Clave FDA</Label>
|
||||
<Input id="fa_fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="fa_fcc">Clave FCC</Label>
|
||||
<Input id="fa_fcc" bind:value={formData.fcc_key} maxlength={30} />
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_fda">Clave FDA</Label>
|
||||
<Input id="fa_fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="fa_fcc">Clave FCC</Label>
|
||||
<Input id="fa_fcc" bind:value={formData.fcc_key} maxlength={30} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
</div>
|
||||
|
||||
</Tabs.Root>
|
||||
</Card.Content>
|
||||
</Card.Root>
|
||||
@@ -479,122 +488,109 @@
|
||||
|
||||
{:else}
|
||||
<form onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-6">
|
||||
<Card.Root>
|
||||
<Card.Root class="shadow-sm">
|
||||
<Card.Content class="p-6">
|
||||
<Tabs.Root bind:value={activeTab} class="w-full">
|
||||
|
||||
<div class="min-h-[500px]">
|
||||
|
||||
<Tabs.Content value="general" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<Tabs.Content value="general" class="space-y-8 pt-6 animate-in fade-in duration-300">
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="part_number" class="text-base font-semibold required">Número de Parte</Label>
|
||||
<Input id="part_number" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="text-lg font-mono" placeholder="Ej: 123-ABC-456"/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 p-4 border rounded-lg bg-slate-50 dark:bg-slate-900/30">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2">
|
||||
<FileText class="h-4 w-4"/> Descripción
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="desc_es">Español</Label>
|
||||
<Textarea id="desc_es" bind:value={formData.description_spanish} maxlength={500} rows={3}/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="desc_en">Inglés</Label>
|
||||
<Textarea id="desc_en" bind:value={formData.description_english} maxlength={500} rows={3}/>
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="part_number" class="text-base font-semibold required">Número de Parte</Label>
|
||||
<div class="relative">
|
||||
<Package class="absolute left-3 top-2.5 h-5 w-5 text-muted-foreground" />
|
||||
<Input id="part_number" bind:value={formData.part_number} disabled={isEdit} maxlength={50} class="pl-10 text-lg font-mono bg-muted/20" placeholder="Ej: 123-ABC-456"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="part_class_client" class="required">Clase (Anexo 24 - Cliente)</Label>
|
||||
<div class="p-5 border rounded-xl bg-slate-50 dark:bg-slate-900/30 space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground flex items-center gap-2">
|
||||
<FileText class="h-4 w-4"/> Descripción de Mercancía
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="desc_es">Español <span class="text-xs text-muted-foreground font-normal ml-1">(Principal)</span></Label>
|
||||
<Textarea id="desc_es" bind:value={formData.description_spanish} maxlength={500} rows={3} class="bg-background"/>
|
||||
</div>
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="desc_en">Inglés</Label>
|
||||
<Textarea id="desc_en" bind:value={formData.description_english} maxlength={500} rows={3} class="bg-background"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="part_class_client" class="required">Clase (Anexo 24)</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative flex-1">
|
||||
<div class="absolute left-3 top-2.5 text-muted-foreground">
|
||||
<Package class="h-4 w-4" />
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<Tag class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="part_class_client" bind:value={formData.part_class} maxlength={8} placeholder="Seleccione Clase..." class="pl-9 font-mono cursor-pointer" readonly onclick={() => showClassModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showClassModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showClassModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
{#if selectedClassDesc}<div class="text-xs text-primary font-medium px-1 flex items-center gap-1"><Tag class="h-3 w-3" />{selectedClassDesc}</div>{/if}
|
||||
{#if selectedClassDesc}<p class="text-[11px] text-primary font-medium px-1">{selectedClassDesc}</p>{/if}
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<Label for="part_class_material">Tipo Material (Catálogo General)</Label>
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="part_class_material">Tipo Material <span class="text-xs text-muted-foreground font-normal ml-1">(Catálogo General)</span></Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative flex-1">
|
||||
<div class="absolute left-3 top-2.5 text-muted-foreground">
|
||||
<Layers class="h-4 w-4" />
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<Layers class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="part_class_material" bind:value={formData.material_type} maxlength={8} placeholder="Seleccione Material..." class="pl-9 font-mono cursor-pointer" readonly onclick={() => showMaterialModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showMaterialModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showMaterialModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
{#if selectedMaterialDesc}<div class="text-xs text-blue-600 font-medium px-1 flex items-center gap-1"><Layers class="h-3 w-3" />{selectedMaterialDesc}</div>{/if}
|
||||
<p class="text-[10px] text-muted-foreground">Opcional: Clasificación adicional por tipo de material.</p>
|
||||
{#if selectedMaterialDesc}<p class="text-[11px] text-blue-600 font-medium px-1">{selectedMaterialDesc}</p>{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="country">País Origen (ISO)</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="country" bind:value={selectedCountryName} readonly onclick={() => showCountryModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showCountryModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<div class="relative w-full">
|
||||
<Globe class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="country" bind:value={selectedCountryName} readonly onclick={() => showCountryModal = true} class="pl-9 cursor-pointer" placeholder="Seleccione..."/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showCountryModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="uom" class="required">Unidad de Medida (TIGIE)</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative flex-1">
|
||||
<div class="absolute left-3 top-2.5 text-muted-foreground">
|
||||
<Scale class="h-4 w-4" />
|
||||
</div>
|
||||
<div class="relative w-full">
|
||||
<Scale class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="uom" bind:value={formData.unit_of_measure} placeholder="Seleccione..." class="pl-9 font-mono cursor-pointer" readonly onclick={() => showUOMModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showUOMModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showUOMModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-lg bg-green-50/50 dark:bg-green-900/10 space-y-4">
|
||||
<h3 class="font-medium text-sm text-green-800 dark:text-green-300 flex items-center gap-2"><DollarSign class="h-4 w-4"/> Costos, valores y peso unitario</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label>Tipos de Moneda</Label>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex items-center gap-4">
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="inv_currency_type" value="NA" bind:group={formData.currency_type} class="h-4 w-4" />
|
||||
<span class="text-sm">Nacional</span>
|
||||
</label>
|
||||
<label class="flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="inv_currency_type" value="EX" bind:group={formData.currency_type} class="h-4 w-4" />
|
||||
<span class="text-sm">Extranjera</span>
|
||||
</label>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" type="button" onclick={() => { formData.currency_type = 'CATALOG'; showCurrencyModal = true; }} class="w-full">
|
||||
<FolderSearch class="h-4 w-4 mr-2" />
|
||||
{selectedCurrencyName || 'Seleccionar del Catálogo'}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="p-5 border rounded-xl bg-slate-50 dark:bg-slate-900/30 space-y-6">
|
||||
<h3 class="font-medium text-sm text-green-700 dark:text-green-400 flex items-center gap-2">
|
||||
<DollarSign class="h-4 w-4"/> Costos y Valor Agregado
|
||||
</h3>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="unit_cost">Costo Unitario</Label>
|
||||
<div class="relative">
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground">$</span>
|
||||
<Input type="number" step="0.0001" id="unit_cost" bind:value={formData.unit_cost} class="pl-7" />
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground font-semibold">$</span>
|
||||
<Input type="number" step="0.0001" id="unit_cost" bind:value={formData.unit_cost} class="pl-7 bg-background" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="unit_weight">Peso Unitario</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input type="number" step="0.0001" id="unit_weight" bind:value={formData.unit_weight} placeholder="0.0000" />
|
||||
<Input type="number" step="0.0001" id="unit_weight" bind:value={formData.unit_weight} placeholder="0.0000" class="bg-background"/>
|
||||
<Select.Root type="single" bind:value={formData.weight_type}>
|
||||
<Select.Trigger class="w-[100px]">{formData.weight_type}</Select.Trigger>
|
||||
<Select.Trigger class="w-[90px] bg-background">{formData.weight_type}</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="KG">KG</Select.Item>
|
||||
<Select.Item value="LB">LB</Select.Item>
|
||||
@@ -602,135 +598,177 @@
|
||||
</Select.Root>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 p-4 border rounded-lg">
|
||||
<Label class="font-semibold">Tipo Valor Agregado</Label>
|
||||
<div class="flex flex-wrap gap-6">
|
||||
<div class="flex items-center space-x-2">
|
||||
<input type="radio" id="va_ext" name="va_type" value="USD" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_ext" class="font-normal cursor-pointer">Extranjera (Dls)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<input type="radio" id="va_nac" name="va_type" value="MXN" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_nac" class="font-normal cursor-pointer">Nacional (Pesos)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2">
|
||||
<input type="radio" id="va_pct" name="va_type" value="PERCENT" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_pct" class="font-normal cursor-pointer">Porcentaje</Label>
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label>Moneda</Label>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="flex gap-4">
|
||||
<label class="text-xs flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="inv_currency_type" value="NA" bind:group={formData.currency_type} class="accent-green-600" /> Nacional
|
||||
</label>
|
||||
<label class="text-xs flex items-center gap-2 cursor-pointer">
|
||||
<input type="radio" name="inv_currency_type" value="EX" bind:group={formData.currency_type} class="accent-green-600" /> Extranjera
|
||||
</label>
|
||||
</div>
|
||||
<Button variant="outline" size="sm" type="button" onclick={() => { formData.currency_type = 'CATALOG'; showCurrencyModal = true; }} class="w-full justify-between bg-background">
|
||||
<span class="flex items-center gap-2 text-xs"><FolderSearch class="h-3 w-3" /> {selectedCurrencyName || 'Catálogo'}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2 mt-2">
|
||||
<div class="relative max-w-xs">
|
||||
{#if formData.value_added_type === 'PERCENT'}
|
||||
<span class="absolute right-3 top-2.5 text-muted-foreground">%</span>
|
||||
{:else}
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground">$</span>
|
||||
{/if}
|
||||
<Input type="number" step="0.0001" id="added_value" bind:value={formData.added_value} class={formData.value_added_type === 'PERCENT' ? 'pr-7' : 'pl-7'} placeholder="0.00"/>
|
||||
|
||||
<Separator class="bg-border/60" />
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
|
||||
<div class="md:col-span-8 space-y-3">
|
||||
<Label class="font-semibold text-xs uppercase tracking-wider text-muted-foreground">Tipo Valor Agregado</Label>
|
||||
<div class="flex flex-wrap gap-6 pt-1">
|
||||
<div class="flex items-center space-x-2 bg-background px-3 py-1.5 rounded-md border shadow-sm">
|
||||
<input type="radio" id="va_ext" name="va_type" value="USD" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_ext" class="font-normal cursor-pointer text-sm">Extranjera (Dls)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 bg-background px-3 py-1.5 rounded-md border shadow-sm">
|
||||
<input type="radio" id="va_nac" name="va_type" value="MXN" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_nac" class="font-normal cursor-pointer text-sm">Nacional (Pesos)</Label>
|
||||
</div>
|
||||
<div class="flex items-center space-x-2 bg-background px-3 py-1.5 rounded-md border shadow-sm">
|
||||
<input type="radio" id="va_pct" name="va_type" value="PERCENT" bind:group={formData.value_added_type} class="accent-primary h-4 w-4 cursor-pointer" />
|
||||
<Label for="va_pct" class="font-normal cursor-pointer text-sm">Porcentaje</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="md:col-span-4 space-y-2">
|
||||
<Label for="added_value">Valor / Porcentaje</Label>
|
||||
<div class="relative">
|
||||
{#if formData.value_added_type === 'PERCENT'}
|
||||
<span class="absolute right-3 top-2.5 text-muted-foreground font-bold">%</span>
|
||||
{:else}
|
||||
<span class="absolute left-3 top-2.5 text-muted-foreground font-semibold">$</span>
|
||||
{/if}
|
||||
<Input type="number" step="0.0001" id="added_value" bind:value={formData.added_value} class="{formData.value_added_type === 'PERCENT' ? 'pr-8' : 'pl-7'} bg-background" placeholder="0.00"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2 pt-4 border-t">
|
||||
<Label for="frac_us">Fracción Americana (HTS)</Label>
|
||||
<Input id="frac_us" bind:value={formData.us_fraction} maxlength={16} placeholder="Ej: 8501.10.00" />
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-6 pt-4 border-t">
|
||||
<div class="md:col-span-6 space-y-2">
|
||||
<Label for="frac_us">Fracción Americana (HTS)</Label>
|
||||
<Input id="frac_us" bind:value={formData.us_fraction} maxlength={16} placeholder="Ej: 8501.10.00" class="font-mono"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="opciones" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<div class="space-y-4 p-4 border rounded-lg bg-card">
|
||||
<Tabs.Content value="opciones" class="space-y-6 pt-6 animate-in fade-in duration-300">
|
||||
<div class="p-6 border rounded-xl space-y-6">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Configuración General</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div class="grid gap-2">
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
||||
<div class="space-y-2">
|
||||
<Label for="fcc">Clave FCC</Label>
|
||||
<Input id="fcc" bind:value={formData.fcc_key} maxlength={30} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="space-y-2">
|
||||
<Label for="supplier">Proveedor (Textil)</Label>
|
||||
<Input id="supplier" bind:value={formData.supplier} maxlength={14} />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<div class="space-y-2">
|
||||
<Label for="photo" class="flex items-center gap-2"><ImageIcon class="h-4 w-4"/> URL Imagen de la parte</Label>
|
||||
<Input id="photo" bind:value={formData.part_photo} maxlength={255} placeholder="https://..." />
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="opcionales2" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<div class="p-4 border rounded-lg space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">FDA</h3>
|
||||
<div class="grid gap-2">
|
||||
<Label for="fda">Clave FDA</Label>
|
||||
<Input id="fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
<Tabs.Content value="opcionales2" class="space-y-6 pt-6 animate-in fade-in duration-300">
|
||||
<div class="p-6 border rounded-xl space-y-4">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Regulaciones Sanitarias</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2">
|
||||
<div class="space-y-2">
|
||||
<Label for="fda">Clave FDA</Label>
|
||||
<Input id="fda" bind:value={formData.fda_key} maxlength={20} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="otros" class="space-y-6 pt-4 animate-in fade-in duration-300">
|
||||
<div class="grid gap-2">
|
||||
<Label for="client_id" class="required">Cliente Asignado</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative flex-1">
|
||||
<UserCheck class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="client_id" bind:value={selectedClientName} class="pl-9" placeholder="Seleccione un cliente..." readonly onclick={() => showClientModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" class="shrink-0" type="button" onclick={() => showClientModal = true}><FolderSearch class="h-4 w-4 mr-2" /> Buscar</Button>
|
||||
</div>
|
||||
{#if selectedClientName}
|
||||
<div class="flex items-center gap-2 text-xs">
|
||||
{#if selectedClientStatus}<span class="text-green-600 flex items-center gap-1 font-medium"><CheckCircle2 class="h-3 w-3"/> Activo</span>{:else}<span class="text-red-600 flex items-center gap-1 font-medium"><XCircle class="h-3 w-3"/> Inactivo</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="comm_pn">Número de Parte Comercial</Label>
|
||||
<Input id="comm_pn" bind:value={formData.commercial_part_number} maxlength={70} />
|
||||
</div>
|
||||
<div class="p-4 border rounded-lg space-y-4">
|
||||
<Label for="alt_um">UM Conversión (Alterna)</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative flex-1">
|
||||
<div class="absolute left-3 top-2.5 text-muted-foreground"><Scale class="h-4 w-4" /></div>
|
||||
<Input id="alt_um" bind:value={formData.alternate_unit_measure} placeholder="Seleccione..." class="pl-9 font-mono cursor-pointer" readonly onclick={() => showAltUOMModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showAltUOMModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 border rounded-lg space-y-4 bg-slate-50 dark:bg-slate-900/30">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Datos Regulatorios</h3>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="fraction_mx" class="required">Fracción Arancelaria (MX)</Label>
|
||||
<Tabs.Content value="otros" class="space-y-6 pt-6 animate-in fade-in duration-300">
|
||||
<div class="grid grid-cols-1 md:grid-cols-12 gap-8">
|
||||
|
||||
<div class="md:col-span-6 space-y-6">
|
||||
<div class="space-y-2">
|
||||
<Label for="client_id" class="required">Cliente Asignado</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fraction_mx" bind:value={formData.fraction} readonly onclick={() => showFractionModal = true} class="cursor-pointer" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showFractionModal = true}><FolderSearch class="h-4 w-4" /></Button>
|
||||
<div class="relative w-full">
|
||||
<UserCheck class="absolute left-3 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input id="client_id" bind:value={selectedClientName} class="pl-9 cursor-pointer" placeholder="Seleccione un cliente..." readonly onclick={() => showClientModal = true}/>
|
||||
</div>
|
||||
<Button variant="outline" class="shrink-0" type="button" onclick={() => showClientModal = true}><FolderSearch class="h-4 w-4 mr-2" /> Buscar</Button>
|
||||
</div>
|
||||
{#if selectedClientName}
|
||||
<div class="flex items-center gap-2 text-xs pt-1">
|
||||
{#if selectedClientStatus}<span class="text-green-600 flex items-center gap-1 font-medium"><CheckCircle2 class="h-3 w-3"/> Cliente Activo</span>{:else}<span class="text-red-600 flex items-center gap-1 font-medium"><XCircle class="h-3 w-3"/> Cliente Inactivo</span>{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="comm_pn">Número de Parte Comercial</Label>
|
||||
<Input id="comm_pn" bind:value={formData.commercial_part_number} maxlength={70} />
|
||||
</div>
|
||||
|
||||
<div class="p-4 border rounded-xl space-y-3 bg-muted/20">
|
||||
<Label for="alt_um" class="flex items-center gap-2"><Scale class="h-4 w-4"/> UM Conversión (Alterna)</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="alt_um" bind:value={formData.alternate_unit_measure} placeholder="Seleccione..." class="font-mono cursor-pointer" readonly onclick={() => showAltUOMModal = true}/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showAltUOMModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="eccn">ECCN</Label>
|
||||
<Input id="eccn" bind:value={formData.eccn} maxlength={20} />
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-6 space-y-6">
|
||||
<div class="p-6 border rounded-xl space-y-4 bg-slate-50 dark:bg-slate-900/30">
|
||||
<h3 class="font-medium text-sm text-muted-foreground">Datos Regulatorios Adicionales</h3>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="fraction_mx" class="required">Fracción Arancelaria (MX)</Label>
|
||||
<div class="flex gap-2">
|
||||
<Input id="fraction_mx" bind:value={formData.fraction} readonly onclick={() => showFractionModal = true} class="cursor-pointer font-mono" placeholder="Seleccione..."/>
|
||||
<Button variant="outline" size="icon" type="button" onclick={() => showFractionModal = true} class="shrink-0"><FolderSearch class="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="eccn">ECCN</Label>
|
||||
<Input id="eccn" bind:value={formData.eccn} maxlength={20} class="font-mono"/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="lic_code">License Code</Label>
|
||||
<Input id="lic_code" bind:value={formData.license_code} maxlength={3} class="font-mono"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="exp_code">Export Code</Label>
|
||||
<Input id="exp_code" bind:value={formData.export_code} maxlength={2} class="font-mono"/>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="exc_sym">Símbolo Exclusión</Label>
|
||||
<Input id="exc_sym" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="lic_code">License Code</Label>
|
||||
<Input id="lic_code" bind:value={formData.license_code} maxlength={3} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="exp_code">Export Code</Label>
|
||||
<Input id="exp_code" bind:value={formData.export_code} maxlength={2} />
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="exc_sym">Símbolo de Exclusión</Label>
|
||||
<Input id="exc_sym" bind:value={formData.exclusion_symbol} maxlength={19} />
|
||||
|
||||
<div class="flex items-center gap-3 p-4 border rounded-xl">
|
||||
<Switch id="is_active" bind:checked={formData.is_active} disabled={loading} />
|
||||
<Label for="is_active" class="cursor-pointer">Parte Activa en Sistema</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 p-4 border rounded-lg bg-card">
|
||||
<Switch id="is_active" bind:checked={formData.is_active} disabled={loading} />
|
||||
<Label for="is_active">Parte Activa en Sistema</Label>
|
||||
|
||||
</div>
|
||||
</Tabs.Content>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user