feature/catalogo-equivalencias
This commit is contained in:
@@ -1,25 +1,25 @@
|
||||
import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import type { EquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { renderComponent } from '$lib/components/ui/data-table';
|
||||
import DataTableActions from './data-table-actions.svelte';
|
||||
import { Header } from '$lib/components/ui/alert-dialog';
|
||||
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<Equivalency>[] {
|
||||
export function createColumns(onSuccess?: () => void): ColumnDef<EquivalencyItem>[] {
|
||||
return [
|
||||
{
|
||||
accessorKey: 'fraccion_mex',
|
||||
header: 'Fracción MX',
|
||||
cell: ({ row }) => row.original.fraccion_mex || 'N/A'
|
||||
accessorKey: 'original_field',
|
||||
header: 'Desde código',
|
||||
cell: ({ row }) => row.original.original_field || 'N/A'
|
||||
},
|
||||
{
|
||||
accessorKey: 'fraccion_us',
|
||||
header: 'Fracción US',
|
||||
cell: ({ row }) => row.original.fraccion_us || 'N/A'
|
||||
accessorKey: 'external_field',
|
||||
header: 'Hacia código',
|
||||
cell: ({ row }) => row.original.external_field || 'N/A'
|
||||
},
|
||||
{
|
||||
accessorKey: 'description',
|
||||
header: 'Descripción',
|
||||
cell: ({ row }) => row.original.description || 'N/A'
|
||||
accessorKey: 'conversion_factor',
|
||||
header: 'Factor de conversión',
|
||||
cell: ({ row }) => (row.original.conversion_factor ?? 0).toString()
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
|
||||
@@ -4,12 +4,13 @@
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import UnitMeasureSelectorDialog from '$lib/components/dashboard/goods/modales/unit-measure-dialog.svelte';
|
||||
import { FolderSearch, Scale } from 'lucide-svelte';
|
||||
import {
|
||||
createEquivalency,
|
||||
updateEquivalency,
|
||||
type Equivalency
|
||||
createEquivalencyItem,
|
||||
updateEquivalencyItem,
|
||||
type EquivalencyItem
|
||||
} from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { obtenerAtajosFormularioEquivalencias } from '$lib/config/shortcuts/dashboard/general_catalogs/equivalencies/edit';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -17,46 +18,50 @@
|
||||
onSuccess
|
||||
}: {
|
||||
open: boolean;
|
||||
item?: Equivalency | null;
|
||||
item?: EquivalencyItem | null;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
// Atajos
|
||||
|
||||
const isEdit = $derived(!!item);
|
||||
const title = $derived(
|
||||
isEdit ? `Editar Equivalencia ${item?.fraccion_mex || ''}` : 'Nueva Equivalencia'
|
||||
isEdit
|
||||
? `Editar Equivalencia ${item?.original_field || ''} → ${item?.external_field || ''}`
|
||||
: 'Nueva Equivalencia'
|
||||
);
|
||||
|
||||
// Estado del formulario
|
||||
let formData = $state({
|
||||
fraccion_mex: '',
|
||||
fraccion_us: '',
|
||||
description: ''
|
||||
original_field: '',
|
||||
external_field: '',
|
||||
conversion_factor: ''
|
||||
});
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
// Cargar datos
|
||||
let showFromUomModal = $state(false);
|
||||
let showToUomModal = $state(false);
|
||||
|
||||
$effect(() => {
|
||||
if (open) {
|
||||
if (item) {
|
||||
formData = {
|
||||
fraccion_mex: item.fraccion_mex || '',
|
||||
fraccion_us: item.fraccion_us || '',
|
||||
description: item.description || ''
|
||||
};
|
||||
} else {
|
||||
// Reset
|
||||
formData = {
|
||||
fraccion_mex: '',
|
||||
fraccion_us: '',
|
||||
description: ''
|
||||
};
|
||||
}
|
||||
error = null;
|
||||
if (!open) return;
|
||||
|
||||
if (item) {
|
||||
formData = {
|
||||
original_field: item.original_field || '',
|
||||
external_field: item.external_field || '',
|
||||
conversion_factor:
|
||||
item.conversion_factor !== null && item.conversion_factor !== undefined
|
||||
? item.conversion_factor.toString()
|
||||
: ''
|
||||
};
|
||||
} else {
|
||||
formData = {
|
||||
original_field: '',
|
||||
external_field: '',
|
||||
conversion_factor: ''
|
||||
};
|
||||
}
|
||||
|
||||
error = null;
|
||||
});
|
||||
|
||||
async function handleSubmit() {
|
||||
@@ -70,15 +75,24 @@
|
||||
error = null;
|
||||
|
||||
try {
|
||||
let response;
|
||||
if (isEdit && item) {
|
||||
response = await updateEquivalency(item.id, formData, companyId);
|
||||
} else {
|
||||
response = await createEquivalency(formData, companyId);
|
||||
}
|
||||
if (!formData.original_field.trim()) throw new Error('Código origen requerido');
|
||||
if (!formData.external_field.trim()) throw new Error('Código destino requerido');
|
||||
if (formData.conversion_factor === '' || formData.conversion_factor === null)
|
||||
throw new Error('Factor de conversión requerido');
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
const factor = parseFloat(formData.conversion_factor);
|
||||
if (isNaN(factor)) throw new Error('El factor de conversión debe ser un número válido');
|
||||
|
||||
const dataToSend = {
|
||||
original_field: formData.original_field.trim(),
|
||||
external_field: formData.external_field.trim(),
|
||||
conversion_factor: factor
|
||||
};
|
||||
|
||||
if (isEdit && item) {
|
||||
await updateEquivalencyItem(item.id, dataToSend, companyId);
|
||||
} else {
|
||||
await createEquivalencyItem(dataToSend, companyId);
|
||||
}
|
||||
|
||||
open = false;
|
||||
@@ -111,46 +125,104 @@
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="fraccion_mex" class="text-right">Fracción MX</Label>
|
||||
<Input
|
||||
id="fraccion_mex"
|
||||
bind:value={formData.fraccion_mex}
|
||||
class="col-span-3"
|
||||
maxlength={10}
|
||||
required
|
||||
placeholder="Ej. 8544.11.01"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-4 py-4">
|
||||
<div class="grid gap-2">
|
||||
<Label for="from_unit_code">
|
||||
Código origen <span class="text-destructive">*</span>
|
||||
</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative w-full">
|
||||
<Scale class="absolute top-2.5 left-3 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
id="from_unit_code"
|
||||
bind:value={formData.original_field}
|
||||
readonly
|
||||
onclick={() => (showFromUomModal = true)}
|
||||
class="cursor-pointer pl-9 font-mono"
|
||||
placeholder="Seleccione..."
|
||||
disabled={loading}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
onclick={() => (showFromUomModal = true)}
|
||||
disabled={loading}
|
||||
class="shrink-0"
|
||||
>
|
||||
<FolderSearch class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="fraccion_us" class="text-right">Fracción US</Label>
|
||||
<Input
|
||||
id="fraccion_us"
|
||||
bind:value={formData.fraccion_us}
|
||||
class="col-span-3"
|
||||
maxlength={100}
|
||||
required
|
||||
placeholder="Ej. 8544.11.00"
|
||||
/>
|
||||
</div>
|
||||
<div class="grid gap-2">
|
||||
<Label for="to_unit_code">
|
||||
Código destino <span class="text-destructive">*</span>
|
||||
</Label>
|
||||
<div class="flex gap-2">
|
||||
<div class="relative w-full">
|
||||
<Scale class="absolute top-2.5 left-3 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
id="to_unit_code"
|
||||
bind:value={formData.external_field}
|
||||
readonly
|
||||
onclick={() => (showToUomModal = true)}
|
||||
class="cursor-pointer pl-9 font-mono"
|
||||
placeholder="Seleccione..."
|
||||
disabled={loading}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
type="button"
|
||||
onclick={() => (showToUomModal = true)}
|
||||
disabled={loading}
|
||||
class="shrink-0"
|
||||
>
|
||||
<FolderSearch class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-4 items-center gap-4">
|
||||
<Label for="description" class="text-right">Descripción</Label>
|
||||
<Input
|
||||
id="description"
|
||||
bind:value={formData.description}
|
||||
class="col-span-3"
|
||||
maxlength={200}
|
||||
/>
|
||||
<div class="grid gap-2">
|
||||
<Label for="conversion_factor">
|
||||
Factor de conversión <span class="text-destructive">*</span>
|
||||
</Label>
|
||||
<Input
|
||||
id="conversion_factor"
|
||||
type="number"
|
||||
step="0.000001"
|
||||
bind:value={formData.conversion_factor}
|
||||
disabled={loading}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button type="button" variant="outline" onclick={() => (open = false)}>Cancelar</Button>
|
||||
<Button type="submit" disabled={loading}>
|
||||
{loading ? 'Guardando...' : 'Guardar'}
|
||||
{loading ? 'Guardando...' : isEdit ? 'Actualizar' : 'Crear'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<UnitMeasureSelectorDialog
|
||||
bind:open={showFromUomModal}
|
||||
onSelect={(u) => {
|
||||
formData.original_field = u.code;
|
||||
}}
|
||||
/>
|
||||
|
||||
<UnitMeasureSelectorDialog
|
||||
bind:open={showToUomModal}
|
||||
onSelect={(u) => {
|
||||
formData.external_field = u.code;
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as DropdownMenu from '$lib/components/ui/dropdown-menu';
|
||||
import { EllipsisVertical, Pencil, Trash2, LoaderCircle } from 'lucide-svelte';
|
||||
import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { deleteEquivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import type { EquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { deleteEquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import CreateEditDialog from './create-edit-dialog.svelte';
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
item,
|
||||
onSuccess
|
||||
}: {
|
||||
item: Equivalency;
|
||||
item: EquivalencyItem;
|
||||
onSuccess?: () => void;
|
||||
} = $props();
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let dialogOpen = $state(false);
|
||||
let selectedItem = $state<Equivalency | null>(null);
|
||||
let selectedItem = $state<EquivalencyItem | null>(null);
|
||||
|
||||
async function handleDelete() {
|
||||
if (!confirm('¿Está seguro de eliminar esta equivalencia?')) {
|
||||
@@ -33,7 +33,7 @@
|
||||
loading = true;
|
||||
|
||||
try {
|
||||
const response = await deleteEquivalency(item.id, companyId);
|
||||
const response = await deleteEquivalencyItem(item.id, companyId);
|
||||
|
||||
if (response.error) {
|
||||
throw new Error(response.error);
|
||||
|
||||
Reference in New Issue
Block a user