diff --git a/frontend/src/lib/components/dashboard/parts/client-selector-dialog.svelte b/frontend/src/lib/components/dashboard/parts/client-selector-dialog.svelte new file mode 100644 index 00000000..e87aee97 --- /dev/null +++ b/frontend/src/lib/components/dashboard/parts/client-selector-dialog.svelte @@ -0,0 +1,146 @@ + + + + + + Seleccionar Cliente + + Busca y selecciona el cliente propietario de la parte. + + + +
+ + +
+ +
+ {#if loading} +
+ +

Cargando catálogo...

+
+ {:else if filteredClients.length === 0} +
+

No se encontraron clientes.

+
+ {:else} + + + + + + + + + + + + {#each filteredClients as client} + + + + + + + + {/each} + +
IDRFCRazón SocialEstadoAcción
{client.id}{client.rfc} +
+ {#if client.client_or_provider === 'client'} + + {:else} + + {/if} + {client.name} +
+
+ {#if client.is_active} + + Activo + + {:else} + + Baja + + {/if} + + +
+ {/if} +
+ + +
+ Mostrando {filteredClients.length} registro(s) +
+ +
+
+
\ No newline at end of file diff --git a/frontend/src/routes/dashboard/goods/parts/edit/[[id]]/+page.svelte b/frontend/src/routes/dashboard/goods/parts/edit/[[id]]/+page.svelte index b0b6ae4f..9254a048 100644 --- a/frontend/src/routes/dashboard/goods/parts/edit/[[id]]/+page.svelte +++ b/frontend/src/routes/dashboard/goods/parts/edit/[[id]]/+page.svelte @@ -12,10 +12,20 @@ import * as Card from '$lib/components/ui/card'; import * as Select from "$lib/components/ui/select"; import { Switch } from "$lib/components/ui/switch"; - import { ArrowLeft, LoaderCircle, Save, Package, DollarSign, FileText, Settings, Image as ImageIcon } from 'lucide-svelte'; + // Iconos + import { + ArrowLeft, LoaderCircle, Save, Package, DollarSign, + FileText, Settings, Image as ImageIcon, Search, + UserCheck, CheckCircle2, XCircle + } from 'lucide-svelte'; + // Stores & APIs import { companyStore } from '$lib/stores/company.svelte'; import { partsApi, type PartCreate } from '$lib/api/dashboard/a76/parts'; + import { clientsProvidersApi } from '$lib/api/dashboard/a76/clients-providers'; + + // COMPONENTE DEL MODAL (Ajusta la ruta si es necesario) + import ClientSelectorDialog from '$lib/components/dashboard/parts/client-selector-dialog.svelte'; // --- 1. IDENTIFICACIÓN --- let id = $derived($page.params.id === 'new' ? null : Number($page.params.id)); @@ -26,22 +36,30 @@ let loading = $state(false); let error = $state(null); + // Estado del Modal de Clientes + let showClientModal = $state(false); + let selectedClientName = $state(""); + let selectedClientStatus = $state(true); + // Estado del Formulario let formData = $state({ client_id: 0, part_number: '', + // General description_spanish: '', description_english: '', part_class: '', country_of_origin: 'MEX', unit_of_measure: 'PZ', + // Costos y Pesos unit_weight: 0, weight_type: 'KG', unit_cost: 0, currency_key: 'USD', added_value: 0, + value_added_type: 'USD', // Campo visual (no en BD) us_fraction: '', // Opciones @@ -110,12 +128,18 @@ unit_cost: Number(d.unit_cost) || 0, currency_key: d.currency_key || 'USD', added_value: Number(d.added_value) || 0, + value_added_type: 'USD', // Valor por defecto al cargar commercial_part_number: d.commercial_part_number || '', alternate_unit_measure: d.alternate_unit_measure || '', part_photo: d.part_photo || '', is_active: d.is_active ?? true }; + + // Cargar info visual del cliente + if (d.client_id) { + await fetchClientName(d.client_id, companyId); + } } } catch (e) { error = "Error al cargar la parte"; @@ -125,11 +149,33 @@ } } + // Función auxiliar para obtener nombre del cliente + async function fetchClientName(clientId: number, companyId: number) { + try { + const res = await clientsProvidersApi.get(clientId, companyId); + // Ajusta esto según cómo devuelva tu API el objeto (res o res.data) + const clientData = (res as any).data || res; + if (clientData) { + selectedClientName = clientData.name; + selectedClientStatus = clientData.is_active ?? true; + } + } catch (e) { + console.log("No se pudo cargar info visual del cliente", e); + } + } + + // Callback del Modal + function handleClientSelect(client: any) { + formData.client_id = client.id; + selectedClientName = client.name; + selectedClientStatus = client.is_active ?? true; + } + async function handleSubmit() { error = null; const activeCompanyId = companyStore.activeCompany?.id; if (!activeCompanyId) { error = 'No hay una compañía activa seleccionada'; return; } - if (!formData.client_id) { error = 'ID Cliente requerido (Pestaña Otros)'; return; } + if (!formData.client_id) { error = 'Debe seleccionar un Cliente (Pestaña Otros)'; return; } if (!formData.part_number.trim()) { error = 'Número de Parte requerido'; return; } loading = true; @@ -245,7 +291,7 @@
- +
@@ -255,11 +301,18 @@

- Unidades de Medida + Tipos de material y unidades de medida

+
- + + +

Campo informativo (Visual)

+
+ +
+ {formData.unit_of_measure || "Seleccione"} @@ -278,32 +331,34 @@

- Costos y Pesos + Costos, valores y peso unitario

- + {formData.currency_key} - Dólar (USD) - Peso (MXP) - Euro (EUR) + Dólares (USD) + Pesos (MXP) + Euros (EUR)
+
- +
+ $ + +
-
-
- + {formData.weight_type} @@ -316,10 +371,42 @@
-
- - -

Ingrese el monto numérico del valor agregado.

+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+ {#if formData.value_added_type === 'PERCENT'} + % + {:else} + $ + {/if} + + +
+
@@ -352,7 +439,7 @@
- + @@ -364,13 +451,44 @@
- +
- - + + +
+
+ + showClientModal = true} + /> +
+ + +
+ + {#if selectedClientName} +
+ {selectedClientName} + + {#if selectedClientStatus} + Activo + {:else} + Baja / Inactivo + {/if} +
+ {/if} +

El cliente propietario de este número de parte.

@@ -461,6 +579,11 @@
+ +