Merge pull request 'fix/tipo_cambio' (#170) from fix/tipo_cambio into development
Reviewed-on: ADUANASOFT/anexo76#170
This commit is contained in:
@@ -166,7 +166,7 @@
|
||||
<Dialog.Overlay class="fixed inset-0 z-[9999] {overlayClass}" />
|
||||
|
||||
<Dialog.Content
|
||||
class="fixed left-[50%] top-[50%] z-[10000] w-full max-w-[480px] translate-x-[-50%] translate-y-[-50%] overflow-hidden border-0 bg-transparent p-0 shadow-2xl sm:rounded-xl"
|
||||
class="fixed top-[50%] left-[50%] z-[10000] w-full max-w-[480px] translate-x-[-50%] translate-y-[-50%] overflow-hidden border-0 bg-transparent p-0 shadow-2xl sm:rounded-xl"
|
||||
>
|
||||
<div
|
||||
class="flex h-full flex-col overflow-hidden rounded-xl border border-border bg-background"
|
||||
@@ -181,7 +181,7 @@
|
||||
<AlertCircle class="text-amber-600 dark:text-amber-400" size={24} />
|
||||
</div>
|
||||
<div class="space-y-1">
|
||||
<h3 class="text-lg font-semibold leading-tight text-amber-900 dark:text-amber-100">
|
||||
<h3 class="text-lg leading-tight font-semibold text-amber-900 dark:text-amber-100">
|
||||
{title}
|
||||
</h3>
|
||||
<p class="text-sm leading-relaxed text-amber-800/80 dark:text-amber-200/80">
|
||||
@@ -232,7 +232,7 @@
|
||||
/>
|
||||
{#if isMissingRateContext}
|
||||
<div
|
||||
class="absolute right-3 top-1/2 -translate-y-1/2 rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-600"
|
||||
class="absolute top-1/2 right-3 -translate-y-1/2 rounded-full bg-amber-100 px-2 py-0.5 text-xs font-medium text-amber-600"
|
||||
>
|
||||
Requerida
|
||||
</div>
|
||||
@@ -241,28 +241,12 @@
|
||||
</div>
|
||||
|
||||
<div class="grid gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<Label for="value" class="ml-1 text-sm font-medium text-muted-foreground"
|
||||
>Tipo de Cambio (MXN/USD)</Label
|
||||
>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="-mr-2 h-6 px-2 text-xs text-primary hover:text-primary/80"
|
||||
disabled={scraping || loading || !formData.date}
|
||||
onclick={() => fetchFromDof(formData.date)}
|
||||
>
|
||||
{#if scraping}
|
||||
<span class="mr-1.5 animate-spin">⟳</span> Consultando...
|
||||
{:else}
|
||||
<CloudDownload size={14} class="mr-1.5" /> Consultar DOF
|
||||
{/if}
|
||||
</Button>
|
||||
</div>
|
||||
<Label for="value" class="ml-1 text-sm font-medium text-muted-foreground"
|
||||
>Tipo de Cambio (MXN/USD)</Label
|
||||
>
|
||||
<div class="group relative">
|
||||
<div
|
||||
class="absolute left-3 top-1/2 -translate-y-1/2 font-semibold text-muted-foreground"
|
||||
class="absolute top-1/2 left-3 -translate-y-1/2 font-semibold text-muted-foreground"
|
||||
>
|
||||
$
|
||||
</div>
|
||||
@@ -270,6 +254,7 @@
|
||||
id="value"
|
||||
type="number"
|
||||
step="0.0001"
|
||||
lang="en"
|
||||
bind:value={formData.value}
|
||||
disabled={loading}
|
||||
required
|
||||
@@ -278,18 +263,30 @@
|
||||
autofocus
|
||||
/>
|
||||
</div>
|
||||
<p class="px-1 text-right text-[11px] text-muted-foreground">Ej. 24.1234</p>
|
||||
<div class="mt-1 flex items-start justify-between">
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
size="sm"
|
||||
class="h-8 font-medium shadow-sm transition-all"
|
||||
disabled={scraping || loading || !formData.date}
|
||||
onclick={() => fetchFromDof(formData.date)}
|
||||
>
|
||||
{#if scraping}
|
||||
<span class="mr-2 animate-spin">⟳</span> Consultando...
|
||||
{:else}
|
||||
<CloudDownload size={15} class="mr-2" /> Consultar DOF
|
||||
{/if}
|
||||
</Button>
|
||||
<p class="mt-2 px-1 text-right text-[11px] text-muted-foreground">Ej. 24.1234</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Dialog.Footer class="grid grid-cols-4 gap-2 pt-2">
|
||||
<Button type="button" variant="outline" class="w-full text-xs" disabled>
|
||||
Cargar TC
|
||||
</Button>
|
||||
<Button type="button" variant="outline" class="w-full text-xs" disabled>Ayuda</Button>
|
||||
<Dialog.Footer class="mt-4 grid grid-cols-2 gap-3 pt-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
variant="outline"
|
||||
onclick={() => (open = false)}
|
||||
disabled={loading}
|
||||
class="w-full hover:bg-muted/50"
|
||||
|
||||
@@ -1,15 +1,20 @@
|
||||
<script lang="ts">
|
||||
import { Button } from "$lib/components/ui/button";
|
||||
import * as Dialog from "$lib/components/ui/dialog";
|
||||
import { Input } from "$lib/components/ui/input";
|
||||
import { Label } from "$lib/components/ui/label";
|
||||
import * as Select from "$lib/components/ui/select";
|
||||
import { invoicesApi, type Invoice, type CreateInvoiceData, type UpdateInvoiceData } from "$lib/api/dashboard/a76/invoices";
|
||||
import { getExchangeRates } from "$lib/api/dashboard/a76/general_catalogs/exchange-rate";
|
||||
import { companyStore } from "$lib/stores/company.svelte";
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import * as Dialog from '$lib/components/ui/dialog';
|
||||
import { Input } from '$lib/components/ui/input';
|
||||
import { Label } from '$lib/components/ui/label';
|
||||
import * as Select from '$lib/components/ui/select';
|
||||
import {
|
||||
invoicesApi,
|
||||
type Invoice,
|
||||
type CreateInvoiceData,
|
||||
type UpdateInvoiceData
|
||||
} from '$lib/api/dashboard/a76/invoices';
|
||||
import { getExchangeRates } from '$lib/api/dashboard/a76/general_catalogs/exchange-rate';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import { LoaderCircle } from 'lucide-svelte';
|
||||
import * as Tabs from "$lib/components/ui/tabs";
|
||||
import ExchangeRateDialog from "$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte";
|
||||
import * as Tabs from '$lib/components/ui/tabs';
|
||||
import ExchangeRateDialog from '$lib/components/dashboard/exchange_rate/create-edit-dialog.svelte';
|
||||
|
||||
let {
|
||||
open = $bindable(false),
|
||||
@@ -27,34 +32,34 @@
|
||||
|
||||
let formData = $state({
|
||||
// Header fields
|
||||
operation_type: "imp" as "imp" | "exp",
|
||||
invoice_type: "",
|
||||
invoice_number: "",
|
||||
project_number: "",
|
||||
purchase_order: "",
|
||||
operation_type: 'imp' as 'imp' | 'exp',
|
||||
invoice_type: '',
|
||||
invoice_number: '',
|
||||
project_number: '',
|
||||
purchase_order: '',
|
||||
related_doc_id: null as number | null,
|
||||
invoice_date: "",
|
||||
traffic_light_status: "",
|
||||
observation_es: "",
|
||||
observation_en: "",
|
||||
comments_status: "",
|
||||
cfdi_uuid: "",
|
||||
path_pdf: "",
|
||||
path_xml: "",
|
||||
invoice_date: '',
|
||||
traffic_light_status: '',
|
||||
observation_es: '',
|
||||
observation_en: '',
|
||||
comments_status: '',
|
||||
cfdi_uuid: '',
|
||||
path_pdf: '',
|
||||
path_xml: '',
|
||||
// Compliance MX fields
|
||||
remesa: null as number | null,
|
||||
aduana: "",
|
||||
customs_broker_id: "",
|
||||
provider_id: "",
|
||||
sold_to_id: "",
|
||||
shipped_to_id: "",
|
||||
shipped_by_id: "",
|
||||
aduana: '',
|
||||
customs_broker_id: '',
|
||||
provider_id: '',
|
||||
sold_to_id: '',
|
||||
shipped_to_id: '',
|
||||
shipped_by_id: '',
|
||||
is_mixed: false,
|
||||
waste_type: "",
|
||||
waste_type: '',
|
||||
appendix_17: null as number | null,
|
||||
edocument: "",
|
||||
edocument: '',
|
||||
// Financials fields
|
||||
currency: "MXN",
|
||||
currency: 'MXN',
|
||||
exchange_rate: null as number | null,
|
||||
value_mn: null as number | null,
|
||||
value_me: null as number | null,
|
||||
@@ -73,38 +78,38 @@
|
||||
let error = $state<string | null>(null);
|
||||
|
||||
let showExchangeRateDialog = $state(false);
|
||||
let missingExchangeRateDate = $state("");
|
||||
let missingExchangeRateDate = $state('');
|
||||
|
||||
// Actualizar formData cuando item cambia
|
||||
$effect(() => {
|
||||
if (item) {
|
||||
formData = {
|
||||
operation_type: item.operation_type || "imp",
|
||||
invoice_type: item.invoice_type || "",
|
||||
invoice_number: item.invoice_number || "",
|
||||
project_number: item.project_number || "",
|
||||
purchase_order: item.purchase_order || "",
|
||||
operation_type: item.operation_type || 'imp',
|
||||
invoice_type: item.invoice_type || '',
|
||||
invoice_number: item.invoice_number || '',
|
||||
project_number: item.project_number || '',
|
||||
purchase_order: item.purchase_order || '',
|
||||
related_doc_id: item.related_doc_id || null,
|
||||
invoice_date: item.invoice_date || "",
|
||||
traffic_light_status: item.traffic_light_status || "",
|
||||
observation_es: item.observation_es || "",
|
||||
observation_en: item.observation_en || "",
|
||||
comments_status: item.comments_status || "",
|
||||
cfdi_uuid: item.cfdi_uuid || "",
|
||||
path_pdf: item.path_pdf || "",
|
||||
path_xml: item.path_xml || "",
|
||||
invoice_date: item.invoice_date || '',
|
||||
traffic_light_status: item.traffic_light_status || '',
|
||||
observation_es: item.observation_es || '',
|
||||
observation_en: item.observation_en || '',
|
||||
comments_status: item.comments_status || '',
|
||||
cfdi_uuid: item.cfdi_uuid || '',
|
||||
path_pdf: item.path_pdf || '',
|
||||
path_xml: item.path_xml || '',
|
||||
remesa: item.compliance_mx?.remesa || null,
|
||||
aduana: item.compliance_mx?.aduana || "",
|
||||
customs_broker_id: item.compliance_mx?.customs_broker_id?.toString() || "",
|
||||
provider_id: item.compliance_mx?.provider_id?.toString() || "",
|
||||
sold_to_id: item.compliance_mx?.sold_to_id?.toString() || "",
|
||||
shipped_to_id: item.compliance_mx?.shipped_to_id?.toString() || "",
|
||||
shipped_by_id: item.compliance_mx?.shipped_by_id?.toString() || "",
|
||||
aduana: item.compliance_mx?.aduana || '',
|
||||
customs_broker_id: item.compliance_mx?.customs_broker_id?.toString() || '',
|
||||
provider_id: item.compliance_mx?.provider_id?.toString() || '',
|
||||
sold_to_id: item.compliance_mx?.sold_to_id?.toString() || '',
|
||||
shipped_to_id: item.compliance_mx?.shipped_to_id?.toString() || '',
|
||||
shipped_by_id: item.compliance_mx?.shipped_by_id?.toString() || '',
|
||||
is_mixed: item.compliance_mx?.is_mixed || false,
|
||||
waste_type: item.compliance_mx?.waste_type || "",
|
||||
waste_type: item.compliance_mx?.waste_type || '',
|
||||
appendix_17: item.compliance_mx?.appendix_17 || null,
|
||||
edocument: item.compliance_mx?.edocument || "",
|
||||
currency: item.financials?.currency || "MXN",
|
||||
edocument: item.compliance_mx?.edocument || '',
|
||||
currency: item.financials?.currency || 'MXN',
|
||||
exchange_rate: item.financials?.exchange_rate || null,
|
||||
value_mn: item.financials?.value_mn || null,
|
||||
value_me: item.financials?.value_me || null,
|
||||
@@ -127,32 +132,32 @@
|
||||
|
||||
function resetForm() {
|
||||
formData = {
|
||||
operation_type: defaultOperationType || "imp",
|
||||
invoice_type: defaultInvoiceType || "",
|
||||
invoice_number: "",
|
||||
project_number: "",
|
||||
purchase_order: "",
|
||||
operation_type: defaultOperationType || 'imp',
|
||||
invoice_type: defaultInvoiceType || '',
|
||||
invoice_number: '',
|
||||
project_number: '',
|
||||
purchase_order: '',
|
||||
related_doc_id: null,
|
||||
invoice_date: "",
|
||||
traffic_light_status: "",
|
||||
observation_es: "",
|
||||
observation_en: "",
|
||||
comments_status: "",
|
||||
cfdi_uuid: "",
|
||||
path_pdf: "",
|
||||
path_xml: "",
|
||||
invoice_date: '',
|
||||
traffic_light_status: '',
|
||||
observation_es: '',
|
||||
observation_en: '',
|
||||
comments_status: '',
|
||||
cfdi_uuid: '',
|
||||
path_pdf: '',
|
||||
path_xml: '',
|
||||
remesa: null,
|
||||
aduana: "",
|
||||
customs_broker_id: "",
|
||||
provider_id: "",
|
||||
sold_to_id: "",
|
||||
shipped_to_id: "",
|
||||
shipped_by_id: "",
|
||||
aduana: '',
|
||||
customs_broker_id: '',
|
||||
provider_id: '',
|
||||
sold_to_id: '',
|
||||
shipped_to_id: '',
|
||||
shipped_by_id: '',
|
||||
is_mixed: false,
|
||||
waste_type: "",
|
||||
waste_type: '',
|
||||
appendix_17: null,
|
||||
edocument: "",
|
||||
currency: "MXN",
|
||||
edocument: '',
|
||||
currency: 'MXN',
|
||||
exchange_rate: null,
|
||||
value_mn: null,
|
||||
value_me: null,
|
||||
@@ -170,9 +175,9 @@
|
||||
|
||||
async function handleSubmit(e: Event) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
if (!companyStore.activeCompany) {
|
||||
error = "No hay compañía seleccionada";
|
||||
error = 'No hay compañía seleccionada';
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -180,14 +185,14 @@
|
||||
error = null;
|
||||
|
||||
try {
|
||||
// Verificar tipo de cambio antes de guardar
|
||||
if (formData.invoice_date) {
|
||||
const rateExists = await checkExchangeRate(formData.invoice_date);
|
||||
if (!rateExists) {
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Verificar tipo de cambio antes de guardar
|
||||
if (formData.invoice_date) {
|
||||
const rateExists = await checkExchangeRate(formData.invoice_date);
|
||||
if (!rateExists) {
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let response;
|
||||
if (isEditing && item) {
|
||||
@@ -210,7 +215,9 @@
|
||||
compliance_mx: {
|
||||
remesa: formData.remesa,
|
||||
aduana: formData.aduana || null,
|
||||
customs_broker_id: formData.customs_broker_id ? parseInt(formData.customs_broker_id) : null,
|
||||
customs_broker_id: formData.customs_broker_id
|
||||
? parseInt(formData.customs_broker_id)
|
||||
: null,
|
||||
provider_id: formData.provider_id ? parseInt(formData.provider_id) : null,
|
||||
sold_to_id: formData.sold_to_id ? parseInt(formData.sold_to_id) : null,
|
||||
shipped_to_id: formData.shipped_to_id ? parseInt(formData.shipped_to_id) : null,
|
||||
@@ -238,9 +245,9 @@
|
||||
};
|
||||
response = await invoicesApi.update(item.id, companyStore.activeCompany.id, payload);
|
||||
} else {
|
||||
const payload: CreateInvoiceData = {
|
||||
system: "a76",
|
||||
document_type: "invoice",
|
||||
const payload: CreateInvoiceData = {
|
||||
system: 'a76',
|
||||
document_type: 'invoice',
|
||||
operation_type: formData.operation_type,
|
||||
invoice_type: formData.invoice_type,
|
||||
invoice_number: formData.invoice_number,
|
||||
@@ -258,7 +265,9 @@
|
||||
compliance_mx: {
|
||||
remesa: formData.remesa,
|
||||
aduana: formData.aduana || null,
|
||||
customs_broker_id: formData.customs_broker_id ? parseInt(formData.customs_broker_id) : null,
|
||||
customs_broker_id: formData.customs_broker_id
|
||||
? parseInt(formData.customs_broker_id)
|
||||
: null,
|
||||
provider_id: formData.provider_id ? parseInt(formData.provider_id) : null,
|
||||
sold_to_id: formData.sold_to_id ? parseInt(formData.sold_to_id) : null,
|
||||
shipped_to_id: formData.shipped_to_id ? parseInt(formData.shipped_to_id) : null,
|
||||
@@ -294,21 +303,23 @@
|
||||
window.location.reload();
|
||||
}, 1500);
|
||||
} else {
|
||||
// Convertir el error a string para buscar mensajes específicos (maneja objetos/arrays de DRF)
|
||||
const errorStr = typeof response.error === 'string'
|
||||
? response.error
|
||||
: JSON.stringify(response.error);
|
||||
|
||||
if (errorStr.includes('No existe un Tipo de Cambio registrado') || errorStr.includes('financials.exchange_rate')) {
|
||||
// Interceptar error de tipo de cambio
|
||||
error = null;
|
||||
|
||||
const dateMatch = errorStr.match(/(\d{4}-\d{2}-\d{2})/);
|
||||
missingExchangeRateDate = dateMatch ? dateMatch[0] : (formData.invoice_date || "");
|
||||
|
||||
showExchangeRateDialog = true;
|
||||
return;
|
||||
}
|
||||
// Convertir el error a string para buscar mensajes específicos (maneja objetos/arrays de DRF)
|
||||
const errorStr =
|
||||
typeof response.error === 'string' ? response.error : JSON.stringify(response.error);
|
||||
|
||||
if (
|
||||
errorStr.includes('No existe un Tipo de Cambio registrado') ||
|
||||
errorStr.includes('financials.exchange_rate')
|
||||
) {
|
||||
// Interceptar error de tipo de cambio
|
||||
error = null;
|
||||
|
||||
const dateMatch = errorStr.match(/(\d{4}-\d{2}-\d{2})/);
|
||||
missingExchangeRateDate = dateMatch ? dateMatch[0] : formData.invoice_date || '';
|
||||
|
||||
showExchangeRateDialog = true;
|
||||
return;
|
||||
}
|
||||
|
||||
error = response.error;
|
||||
}
|
||||
@@ -316,13 +327,13 @@
|
||||
}
|
||||
|
||||
// Check exchange rate BEFORE calling API to avoid 400 error
|
||||
if (formData.invoice_date) {
|
||||
const rateExists = await checkExchangeRate(formData.invoice_date);
|
||||
if (!rateExists) {
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (formData.invoice_date) {
|
||||
const rateExists = await checkExchangeRate(formData.invoice_date);
|
||||
if (!rateExists) {
|
||||
loading = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Éxito
|
||||
open = false;
|
||||
@@ -330,8 +341,8 @@
|
||||
onSuccess();
|
||||
}
|
||||
} catch (e) {
|
||||
error = e instanceof Error ? e.message : "Error al guardar";
|
||||
console.error("Error saving:", e);
|
||||
error = e instanceof Error ? e.message : 'Error al guardar';
|
||||
console.error('Error saving:', e);
|
||||
} finally {
|
||||
loading = false;
|
||||
}
|
||||
@@ -345,11 +356,11 @@
|
||||
date: date,
|
||||
page_size: 1
|
||||
});
|
||||
|
||||
|
||||
// api.get returns { data: ..., status: ... } and types now reflect that
|
||||
const items = response.data?.items || [];
|
||||
|
||||
// Verificar estrictamente que haya items
|
||||
|
||||
// Verificar estrictamente que haya items
|
||||
if (items.length === 0) {
|
||||
missingExchangeRateDate = date;
|
||||
showExchangeRateDialog = true;
|
||||
@@ -360,7 +371,7 @@
|
||||
console.error('Error checking exchange rate:', error);
|
||||
missingExchangeRateDate = date;
|
||||
showExchangeRateDialog = true;
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -374,15 +385,13 @@
|
||||
</script>
|
||||
|
||||
<Dialog.Root {open} onOpenChange={handleOpenChange}>
|
||||
<Dialog.Content class="sm:max-w-full max-h-[90vh] overflow-y-auto">
|
||||
<Dialog.Content class="max-h-[90vh] overflow-y-auto sm:max-w-full">
|
||||
<Dialog.Header>
|
||||
<Dialog.Title>
|
||||
{isEditing ? "Editar Factura" : "Nueva Factura"}
|
||||
{isEditing ? 'Editar Factura' : 'Nueva Factura'}
|
||||
</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
{isEditing
|
||||
? "Modifica los datos de la factura"
|
||||
: "Ingresa los datos de la nueva factura"}
|
||||
{isEditing ? 'Modifica los datos de la factura' : 'Ingresa los datos de la nueva factura'}
|
||||
</Dialog.Description>
|
||||
</Dialog.Header>
|
||||
|
||||
@@ -397,24 +406,29 @@
|
||||
<!-- General Tab -->
|
||||
<Tabs.Content value="general" class="space-y-4">
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="operation_type">Tipo de Operación *</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type}
|
||||
onValueChange={(v: string) => {
|
||||
if (v) formData.operation_type = v as "imp" | "exp";
|
||||
}}
|
||||
>
|
||||
<Select.Trigger>
|
||||
{formData.operation_type === 'imp' ? 'Importación' : formData.operation_type === 'exp' ? 'Exportación' : 'Seleccionar tipo'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="imp">Importación</Select.Item>
|
||||
<Select.Item value="exp">Exportación</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div> <div class="space-y-2">
|
||||
<div class="space-y-2">
|
||||
<Label for="operation_type">Tipo de Operación *</Label>
|
||||
<Select.Root
|
||||
type="single"
|
||||
value={formData.operation_type}
|
||||
onValueChange={(v: string) => {
|
||||
if (v) formData.operation_type = v as 'imp' | 'exp';
|
||||
}}
|
||||
>
|
||||
<Select.Trigger>
|
||||
{formData.operation_type === 'imp'
|
||||
? 'Importación'
|
||||
: formData.operation_type === 'exp'
|
||||
? 'Exportación'
|
||||
: 'Seleccionar tipo'}
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="imp">Importación</Select.Item>
|
||||
<Select.Item value="exp">Exportación</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label for="invoice_number">Número de Factura</Label>
|
||||
<Input
|
||||
id="invoice_number"
|
||||
@@ -452,11 +466,7 @@
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="invoice_date">Fecha de Factura</Label>
|
||||
<Input
|
||||
id="invoice_date"
|
||||
type="date"
|
||||
bind:value={formData.invoice_date}
|
||||
/>
|
||||
<Input id="invoice_date" type="date" bind:value={formData.invoice_date} />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@@ -470,11 +480,7 @@
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="cfdi_uuid">CFDI UUID</Label>
|
||||
<Input
|
||||
id="cfdi_uuid"
|
||||
bind:value={formData.cfdi_uuid}
|
||||
placeholder="UUID del CFDI"
|
||||
/>
|
||||
<Input id="cfdi_uuid" bind:value={formData.cfdi_uuid} placeholder="UUID del CFDI" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -514,11 +520,7 @@
|
||||
|
||||
<div class="space-y-2">
|
||||
<Label for="aduana">Aduana</Label>
|
||||
<Input
|
||||
id="aduana"
|
||||
bind:value={formData.aduana}
|
||||
placeholder="Código de aduana"
|
||||
/>
|
||||
<Input id="aduana" bind:value={formData.aduana} placeholder="Código de aduana" />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@@ -548,7 +550,7 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2 flex items-center gap-2 pt-8">
|
||||
<div class="flex items-center gap-2 space-y-2 pt-8">
|
||||
<input
|
||||
id="is_mixed"
|
||||
type="checkbox"
|
||||
@@ -565,11 +567,7 @@
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="space-y-2">
|
||||
<Label for="currency">Moneda</Label>
|
||||
<Input
|
||||
id="currency"
|
||||
bind:value={formData.currency}
|
||||
placeholder="MXN, USD, etc."
|
||||
/>
|
||||
<Input id="currency" bind:value={formData.currency} placeholder="MXN, USD, etc." />
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
@@ -696,34 +694,31 @@
|
||||
</Tabs.Root>
|
||||
|
||||
{#if error}
|
||||
<div class="p-3 text-sm text-destructive bg-destructive/10 rounded-md">
|
||||
<div class="rounded-md bg-destructive/10 p-3 text-sm text-destructive">
|
||||
{error}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<Dialog.Footer>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onclick={() => (open = false)}
|
||||
disabled={loading}
|
||||
>
|
||||
<Button type="button" variant="outline" onclick={() => (open = false)} disabled={loading}>
|
||||
Cancelar
|
||||
</Button>
|
||||
<Button type="submit" disabled={loading}>
|
||||
{#if loading}
|
||||
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
||||
{/if}
|
||||
{isEditing ? "Actualizar" : "Crear"}
|
||||
{isEditing ? 'Actualizar' : 'Crear'}
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</form>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
|
||||
<ExchangeRateDialog
|
||||
bind:open={showExchangeRateDialog}
|
||||
<ExchangeRateDialog
|
||||
bind:open={showExchangeRateDialog}
|
||||
initialDate={missingExchangeRateDate}
|
||||
overlayClass="bg-black/20"
|
||||
onSuccess={() => {/* Optional: maybe refresh something or just let user continue */}}
|
||||
onSuccess={() => {
|
||||
/* Optional: maybe refresh something or just let user continue */
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
import * as Sidebar from '$lib/components/ui/sidebar/index.js';
|
||||
import { companyStore } from '$lib/stores/company.svelte';
|
||||
import ExchangeRateGuard from '$lib/components/dashboard/exchange_rate/exchange-rate-guard.svelte';
|
||||
import { page } from '$app/state';
|
||||
|
||||
let { data, children }: { data: LayoutData; children: any } = $props();
|
||||
|
||||
@@ -63,4 +64,6 @@
|
||||
</Sidebar.Inset>
|
||||
</Sidebar.Provider>
|
||||
|
||||
<ExchangeRateGuard overlayClass="bg-black/5" />
|
||||
{#if !page.url.pathname.includes('/dashboard/invoices') && !page.url.pathname.includes('/dashboard/pedimentos')}
|
||||
<ExchangeRateGuard overlayClass="bg-black/5" />
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user