diff --git a/backend/api/v1/modules/a76/general_catalogs/equivalencies/dto.py b/backend/api/v1/modules/a76/general_catalogs/equivalencies/dto.py index f2017259..a4088acd 100644 --- a/backend/api/v1/modules/a76/general_catalogs/equivalencies/dto.py +++ b/backend/api/v1/modules/a76/general_catalogs/equivalencies/dto.py @@ -1,39 +1,15 @@ -from typing import Optional, List +from typing import Optional +from decimal import Decimal + from pydantic import BaseModel, Field, ConfigDict -# Equivalency Item DTOs - - -class EquivalencyItemBase(BaseModel): - original_field: str = Field(..., max_length=100, - description="Original Field (Unit of Measure)") - external_field: str = Field(..., max_length=100, - description="External Field") - - -class EquivalencyItemCreate(EquivalencyItemBase): - pass - - -class EquivalencyItemUpdate(BaseModel): - original_field: Optional[str] = Field(None, max_length=100) - external_field: Optional[str] = Field(None, max_length=100) - - -class EquivalencyItemResponse(EquivalencyItemBase): - id: int - equivalency_id: int - - model_config = ConfigDict(from_attributes=True) - -# Equivalency DTOs +# Equivalency (parent) DTOs class EquivalencyBase(BaseModel): - fraccion_mex: str = Field(..., max_length=10, description="Fraccion MX (Identifier)") - fraccion_us: str = Field(..., max_length=100, description="Fraccion US (External Field)") - description: Optional[str] = Field( - None, max_length=200, description="Description") + # Agrupa múltiples destinos para un mismo origen. + identifier: str = Field(..., max_length=10, description="From unit code") + description: Optional[str] = Field(None, max_length=200, description="Description (optional)") class EquivalencyCreate(EquivalencyBase): @@ -41,8 +17,7 @@ class EquivalencyCreate(EquivalencyBase): class EquivalencyUpdate(BaseModel): - fraccion_mex: Optional[str] = Field(None, max_length=10) - fraccion_us: Optional[str] = Field(None, max_length=100) + identifier: Optional[str] = Field(None, max_length=10) description: Optional[str] = Field(None, max_length=200) @@ -53,4 +28,30 @@ class EquivalencyResponse(EquivalencyBase): model_config = ConfigDict(from_attributes=True) + +# Equivalency Item DTOs (catálogo por fila) + + +class EquivalencyItemBase(BaseModel): + original_field: str = Field(..., max_length=100, description="Original unit code (from)") + external_field: str = Field(..., max_length=100, description="External unit code (to)") + conversion_factor: Optional[Decimal] = Field(None, description="Conversion factor") + + +class EquivalencyItemCreate(EquivalencyItemBase): + conversion_factor: Decimal = Field(..., description="Conversion factor") + + +class EquivalencyItemUpdate(BaseModel): + original_field: Optional[str] = Field(None, max_length=100) + external_field: Optional[str] = Field(None, max_length=100) + conversion_factor: Optional[Decimal] = None + + +class EquivalencyItemResponse(EquivalencyItemBase): + id: int + equivalency_id: int + tenant_id: int + company_id: int + model_config = ConfigDict(from_attributes=True) diff --git a/backend/api/v1/modules/a76/general_catalogs/equivalencies/models.py b/backend/api/v1/modules/a76/general_catalogs/equivalencies/models.py index 5211bc10..87de137c 100644 --- a/backend/api/v1/modules/a76/general_catalogs/equivalencies/models.py +++ b/backend/api/v1/modules/a76/general_catalogs/equivalencies/models.py @@ -1,5 +1,6 @@ from typing import Optional, List -from sqlalchemy import Integer, String, ForeignKey, UniqueConstraint, ForeignKeyConstraint +from decimal import Decimal +from sqlalchemy import Integer, String, ForeignKey, UniqueConstraint, ForeignKeyConstraint, Numeric from sqlalchemy.orm import Mapped, mapped_column, relationship from api.v1.common.base_models import TenantScopedMixin, TimestampMixin from core.database import Base @@ -50,6 +51,10 @@ class EquivalencyItem(Base, TenantScopedMixin, TimestampMixin): external_field: Mapped[str] = mapped_column(String(100), nullable=False) + conversion_factor: Mapped[Optional[Decimal]] = mapped_column( + Numeric(13, 6), nullable=True + ) + equivalency: Mapped["Equivalency"] = relationship(back_populates="items") unit_of_measure: Mapped["UnitOfMeasure"] = relationship() diff --git a/backend/api/v1/modules/a76/general_catalogs/equivalencies/routes.py b/backend/api/v1/modules/a76/general_catalogs/equivalencies/routes.py index d7c1c42f..d5f00b96 100644 --- a/backend/api/v1/modules/a76/general_catalogs/equivalencies/routes.py +++ b/backend/api/v1/modules/a76/general_catalogs/equivalencies/routes.py @@ -38,6 +38,7 @@ item_crud = TenantCRUDRoutes( tags=["Equivalency Items"], resource_name="EquivalencyItem", enable_list=True, + enable_filters=True, ) # Custom endpoint for creating items nested under equivalency diff --git a/backend/api/v1/modules/a76/general_catalogs/equivalencies/service.py b/backend/api/v1/modules/a76/general_catalogs/equivalencies/service.py index 3580ef22..f55b2bf8 100644 --- a/backend/api/v1/modules/a76/general_catalogs/equivalencies/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/equivalencies/service.py @@ -1,6 +1,5 @@ from typing import List, Optional, Tuple, Dict, Any -from sqlalchemy.orm import Session, joinedload -from sqlalchemy import select +from sqlalchemy.orm import Session from sqlalchemy.exc import IntegrityError from fastapi import HTTPException @@ -20,27 +19,26 @@ class EquivalencyService: ) -> Tuple[List[Equivalency], int]: query = db.query(Equivalency).filter( Equivalency.tenant_id == tenant_id, - Equivalency.company_id == company_id - ).options(joinedload(Equivalency.items)) + Equivalency.company_id == company_id, + ) if filters: - if 'fraccion_mex' in filters: - query = query.filter(Equivalency.identifier.ilike(f"%{filters['fraccion_mex']}%")) - if 'description' in filters: - query = query.filter(Equivalency.description.ilike(f"%{filters['description']}%")) + # Soporta filtros de UI por nombre de parámetro. + if "from_unit_code" in filters: + query = query.filter( + Equivalency.identifier.ilike(f"%{filters['from_unit_code']}%") + ) + if "identifier" in filters: + query = query.filter( + Equivalency.identifier.ilike(f"%{filters['identifier']}%") + ) + if "description" in filters: + query = query.filter( + Equivalency.description.ilike(f"%{filters['description']}%") + ) total = query.count() items = query.offset(skip).limit(limit).all() - - # Map internal fields to DTO fields - for item in items: - item.fraccion_mex = item.identifier - # Try to find the first item to get fraccion_us - if item.items: - item.fraccion_us = item.items[0].external_field - else: - item.fraccion_us = "" - return items, total @staticmethod @@ -54,15 +52,8 @@ class EquivalencyService: Equivalency.id == id, Equivalency.tenant_id == tenant_id, Equivalency.company_id == company_id - ).options(joinedload(Equivalency.items)).first() - - if item: - item.fraccion_mex = item.identifier - if item.items: - item.fraccion_us = item.items[0].external_field - else: - item.fraccion_us = "" - + ).first() + return item @staticmethod @@ -73,53 +64,27 @@ class EquivalencyService: company_id: int ) -> Equivalency: try: - # Create Parent db_obj = Equivalency( - identifier=data.fraccion_mex, + identifier=data.identifier, description=data.description, tenant_id=tenant_id, - company_id=company_id + company_id=company_id, ) db.add(db_obj) - db.flush() # Flush to get ID - - # Create Child Item (mapping fraccion_mex -> original_field, fraccion_us -> external_field) - item = EquivalencyItem( - equivalency_id=db_obj.id, - original_field=data.fraccion_mex, # Must exist in units_of_measure - external_field=data.fraccion_us, - tenant_id=tenant_id, - company_id=company_id - ) - db.add(item) - db.commit() db.refresh(db_obj) - - # Map for response - db_obj.fraccion_mex = db_obj.identifier - db_obj.fraccion_us = item.external_field - return db_obj except IntegrityError as e: db.rollback() - error_msg = str(e.orig) if hasattr(e, 'orig') else str(e) - print(f"IntegrityError in create: {error_msg}") - - if "units_of_measure" in error_msg: - raise HTTPException( - status_code=400, - detail=f"La Fracción MX '{data.fraccion_mex}' no es válida. Debe existir en el catálogo de Unidades de Medida." - ) + error_msg = str(e.orig) if hasattr(e, "orig") else str(e) if "uq_equivalency_identifier" in error_msg: raise HTTPException( - status_code=400, - detail=f"Ya existe una equivalencia para la Fracción MX '{data.fraccion_mex}'." - ) - raise HTTPException(status_code=400, detail=f"Error al guardar: {error_msg}") + status_code=400, + detail=f"Ya existe un registro para el origen '{data.identifier}'.", + ) from e + raise HTTPException(status_code=400, detail=f"Error al guardar: {error_msg}") from e except Exception as e: db.rollback() - print(f"Error in create: {str(e)}") raise e @staticmethod @@ -135,58 +100,19 @@ class EquivalencyService: return None try: - if data.fraccion_mex: - db_obj.identifier = data.fraccion_mex - if data.description: - db_obj.description = data.description - - # Update Item - item = None - if db_obj.items: - item = db_obj.items[0] - - if item: - if data.fraccion_us: - item.external_field = data.fraccion_us - if data.fraccion_mex: - item.original_field = data.fraccion_mex - else: - # Create if missing - if data.fraccion_us or data.fraccion_mex: - item = EquivalencyItem( - equivalency_id=db_obj.id, - original_field=data.fraccion_mex or db_obj.identifier, - external_field=data.fraccion_us or "", - tenant_id=tenant_id, - company_id=company_id - ) - db.add(item) + update_dict = data.model_dump(exclude_unset=True) + for key, value in update_dict.items(): + setattr(db_obj, key, value) db.commit() db.refresh(db_obj) - - # Map for response - db_obj.fraccion_mex = db_obj.identifier - if db_obj.items: - db_obj.fraccion_us = db_obj.items[0].external_field - else: - db_obj.fraccion_us = "" - return db_obj except IntegrityError as e: db.rollback() - error_msg = str(e.orig) if hasattr(e, 'orig') else str(e) - print(f"IntegrityError in update: {error_msg}") - - if "units_of_measure" in error_msg: - raise HTTPException( - status_code=400, - detail=f"La Fracción MX '{data.fraccion_mex or db_obj.identifier}' no es válida. Debe existir en el catálogo de Unidades de Medida." - ) - raise HTTPException(status_code=400, detail=f"Error al actualizar: {error_msg}") + error_msg = str(e.orig) if hasattr(e, "orig") else str(e) + raise HTTPException(status_code=400, detail=f"Error al actualizar: {error_msg}") from e except Exception as e: db.rollback() - print(f"Error in update: {str(e)}") raise e @staticmethod @@ -216,8 +142,21 @@ class EquivalencyItemService: ) -> Tuple[List[EquivalencyItem], int]: query = db.query(EquivalencyItem).filter( EquivalencyItem.tenant_id == tenant_id, - EquivalencyItem.company_id == company_id + EquivalencyItem.company_id == company_id, ) + + if filters: + if "from_unit_code" in filters: + query = query.filter( + EquivalencyItem.original_field.ilike( + f"%{filters['from_unit_code']}%" + ) + ) + if "to_unit_code" in filters: + query = query.filter( + EquivalencyItem.external_field.ilike(f"%{filters['to_unit_code']}%") + ) + total = query.count() items = query.offset(skip).limit(limit).all() return items, total @@ -242,15 +181,51 @@ class EquivalencyItemService: tenant_id: int, company_id: int ) -> EquivalencyItem: - db_obj = EquivalencyItem( - **data.model_dump(), - tenant_id=tenant_id, - company_id=company_id - ) - db.add(db_obj) - db.commit() - db.refresh(db_obj) - return db_obj + try: + # Equivalency padre agrupado por `from_unit_code` (original_field) + parent = ( + db.query(Equivalency) + .filter( + Equivalency.tenant_id == tenant_id, + Equivalency.company_id == company_id, + Equivalency.identifier == data.original_field, + ) + .first() + ) + + if not parent: + parent = Equivalency( + identifier=data.original_field, + description=None, + tenant_id=tenant_id, + company_id=company_id, + ) + db.add(parent) + db.flush() # obtener id sin commit + + db_obj = EquivalencyItem( + equivalency_id=parent.id, + original_field=data.original_field, + external_field=data.external_field, + conversion_factor=data.conversion_factor, + tenant_id=tenant_id, + company_id=company_id, + ) + db.add(db_obj) + db.commit() + db.refresh(db_obj) + return db_obj + except IntegrityError as e: + db.rollback() + error_msg = str(e.orig) if hasattr(e, "orig") else str(e) + if "units_of_measure" in error_msg: + raise HTTPException( + status_code=400, + detail=( + "Verifica que las unidades existan en el catálogo de U.M." + ), + ) from e + raise HTTPException(status_code=400, detail=f"Error al guardar: {error_msg}") from e @staticmethod def create_nested( @@ -264,6 +239,7 @@ class EquivalencyItemService: equivalency_id=equivalency_id, original_field=data.original_field, external_field=data.external_field, + conversion_factor=data.conversion_factor, tenant_id=tenant_id, company_id=company_id ) @@ -283,13 +259,47 @@ class EquivalencyItemService: db_obj = EquivalencyItemService.get_by_id(db, id, tenant_id, company_id) if not db_obj: return None - - for key, value in data.model_dump(exclude_unset=True).items(): - setattr(db_obj, key, value) - - db.commit() - db.refresh(db_obj) - return db_obj + + update_dict = data.model_dump(exclude_unset=True) + try: + new_original = update_dict.get("original_field") + if new_original and new_original != db_obj.original_field: + # Re-asignar al padre del nuevo `from_unit_code` + parent = ( + db.query(Equivalency) + .filter( + Equivalency.tenant_id == tenant_id, + Equivalency.company_id == company_id, + Equivalency.identifier == new_original, + ) + .first() + ) + if not parent: + parent = Equivalency( + identifier=new_original, + description=None, + tenant_id=tenant_id, + company_id=company_id, + ) + db.add(parent) + db.flush() + + db_obj.equivalency_id = parent.id + db_obj.original_field = new_original + + # Aplicar resto de cambios + for key, value in update_dict.items(): + if key == "original_field": + continue # ya aplicado arriba (y con posible re-parenting) + setattr(db_obj, key, value) + + db.commit() + db.refresh(db_obj) + return db_obj + except IntegrityError as e: + db.rollback() + error_msg = str(e.orig) if hasattr(e, "orig") else str(e) + raise HTTPException(status_code=400, detail=f"Error al actualizar: {error_msg}") from e @staticmethod def delete( diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/equivalencies.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/equivalencies.ts index 0b6c70c3..74788989 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/equivalencies.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/equivalencies.ts @@ -1,43 +1,44 @@ import { api } from '$lib/api'; import type { ApiResponse } from '$lib/api'; -export interface Equivalency { +export interface EquivalencyItem { id: number; - fraccion_mex: string; - fraccion_us: string; - description?: string; + original_field: string; // from_unit_code + external_field: string; // to_unit_code + conversion_factor: number | null; + equivalency_id: number; tenant_id: number; company_id: number; created_at: string; updated_at?: string; } -export interface EquivalencyCreate { - fraccion_mex: string; - fraccion_us: string; - description?: string; +export interface EquivalencyItemCreate { + original_field: string; + external_field: string; + conversion_factor: number; } -export interface EquivalencyUpdate { - fraccion_mex?: string; - fraccion_us?: string; - description?: string; +export interface EquivalencyItemUpdate { + original_field?: string; + external_field?: string; + conversion_factor?: number | null; } -export interface EquivalencyListResponse { - items: Equivalency[]; +export interface EquivalencyItemListResponse { + items: EquivalencyItem[]; total: number; page: number; page_size: number; pages: number; } -export async function getEquivalencies( +export async function getEquivalencyItems( page: number = 1, pageSize: number = 50, companyId: number, filters: Record = {} -): Promise> { +) : Promise> { const params = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), @@ -45,28 +46,31 @@ export async function getEquivalencies( ...filters }); - return await api.get(`/v1/a76/equivalencies/?${params.toString()}`); + return await api.get(`/v1/a76/equivalencies/items/?${params.toString()}`); } -export async function getEquivalency(id: number, companyId: number): Promise> { - return await api.get(`/v1/a76/equivalencies/${id}/?company_id=${companyId}`); -} - -export async function createEquivalency( - data: EquivalencyCreate, +export async function getEquivalencyItem( + id: number, companyId: number -): Promise> { - return await api.post(`/v1/a76/equivalencies/?company_id=${companyId}`, data); +): Promise> { + return await api.get(`/v1/a76/equivalencies/items/${id}/?company_id=${companyId}`); } -export async function updateEquivalency( - id: number, - data: EquivalencyUpdate, +export async function createEquivalencyItem( + data: EquivalencyItemCreate, companyId: number -): Promise> { - return await api.put(`/v1/a76/equivalencies/${id}/?company_id=${companyId}`, data); +): Promise> { + return await api.post(`/v1/a76/equivalencies/items/?company_id=${companyId}`, data); } -export async function deleteEquivalency(id: number, companyId: number): Promise> { - return await api.delete(`/v1/a76/equivalencies/${id}/?company_id=${companyId}`); +export async function updateEquivalencyItem( + id: number, + data: EquivalencyItemUpdate, + companyId: number +): Promise> { + return await api.put(`/v1/a76/equivalencies/items/${id}/?company_id=${companyId}`, data); +} + +export async function deleteEquivalencyItem(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/equivalencies/items/${id}?company_id=${companyId}`); } diff --git a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/columns.ts index f4a92c75..61d243e7 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/columns.ts +++ b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/columns.ts @@ -1,25 +1,25 @@ import type { ColumnDef } from '@tanstack/table-core'; -import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; +import type { EquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; import { renderComponent } from '$lib/components/ui/data-table'; import DataTableActions from './data-table-actions.svelte'; import { Header } from '$lib/components/ui/alert-dialog'; -export function createColumns(onSuccess?: () => void): ColumnDef[] { +export function createColumns(onSuccess?: () => void): ColumnDef[] { return [ { - accessorKey: 'fraccion_mex', - header: 'Fracción MX', - cell: ({ row }) => row.original.fraccion_mex || 'N/A' + accessorKey: 'original_field', + header: 'Desde código', + cell: ({ row }) => row.original.original_field || 'N/A' }, { - accessorKey: 'fraccion_us', - header: 'Fracción US', - cell: ({ row }) => row.original.fraccion_us || 'N/A' + accessorKey: 'external_field', + header: 'Hacia código', + cell: ({ row }) => row.original.external_field || 'N/A' }, { - accessorKey: 'description', - header: 'Descripción', - cell: ({ row }) => row.original.description || 'N/A' + accessorKey: 'conversion_factor', + header: 'Factor de conversión', + cell: ({ row }) => (row.original.conversion_factor ?? 0).toString() }, { id: 'actions', diff --git a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/create-edit-dialog.svelte index ae9a0540..f445acab 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/create-edit-dialog.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/create-edit-dialog.svelte @@ -4,12 +4,13 @@ import { Input } from '$lib/components/ui/input'; import { Label } from '$lib/components/ui/label'; import { companyStore } from '$lib/stores/company.svelte'; + import UnitMeasureSelectorDialog from '$lib/components/dashboard/goods/modales/unit-measure-dialog.svelte'; + import { FolderSearch, Scale } from 'lucide-svelte'; import { - createEquivalency, - updateEquivalency, - type Equivalency + createEquivalencyItem, + updateEquivalencyItem, + type EquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; - import { obtenerAtajosFormularioEquivalencias } from '$lib/config/shortcuts/dashboard/general_catalogs/equivalencies/edit'; let { open = $bindable(false), @@ -17,46 +18,50 @@ onSuccess }: { open: boolean; - item?: Equivalency | null; + item?: EquivalencyItem | null; onSuccess?: () => void; } = $props(); - // Atajos - const isEdit = $derived(!!item); const title = $derived( - isEdit ? `Editar Equivalencia ${item?.fraccion_mex || ''}` : 'Nueva Equivalencia' + isEdit + ? `Editar Equivalencia ${item?.original_field || ''} → ${item?.external_field || ''}` + : 'Nueva Equivalencia' ); - // Estado del formulario let formData = $state({ - fraccion_mex: '', - fraccion_us: '', - description: '' + original_field: '', + external_field: '', + conversion_factor: '' }); let loading = $state(false); let error = $state(null); - // Cargar datos + let showFromUomModal = $state(false); + let showToUomModal = $state(false); + $effect(() => { - if (open) { - if (item) { - formData = { - fraccion_mex: item.fraccion_mex || '', - fraccion_us: item.fraccion_us || '', - description: item.description || '' - }; - } else { - // Reset - formData = { - fraccion_mex: '', - fraccion_us: '', - description: '' - }; - } - error = null; + if (!open) return; + + if (item) { + formData = { + original_field: item.original_field || '', + external_field: item.external_field || '', + conversion_factor: + item.conversion_factor !== null && item.conversion_factor !== undefined + ? item.conversion_factor.toString() + : '' + }; + } else { + formData = { + original_field: '', + external_field: '', + conversion_factor: '' + }; } + + error = null; }); async function handleSubmit() { @@ -70,15 +75,24 @@ error = null; try { - let response; - if (isEdit && item) { - response = await updateEquivalency(item.id, formData, companyId); - } else { - response = await createEquivalency(formData, companyId); - } + if (!formData.original_field.trim()) throw new Error('Código origen requerido'); + if (!formData.external_field.trim()) throw new Error('Código destino requerido'); + if (formData.conversion_factor === '' || formData.conversion_factor === null) + throw new Error('Factor de conversión requerido'); - if (response.error) { - throw new Error(response.error); + const factor = parseFloat(formData.conversion_factor); + if (isNaN(factor)) throw new Error('El factor de conversión debe ser un número válido'); + + const dataToSend = { + original_field: formData.original_field.trim(), + external_field: formData.external_field.trim(), + conversion_factor: factor + }; + + if (isEdit && item) { + await updateEquivalencyItem(item.id, dataToSend, companyId); + } else { + await createEquivalencyItem(dataToSend, companyId); } open = false; @@ -111,46 +125,104 @@ {/if} -
- - -
+
+
+ +
+
+ + (showFromUomModal = true)} + class="cursor-pointer pl-9 font-mono" + placeholder="Seleccione..." + disabled={loading} + required + /> +
+ +
+
-
- - -
+
+ +
+
+ + (showToUomModal = true)} + class="cursor-pointer pl-9 font-mono" + placeholder="Seleccione..." + disabled={loading} + required + /> +
+ +
+
-
- - +
+ + +
+ + { + formData.original_field = u.code; + }} +/> + + { + formData.external_field = u.code; + }} +/> diff --git a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-table-actions.svelte index 8128f9ee..d2d7e9d9 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/equivalencies/data-table-actions.svelte @@ -2,8 +2,8 @@ import { Button } from '$lib/components/ui/button'; import * as DropdownMenu from '$lib/components/ui/dropdown-menu'; import { EllipsisVertical, Pencil, Trash2, LoaderCircle } from 'lucide-svelte'; - import type { Equivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; - import { deleteEquivalency } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; + import type { EquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; + import { deleteEquivalencyItem } from '$lib/api/dashboard/a76/general_catalogs/equivalencies'; import { companyStore } from '$lib/stores/company.svelte'; import CreateEditDialog from './create-edit-dialog.svelte'; @@ -11,14 +11,14 @@ item, onSuccess }: { - item: Equivalency; + item: EquivalencyItem; onSuccess?: () => void; } = $props(); let loading = $state(false); let error = $state(null); let dialogOpen = $state(false); - let selectedItem = $state(null); + let selectedItem = $state(null); async function handleDelete() { if (!confirm('¿Está seguro de eliminar esta equivalencia?')) { @@ -33,7 +33,7 @@ loading = true; try { - const response = await deleteEquivalency(item.id, companyId); + const response = await deleteEquivalencyItem(item.id, companyId); if (response.error) { throw new Error(response.error); diff --git a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.server.ts index b1b1a5c7..66175ed1 100644 --- a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.server.ts @@ -24,11 +24,11 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { } const filters: Record = {}; - const identifier = url.searchParams.get('identifier'); - const description = url.searchParams.get('description'); + const fromUnitCode = url.searchParams.get('from_unit_code'); + const toUnitCode = url.searchParams.get('to_unit_code'); - if (identifier) filters.identifier = identifier; - if (description) filters.description = description; + if (fromUnitCode) filters.from_unit_code = fromUnitCode; + if (toUnitCode) filters.to_unit_code = toUnitCode; const queryParams = new URLSearchParams({ page: page.toString(), @@ -37,7 +37,7 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { ...filters }); - const response = await authenticatedFetch(`v1/a76/equivalencies/?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); + const response = await authenticatedFetch(`v1/a76/equivalencies/items/?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); if (!response.ok) { return { error: 'Failed to load', equivalencies: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte index af77bff5..72cae2e0 100644 --- a/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/equivalencies/+page.svelte @@ -26,8 +26,8 @@ ); // Filtros - let searchFraccion = $state($page.url.searchParams.get('fraccion_mex') || ''); - let searchDesc = $state($page.url.searchParams.get('description') || ''); + let searchFrom = $state($page.url.searchParams.get('from_unit_code') || ''); + let searchTo = $state($page.url.searchParams.get('to_unit_code') || ''); let timeout: ReturnType; function handleSearch() { @@ -35,11 +35,11 @@ clearTimeout(timeout); timeout = setTimeout(() => { const url = new URL($page.url); - if (searchFraccion) url.searchParams.set('fraccion_mex', searchFraccion); - else url.searchParams.delete('fraccion_mex'); + if (searchFrom) url.searchParams.set('from_unit_code', searchFrom); + else url.searchParams.delete('from_unit_code'); - if (searchDesc) url.searchParams.set('description', searchDesc); - else url.searchParams.delete('description'); + if (searchTo) url.searchParams.set('to_unit_code', searchTo); + else url.searchParams.delete('to_unit_code'); url.searchParams.set('page', '1'); goto(url, { keepFocus: true, noScroll: true }); @@ -67,15 +67,15 @@