Modulo de tipo de cambio inteligente
This commit is contained in:
@@ -1,59 +1,56 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { getExchangeRates } from '$lib/api/dashboard/a76/general_catalogs/exchange-rate';
|
||||
import CreateEditDialog from './create-edit-dialog.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { getExchangeRates } from '$lib/api/dashboard/a76/general_catalogs/exchange-rate';
|
||||
import { page } from '$app/state';
|
||||
import CreateEditDialog from './create-edit-dialog.svelte';
|
||||
|
||||
let open = $state(false);
|
||||
let checked = $state(false);
|
||||
let open = $state(false);
|
||||
let checked = $state(false);
|
||||
|
||||
async function checkExchangeRate() {
|
||||
console.log('[ExchangeRateGuard] Checking...', companyStore.activeCompany);
|
||||
if (!companyStore.activeCompany?.id) {
|
||||
console.log('[ExchangeRateGuard] No active company');
|
||||
return;
|
||||
}
|
||||
async function checkExchangeRate() {
|
||||
console.log('[ExchangeRateGuard] Checking...', companyStore.activeCompany);
|
||||
if (!companyStore.activeCompany?.id) {
|
||||
console.log('[ExchangeRateGuard] No active company');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use local date instead of UTC
|
||||
const today = new Date().toLocaleDateString('fr-CA'); // YYYY-MM-DD
|
||||
console.log('[ExchangeRateGuard] Date:', today);
|
||||
|
||||
try {
|
||||
const response = await getExchangeRates(companyStore.activeCompany.id, {
|
||||
date: today,
|
||||
page_size: 1
|
||||
});
|
||||
console.log('[ExchangeRateGuard] Response (stringified):', JSON.stringify(response, null, 2));
|
||||
// Use local date instead of UTC
|
||||
const today = new Date().toLocaleDateString('fr-CA'); // YYYY-MM-DD
|
||||
console.log('[ExchangeRateGuard] Date:', today);
|
||||
|
||||
// api.get returns { data: ..., status: ... } and types now reflect that
|
||||
const items = response.data?.items || [];
|
||||
|
||||
if (items.length === 0) {
|
||||
console.log('[ExchangeRateGuard] No rate found, opening modal');
|
||||
open = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[ExchangeRateGuard] Error checking exchange rate:', error);
|
||||
} finally {
|
||||
checked = true;
|
||||
}
|
||||
}
|
||||
try {
|
||||
const response = await getExchangeRates(companyStore.activeCompany.id, {
|
||||
date: today,
|
||||
page_size: 1
|
||||
});
|
||||
console.log('[ExchangeRateGuard] Response (stringified):', JSON.stringify(response, null, 2));
|
||||
|
||||
$effect(() => {
|
||||
if (companyStore.activeCompany?.id && !checked) {
|
||||
checkExchangeRate();
|
||||
}
|
||||
});
|
||||
// api.get returns { data: ..., status: ... } and types now reflect that
|
||||
const items = response.data?.items || [];
|
||||
|
||||
function handleSuccess() {
|
||||
|
||||
console.log('Exchange rate created successfully via guard');
|
||||
checked = true;
|
||||
}
|
||||
if (items.length === 0) {
|
||||
console.log('[ExchangeRateGuard] No rate found, opening modal');
|
||||
open = true;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[ExchangeRateGuard] Error checking exchange rate:', error);
|
||||
} finally {
|
||||
checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
$effect(() => {
|
||||
const isDashboard = page.url.pathname === '/dashboard' || page.url.pathname === '/dashboard/';
|
||||
if (companyStore.activeCompany?.id && !checked && isDashboard) {
|
||||
checkExchangeRate();
|
||||
}
|
||||
});
|
||||
|
||||
function handleSuccess() {
|
||||
console.log('Exchange rate created successfully via guard');
|
||||
checked = true;
|
||||
}
|
||||
</script>
|
||||
|
||||
<CreateEditDialog
|
||||
bind:open
|
||||
onSuccess={handleSuccess}
|
||||
overlayClass="bg-black/20"
|
||||
/>
|
||||
<CreateEditDialog bind:open onSuccess={handleSuccess} overlayClass="bg-black/20" />
|
||||
|
||||
@@ -1,196 +1,214 @@
|
||||
<script lang="ts">
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import type { Invoice } from '$lib/api/dashboard/a76/invoices';
|
||||
import type { InvoiceType } from '$lib/api/dashboard/refrence_data/invoice_types';
|
||||
import type { Pedimento } from '$lib/api/dashboard/a76/pedimentos';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import { Switch } from '$lib/components/ui/switch';
|
||||
import type { Invoice } from '$lib/api/dashboard/a76/invoices';
|
||||
import type { InvoiceType } from '$lib/api/dashboard/refrence_data/invoice_types';
|
||||
import type { Pedimento } from '$lib/api/dashboard/a76/pedimentos';
|
||||
|
||||
let {
|
||||
invoice,
|
||||
formData = $bindable(),
|
||||
invoiceTypes = [],
|
||||
pedimentos = [],
|
||||
defaultOperationType = undefined,
|
||||
defaultInvoiceType = undefined,
|
||||
}: {
|
||||
invoice: Invoice | null;
|
||||
formData?: any;
|
||||
invoiceTypes?: InvoiceType[];
|
||||
pedimentos?: Pedimento[];
|
||||
defaultOperationType?: string | null;
|
||||
defaultInvoiceType?: string | null;
|
||||
} = $props();
|
||||
let {
|
||||
invoice,
|
||||
formData = $bindable(),
|
||||
invoiceTypes = [],
|
||||
pedimentos = [],
|
||||
defaultOperationType = undefined,
|
||||
defaultInvoiceType = undefined
|
||||
}: {
|
||||
invoice: Invoice | null;
|
||||
formData?: any;
|
||||
invoiceTypes?: InvoiceType[];
|
||||
pedimentos?: Pedimento[];
|
||||
defaultOperationType?: string | null;
|
||||
defaultInvoiceType?: string | null;
|
||||
} = $props();
|
||||
|
||||
function handlePedimentoChange(pedimentoId: string) {
|
||||
if (!pedimentoId) return;
|
||||
|
||||
const selectedPedimento = pedimentos.find(p => p.id === parseInt(pedimentoId));
|
||||
if (!selectedPedimento) return;
|
||||
function handlePedimentoChange(pedimentoId: string) {
|
||||
if (!pedimentoId) return;
|
||||
|
||||
// Actualizar los campos del pedimento en formData
|
||||
formData.fecha_pedimento_del = selectedPedimento.pedimento_dates?.start_date || '';
|
||||
formData.fecha_pedimento_al = selectedPedimento.pedimento_dates?.end_date || '';
|
||||
formData.clave_pedimento = selectedPedimento.pedimento_code || '';
|
||||
formData.regimen_pedimento = selectedPedimento.regime || '';
|
||||
|
||||
// Construir el número de pedimento completo
|
||||
const pedimentoNumber = `${selectedPedimento.customs_office?.slice(0,2) || ''}-${selectedPedimento.license || ''}-${selectedPedimento.pedimento_number || ''}`.replace(/^-+|-+$/g, '');
|
||||
formData.pedimento = pedimentoNumber;
|
||||
}
|
||||
const selectedPedimento = pedimentos.find((p) => p.id === parseInt(pedimentoId));
|
||||
if (!selectedPedimento) return;
|
||||
|
||||
$effect(() => {
|
||||
if (formData?.pedimento_id && pedimentos.length > 0 && !formData.pedimento) {
|
||||
handlePedimentoChange(formData.pedimento_id);
|
||||
}
|
||||
});
|
||||
// Actualizar los campos del pedimento en formData
|
||||
formData.fecha_pedimento_del = selectedPedimento.pedimento_dates?.start_date || '';
|
||||
formData.fecha_pedimento_al = selectedPedimento.pedimento_dates?.end_date || '';
|
||||
formData.clave_pedimento = selectedPedimento.pedimento_code || '';
|
||||
formData.regimen_pedimento = selectedPedimento.regime || '';
|
||||
|
||||
// Efecto para actualizar operation_type cuando cambia defaultOperationType
|
||||
$effect(() => {
|
||||
if (formData && defaultOperationType !== undefined && defaultOperationType !== null) {
|
||||
// Si operation_type está vacío, null, o undefined, actualizarlo con defaultOperationType
|
||||
if (!formData.operation_type) {
|
||||
formData.operation_type = defaultOperationType;
|
||||
}
|
||||
}
|
||||
});
|
||||
// Construir el número de pedimento completo
|
||||
const pedimentoNumber =
|
||||
`${selectedPedimento.customs_office?.slice(0, 2) || ''}-${selectedPedimento.license || ''}-${selectedPedimento.pedimento_number || ''}`.replace(
|
||||
/^-+|-+$/g,
|
||||
''
|
||||
);
|
||||
formData.pedimento = pedimentoNumber;
|
||||
}
|
||||
|
||||
if (!formData) {
|
||||
let operationType: string | null = null;
|
||||
if (invoice?.operation_type) {
|
||||
operationType = invoice.operation_type;
|
||||
} else if (defaultOperationType !== undefined) {
|
||||
operationType = defaultOperationType ?? null;
|
||||
}
|
||||
$effect(() => {
|
||||
if (formData?.pedimento_id && pedimentos.length > 0 && !formData.pedimento) {
|
||||
handlePedimentoChange(formData.pedimento_id);
|
||||
}
|
||||
});
|
||||
|
||||
formData = {
|
||||
is_pedimento_pending: false,
|
||||
pedimento_id: invoice?.compliance_mx?.pedimento_id || '',
|
||||
remesa: invoice?.compliance_mx?.remesa || '',
|
||||
invoice_number: invoice?.invoice_number || '',
|
||||
invoice_date: invoice?.invoice_date || new Date().toISOString().split('T')[0],
|
||||
emission_date: new Date().toISOString().split('T')[0],
|
||||
operation_type: operationType,
|
||||
invoice_type: invoice?.invoice_type || (defaultInvoiceType ?? ''),
|
||||
// Campos del pedimento (se llenarán al seleccionar un pedimento)
|
||||
fecha_pedimento_del: '',
|
||||
fecha_pedimento_al: '',
|
||||
clave_pedimento: '',
|
||||
regimen_pedimento: '',
|
||||
};
|
||||
} else {
|
||||
// Si formData ya existe pero operation_type está vacío, usar defaultOperationType
|
||||
if (!formData.operation_type && defaultOperationType !== undefined && defaultOperationType !== null) {
|
||||
formData.operation_type = defaultOperationType;
|
||||
}
|
||||
}
|
||||
// Efecto para actualizar operation_type cuando cambia defaultOperationType
|
||||
$effect(() => {
|
||||
if (formData && defaultOperationType !== undefined && defaultOperationType !== null) {
|
||||
// Si operation_type está vacío, null, o undefined, actualizarlo con defaultOperationType
|
||||
if (!formData.operation_type) {
|
||||
formData.operation_type = defaultOperationType;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (!formData) {
|
||||
let operationType: string | null = null;
|
||||
if (invoice?.operation_type) {
|
||||
operationType = invoice.operation_type;
|
||||
} else if (defaultOperationType !== undefined) {
|
||||
operationType = defaultOperationType ?? null;
|
||||
}
|
||||
|
||||
formData = {
|
||||
is_pedimento_pending: false,
|
||||
pedimento_id: invoice?.compliance_mx?.pedimento_id || '',
|
||||
remesa: invoice?.compliance_mx?.remesa || '',
|
||||
invoice_number: invoice?.invoice_number || '',
|
||||
invoice_date:
|
||||
invoice?.invoice_date || (invoice ? '' : new Date().toISOString().split('T')[0]),
|
||||
emission_date: invoice?.emission_date || new Date().toISOString().split('T')[0],
|
||||
operation_type: operationType,
|
||||
invoice_type: invoice?.invoice_type || (defaultInvoiceType ?? ''),
|
||||
// Campos del pedimento (se llenarán al seleccionar un pedimento)
|
||||
fecha_pedimento_del: '',
|
||||
fecha_pedimento_al: '',
|
||||
clave_pedimento: '',
|
||||
regimen_pedimento: ''
|
||||
};
|
||||
} else {
|
||||
// Si formData ya existe pero operation_type está vacío, usar defaultOperationType
|
||||
if (
|
||||
!formData.operation_type &&
|
||||
defaultOperationType !== undefined &&
|
||||
defaultOperationType !== null
|
||||
) {
|
||||
formData.operation_type = defaultOperationType;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Datos Principales en una fila compacta (reusable across tabs) -->
|
||||
<div class="grid grid-cols-12 gap-3 items-end pb-3">
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs">Tipo de Operación<span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type || ''}
|
||||
onValueChange={(v) => {
|
||||
formData.operation_type = v;
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="operation_type" class="h-8 text-sm">
|
||||
<span class="truncate">
|
||||
{formData.operation_type
|
||||
? (formData.operation_type === 'exp' ? 'Exp' : 'Imp')
|
||||
: '...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="exp">Exportación</Select.Item>
|
||||
<Select.Item value="imp">Importación</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs">Tipo de factura <span class="text-red-500">*</span></Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.invoice_type || ''}
|
||||
onValueChange={(v) => {
|
||||
formData.invoice_type = v ?? '';
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="invoice_type" class="h-7 text-xs">
|
||||
<span class="truncate">
|
||||
{formData.invoice_type
|
||||
? `${formData.invoice_type}`
|
||||
: '...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each invoiceTypes as type}
|
||||
<Select.Item value={type.key}>
|
||||
{type.key} - {type.description}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="grid grid-cols-12 items-end gap-3 pb-3">
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs"
|
||||
>Tipo de Operación<span class="text-red-500">*</span></Label
|
||||
>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type || ''}
|
||||
onValueChange={(v) => {
|
||||
formData.operation_type = v;
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="operation_type" class="h-8 text-sm">
|
||||
<span class="truncate">
|
||||
{formData.operation_type ? (formData.operation_type === 'exp' ? 'Exp' : 'Imp') : '...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="exp">Exportación</Select.Item>
|
||||
<Select.Item value="imp">Importación</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="operation_type" class="text-xs"
|
||||
>Tipo de factura <span class="text-red-500">*</span></Label
|
||||
>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.invoice_type || ''}
|
||||
onValueChange={(v) => {
|
||||
formData.invoice_type = v ?? '';
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="invoice_type" class="h-7 text-xs">
|
||||
<span class="truncate">
|
||||
{formData.invoice_type ? `${formData.invoice_type}` : '...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each invoiceTypes as type}
|
||||
<Select.Item value={type.key}>
|
||||
{type.key} - {type.description}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<div class="col-span-1 space-y-1 pb-1 items-center flex flex-col">
|
||||
<Label for="is_pedimento_pending" class="text-xs">Pedimento Pendiente?</Label>
|
||||
<Switch
|
||||
id="is_pedimento_pending"
|
||||
checked={formData.is_pedimento_pending}
|
||||
onCheckedChange={(checked) => {
|
||||
formData.is_pedimento_pending = checked;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="pedimento" class="text-xs">Pedimento</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_id ? String(formData.pedimento_id) : ''}
|
||||
onValueChange={(v) => {
|
||||
formData.pedimento_id = v ? parseInt(v) : null;
|
||||
if (v) {
|
||||
handlePedimentoChange(v);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="pedimento" class="h-8 text-sm">
|
||||
<span class="truncate">
|
||||
{formData.pedimento || 'Selecciona pedimento...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each pedimentos as pedimento}
|
||||
<Select.Item value={String(pedimento.id)}>
|
||||
{pedimento.customs_office?.slice(0, 2)}-{pedimento.license}-{pedimento.pedimento_number}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="col-span-1 flex flex-col items-center space-y-1 pb-1">
|
||||
<Label for="is_pedimento_pending" class="text-xs">Pedimento Pendiente?</Label>
|
||||
<Switch
|
||||
id="is_pedimento_pending"
|
||||
checked={formData.is_pedimento_pending}
|
||||
onCheckedChange={(checked) => {
|
||||
formData.is_pedimento_pending = checked;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="pedimento" class="text-xs">Pedimento</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.pedimento_id ? String(formData.pedimento_id) : ''}
|
||||
onValueChange={(v) => {
|
||||
formData.pedimento_id = v ? parseInt(v) : null;
|
||||
if (v) {
|
||||
handlePedimentoChange(v);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Select.Trigger id="pedimento" class="h-8 text-sm">
|
||||
<span class="truncate">
|
||||
{formData.pedimento || 'Selecciona pedimento...'}
|
||||
</span>
|
||||
</Select.Trigger>
|
||||
<Select.Content class="max-h-[300px]">
|
||||
{#each pedimentos as pedimento}
|
||||
<Select.Item value={String(pedimento.id)}>
|
||||
{pedimento.customs_office?.slice(0, 2)}-{pedimento.license}-{pedimento.pedimento_number}
|
||||
</Select.Item>
|
||||
{/each}
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="remesa" class="text-xs">Remesa</Label>
|
||||
<Input id="remesa" bind:value={formData.remesa} class="h-8 text-sm" />
|
||||
</div>
|
||||
<div class="col-span-1 space-y-1">
|
||||
<Label for="remesa" class="text-xs">Remesa</Label>
|
||||
<Input id="remesa" bind:value={formData.remesa} class="h-8 text-sm" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_number" class="text-xs">Núm. Factura <span class="text-red-500">*</span></Label>
|
||||
<Input id="invoice_number" bind:value={formData.invoice_number} class="h-8 text-sm font-medium" required />
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_number" class="text-xs"
|
||||
>Núm. Factura <span class="text-red-500">*</span></Label
|
||||
>
|
||||
<Input
|
||||
id="invoice_number"
|
||||
bind:value={formData.invoice_number}
|
||||
class="h-8 text-sm font-medium"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_date" class="text-xs">Fecha Factura <span class="text-red-500">*</span></Label>
|
||||
<Input id="invoice_date" type="date" bind:value={formData.invoice_date} class="h-8 text-sm" />
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="invoice_date" class="text-xs"
|
||||
>Fecha Factura <span class="text-red-500">*</span></Label
|
||||
>
|
||||
<Input id="invoice_date" type="date" bind:value={formData.invoice_date} class="h-8 text-sm" />
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="emission_date" class="text-xs">Fecha Emisión</Label>
|
||||
<Input id="emission_date" type="date" bind:value={formData.emission_date} class="h-8 text-sm" />
|
||||
</div>
|
||||
<div class="col-span-2 space-y-1">
|
||||
<Label for="emission_date" class="text-xs">Fecha Emisión</Label>
|
||||
<Input id="emission_date" type="date" bind:value={formData.emission_date} class="h-8 text-sm" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -109,6 +109,9 @@
|
||||
data.invoice?.financials?.exchange_rate ?? null
|
||||
);
|
||||
|
||||
// Guardar la fecha inicial para detectar cambios manuales
|
||||
let initialInvoiceDate = data.invoice?.invoice_date || '';
|
||||
|
||||
let showExchangeRateDialog = $state(false);
|
||||
let missingExchangeRateDate = $state('');
|
||||
|
||||
@@ -149,13 +152,32 @@
|
||||
|
||||
// Efecto para actualizar el tipo de cambio cuando cambia la fecha de factura
|
||||
$effect(() => {
|
||||
if (mounted && companyStore?.activeCompany?.id && InvoiceTopFieldsFormData?.invoice_date) {
|
||||
getExchangeRateByDate(InvoiceTopFieldsFormData.invoice_date, companyStore.activeCompany.id)
|
||||
const currentDate = InvoiceTopFieldsFormData?.invoice_date;
|
||||
|
||||
// Solo proceder si:
|
||||
// 1. Tenemos datos cargados y compañía activa
|
||||
// 2. Es una factura nueva (isCreate)
|
||||
// 3. O la fecha es distinta a la original (el usuario la cambió)
|
||||
// 4. O no tenemos ningún tipo de cambio todavía
|
||||
|
||||
const shouldFetch =
|
||||
mounted &&
|
||||
companyStore?.activeCompany?.id &&
|
||||
currentDate &&
|
||||
(data.isCreate || currentDate !== initialInvoiceDate || !calculatedExchangeRate);
|
||||
|
||||
if (shouldFetch) {
|
||||
getExchangeRateByDate(currentDate, companyStore.activeCompany.id)
|
||||
.then((rate) => {
|
||||
if (rate) {
|
||||
calculatedExchangeRate = rate.value;
|
||||
} else {
|
||||
calculatedExchangeRate = 0;
|
||||
// Si no hay en catálogo, pero YA teníamos uno en la factura (y no cambió fecha), NO poner 0
|
||||
if (currentDate === initialInvoiceDate && data.invoice?.financials?.exchange_rate) {
|
||||
calculatedExchangeRate = data.invoice.financials.exchange_rate;
|
||||
} else {
|
||||
calculatedExchangeRate = 0;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => console.error('Error auto-updating exchange rate:', err));
|
||||
@@ -293,7 +315,7 @@
|
||||
: null}
|
||||
Nueva Factura
|
||||
{#if invoiceTypeInfo}
|
||||
<span class="text-muted-foreground font-normal text-2xl">
|
||||
<span class="text-2xl font-normal text-muted-foreground">
|
||||
- {invoiceTypeInfo.description}
|
||||
</span>
|
||||
{/if}
|
||||
@@ -420,9 +442,9 @@
|
||||
}}
|
||||
/>
|
||||
<div
|
||||
class="fixed bottom-0 left-0 right-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 border-t shadow-lg z-[5] group-has-data-[state=collapsed]/sidebar-wrapper:ml-[calc(var(--sidebar-width-icon))] ml-[calc(var(--sidebar-width))]"
|
||||
class="fixed right-0 bottom-0 left-0 z-[5] ml-[calc(var(--sidebar-width))] border-t bg-background/95 shadow-lg backdrop-blur group-has-data-[state=collapsed]/sidebar-wrapper:ml-[calc(var(--sidebar-width-icon))] supports-[backdrop-filter]:bg-background/80"
|
||||
>
|
||||
<div class="px-4 py-4 space-y-4 max-w-[1400px] mx-auto">
|
||||
<div class="mx-auto max-w-[1400px] space-y-4 px-4 py-4">
|
||||
<!-- Tabs Navigation -->
|
||||
<Tabs.Root bind:value={activeTab}>
|
||||
<div class="w-full overflow-x-auto pb-2">
|
||||
|
||||
Reference in New Issue
Block a user