From 9b32c019ef976dd5c32d169d57b1a77edb0634a0 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Thu, 22 Jan 2026 09:52:21 -0600 Subject: [PATCH] feat(line_items): update part number and component part number fields to use integers; enhance schemas and services for better data handling --- .../v1/modules/a76/items/line_items/models.py | 8 +- .../modules/a76/items/line_items/schemas.py | 14 +- backend/api/v1/modules/a76/items/service.py | 12 ++ .../edit/items/fa/item-configuration.svelte | 42 ++++- .../invoices/edit/items/fa/main-data.svelte | 71 +++++-- .../edit/items/fa/part-number-dialog.svelte | 175 ++++++++++++++++++ .../invoices/edit/items/items-tab-form.svelte | 123 +++++++++++- .../dashboard/pedimentos/columns.ts | 16 +- .../api-sveltekit/classes/[id]/+server.ts | 87 +++++++++ .../src/routes/api-sveltekit/parts/+server.ts | 91 +++++++++ .../api-sveltekit/parts/[id]/+server.ts | 87 +++++++++ .../units-of-measure/[id]/+server.ts | 87 +++++++++ 12 files changed, 777 insertions(+), 36 deletions(-) create mode 100644 frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte create mode 100644 frontend/src/routes/api-sveltekit/classes/[id]/+server.ts create mode 100644 frontend/src/routes/api-sveltekit/parts/+server.ts create mode 100644 frontend/src/routes/api-sveltekit/parts/[id]/+server.ts create mode 100644 frontend/src/routes/api-sveltekit/units-of-measure/[id]/+server.ts diff --git a/backend/api/v1/modules/a76/items/line_items/models.py b/backend/api/v1/modules/a76/items/line_items/models.py index 6ac7bee0..a7603d11 100644 --- a/backend/api/v1/modules/a76/items/line_items/models.py +++ b/backend/api/v1/modules/a76/items/line_items/models.py @@ -40,11 +40,11 @@ class LineItem(Base, TenantScopedMixin, TimestampMixin): line_number: Mapped[int] = mapped_column(Integer) # LINEAIMPO/LINEAEXPO/LINEA # Part identification - part_number: Mapped[Optional[str]] = mapped_column( - ForeignKey("a76.parts.id") + part_number: Mapped[Optional[int]] = mapped_column( + Integer, ForeignKey("a76.parts.id") ) # NUMPARTE - component_part_number: Mapped[Optional[str]] = mapped_column( - ForeignKey("a76.parts.id") + component_part_number: Mapped[Optional[int]] = mapped_column( + Integer, ForeignKey("a76.parts.id") ) # NUMPARTECOM class_id: Mapped[Optional[int]] = mapped_column( ForeignKey("a76.classes.id") diff --git a/backend/api/v1/modules/a76/items/line_items/schemas.py b/backend/api/v1/modules/a76/items/line_items/schemas.py index 0bea3647..725ff80f 100644 --- a/backend/api/v1/modules/a76/items/line_items/schemas.py +++ b/backend/api/v1/modules/a76/items/line_items/schemas.py @@ -44,12 +44,16 @@ from api.v1.modules.a24.fa.fa_item_lines.dto import ( class LineItemBase(BaseModel): """Base schema for line items""" + model_config = ConfigDict(populate_by_name=True) + line_number: int = Field(..., description="Line number") # Part identification - part_number_id: Optional[int] = Field(None, description="Part number") + part_number_id: Optional[int] = Field( + None, description="Part number", alias="part_number", serialization_alias="part_number_id" + ) component_part_number_id: Optional[int] = Field( - None, description="Component part number" + None, description="Component part number", alias="component_part_number", serialization_alias="component_part_number_id" ) class_id: Optional[int] = Field(None, description="Class code") @@ -257,6 +261,12 @@ class LineItemResponse(LineItemBase): if hasattr(data, key): result[key] = getattr(data, key) + # Map model field names to schema field names for aliased fields + if hasattr(data, "part_number"): + result["part_number_id"] = data.part_number + if hasattr(data, "component_part_number"): + result["component_part_number_id"] = data.component_part_number + # Extract class info if hasattr(data, "class_info") and data.class_info is not None: result["class_code"] = data.class_info.class_code diff --git a/backend/api/v1/modules/a76/items/service.py b/backend/api/v1/modules/a76/items/service.py index 2866fb3d..db983fd5 100644 --- a/backend/api/v1/modules/a76/items/service.py +++ b/backend/api/v1/modules/a76/items/service.py @@ -269,6 +269,12 @@ class ItemService: line_dict["tenant_id"] = tenant_id line_dict["company_id"] = company_id + # Map schema field names to model field names + if "part_number_id" in line_dict: + line_dict["part_number"] = line_dict.pop("part_number_id") + if "component_part_number_id" in line_dict: + line_dict["component_part_number"] = line_dict.pop("component_part_number_id") + # Create line item db_line = LineItem(**line_dict) db.add(db_line) @@ -485,6 +491,12 @@ class ItemService: line_dict["tenant_id"] = tenant_id line_dict["company_id"] = company_id + # Map schema field names to model field names + if "part_number_id" in line_dict: + line_dict["part_number"] = line_dict.pop("part_number_id") + if "component_part_number_id" in line_dict: + line_dict["component_part_number"] = line_dict.pop("component_part_number_id") + db_line = LineItem(**line_dict) db.add(db_line) db.flush() 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 34333daa..831d2739 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 @@ -2,6 +2,9 @@ import * as RadioGroup from '$lib/components/ui/radio-group'; import { Input } from '$lib/components/ui/input'; import { Label } from '$lib/components/ui/label'; + import { Button } from '$lib/components/ui/button'; + import { Folder } from 'lucide-svelte'; + import PartNumberDialog from './part-number-dialog.svelte'; import type { LineItem, LineDescriptions } from '$lib/api/dashboard/a76/items'; let { @@ -12,6 +15,8 @@ descriptions: LineDescriptions; } = $props(); + let showPartDialog = $state(false); + // Initialize fa_data for fixed asset system if (!lineItem.fa_data) { lineItem.fa_data = {}; @@ -29,8 +34,18 @@ if (!lineItem.fa_data) lineItem.fa_data = {}; lineItem.fa_data.contains_subitems = val === 'si'; } + + function handlePartSelect(part: any) { + lineItem.part_number_id = part.id; + // Store part number for display + (lineItem as any).part_number = part.part_number; + (lineItem as any).part_description_es = part.description_spanish; + (lineItem as any).part_description_en = part.description_english; + } + +
@@ -72,11 +87,32 @@
- +
- + (showPartDialog = true)} + /> +
-

ID de número de parte existente en catálogo

+ {#if (lineItem as any).part_description_es} +

{(lineItem as any).part_description_es}

+ {/if} + {#if lineItem.part_number_id} +

ID: {lineItem.part_number_id}

+ {/if}
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 e11174dc..ffa3152c 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 @@ -35,20 +35,27 @@ function handleClassSelect(classItem: any) { lineItem.class_id = classItem.id; - // Store the code in the lineItem for display + // 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; } function handleUnitSelect(unit: any) { lineItem.unit_of_measure = unit.id; + // Store unit code for display + (lineItem as any).unit_code = unit.code; + (lineItem as any).unit_description = unit.description || unit.description_en; } function handleCountrySelect(country: any) { - customs.origin_country = country.mex_key || country.m3_key; + customs.origin_country = country.m3_key || country.mex_key; + (customs as any).origin_country_name = country.description || country.description_en; } function handleFractionSelect(fraction: any) { customs.fraction = fraction.fraction; + (customs as any).fraction_description = fraction.description; } @@ -63,14 +70,16 @@
- +
(showClassDialog = true)} />
- {#if (lineItem as any).class_code} -

Código: {(lineItem as any).class_code}

+ {#if (lineItem as any).class_description} +

{(lineItem as any).class_description}

+ {/if} + {#if lineItem.class_id} +

ID: {lineItem.class_id}

{/if}
@@ -95,7 +107,15 @@
- + (showUnitDialog = true)} + />
+ {#if (lineItem as any).unit_description} +

{(lineItem as any).unit_description}

+ {/if}
@@ -117,9 +140,16 @@
- +
- + (showFractionDialog = true)} + />
+ {#if (customs as any).fraction_description} +

{(customs as any).fraction_description}

+ {/if}
- +
- + (showCountryDialog = true)} + />
+ {#if (customs as any).origin_country_name} +

{(customs as any).origin_country_name}

+ {/if}
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte new file mode 100644 index 00000000..bcb53791 --- /dev/null +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/fa/part-number-dialog.svelte @@ -0,0 +1,175 @@ + + + + + + Seleccionar Número de Parte + + Busca y selecciona un número de parte para la partida + + + +
+
+ + +
+
+ +
+ {#if isSearching} +
+ +
+ {:else} + + + + Número de Parte + Descripción (ES) + Descripción (EN) + Clase + + + + + {#if displayedParts.length === 0} + + + No se encontraron números de parte + + + {:else} + {#each displayedParts as part} + handleSelect(part)}> + {part.part_number} + {part.description_spanish || '-'} + {part.description_english || '-'} + {part.part_class || '-'} + + + + + {/each} + {/if} + + + {/if} +
+ + +

+ Mostrando {displayedParts.length} de {filteredParts.length} resultados +

+
+
+
diff --git a/frontend/src/lib/components/dashboard/invoices/edit/items/items-tab-form.svelte b/frontend/src/lib/components/dashboard/invoices/edit/items/items-tab-form.svelte index 3c4210d3..afda3f78 100644 --- a/frontend/src/lib/components/dashboard/invoices/edit/items/items-tab-form.svelte +++ b/frontend/src/lib/components/dashboard/invoices/edit/items/items-tab-form.svelte @@ -212,9 +212,109 @@ selectedItem = lineData.full_item; // Deep clone and normalize numeric values editingItem = normalizeItemData({ ...lineData.full_item }); + // Enrich with descriptive data + enrichItemData(editingItem); showItemSheet = true; } + // Enrich item with descriptive data for display + async function enrichItemData(item: Partial) { + if (!item.lines || item.lines.length === 0 || !activeCompanyId) return; + + const line = item.lines[0]; + + // Load class data + if (line.class_id) { + try { + const response = await fetch( + `/api-sveltekit/classes/${line.class_id}?company_id=${activeCompanyId}`, + { method: 'GET', headers: { 'Content-Type': 'application/json' } } + ); + if (response.ok) { + const classData = await response.json(); + (line as any).class_code = classData.class_code; + (line as any).class_unit_of_measure = classData.unit_of_measure; + (line as any).class_description = classData.description_es || classData.description_en; + } + } catch (error) { + console.error('Error loading class data:', error); + } + } + + // Load part number data + if (line.part_number_id) { + try { + const response = await fetch( + `/api-sveltekit/parts/${line.part_number_id}?company_id=${activeCompanyId}`, + { method: 'GET', headers: { 'Content-Type': 'application/json' } } + ); + if (response.ok) { + const partData = await response.json(); + (line as any).part_number = partData.part_number; + (line as any).part_description_es = partData.description_spanish; + (line as any).part_description_en = partData.description_english; + } + } catch (error) { + console.error('Error loading part data:', error); + } + } + + // Load unit of measure data + if (line.unit_of_measure) { + try { + const response = await fetch( + `/api-sveltekit/units-of-measure/${line.unit_of_measure}`, + { method: 'GET', headers: { 'Content-Type': 'application/json' } } + ); + if (response.ok) { + const unitData = await response.json(); + (line as any).unit_code = unitData.code; + (line as any).unit_description = unitData.description || unitData.description_en; + } + } catch (error) { + console.error('Error loading unit data:', error); + } + } + + // Load country data (if needed) + if (line.customs?.origin_country) { + try { + const response = await fetch( + `/api-sveltekit/countries?search=${line.customs.origin_country}`, + { method: 'GET', headers: { 'Content-Type': 'application/json' } } + ); + if (response.ok) { + const data = await response.json(); + if (data.items && data.items.length > 0) { + const country = data.items[0]; + (line.customs as any).origin_country_name = country.description || country.description_en; + } + } + } catch (error) { + console.error('Error loading country data:', error); + } + } + + // Load fraction data (if needed) + if (line.customs?.fraction) { + try { + const response = await fetch( + `/api-sveltekit/tariff-fractions?search=${line.customs.fraction}`, + { method: 'GET', headers: { 'Content-Type': 'application/json' } } + ); + if (response.ok) { + const data = await response.json(); + if (data.items && data.items.length > 0) { + const fraction = data.items[0]; + (line.customs as any).fraction_description = fraction.description; + } + } + } catch (error) { + console.error('Error loading fraction data:', error); + } + } + } + // Normalize numeric values from strings to numbers function normalizeItemData(item: Partial): Partial { if (item.lines && item.lines.length > 0) { @@ -300,6 +400,22 @@ cleaned.unit_of_measure = toNumberOrUndefined(cleaned.unit_of_measure); cleaned.alternate_unit = toNumberOrUndefined(cleaned.alternate_unit); + // Remove display-only fields + delete cleaned.class_code; + delete cleaned.class_unit_of_measure; + delete cleaned.class_description; + delete cleaned.part_number; + delete cleaned.part_description_es; + delete cleaned.part_description_en; + delete cleaned.unit_code; + delete cleaned.unit_description; + + // Remove display-only fields from nested objects + if (cleaned.customs) { + delete cleaned.customs.origin_country_name; + delete cleaned.customs.fraction_description; + } + // Remove empty nested objects if (!hasValues(cleaned.financial)) delete cleaned.financial; if (!hasValues(cleaned.quantity)) delete cleaned.quantity; @@ -325,7 +441,7 @@ order: editingItem.order, warehouse: editingItem.warehouse, location: editingItem.location, - lines: editingItem.lines || [] + lines: cleanedLines }); // Verificar si hay errores de validación @@ -384,12 +500,15 @@ isSaving = true; try { + // Clean lines data before sending + const cleanedLines = (editingItem.lines || []).map(cleanLineData); + const response = await itemsApi.update(selectedItem.id, activeCompanyId, { reference_number: editingItem.reference_number, order: editingItem.order, warehouse: editingItem.warehouse, location: editingItem.location, - lines: editingItem.lines || [] + lines: cleanedLines }); // Verificar si hay errores de validación diff --git a/frontend/src/lib/components/dashboard/pedimentos/columns.ts b/frontend/src/lib/components/dashboard/pedimentos/columns.ts index 2bdfbe51..784a23d7 100644 --- a/frontend/src/lib/components/dashboard/pedimentos/columns.ts +++ b/frontend/src/lib/components/dashboard/pedimentos/columns.ts @@ -1,7 +1,6 @@ import type { ColumnDef } from "@tanstack/table-core"; import { renderComponent, renderSnippet } from "$lib/components/ui/data-table/index.js"; import { createRawSnippet } from "svelte"; -import DataTableActions from "./data-table-actions.svelte"; import type { Pedimento } from "$lib/api/dashboard/a76/pedimentos"; /** @@ -201,7 +200,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { return renderSnippet(dateSnippet, { date: formatDate(row.original.pedimento_dates?.payment_date) }); } }, - { + /*{ accessorKey: "pedimento_config_update_rectification.pediment_rectifed_18", header: "Pedimento 18", cell: ({ row }) => { @@ -214,8 +213,8 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(ped18Snippet, { value: row.original.pedimento_config_update_rectification?.pediment_rectifed_18 }); } - }, - { + },*/ + /*{ accessorKey: "pedimento_config_update_rectification.r1", header: "Pedimento R1", cell: ({ row }) => { @@ -228,7 +227,7 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(r1Snippet, { value: row.original.pedimento_config_update_rectification?.r1 }); } - }, + },*/ { accessorKey: "pedimento_validation.electronic_signature", header: "Acuse Electrónico", @@ -375,13 +374,8 @@ export function createColumns(onSuccess?: () => void): ColumnDef[] { }); return renderSnippet(dateSnippet, { date: formatDate(row.original.created_at) }); } - }, - { - id: "actions", - cell: ({ row }) => { - return renderComponent(DataTableActions, { item: row.original, onSuccess }); - } } + // Columna de acciones eliminada - ahora usamos botones en el footer ]; } diff --git a/frontend/src/routes/api-sveltekit/classes/[id]/+server.ts b/frontend/src/routes/api-sveltekit/classes/[id]/+server.ts new file mode 100644 index 00000000..d8de375c --- /dev/null +++ b/frontend/src/routes/api-sveltekit/classes/[id]/+server.ts @@ -0,0 +1,87 @@ +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async ({ cookies, url, params }) => { + const token = cookies.get('access_token'); + const { id } = params; + + // Obtener company_id de la cookie o query params + const companyId = cookies.get('active_company_id') || url.searchParams.get('company_id'); + + if (!companyId) { + return new Response( + JSON.stringify({ error: 'No company selected' }), + { + status: 400, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + // Configurar la URL de la API usando las variables de entorno + let apiUrl = process.env.INTERNAL_API_URL; + if (!apiUrl) { + apiUrl = process.env.VITE_API_URL; + // Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR) + apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend'); + } + + // Normalizar la URL + const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`; + + try { + const fetchUrl = `${baseUrl}v1/a76/classes/${id}?company_id=${companyId}`; + console.log('Fetching class from:', fetchUrl); + + const response = await fetch( + fetchUrl, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + } + ); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Error response from backend:', errorText); + return new Response( + JSON.stringify({ + error: 'Failed to fetch class', + details: errorText + }), + { + status: response.status, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + const data = await response.json(); + return new Response(JSON.stringify(data), { + status: 200, + headers: { + 'Content-Type': 'application/json' + } + }); + } catch (error) { + console.error('Error in class API route:', error); + return new Response( + JSON.stringify({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } +}; diff --git a/frontend/src/routes/api-sveltekit/parts/+server.ts b/frontend/src/routes/api-sveltekit/parts/+server.ts new file mode 100644 index 00000000..1c1cae0e --- /dev/null +++ b/frontend/src/routes/api-sveltekit/parts/+server.ts @@ -0,0 +1,91 @@ +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async ({ cookies, url }) => { + const token = cookies.get('access_token'); + + // Obtener company_id de la cookie + const companyId = cookies.get('active_company_id'); + + if (!companyId) { + return new Response( + JSON.stringify({ error: 'No company selected' }), + { + status: 400, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + // Configurar la URL de la API usando las variables de entorno + let apiUrl = process.env.INTERNAL_API_URL; + if (!apiUrl) { + apiUrl = process.env.VITE_API_URL; + // Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR) + apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend'); + } + + // Normalizar la URL + const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`; + + // Get query parameters and add company_id + const searchParams = new URLSearchParams(url.search); + searchParams.set('company_id', companyId); + const queryString = searchParams.toString(); + + try { + const fetchUrl = `${baseUrl}v1/a76/parts?${queryString}`; + console.log('Fetching parts from:', fetchUrl); + + const response = await fetch( + fetchUrl, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + } + ); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Error response from backend:', errorText); + return new Response( + JSON.stringify({ + error: 'Failed to fetch parts', + details: errorText + }), + { + status: response.status, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + const data = await response.json(); + return new Response(JSON.stringify(data), { + status: 200, + headers: { + 'Content-Type': 'application/json' + } + }); + } catch (error) { + console.error('Error in parts API route:', error); + return new Response( + JSON.stringify({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } +}; diff --git a/frontend/src/routes/api-sveltekit/parts/[id]/+server.ts b/frontend/src/routes/api-sveltekit/parts/[id]/+server.ts new file mode 100644 index 00000000..ba82f40d --- /dev/null +++ b/frontend/src/routes/api-sveltekit/parts/[id]/+server.ts @@ -0,0 +1,87 @@ +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async ({ cookies, url, params }) => { + const token = cookies.get('access_token'); + const { id } = params; + + // Obtener company_id de la cookie o query params + const companyId = cookies.get('active_company_id') || url.searchParams.get('company_id'); + + if (!companyId) { + return new Response( + JSON.stringify({ error: 'No company selected' }), + { + status: 400, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + // Configurar la URL de la API usando las variables de entorno + let apiUrl = process.env.INTERNAL_API_URL; + if (!apiUrl) { + apiUrl = process.env.VITE_API_URL; + // Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR) + apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend'); + } + + // Normalizar la URL + const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`; + + try { + const fetchUrl = `${baseUrl}v1/a76/parts/${id}?company_id=${companyId}`; + console.log('Fetching part from:', fetchUrl); + + const response = await fetch( + fetchUrl, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + } + ); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Error response from backend:', errorText); + return new Response( + JSON.stringify({ + error: 'Failed to fetch part', + details: errorText + }), + { + status: response.status, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + const data = await response.json(); + return new Response(JSON.stringify(data), { + status: 200, + headers: { + 'Content-Type': 'application/json' + } + }); + } catch (error) { + console.error('Error in part API route:', error); + return new Response( + JSON.stringify({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } +}; diff --git a/frontend/src/routes/api-sveltekit/units-of-measure/[id]/+server.ts b/frontend/src/routes/api-sveltekit/units-of-measure/[id]/+server.ts new file mode 100644 index 00000000..110e12c4 --- /dev/null +++ b/frontend/src/routes/api-sveltekit/units-of-measure/[id]/+server.ts @@ -0,0 +1,87 @@ +import type { RequestHandler } from './$types'; + +export const GET: RequestHandler = async ({ cookies, params, url }) => { + const token = cookies.get('access_token'); + const { id } = params; + + // Obtener company_id de la cookie o query params + const companyId = cookies.get('active_company_id') || url.searchParams.get('company_id'); + + if (!companyId) { + return new Response( + JSON.stringify({ error: 'No company selected' }), + { + status: 400, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + // Configurar la URL de la API usando las variables de entorno + let apiUrl = process.env.INTERNAL_API_URL; + if (!apiUrl) { + apiUrl = process.env.VITE_API_URL; + // Reemplazar 'localhost' con 'backend' para llamadas desde el servidor (SSR) + apiUrl = apiUrl?.replace('localhost', 'backend').replace('127.0.0.1', 'backend'); + } + + // Normalizar la URL + const baseUrl = apiUrl?.endsWith('/') ? apiUrl : `${apiUrl}/`; + + try { + const fetchUrl = `${baseUrl}v1/a76/units-of-measure/${id}?company_id=${companyId}`; + console.log('Fetching unit of measure from:', fetchUrl); + + const response = await fetch( + fetchUrl, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}` + } + } + ); + + if (!response.ok) { + const errorText = await response.text(); + console.error('Error response from backend:', errorText); + return new Response( + JSON.stringify({ + error: 'Failed to fetch unit of measure', + details: errorText + }), + { + status: response.status, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } + + const data = await response.json(); + return new Response(JSON.stringify(data), { + status: 200, + headers: { + 'Content-Type': 'application/json' + } + }); + } catch (error) { + console.error('Error in unit of measure API route:', error); + return new Response( + JSON.stringify({ + error: 'Internal server error', + message: error instanceof Error ? error.message : 'Unknown error' + }), + { + status: 500, + headers: { + 'Content-Type': 'application/json' + } + } + ); + } +};