From af863e624fd163163f21f348c1fe4a412c587090 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Thu, 22 Jan 2026 12:19:58 -0600 Subject: [PATCH 1/3] fix(main-data): implement automatic class description updates based on class_id changes --- .../invoices/edit/items/fa/main-data.svelte | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/main-data.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/main-data.svelte index ffa3152c..21e16369 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/main-data.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/main-data.svelte @@ -8,6 +8,7 @@ import TariffFractionDialog from './tariff-fraction-dialog.svelte'; import ClassDialog from './class-dialog.svelte'; import type { LineItem, LineQuantities, LineFinancials, LineCustoms } from '$lib/api/dashboard/a76/items'; + import { companyStore } from '$lib/stores/company.svelte'; let { lineItem = $bindable(), @@ -26,6 +27,9 @@ let showCountryDialog = $state(false); let showFractionDialog = $state(false); + // Track previous class_id to detect changes + let previousClassId = $state(undefined); + // Initialize from existing data $effect(() => { if (lineItem.class_code) { @@ -33,12 +37,66 @@ } }); + // Watch for class_id changes and update descriptions automatically + $effect(() => { + const currentClassId = lineItem.class_id; + const activeCompanyId = companyStore?.activeCompany?.id; + + // Only fetch if class_id changed, is valid, and we have a company + if (currentClassId && currentClassId !== previousClassId && activeCompanyId) { + previousClassId = currentClassId; + + // Fetch all classes and find the one with matching ID + fetch(`/api-sveltekit/classes?company_id=${activeCompanyId}&limit=100`) + .then(response => { + if (response.ok) { + return response.json(); + } + throw new Error('Failed to fetch classes'); + }) + .then(data => { + const classes = data.items || []; + const classItem = classes.find((c: any) => c.id === currentClassId); + + if (classItem) { + // Store the code and description in the lineItem for display + (lineItem as any).class_code = classItem.class_code; + (lineItem as any).class_unit_of_measure = classItem.unit_of_measure; + (lineItem as any).class_description = classItem.description_es || classItem.description_en; + + // Update description fields if description object exists + if ((lineItem as any).description) { + if (classItem.description_es) { + (lineItem as any).description.description_spanish = classItem.description_es; + } + if (classItem.description_en) { + (lineItem as any).description.description_english = classItem.description_en; + } + } + } + }) + .catch(error => { + console.error('Error fetching class data:', error); + }); + } + }); + function handleClassSelect(classItem: any) { lineItem.class_id = classItem.id; // Store the unit of measure and description for display (lineItem as any).class_unit_of_measure = classItem.unit_of_measure; (lineItem as any).class_code = classItem.class_code; (lineItem as any).class_description = classItem.description_es || classItem.description_en; + + // Update description fields if description object exists + if ((lineItem as any).description) { + if (classItem.description_es) { + (lineItem as any).description.description_spanish = classItem.description_es; + } + if (classItem.description_en) { + (lineItem as any).description.description_english = classItem.description_en; + } + } } function handleUnitSelect(unit: any) { From 0782e784ac70db3a419394ac645efe870c3dc817 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Thu, 22 Jan 2026 12:26:57 -0600 Subject: [PATCH 2/3] fix(validators): update part_number_id validation to be optional in item creation --- .../a76/items/imports/temporary/validators/create.py | 10 ++-------- .../invoices/edit/items/fa/item-configuration.svelte | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py b/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py index d6080ac3..7c3ae0d8 100644 --- a/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py +++ b/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py @@ -33,14 +33,8 @@ def validate_create( code="REQUIRED" ) - # 2. Validar part_number_id - if not line.part_number_id: - errors.add_error( - field="part_number_id", - message="Part Number ID es obligatorio", - solution="Selecciona un número de parte válido del catálogo", - code="REQUIRED" - ) + # 2. Validar part_number_id (OPCIONAL - ya no es obligatorio) + # El campo part_number_id ahora es opcional # 3. Validar class_id if not line.class_id: diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-configuration.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-configuration.svelte index 831d2739..e71c6096 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-configuration.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-configuration.svelte @@ -87,7 +87,7 @@
- +
Date: Thu, 22 Jan 2026 12:54:26 -0600 Subject: [PATCH 3/3] fix(validators): add required validations for customs fields in item creation and update feat(item-sheet): implement cancel functionality to restore original item data --- .../imports/temporary/validators/create.py | 18 +++++ .../imports/temporary/validators/update.py | 44 +++++++---- .../edit/items/fa/item-sheet-fa.svelte | 6 +- .../invoices/edit/items/fa/main-data.svelte | 1 + .../edit/items/inv/item-sheet-inv.svelte | 4 +- .../invoices/edit/items/items-tab-form.svelte | 77 ++++++++++++++++++- 6 files changed, 129 insertions(+), 21 deletions(-) diff --git a/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py b/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py index 7c3ae0d8..2507f953 100644 --- a/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py +++ b/backend/api/v1/modules/a76/items/imports/temporary/validators/create.py @@ -109,4 +109,22 @@ def validate_create( message="Description in Spanish es obligatorio", solution="Proporciona una descripción del item en español", code="REQUIRED" + ) + + # 8. Validar customs.origin_country + if not line.customs or not line.customs.origin_country: + errors.add_error( + field="customs.origin_country", + message="País de Origen es obligatorio", + solution="Selecciona el país de origen del item", + code="REQUIRED" + ) + + # 9. Validar customs.fraction_type + if not line.customs or not line.customs.fraction_type: + errors.add_error( + field="customs.fraction_type", + message="Tipo de Tarifa es obligatorio", + solution="Selecciona el tipo de tarifa (GENERAL, PROSEC, ALADI, TLCS)", + code="REQUIRED" ) \ No newline at end of file diff --git a/backend/api/v1/modules/a76/items/imports/temporary/validators/update.py b/backend/api/v1/modules/a76/items/imports/temporary/validators/update.py index 8feaa515..08aed895 100644 --- a/backend/api/v1/modules/a76/items/imports/temporary/validators/update.py +++ b/backend/api/v1/modules/a76/items/imports/temporary/validators/update.py @@ -138,14 +138,25 @@ def validate_update( # 8. Validar datos aduanales si se proporcionan if line.customs: - # Validar país de origen - if line.customs.origin_country is not None and not line.customs.origin_country: - errors.add_error( - field="customs.origin_country", - message="Origin Country no puede estar vacío", - solution="Selecciona el país de origen del item", - code="REQUIRED" - ) + # Validar país de origen (OBLIGATORIO) + if line.customs.origin_country is not None: + if not line.customs.origin_country: + errors.add_error( + field="customs.origin_country", + message="País de Origen es obligatorio", + solution="Selecciona el país de origen del item", + code="REQUIRED" + ) + + # Validar tipo de tarifa (OBLIGATORIO) + if line.customs.fraction_type is not None: + if not line.customs.fraction_type: + errors.add_error( + field="customs.fraction_type", + message="Tipo de Tarifa es obligatorio", + solution="Selecciona el tipo de tarifa (GENERAL, PROSEC, ALADI, TLCS)", + code="REQUIRED" + ) # Validar preferencia arancelaria if line.customs.preference is not None and not line.customs.preference: @@ -184,15 +195,16 @@ def validate_update( code="INVALID_VALUE" ) - # 9. Validar descripción en español si se proporciona + # 9. Validar descripción en español (OBLIGATORIA) if line.description and hasattr(line.description, 'description_spanish'): - if line.description.description_spanish is not None and not line.description.description_spanish: - errors.add_error( - field="description.description_spanish", - message="La descripción en español no puede estar vacía", - solution="Proporciona una descripción del item en español", - code="REQUIRED" - ) + if line.description.description_spanish is not None: + if not line.description.description_spanish.strip(): + errors.add_error( + field="description.description_spanish", + message="Descripción en Español es obligatoria", + solution="Proporciona una descripción del item en español", + code="REQUIRED" + ) # 10. Validar subpartidas si se actualizan if line.fa_data and line.fa_data.is_subitem: diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte index a091ac75..5bf87a1c 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/item-sheet-fa.svelte @@ -23,6 +23,7 @@ editingItem = $bindable(), invoice, onSave, + onCancel, isSaving = false }: { open: boolean; @@ -30,6 +31,7 @@ editingItem: Partial; invoice: Invoice | null; onSave: () => void; + onCancel?: () => void; isSaving?: boolean; } = $props(); @@ -55,7 +57,7 @@

- @@ -164,7 +166,7 @@