diff --git a/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/routes.py b/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/routes.py index e98e7e02..1dd91120 100644 --- a/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/routes.py +++ b/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/routes.py @@ -16,6 +16,7 @@ multi_currency_type_crud = TenantCRUDRoutes( tags=["Multi Currency Types"], resource_name="MultiCurrencyType", enable_list=True, + enable_filters=True, list_permissions=["cat_multi_currency_types.view"], get_permissions=["cat_multi_currency_types.view"], create_permissions=["cat_multi_currency_types.create"], diff --git a/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/service.py b/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/service.py index 979ff3d3..f9e2523f 100644 --- a/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/multi_currency_types/service.py @@ -22,8 +22,14 @@ class MultiCurrencyTypeService: ) if filters: - # Add filters here if needed - pass + if filters.get('currency_type_code'): + query = query.filter( + MultiCurrencyType.currency_type_code.ilike(f"%{filters['currency_type_code']}%") + ) + if filters.get('country_key'): + query = query.filter( + MultiCurrencyType.country_key.ilike(f"%{filters['country_key']}%") + ) total = query.count() items = query.offset(skip).limit(limit).all() diff --git a/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte index 452dd557..b318e602 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte @@ -3,15 +3,19 @@ import * as Dialog from '$lib/components/ui/dialog'; import { Input } from '$lib/components/ui/input'; import { Label } from '$lib/components/ui/label'; - // 👇 Verifica la ruta de tu archivo TS + import { Search } from 'lucide-svelte'; import { createMultiCurrencyType, updateMultiCurrencyType, type MultiCurrencyType } from '$lib/api/dashboard/a76/general_catalogs/multi-currency-types'; import { companyStore } from '$lib/stores/company.svelte'; - import { obtenerAtajosFormularioMonedas } from '$lib/config/shortcuts/dashboard/general_catalogs/multi_currency_types/edit'; import { m } from '$lib/i18n/messages'; + import CurrencySelectorDialog from '$lib/components/dashboard/goods/modales/currency-selector-dialog.svelte'; + import CountrySelectorDialog from '$lib/components/dashboard/goods/modales/country-selector-dialog.svelte'; + import type { CurrencyType } from '$lib/api/dashboard/reference_data/currency_types'; + import type { Country } from '$lib/api/dashboard/reference_data/countries'; + import { toast } from 'svelte-sonner'; let { open = $bindable(false), @@ -23,45 +27,36 @@ onSuccess?: () => void; } = $props(); - // Atajos - const isEdit = $derived(!!item); - const title = $derived( - isEdit ? m.multi_currency_edit_title() : m.multi_currency_new_title() - ); + const title = $derived(isEdit ? m.multi_currency_edit_title() : m.multi_currency_new_title()); - // Estado del formulario let formData = $state({ currency_type_code: '', country_key: '', conversion_factor: null as number | null, - date_str: '' // Usamos un string temporal para el input type="date" + date_str: '' }); let loading = $state(false); let error = $state(null); + let showCurrencyDialog = $state(false); + let showCountryDialog = $state(false); - // Cargar datos al abrir $effect(() => { if (open) { if (item) { - // Truco: Convertir Entero (20251231) -> String ("2025-12-31") + const s = item.publication_date?.toString(); let dateFormatted = ''; - if (item.publication_date) { - const s = item.publication_date.toString(); - if (s.length === 8) { - dateFormatted = `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}`; - } + if (s?.length === 8) { + dateFormatted = `${s.slice(0, 4)}-${s.slice(4, 6)}-${s.slice(6, 8)}`; } - formData = { currency_type_code: item.currency_type_code, country_key: item.country_key || '', conversion_factor: item.conversion_factor, date_str: dateFormatted }; - } else { - // Default: Fecha de hoy + } else { formData = { currency_type_code: '', country_key: '', @@ -73,6 +68,16 @@ } }); + function handleCurrencySelect(currency: CurrencyType) { + formData.currency_type_code = currency.code; + toast.success(`${currency.code} — ${currency.currency_name}`); + } + + function handleCountrySelect(country: Country) { + formData.country_key = country.m3_key; + toast.success(`${country.m3_key} — ${country.description_es || country.description_en || ''}`); + } + async function handleSubmit() { loading = true; error = null; @@ -80,33 +85,23 @@ try { const companyId = companyStore.activeCompany?.id; if (!companyId) throw new Error(m.exchange_rate_error_no_company()); - - // Validaciones if (!formData.currency_type_code.trim()) throw new Error(m.multi_currency_error_currency_required()); if (!formData.date_str) throw new Error(m.multi_currency_error_date_required()); - // Truco: Convertir String ("2025-12-31") -> Entero (20251231) - // Quitamos los guiones y parseamos a int const dateInt = parseInt(formData.date_str.replaceAll('-', ''), 10); - // Preparar datos const dataToSend = { currency_type_code: formData.currency_type_code.trim().toUpperCase(), country_key: formData.country_key.trim().toUpperCase() || null, conversion_factor: formData.conversion_factor ? Number(formData.conversion_factor) : null, - publication_date: dateInt // Mandamos el INT que espera Python + publication_date: dateInt }; - let response; - if (isEdit && item) { - response = await updateMultiCurrencyType(item.id, dataToSend, companyId); - } else { - response = await createMultiCurrencyType(dataToSend, companyId); - } + const response = isEdit && item + ? await updateMultiCurrencyType(item.id, dataToSend, companyId) + : await createMultiCurrencyType(dataToSend, companyId); - if (response?.error) { - throw new Error(response.error); - } + if (response?.error) throw new Error(response.error); open = false; if (onSuccess) onSuccess(); @@ -119,16 +114,16 @@ - + e.preventDefault()} + > {title}
{ - e.preventDefault(); - handleSubmit(); - }} + onsubmit={(e) => { e.preventDefault(); handleSubmit(); }} class="space-y-4 py-4" > {#if error} @@ -138,41 +133,77 @@ {/if}
+
- -
+ +
{ + formData.currency_type_code = e.currentTarget.value + .toUpperCase() + .replace(/[^A-Z]/g, '') + .slice(0, 3); + e.currentTarget.value = formData.currency_type_code; + }} + placeholder="Ej. USD" maxlength={3} disabled={loading} - required + class="flex-1 font-mono" /> -

{m.multi_currency_currency_help()}

+
+
-
+
{ + formData.country_key = e.currentTarget.value + .toUpperCase() + .replace(/[^A-Z]/g, '') + .slice(0, 3); + e.currentTarget.value = formData.country_key; + }} + placeholder="Ej. MEX" maxlength={3} disabled={loading} + class="flex-1 font-mono" /> -

{m.multi_currency_country_help()}

+
+
- +
-

{m.multi_currency_date_help()}

+

{m.multi_currency_date_help()}

+
@@ -211,3 +243,6 @@ + + + diff --git a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte index 2152fdcb..d1cbcb20 100644 --- a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte @@ -72,7 +72,11 @@ { accessorKey: 'publication_date', header: 'Fecha Publicación', - cell: ({ row }) => row.original.publication_date || '-' + cell: ({ row }) => { + const d = row.original.publication_date?.toString(); + if (!d || d.length !== 8) return '-'; + return `${d.slice(6, 8)}/${d.slice(4, 6)}/${d.slice(0, 4)}`; + } } ]; @@ -258,8 +262,8 @@

Gestión del catálogo de tipos de moneda múltiple

- {#if !isError && canCreate}