Merge pull request 'add/tables' (#57) from add/tables into development

Reviewed-on: ADUANASOFT/anexo76#57
This commit is contained in:
2026-01-20 18:54:41 +00:00
19 changed files with 896 additions and 141 deletions

View File

@@ -37,6 +37,61 @@ export function createColumns(onSuccess) {
return renderSnippet(snippet, { val: row.original.name });
}
},
{
id: "streets",
header: "Calles",
cell: ({ row }) => {
const snippet = createRawSnippet((getData) => {
const { val } = getData();
return { render: () => `<div class="max-w-[200px] truncate" title="${val || ''}">${val || '-'}</div>` };
});
return renderSnippet(snippet, { val: row.original.address?.streets });
}
},
{
id: "exterior_number",
header: "Num Ext.",
cell: ({ row }) => {
const snippet = createRawSnippet((getData) => {
const { val } = getData();
return { render: () => `<div>${val || '-'}</div>` };
});
return renderSnippet(snippet, { val: row.original.address?.exterior_number });
}
},
{
id: "postal_code",
header: "Código Postal",
cell: ({ row }) => {
const snippet = createRawSnippet((getData) => {
const { val } = getData();
return { render: () => `<code class="bg-muted px-1 py-0.5 rounded text-sm">${val || '-'}</code>` };
});
return renderSnippet(snippet, { val: row.original.address?.postal_code });
}
},
{
id: "neighborhood",
header: "Colonia",
cell: ({ row }) => {
const snippet = createRawSnippet((getData) => {
const { val } = getData();
return { render: () => `<div class="max-w-[150px] truncate" title="${val || ''}">${val || '-'}</div>` };
});
return renderSnippet(snippet, { val: row.original.address?.neighborhood });
}
},
{
id: "city",
header: "Ciudad",
cell: ({ row }) => {
const snippet = createRawSnippet((getData) => {
const { val } = getData();
return { render: () => `<div class="max-w-[150px] truncate" title="${val || ''}">${val || '-'}</div>` };
});
return renderSnippet(snippet, { val: row.original.address?.city });
}
},
{
id: "country",
header: "País",

View File

@@ -22,9 +22,22 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
return renderSnippet(keySnippet, { key: row.original.broker_key });
}
},
{
accessorKey: "type",
header: "Tipo",
cell: ({ row }) => {
const typeSnippet = createRawSnippet<[{ type: string | null | undefined }]>((getType) => {
const { type } = getType();
return {
render: () => `<div class="max-w-[120px] truncate">${type || '-'}</div>`
};
});
return renderSnippet(typeSnippet, { type: row.original.type });
}
},
{
accessorKey: "name",
header: "Nombre",
header: "Nombre Completo",
cell: ({ row }) => {
const nameSnippet = createRawSnippet<[{ name: string | null | undefined }]>((getName) => {
const { name } = getName();
@@ -36,16 +49,84 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
}
},
{
accessorKey: "type",
header: "Tipo",
accessorKey: "address",
header: "Dirección",
cell: ({ row }) => {
const typeSnippet = createRawSnippet<[{ type: string | null | undefined }]>((getType) => {
const { type } = getType();
const addressSnippet = createRawSnippet<[{ address: string | null | undefined }]>((getAddress) => {
const { address } = getAddress();
return {
render: () => `<div class="max-w-[120px] truncate">${type || '-'}</div>`
render: () => `<div class="max-w-[250px] truncate" title="${address || ''}">${address || '-'}</div>`
};
});
return renderSnippet(typeSnippet, { type: row.original.type });
return renderSnippet(addressSnippet, { address: row.original.address });
}
},
{
accessorKey: "postal_code",
header: "Código Postal",
cell: ({ row }) => {
const postalSnippet = createRawSnippet<[{ postal: string | null | undefined }]>((getPostal) => {
const { postal } = getPostal();
return {
render: () =>
postal
? `<code class="bg-muted px-1 py-0.5 rounded text-sm">${postal}</code>`
: `<span class="text-muted-foreground">-</span>`
};
});
return renderSnippet(postalSnippet, { postal: row.original.postal_code });
}
},
{
accessorKey: "city",
header: "Ciudad",
cell: ({ row }) => {
const citySnippet = createRawSnippet<[{ city: string | null | undefined }]>((getCity) => {
const { city } = getCity();
return {
render: () => `<div class="max-w-[150px] truncate">${city || '-'}</div>`
};
});
return renderSnippet(citySnippet, { city: row.original.city });
}
},
{
accessorKey: "state",
header: "Estado",
cell: ({ row }) => {
const stateSnippet = createRawSnippet<[{ state: string | null | undefined }]>((getState) => {
const { state } = getState();
return {
render: () => `<div class="max-w-[150px] truncate">${state || '-'}</div>`
};
});
return renderSnippet(stateSnippet, { state: row.original.state });
}
},
{
accessorKey: "phone",
header: "Teléfono",
cell: ({ row }) => {
const phoneSnippet = createRawSnippet<[{ phone: string | null | undefined }]>((getPhone) => {
const { phone } = getPhone();
return {
render: () => `<div class="max-w-[140px] truncate text-sm">${phone || '-'}</div>`
};
});
return renderSnippet(phoneSnippet, { phone: row.original.phone });
}
},
{
accessorKey: "fax",
header: "Número Fax",
cell: ({ row }) => {
const faxSnippet = createRawSnippet<[{ fax: string | null | undefined }]>((getFax) => {
const { fax } = getFax();
return {
render: () => `<div class="max-w-[140px] truncate text-sm">${fax || '-'}</div>`
};
});
return renderSnippet(faxSnippet, { fax: row.original.fax });
}
},
{
@@ -90,32 +171,6 @@ export function createColumns(onSuccess?: () => void): ColumnDef<CustomsBroker>[
return renderSnippet(emailSnippet, { email: row.original.email });
}
},
{
accessorKey: "phone",
header: "Teléfono",
cell: ({ row }) => {
const phoneSnippet = createRawSnippet<[{ phone: string | null | undefined }]>((getPhone) => {
const { phone } = getPhone();
return {
render: () => `<div class="max-w-[140px] truncate text-sm">${phone || '-'}</div>`
};
});
return renderSnippet(phoneSnippet, { phone: row.original.phone });
}
},
{
accessorKey: "city",
header: "Ciudad",
cell: ({ row }) => {
const citySnippet = createRawSnippet<[{ city: string | null | undefined }]>((getCity) => {
const { city } = getCity();
return {
render: () => `<div class="max-w-[150px] truncate">${city || '-'}</div>`
};
});
return renderSnippet(citySnippet, { city: row.original.city });
}
},
{
id: "actions",
header: "Acciones",

View File

@@ -112,7 +112,25 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
}
},
// 7. FRACCION
// 7. U.M. (Unidad de Medida)
{
accessorKey: "unit_of_measure",
header: "U.M.",
cell: ({ row }) => {
const umSnippet = createRawSnippet<[{ um: string }]>((getUm) => {
const { um } = getUm();
return {
render: () =>
`<span class="inline-flex items-center rounded-sm bg-blue-50 dark:bg-blue-900 text-blue-700 dark:text-blue-300 px-1.5 py-0.5 text-[10px] font-bold ring-1 ring-inset ring-blue-700/10">
${um}
</span>`
};
});
return renderSnippet(umSnippet, { um: row.original.unit_of_measure });
}
},
// 8. FRACCION
{
accessorKey: "fraction",
header: "Fracción",
@@ -127,25 +145,22 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
}
},
// 8. UMT (Unidad de Medida)
// 9. U.M.T. (del inv_data)
{
accessorKey: "unit_of_measure",
header: "UMT",
id: "stock_uom",
header: "U.M.T.",
cell: ({ row }) => {
const umtSnippet = createRawSnippet<[{ um: string }]>((getUm) => {
const { um } = getUm();
const umtSnippet = createRawSnippet<[{ umt: string }]>((getUmt) => {
const { umt } = getUmt();
return {
render: () =>
`<span class="inline-flex items-center rounded-sm bg-blue-50 text-blue-700 px-1.5 py-0.5 text-[10px] font-bold ring-1 ring-inset ring-blue-700/10">
${um}
</span>`
render: () => `<div class="text-xs font-mono">${umt || '-'}</div>`
};
});
return renderSnippet(umtSnippet, { um: row.original.unit_of_measure });
return renderSnippet(umtSnippet, { umt: row.original.inv_data?.stock_uom || '' });
}
},
// 9. COSTO
// 10. COSTO
{
accessorKey: "unit_cost",
header: "Costo",
@@ -163,6 +178,78 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Part>[] {
}
},
// 11. MONEDA
{
accessorKey: "currency_key",
header: "Moneda",
cell: ({ row }) => {
const currSnippet = createRawSnippet<[{ curr: string }]>((getCurr) => {
const { curr } = getCurr();
return {
render: () => `<span class="inline-flex items-center rounded-sm bg-emerald-50 dark:bg-emerald-900 text-emerald-700 dark:text-emerald-300 px-1.5 py-0.5 text-[10px] font-bold">${curr || '-'}</span>`
};
});
return renderSnippet(currSnippet, { curr: row.original.currency_key || '' });
}
},
// 12. PESO UNITARIO
{
accessorKey: "unit_weight",
header: "Peso Unitario",
cell: ({ row }) => {
const weightSnippet = createRawSnippet<[{ weight: number | null, type: string | null }]>((getWeight) => {
const { weight, type } = getWeight();
return {
render: () => {
if (weight === null || weight === undefined) return '-';
return `<div class="text-xs font-mono">${weight.toFixed(4)} ${type || ''}</div>`;
}
};
});
return renderSnippet(weightSnippet, {
weight: row.original.unit_weight,
type: row.original.weight_type
});
}
},
// 13. U.M. EXIST (Stock UOM del inv_data)
{
id: "equivalent_uom",
header: "U.M. Exist",
cell: ({ row }) => {
const eqUomSnippet = createRawSnippet<[{ uom: string }]>((getUom) => {
const { uom } = getUom();
return {
render: () => `<div class="text-xs">${uom || '-'}</div>`
};
});
return renderSnippet(eqUomSnippet, { uom: row.original.inv_data?.equivalent_uom || '' });
}
},
// 14. FECHA MODIFICACIÓN
{
accessorKey: "updated_at",
header: "Fecha Modificación",
cell: ({ row }) => {
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
const { date } = getDate();
if (!date) return { render: () => '-' };
const formatted = new Date(date).toLocaleDateString('es-MX', {
year: 'numeric',
month: '2-digit',
day: '2-digit'
});
return {
render: () => `<div class="text-xs text-muted-foreground">${formatted}</div>`
};
});
return renderSnippet(dateSnippet, { date: row.original.updated_at });
}
},
// ACCIONES
{
id: "actions",

View File

@@ -117,6 +117,152 @@ export function createColumns(onSuccess?: () => void): ColumnDef<Pedimento>[] {
return renderSnippet(numberSnippet, { number: fullNumber });
}
},
{
accessorKey: "pedimento_type",
header: "Tipo",
cell: ({ row }) => {
const typeSnippet = createRawSnippet<[{ type?: string | null }]>((getType) => {
const { type } = getType();
return {
render: () =>
`<div class="text-sm">${type || '-'}</div>`
};
});
return renderSnippet(typeSnippet, { type: row.original.pedimento_type });
}
},
{
accessorKey: "pedimento_code",
header: "Clave",
cell: ({ row }) => {
const codeSnippet = createRawSnippet<[{ code?: string | null }]>((getCode) => {
const { code } = getCode();
return {
render: () =>
`<div class="text-sm">${code || '-'}</div>`
};
});
return renderSnippet(codeSnippet, { code: row.original.pedimento_code });
}
},
{
accessorKey: "regime",
header: "Régimen",
cell: ({ row }) => {
const regimeSnippet = createRawSnippet<[{ regime?: string | null }]>((getRegime) => {
const { regime } = getRegime();
return {
render: () =>
`<div class="text-sm">${regime || '-'}</div>`
};
});
return renderSnippet(regimeSnippet, { regime: row.original.regime });
}
},
{
accessorKey: "pedimento_dates.start_date",
header: "Fecha Inicio",
cell: ({ row }) => {
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
const { date } = getDate();
return {
render: () =>
`<div class="text-sm text-muted-foreground">${date}</div>`
};
});
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.start_date) });
}
},
{
accessorKey: "pedimento_dates.end_date",
header: "Fecha Final",
cell: ({ row }) => {
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
const { date } = getDate();
return {
render: () =>
`<div class="text-sm text-muted-foreground">${date}</div>`
};
});
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.end_date) });
}
},
{
accessorKey: "pedimento_dates.payment_date",
header: "Fecha de Pago",
cell: ({ row }) => {
const dateSnippet = createRawSnippet<[{ date: string }]>((getDate) => {
const { date } = getDate();
return {
render: () =>
`<div class="text-sm text-muted-foreground">${date}</div>`
};
});
return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.payment_date) });
}
},
{
accessorKey: "pedimento_config_update_rectification.pediment_rectifed_18",
header: "Pedimento 18",
cell: ({ row }) => {
const ped18Snippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
const { value } = getValue();
return {
render: () =>
`<div class="text-sm">${value || '-'}</div>`
};
});
return renderSnippet(ped18Snippet, { value: row.original.pedimento_config_update_rectification?.pediment_rectifed_18 });
}
},
{
accessorKey: "pedimento_config_update_rectification.r1",
header: "Pedimento R1",
cell: ({ row }) => {
const r1Snippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
const { value } = getValue();
return {
render: () =>
`<div class="text-sm">${value || '-'}</div>`
};
});
return renderSnippet(r1Snippet, { value: row.original.pedimento_config_update_rectification?.r1 });
}
},
{
accessorKey: "pedimento_validation.electronic_signature",
header: "Acuse Electrónico",
cell: ({ row }) => {
const ackSnippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
const { value } = getValue();
const hasValue = value && value !== '';
return {
render: () =>
`<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${hasValue ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}">
${hasValue ? 'Sí' : 'No'}
</span>`
};
});
return renderSnippet(ackSnippet, { value: row.original.pedimento_validation?.electronic_signature });
}
},
{
accessorKey: "pedimento_payments.total_contributions",
header: "¿Se pagó el impuesto?",
cell: ({ row }) => {
const paidSnippet = createRawSnippet<[{ value?: string | null }]>((getValue) => {
const { value } = getValue();
const isPaid = value && parseFloat(value) > 0;
return {
render: () =>
`<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${isPaid ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800'}">
${isPaid ? 'Sí' : 'No'}
</span>`
};
});
return renderSnippet(paidSnippet, { value: row.original.pedimento_payments?.total_contributions });
}
},
{
accessorKey: "client_id",
header: "Cliente",

View File

@@ -203,7 +203,7 @@
<!-- Error Message -->
{#if error}
<Card.Root class="border-destructive">
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive dark:border-red-800">
<Card.Header>
<Card.Title class="text-destructive">Error</Card.Title>
<Card.Description>
@@ -214,11 +214,10 @@
{/if}
<!-- Data Table -->
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<div class="flex items-center justify-between">
<div>
<Card.Title>Listado de Clientes y Proveedores</Card.Title>
<Card.Description>
Mostrando {allItems.length} de {totalItems} registros
{#if companyStore.activeCompany}

View File

@@ -130,8 +130,13 @@
if (response.data) {
if (Array.isArray(response.data)) {
brokersList = response.data;
} else if (response.data.items && Array.isArray(response.data.items)) {
brokersList = response.data.items;
} else if (typeof response.data === 'object' && 'items' in response.data) {
const dataWithItems = response.data as { items?: CustomsBroker[] };
if (Array.isArray(dataWithItems.items)) {
brokersList = dataWithItems.items;
} else {
brokersList = [];
}
} else {
console.error("⚠️ Estructura de datos inesperada:", response.data);
brokersList = [];
@@ -171,9 +176,8 @@
</Button>
</div>
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<Card.Title>Buscar Agente Aduanal</Card.Title>
<Card.Description>
Ingresa la clave del agente aduanal para buscarlo
{#if companyStore.activeCompany}
@@ -222,7 +226,7 @@
</Card.Content>
</Card.Root>
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<div class="flex items-center justify-between">
<div>
@@ -271,4 +275,12 @@
</Card.Root>
</div>
<CreateDialog bind:open={showCreateDialog} onSuccess={handleSuccess} />
<CreateDialog
bind:open={showCreateDialog}
companyId={companyStore.activeCompany?.id.toString() || ''}
onSave={async (data) => {
// El CreateDialog maneja la creación internamente
// Después de guardar exitosamente, recargar los datos
await handleSuccess();
}}
/>

View File

@@ -121,11 +121,7 @@
</div>
</div>
<Card.Root>
<Card.Header>
<Card.Title>Búsqueda Rápida</Card.Title>
<Card.Description>Ingresa el número de parte o descripción para filtrar.</Card.Description>
</Card.Header>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Content>
<div class="flex gap-4">
<div class="flex-1 max-w-xl">
@@ -155,7 +151,7 @@
</Card.Content>
</Card.Root>
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<Card.Title>
{#if isSearching}

View File

@@ -392,11 +392,7 @@
</div>
<!-- Filtros -->
<Card.Root>
<Card.Header>
<Card.Title>Filtros</Card.Title>
<Card.Description>Filtra las facturas por diferentes criterios (los filtros se aplican automáticamente)</Card.Description>
</Card.Header>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Content>
<div class="grid grid-cols-1 md:grid-cols-5 gap-4">
<div class="space-y-2">
@@ -458,7 +454,7 @@
<!-- Error Message -->
{#if error}
<Card.Root class="border-destructive">
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive dark:border-red-800">
<Card.Header>
<Card.Title class="text-destructive">Error</Card.Title>
<Card.Description>{error}</Card.Description>
@@ -467,7 +463,7 @@
{/if}
<!-- Data Table -->
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<div class="flex items-center justify-between">
<div>

View File

@@ -267,18 +267,15 @@
</div>
<!-- Filtros -->
<Card.Root>
<Card.Header>
<Card.Title>Filtros</Card.Title>
<Card.Description>Filtra los pedimentos por diferentes criterios</Card.Description>
</Card.Header>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Content>
<form onsubmit={(e) => { e.preventDefault(); applyFilters(); }} class="grid grid-cols-1 md:grid-cols-4 gap-4">
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="space-y-2">
<Label for="filter-status">Estado</Label>
<select
id="filter-status"
bind:value={filters.status}
onchange={applyFilters}
class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
>
{#each statusOptions as option}
@@ -293,6 +290,7 @@
id="filter-client"
type="number"
bind:value={filters.client_id}
oninput={applyFilters}
placeholder="Ej: 123"
/>
</div>
@@ -302,27 +300,18 @@
<Input
id="filter-year"
bind:value={filters.year}
oninput={applyFilters}
placeholder="Ej: 23"
maxlength={2}
/>
</div>
<div class="flex items-end gap-2">
<Button type="submit" disabled={loading} class="flex-1">
<Filter class="mr-2" size={16} />
Filtrar
</Button>
<Button type="button" variant="outline" onclick={clearFilters} disabled={loading}>
<Trash2 size={16} />
</Button>
</div>
</form>
</div>
</Card.Content>
</Card.Root>
<!-- Error Message -->
{#if error}
<Card.Root class="border-destructive">
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-destructive">
<Card.Header>
<Card.Title class="text-destructive">Error</Card.Title>
<Card.Description>{error}</Card.Description>
@@ -331,7 +320,7 @@
{/if}
<!-- Data Table -->
<Card.Root>
<Card.Root class="bg-card dark:bg-black text-card-foreground dark:text-white border-border dark:border-gray-800">
<Card.Header>
<div class="flex items-center justify-between">
<div>