701 lines
24 KiB
Svelte
701 lines
24 KiB
Svelte
<script lang="ts">
|
|
import { onMount } from 'svelte';
|
|
import { browser } from '$app/environment';
|
|
import { page } from '$app/stores';
|
|
import * as Tabs from '$lib/components/ui/tabs';
|
|
import * as Card from '$lib/components/ui/card';
|
|
import { Button } from '$lib/components/ui/button';
|
|
import { Label } from '$lib/components/ui/label';
|
|
import { Input } from '$lib/components/ui/input';
|
|
import { Badge } from '$lib/components/ui/badge';
|
|
import { Separator } from '$lib/components/ui/separator';
|
|
import {
|
|
LoaderCircle, Save, FileText, Eye, DollarSign,
|
|
Truck, Package, ArrowLeft
|
|
} from 'lucide-svelte';
|
|
import { toast } from 'svelte-sonner';
|
|
import { api } from '$lib/api';
|
|
import { goto } from '$app/navigation';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '$lib/components/ui/select';
|
|
// Import Form Components
|
|
import GeneralTabForm from '$lib/components/dashboard/invoices/edit/general-tab-form.svelte';
|
|
import ObservationsTabForm from '$lib/components/dashboard/invoices/edit/observations-tab-form.svelte';
|
|
import ItemsTabForm from '$lib/components/dashboard/invoices/edit/items/items-tab-form.svelte';
|
|
import OthersTabForm from '$lib/components/dashboard/invoices/edit/others-tab-form.svelte';
|
|
import InvoiceTopFields from '$lib/components/dashboard/invoices/edit/invoice-top-fields.svelte';
|
|
import ContinuationTabForm from '$lib/components/dashboard/invoices/edit/continuation-tab-form.svelte';
|
|
import SsimpSettingsForm from '$lib/components/dashboard/invoices/settings/ssimp-settings-form.svelte';
|
|
import SsisdefSettingsForm from '$lib/components/dashboard/invoices/settings/ssisdef-settings-form.svelte';
|
|
import SsicmSettingsForm from '$lib/components/dashboard/invoices/settings/ssicm-settings-form.svelte';
|
|
import SscrSettingsForm from '$lib/components/dashboard/invoices/settings/sscr-settings-form.svelte';
|
|
|
|
// Props
|
|
let { data } = $props();
|
|
|
|
// State
|
|
let selectedInvoiceType = $state<string>('');
|
|
let selectedOperationType = $state<string>('');
|
|
let isLoading = $state(false);
|
|
let isSaving = $state(false);
|
|
let activeTab = $state('general');
|
|
let companyStore: any = $state(undefined);
|
|
|
|
// Form Data State - Initialize as null to let components self-initialize
|
|
let InvoiceTopFieldsFormData = $state<any>(null);
|
|
let generalFormData = $state<any>(null);
|
|
let observationFormData = $state<any>(null);
|
|
let itemsFormData = $state<any>(null);
|
|
let othersFormData = $state<any>(null);
|
|
let continuationFormData = $state<any>(null);
|
|
let ssimpFormData = $state<any>(null);
|
|
|
|
// Derived object for components to consume context
|
|
// We use a getter to avoid circular reactivity issues during initialization
|
|
let invoice = $derived.by(() => ({
|
|
id: 0,
|
|
tenant_id: 0,
|
|
company_id: companyStore?.activeCompany?.id || 0,
|
|
capture_date: new Date().toISOString(),
|
|
operation_type: selectedOperationType,
|
|
invoice_type: selectedInvoiceType,
|
|
financials: { exchange_rate: 0 },
|
|
compliance_mx: {
|
|
pedimento_id: InvoiceTopFieldsFormData?.pedimento_id || '',
|
|
remesa: InvoiceTopFieldsFormData?.remesa || ''
|
|
},
|
|
invoice_number: InvoiceTopFieldsFormData?.invoice_number || '',
|
|
invoice_date: InvoiceTopFieldsFormData?.invoice_date || '',
|
|
alternate_invoice: observationFormData?.alternate_invoice || ''
|
|
}) as any);
|
|
|
|
// Existence flags (not strictly needed for settings but required by components)
|
|
let observationExists = $state(false);
|
|
let itemsExists = $state(false);
|
|
let othersExists = $state(false);
|
|
let continuationExists = $state(false);
|
|
|
|
const operationTypes = [
|
|
{ value: 'imp', label: 'Importación' },
|
|
{ value: 'exp', label: 'Exportación' }
|
|
];
|
|
|
|
onMount(async () => {
|
|
try {
|
|
const companyStoreModule = await import('$lib/stores/company.svelte');
|
|
companyStore = companyStoreModule.companyStore;
|
|
} catch (err) {
|
|
console.error('Error loading company store:', err);
|
|
}
|
|
});
|
|
|
|
async function loadSettings() {
|
|
if (!selectedInvoiceType || !selectedOperationType || !companyStore?.activeCompany?.id) return;
|
|
|
|
isLoading = true;
|
|
try {
|
|
const res = await api.get(
|
|
`/v1/a76/invoice-settings/${selectedInvoiceType}?operation_type=${selectedOperationType}&company_id=${companyStore.activeCompany.id}`
|
|
);
|
|
|
|
if (res.status === 200 || res.data) {
|
|
const settingsData = res.data;
|
|
if (settingsData && settingsData.settings) {
|
|
applySettings(settingsData.settings);
|
|
} else {
|
|
resetForms();
|
|
}
|
|
} else {
|
|
resetForms();
|
|
}
|
|
} catch (error) {
|
|
console.error('Error loading settings', error);
|
|
resetForms();
|
|
} finally {
|
|
isLoading = false;
|
|
}
|
|
}
|
|
|
|
function applySettings(settings: any) {
|
|
InvoiceTopFieldsFormData = {
|
|
is_pedimento_pending: false,
|
|
pedimento_id: '',
|
|
remesa: '',
|
|
invoice_number: '',
|
|
invoice_date: new Date().toISOString().split('T')[0],
|
|
emission_date: new Date().toISOString().split('T')[0],
|
|
operation_type: selectedOperationType,
|
|
invoice_type: selectedInvoiceType,
|
|
fecha_pedimento_del: '',
|
|
fecha_pedimento_al: '',
|
|
clave_pedimento: '',
|
|
regimen_pedimento: '',
|
|
...(settings.InvoiceTopFieldsFormData || {})
|
|
};
|
|
generalFormData = {
|
|
provider_header: 'proveedor',
|
|
provider_id: null,
|
|
sold_to_header: 'consignado_a',
|
|
sold_to_id: null,
|
|
shipped_to_header: 'enviado_a',
|
|
shipped_to_id: null,
|
|
customs_broker_id: null,
|
|
customs_broker_us_id: null,
|
|
currency_type: '',
|
|
currency: 'foreign',
|
|
exchange_rate: null,
|
|
weight_type: 'kgs',
|
|
iva_factor: null,
|
|
carrier_id: null,
|
|
transport_id: '',
|
|
driver_name: '',
|
|
transport_type: '',
|
|
transport_num: '',
|
|
aduana: '',
|
|
document_type: '',
|
|
...(settings.generalFormData || {})
|
|
};
|
|
observationFormData = {
|
|
observation_es: '',
|
|
observation_en: '',
|
|
freight: null,
|
|
insurance_value: null,
|
|
insurance: null,
|
|
packaging: null,
|
|
other_increments: null,
|
|
total_increments_mn: null,
|
|
total_increments_me: null,
|
|
incoterm: null,
|
|
enclosure: null,
|
|
num_seals: null,
|
|
movement_type: '',
|
|
alternate_invoice: '',
|
|
valuation_method: null,
|
|
...(settings.observationFormData || {})
|
|
};
|
|
itemsFormData = settings.itemsFormData || {};
|
|
ssimpFormData = settings.ssimpFormData || {};
|
|
othersFormData = {
|
|
comments_status: '',
|
|
transport_mode: 'TRUCK',
|
|
is_mixed: null,
|
|
print_stamp: false,
|
|
rule_3121_parties_ii: false,
|
|
related_doc_id: null,
|
|
code_signature: '',
|
|
electronic_signature: '',
|
|
mandatory_person: '',
|
|
contingency_mode: false,
|
|
cove: '',
|
|
operation_num: '',
|
|
adendas: '',
|
|
observations_vu: '',
|
|
certified_number: '',
|
|
...(settings.othersFormData || {})
|
|
};
|
|
continuationFormData = {
|
|
numero_tipo_transporte: '',
|
|
es_ferrocarril: 'no',
|
|
numero_bl: '',
|
|
cantidad_guias_embarque: null,
|
|
destino_origen: '',
|
|
puerto_entrada: '',
|
|
fue_revisado_equipo: false,
|
|
sub_division: false,
|
|
funge_como_cd: false,
|
|
llego_pedimento: false,
|
|
errores_facturacion: [],
|
|
semaforo_verde_aduana_mexicana: false,
|
|
semaforo_verde_aduana_americana: false,
|
|
semaforo_rojo_aduana_mexicana: false,
|
|
semaforo_rojo_aduana_americana: false,
|
|
...(settings.continuationFormData || {})
|
|
};
|
|
|
|
// The derived 'invoice' will update automatically because it spread InvoiceTopFieldsFormData
|
|
}
|
|
|
|
function resetForms() {
|
|
InvoiceTopFieldsFormData = {
|
|
is_pedimento_pending: false,
|
|
pedimento_id: '',
|
|
remesa: '',
|
|
invoice_number: '',
|
|
invoice_date: new Date().toISOString().split('T')[0],
|
|
emission_date: new Date().toISOString().split('T')[0],
|
|
operation_type: selectedOperationType,
|
|
invoice_type: selectedInvoiceType,
|
|
fecha_pedimento_del: '',
|
|
fecha_pedimento_al: '',
|
|
clave_pedimento: '',
|
|
regimen_pedimento: ''
|
|
};
|
|
generalFormData = {
|
|
provider_header: 'proveedor',
|
|
provider_id: null,
|
|
sold_to_header: 'consignado_a',
|
|
sold_to_id: null,
|
|
shipped_to_header: 'enviado_a',
|
|
shipped_to_id: null,
|
|
customs_broker_id: null,
|
|
customs_broker_us_id: null,
|
|
currency_type: '',
|
|
currency: 'foreign',
|
|
exchange_rate: null,
|
|
weight_type: 'kgs',
|
|
iva_factor: null,
|
|
carrier_id: null,
|
|
transport_id: '',
|
|
driver_name: '',
|
|
transport_type: '',
|
|
transport_num: '',
|
|
aduana: '',
|
|
document_type: ''
|
|
};
|
|
observationFormData = {
|
|
observation_es: '',
|
|
observation_en: '',
|
|
freight: null,
|
|
insurance_value: null,
|
|
insurance: null,
|
|
packaging: null,
|
|
other_increments: null,
|
|
total_increments_mn: null,
|
|
total_increments_me: null,
|
|
incoterm: null,
|
|
enclosure: null,
|
|
num_seals: null,
|
|
movement_type: '',
|
|
alternate_invoice: '',
|
|
valuation_method: null
|
|
};
|
|
itemsFormData = {};
|
|
ssimpFormData = {};
|
|
othersFormData = {
|
|
comments_status: '',
|
|
transport_mode: 'TRUCK',
|
|
is_mixed: null,
|
|
print_stamp: false,
|
|
rule_3121_parties_ii: false,
|
|
related_doc_id: null,
|
|
code_signature: '',
|
|
electronic_signature: '',
|
|
mandatory_person: '',
|
|
contingency_mode: false,
|
|
cove: '',
|
|
operation_num: '',
|
|
adendas: '',
|
|
observations_vu: '',
|
|
certified_number: ''
|
|
};
|
|
continuationFormData = {
|
|
numero_tipo_transporte: '',
|
|
es_ferrocarril: 'no',
|
|
numero_bl: '',
|
|
cantidad_guias_embarque: null,
|
|
destino_origen: '',
|
|
puerto_entrada: '',
|
|
fue_revisado_equipo: false,
|
|
sub_division: false,
|
|
funge_como_cd: false,
|
|
llego_pedimento: false,
|
|
errores_facturacion: [],
|
|
semaforo_verde_aduana_mexicana: false,
|
|
semaforo_verde_aduana_americana: false,
|
|
semaforo_rojo_aduana_mexicana: false,
|
|
semaforo_rojo_aduana_americana: false
|
|
};
|
|
// The derived 'invoice' handles itself
|
|
}
|
|
|
|
function cleanObject(obj: any): any {
|
|
if (Array.isArray(obj)) {
|
|
return obj.map(cleanObject).filter((v) => v !== null && v !== undefined && v !== '');
|
|
}
|
|
if (obj !== null && typeof obj === 'object') {
|
|
return Object.entries(obj).reduce((acc: any, [key, value]) => {
|
|
const cleaned = cleanObject(value);
|
|
if (
|
|
cleaned !== null &&
|
|
cleaned !== undefined &&
|
|
cleaned !== '' &&
|
|
!(typeof cleaned === 'object' && Object.keys(cleaned).length === 0)
|
|
) {
|
|
acc[key] = cleaned;
|
|
}
|
|
return acc;
|
|
}, {});
|
|
}
|
|
return obj;
|
|
}
|
|
|
|
function handleBack() {
|
|
goto('/dashboard/invoices');
|
|
}
|
|
|
|
let operationTypeText = $derived.by(() => {
|
|
if (selectedOperationType === 'exp') return 'EXPORTACIÓN';
|
|
if (selectedOperationType === 'imp') return 'IMPORTACIÓN';
|
|
return 'TIPO NO DEFINIDO';
|
|
});
|
|
|
|
let operationColorClass = $derived.by(() => {
|
|
if (selectedOperationType === 'exp') return 'bg-blue-500/10 text-blue-600 border-blue-500/20';
|
|
if (selectedOperationType === 'imp') return 'bg-emerald-500/10 text-emerald-600 border-emerald-500/20';
|
|
return 'bg-muted text-muted-foreground border-border';
|
|
});
|
|
|
|
// Contexto reactivo para componentes
|
|
let invoiceType = $derived(selectedInvoiceType || 'TEM');
|
|
let operationTypeNumeric = $derived(selectedOperationType === 'exp' ? 1 : 2);
|
|
|
|
async function handleSaveSettings() {
|
|
if (!selectedInvoiceType || !selectedOperationType || !companyStore?.activeCompany?.id) {
|
|
toast.error('Por favor selecciona tipo de factura y operación');
|
|
return;
|
|
}
|
|
|
|
isSaving = true;
|
|
|
|
// Use snaphot to get clean data from Svelte 5 proxies
|
|
const rawSettings = {
|
|
InvoiceTopFieldsFormData: $state.snapshot(InvoiceTopFieldsFormData),
|
|
generalFormData: $state.snapshot(generalFormData),
|
|
observationFormData: $state.snapshot(observationFormData),
|
|
itemsFormData: $state.snapshot(itemsFormData),
|
|
ssimpFormData: $state.snapshot(ssimpFormData),
|
|
othersFormData: $state.snapshot(othersFormData),
|
|
continuationFormData: $state.snapshot(continuationFormData)
|
|
};
|
|
|
|
// Clean the settings to only save what's configured
|
|
const cleanedSettings = cleanObject(rawSettings);
|
|
|
|
const settingsPayload = {
|
|
invoice_type: selectedInvoiceType,
|
|
operation_type: selectedOperationType,
|
|
settings: cleanedSettings
|
|
};
|
|
|
|
try {
|
|
const response = await api.put(
|
|
`/v1/a76/invoice-settings/?company_id=${companyStore.activeCompany.id}`,
|
|
settingsPayload
|
|
);
|
|
|
|
if (response.status === 200 || response.data) {
|
|
toast.success('Configuración guardada correctamente.');
|
|
} else {
|
|
console.error('Save error details:', response.error || response.validationErrors);
|
|
toast.error('Error al guardar la configuración.');
|
|
}
|
|
} catch (error) {
|
|
console.error('Error saving settings:', error);
|
|
toast.error('Ocurrió un error al guardar.');
|
|
} finally {
|
|
isSaving = false;
|
|
}
|
|
}
|
|
|
|
// Watch for selection changes
|
|
// We'll call loadSettings manually when selection changes to avoid reactive loops
|
|
$effect(() => {
|
|
if (browser && !InvoiceTopFieldsFormData && companyStore?.activeCompany?.id) {
|
|
loadSettings();
|
|
}
|
|
});
|
|
|
|
// Handle explicit changes
|
|
function handleOperationTypeChange(v: string) {
|
|
selectedOperationType = v;
|
|
loadSettings();
|
|
}
|
|
|
|
function handleInvoiceTypeChange(v: string) {
|
|
selectedInvoiceType = v;
|
|
loadSettings();
|
|
}
|
|
</script>
|
|
|
|
<Tabs.Root bind:value={activeTab}>
|
|
<div class="space-y-4">
|
|
<!-- Header -->
|
|
<div class="flex items-center justify-between">
|
|
<div class="space-y-1">
|
|
<div class="flex items-center gap-3">
|
|
<Button variant="ghost" size="icon" onclick={handleBack}>
|
|
<ArrowLeft size={20} />
|
|
</Button>
|
|
<h1 class="text-3xl font-bold tracking-tight">
|
|
Configuración de Facturas
|
|
</h1>
|
|
{#if selectedOperationType}
|
|
<Badge variant="outline" class="px-3 py-1 text-sm font-bold {operationColorClass}">
|
|
{operationTypeText}
|
|
</Badge>
|
|
{/if}
|
|
{#if selectedInvoiceType}
|
|
<Badge variant="secondary">
|
|
{data.invoiceTypes.find((t: any) => t.key === selectedInvoiceType)?.description || selectedInvoiceType}
|
|
</Badge>
|
|
{/if}
|
|
</div>
|
|
<p class="text-muted-foreground">
|
|
Define los valores predeterminados para la creación de facturas.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
<div class="pb-48">
|
|
<Card.Root class="mb-8 border-dashed bg-muted/30">
|
|
<Card.Header class="py-4">
|
|
<Card.Title class="text-lg">Contexto de Configuración</Card.Title>
|
|
<Card.Description
|
|
>Selecciona el contexto para editar sus valores por defecto.</Card.Description
|
|
>
|
|
</Card.Header>
|
|
<Card.Content class="flex gap-6 py-2">
|
|
<div class="space-y-2">
|
|
<Label class="text-xs uppercase text-muted-foreground font-bold tracking-wider">Tipo de Operación</Label>
|
|
<Select type="single" value={selectedOperationType} onValueChange={handleOperationTypeChange}>
|
|
<SelectTrigger class="w-[200px] h-10 bg-background">
|
|
{operationTypes.find((t: any) => t.value === selectedOperationType)?.label ||
|
|
'Seleccionar...'}
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{#each operationTypes as type}
|
|
<SelectItem value={type.value}>{type.label}</SelectItem>
|
|
{/each}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div class="space-y-2">
|
|
<Label class="text-xs uppercase text-muted-foreground font-bold tracking-wider">Tipo de Factura</Label>
|
|
<Select type="single" value={selectedInvoiceType} onValueChange={handleInvoiceTypeChange}>
|
|
<SelectTrigger class="w-[300px] h-10 bg-background">
|
|
{@const type = data.invoiceTypes.find((t: any) => t.key === selectedInvoiceType)}
|
|
{type ? `${type.key} - ${type.description}` : 'Seleccionar...'}
|
|
</SelectTrigger>
|
|
<SelectContent class="max-h-[300px]">
|
|
{#each data.invoiceTypes as type}
|
|
<SelectItem value={type.key}>{type.key} - {type.description}</SelectItem>
|
|
{/each}
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</Card.Content>
|
|
</Card.Root>
|
|
|
|
{#if selectedInvoiceType && selectedOperationType}
|
|
{#if isLoading}
|
|
<div class="flex justify-center py-24">
|
|
<div class="flex flex-col items-center gap-4">
|
|
<LoaderCircle class="animate-spin h-10 w-10 text-primary" />
|
|
<p class="text-sm text-muted-foreground animate-pulse">Cargando configuración...</p>
|
|
</div>
|
|
</div>
|
|
{:else}
|
|
<div class="grid gap-6">
|
|
<!-- Top Fields (Header) -->
|
|
<div class="bg-background rounded-xl border-2 shadow-sm p-6">
|
|
<div class="flex items-center gap-2 mb-6 border-b pb-4">
|
|
<div class="p-1.5 bg-primary/10 rounded-md">
|
|
<FileText class="w-5 h-5 text-primary" />
|
|
</div>
|
|
<h3 class="text-lg font-bold">Encabezado Predeterminado</h3>
|
|
</div>
|
|
|
|
<InvoiceTopFields
|
|
{invoice}
|
|
bind:formData={InvoiceTopFieldsFormData}
|
|
invoiceTypes={data.invoiceTypes || []}
|
|
pedimentos={data.pedimentos || []}
|
|
defaultOperationType={selectedOperationType}
|
|
defaultInvoiceType={selectedInvoiceType}
|
|
{invoiceType}
|
|
isSettings={true}
|
|
/>
|
|
</div>
|
|
|
|
<div class="space-y-4">
|
|
<Tabs.Content value="general">
|
|
<GeneralTabForm
|
|
{invoice}
|
|
bind:formData={generalFormData}
|
|
invoiceTypes={data.invoiceTypes || []}
|
|
customsBrokers={data.customsBrokers || []}
|
|
clients={data.clients || []}
|
|
providers={data.providers || []}
|
|
currencyTypes={data.currencyTypes || []}
|
|
transportTypes={data.transportTypes || []}
|
|
transporters={data.transporters || []}
|
|
vehicles={data.vehicles || []}
|
|
drivers={data.drivers || []}
|
|
trailers={data.trailers || []}
|
|
customsSections={data.customsSections || []}
|
|
codePedimentoRegimens={data.codePedimentoRegimens || []}
|
|
operationType={operationTypeNumeric}
|
|
{invoiceType}
|
|
exchangeRate={0}
|
|
isSettings={true}
|
|
/>
|
|
</Tabs.Content>
|
|
|
|
<Tabs.Content value="observations">
|
|
<ObservationsTabForm
|
|
{invoice}
|
|
bind:formData={observationFormData}
|
|
bind:exists={observationExists}
|
|
seals={[]}
|
|
incoterms={data.incoterms || []}
|
|
enclosure={[]}
|
|
operationType={operationTypeNumeric}
|
|
{invoiceType}
|
|
isSettings={true}
|
|
/>
|
|
</Tabs.Content>
|
|
|
|
<Tabs.Content value="items">
|
|
<div class="p-12 border-2 border-dashed rounded-xl bg-muted/20 text-center flex flex-col items-center gap-4">
|
|
<div class="p-4 bg-muted rounded-full">
|
|
<DollarSign class="w-8 h-8 text-muted-foreground opacity-50" />
|
|
</div>
|
|
<div class="max-w-md">
|
|
<h4 class="font-bold text-lg">Configuración de Partidas</h4>
|
|
<p class="text-sm text-muted-foreground mt-1">
|
|
La configuración predeterminada de partidas es limitada desde esta sección. Los valores se heredarán de los maestros de productos cuando sea posible.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</Tabs.Content>
|
|
|
|
<Tabs.Content value="others">
|
|
<OthersTabForm
|
|
{invoice}
|
|
bind:formData={othersFormData}
|
|
bind:exists={othersExists}
|
|
transportModes={data.transportModes || []}
|
|
operationType={operationTypeNumeric}
|
|
{invoiceType}
|
|
isSettings={true}
|
|
/>
|
|
</Tabs.Content>
|
|
|
|
<Tabs.Content value="continuation">
|
|
<div class="space-y-6">
|
|
{#if invoiceType !== 'MEX'}
|
|
<div class="bg-background rounded-xl border p-6">
|
|
<h4 class="text-sm font-semibold uppercase text-muted-foreground mb-4">Captura de Valores por Defecto</h4>
|
|
<ContinuationTabForm
|
|
{invoice}
|
|
bind:formData={continuationFormData}
|
|
bind:exists={continuationExists}
|
|
operationType={operationTypeNumeric}
|
|
{invoiceType}
|
|
isSettings={true}
|
|
/>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</Tabs.Content>
|
|
|
|
<Tabs.Content value="ssimp">
|
|
<div class="space-y-6">
|
|
<div class="bg-background rounded-xl border p-6">
|
|
<h4 class="text-sm font-semibold uppercase text-muted-foreground mb-4">
|
|
{selectedOperationType === 'exp'
|
|
? `Parámetros de Exportación — ${data.invoiceTypes?.find((t: any) => t.key === invoiceType)?.description || invoiceType}`
|
|
: invoiceType === 'DEF'
|
|
? 'Parámetros Adicionales SSisDef'
|
|
: invoiceType === 'MEX'
|
|
? 'Parámetros Adicionales SSICM'
|
|
: 'Parámetros Adicionales SSimp'}
|
|
</h4>
|
|
{#if selectedOperationType === 'exp'}
|
|
<SscrSettingsForm bind:formData={ssimpFormData} />
|
|
{:else if invoiceType === 'DEF'}
|
|
<SsisdefSettingsForm bind:formData={ssimpFormData} />
|
|
{:else if invoiceType === 'MEX'}
|
|
<SsicmSettingsForm bind:formData={ssimpFormData} drivers={data.drivers || []} />
|
|
{:else}
|
|
<SsimpSettingsForm bind:formData={ssimpFormData} />
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
</Tabs.Content>
|
|
</div>
|
|
</div>
|
|
{/if}
|
|
{:else}
|
|
<div
|
|
class="flex flex-col items-center justify-center border-2 border-dashed rounded-xl p-24 text-muted-foreground bg-muted/10 mt-12"
|
|
>
|
|
<div class="p-6 bg-muted rounded-full mb-6">
|
|
<FileText class="h-16 w-16 opacity-20" />
|
|
</div>
|
|
<h3 class="text-xl font-bold text-foreground">Sin Contexto de Edición</h3>
|
|
<p class="max-w-xs text-center mt-2">
|
|
Selecciona un tipo de operación y factura para comenzar a editar los valores globales por defecto.
|
|
</p>
|
|
</div>
|
|
{/if}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Sticky Footer -->
|
|
<div
|
|
class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur border-t shadow-lg z-[10] transition-all duration-300 md:ml-[calc(var(--sidebar-width))] group-has-data-[state=collapsed]/sidebar-wrapper:md:ml-[calc(var(--sidebar-width-icon))]"
|
|
>
|
|
<div class="container mx-auto max-w-[1400px] space-y-4 p-4">
|
|
<!-- Tabs Navigation (Only shown if context selected) -->
|
|
{#if selectedInvoiceType && selectedOperationType}
|
|
<div class="w-full overflow-x-auto pb-2">
|
|
<Tabs.List class="inline-flex md:grid md:w-full md:grid-cols-6 bg-muted rounded-md p-1 h-auto flex-wrap">
|
|
<Tabs.Trigger value="general" class="whitespace-nowrap">
|
|
<FileText size={16} class="mr-2" />
|
|
General
|
|
</Tabs.Trigger>
|
|
<Tabs.Trigger value="observations" class="whitespace-nowrap">
|
|
<Eye size={16} class="mr-2" />
|
|
Observaciones
|
|
</Tabs.Trigger>
|
|
<Tabs.Trigger value="items" class="whitespace-nowrap">
|
|
<DollarSign size={16} class="mr-2" />
|
|
Partidas
|
|
</Tabs.Trigger>
|
|
<Tabs.Trigger value="others" class="whitespace-nowrap">
|
|
<Truck size={16} class="mr-2" />
|
|
Otros
|
|
</Tabs.Trigger>
|
|
<Tabs.Trigger value="continuation" class="whitespace-nowrap">
|
|
<Package size={16} class="mr-2" />
|
|
Cont.
|
|
</Tabs.Trigger>
|
|
<Tabs.Trigger value="ssimp" class="whitespace-nowrap">
|
|
<Package size={16} class="mr-2" />
|
|
Continuación
|
|
</Tabs.Trigger>
|
|
</Tabs.List>
|
|
</div>
|
|
{/if}
|
|
|
|
<div class="flex justify-end gap-3">
|
|
<Button variant="outline" onclick={resetForms} disabled={isSaving || !selectedInvoiceType}>
|
|
Restablecer
|
|
</Button>
|
|
<Button onclick={handleSaveSettings} disabled={isSaving || !selectedInvoiceType}>
|
|
{#if isSaving}
|
|
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
|
Guardando...
|
|
{:else}
|
|
<Save class="mr-2 h-4 w-4" />
|
|
Guardar Configuración
|
|
{/if}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Tabs.Root>
|