fix/catalogo-agente-aduanal
This commit is contained in:
@@ -59,5 +59,5 @@ export async function updateCustomsBrokerConcept(id: number, data: CustomsBroker
|
||||
}
|
||||
|
||||
export async function deleteCustomsBrokerConcept(id: number, companyId: number): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/customs-broker-concepts/${id}/?company_id=${companyId}`);
|
||||
return await api.delete(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import { FolderSearch } from 'lucide-svelte';
|
||||
import BrokerSelectorDialog from '$lib/components/dashboard/export/manifest/modals/broker-selector-dialog.svelte';
|
||||
import {
|
||||
customsBrokersApi,
|
||||
type CustomsBroker
|
||||
} from '$lib/api/dashboard/a76/customs-brokers';
|
||||
import {
|
||||
createCustomsBrokerConcept,
|
||||
updateCustomsBrokerConcept,
|
||||
@@ -38,6 +44,8 @@
|
||||
|
||||
let loading = $state(false);
|
||||
let error = $state<string | null>(null);
|
||||
let showBrokerSelector = $state(false);
|
||||
let selectedBrokerLabel = $state('');
|
||||
|
||||
// Cargar datos al editar
|
||||
$effect(() => {
|
||||
@@ -48,6 +56,7 @@
|
||||
amount: item.amount,
|
||||
priority: item.priority
|
||||
};
|
||||
selectedBrokerLabel = item.broker_key || '';
|
||||
} else {
|
||||
formData = {
|
||||
broker_key: '',
|
||||
@@ -55,9 +64,36 @@
|
||||
amount: undefined,
|
||||
priority: undefined
|
||||
};
|
||||
selectedBrokerLabel = '';
|
||||
}
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
if (!open || !formData.broker_key || !companyId || selectedBrokerLabel) return;
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const response = await customsBrokersApi.get(formData.broker_key, companyId.toString());
|
||||
if (response.data) {
|
||||
selectedBrokerLabel = response.data.name || response.data.broker_key;
|
||||
}
|
||||
} catch (e) {
|
||||
selectedBrokerLabel = formData.broker_key;
|
||||
}
|
||||
})();
|
||||
});
|
||||
|
||||
function handleBrokerSelect(broker: CustomsBroker) {
|
||||
formData.broker_key = broker.broker_key || '';
|
||||
selectedBrokerLabel = broker.name || broker.broker_key || '';
|
||||
}
|
||||
|
||||
const brokerDisplayValue = $derived(
|
||||
selectedBrokerLabel && selectedBrokerLabel !== formData.broker_key
|
||||
? `${selectedBrokerLabel} (${formData.broker_key})`
|
||||
: formData.broker_key
|
||||
);
|
||||
|
||||
async function handleSubmit() {
|
||||
error = null;
|
||||
loading = true;
|
||||
@@ -118,13 +154,28 @@
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid gap-2 col-span-1">
|
||||
<Label for="broker_key">Clave del Agente <span class="text-destructive">*</span></Label>
|
||||
<Input
|
||||
id="broker_key"
|
||||
bind:value={formData.broker_key}
|
||||
placeholder="Ej: 01001"
|
||||
maxlength={5}
|
||||
disabled={isEdit}
|
||||
/>
|
||||
<div class="flex gap-2">
|
||||
<Input
|
||||
id="broker_key"
|
||||
value={brokerDisplayValue}
|
||||
placeholder="Seleccionar agente aduanal"
|
||||
readonly
|
||||
disabled={isEdit}
|
||||
class={!isEdit ? 'cursor-pointer' : ''}
|
||||
onclick={() => {
|
||||
if (!isEdit) showBrokerSelector = true;
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="icon"
|
||||
onclick={() => (showBrokerSelector = true)}
|
||||
disabled={isEdit}
|
||||
>
|
||||
<FolderSearch class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2 col-span-1">
|
||||
@@ -166,3 +217,5 @@
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<BrokerSelectorDialog bind:open={showBrokerSelector} onSelect={handleBrokerSelect} />
|
||||
|
||||
@@ -6,26 +6,34 @@
|
||||
import CreateEditDialog from '$lib/components/dashboard/general_catalogs/customs_broker_concepts/create-edit-dialog.svelte';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Plus, RefreshCw } from 'lucide-svelte';
|
||||
import { goto } from '$app/navigation';
|
||||
import { Pencil, Plus, Trash2 } from 'lucide-svelte';
|
||||
import { browser } from '$app/environment';
|
||||
import { useShortcuts } from '$lib/hooks/use-shortcuts';
|
||||
import { obtenerAtajosListaConceptosAA } from '$lib/config/shortcuts/dashboard/general_catalogs/customs_broker_concepts/list';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { getCustomsBrokerConcepts } from '$lib/api/dashboard/a76/general_catalogs/customs-broker-concepts';
|
||||
import {
|
||||
deleteCustomsBrokerConcept,
|
||||
getCustomsBrokerConcepts,
|
||||
type CustomsBrokerConcept
|
||||
} from '$lib/api/dashboard/a76/general_catalogs/customs-broker-concepts';
|
||||
|
||||
let { data } = $props();
|
||||
|
||||
const activeCompanyId = $derived(companyStore.activeCompany?.id);
|
||||
let dialogOpen = $state(false);
|
||||
let editingItem = $state<CustomsBrokerConcept | null>(null);
|
||||
let error = $state<string | null>(data.error || null);
|
||||
let selectedIds = $state<(string | number)[]>([]);
|
||||
|
||||
// Atajos
|
||||
useShortcuts(
|
||||
'Lista Conceptos AA',
|
||||
obtenerAtajosListaConceptosAA({
|
||||
manejarNuevo: () => (dialogOpen = true),
|
||||
manejarActualizar: () => goto($page.url, { invalidateAll: true }),
|
||||
manejarNuevo: () => {
|
||||
editingItem = null;
|
||||
dialogOpen = true;
|
||||
},
|
||||
manejarActualizar: reloadData,
|
||||
})
|
||||
);
|
||||
|
||||
@@ -42,6 +50,9 @@
|
||||
let totalItems = $state(data.concepts?.total || 0);
|
||||
let loading = $state(false);
|
||||
let hasMore = $derived(allItems.length < totalItems);
|
||||
const selectedConcept = $derived(
|
||||
selectedIds.length === 1 ? allItems.find((item) => item.id === selectedIds[0]) ?? null : null
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
if (data.concepts) {
|
||||
@@ -150,8 +161,62 @@
|
||||
}
|
||||
|
||||
function handleSuccess() {
|
||||
dialogOpen = false;
|
||||
editingItem = null;
|
||||
selectedIds = [];
|
||||
reloadData();
|
||||
}
|
||||
|
||||
function handleRowClick(row: CustomsBrokerConcept) {
|
||||
const id = row.id;
|
||||
selectedIds = selectedIds.includes(id) ? [] : [id];
|
||||
}
|
||||
|
||||
function handleRowDoubleClick(row: CustomsBrokerConcept) {
|
||||
editingItem = row;
|
||||
dialogOpen = true;
|
||||
}
|
||||
|
||||
function handleEditSelected() {
|
||||
if (!selectedConcept) return;
|
||||
editingItem = selectedConcept;
|
||||
dialogOpen = true;
|
||||
}
|
||||
|
||||
async function handleDeleteSelected() {
|
||||
if (!selectedConcept || !companyStore.activeCompany) return;
|
||||
|
||||
if (
|
||||
!confirm(
|
||||
`¿Estás seguro de eliminar el concepto "${selectedConcept.concept}" del agente "${selectedConcept.broker_key}"?`
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
loading = true;
|
||||
error = null;
|
||||
|
||||
try {
|
||||
const response = await deleteCustomsBrokerConcept(
|
||||
selectedConcept.id,
|
||||
companyStore.activeCompany.id
|
||||
);
|
||||
|
||||
if (response.error) {
|
||||
error = response.error;
|
||||
return;
|
||||
}
|
||||
|
||||
selectedIds = [];
|
||||
await reloadData();
|
||||
} catch (err) {
|
||||
error = 'Error al eliminar el concepto';
|
||||
console.error('Error deleting broker concept:', err);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-6 p-6 h-[calc(100svh-4rem)] group-has-data-[collapsible=icon]/sidebar-wrapper:h-[calc(100svh-3rem)] overflow-hidden">
|
||||
@@ -161,11 +226,13 @@
|
||||
<p class="text-muted-foreground">Gestión del catálogo de conceptos de agente aduanal</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-3">
|
||||
<Button variant="outline" size="sm" class="h-9" onclick={reloadData}>
|
||||
<RefreshCw class="mr-2 h-4 w-4" />
|
||||
Actualizar
|
||||
</Button>
|
||||
<Button class="h-9" onclick={() => (dialogOpen = true)}>
|
||||
<Button
|
||||
class="h-9"
|
||||
onclick={() => {
|
||||
editingItem = null;
|
||||
dialogOpen = true;
|
||||
}}
|
||||
>
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
Nuevo Concepto
|
||||
</Button>
|
||||
@@ -206,6 +273,10 @@
|
||||
{loading}
|
||||
{hasMore}
|
||||
{loadMore}
|
||||
{selectedIds}
|
||||
onSelectedIdsChange={(ids) => (selectedIds = ids)}
|
||||
onRowClick={handleRowClick}
|
||||
onRowDoubleClick={handleRowDoubleClick}
|
||||
/>
|
||||
</div>
|
||||
</Card.Content>
|
||||
@@ -215,9 +286,41 @@
|
||||
Mostrando {allItems.length} de {totalItems} registros
|
||||
</div>
|
||||
|
||||
<div class="h-20"></div>
|
||||
|
||||
<div
|
||||
id="customs-broker-concepts-list-footer"
|
||||
class="fixed right-0 bottom-0 left-0 z-50 ml-[calc(var(--sidebar-width))] border-t bg-background/95 shadow-lg backdrop-blur group-has-data-[state=collapsed]/sidebar-wrapper:ml-[calc(var(--sidebar-width-icon))] supports-[backdrop-filter]:bg-background/80"
|
||||
>
|
||||
<div class="mx-auto max-w-[1400px] px-4 py-4">
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={handleEditSelected}
|
||||
disabled={selectedIds.length !== 1}
|
||||
>
|
||||
<Pencil size={16} class="mr-2" />
|
||||
Editar
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onclick={handleDeleteSelected}
|
||||
disabled={selectedIds.length !== 1}
|
||||
class="text-destructive hover:bg-destructive/10 hover:text-destructive"
|
||||
>
|
||||
<Trash2 size={16} class="mr-2" />
|
||||
Eliminar
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if activeCompanyId}
|
||||
<CreateEditDialog
|
||||
bind:open={dialogOpen}
|
||||
item={editingItem}
|
||||
companyId={activeCompanyId}
|
||||
onSuccess={handleSuccess}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user