diff --git a/backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py b/backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py index d4edfaee..fbc8f887 100644 --- a/backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py +++ b/backend/api/v1/modules/a76/pedmientos/routes/pedimentos.py @@ -16,7 +16,7 @@ router = TenantCRUDRoutes( prefix="", # No prefix here, will be added in main router tags=["a76 / pedimentos"], # Tag for Swagger documentation resource_name="Pedimento", - id_name="pedimento_id", + id_name="id", # Use standard REST convention enable_list=True, # Enable GET / with pagination enable_filters=True, # Enable status, client_id, year filters default_page_size=50, diff --git a/frontend/src/lib/api/dashboard/a76/pedimentos.ts b/frontend/src/lib/api/dashboard/a76/pedimentos.ts index 574c447f..a5069c9f 100644 --- a/frontend/src/lib/api/dashboard/a76/pedimentos.ts +++ b/frontend/src/lib/api/dashboard/a76/pedimentos.ts @@ -324,5 +324,5 @@ export const pedimentosApi = { * @param id - ID del pedimento a eliminar * @param companyId - ID de la compañía (por defecto 1) */ - delete: (id: number, companyId = 1) => api.delete(`/v1/a76/pedimentos/${id}/?company_id=${companyId}`) + delete: (id: number, companyId = 1) => api.delete(`/v1/a76/pedimentos/${id}?company_id=${companyId}`) }; diff --git a/frontend/src/lib/components/dashboard/pedimentos/columns.ts b/frontend/src/lib/components/dashboard/pedimentos/columns.ts index d56a174e..3c085396 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/columns.ts +++ b/frontend/src/lib/components/dashboard/pedimentos/columns.ts @@ -1,7 +1,6 @@ import type { ColumnDef } from "@tanstack/table-core"; import { renderComponent, renderSnippet } from "$lib/components/ui/data-table/index.js"; import { createRawSnippet } from "svelte"; -import DataTableActions from "./data-table-actions.svelte"; import type { Pedimento } from "$lib/api/dashboard/a76/pedimentos"; // Extender el tipo ColumnMeta para incluir className @@ -93,6 +92,33 @@ function getStatusColor(status?: string | null): string { export function createColumns(onSuccess?: () => void): ColumnDef[] { return [ + { + id: "select", + header: ({ table }) => { + return renderSnippet( + createRawSnippet(() => ({ + render: () => `
` + })) + ); + }, + cell: ({ row }) => { + const isSelected = row.getIsSelected(); + + const checkboxSnippet = createRawSnippet<[{ selected: boolean }]>((getProps) => { + const { selected } = getProps(); + return { + render: () => `
+ +
` + }; + }); + + return renderSnippet(checkboxSnippet, { selected: isSelected }); + }, + size: 40, + enableSorting: false, + enableHiding: false + }, { accessorKey: "id", header: "ID", @@ -214,7 +240,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.payment_date) }); } }, - { + /*{ accessorKey: "pedimento_config_update_rectification.pediment_rectifed_18", header: "Pedimento 18", meta: { className: "hidden lg:table-cell" }, @@ -228,8 +254,8 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(ped18Snippet, { value: row.original.pedimento_config_update_rectification?.pediment_rectifed_18 }); } - }, - { + },*/ + /*{ accessorKey: "pedimento_config_update_rectification.r1", header: "Pedimento R1", meta: { className: "hidden lg:table-cell" }, @@ -243,7 +269,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(r1Snippet, { value: row.original.pedimento_config_update_rectification?.r1 }); } - }, + },*/ { accessorKey: "pedimento_validation.electronic_signature", header: "Acuse Electrónico", @@ -397,13 +423,8 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(dateSnippet, { date: formatDate(row.original.created_at) }); } - }, - { - id: "actions", - cell: ({ row }) => { - return renderComponent(DataTableActions, { item: row.original, onSuccess }); - } } + // Columna de acciones eliminada - ahora usamos botones en el footer ]; } diff --git a/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte b/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte index 1a5b4fd6..8f4bfe0d 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte +++ b/frontend/src/lib/components/dashboard/pedimentos/data-table.svelte @@ -2,10 +2,13 @@ import { onMount } from 'svelte'; import { type ColumnDef, - getCoreRowModel + getCoreRowModel, + type RowSelectionState } from "@tanstack/table-core"; import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js"; import * as Table from "$lib/components/ui/table/index.js"; + import { Button } from "$lib/components/ui/button"; + import { Edit } from "lucide-svelte"; type DataTableProps = { columns: ColumnDef[]; @@ -13,6 +16,8 @@ loading: boolean; hasMore: boolean; loadMore: () => void; + selectedId?: number | null; + onRowClick?: (row: TData) => void; }; let { @@ -20,7 +25,9 @@ columns, loading, hasMore, - loadMore + loadMore, + selectedId = null, + onRowClick }: DataTableProps = $props(); const table = createSvelteTable({ @@ -28,12 +35,28 @@ return data; }, columns, - getCoreRowModel: getCoreRowModel() + getCoreRowModel: getCoreRowModel(), + getRowId: (row: any) => row.id?.toString(), + state: { + get rowSelection() { + return selectedId ? { [selectedId]: true } : {}; + } + }, + enableRowSelection: true, + enableMultiRowSelection: false }); let scrollContainer = $state(); let loadingTrigger = $state(); + // Función para manejar doble clic en una fila + function handleRowDoubleClick(row: any) { + const pedimento = row.original; + if (pedimento?.id) { + window.location.href = `/dashboard/pedimentos/edit/${pedimento.id}`; + } + } + // Intersection Observer para detectar cuando el usuario llega al final onMount(() => { const observer = new IntersectionObserver( @@ -80,7 +103,16 @@ {#each table.getRowModel().rows as row (row.id)} - + { + if (onRowClick) { + onRowClick(row.original); + } + }} + ondblclick={() => handleRowDoubleClick(row)} + class="cursor-pointer hover:bg-muted/50 transition-colors {row.getIsSelected() ? 'bg-primary/10' : ''}" + > {#each row.getVisibleCells() as cell (cell.id)} (data.error || null); + + // Estado para selección de filas + let selectedId = $state(null); + let hasSelection = $derived(selectedId !== null); + let showDeleteDialog = $state(false); + + function handleRowClick(pedimento: Pedimento) { + // Toggle: si ya está seleccionado, deseleccionar; si no, seleccionar + selectedId = selectedId === pedimento.id ? null : pedimento.id; + console.log('🔘 Row clicked, pedimento.id:', pedimento.id, 'selectedId:', selectedId, 'hasSelection:', hasSelection); + } + + function handleEditSelected() { + if (selectedId) { + window.location.href = `/dashboard/pedimentos/edit/${selectedId}`; + } + } + + function handleDelete() { + if (!selectedId) { + return; + } + showDeleteDialog = true; + } + + async function confirmDelete() { + if (!selectedId) return; + + const companyId = companyStore.activeCompany?.id; + if (!companyId) { + error = 'No hay compañía seleccionada'; + return; + } + + try { + const response = await pedimentosApi.delete(selectedId, companyId); + + if (response.error) { + console.error('🗑️ [Pedimentos] Error al eliminar:', response.error); + error = response.error; + return; + } + + // Recargar datos + await reloadData(); + + selectedId = null; + showDeleteDialog = false; + } catch (e) { + console.error('🗑️ [Pedimentos] Error deleting:', e); + error = 'Error al eliminar el pedimento'; + } + } async function loadMore() { if (loading || !hasMore) return; @@ -343,7 +398,50 @@ {loading} {hasMore} {loadMore} + {selectedId} + onRowClick={handleRowClick} /> + + +
+
+ +
+ + + +
+
+
+ + + + + + ¿Eliminar pedimento? + + Esta acción no se puede deshacer. El pedimento será eliminado permanentemente. + + +
+ + +
+
+