181 lines
4.8 KiB
Svelte
181 lines
4.8 KiB
Svelte
<script lang="ts">
|
|
import * as Dialog from '$lib/components/ui/dialog';
|
|
import { Input } from '$lib/components/ui/input';
|
|
import { Label } from '$lib/components/ui/label';
|
|
import { Button } from '$lib/components/ui/button';
|
|
import { Textarea } from '$lib/components/ui/textarea';
|
|
import {
|
|
createCanadianFraction,
|
|
updateCanadianFraction,
|
|
type CanadianFraction,
|
|
type CanadianFractionCreate,
|
|
type CanadianFractionUpdate
|
|
} from '$lib/api/dashboard/general_catalogs/canadian';
|
|
import { companyStore } from '$lib/stores/company.svelte';
|
|
import { toast } from 'svelte-sonner';
|
|
import { Loader2 } from 'lucide-svelte';
|
|
|
|
let {
|
|
open = $bindable(false),
|
|
fraction = null, // If null, create mode. If set, edit mode.
|
|
onSuccess
|
|
}: {
|
|
open: boolean;
|
|
fraction?: CanadianFraction | null;
|
|
onSuccess: () => void;
|
|
} = $props();
|
|
|
|
let isLoading = $state(false);
|
|
|
|
// Form fields
|
|
let fractionCode = $state('');
|
|
let countryCode = $state('');
|
|
let description = $state('');
|
|
let unitOfMeasure = $state('');
|
|
let adValorem = $state('');
|
|
|
|
// Load data on open/fraction change
|
|
$effect(() => {
|
|
if (open) {
|
|
if (fraction) {
|
|
// Edit mode
|
|
fractionCode = fraction.fraction;
|
|
countryCode = fraction.country_code;
|
|
description = fraction.description || '';
|
|
unitOfMeasure = fraction.unit_of_measure || '';
|
|
adValorem = fraction.ad_valorem?.toString() || '';
|
|
} else {
|
|
// Create mode - reset
|
|
fractionCode = '';
|
|
countryCode = '';
|
|
description = '';
|
|
unitOfMeasure = '';
|
|
adValorem = '';
|
|
}
|
|
}
|
|
});
|
|
|
|
async function handleSubmit() {
|
|
const companyId = companyStore.activeCompany?.id;
|
|
if (!companyId) return;
|
|
|
|
// Validation
|
|
if (!fractionCode) {
|
|
toast.error('La fracción es requerida');
|
|
return;
|
|
}
|
|
if (!countryCode) {
|
|
toast.error('El código de país es requerido');
|
|
return;
|
|
}
|
|
|
|
isLoading = true;
|
|
try {
|
|
const adValoremNum = adValorem ? parseFloat(adValorem) : undefined;
|
|
if (adValorem && isNaN(adValoremNum!)) {
|
|
toast.error('El Ad Valorem debe ser un número válido');
|
|
isLoading = false;
|
|
return;
|
|
}
|
|
|
|
if (fraction) {
|
|
// Update
|
|
const updateData: CanadianFractionUpdate = {
|
|
fraction: fractionCode,
|
|
country_code: countryCode,
|
|
description,
|
|
unit_of_measure: unitOfMeasure || undefined,
|
|
ad_valorem: adValoremNum
|
|
};
|
|
await updateCanadianFraction(companyId, fraction.id, updateData);
|
|
toast.success('Fracción actualizada correctamente');
|
|
} else {
|
|
// Create
|
|
const createData: CanadianFractionCreate = {
|
|
fraction: fractionCode,
|
|
country_code: countryCode,
|
|
description,
|
|
unit_of_measure: unitOfMeasure || undefined,
|
|
ad_valorem: adValoremNum
|
|
};
|
|
await createCanadianFraction(companyId, createData);
|
|
toast.success('Fracción creada correctamente');
|
|
}
|
|
onSuccess();
|
|
open = false;
|
|
} catch (error) {
|
|
console.error('Error saving Canadian fraction:', error);
|
|
toast.error('Error al guardar la fracción');
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<Dialog.Root bind:open>
|
|
<Dialog.Content class="sm:max-w-[600px]">
|
|
<Dialog.Header>
|
|
<Dialog.Title>{fraction ? 'Editar' : 'Crear'} Fracción Canadiense</Dialog.Title>
|
|
<Dialog.Description>
|
|
{fraction
|
|
? 'Modifica los detalles de la fracción seleccionada.'
|
|
: 'Ingresa los datos para la nueva fracción.'}
|
|
</Dialog.Description>
|
|
</Dialog.Header>
|
|
|
|
<div class="grid gap-4 py-4">
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="space-y-2">
|
|
<Label for="fraction">Fracción</Label>
|
|
<Input
|
|
id="fraction"
|
|
bind:value={fractionCode}
|
|
placeholder="Ej. 9999999999"
|
|
maxlength={13}
|
|
/>
|
|
</div>
|
|
<div class="space-y-2">
|
|
<Label for="country_code">País (Código ISO)</Label>
|
|
<Input id="country_code" bind:value={countryCode} placeholder="Ej. CAN" maxlength={3} />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<Label for="description">Descripción</Label>
|
|
<Textarea
|
|
id="description"
|
|
bind:value={description}
|
|
placeholder="Descripción de la mercancía..."
|
|
/>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div class="space-y-2">
|
|
<Label for="unit">Unidad de Medida</Label>
|
|
<Input id="unit" bind:value={unitOfMeasure} placeholder="Ej. Kg" maxlength={5} />
|
|
</div>
|
|
<div class="space-y-2">
|
|
<Label for="ad_valorem">Ad Valorem (%)</Label>
|
|
<Input
|
|
id="ad_valorem"
|
|
type="number"
|
|
step="0.01"
|
|
bind:value={adValorem}
|
|
placeholder="0.00"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Dialog.Footer>
|
|
<Button variant="outline" onclick={() => (open = false)}>Cancelar</Button>
|
|
<Button onclick={handleSubmit} disabled={isLoading}>
|
|
{#if isLoading}
|
|
<Loader2 class="mr-2 h-4 w-4 animate-spin" />
|
|
{/if}
|
|
Guardar
|
|
</Button>
|
|
</Dialog.Footer>
|
|
</Dialog.Content>
|
|
</Dialog.Root>
|