feature/api-doda-update
This commit is contained in:
@@ -73,7 +73,13 @@
|
||||
toast.success(m['sidebar.doda_alta.export_excel_success']());
|
||||
} catch (e) {
|
||||
const msg = e instanceof Error ? e.message : String(e);
|
||||
toast.error(msg || m['sidebar.doda_alta.export_excel_error']());
|
||||
const isEmpty =
|
||||
/no existen doda|no se encontr[óo] informaci[óo]n para exportar|no doda.*range/i.test(
|
||||
String(msg)
|
||||
);
|
||||
toast.error(
|
||||
isEmpty ? m['sidebar.doda_alta.export_no_data']() : (msg || m['sidebar.doda_alta.export_excel_error']())
|
||||
);
|
||||
} finally {
|
||||
busy = false;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Plus, Pencil, Trash2, Inbox } from 'lucide-svelte';
|
||||
import { cn } from '$lib/utils';
|
||||
import { dodaFormT } from '$lib/i18n/doda-form-strings';
|
||||
|
||||
interface Column {
|
||||
header: string;
|
||||
@@ -12,6 +13,8 @@
|
||||
|
||||
let {
|
||||
title = '',
|
||||
/** `en` / `es` (viene del padre; evita leer `page` aquí, más seguro con SSR) */
|
||||
locale: localeProp = 'es',
|
||||
columns = [],
|
||||
data = [],
|
||||
onAdd,
|
||||
@@ -24,6 +27,7 @@
|
||||
class: className = ''
|
||||
}: {
|
||||
title?: string;
|
||||
locale?: 'en' | 'es';
|
||||
columns: Column[];
|
||||
data: any[];
|
||||
onAdd?: () => void;
|
||||
@@ -34,6 +38,8 @@
|
||||
class?: string;
|
||||
} = $props();
|
||||
|
||||
const dodaLoc = $derived((localeProp === 'en' ? 'en' : 'es') as 'en' | 'es');
|
||||
|
||||
let selectedIndex = $state<number | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
@@ -86,7 +92,7 @@
|
||||
class="flex flex-col items-center justify-center gap-1 text-muted-foreground"
|
||||
>
|
||||
<Inbox class="h-5 w-5 opacity-45" />
|
||||
<span class="text-xs">Sin filas. «Nuevo» para añadir.</span>
|
||||
<span class="text-xs">{dodaFormT(dodaLoc, 'child_empty')}</span>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
@@ -133,7 +139,7 @@
|
||||
<div class="flex flex-wrap items-center justify-end gap-2 border-t border-border/30 bg-muted/20 px-3 py-2 sm:px-4">
|
||||
<Button variant="outline" size="sm" onclick={onAdd} class="h-8 gap-1.5 px-3 text-xs font-medium">
|
||||
<Plus class="h-3.5 w-3.5" />
|
||||
Nuevo
|
||||
{dodaFormT(dodaLoc, 'child_new')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
@@ -147,7 +153,7 @@
|
||||
disabled={data.length === 0 || selectedIndex == null}
|
||||
>
|
||||
<Pencil class="h-3.5 w-3.5" />
|
||||
Editar
|
||||
{dodaFormT(dodaLoc, 'child_edit')}
|
||||
</Button>
|
||||
<Button
|
||||
variant="destructive"
|
||||
@@ -161,7 +167,7 @@
|
||||
disabled={data.length === 0 || selectedIndex == null}
|
||||
>
|
||||
<Trash2 class="h-3.5 w-3.5" />
|
||||
Borrar
|
||||
{dodaFormT(dodaLoc, 'child_delete')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,6 +2,8 @@ import type { ColumnDef } from '@tanstack/table-core';
|
||||
import type { Doda } from '$lib/api/dashboard/a76/general_catalogs/doda';
|
||||
import { renderSnippet } from '$lib/components/ui/data-table';
|
||||
import { createRawSnippet } from 'svelte';
|
||||
import { getLocale } from '$lib/paraglide/runtime';
|
||||
import { dodaFormT, type DodaFormKey } from '$lib/i18n/doda-form-strings';
|
||||
|
||||
/**
|
||||
* doda_date se almacena como Integer con formato YYYYMMDD (ej. 20180409).
|
||||
@@ -18,7 +20,7 @@ function formatDodaDate(val?: number | string | null): string {
|
||||
}
|
||||
// Fallback: ISO string
|
||||
try {
|
||||
return new Date(s).toLocaleDateString('es-MX', {
|
||||
return new Date(s).toLocaleDateString(getLocale() === 'en' ? 'en-US' : 'es-MX', {
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
year: 'numeric'
|
||||
@@ -36,11 +38,12 @@ const STATUS_CLASSES: Record<string, string> = {
|
||||
ELIMINADO: 'bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300',
|
||||
};
|
||||
|
||||
export function createColumns(): ColumnDef<Doda>[] {
|
||||
export function createColumns(loc: 'en' | 'es'): ColumnDef<Doda>[] {
|
||||
const t = (k: DodaFormKey) => dodaFormT(loc, k);
|
||||
return [
|
||||
{
|
||||
accessorKey: 'id',
|
||||
header: 'Folio',
|
||||
header: t('list_col_folio'),
|
||||
size: 70,
|
||||
cell: ({ row }) => {
|
||||
const n = row.original.id;
|
||||
@@ -53,7 +56,7 @@ export function createColumns(): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
accessorKey: 'doda_date',
|
||||
header: 'Fecha Doda',
|
||||
header: t('list_col_doda_date'),
|
||||
size: 100,
|
||||
cell: ({ row }) => {
|
||||
const d = formatDodaDate(row.original.doda_date);
|
||||
@@ -65,19 +68,19 @@ export function createColumns(): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
accessorKey: 'dispatch_customs',
|
||||
header: 'Desp.',
|
||||
header: t('list_col_desp'),
|
||||
size: 60,
|
||||
cell: ({ row }) => row.original.dispatch_customs || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'patent',
|
||||
header: 'Patente',
|
||||
header: t('list_col_patent'),
|
||||
size: 70,
|
||||
cell: ({ row }) => row.original.patent || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'pedimentos',
|
||||
header: 'Pedimento(s)',
|
||||
header: t('list_col_pedimentos'),
|
||||
cell: ({ row }) => {
|
||||
const v = row.original.pedimentos || '-';
|
||||
const s = createRawSnippet(() => ({
|
||||
@@ -89,13 +92,13 @@ export function createColumns(): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
accessorKey: 'shipments',
|
||||
header: 'Remesa(s)',
|
||||
header: t('list_col_remesas'),
|
||||
size: 90,
|
||||
cell: ({ row }) => row.original.shipments || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'integration_number',
|
||||
header: 'Integración',
|
||||
header: t('list_col_integracion'),
|
||||
size: 110,
|
||||
cell: ({ row }) => {
|
||||
const v = row.original.integration_number;
|
||||
@@ -110,7 +113,7 @@ export function createColumns(): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
accessorKey: 'transaction_number',
|
||||
header: 'No. Transacción',
|
||||
header: t('list_col_trans'),
|
||||
cell: ({ row }) => {
|
||||
const v = row.original.transaction_number || '-';
|
||||
const s = createRawSnippet(() => ({
|
||||
@@ -122,25 +125,25 @@ export function createColumns(): ColumnDef<Doda>[] {
|
||||
},
|
||||
{
|
||||
accessorKey: 'transport_identification',
|
||||
header: 'Id. Transporte',
|
||||
header: t('list_col_id_transport'),
|
||||
size: 120,
|
||||
cell: ({ row }) => row.original.transport_identification || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'caat',
|
||||
header: 'CAAT',
|
||||
header: t('list_col_caat'),
|
||||
size: 70,
|
||||
cell: ({ row }) => row.original.caat || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'last_user',
|
||||
header: 'Usuario',
|
||||
header: t('list_col_user'),
|
||||
size: 90,
|
||||
cell: ({ row }) => row.original.last_user || '-'
|
||||
},
|
||||
{
|
||||
accessorKey: 'status',
|
||||
header: 'Estatus',
|
||||
header: t('list_col_status'),
|
||||
size: 110,
|
||||
cell: ({ row }) => {
|
||||
const status = (row.original.status || '').toUpperCase();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { type ColumnDef, getCoreRowModel } 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 { dodaFormT } from '$lib/i18n/doda-form-strings';
|
||||
|
||||
type DataTableProps<TData, TValue> = {
|
||||
columns: ColumnDef<TData, TValue>[];
|
||||
@@ -13,6 +14,8 @@
|
||||
selectedId?: number | null;
|
||||
onRowClick?: (row: TData) => void;
|
||||
onRowDoubleClick?: (row: TData) => void;
|
||||
/** Solo catálogo DODA: textos i18n de carga / vacío */
|
||||
locale?: 'en' | 'es';
|
||||
};
|
||||
|
||||
let {
|
||||
@@ -23,9 +26,12 @@
|
||||
loadMore,
|
||||
selectedId = null,
|
||||
onRowClick,
|
||||
onRowDoubleClick
|
||||
onRowDoubleClick,
|
||||
locale = 'es'
|
||||
}: DataTableProps<TData, TValue> = $props();
|
||||
|
||||
const loc = $derived((locale === 'en' ? 'en' : 'es') as 'en' | 'es');
|
||||
|
||||
const table = createSvelteTable({
|
||||
get data() {
|
||||
return data;
|
||||
@@ -108,7 +114,7 @@
|
||||
{:else}
|
||||
<Table.Row inTabOrder={false}>
|
||||
<Table.Cell colspan={columns.length} class="h-24 text-center text-sm text-muted-foreground">
|
||||
No hay resultados.
|
||||
{dodaFormT(loc, 'list_no_results')}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
@@ -122,10 +128,10 @@
|
||||
<div
|
||||
class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"
|
||||
></div>
|
||||
<span class="text-sm text-muted-foreground">Cargando más...</span>
|
||||
<span class="text-sm text-muted-foreground">{dodaFormT(loc, 'list_loading_more')}</span>
|
||||
</div>
|
||||
{:else}
|
||||
<div class="text-sm text-muted-foreground">Desplázate para cargar más</div>
|
||||
<div class="text-sm text-muted-foreground">{dodaFormT(loc, 'list_scroll_for_more')}</div>
|
||||
{/if}
|
||||
</div>
|
||||
</Table.Cell>
|
||||
|
||||
@@ -72,6 +72,9 @@ export function isPitaCustomsClearance(customsClearance: number | undefined | nu
|
||||
return customsClearance === 1;
|
||||
}
|
||||
|
||||
/** Códigos de error para mapear a i18n (`sidebar.doda_form.*`). */
|
||||
export type AmericanPedimentoTipoError = 'required' | 'import_range' | 'export_range' | 'op_undefined';
|
||||
|
||||
/**
|
||||
* Valida `american_pedimento_type` frente a `operation_type` (legacy Clarion).
|
||||
* Importación: tipos 1–5. Exportación: tipos 6–8.
|
||||
@@ -79,9 +82,9 @@ export function isPitaCustomsClearance(customsClearance: number | undefined | nu
|
||||
export function validateAmericanPedimentoTipo(
|
||||
operationType: string | undefined,
|
||||
tipo: string | undefined
|
||||
): string | null {
|
||||
): AmericanPedimentoTipoError | null {
|
||||
const t = (tipo || '').trim();
|
||||
if (!t) return 'El tipo de pedimento americano es obligatorio.';
|
||||
if (!t) return 'required';
|
||||
|
||||
const op = (operationType || '').trim().toUpperCase();
|
||||
const isImport = op === 'I' || op === '1';
|
||||
@@ -89,14 +92,14 @@ export function validateAmericanPedimentoTipo(
|
||||
|
||||
if (isImport) {
|
||||
if (!['1', '2', '3', '4', '5'].includes(t)) {
|
||||
return 'El tipo de pedimento americano no es correcto para importación (debe ser 1, 2, 3, 4 o 5).';
|
||||
return 'import_range';
|
||||
}
|
||||
} else if (isExport) {
|
||||
if (!['6', '7', '8'].includes(t)) {
|
||||
return 'El tipo de pedimento americano no es correcto para exportación (debe ser 6, 7 u 8).';
|
||||
return 'export_range';
|
||||
}
|
||||
} else {
|
||||
return 'Define el tipo de operación (I/E) antes de validar el pedimento americano.';
|
||||
return 'op_undefined';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user