|
|
|
|
@@ -7,9 +7,9 @@
|
|
|
|
|
import * as Select from "$lib/components/ui/select";
|
|
|
|
|
import { classesApi, type A76Class, type A76ClassCreate, type A76ClassUpdate } from "$lib/api/dashboard/a76/classes";
|
|
|
|
|
import { materialTypesApi, type MaterialType } from "$lib/api/dashboard/refrence_data/material_types";
|
|
|
|
|
import { clientsProvidersApi, type ClientProviderBasic } from "$lib/api/dashboard/a76/clients-providers";
|
|
|
|
|
import { companyStore } from "$lib/stores/company.svelte";
|
|
|
|
|
import { onMount } from 'svelte';
|
|
|
|
|
import { LoaderCircle, Home } from 'lucide-svelte';
|
|
|
|
|
|
|
|
|
|
let {
|
|
|
|
|
open = $bindable(false),
|
|
|
|
|
@@ -27,6 +27,7 @@
|
|
|
|
|
|
|
|
|
|
// Estado del formulario
|
|
|
|
|
let formData = $state({
|
|
|
|
|
client_id: item?.client_id || null,
|
|
|
|
|
class_code: item?.class_code || '',
|
|
|
|
|
description_es: item?.description_es || '',
|
|
|
|
|
description_en: item?.description_en || '',
|
|
|
|
|
@@ -43,17 +44,23 @@
|
|
|
|
|
let error = $state<string | null>(null);
|
|
|
|
|
let materialTypes = $state<MaterialType[]>([]);
|
|
|
|
|
let loadingMaterialTypes = $state(false);
|
|
|
|
|
let clients = $state<ClientProviderBasic[]>([]);
|
|
|
|
|
let loadingClients = $state(false);
|
|
|
|
|
|
|
|
|
|
// Variables para controlar los selects
|
|
|
|
|
let selectedUnitValue = $state<string>('KG');
|
|
|
|
|
let selectedMaterialValue = $state<string>('');
|
|
|
|
|
let selectedPhysicalReviewValue = $state<number>(0);
|
|
|
|
|
|
|
|
|
|
// Cargar tipos de materiales al montar
|
|
|
|
|
// Cargar tipos de materiales y clientes al montar
|
|
|
|
|
onMount(async () => {
|
|
|
|
|
const companyId = companyStore.activeCompany?.id;
|
|
|
|
|
if (!companyId) return;
|
|
|
|
|
|
|
|
|
|
// Cargar tipos de materiales
|
|
|
|
|
loadingMaterialTypes = true;
|
|
|
|
|
try {
|
|
|
|
|
const response = await materialTypesApi.list(1, 100); // Cargar los primeros 100
|
|
|
|
|
const response = await materialTypesApi.list(1, 100);
|
|
|
|
|
if (response.data) {
|
|
|
|
|
materialTypes = response.data.items;
|
|
|
|
|
}
|
|
|
|
|
@@ -62,12 +69,26 @@
|
|
|
|
|
} finally {
|
|
|
|
|
loadingMaterialTypes = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cargar clientes
|
|
|
|
|
loadingClients = true;
|
|
|
|
|
try {
|
|
|
|
|
const response = await clientsProvidersApi.listClients(companyId, 0, 500);
|
|
|
|
|
if (response.data) {
|
|
|
|
|
clients = response.data;
|
|
|
|
|
}
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error('Error loading clients:', e);
|
|
|
|
|
} finally {
|
|
|
|
|
loadingClients = false;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Resetear formulario cuando cambia el item
|
|
|
|
|
$effect(() => {
|
|
|
|
|
if (item) {
|
|
|
|
|
formData = {
|
|
|
|
|
client_id: item.client_id,
|
|
|
|
|
class_code: item.class_code,
|
|
|
|
|
description_es: item.description_es || '',
|
|
|
|
|
description_en: item.description_en || '',
|
|
|
|
|
@@ -86,6 +107,7 @@
|
|
|
|
|
} else {
|
|
|
|
|
// Reset para modo crear
|
|
|
|
|
formData = {
|
|
|
|
|
client_id: null,
|
|
|
|
|
class_code: '',
|
|
|
|
|
description_es: '',
|
|
|
|
|
description_en: '',
|
|
|
|
|
@@ -122,6 +144,10 @@
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Validaciones básicas
|
|
|
|
|
if (!formData.client_id) {
|
|
|
|
|
error = 'Debes seleccionar un cliente';
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!formData.class_code.trim()) {
|
|
|
|
|
error = 'El código de clase es requerido';
|
|
|
|
|
return;
|
|
|
|
|
@@ -152,6 +178,7 @@
|
|
|
|
|
if (isEdit && item) {
|
|
|
|
|
// Actualizar
|
|
|
|
|
const updateData: A76ClassUpdate = {
|
|
|
|
|
client_id: formData.client_id!,
|
|
|
|
|
class_code: formData.class_code,
|
|
|
|
|
description_es: formData.description_es || null,
|
|
|
|
|
description_en: formData.description_en || null,
|
|
|
|
|
@@ -165,10 +192,10 @@
|
|
|
|
|
};
|
|
|
|
|
response = await classesApi.update(item.id, updateData, companyId);
|
|
|
|
|
} else {
|
|
|
|
|
// Crear - usa el company_id como client_id
|
|
|
|
|
// Crear con el client_id seleccionado
|
|
|
|
|
const createData: A76ClassCreate = {
|
|
|
|
|
company_id: companyId,
|
|
|
|
|
client_id: companyId, // Usa el mismo company_id como client_id
|
|
|
|
|
client_id: formData.client_id!,
|
|
|
|
|
class_code: formData.class_code,
|
|
|
|
|
description_es: formData.description_es || null,
|
|
|
|
|
description_en: formData.description_en || null,
|
|
|
|
|
@@ -249,7 +276,21 @@
|
|
|
|
|
{#if companyStore.activeCompany}
|
|
|
|
|
<div class="rounded-md bg-blue-50 border border-blue-200 p-3">
|
|
|
|
|
<div class="flex items-center gap-2">
|
|
|
|
|
<Home class="h-4 w-4 text-blue-600" />
|
|
|
|
|
<svg
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
width="16"
|
|
|
|
|
height="16"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
fill="none"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
stroke-width="2"
|
|
|
|
|
stroke-linecap="round"
|
|
|
|
|
stroke-linejoin="round"
|
|
|
|
|
class="text-blue-600"
|
|
|
|
|
>
|
|
|
|
|
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
|
|
|
|
<polyline points="9 22 9 12 15 12 15 22" />
|
|
|
|
|
</svg>
|
|
|
|
|
<div>
|
|
|
|
|
<p class="text-sm font-medium text-blue-900">
|
|
|
|
|
{companyStore.activeCompany.name}
|
|
|
|
|
@@ -262,6 +303,34 @@
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<!-- Cliente -->
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
<Label for="client_id" class="required">Cliente</Label>
|
|
|
|
|
{#if loadingClients}
|
|
|
|
|
<div class="flex items-center gap-2 text-sm text-muted-foreground">
|
|
|
|
|
<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
|
|
|
|
|
Cargando clientes...
|
|
|
|
|
</div>
|
|
|
|
|
{:else if clients.length > 0}
|
|
|
|
|
<select
|
|
|
|
|
bind:value={formData.client_id}
|
|
|
|
|
disabled={loading}
|
|
|
|
|
class="border-input bg-background selection:bg-primary dark:bg-input/30 selection:text-primary-foreground ring-offset-background placeholder:text-muted-foreground shadow-xs flex h-9 w-full min-w-0 rounded-md border px-3 py-1 text-base outline-none transition-[color,box-shadow] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
|
|
|
|
>
|
|
|
|
|
<option value="">Selecciona un cliente</option>
|
|
|
|
|
{#each clients as client}
|
|
|
|
|
<option value={client.id}>
|
|
|
|
|
{client.name} ({client.rfc})
|
|
|
|
|
</option>
|
|
|
|
|
{/each}
|
|
|
|
|
</select>
|
|
|
|
|
{:else}
|
|
|
|
|
<div class="text-sm text-muted-foreground">
|
|
|
|
|
No hay clientes disponibles
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Código de Clase -->
|
|
|
|
|
<div class="space-y-2">
|
|
|
|
|
<Label for="class_code" class="required">Código de Clase</Label>
|
|
|
|
|
@@ -413,7 +482,26 @@
|
|
|
|
|
</Button>
|
|
|
|
|
<Button type="submit" disabled={loading}>
|
|
|
|
|
{#if loading}
|
|
|
|
|
<LoaderCircle class="mr-2 h-4 w-4 animate-spin" />
|
|
|
|
|
<svg
|
|
|
|
|
class="mr-2 h-4 w-4 animate-spin"
|
|
|
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
|
|
|
fill="none"
|
|
|
|
|
viewBox="0 0 24 24"
|
|
|
|
|
>
|
|
|
|
|
<circle
|
|
|
|
|
class="opacity-25"
|
|
|
|
|
cx="12"
|
|
|
|
|
cy="12"
|
|
|
|
|
r="10"
|
|
|
|
|
stroke="currentColor"
|
|
|
|
|
stroke-width="4"
|
|
|
|
|
></circle>
|
|
|
|
|
<path
|
|
|
|
|
class="opacity-75"
|
|
|
|
|
fill="currentColor"
|
|
|
|
|
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
|
|
|
></path>
|
|
|
|
|
</svg>
|
|
|
|
|
Guardando...
|
|
|
|
|
{:else}
|
|
|
|
|
{isEdit ? 'Actualizar' : 'Crear'}
|
|
|
|
|
|