Partidas por tipo de factura en importacion
This commit is contained in:
@@ -35,6 +35,33 @@ export interface IdentifierListResponse {
|
||||
pages: number;
|
||||
}
|
||||
|
||||
export interface IdentifierDetail {
|
||||
id: number;
|
||||
invoice_consecutive: number | null;
|
||||
part_line: number | null;
|
||||
identifier_code: string | null;
|
||||
module: string | null;
|
||||
complement1: string | null;
|
||||
complement2: string | null;
|
||||
complement3: string | null;
|
||||
item_line_id: number | null;
|
||||
company_id: number;
|
||||
tenant_id: number;
|
||||
}
|
||||
|
||||
export interface IdentifierDetailCreate {
|
||||
invoice_consecutive?: number | null;
|
||||
part_line?: number | null;
|
||||
identifier_code?: string | null;
|
||||
module?: string | null;
|
||||
complement1?: string | null;
|
||||
complement2?: string | null;
|
||||
complement3?: string | null;
|
||||
item_line_id?: number | null;
|
||||
}
|
||||
|
||||
export interface IdentifierDetailUpdate extends Partial<IdentifierDetailCreate> { }
|
||||
|
||||
export async function getIdentifiers(
|
||||
page = 1,
|
||||
pageSize = 50,
|
||||
@@ -71,4 +98,29 @@ export async function deleteIdentifier(
|
||||
companyId: number
|
||||
): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/identifiers/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* API for Identifier Details
|
||||
*/
|
||||
export async function createIdentifierDetail(
|
||||
data: IdentifierDetailCreate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<IdentifierDetail>> {
|
||||
return await api.post(`/v1/a76/identifiers/details/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function updateIdentifierDetail(
|
||||
id: number,
|
||||
data: IdentifierDetailUpdate,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<IdentifierDetail>> {
|
||||
return await api.put(`/v1/a76/identifiers/details/${id}/?company_id=${companyId}`, data);
|
||||
}
|
||||
|
||||
export async function deleteIdentifierDetail(
|
||||
id: number,
|
||||
companyId: number
|
||||
): Promise<ApiResponse<void>> {
|
||||
return await api.delete(`/v1/a76/identifiers/details/${id}/?company_id=${companyId}`);
|
||||
}
|
||||
@@ -88,6 +88,10 @@ export interface LineReferences {
|
||||
serie_id?: number;
|
||||
}
|
||||
|
||||
import type {
|
||||
IdentifierDetail
|
||||
} from './general_catalogs/identifiers';
|
||||
|
||||
export interface Serie {
|
||||
id?: number;
|
||||
line_item_id?: number;
|
||||
@@ -98,6 +102,9 @@ export interface Serie {
|
||||
brand?: string;
|
||||
expo_brad?: string;
|
||||
number_id?: string;
|
||||
import_invoice?: string;
|
||||
import_line?: number;
|
||||
image_path?: string;
|
||||
}
|
||||
|
||||
export interface FaLineItem {
|
||||
@@ -207,6 +214,7 @@ export interface Item {
|
||||
reference?: LineReferences;
|
||||
fa_data?: FaLineItem; // Fixed Asset specific data
|
||||
series?: Serie[]; // Series data (multiple per line)
|
||||
identifiers?: IdentifierDetail[]; // Identifiers for this line
|
||||
}
|
||||
|
||||
export interface ItemListResponse {
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<script lang="ts">
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Search, Loader2 } from "lucide-svelte";
|
||||
import { getIdentifiers, type Identifier } from "$lib/api/dashboard/a76/general_catalogs/identifiers";
|
||||
import { onMount } from "svelte";
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
onSelect
|
||||
}: {
|
||||
open: boolean;
|
||||
onSelect: (identifier: Identifier) => void;
|
||||
} = $props();
|
||||
|
||||
let identifiers = $state<Identifier[]>([]);
|
||||
let loading = $state(false);
|
||||
let searchTerm = $state("");
|
||||
|
||||
async function loadIdentifiers() {
|
||||
const companyId = companyStore?.activeCompany?.id;
|
||||
if (!companyId) return;
|
||||
|
||||
loading = true;
|
||||
try {
|
||||
// Using a large limit for now to avoid complex pagination in the selector
|
||||
const res = await getIdentifiers(1, 1000, companyId);
|
||||
if (res.data) {
|
||||
identifiers = res.data.items || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading identifiers:", error);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadIdentifiers();
|
||||
});
|
||||
|
||||
const filteredIdentifiers = $derived(
|
||||
identifiers.filter(i =>
|
||||
i.code.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
(i.description?.toLowerCase().includes(searchTerm.toLowerCase()) ?? false)
|
||||
)
|
||||
);
|
||||
|
||||
function handleSelect(identifier: Identifier) {
|
||||
onSelect(identifier);
|
||||
open = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[600px] h-[600px] flex flex-col p-0 text-xs">
|
||||
<Dialog.Header class="px-6 pt-6 pb-4 shrink-0">
|
||||
<Dialog.Title>Seleccionar Identificador</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Busca y selecciona un identificador del catálogo (Apéndice 8).
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="px-6 pb-4 shrink-0">
|
||||
<div class="relative">
|
||||
<Search class="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Buscar por clave o descripción..."
|
||||
class="pl-9 h-9 text-xs"
|
||||
bind:value={searchTerm}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto px-6 pb-6">
|
||||
{#if loading}
|
||||
<div class="flex h-full items-center justify-center">
|
||||
<Loader2 class="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
{:else}
|
||||
<Table.Root>
|
||||
<Table.Header class="sticky top-0 bg-background z-10">
|
||||
<Table.Row>
|
||||
<Table.Head class="w-16">Clave</Table.Head>
|
||||
<Table.Head>Descripción</Table.Head>
|
||||
<Table.Head class="w-16">Nivel</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each filteredIdentifiers as item}
|
||||
<Table.Row
|
||||
class="cursor-pointer hover:bg-muted"
|
||||
onclick={() => handleSelect(item)}
|
||||
>
|
||||
<Table.Cell class="font-bold">{item.code}</Table.Cell>
|
||||
<Table.Cell>{item.description || '-'}</Table.Cell>
|
||||
<Table.Cell>{item.level || '-'}</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={3} class="h-24 text-center text-muted-foreground">
|
||||
No se encontraron identificadores.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
{/if}
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -216,7 +216,7 @@
|
||||
{ value: 'generales', label: 'General', visible: true },
|
||||
{ value: 'continuacion', label: 'Continuación', visible: true },
|
||||
{ value: 'series', label: 'Series', visible: true },
|
||||
{ value: 'etiquetado', label: 'Etiquetado', visible: true },
|
||||
{ value: 'etiquetado', label: 'Etiquetado', visible: visibility.showLabelingTab },
|
||||
{ value: 'identificadores', label: 'IDs', visible: visibility.showIdentifiersTab }
|
||||
].filter((tab) => tab.visible));
|
||||
const tabListStyle = $derived(`grid-template-columns: repeat(${visibleTabs.length || 1}, minmax(0, 1fr));`);
|
||||
@@ -544,13 +544,20 @@
|
||||
/>
|
||||
</Tabs.Content>
|
||||
|
||||
<Tabs.Content value="etiquetado" class="m-0 focus-visible:outline-none">
|
||||
<TabLabeling bind:descriptions={editingItem.description!} />
|
||||
</Tabs.Content>
|
||||
{#if visibility.showLabelingTab}
|
||||
<Tabs.Content value="etiquetado" class="m-0 focus-visible:outline-none">
|
||||
<TabLabeling bind:lineItem={editingItem} bind:descriptions={editingItem.description!} {visibility} />
|
||||
</Tabs.Content>
|
||||
{/if}
|
||||
|
||||
{#if visibility.showIdentifiersTab}
|
||||
<Tabs.Content value="identificadores" class="m-0 focus-visible:outline-none">
|
||||
<TabIdentifiers bind:lineItem={editingItem} />
|
||||
<TabIdentifiers
|
||||
bind:lineItem={editingItem}
|
||||
invoiceConsecutive={invoice?.id}
|
||||
invoiceNumber={invoice?.invoice_number ?? ''}
|
||||
{visibility}
|
||||
/>
|
||||
</Tabs.Content>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -1,26 +1,376 @@
|
||||
<script lang="ts">
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import type { Item } from '$lib/api/dashboard/a76/items';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Table from '$lib/components/ui/table';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { Plus, Pencil, Trash2, Search, Image as ImageIcon, Upload } from 'lucide-svelte';
|
||||
import type { Item, Serie } from '$lib/api/dashboard/a76/items';
|
||||
import type { IdentifierDetail } from '$lib/api/dashboard/a76/general_catalogs/identifiers';
|
||||
import IdentifierCatalogSelector from './identifier-catalog-selector.svelte';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
|
||||
let { lineItem = $bindable() }: { lineItem: Partial<Item> } = $props();
|
||||
let {
|
||||
lineItem = $bindable(),
|
||||
invoiceConsecutive = undefined,
|
||||
invoiceNumber = '',
|
||||
visibility = { showMexicanIdEnhanced: false }
|
||||
}: {
|
||||
lineItem: Partial<Item>,
|
||||
invoiceConsecutive?: number,
|
||||
invoiceNumber?: string,
|
||||
visibility?: any
|
||||
} = $props();
|
||||
|
||||
// Initialize identifiers if not present
|
||||
if (!lineItem.identifiers) {
|
||||
lineItem.identifiers = [];
|
||||
}
|
||||
// Initialize series if not present
|
||||
if (!lineItem.series) {
|
||||
lineItem.series = [];
|
||||
}
|
||||
|
||||
let showModal = $state(false);
|
||||
let showMexModal = $state(false);
|
||||
let showCatalogSelector = $state(false);
|
||||
let isEditing = $state(false);
|
||||
let editingIndex = $state(-1);
|
||||
|
||||
// State for standard Identifiers
|
||||
let currentDetail = $state<Partial<IdentifierDetail>>({
|
||||
invoice_consecutive: invoiceConsecutive || null,
|
||||
part_line: lineItem.line_number || null,
|
||||
module: 'SCAF-IT',
|
||||
identifier_code: '',
|
||||
complement1: '',
|
||||
complement2: '',
|
||||
complement3: ''
|
||||
});
|
||||
|
||||
// State for MEX Assets
|
||||
let currentMexAsset = $state<Partial<Serie>>({
|
||||
number_id: '',
|
||||
import_invoice: invoiceNumber || '',
|
||||
import_line: lineItem.line_number ?? undefined,
|
||||
image_path: ''
|
||||
});
|
||||
|
||||
// Standard ID Functions
|
||||
function openInsert() {
|
||||
isEditing = false;
|
||||
currentDetail = {
|
||||
invoice_consecutive: invoiceConsecutive ?? null,
|
||||
part_line: lineItem.line_number ?? null,
|
||||
module: 'SCAF-IT',
|
||||
identifier_code: '',
|
||||
complement1: '',
|
||||
complement2: '',
|
||||
complement3: ''
|
||||
};
|
||||
showModal = true;
|
||||
}
|
||||
|
||||
function openEdit(index: number) {
|
||||
isEditing = true;
|
||||
editingIndex = index;
|
||||
currentDetail = { ...lineItem.identifiers![index] };
|
||||
showModal = true;
|
||||
}
|
||||
|
||||
function deleteDetail(index: number) {
|
||||
lineItem.identifiers = lineItem.identifiers!.filter((_, i) => i !== index);
|
||||
}
|
||||
|
||||
function saveDetail() {
|
||||
if (!lineItem.identifiers) lineItem.identifiers = [];
|
||||
if (isEditing) {
|
||||
lineItem.identifiers[editingIndex] = currentDetail as IdentifierDetail;
|
||||
} else {
|
||||
lineItem.identifiers = [...lineItem.identifiers, currentDetail as IdentifierDetail];
|
||||
}
|
||||
showModal = false;
|
||||
}
|
||||
|
||||
// MEX Asset Functions
|
||||
function openMexInsert() {
|
||||
isEditing = false;
|
||||
currentMexAsset = {
|
||||
number_id: '',
|
||||
import_invoice: invoiceNumber || '',
|
||||
import_line: lineItem.line_number ?? undefined,
|
||||
image_path: ''
|
||||
};
|
||||
showMexModal = true;
|
||||
}
|
||||
|
||||
function openMexEdit(index: number) {
|
||||
isEditing = true;
|
||||
editingIndex = index;
|
||||
currentMexAsset = { ...lineItem.series![index] };
|
||||
showMexModal = true;
|
||||
}
|
||||
|
||||
function deleteMexAsset(index: number) {
|
||||
lineItem.series = lineItem.series!.filter((_, i) => i !== index);
|
||||
}
|
||||
|
||||
function saveMexAsset() {
|
||||
if (!lineItem.series) lineItem.series = [];
|
||||
if (isEditing) {
|
||||
lineItem.series[editingIndex] = currentMexAsset as Serie;
|
||||
} else {
|
||||
lineItem.series = [...lineItem.series, currentMexAsset as Serie];
|
||||
}
|
||||
showMexModal = false;
|
||||
}
|
||||
|
||||
function handleCatalogSelect(identifier: any) {
|
||||
currentDetail.identifier_code = identifier.code;
|
||||
showCatalogSelector = false;
|
||||
}
|
||||
|
||||
// File selection simulation for image_path
|
||||
function triggerFileSelect() {
|
||||
// In a real scenario, this would trigger an input type="file"
|
||||
// For now we'll just simulate setting a path/name
|
||||
const simulatedPath = `assets/img_${Date.now()}.jpg`;
|
||||
currentMexAsset.image_path = simulatedPath;
|
||||
}
|
||||
</script>
|
||||
|
||||
<fieldset class="border rounded-md p-3 space-y-3">
|
||||
<legend class="text-xs font-semibold px-2 uppercase">Identifiers</legend>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="identificador1" class="text-xs">Main Identifier:</Label>
|
||||
<Input id="identificador1" bind:value={lineItem.identifier} class="h-8 text-sm" />
|
||||
</div>
|
||||
<div class="space-y-4">
|
||||
{#if visibility.showMexicanIdEnhanced}
|
||||
<!-- MEX Specific Layout -->
|
||||
<fieldset class="border rounded-md p-3">
|
||||
<legend class="text-xs font-semibold px-2 uppercase flex items-center gap-2">
|
||||
Activos / Num. Etiquetado (MEX)
|
||||
</legend>
|
||||
|
||||
<div class="flex justify-end mb-2">
|
||||
<Button size="sm" variant="outline" class="h-8 text-xs gap-1" onclick={openMexInsert}>
|
||||
<Plus class="h-3 w-3" />
|
||||
Insertar Activo
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="notas_identificadores" class="text-xs">Additional Identifiers / Notes:</Label>
|
||||
<textarea
|
||||
id="notas_identificadores"
|
||||
bind:value={lineItem.wildcard_field}
|
||||
class="flex min-h-[120px] w-full rounded-md border-2 border-input dark:border-zinc-600 bg-background dark:text-white px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 dark:focus-visible:border-zinc-400 dark:focus-visible:ring-zinc-400/50"
|
||||
placeholder="Additional identifiers or notes..."
|
||||
></textarea>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="border rounded-md overflow-hidden bg-white dark:bg-zinc-900">
|
||||
<Table.Root>
|
||||
<Table.Header class="bg-gray-50 dark:bg-zinc-800">
|
||||
<Table.Row class="h-8">
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Asset Number</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Num. Factura</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Línea</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8 text-center">Imagen</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8 w-20 text-center">Acciones</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#if lineItem.series && lineItem.series.length > 0}
|
||||
{#each lineItem.series as asset, index}
|
||||
<Table.Row class="h-8 hover:bg-gray-50 dark:hover:bg-zinc-800/50 transition-colors">
|
||||
<Table.Cell class="py-1 text-xs font-semibold">{asset.number_id}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">{asset.import_invoice || '-'}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">{asset.import_line || '-'}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs text-center">
|
||||
{#if asset.image_path}
|
||||
<div class="flex justify-center">
|
||||
<ImageIcon class="h-4 w-4 text-blue-500" />
|
||||
</div>
|
||||
{:else}
|
||||
<span class="text-gray-400">-</span>
|
||||
{/if}
|
||||
</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<Button size="icon" variant="ghost" class="h-6 w-6 text-blue-500 hover:text-blue-600 hover:bg-blue-50" onclick={() => openMexEdit(index)}>
|
||||
<Pencil class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button size="icon" variant="ghost" class="h-6 w-6 text-red-500 hover:text-red-600 hover:bg-red-50" onclick={() => deleteMexAsset(index)}>
|
||||
<Trash2 class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={5} class="h-20 text-center text-gray-400 text-xs italic">
|
||||
No hay activos registrados.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/if}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
</fieldset>
|
||||
{:else}
|
||||
<!-- Standard ID Layout -->
|
||||
<fieldset class="border rounded-md p-3">
|
||||
<legend class="text-xs font-semibold px-2 uppercase flex items-center gap-2">
|
||||
Tabla de Identificadores
|
||||
</legend>
|
||||
|
||||
<div class="flex justify-end mb-2">
|
||||
<Button size="sm" variant="outline" class="h-8 text-xs gap-1" onclick={openInsert}>
|
||||
<Plus class="h-3 w-3" />
|
||||
Insertar
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="border rounded-md overflow-hidden bg-white dark:bg-zinc-900">
|
||||
<Table.Root>
|
||||
<Table.Header class="bg-gray-100 dark:bg-zinc-800">
|
||||
<Table.Row class="h-8">
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Clave</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Compl. 1</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Compl. 2</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8">Compl. 3</Table.Head>
|
||||
<Table.Head class="text-[10px] uppercase font-bold text-gray-600 dark:text-gray-300 h-8 w-20 text-center">Acciones</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#if lineItem.identifiers && lineItem.identifiers.length > 0}
|
||||
{#each lineItem.identifiers as idDetail, index}
|
||||
<Table.Row class="h-8 hover:bg-gray-50 dark:hover:bg-zinc-800/50 transition-colors">
|
||||
<Table.Cell class="py-1 text-xs font-semibold">{idDetail.identifier_code}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">{idDetail.complement1 || '-'}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">{idDetail.complement2 || '-'}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">{idDetail.complement3 || '-'}</Table.Cell>
|
||||
<Table.Cell class="py-1 text-xs">
|
||||
<div class="flex items-center justify-center gap-1">
|
||||
<Button size="icon" variant="ghost" class="h-6 w-6 text-blue-500 hover:text-blue-600 hover:bg-blue-50" onclick={() => openEdit(index)}>
|
||||
<Pencil class="h-3 w-3" />
|
||||
</Button>
|
||||
<Button size="icon" variant="ghost" class="h-6 w-6 text-red-500 hover:text-red-600 hover:bg-red-50" onclick={() => deleteDetail(index)}>
|
||||
<Trash2 class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={5} class="h-20 text-center text-gray-400 text-xs italic">
|
||||
No hay identificadores registrados.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/if}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
</fieldset>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Modal Standard ID -->
|
||||
<Dialog.Root bind:open={showModal}>
|
||||
<Dialog.Content class="sm:max-w-[500px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{isEditing ? 'Editar' : 'Insertar'} Identificador</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Ingrese los detalles del identificador para esta partida.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4 py-4">
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Consecutivo Factura</Label>
|
||||
<Input bind:value={currentDetail.invoice_consecutive} readonly class="h-8 text-xs bg-gray-50" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Partida (Número)</Label>
|
||||
<Input bind:value={currentDetail.part_line} readonly class="h-8 text-xs bg-gray-50" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Módulo</Label>
|
||||
<Input bind:value={currentDetail.module} class="h-8 text-xs" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Clave</Label>
|
||||
<div class="flex gap-1">
|
||||
<Input bind:value={currentDetail.identifier_code} class="h-8 text-xs font-bold" placeholder="Clave" />
|
||||
<Button size="icon" variant="outline" class="h-8 w-8 shrink-0" onclick={() => showCatalogSelector = true}>
|
||||
<Search class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 grid grid-cols-3 gap-2">
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Complemento 1</Label>
|
||||
<Input bind:value={currentDetail.complement1} class="h-8 text-xs" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Complemento 2</Label>
|
||||
<Input bind:value={currentDetail.complement2} class="h-8 text-xs" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Complemento 3</Label>
|
||||
<Input bind:value={currentDetail.complement3} class="h-8 text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button variant="outline" onclick={() => showModal = false} class="h-8 text-xs">Cancelar</Button>
|
||||
<Button onclick={saveDetail} class="h-8 text-xs">Guardar</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<!-- Modal MEX Assets -->
|
||||
<Dialog.Root bind:open={showMexModal}>
|
||||
<Dialog.Content class="sm:max-w-[450px]">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>{isEditing ? 'Editar' : 'Insertar'} Asset Tag (Etiquetado)</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Detalles del etiquetado de activos para Compras Mexicanas.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="space-y-4 py-4">
|
||||
<!-- Info Section -->
|
||||
<div class="bg-gray-50 dark:bg-zinc-800 p-3 rounded-md grid grid-cols-2 gap-3 border">
|
||||
<div class="space-y-1">
|
||||
<Label class="text-[10px] uppercase text-gray-500">Número de Factura</Label>
|
||||
<p class="text-xs font-bold">{currentMexAsset.import_invoice || '-'}</p>
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<Label class="text-[10px] uppercase text-gray-500">Línea de Partida</Label>
|
||||
<p class="text-xs font-bold">{currentMexAsset.import_line || '-'}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Input Section -->
|
||||
<div class="space-y-3">
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Asset Number</Label>
|
||||
<Input bind:value={currentMexAsset.number_id} placeholder="Ingrese número de activo..." class="h-9 text-xs" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label class="text-xs">Imagen del Archivo</Label>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex-1 h-9 px-3 py-2 border rounded-md bg-white dark:bg-zinc-900 text-xs truncate italic text-gray-500">
|
||||
{currentMexAsset.image_path || 'Ningún archivo seleccionado'}
|
||||
</div>
|
||||
<Button size="sm" variant="secondary" class="h-9 gap-1 text-xs" onclick={triggerFileSelect}>
|
||||
<Upload class="h-3 w-3" />
|
||||
Subir
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button variant="outline" onclick={() => showMexModal = false} class="h-8 text-xs">Cancelar</Button>
|
||||
<Button onclick={saveMexAsset} class="h-8 text-xs">Guardar</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<IdentifierCatalogSelector
|
||||
bind:open={showCatalogSelector}
|
||||
onSelect={handleCatalogSelect}
|
||||
/>
|
||||
|
||||
@@ -1,32 +1,256 @@
|
||||
<script lang="ts">
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import type { LineDescriptions } from '$lib/api/dashboard/a76/items';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Table from '$lib/components/ui/table';
|
||||
import { Plus, Pencil, Trash2, Folder } from 'lucide-svelte';
|
||||
import type { Item, LineDescriptions, Serie } from '$lib/api/dashboard/a76/items';
|
||||
import ValuationMethodSelector from './valuation-method-selector.svelte';
|
||||
|
||||
let { descriptions = $bindable() }: { descriptions: LineDescriptions } = $props();
|
||||
let {
|
||||
lineItem = $bindable(),
|
||||
descriptions = $bindable(),
|
||||
visibility
|
||||
}: {
|
||||
lineItem: Partial<Item>,
|
||||
descriptions: LineDescriptions,
|
||||
visibility: any
|
||||
} = $props();
|
||||
|
||||
// Ensure series is an array
|
||||
if (!lineItem.series) {
|
||||
lineItem.series = [];
|
||||
}
|
||||
|
||||
let valuationSelectorOpen = $state(false);
|
||||
|
||||
// Asset management state
|
||||
let selectedAssetIndex = $state<number | null>(null);
|
||||
let editingAsset = $state<Serie>({
|
||||
row: 0,
|
||||
number_id: '',
|
||||
import_invoice: '',
|
||||
import_line: undefined
|
||||
});
|
||||
|
||||
function handleValuationMethodSelect(method: { key: string }) {
|
||||
lineItem.valuation_method = method.key;
|
||||
}
|
||||
|
||||
function addAsset() {
|
||||
const newAsset: Serie = {
|
||||
row: (lineItem.series?.length || 0) + 1,
|
||||
number_id: '',
|
||||
import_invoice: '',
|
||||
import_line: undefined
|
||||
};
|
||||
lineItem.series = [...(lineItem.series || []), newAsset];
|
||||
editAsset((lineItem.series || []).length - 1);
|
||||
}
|
||||
|
||||
function editAsset(index: number) {
|
||||
selectedAssetIndex = index;
|
||||
editingAsset = { ...(lineItem.series?.[index] as Serie) };
|
||||
}
|
||||
|
||||
function saveAsset() {
|
||||
if (selectedAssetIndex !== null && lineItem.series) {
|
||||
const updatedSeries = [...lineItem.series];
|
||||
updatedSeries[selectedAssetIndex] = { ...editingAsset };
|
||||
lineItem.series = updatedSeries;
|
||||
selectedAssetIndex = null;
|
||||
}
|
||||
}
|
||||
|
||||
function deleteAsset(index: number) {
|
||||
if (lineItem.series) {
|
||||
lineItem.series = lineItem.series.filter((_, i) => i !== index);
|
||||
// Re-index rows
|
||||
lineItem.series = lineItem.series.map((s, i) => ({ ...s, row: i + 1 }));
|
||||
if (selectedAssetIndex === index) {
|
||||
selectedAssetIndex = null;
|
||||
} else if (selectedAssetIndex !== null && selectedAssetIndex > index) {
|
||||
selectedAssetIndex--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cancelAssetEdit() {
|
||||
selectedAssetIndex = null;
|
||||
}
|
||||
</script>
|
||||
|
||||
<fieldset class="border rounded-md p-3 space-y-3">
|
||||
<legend class="text-xs font-semibold px-2 uppercase">Labeling</legend>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="numero_etiqueta" class="text-xs">Label Number:</Label>
|
||||
<Input id="numero_etiqueta" bind:value={descriptions.lot} class="h-8 text-sm" />
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="tipo_etiqueta" class="text-xs">Label Type:</Label>
|
||||
<Input id="tipo_etiqueta" bind:value={descriptions.entry_number} class="h-8 text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||
<!-- Left Side: Labeling & Valuation -->
|
||||
<fieldset class="border rounded-md p-2 space-y-2">
|
||||
<legend class="text-xs font-semibold px-2 bg-gray-200 dark:bg-gray-700 uppercase">Labeling & Valuation</legend>
|
||||
|
||||
{#if visibility.showLabelingStandard}
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="space-y-1">
|
||||
<Label for="numero_etiqueta" class="text-xs">Label Number:</Label>
|
||||
<Input id="numero_etiqueta" bind:value={descriptions.lot} class="h-7 text-xs" />
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<Label for="tipo_etiqueta" class="text-xs">Label Type:</Label>
|
||||
<Input id="tipo_etiqueta" bind:value={descriptions.entry_number} class="h-7 text-xs" />
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="observaciones_etiqueta" class="text-xs">Observations:</Label>
|
||||
<textarea
|
||||
id="observaciones_etiqueta"
|
||||
bind:value={descriptions.additional_info_spanish}
|
||||
class="flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
|
||||
placeholder="Labeling observations..."
|
||||
></textarea>
|
||||
</div>
|
||||
</fieldset>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
{#if visibility.showLabelingEnhanced}
|
||||
{#if visibility.showLabelingQuantity}
|
||||
<div class="space-y-1">
|
||||
<Label for="cantidad_importar" class="text-xs">Cantidad a importar:</Label>
|
||||
<Input
|
||||
id="cantidad_importar"
|
||||
type="number"
|
||||
bind:value={lineItem.quantity!.quantity}
|
||||
class="h-7 text-xs"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
<div class="space-y-1">
|
||||
<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-7 text-xs"
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
{#if visibility.showLabelingEnhanced}
|
||||
<div class="space-y-1">
|
||||
<Label for="metodos_valoracion" class="text-xs">Métodos de valoración:</Label>
|
||||
<div class="flex gap-1">
|
||||
<Input
|
||||
id="metodos_valoracion"
|
||||
bind:value={lineItem.valuation_method}
|
||||
class="h-7 text-xs flex-1"
|
||||
placeholder="Seleccione..."
|
||||
/>
|
||||
<Button
|
||||
size="icon"
|
||||
variant="outline"
|
||||
class="h-7 w-7"
|
||||
onclick={() => valuationSelectorOpen = true}
|
||||
>
|
||||
<Folder class="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{#if visibility.showUsageReason}
|
||||
<div class="space-y-1">
|
||||
<Label for="motivo_uso" class="text-xs">Motivo de uso:</Label>
|
||||
<Input
|
||||
id="motivo_uso"
|
||||
bind:value={lineItem.valuation_reason}
|
||||
class="h-7 text-xs"
|
||||
placeholder="Especifique motivo..."
|
||||
/>
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
|
||||
{#if visibility.showLabelingStandard}
|
||||
<div class="space-y-1">
|
||||
<Label for="observaciones_etiqueta" class="text-xs">Observations:</Label>
|
||||
<textarea
|
||||
id="observaciones_etiqueta"
|
||||
bind:value={descriptions.additional_info_spanish}
|
||||
class="flex min-h-[60px] w-full rounded-md border border-input bg-background px-3 py-1.5 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"
|
||||
placeholder="Labeling observations..."
|
||||
></textarea>
|
||||
</div>
|
||||
{/if}
|
||||
</fieldset>
|
||||
|
||||
{#if visibility.showLabelingEnhanced}
|
||||
<!-- Right Side: Assets Table -->
|
||||
<fieldset class="border rounded-md p-2 space-y-2">
|
||||
<legend class="text-xs font-semibold px-2 bg-gray-200 dark:bg-gray-700 uppercase">Assets / Series</legend>
|
||||
|
||||
<div class="flex justify-end">
|
||||
<Button size="sm" variant="outline" class="h-7 text-xs px-2" onclick={addAsset}>
|
||||
<Plus class="h-3 h-3 mr-1" /> Insertar Activo
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div class="rounded-md border overflow-hidden max-h-[180px] overflow-y-auto">
|
||||
<Table.Root>
|
||||
<Table.Header>
|
||||
<Table.Row class="bg-muted/50 h-7">
|
||||
<Table.Head class="w-8 text-center text-[10px] p-0 px-1">#</Table.Head>
|
||||
<Table.Head class="text-[10px] p-0 px-1">Asset Num</Table.Head>
|
||||
<Table.Head class="text-[10px] p-0 px-1">Factura</Table.Head>
|
||||
<Table.Head class="text-[10px] p-0 px-1">Línea</Table.Head>
|
||||
<Table.Head class="w-14 text-right text-[10px] p-0 px-2">Acc</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each lineItem.series || [] as asset, i}
|
||||
<Table.Row class="hover:bg-muted/50 h-7">
|
||||
<Table.Cell class="text-center text-[10px] p-0 px-1 font-medium">{asset.row || i+1}</Table.Cell>
|
||||
<Table.Cell class="text-[10px] p-0 px-1 truncate max-w-[60px]">{asset.number_id || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-[10px] p-0 px-1 truncate max-w-[60px]">{asset.import_invoice || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-[10px] p-0 px-1">{asset.import_line || '-'}</Table.Cell>
|
||||
<Table.Cell class="text-right p-0 px-2">
|
||||
<div class="flex justify-end gap-0.5">
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5" onclick={() => editAsset(i)}>
|
||||
<Pencil class="h-2.5 w-2.5" />
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" class="h-5 w-5 text-destructive" onclick={() => deleteAsset(i)}>
|
||||
<Trash2 class="h-2.5 w-2.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={5} class="h-12 text-center text-muted-foreground text-[10px]">
|
||||
No hay activos.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
</div>
|
||||
|
||||
{#if selectedAssetIndex !== null}
|
||||
<div class="p-2 border rounded bg-muted/20 space-y-2">
|
||||
<div class="text-[10px] font-semibold uppercase">Editar #{editingAsset.row}</div>
|
||||
<div class="grid grid-cols-2 gap-2">
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-[10px]">Asset Number</Label>
|
||||
<Input bind:value={editingAsset.number_id} class="h-6 text-[10px]" />
|
||||
</div>
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-[10px]">Factura Impo</Label>
|
||||
<Input bind:value={editingAsset.import_invoice} class="h-6 text-[10px]" />
|
||||
</div>
|
||||
<div class="space-y-0.5">
|
||||
<Label class="text-[10px]">Linea Impo</Label>
|
||||
<Input type="number" bind:value={editingAsset.import_line} class="h-6 text-[10px]" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end gap-1.5 pt-1">
|
||||
<Button size="sm" variant="ghost" class="h-6 text-[10px] px-2" onclick={cancelAssetEdit}>Can</Button>
|
||||
<Button size="sm" class="h-6 text-[10px] px-2" onclick={saveAsset}>Guar</Button>
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
</fieldset>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<ValuationMethodSelector
|
||||
bind:open={valuationSelectorOpen}
|
||||
onSelect={handleValuationMethodSelect}
|
||||
/>
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<script lang="ts">
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import * as Table from "$lib/components/ui/table";
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Search, Loader2 } from "lucide-svelte";
|
||||
import { valuationMethodsApi, type ValuationMethod } from "$lib/api/dashboard/reference_data/valuation_methods";
|
||||
import { onMount } from "svelte";
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
onSelect
|
||||
}: {
|
||||
open: boolean;
|
||||
onSelect: (method: ValuationMethod) => void;
|
||||
} = $props();
|
||||
|
||||
let methods = $state<ValuationMethod[]>([]);
|
||||
let loading = $state(false);
|
||||
let searchTerm = $state("");
|
||||
|
||||
async function loadMethods() {
|
||||
loading = true;
|
||||
try {
|
||||
const res = await valuationMethodsApi.list(1, 100);
|
||||
if (res.data) {
|
||||
methods = res.data.items || [];
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error loading valuation methods:", error);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
loadMethods();
|
||||
});
|
||||
|
||||
const filteredMethods = $derived(
|
||||
methods.filter(m =>
|
||||
m.key.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
||||
m.description.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
)
|
||||
);
|
||||
|
||||
function handleSelect(method: ValuationMethod) {
|
||||
onSelect(method);
|
||||
open = false;
|
||||
}
|
||||
</script>
|
||||
|
||||
<Dialog.Root bind:open>
|
||||
<Dialog.Content class="sm:max-w-[500px] h-[600px] flex flex-col p-0">
|
||||
<Dialog.Header class="px-6 pt-6 pb-4 shrink-0">
|
||||
<Dialog.Title>Seleccionar Método de Valoración</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Busca y selecciona un método de valoración de la lista.
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
<div class="px-6 pb-4 shrink-0">
|
||||
<div class="relative">
|
||||
<Search class="absolute left-2.5 top-2.5 h-4 w-4 text-muted-foreground" />
|
||||
<Input
|
||||
type="search"
|
||||
placeholder="Buscar por clave o descripción..."
|
||||
class="pl-9 h-9"
|
||||
bind:value={searchTerm}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 overflow-y-auto px-6 pb-6">
|
||||
{#if loading}
|
||||
<div class="flex h-full items-center justify-center">
|
||||
<Loader2 class="h-6 w-6 animate-spin text-muted-foreground" />
|
||||
</div>
|
||||
{:else}
|
||||
<Table.Root>
|
||||
<Table.Header class="sticky top-0 bg-background z-10">
|
||||
<Table.Row>
|
||||
<Table.Head class="w-20">Clave</Table.Head>
|
||||
<Table.Head>Descripción</Table.Head>
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
<Table.Body>
|
||||
{#each filteredMethods as method}
|
||||
<Table.Row
|
||||
class="cursor-pointer hover:bg-muted"
|
||||
onclick={() => handleSelect(method)}
|
||||
>
|
||||
<Table.Cell class="font-medium">{method.key}</Table.Cell>
|
||||
<Table.Cell>{method.description}</Table.Cell>
|
||||
</Table.Row>
|
||||
{:else}
|
||||
<Table.Row>
|
||||
<Table.Cell colspan={2} class="h-24 text-center text-muted-foreground">
|
||||
No se encontraron métodos de valoración.
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{/each}
|
||||
</Table.Body>
|
||||
</Table.Root>
|
||||
{/if}
|
||||
</div>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
@@ -31,6 +31,18 @@ export interface InvoiceItemVisibility {
|
||||
showContinuationConsiderA31: boolean;
|
||||
/** Continuación tab: Extra Description in Spanish. */
|
||||
showContinuationExtraDescription: boolean;
|
||||
/** Etiquetado tab: Quantity, Valuation, Assets Table. */
|
||||
showLabelingEnhanced: boolean;
|
||||
/** Identificadores tab: Special Assets table for MEX. */
|
||||
showMexicanIdEnhanced: boolean;
|
||||
/** Etiquetado tab visibility. */
|
||||
showLabelingTab: boolean;
|
||||
/** Etiquetado tab: Usage Reason field. */
|
||||
showUsageReason: boolean;
|
||||
/** Etiquetado tab: Standard fields (Label No, Type, Observations). */
|
||||
showLabelingStandard: boolean;
|
||||
/** Etiquetado tab: Quantity field. */
|
||||
showLabelingQuantity: boolean;
|
||||
}
|
||||
|
||||
const defaultVisibility: InvoiceItemVisibility = {
|
||||
@@ -50,7 +62,13 @@ const defaultVisibility: InvoiceItemVisibility = {
|
||||
showContinuationOwnOmitAnnex: true,
|
||||
showContinuationLotEntry: true,
|
||||
showContinuationConsiderA31: true,
|
||||
showContinuationExtraDescription: true
|
||||
showContinuationExtraDescription: true,
|
||||
showLabelingEnhanced: false,
|
||||
showMexicanIdEnhanced: false,
|
||||
showLabelingTab: true,
|
||||
showUsageReason: false,
|
||||
showLabelingStandard: true,
|
||||
showLabelingQuantity: false
|
||||
};
|
||||
|
||||
function normalizeInvoiceType(invoiceType?: string | null): string {
|
||||
@@ -126,14 +144,21 @@ export function getVisibility(
|
||||
return {
|
||||
...defaultVisibility,
|
||||
showCrTrackingHeader: false,
|
||||
showFdaFcc: false
|
||||
showFdaFcc: false,
|
||||
showLabelingEnhanced: true,
|
||||
showLabelingQuantity: true
|
||||
};
|
||||
|
||||
case 'CR':
|
||||
return {
|
||||
...defaultVisibility,
|
||||
showEighthRule: false,
|
||||
showValuationFields: true
|
||||
showIdentifiersTab: true,
|
||||
showValuationFields: true,
|
||||
showUsageReason: true,
|
||||
showLabelingEnhanced: true,
|
||||
showLabelingQuantity: false,
|
||||
showLabelingStandard: false
|
||||
};
|
||||
|
||||
case 'REP':
|
||||
@@ -165,7 +190,9 @@ export function getVisibility(
|
||||
showEighthRule: false,
|
||||
showFdaFcc: false,
|
||||
showCertificateOfOrigin: false,
|
||||
showIdentifiersTab: false,
|
||||
showIdentifiersTab: true,
|
||||
showMexicanIdEnhanced: true,
|
||||
showLabelingTab: false,
|
||||
showContinuationIgi: false,
|
||||
showContinuationLocation: true,
|
||||
showContinuationMilitary: false,
|
||||
|
||||
Reference in New Issue
Block a user