390 lines
11 KiB
TypeScript
390 lines
11 KiB
TypeScript
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";
|
|
|
|
/**
|
|
* Formatea un número como moneda
|
|
*/
|
|
function formatCurrency(value?: number | null): string {
|
|
if (value === null || value === undefined) return '-';
|
|
return new Intl.NumberFormat('es-MX', {
|
|
style: 'currency',
|
|
currency: 'USD',
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2
|
|
}).format(value);
|
|
}
|
|
|
|
/**
|
|
* Formatea un número con separadores de miles
|
|
*/
|
|
function formatNumber(value?: number | null, decimals = 2): string {
|
|
if (value === null || value === undefined) return '-';
|
|
return new Intl.NumberFormat('es-MX', {
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
}).format(value);
|
|
}
|
|
|
|
/**
|
|
* Formatea una fecha
|
|
*/
|
|
function formatDate(date?: string | null): string {
|
|
if (!date) return '-';
|
|
return new Date(date).toLocaleDateString('es-MX', {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Obtiene el color del badge según el status
|
|
*/
|
|
function getStatusColor(status?: string | null): string {
|
|
if (!status) return 'bg-gray-100 text-gray-800';
|
|
|
|
const statusUpper = status.toUpperCase();
|
|
|
|
// Estados completados/exitosos - Verde
|
|
if (statusUpper === 'VALIDADO' || statusUpper === 'PAGADO' || statusUpper === 'CARTA CUPO') {
|
|
return 'bg-green-100 text-green-800';
|
|
}
|
|
|
|
// Estados en espera/proceso - Amarillo
|
|
if (statusUpper.startsWith('ESPERA')) {
|
|
return 'bg-yellow-100 text-yellow-800';
|
|
}
|
|
|
|
// Estados con firma - Azul
|
|
if (statusUpper === 'CON FIRMA DE PREVIO') {
|
|
return 'bg-blue-100 text-blue-800';
|
|
}
|
|
|
|
// Estados modificables/editables - Índigo
|
|
if (statusUpper === 'MODIFICABLE') {
|
|
return 'bg-indigo-100 text-indigo-800';
|
|
}
|
|
|
|
// Estados de borrado - Naranja
|
|
if (statusUpper.includes('BORRADA')) {
|
|
return 'bg-orange-100 text-orange-800';
|
|
}
|
|
|
|
// Estados cancelados/desistidos - Rojo
|
|
if (statusUpper === 'DESISTIO') {
|
|
return 'bg-red-100 text-red-800';
|
|
}
|
|
|
|
// Default - Gris
|
|
return 'bg-gray-100 text-gray-800';
|
|
}
|
|
|
|
export function createColumns(onSuccess?: () => void): ColumnDef<Pedimento>[] {
|
|
return [
|
|
{
|
|
accessorKey: "id",
|
|
header: "ID",
|
|
cell: ({ row }) => {
|
|
const idSnippet = createRawSnippet<[{ id: number }]>((getId) => {
|
|
const { id } = getId();
|
|
return {
|
|
render: () =>
|
|
`<div class="font-medium">#${id}</div>`
|
|
};
|
|
});
|
|
return renderSnippet(idSnippet, { id: row.original.id });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "pedimento_number",
|
|
header: "Número de Pedimento",
|
|
cell: ({ row }) => {
|
|
const pedimento = row.original;
|
|
const fullNumber = `${pedimento.year || ''}-${pedimento.customs_office || ''}-${pedimento.license || ''}-${pedimento.pedimento_number || ''}`;
|
|
|
|
const numberSnippet = createRawSnippet<[{ number: string }]>((getNumber) => {
|
|
const { number } = getNumber();
|
|
return {
|
|
render: () =>
|
|
`<code class="relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono text-sm font-semibold">${number || 'N/A'}</code>`
|
|
};
|
|
});
|
|
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",
|
|
cell: ({ row }) => {
|
|
const clientSnippet = createRawSnippet<[{ clientId?: number | null }]>((getClient) => {
|
|
const { clientId } = getClient();
|
|
return {
|
|
render: () =>
|
|
`<div>${clientId ? `Cliente #${clientId}` : '-'}</div>`
|
|
};
|
|
});
|
|
return renderSnippet(clientSnippet, { clientId: row.original.client_id });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "status",
|
|
header: "Estado",
|
|
cell: ({ row }) => {
|
|
const status = row.original.status;
|
|
const colorClass = getStatusColor(status);
|
|
const formattedStatus = status
|
|
? status.charAt(0).toUpperCase() + status.slice(1).toLowerCase()
|
|
: 'N/A';
|
|
|
|
const statusSnippet = createRawSnippet<[{ status: string; colorClass: string }]>((getStatus) => {
|
|
const { status, colorClass } = getStatus();
|
|
return {
|
|
render: () =>
|
|
`<span class="inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${colorClass}">
|
|
${status}
|
|
</span>`
|
|
};
|
|
});
|
|
return renderSnippet(statusSnippet, { status: formattedStatus, colorClass });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "usd_value",
|
|
header: () => {
|
|
const headerSnippet = createRawSnippet(() => {
|
|
return {
|
|
render: () => `<div class="text-right">Valor USD</div>`
|
|
};
|
|
});
|
|
return renderSnippet(headerSnippet, {});
|
|
},
|
|
cell: ({ row }) => {
|
|
const valueSnippet = createRawSnippet<[{ value: string }]>((getValue) => {
|
|
const { value } = getValue();
|
|
return {
|
|
render: () =>
|
|
`<div class="text-right font-medium">${value}</div>`
|
|
};
|
|
});
|
|
return renderSnippet(valueSnippet, { value: formatCurrency(row.original.usd_value) });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "paid_price",
|
|
header: () => {
|
|
const headerSnippet = createRawSnippet(() => {
|
|
return {
|
|
render: () => `<div class="text-right">Precio Pagado</div>`
|
|
};
|
|
});
|
|
return renderSnippet(headerSnippet, {});
|
|
},
|
|
cell: ({ row }) => {
|
|
const priceSnippet = createRawSnippet<[{ price: string }]>((getPrice) => {
|
|
const { price } = getPrice();
|
|
return {
|
|
render: () =>
|
|
`<div class="text-right font-medium">${price}</div>`
|
|
};
|
|
});
|
|
return renderSnippet(priceSnippet, { price: formatCurrency(row.original.paid_price) });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "gross_weight",
|
|
header: () => {
|
|
const headerSnippet = createRawSnippet(() => {
|
|
return {
|
|
render: () => `<div class="text-right">Peso Bruto</div>`
|
|
};
|
|
});
|
|
return renderSnippet(headerSnippet, {});
|
|
},
|
|
cell: ({ row }) => {
|
|
const weightSnippet = createRawSnippet<[{ weight: string }]>((getWeight) => {
|
|
const { weight } = getWeight();
|
|
return {
|
|
render: () =>
|
|
`<div class="text-right">${weight}</div>`
|
|
};
|
|
});
|
|
return renderSnippet(weightSnippet, { weight: formatNumber(row.original.gross_weight, 3) });
|
|
}
|
|
},
|
|
{
|
|
accessorKey: "created_at",
|
|
header: "Fecha de Creación",
|
|
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.created_at) });
|
|
}
|
|
},
|
|
{
|
|
id: "actions",
|
|
cell: ({ row }) => {
|
|
return renderComponent(DataTableActions, { item: row.original, onSuccess });
|
|
}
|
|
}
|
|
];
|
|
}
|
|
|
|
// Mantener compatibilidad hacia atrás
|
|
export const columns = createColumns();
|