feature/checkpoin-before-table

This commit is contained in:
hreyes
2026-03-12 12:54:33 -06:00
parent e1d4ef4a68
commit 678f91ecdc
4 changed files with 271 additions and 49 deletions

View File

@@ -161,6 +161,7 @@ export interface Item {
fcc_key?: string;
has_certificate?: boolean;
certificate_number?: string;
certificate_end_date?: string;
octave_permit?: string;
// Flags
@@ -174,6 +175,11 @@ export interface Item {
igi_payment_method?: string;
igi_amount?: number;
// Export valuation (Met Valor, Valor Det., Motivo De Uso)
valuation_method?: string;
valuation_determined_value?: number;
valuation_reason?: string;
// Additional notes
wildcard_field?: string;

View File

@@ -72,6 +72,24 @@
return visibility.showCrTrackingHeader;
});
/** Show link-to-import block for import (CR tracking) or for export when showExportLinkToImportBlock. */
const showLinkToImportBlock = $derived.by(() => {
const normalizedOperationType = operationType ?? invoice?.operation_type;
if (normalizedOperationType === 1 || normalizedOperationType === 'exp') {
return visibility.showExportLinkToImportBlock;
}
return visibility.showCrTrackingHeader;
});
const isExport = $derived.by(() => {
const op = operationType ?? invoice?.operation_type;
return op === 1 || op === 'exp';
});
/** Show repair-import block (Factura de Expo / Línea de Expo) for REP/REPAR. */
const showRepairBlock = $derived.by(() => {
const op = operationType ?? invoice?.operation_type;
if (op === 1 || op === 'exp') return false;
return visibility.showRepairLinkToExportBlock;
});
const visibleTabs = $derived.by(() => [
{ value: 'generales', label: 'General', visible: true },
{ value: 'continuacion', label: 'Continuación', visible: true },
@@ -117,52 +135,117 @@
<div class="space-y-2">
{#if line}
{#if showCrTrackingBlock}
<div class="grid grid-cols-1 gap-2 lg:grid-cols-4">
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_invoice" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Factura Impo
{#if showRepairBlock}
<!-- Importación de Reparación: Genera Descarga? + Factura de Expo + Línea de Expo -->
<div class="space-y-2 rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<div class="flex items-center gap-4">
<span class="text-[10px] font-semibold uppercase tracking-wide text-zinc-500">Genera Descarga?</span>
<label class="flex items-center gap-1.5">
<input type="radio" name="fa_rep_download" value="si" checked={editingItem.fa_data?.download === true} onchange={() => (editingItem.fa_data = editingItem.fa_data || {}, editingItem.fa_data.download = true)} class="rounded border-input" />
<span class="text-xs"></span>
</label>
<label class="flex items-center gap-1.5">
<input type="radio" name="fa_rep_download" value="no" checked={editingItem.fa_data?.download === false || editingItem.fa_data?.download === undefined} onchange={() => (editingItem.fa_data = editingItem.fa_data || {}, editingItem.fa_data.download = false)} class="rounded border-input" />
<span class="text-xs">No</span>
</label>
<input
id="fa_search_invoice"
type="text"
bind:value={editingItem.fa_data.search_invoice}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_line" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Línea
</label>
<input
id="fa_search_line"
type="number"
min="0"
bind:value={editingItem.fa_data.search_line}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
<div class="grid grid-cols-1 gap-2 lg:grid-cols-4">
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_rep_search_invoice" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Factura de Expo
</label>
<input
id="fa_rep_search_invoice"
type="text"
bind:value={editingItem.fa_data.search_invoice}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_rep_search_line" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Línea de Expo
</label>
<input
id="fa_rep_search_line"
type="number"
min="0"
bind:value={editingItem.fa_data.search_line}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_rep_search_type" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Tipo Búsqueda
</label>
<input
id="fa_rep_search_type"
type="text"
bind:value={editingItem.fa_data.search_type}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_type" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Tipo Búsqueda
</div>
{:else if showLinkToImportBlock}
<div class="space-y-2 rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<!-- Genera Descarga? visible when block is shown (expo or import CR per legacy). -->
<div class="flex items-center gap-4">
<span class="text-[10px] font-semibold uppercase tracking-wide text-zinc-500">Genera Descarga?</span>
<label class="flex items-center gap-1.5">
<input type="radio" name="fa_download" value="si" checked={editingItem.fa_data?.download === true} onchange={() => (editingItem.fa_data = editingItem.fa_data || {}, editingItem.fa_data.download = true)} class="rounded border-input" />
<span class="text-xs"></span>
</label>
<label class="flex items-center gap-1.5">
<input type="radio" name="fa_download" value="no" checked={editingItem.fa_data?.download === false || editingItem.fa_data?.download === undefined} onchange={() => (editingItem.fa_data = editingItem.fa_data || {}, editingItem.fa_data.download = false)} class="rounded border-input" />
<span class="text-xs">No</span>
</label>
<input
id="fa_search_type"
type="text"
bind:value={editingItem.fa_data.search_type}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_movement_type_import" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Tipo Movimiento
</label>
<input
id="fa_movement_type_import"
type="text"
bind:value={editingItem.fa_data.movement_type_import}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
<div class="grid grid-cols-1 gap-2 lg:grid-cols-4">
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_invoice" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Factura Impo
</label>
<input
id="fa_search_invoice"
type="text"
bind:value={editingItem.fa_data.search_invoice}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_line" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Línea
</label>
<input
id="fa_search_line"
type="number"
min="0"
bind:value={editingItem.fa_data.search_line}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_search_type" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Tipo Búsqueda
</label>
<input
id="fa_search_type"
type="text"
bind:value={editingItem.fa_data.search_type}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
<div class="rounded border border-zinc-200 bg-white p-2 dark:border-zinc-800 dark:bg-zinc-900">
<label for="fa_movement_type_import" class="mb-1 block text-[10px] font-semibold uppercase tracking-wide text-zinc-500">
Tipo Importación / Tipo Movimiento
</label>
<input
id="fa_movement_type_import"
type="text"
bind:value={editingItem.fa_data.movement_type_import}
class="flex h-8 w-full rounded-md border border-input bg-background px-3 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
/>
</div>
</div>
</div>
{/if}

View File

@@ -94,6 +94,7 @@
<div class="grid grid-cols-1 items-start gap-2 lg:grid-cols-2">
<!-- Left Column -->
<div class="space-y-2">
{#if visibility.showContinuationTaxPayment}
<!-- TAX PAID -->
<div class="grid grid-cols-4 gap-2">
<fieldset class="border rounded p-1.5 space-y-1">
@@ -131,7 +132,9 @@
<Label for="credito_iva" class="text-xs">{payment_method_description || ''}</Label>
</div>
</div>
{/if}
{#if visibility.showContinuationIgi}
<!-- IGI Amount -->
<div class="grid grid-cols-2 gap-2">
<div class="space-y-0.5">
@@ -143,6 +146,7 @@
<Input id="igi_payment_method" bind:value={lineItem.igi_payment_method} class="h-6 text-xs" />
</div>
</div>
{/if}
{#if visibility.showFdaFcc}
<div class="space-y-2 rounded-md border p-2">
@@ -185,12 +189,41 @@
</fieldset>
<div class="col-span-3 space-y-0.5">
<Label for="num_cert_origen" class="text-xs">Certificate of Origin No.:</Label>
<Input id="num_cert_origen" bind:value={lineItem.certificate_number} class="h-6 text-xs" />
<Label for="num_cert_origen" class="text-xs">End Date:</Label>
<Input id="num_cert_origen" bind:value={lineItem.certificate_number} class="h-6 text-xs" disabled={!lineItem.has_certificate} />
<Label for="cert_end_date" class="text-xs">End Date:</Label>
<Input id="cert_end_date" type="text" bind:value={lineItem.certificate_end_date} class="h-6 text-xs" placeholder="YYYY-MM-DD" disabled={!lineItem.has_certificate} />
</div>
</div>
{/if}
{#if visibility.showExportValuationFields || visibility.showValuationFields}
<!-- Valoración: Met Valor, Valor Det., Motivo De Uso (expo or import CR per legacy). -->
<div class="space-y-2 rounded-md border p-2">
<div class="text-xs font-semibold">Valoración</div>
<div class="grid grid-cols-1 gap-2 lg:grid-cols-3">
<div class="space-y-0.5">
<Label for="met_valor" class="text-xs">Met Valor:</Label>
<Input id="met_valor" bind:value={lineItem.valuation_method} class="h-6 text-xs" maxlength={2} placeholder="Método" />
</div>
<div class="space-y-0.5">
<Label for="valor_det" class="text-xs">Valor Det.:</Label>
<Input id="valor_det" type="number" step="0.00000001" bind:value={lineItem.valuation_determined_value} class="h-6 text-xs" />
</div>
<div class="space-y-0.5 lg:col-span-1">
<Label for="motivo_uso" class="text-xs">Motivo De Uso:</Label>
<textarea
id="motivo_uso"
bind:value={lineItem.valuation_reason}
class="min-h-[60px] w-full rounded-md border border-input bg-background px-2 py-1 text-xs ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
placeholder="Razón valoración"
maxlength={500}
></textarea>
</div>
</div>
</div>
{/if}
{#if visibility.showContinuationLocation}
<!-- Location -->
<div class="space-y-1">
<div class="space-y-0.5">
@@ -201,13 +234,17 @@
<Label for="localizacion_maquinaria" class="text-xs">Location variable</Label>
</div>
</div>
{/if}
{#if visibility.showContinuationMilitary}
<!-- Military Equipment -->
<div class="flex items-center space-x-1.5 ">
<Checkbox id="equipo_militar" bind:checked={lineItem.is_military_mcia} />
<Label for="equipo_militar" class="text-xs font-normal">Enable if Item Contains Military Equipment</Label>
</div>
{/if}
{#if visibility.showContinuationOwnOmitAnnex}
<div class="grid grid-cols-1 gap-2 lg:grid-cols-2">
<div class="flex items-center space-x-1.5 ">
<Checkbox id="fa_own_equipment" bind:checked={lineItem.fa_data.own_equipment} />
@@ -218,7 +255,9 @@
<Label for="fa_omit_annex31" class="text-xs font-normal">Omit Annex 31</Label>
</div>
</div>
{/if}
{#if visibility.showContinuationLotEntry}
<!-- Lot and Entry Number -->
<div class="grid grid-cols-2 gap-2">
<div class="space-y-0.5">
@@ -229,7 +268,8 @@
<Label for="num_entrada" class="text-xs">Entry No.:</Label>
<Input id="num_entrada" bind:value={descriptions.entry_number} class="h-6 text-xs" />
</div>
</div>
</div>
{/if}
</div>
<!-- Right Column -->
@@ -255,13 +295,16 @@
</div>
</div>
{/if}
{#if visibility.showContinuationConsiderA31}
<!-- Consider in a31 -->
<div class="flex items-center space-x-1.5 ">
<Checkbox id="a31" bind:checked={descriptions.consider_a31} />
<Label for="a31" class="text-xs font-normal">Consider in A31</Label>
</div>
{/if}
{#if visibility.showContinuationExtraDescription}
<!-- Extra Description -->
<div class="flex-1 space-y-0.5">
<Label for="desc_extra_espanol" class="text-xs">Extra Description in Spanish:</Label>
@@ -270,7 +313,8 @@
bind:value={descriptions.description_spanish}
class="flex min-h-[60px] w-full flex-1 rounded-md border border-input bg-background px-2 py-1 text-xs ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
></textarea>
</div>
</div>
{/if}
</div>
</div>
<PaymentMethodDialog bind:open={paymentMethodDialogOpen} onSelect={handlePaymentMethodSelect} />

View File

@@ -1,9 +1,36 @@
/** Export invoice types that affect item visibility (tipo factura for operation_type === exp). */
export type ExportInvoiceType = 'NODES' | 'AFIJO' | 'DONAC' | 'SCRAP';
export interface InvoiceItemVisibility {
showCrTrackingHeader: boolean;
showEighthRule: boolean;
showFdaFcc: boolean;
showCertificateOfOrigin: boolean;
showIdentifiersTab: boolean;
/** Show block: Genera Descarga? + Tipo Importación + Tipo Búsqueda + Factura de Impo + Línea (expo, or import CR). */
showExportLinkToImportBlock: boolean;
/** Show Met Valor, Valor Det., Motivo De Uso in Continuación tab (expo). */
showExportValuationFields: boolean;
/** Show Met Valor, Valor Det., Motivo De Uso for import (e.g. Cambio de Régimen). */
showValuationFields: boolean;
/** Show block: Genera Descarga? + Factura de Expo + Línea de Expo (importación reparación, REP). */
showRepairLinkToExportBlock: boolean;
/** Continuación tab: TAX PAID + Forma Pago. */
showContinuationTaxPayment: boolean;
/** Continuación tab: IGI Amount + IGI Payment Method. */
showContinuationIgi: boolean;
/** Continuación tab: Machinery and equipment location. */
showContinuationLocation: boolean;
/** Continuación tab: Military Equipment checkbox. */
showContinuationMilitary: boolean;
/** Continuación tab: Own Equipment + Omit Annex 31. */
showContinuationOwnOmitAnnex: boolean;
/** Continuación tab: Lot + Entry No. */
showContinuationLotEntry: boolean;
/** Continuación tab: Consider in A31. */
showContinuationConsiderA31: boolean;
/** Continuación tab: Extra Description in Spanish. */
showContinuationExtraDescription: boolean;
}
const defaultVisibility: InvoiceItemVisibility = {
@@ -11,7 +38,19 @@ const defaultVisibility: InvoiceItemVisibility = {
showEighthRule: true,
showFdaFcc: true,
showCertificateOfOrigin: true,
showIdentifiersTab: true
showIdentifiersTab: true,
showExportLinkToImportBlock: false,
showExportValuationFields: false,
showValuationFields: false,
showRepairLinkToExportBlock: false,
showContinuationTaxPayment: true,
showContinuationIgi: true,
showContinuationLocation: true,
showContinuationMilitary: true,
showContinuationOwnOmitAnnex: true,
showContinuationLotEntry: true,
showContinuationConsiderA31: true,
showContinuationExtraDescription: true
};
function normalizeInvoiceType(invoiceType?: string | null): string {
@@ -45,12 +84,40 @@ function normalizeOperationType(operationType?: string | number | null): 'imp' |
return null;
}
const EXPORT_INVOICE_TYPES: ExportInvoiceType[] = ['NODES', 'AFIJO', 'DONAC', 'SCRAP'];
function normalizeExportInvoiceType(exportInvoiceType?: string | null): ExportInvoiceType {
const normalized = String(exportInvoiceType || '')
.trim()
.toUpperCase();
if (EXPORT_INVOICE_TYPES.includes(normalized as ExportInvoiceType)) {
return normalized as ExportInvoiceType;
}
return 'AFIJO';
}
export function getVisibility(
invoiceType?: string | null,
operationType?: string | number | null
): InvoiceItemVisibility {
if (normalizeOperationType(operationType) === 'exp') {
return defaultVisibility;
const exportType = normalizeExportInvoiceType(invoiceType);
// Base visibility for export: existing flags stay true; export-only flags set by type.
const expVisibility: InvoiceItemVisibility = {
...defaultVisibility,
showExportLinkToImportBlock: true,
showExportValuationFields: true
};
// Per-type overrides can be added here (e.g. hide valuation for SCRAP).
switch (exportType) {
case 'NODES':
case 'AFIJO':
case 'DONAC':
case 'SCRAP':
return expVisibility;
default:
return expVisibility;
}
}
switch (normalizeInvoiceType(invoiceType)) {
@@ -65,7 +132,29 @@ export function getVisibility(
case 'CR':
return {
...defaultVisibility,
showEighthRule: false
showEighthRule: false,
showValuationFields: true
};
case 'REP':
case 'REPAR':
// Continuación: solo campos de la captura (sin Valoración, FDA/FCC, Regla Octava, Own/Omit, Lote/Entrada, Consider A31)
return {
...defaultVisibility,
showCrTrackingHeader: false,
showRepairLinkToExportBlock: true,
showValuationFields: false,
showFdaFcc: false,
showCertificateOfOrigin: true,
showEighthRule: false,
showContinuationTaxPayment: true,
showContinuationIgi: true,
showContinuationLocation: true,
showContinuationMilitary: true,
showContinuationOwnOmitAnnex: false,
showContinuationLotEntry: false,
showContinuationConsiderA31: false,
showContinuationExtraDescription: true
};
case 'MEX':