Se integro el sistema de extraer el tipo de cambio

This commit is contained in:
2026-01-23 10:42:21 -06:00
parent bf26268f23
commit b8045d73e6
9 changed files with 228 additions and 18 deletions

View File

@@ -8,10 +8,11 @@
import {
createExchangeRate,
updateExchangeRate,
type ExchangeRate
type ExchangeRate,
getDofExchangeRate
} from "$lib/api/dashboard/a76/general_catalogs/exchange-rate";
import { companyStore } from "$lib/stores/company.svelte";
import { Scale, BadgeDollarSign, Info, AlertCircle, ArrowRight } from "lucide-svelte";
import { Scale, BadgeDollarSign, Info, AlertCircle, ArrowRight, CloudDownload } from "lucide-svelte";
import { fly, scale } from 'svelte/transition';
import { cubicOut } from 'svelte/easing';
@@ -44,6 +45,7 @@
});
let loading = $state(false);
let scraping = $state(false);
let error = $state<string | null>(null);
let showConfirmation = $state(false);
@@ -65,11 +67,40 @@
local_currency: 'MXN',
foreign_currency: 'USD'
};
// Si es modo contexto (falta dato) y tenemos fecha, intentar cargar automáticamente del DOF
if (initialDate && !item) {
// Opcional: Auto-consultar
// fetchFromDof(initialDate);
}
}
error = null;
}
});
async function fetchFromDof(date: string) {
if (!date) return;
scraping = true;
error = null;
try {
const response = await getDofExchangeRate(date);
// The API returns an ApiResponse object, so we need to access response.data
// response.data contains { success: boolean, value: number, message: string }
if (response.data?.success && response.data?.value) {
formData.value = response.data.value;
toast.success(`Tipo de cambio obtenido del DOF: ${response.data.value}`);
} else {
toast.error(response.data?.message || response.error || 'No se pudo obtener el dato del DOF');
// No bloquear, permitir manual
}
} catch (e) {
console.error(e);
toast.error('Error al consultar el servicio del DOF');
} finally {
scraping = false;
}
}
function handleSubmit() {
error = null;
try {
@@ -124,8 +155,6 @@
<Dialog.Content
class="fixed left-[50%] top-[50%] z-[10000] w-full max-w-[480px] translate-x-[-50%] translate-y-[-50%] border-0 bg-transparent shadow-2xl p-0 sm:rounded-xl overflow-hidden"
transition={scale}
params={{ duration: 300, easing: cubicOut, start: 0.95 }}
>
<div class="bg-background flex flex-col h-full rounded-xl overflow-hidden border border-border">
@@ -181,7 +210,23 @@
</div>
<div class="grid gap-2">
<Label for="value" class="text-sm font-medium text-muted-foreground ml-1">Tipo de Cambio (MXN/USD)</Label>
<div class="flex items-center justify-between">
<Label for="value" class="text-sm font-medium text-muted-foreground ml-1">Tipo de Cambio (MXN/USD)</Label>
<Button
type="button"
variant="ghost"
size="sm"
class="h-6 text-xs text-primary hover:text-primary/80 px-2 -mr-2"
disabled={scraping || loading || !formData.date}
onclick={() => fetchFromDof(formData.date)}
>
{#if scraping}
<span class="animate-spin mr-1.5"></span> Consultando...
{:else}
<CloudDownload size={14} class="mr-1.5" /> Consultar DOF
{/if}
</Button>
</div>
<div class="relative group">
<div class="absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground font-semibold">$</div>
<Input

View File

@@ -25,9 +25,8 @@
});
console.log('[ExchangeRateGuard] Response (stringified):', JSON.stringify(response, null, 2));
// api.get returns { data: ..., status: ... } but types say otherwise
const actualResponse = response as any;
const items = actualResponse.data?.items || [];
// 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');

View File

@@ -354,8 +354,8 @@
page_size: 1
});
const actualResponse = response as any;
const items = actualResponse.data?.items || [];
// api.get returns { data: ..., status: ... } and types now reflect that
const items = response.data?.items || [];
// Verificar estrictamente que haya items
if (items.length === 0) {