diff --git a/backend/api/v1/modules/a76/general_catalogs/classification_concepts/service.py b/backend/api/v1/modules/a76/general_catalogs/classification_concepts/service.py index 33245a6d..785403d7 100644 --- a/backend/api/v1/modules/a76/general_catalogs/classification_concepts/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/classification_concepts/service.py @@ -1,10 +1,15 @@ from typing import List, Optional, Tuple, Dict, Any from sqlalchemy.orm import Session from sqlalchemy import select +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException +import logging from .models import ClassificationConcept from .dto import ClassificationConceptCreate, ClassificationConceptUpdate +logger = logging.getLogger(__name__) + class ClassificationConceptService: @staticmethod @@ -76,6 +81,14 @@ class ClassificationConceptService: if not db_obj: return False - db.delete(db_obj) - db.commit() - return True + try: + db.delete(db_obj) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"Error de integridad al eliminar clasificación de concepto {id}: {str(e)}") + raise HTTPException( + status_code=400, + detail="No se puede eliminar esta clasificación porque tiene registros relacionados (pedimentos, facturas, etc.). Primero debe eliminar o reasignar esos registros." + ) diff --git a/backend/api/v1/modules/a76/general_catalogs/company/routes.py b/backend/api/v1/modules/a76/general_catalogs/company/routes.py index 8a948f6b..294ff490 100644 --- a/backend/api/v1/modules/a76/general_catalogs/company/routes.py +++ b/backend/api/v1/modules/a76/general_catalogs/company/routes.py @@ -40,6 +40,55 @@ async def create_company( return service.create_company_manually(data, tenant_id=tenant_id) +@router.get( + "", # GET /api/v1/a76/company with pagination + response_model=dict, + summary="Get companies with pagination", +) +async def list_companies( + page: int = 1, + page_size: int = 50, + name: Optional[str] = None, + rfc: Optional[str] = None, + db: Session = Depends(get_core_db), + current_user: dict = Depends(get_current_user), +): + """Get paginated list of companies for current tenant with optional filters""" + tenant_id = current_user.get("tenant_id") + if not tenant_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Tenant ID not found in user data", + ) + + skip = (page - 1) * page_size + filters = {} + if name: + filters["name"] = name + if rfc: + filters["rfc"] = rfc + + service = CompanyService(db) + items, total = service.get_all( + db, + tenant_id, + company_id=0, # Not used for companies + skip=skip, + limit=page_size, + filters=filters if filters else None + ) + + total_pages = (total + page_size - 1) // page_size + + return { + "items": [CompanyResponseDTO.model_validate(item) for item in items], + "total": total, + "page": page, + "page_size": page_size, + "pages": total_pages, + } + + @router.get( "/my-companies", response_model=List[CompanyResponseDTO], @@ -189,16 +238,89 @@ async def get_program_info( "prosec_authorization": company.prosec_authorization, } -base_router = TenantCRUDRoutes( - service=CompanyService, - create_schema=None, - update_schema=CompanyUpdateDTO, - response_schema=CompanyResponseDTO, - prefix="", - tags=[], - id_name="id", - enable_list=True, - enable_filters=True, -).router -router.include_router(base_router) \ No newline at end of file +@router.get( + "/{company_id}", + response_model=CompanyResponseDTO, + summary="Get company by ID", +) +async def get_company( + company_id: int, + db: Session = Depends(get_core_db), + current_user: dict = Depends(get_current_user), +): + """Get a specific company by ID""" + tenant_id = current_user.get("tenant_id") + if not tenant_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Tenant ID not found in user data", + ) + + company = CompanyService.get_by_id(db, company_id, tenant_id, 0) + if not company: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Company not found", + ) + + return CompanyResponseDTO.model_validate(company) + + +@router.put( + "/{company_id}", + response_model=CompanyResponseDTO, + summary="Update company", +) +async def update_company( + company_id: int, + data: CompanyUpdateDTO, + db: Session = Depends(get_core_db), + current_user: dict = Depends(get_current_user), +): + """Update a company""" + tenant_id = current_user.get("tenant_id") + if not tenant_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Tenant ID not found in user data", + ) + + updated_company = CompanyService.update( + db, company_id, tenant_id, 0, data + ) + if not updated_company: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Company not found", + ) + + return CompanyResponseDTO.model_validate(updated_company) + + +@router.delete( + "/{company_id}", + status_code=status.HTTP_204_NO_CONTENT, + summary="Delete company", +) +async def delete_company( + company_id: int, + db: Session = Depends(get_core_db), + current_user: dict = Depends(get_current_user), +): + """Delete a company""" + tenant_id = current_user.get("tenant_id") + if not tenant_id: + raise HTTPException( + status_code=status.HTTP_400_BAD_REQUEST, + detail="Tenant ID not found in user data", + ) + + success = CompanyService.delete(db, company_id, tenant_id, 0) + if not success: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Company not found", + ) + + return None \ No newline at end of file diff --git a/backend/api/v1/modules/a76/general_catalogs/company/service.py b/backend/api/v1/modules/a76/general_catalogs/company/service.py index f3c03827..63835cd1 100644 --- a/backend/api/v1/modules/a76/general_catalogs/company/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/company/service.py @@ -137,10 +137,20 @@ class CompanyService: db.delete(company) db.commit() return True + except IntegrityError as e: + db.rollback() + logger.error(f"IntegrityError deleting company {company_id}: {str(e)}") + # Check if it's a foreign key constraint + if "foreign key constraint" in str(e).lower(): + raise HTTPException( + status_code=400, + detail="No se puede eliminar la empresa porque tiene registros relacionados (facturas, conceptos, etc.)" + ) + raise HTTPException(status_code=400, detail="Error al eliminar la empresa") except Exception as e: db.rollback() logger.error(f"Error deleting company {company_id}: {str(e)}") - raise HTTPException(status_code=500, detail="Error deleting company") + raise HTTPException(status_code=500, detail="Error al eliminar la empresa") # Custom methods def get_companies_by_tenant(self, tenant_id: int) -> List[Company]: diff --git a/backend/api/v1/modules/a76/general_catalogs/concepts/service.py b/backend/api/v1/modules/a76/general_catalogs/concepts/service.py index bba0de63..b0117771 100644 --- a/backend/api/v1/modules/a76/general_catalogs/concepts/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/concepts/service.py @@ -1,10 +1,16 @@ from typing import List, Optional, Tuple, Dict, Any +import logging + from sqlalchemy.orm import Session from sqlalchemy import select +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException from .models import Concept from .dto import ConceptCreate, ConceptUpdate +logger = logging.getLogger(__name__) + class ConceptService: @staticmethod @@ -74,6 +80,20 @@ class ConceptService: if not db_obj: return False - db.delete(db_obj) - db.commit() - return True + try: + db.delete(db_obj) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"IntegrityError deleting concept {id}: {str(e)}") + if "foreign key constraint" in str(e).lower(): + raise HTTPException( + status_code=400, + detail="No se puede eliminar el concepto porque tiene registros relacionados" + ) + raise HTTPException(status_code=400, detail="Error al eliminar el concepto") + except Exception as e: + db.rollback() + logger.error(f"Error deleting concept {id}: {str(e)}") + raise HTTPException(status_code=500, detail="Error al eliminar el concepto") diff --git a/backend/api/v1/modules/a76/general_catalogs/customs_broker_concepts/service.py b/backend/api/v1/modules/a76/general_catalogs/customs_broker_concepts/service.py index 43e7d1d8..643981e4 100644 --- a/backend/api/v1/modules/a76/general_catalogs/customs_broker_concepts/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/customs_broker_concepts/service.py @@ -1,10 +1,16 @@ from typing import List, Optional, Tuple, Dict, Any +import logging + from sqlalchemy.orm import Session from sqlalchemy import select +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException from .models import CustomsBrokerConcept from .dto import CustomsBrokerConceptCreate, CustomsBrokerConceptUpdate +logger = logging.getLogger(__name__) + class CustomsBrokerConceptService: @staticmethod @@ -76,6 +82,20 @@ class CustomsBrokerConceptService: if not db_obj: return False - db.delete(db_obj) - db.commit() - return True + try: + db.delete(db_obj) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"IntegrityError deleting customs broker concept {id}: {str(e)}") + if "foreign key constraint" in str(e).lower(): + raise HTTPException( + status_code=400, + detail="No se puede eliminar el concepto porque tiene registros relacionados" + ) + raise HTTPException(status_code=400, detail="Error al eliminar el concepto") + except Exception as e: + db.rollback() + logger.error(f"Error deleting customs broker concept {id}: {str(e)}") + raise HTTPException(status_code=500, detail="Error al eliminar el concepto") diff --git a/backend/api/v1/modules/a76/general_catalogs/doda/service.py b/backend/api/v1/modules/a76/general_catalogs/doda/service.py index 43690982..cccb1314 100644 --- a/backend/api/v1/modules/a76/general_catalogs/doda/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/doda/service.py @@ -131,14 +131,21 @@ class DodaService: db: Session, id: int, tenant_id: int, company_id: int ) -> bool: """Delete a DODA""" - try: - db_doda = DodaService.get_by_id(db, id, tenant_id, company_id) - if not db_doda: - return False + db_doda = DodaService.get_by_id(db, id, tenant_id, company_id) + if not db_doda: + return False + try: db.delete(db_doda) db.commit() return True + except IntegrityError as e: + db.rollback() + logger.error(f"Error de integridad al eliminar DODA {id}: {str(e)}") + raise HTTPException( + status_code=400, + detail="No se puede eliminar este DODA porque tiene registros relacionados. Primero debe eliminar o reasignar esos registros." + ) except Exception as e: db.rollback() logger.error(f"Error deleting DODA: {str(e)}") diff --git a/backend/api/v1/modules/a76/general_catalogs/legends/routes.py b/backend/api/v1/modules/a76/general_catalogs/legends/routes.py index 92f4a64b..69772309 100644 --- a/backend/api/v1/modules/a76/general_catalogs/legends/routes.py +++ b/backend/api/v1/modules/a76/general_catalogs/legends/routes.py @@ -4,17 +4,13 @@ from .models import Legend from .dto import LegendCreate, LegendResponse, LegendUpdate from .service import LegendService -router = APIRouter(prefix="/legends", tags=["a76.general_catalogs.legends"]) - -legend_crud = TenantCRUDRoutes( +router = TenantCRUDRoutes( service=LegendService, create_schema=LegendCreate, update_schema=LegendUpdate, response_schema=LegendResponse, prefix="/legends", - tags=["Legends"], + tags=["a76.general_catalogs.legends"], resource_name="Legend", enable_list=True, -) - -router.include_router(legend_crud.router) +).router diff --git a/backend/api/v1/modules/a76/general_catalogs/legends/service.py b/backend/api/v1/modules/a76/general_catalogs/legends/service.py index 0221ecbb..0351f16a 100644 --- a/backend/api/v1/modules/a76/general_catalogs/legends/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/legends/service.py @@ -1,10 +1,15 @@ from typing import List, Optional, Tuple, Dict, Any from sqlalchemy.orm import Session from sqlalchemy import select +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException +import logging from .models import Legend from .dto import LegendCreate, LegendUpdate +logger = logging.getLogger(__name__) + class LegendService: @staticmethod @@ -63,8 +68,8 @@ class LegendService: def update( db: Session, id: int, - data: LegendUpdate, tenant_id: int, + data: LegendUpdate, company_id: int ) -> Optional[Legend]: db_obj = LegendService.get_by_id(db, id, tenant_id, company_id) @@ -90,6 +95,14 @@ class LegendService: if not db_obj: return False - db.delete(db_obj) - db.commit() - return True + try: + db.delete(db_obj) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"Error de integridad al eliminar leyenda {id}: {str(e)}") + raise HTTPException( + status_code=400, + detail="No se puede eliminar esta leyenda porque tiene registros relacionados (pedimentos, facturas, etc.). Primero debe eliminar o reasignar esos registros." + ) diff --git a/backend/api/v1/modules/a76/general_catalogs/packages/services.py b/backend/api/v1/modules/a76/general_catalogs/packages/services.py index be52f4f7..cea4d882 100644 --- a/backend/api/v1/modules/a76/general_catalogs/packages/services.py +++ b/backend/api/v1/modules/a76/general_catalogs/packages/services.py @@ -3,11 +3,16 @@ Service layer for Packages (GBultos). """ from typing import Optional, Tuple, List, Dict, Any +import logging from sqlalchemy.orm import Session +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException from . import dto, models +logger = logging.getLogger(__name__) + class PackageService: """Service for Package CRUD operations with tenant support""" @@ -109,6 +114,20 @@ class PackageService: if not package: return False - db.delete(package) - db.commit() - return True + try: + db.delete(package) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"IntegrityError deleting package {package_id}: {str(e)}") + if "foreign key constraint" in str(e).lower(): + raise HTTPException( + status_code=400, + detail="No se puede eliminar el bulto porque tiene registros relacionados" + ) + raise HTTPException(status_code=400, detail="Error al eliminar el bulto") + except Exception as e: + db.rollback() + logger.error(f"Error deleting package {package_id}: {str(e)}") + raise HTTPException(status_code=500, detail="Error al eliminar el bulto") diff --git a/backend/api/v1/modules/a76/general_catalogs/units_of_measure/service.py b/backend/api/v1/modules/a76/general_catalogs/units_of_measure/service.py index b21faa7a..19304472 100644 --- a/backend/api/v1/modules/a76/general_catalogs/units_of_measure/service.py +++ b/backend/api/v1/modules/a76/general_catalogs/units_of_measure/service.py @@ -1,6 +1,11 @@ from typing import List, Optional, Tuple, Dict, Any, Type from sqlalchemy import Sequence from sqlalchemy.orm import Session +from sqlalchemy.exc import IntegrityError +from fastapi import HTTPException +import logging + +logger = logging.getLogger(__name__) from .models import ( UnitOfMeasureACE, UnitOfMeasureOMA, UnitOfMeasureAmerican, UnitOfMeasureCustoms, @@ -102,9 +107,17 @@ class BaseService: if not db_obj: return False - db.delete(db_obj) - db.commit() - return True + try: + db.delete(db_obj) + db.commit() + return True + except IntegrityError as e: + db.rollback() + logger.error(f"Error de integridad al eliminar {cls.model.__name__} {id}: {str(e)}") + raise HTTPException( + status_code=400, + detail="No se puede eliminar esta unidad de medida porque tiene registros relacionados. Primero debe eliminar o reasignar esos registros." + ) class UnitOfMeasureACEService(BaseService): diff --git a/frontend/messages/en.json b/frontend/messages/en.json index 86f3f4ce..d4274cd5 100644 --- a/frontend/messages/en.json +++ b/frontend/messages/en.json @@ -41,11 +41,11 @@ "valuation_methods": "Valuation Methods", "countries": "Countries", "ports": "Ports", - "unit_measures": "Unit Measures", - "um_customs_mex": "U.M. Customs Mexico", - "um_customs_ame": "U.M. Customs America", - "um_ace": "U.M. ACE", - "um_oma": "U.M. OMA", + "unit_measures": "Units of Measure - General", + "um_customs_mex": "Units of Measure - Mexican Customs", + "um_customs_ame": "Units of Measure - American Customs", + "um_ace": "Units of Measure - ACE", + "um_oma": "Units of Measure - OMA", "conversions": "Conversions", "equivalences": "Equivalences", "exchange_rates": "Exchange Rates", diff --git a/frontend/messages/es.json b/frontend/messages/es.json index af9b2e69..e4b9728e 100644 --- a/frontend/messages/es.json +++ b/frontend/messages/es.json @@ -41,11 +41,11 @@ "valuation_methods": "Metódos de valoración", "countries": "Países", "ports": "Puertos", - "unit_measures": "Unidades de medida", - "um_customs_mex": "U.M. Aduanas Mexicanas", - "um_customs_ame": "U.M. Aduanas Americanas", - "um_ace": "U.M. ACE", - "um_oma": "U.M. OMA", + "unit_measures": "Unidades de medida general", + "um_customs_mex": "Unidades de medida - Aduanas Mexicanas", + "um_customs_ame": "Unidades de medida - Aduanas Americanas", + "um_ace": "Unidades de medida - ACE", + "um_oma": "Unidades de medida - OMA", "conversions": "Conversiones", "equivalences": "Equivalencias", "exchange_rates": "Tipos de cambio", diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 8bc86a87..5221c628 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -194,6 +194,14 @@ async function fetchApi( } } + // Manejar respuestas sin contenido (204 No Content) + if (response.status === 204) { + return { + data: null as T, + status: response.status + }; + } + const data = await response.json(); if (!response.ok) { diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/classification-concepts.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/classification-concepts.ts index 984cc4c0..f87a5871 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/classification-concepts.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/classification-concepts.ts @@ -37,36 +37,28 @@ export async function getClassificationConcepts( ...filters }); - - const response = await api.get(`/v1/a76/classification-concepts/?${params.toString()}`); - return response.data; + return await api.get(`/v1/a76/classification-concepts/?${params.toString()}`); } -export async function getClassificationConcept(id: number, companyId: number): Promise { - const response = await api.get(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`); - return response.data; +export async function getClassificationConcept(id: number, companyId: number): Promise> { + return await api.get(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`); } export async function createClassificationConcept( data: ClassificationConceptCreate, companyId: number -): Promise { - // 👇 AQUÍ ESTABA EL ERROR GRAVE - const response = await api.post(`/v1/a76/classification-concepts/?company_id=${companyId}`, data); - return response.data; +): Promise> { + return await api.post(`/v1/a76/classification-concepts/?company_id=${companyId}`, data); } - export async function updateClassificationConcept( id: number, data: ClassificationConceptUpdate, - companyId: number // <-- Faltaba esto -): Promise { - const response = await api.put(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`, data); - return response.data; + companyId: number +): Promise> { + return await api.put(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`, data); } - -export async function deleteClassificationConcept(id: number, companyId: number): Promise { - await api.delete(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`); +export async function deleteClassificationConcept(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/classification-concepts/${id}/?company_id=${companyId}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/company.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/company.ts index 05f4682f..d31e6aba 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/company.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/company.ts @@ -1,91 +1,115 @@ - import { api } from '$lib/api'; - import type { ApiResponse } from '$lib/api'; +import { api } from '$lib/api'; +import type { ApiResponse } from '$lib/api'; - export interface Company { - id: number; - tenant_id: number; - name: string | null; - rfc: string | null; - main_activity: string | null; - program: string | null; - program_number: string | null; - prosec: number | null; - prosec_authorization: string | null; - manufacturer_id: string | null; - broker_company: string | null; - responsible: string | null; - responsible_name: string | null; - responsible_last_name: string | null; - responsible_mother_last_name: string | null; - created_at: string | null; - updated_at: string | null; - } +export interface Company { + id: number; + tenant_id: number; + name: string | null; + rfc: string | null; + curp?: string | null; + main_activity: string | null; + program: string | null; + program_number: string | null; + prosec: number | null; + prosec_authorization: string | null; + manufacturer_id: string | null; + broker_company: string | null; + responsible: string | null; + responsible_name: string | null; + responsible_last_name: string | null; + responsible_mother_last_name: string | null; + responsible_rfc?: string | null; + position?: string | null; + has_express_line?: boolean; + is_service_company?: boolean; + order_format_type?: string | null; + ctpat_svi?: string | null; + trusted_exporter_number?: string | null; + created_at: string | null; + updated_at: string | null; +} - export interface CompanyCreate { - name?: string | null; - rfc?: string | null; - main_activity?: string | null; - program?: string | null; - program_number?: string | null; - prosec?: number | null; - prosec_authorization?: string | null; - manufacturer_id?: string | null; - broker_company?: string | null; - responsible?: string | null; - responsible_name?: string | null; - responsible_last_name?: string | null; - responsible_mother_last_name?: string | null; - } +export interface CompanyCreate { + name?: string | null; + rfc?: string | null; + curp?: string | null; + main_activity?: string | null; + program?: string | null; + program_number?: string | null; + prosec?: number | null; + prosec_authorization?: string | null; + manufacturer_id?: string | null; + broker_company?: string | null; + responsible?: string | null; + responsible_name?: string | null; + responsible_last_name?: string | null; + responsible_mother_last_name?: string | null; + responsible_rfc?: string | null; + position?: string | null; + has_express_line?: boolean; + is_service_company?: boolean; + order_format_type?: string | null; + ctpat_svi?: string | null; + trusted_exporter_number?: string | null; +} - export interface CompanyUpdate { - name?: string | null; - rfc?: string | null; - main_activity?: string | null; - program?: string | null; - program_number?: string | null; - prosec?: number | null; - prosec_authorization?: string | null; - manufacturer_id?: string | null; - broker_company?: string | null; - responsible?: string | null; - responsible_name?: string | null; - responsible_last_name?: string | null; - responsible_mother_last_name?: string | null; - } +export interface CompanyUpdate { + name?: string | null; + rfc?: string | null; + curp?: string | null; + main_activity?: string | null; + program?: string | null; + program_number?: string | null; + prosec?: number | null; + prosec_authorization?: string | null; + manufacturer_id?: string | null; + broker_company?: string | null; + responsible?: string | null; + responsible_name?: string | null; + responsible_last_name?: string | null; + responsible_mother_last_name?: string | null; + responsible_rfc?: string | null; + position?: string | null; + has_express_line?: boolean; + is_service_company?: boolean; + order_format_type?: string | null; + ctpat_svi?: string | null; + trusted_exporter_number?: string | null; +} - export interface CompanyListResponse { - items: Company[]; - total: number; - page: number; - page_size: number; - pages: number; - } +export interface CompanyListResponse { + items: Company[]; + total: number; + page: number; + page_size: number; + pages: number; +} - export async function getCompanies( - page = 1, - pageSize = 50, - filters: Record = {} - ): Promise> { - const queryParams = new URLSearchParams({ - page: page.toString(), - page_size: pageSize.toString(), - ...filters - }); - return await api.get(`/a76/company?${queryParams.toString()}`); - } +export async function getCompanies( + page = 1, + pageSize = 50, + filters: Record = {} +): Promise> { + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + ...filters + }); + return await api.get(`/v1/a76/company?${queryParams.toString()}`); +} - export async function getCompany(id: number): Promise> { - return await api.get(`/a76/company/${id}`); - } +export async function getCompany(id: number): Promise> { + return await api.get(`/v1/a76/company/${id}`); +} - export async function createCompany(data: CompanyCreate): Promise> { - return await api.post(`/v1/a76/company`, data); - } +export async function createCompany(data: CompanyCreate): Promise> { + return await api.post(`/v1/a76/company`, data); +} - export async function updateCompany(id: number, data: CompanyUpdate): Promise> { - return await api.put(`/a76/company/${id}`, data); - } +export async function updateCompany(id: number, data: CompanyUpdate): Promise> { + return await api.put(`/v1/a76/company/${id}`, data); +} - export async function deleteCompany(id: number): Promise> { - return await api.delete(`/a76/company/${id}`); - } +export async function deleteCompany(id: number): Promise> { + return await api.delete(`/v1/a76/company/${id}`); +} diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/concepts.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/concepts.ts index 2371e1c4..86a58061 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/concepts.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/concepts.ts @@ -57,33 +57,25 @@ export async function getConcepts( ...filters }); - const response = await api.get(`/v1/a76/concepts/?${params.toString()}`); - return response.data; + return await api.get(`/v1/a76/concepts?${params.toString()}`); } -export async function getConcept(id: number, companyId: number): Promise { - - const response = await api.get(`/v1/a76/concepts/${id}/?company_id=${companyId}`); - return response.data; +export async function getConcept(id: number, companyId: number): Promise> { + return await api.get(`/v1/a76/concepts/${id}?company_id=${companyId}`); } -export async function createConcept(data: ConceptCreate, companyId: number): Promise { - - const response = await api.post(`/v1/a76/concepts/?company_id=${companyId}`, data); - return response.data; +export async function createConcept(data: ConceptCreate, companyId: number): Promise> { + return await api.post(`/v1/a76/concepts?company_id=${companyId}`, data); } -export async function updateConcept(id: number, data: ConceptUpdate, companyId: number): Promise { - - const response = await api.put(`/v1/a76/concepts/${id}/?company_id=${companyId}`, data); - return response.data; +export async function updateConcept(id: number, data: ConceptUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/concepts/${id}?company_id=${companyId}`, data); } -export async function deleteConcept(id: number, companyId: number): Promise { - - await api.delete(`/v1/a76/concepts/${id}/?company_id=${companyId}`); +export async function deleteConcept(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/concepts/${id}?company_id=${companyId}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/customs_broker_concepts.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/customs_broker_concepts.ts new file mode 100644 index 00000000..e9cf0b07 --- /dev/null +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/customs_broker_concepts.ts @@ -0,0 +1,75 @@ +import { api } from '$lib/api'; +import type { ApiResponse } from '$lib/api'; + +export interface CustomsBrokerConcept { + id: number; + code: string; + description?: string; + description_en?: string; + detailed_description?: string; + priority?: number; + first_total?: boolean; + type?: string; + is_printed?: boolean; + section?: number; + classification?: string; + tenant_id: string; + company_id?: string; + created_at: string; + updated_at?: string; +} + +export interface CustomsBrokerConceptCreate { + code: string; + description?: string; + description_en?: string; + detailed_description?: string; + priority?: number; + first_total?: boolean; + type?: string; + is_printed?: boolean; + section?: number; + classification?: string; +} + +export interface CustomsBrokerConceptUpdate extends Partial {} + +export interface CustomsBrokerConceptListResponse { + items: CustomsBrokerConcept[]; + total: number; + page: number; + page_size: number; + pages: number; +} + +export async function getCustomsBrokerConcepts( + page: number = 1, + pageSize: number = 50, + companyId: number, + filters: Record = {}, +): Promise> { + const params = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString(), + ...filters + }); + + return await api.get(`/v1/a76/customs-broker-concepts?${params.toString()}`); +} + +export async function getCustomsBrokerConcept(id: number, companyId: number): Promise> { + return await api.get(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`); +} + +export async function createCustomsBrokerConcept(data: CustomsBrokerConceptCreate, companyId: number): Promise> { + return await api.post(`/v1/a76/customs-broker-concepts?company_id=${companyId}`, data); +} + +export async function updateCustomsBrokerConcept(id: number, data: CustomsBrokerConceptUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`, data); +} + +export async function deleteCustomsBrokerConcept(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/customs-broker-concepts/${id}?company_id=${companyId}`); +} diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/legends.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/legends.ts index 989f8d37..1e81cb63 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/legends.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/legends.ts @@ -38,35 +38,28 @@ export async function getLegends( company_id: companyId.toString(), ...filters }); - const response = await api.get(`/v1/a76/legends/?${params.toString()}`); - return response.data; + return await api.get(`/v1/a76/legends/?${params.toString()}`); } -export async function getLegend(id: number, companyId: number): Promise { - const response = await api.get(`/v1/a76/legends/${id}/?company_id=${companyId}`); - return response.data; +export async function getLegend(id: number, companyId: number): Promise> { + return await api.get(`/v1/a76/legends/${id}/?company_id=${companyId}`); } - export async function createLegend( data: LegendCreate, companyId: number -): Promise { - - const response = await api.post(`/v1/a76/legends/?company_id=${companyId}`, data); - return response.data; +): Promise> { + return await api.post(`/v1/a76/legends/?company_id=${companyId}`, data); } export async function updateLegend( id: number, data: LegendUpdate, companyId: number -): Promise { - - const response = await api.put(`/v1/a76/legends/${id}/?company_id=${companyId}`, data); - return response.data; +): Promise> { + return await api.put(`/v1/a76/legends/${id}/?company_id=${companyId}`, data); } -export async function deleteLegend(id: number, companyId: number): Promise { - await api.delete(`/v1/a76/legends/${id}/?company_id=${companyId}`); +export async function deleteLegend(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/legends/${id}/?company_id=${companyId}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts index 630a1185..a624e361 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/multi-currency-types.ts @@ -1,79 +1,78 @@ import { api } from '$lib/api'; -import type { ApiResponse } from '$lib/api'; +import type { PaginatedResponse } from '$lib/types'; export interface MultiCurrencyType { - id: number; - - currency_type_code: string; - country_key: string | null; - conversion_factor: number | null; - publication_date: number; - tenant_id: number; - company_id: number; - created_at: string; - updated_at?: string; + id: number; + currency_type_code: string; + country_key: string | null; + conversion_factor: number | null; + publication_date: number; + company_id: number; + tenant_id: number; } export interface MultiCurrencyTypeCreate { - currency_type_code: string; - country_key?: string | null; - conversion_factor?: number | null; - publication_date: number; + currency_type_code: string; + country_key?: string | null; + conversion_factor?: number | null; + publication_date: number; } -export interface MultiCurrencyTypeUpdate extends Partial {} +export interface MultiCurrencyTypeUpdate { + currency_type_code?: string; + country_key?: string | null; + conversion_factor?: number | null; + publication_date?: number; +} -export interface MultiCurrencyTypeListResponse { - items: MultiCurrencyType[]; - total: number; - page: number; - page_size: number; - pages: number; +export interface MultiCurrencyTypeListResponse extends PaginatedResponse { + items: MultiCurrencyType[]; } export async function getMultiCurrencyTypes( - page: number = 1, - pageSize: number = 50, - companyId: number, - filters: Record = {} -): Promise> { - const params = new URLSearchParams({ - page: page.toString(), - page_size: pageSize.toString(), - company_id: companyId.toString(), - ...filters - }); + companyId: number, + page?: number, + pageSize?: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + if (page) params.append('page', page.toString()); + if (pageSize) params.append('page_size', pageSize.toString()); - // Agregamos /v1 y el path correcto - const response = await api.get(`/v1/a76/multi_currency_types/?${params.toString()}`); - return response.data; + return api.get(`/v1/a76/multi-currency-types/?${params.toString()}`); } - -export async function getMultiCurrencyType(id: number, companyId: number): Promise { - const response = await api.get(`/v1/a76/multi_currency_types/${id}/?company_id=${companyId}`); - return response.data; +export async function getMultiCurrencyType( + multiCurrencyTypeId: number, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.get(`/v1/a76/multi-currency-types/${multiCurrencyTypeId}?${params.toString()}`); } export async function createMultiCurrencyType( - data: MultiCurrencyTypeCreate, - companyId: number + data: MultiCurrencyTypeCreate, + companyId: number ): Promise { - const response = await api.post(`/v1/a76/multi_currency_types/?company_id=${companyId}`, data); - return response.data; + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.post(`/v1/a76/multi-currency-types/?${params.toString()}`, data); } - export async function updateMultiCurrencyType( - id: number, - data: MultiCurrencyTypeUpdate, - companyId: number + multiCurrencyTypeId: number, + data: MultiCurrencyTypeUpdate, + companyId: number ): Promise { - const response = await api.put(`/v1/a76/multi_currency_types/${id}/?company_id=${companyId}`, data); - return response.data; + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.put( + `/v1/a76/multi-currency-types/${multiCurrencyTypeId}?${params.toString()}`, + data + ); } - -export async function deleteMultiCurrencyType(id: number, companyId: number): Promise { - await api.delete(`/v1/a76/multi_currency_types/${id}/?company_id=${companyId}`); +export async function deleteMultiCurrencyType( + multiCurrencyTypeId: number, + companyId: number +): Promise { + const params = new URLSearchParams({ company_id: companyId.toString() }); + return api.delete(`/v1/a76/multi-currency-types/${multiCurrencyTypeId}?${params.toString()}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/packages.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/packages.ts index 49e620ca..13a9783a 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/packages.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/packages.ts @@ -52,22 +52,19 @@ export async function getPackages( ...filters }); - const response = await api.get(`/v1/a76/packages/?${params.toString()}`); - return response.data; + return await api.get(`/v1/a76/packages?${params.toString()}`); } -export async function getPackage(id: number, companyId: number): Promise { - const response = await api.get(`/v1/a76/packages/${id}/?company_id=${companyId}`); - return response.data; +export async function getPackage(id: number, companyId: number): Promise> { + return await api.get(`/v1/a76/packages/${id}?company_id=${companyId}`); } export async function createPackage( data: PackageCreate, companyId: number -): Promise { - const response = await api.post(`/v1/a76/packages/?company_id=${companyId}`, data); - return response.data; +): Promise> { + return await api.post(`/v1/a76/packages?company_id=${companyId}`, data); } @@ -75,11 +72,10 @@ export async function updatePackage( id: number, data: PackageUpdate, companyId: number -): Promise { - const response = await api.put(`/v1/a76/packages/${id}/?company_id=${companyId}`, data); - return response.data; +): Promise> { + return await api.put(`/v1/a76/packages/${id}?company_id=${companyId}`, data); } -export async function deletePackage(id: number, companyId: number): Promise { - await api.delete(`/v1/a76/packages/${id}/?company_id=${companyId}`); +export async function deletePackage(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/packages/${id}?company_id=${companyId}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/unit-conversions.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/unit-conversions.ts index 610f707d..9a7202ca 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/unit-conversions.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/unit-conversions.ts @@ -73,5 +73,5 @@ export async function updateUnitConversion( } export async function deleteUnitConversion(id: number, companyId: number): Promise { - await api.delete(`/v1/a76/unit_conversions/${id}/?company_id=${companyId}`); + await api.delete(`/v1/a76/unit-conversions/${id}/?company_id=${companyId}`); } \ No newline at end of file diff --git a/frontend/src/lib/api/dashboard/a76/general_catalogs/units-of-measure.ts b/frontend/src/lib/api/dashboard/a76/general_catalogs/units-of-measure.ts index cdfa50e4..2aa553ca 100644 --- a/frontend/src/lib/api/dashboard/a76/general_catalogs/units-of-measure.ts +++ b/frontend/src/lib/api/dashboard/a76/general_catalogs/units-of-measure.ts @@ -31,26 +31,28 @@ export interface UnitOfMeasureACEListResponse { export async function getUnitsOfMeasureACE( page = 1, pageSize = 50, + companyId: number, filters: Record = {} ): Promise> { const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), + company_id: companyId.toString(), ...filters }); - return await api.get(`/a76/units-of-measure/ace?${queryParams.toString()}`); + return await api.get(`/v1/a76/units-of-measure/ace/?${queryParams.toString()}`); } -export async function createUnitOfMeasureACE(data: UnitOfMeasureACECreate): Promise> { - return await api.post('/a76/units-of-measure/ace', data); +export async function createUnitOfMeasureACE(data: UnitOfMeasureACECreate, companyId: number): Promise> { + return await api.post(`/v1/a76/units-of-measure/ace/?company_id=${companyId}`, data); } -export async function updateUnitOfMeasureACE(id: number, data: UnitOfMeasureACEUpdate): Promise> { - return await api.put(`/a76/units-of-measure/ace/${id}`, data); +export async function updateUnitOfMeasureACE(id: number, data: UnitOfMeasureACEUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/units-of-measure/ace/${id}/?company_id=${companyId}`, data); } -export async function deleteUnitOfMeasureACE(id: number): Promise> { - return await api.delete(`/a76/units-of-measure/ace/${id}`); +export async function deleteUnitOfMeasureACE(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/units-of-measure/ace/${id}/?company_id=${companyId}`); } // --- OMA --- @@ -81,28 +83,30 @@ export interface UnitOfMeasureOMAListResponse { } export async function getUnitsOfMeasureOMA( - page = 1, - pageSize = 50, + page: number = 1, + pageSize: number = 50, + companyId: number, filters: Record = {} ): Promise> { const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), + company_id: companyId.toString(), ...filters }); - return await api.get(`/a76/units-of-measure/oma?${queryParams.toString()}`); + return await api.get(`/v1/a76/units-of-measure/oma/?${queryParams.toString()}`); } -export async function createUnitOfMeasureOMA(data: UnitOfMeasureOMACreate): Promise> { - return await api.post('/a76/units-of-measure/oma', data); +export async function createUnitOfMeasureOMA(data: UnitOfMeasureOMACreate, companyId: number): Promise> { + return await api.post(`/v1/a76/units-of-measure/oma/?company_id=${companyId}`, data); } -export async function updateUnitOfMeasureOMA(id: number, data: UnitOfMeasureOMAUpdate): Promise> { - return await api.put(`/a76/units-of-measure/oma/${id}`, data); +export async function updateUnitOfMeasureOMA(id: number, data: UnitOfMeasureOMAUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/units-of-measure/oma/${id}/?company_id=${companyId}`, data); } -export async function deleteUnitOfMeasureOMA(id: number): Promise> { - return await api.delete(`/a76/units-of-measure/oma/${id}`); +export async function deleteUnitOfMeasureOMA(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/units-of-measure/oma/${id}/?company_id=${companyId}`); } // --- American --- @@ -133,26 +137,139 @@ export interface UnitOfMeasureAmericanListResponse { } export async function getUnitsOfMeasureAmerican( - page = 1, - pageSize = 50, + page: number = 1, + pageSize: number = 50, + companyId: number, filters: Record = {} ): Promise> { const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), + company_id: companyId.toString(), ...filters }); - return await api.get(`/a76/units-of-measure/american?${queryParams.toString()}`); + return await api.get(`/v1/a76/units-of-measure/american/?${queryParams.toString()}`); } -export async function createUnitOfMeasureAmerican(data: UnitOfMeasureAmericanCreate): Promise> { - return await api.post('/a76/units-of-measure/american', data); +export async function createUnitOfMeasureAmerican(data: UnitOfMeasureAmericanCreate, companyId: number): Promise> { + return await api.post(`/v1/a76/units-of-measure/american/?company_id=${companyId}`, data); } -export async function updateUnitOfMeasureAmerican(id: number, data: UnitOfMeasureAmericanUpdate): Promise> { - return await api.put(`/a76/units-of-measure/american/${id}`, data); +export async function updateUnitOfMeasureAmerican(id: number, data: UnitOfMeasureAmericanUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/units-of-measure/american/${id}/?company_id=${companyId}`, data); } -export async function deleteUnitOfMeasureAmerican(id: number): Promise> { - return await api.delete(`/a76/units-of-measure/american/${id}`); +export async function deleteUnitOfMeasureAmerican(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/units-of-measure/american/${id}/?company_id=${companyId}`); +} + +// --- General --- +export interface UnitOfMeasureGeneral { + id: number; + code: string; + description: string | null; + created_at: string | null; + updated_at: string | null; +} + +export interface UnitOfMeasureGeneralCreate { + code: string; + description?: string | null; +} + +export interface UnitOfMeasureGeneralUpdate { + code?: string; + description?: string | null; +} + +export interface UnitOfMeasureGeneralListResponse { + items: UnitOfMeasureGeneral[]; + total: number; + page: number; + page_size: number; + pages: number; +} + +export async function getUnitsOfMeasureGeneral( + page = 1, + pageSize = 50, + companyId: number, + filters: Record = {} +): Promise> { + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString(), + ...filters + }); + return await api.get(`/v1/a76/units-of-measure/general/?${queryParams.toString()}`); +} + +export async function createUnitOfMeasureGeneral(data: UnitOfMeasureGeneralCreate, companyId: number): Promise> { + return await api.post(`/v1/a76/units-of-measure/general/?company_id=${companyId}`, data); +} + +export async function updateUnitOfMeasureGeneral(id: number, data: UnitOfMeasureGeneralUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/units-of-measure/general/${id}/?company_id=${companyId}`, data); +} + +export async function deleteUnitOfMeasureGeneral(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/units-of-measure/general/${id}/?company_id=${companyId}`); +} + +// --- Customs --- +export interface UnitOfMeasureCustoms { + id: number; + code: string; + description: string | null; + scaii_unit_code: string | null; + created_at: string | null; + updated_at: string | null; +} + +export interface UnitOfMeasureCustomsCreate { + code: string; + description?: string | null; + scaii_unit_code?: string | null; +} + +export interface UnitOfMeasureCustomsUpdate { + code?: string; + description?: string | null; + scaii_unit_code?: string | null; +} + +export interface UnitOfMeasureCustomsListResponse { + items: UnitOfMeasureCustoms[]; + total: number; + page: number; + page_size: number; + pages: number; +} + +export async function getUnitsOfMeasureCustoms( + page: number = 1, + pageSize: number = 50, + companyId: number, + filters: Record = {} +): Promise> { + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString(), + ...filters + }); + return await api.get(`/v1/a76/units-of-measure/customs/?${queryParams.toString()}`); +} + +export async function createUnitOfMeasureCustoms(data: UnitOfMeasureCustomsCreate, companyId: number): Promise> { + return await api.post(`/v1/a76/units-of-measure/customs/?company_id=${companyId}`, data); +} + +export async function updateUnitOfMeasureCustoms(id: number, data: UnitOfMeasureCustomsUpdate, companyId: number): Promise> { + return await api.put(`/v1/a76/units-of-measure/customs/${id}/?company_id=${companyId}`, data); +} + +export async function deleteUnitOfMeasureCustoms(id: number, companyId: number): Promise> { + return await api.delete(`/v1/a76/units-of-measure/customs/${id}/?company_id=${companyId}`); } diff --git a/frontend/src/lib/components/dashboard/exchange-rate/columns.ts b/frontend/src/lib/components/dashboard/exchange-rate/columns.ts index 2b6b07b0..00dfe0db 100644 --- a/frontend/src/lib/components/dashboard/exchange-rate/columns.ts +++ b/frontend/src/lib/components/dashboard/exchange-rate/columns.ts @@ -5,44 +5,44 @@ import DataTableActions from './data-table-actions.svelte'; export function createColumns(onSuccess?: () => void): ColumnDef[] { return [ - { - accessorKey: 'date', - header: 'Fecha', - cell: ({ row }) => { - const dateStr = row.original.date; - if (!dateStr) return 'N/A'; - const date = new Date(dateStr); - return date.toLocaleDateString('es-MX'); + { + accessorKey: 'date', + header: 'Fecha', + cell: ({ row }) => { + const dateStr = row.original.date; + if (!dateStr) return 'N/A'; + const date = new Date(dateStr); + return date.toLocaleDateString('es-MX'); + } + }, + { + accessorKey: 'value', + header: 'Valor', + cell: ({ row }) => { + const value = row.original.value; + if (value === null || value === undefined) return 'N/A'; + return value.toFixed(6); + } + }, + { + accessorKey: 'local_currency', + header: 'Moneda Local', + cell: ({ row }) => row.original.local_currency ?? 'N/A' + }, + { + accessorKey: 'foreign_currency', + header: 'Moneda Extranjera', + cell: ({ row }) => row.original.foreign_currency ?? 'N/A' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } } - }, - { - accessorKey: 'value', - header: 'Tipo de Cambio', - cell: ({ row }) => { - const value = row.original.value; - if (value === null || value === undefined) return 'N/A'; - return value.toFixed(6); - } - }, - { - accessorKey: 'local_currency', - header: 'Moneda Local', - cell: ({ row }) => row.original.local_currency ?? 'N/A' - }, - { - accessorKey: 'foreign_currency', - header: 'Moneda Extranjera', - cell: ({ row }) => row.original.foreign_currency ?? 'N/A' - }, - { - id: 'actions', - header: 'Acciones', - cell: ({ row }) => { - return renderComponent(DataTableActions, { - item: row.original, - onSuccess - }); - } - } ]; } \ No newline at end of file diff --git a/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte index d2a2f7fe..34c61657 100644 --- a/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte +++ b/frontend/src/lib/components/dashboard/exchange-rate/create-edit-dialog.svelte @@ -75,8 +75,10 @@ if (isEdit && item) { await updateExchangeRate(item.id, dataToSend, companyId); + alert(`✅ Tipo de cambio actualizado correctamente`); } else { await createExchangeRate(dataToSend, companyId); + alert(`✅ Tipo de cambio creado correctamente`); } open = false; diff --git a/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte b/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte index 56da5881..cce3e6b2 100644 --- a/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/exchange-rate/data-table-actions.svelte @@ -27,23 +27,21 @@ const companyId = companyStore.activeCompany?.id; if (!companyId) { - alert('No hay compañía seleccionada'); + alert('❌ Error: No hay compañía seleccionada'); return; } loading = true; - error = null; try { await deleteExchangeRate(item.id, companyId); - - // Éxito + alert(`✅ Tipo de cambio del ${new Date(item.date).toLocaleDateString('es-MX')} eliminado correctamente`); if (onSuccess) { onSuccess(); } } catch (err: any) { error = err.message || 'Error al eliminar el tipo de cambio'; - alert(`Error: ${error}`); + alert(`❌ Error: ${error}`); console.error('Error deleting:', err); } finally { loading = false; diff --git a/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte b/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte index ef98de23..72fb9bf3 100644 --- a/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte +++ b/frontend/src/lib/components/dashboard/exchange-rate/data-table.svelte @@ -1,123 +1,106 @@ -
-
- - - {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} - - {#each headerGroup.headers as header (header.id)} - - {#if !header.isPlaceholder} - - {/if} - - {/each} - - {/each} - - - {#each table.getRowModel().rows as row (row.id)} - - {#each row.getVisibleCells() as cell (cell.id)} - - - - {/each} - - {:else} - - - No hay resultados. - - - {/each} - - - {#if hasMore} - - -
- {#if loading} -
-
- Cargando más... -
- {:else} -
- Desplázate para cargar más -
- {/if} -
-
-
- {/if} -
-
-
+
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/columns.ts new file mode 100644 index 00000000..6bc0b68f --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/columns.ts @@ -0,0 +1,29 @@ +import type { ClassificationConcept } from '$lib/api/dashboard/a76/general_catalogs/classification-concepts'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'classification', + header: 'Clasificación', + cell: ({ row }) => row.original.classification || '-' + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: ({ row }) => row.original.description || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table-actions.svelte new file mode 100644 index 00000000..d13cf06c --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table-actions.svelte @@ -0,0 +1,89 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/classification_concepts/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/company/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table-actions.svelte index 2440e100..d180718b 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/company/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table-actions.svelte @@ -18,7 +18,7 @@ let dialogOpen = $state(false); async function handleDelete() { - if (!confirm(`¿Estás seguro de eliminar la empresa "${item.name}"?`)) { + if (!confirm(`¿Estás seguro de eliminar la empresa "${item.name}"?\n\nNota: No se puede eliminar si tiene registros relacionados.`)) { return; } @@ -28,16 +28,23 @@ try { const response = await deleteCompany(item.id); + // Si hay error en la respuesta if (response.error) { - alert(`Error al eliminar: ${response.error}`); + alert(`❌ Error al eliminar:\n\n${response.error}`); return; } - if (onSuccess) { - onSuccess(); + // Éxito (status 204 o 200) + if (response.status === 204 || response.status === 200 || !response.error) { + alert(`✅ Empresa "${item.name}" eliminada correctamente`); + + if (onSuccess) { + onSuccess(); + } } } catch (e) { - alert('Error al eliminar el registro'); + const errorMsg = e instanceof Error ? e.message : 'Error desconocido al eliminar el registro'; + alert(`❌ Error al eliminar:\n\n${errorMsg}`); } finally { loading = false; } @@ -55,7 +62,7 @@ Acciones - dialogOpen = true}> + dialogOpen = true}> Editar diff --git a/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte new file mode 100644 index 00000000..547154cb --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/company/data-table.svelte @@ -0,0 +1,109 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
\ No newline at end of file diff --git a/frontend/src/lib/components/dashboard/general_catalogs/concepts/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/concepts/columns.ts new file mode 100644 index 00000000..a466a539 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/concepts/columns.ts @@ -0,0 +1,39 @@ +import type { Concept } from '$lib/api/dashboard/a76/general_catalogs/concepts'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'code', + header: 'Código', + cell: ({ row }) => row.original.code || '-' + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: ({ row }) => row.original.description || '-' + }, + { + accessorKey: 'type', + header: 'Tipo', + cell: ({ row }) => row.original.type || '-' + }, + { + accessorKey: 'section', + header: 'Sección', + cell: ({ row }) => row.original.section?.toString() || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table-actions.svelte new file mode 100644 index 00000000..da527c98 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table-actions.svelte @@ -0,0 +1,89 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/concepts/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/columns.ts new file mode 100644 index 00000000..9de1fbdf --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/columns.ts @@ -0,0 +1,39 @@ +import type { CustomsBrokerConcept } from '$lib/api/dashboard/a76/general_catalogs/customs_broker_concepts'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'code', + header: 'Código', + cell: ({ row }) => row.original.code || '-' + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: ({ row }) => row.original.description || '-' + }, + { + accessorKey: 'type', + header: 'Tipo', + cell: ({ row }) => row.original.type || '-' + }, + { + accessorKey: 'section', + header: 'Sección', + cell: ({ row }) => row.original.section?.toString() || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table-actions.svelte new file mode 100644 index 00000000..49dd7b58 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table-actions.svelte @@ -0,0 +1,89 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/customs_broker_concepts/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legend/create-edite-dialoge.svelte b/frontend/src/lib/components/dashboard/general_catalogs/legend/create-edite-dialoge.svelte index 8e61a795..7d9c1cf0 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/legend/create-edite-dialoge.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/legend/create-edite-dialoge.svelte @@ -71,13 +71,17 @@ let response; - if (isEdit && item) { response = await updateLegend(item.id, dataToSend, companyId); } else { response = await createLegend(dataToSend, companyId); } + // Verificar si hubo error + if (response.error) { + throw new Error(response.error); + } + open = false; if (onSuccess) onSuccess(); diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legends/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/legends/columns.ts new file mode 100644 index 00000000..4a711c45 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/legends/columns.ts @@ -0,0 +1,29 @@ +import type { Legend } from '$lib/api/dashboard/a76/general_catalogs/legends'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'code', + header: 'Código', + cell: ({ row }) => row.original.code?.toString() || '-' + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: ({ row }) => row.original.description || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table-actions.svelte new file mode 100644 index 00000000..b752b56a --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table-actions.svelte @@ -0,0 +1,90 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/legends/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte index 738d2fb7..b3727220 100644 --- a/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte +++ b/frontend/src/lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte @@ -90,14 +90,13 @@ conversion_factor: formData.conversion_factor ? Number(formData.conversion_factor) : null, publication_date: dateInt // Mandamos el INT que espera Python }; - - let response; - // 👇 companyId por fuera if (isEdit && item) { - response = await updateMultiCurrencyType(item.id, dataToSend, companyId); + await updateMultiCurrencyType(item.id, dataToSend, companyId); + alert(`✅ Tipo de moneda múltiple actualizado correctamente`); } else { - response = await createMultiCurrencyType(dataToSend, companyId); + await createMultiCurrencyType(dataToSend, companyId); + alert(`✅ Tipo de moneda múltiple creado correctamente`); } open = false; diff --git a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/columns.ts new file mode 100644 index 00000000..2f728ce2 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/columns.ts @@ -0,0 +1,32 @@ +import type { ColumnDef } from '@tanstack/table-core'; +import type { UnitConversion } from '$lib/api/dashboard/a76/general_catalogs/unit-conversions'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'from_unit_code', + header: 'Desde código' + }, + { + accessorKey: 'to_unit_code', + header: 'Hacia código' + }, + { + accessorKey: 'conversion_factor', + header: 'Factor de conversión' + }, + { + id: 'actions', + cell: ({ row }) => { + return { + component: DataTableActions, + props: { + conversion: row.original, + onSuccess + } + }; + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/create-edit-dialog.svelte new file mode 100644 index 00000000..793873d3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/create-edit-dialog.svelte @@ -0,0 +1,148 @@ + + + + + + {title} + + +
{ e.preventDefault(); handleSubmit(); }} class="space-y-4"> + {#if error} +
+ {error} +
+ {/if} + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table-actions.svelte new file mode 100644 index 00000000..b5fbb374 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table-actions.svelte @@ -0,0 +1,79 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/unit_conversions/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/columns.ts new file mode 100644 index 00000000..64c72924 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/columns.ts @@ -0,0 +1,29 @@ +import type { UnitOfMeasureACE } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; +import type { ColumnDef } from '@tanstack/table-core'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'code', + header: 'Código', + cell: ({ row }) => row.original.code || '-' + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: ({ row }) => row.original.description || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + item: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/create-edit-dialog.svelte new file mode 100644 index 00000000..8a87d14f --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/create-edit-dialog.svelte @@ -0,0 +1,126 @@ + + + + + + {title} + + +
{ e.preventDefault(); handleSubmit(); }} class="space-y-4"> + {#if error} +
+ {error} +
+ {/if} + +
+
+ + +
+ +
+ + +
+
+ + + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table-actions.svelte new file mode 100644 index 00000000..b72a2c06 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table-actions.svelte @@ -0,0 +1,86 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + dialogOpen = true}> + + Editar + + + + {#if loading} + + {:else} + + {/if} + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/ace/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/columns.ts new file mode 100644 index 00000000..d9f1124e --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/columns.ts @@ -0,0 +1,25 @@ +import type { ColumnDef } from "@tanstack/table-core"; +import type { UnitOfMeasureAmerican } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure"; +import { renderComponent } from "$lib/components/ui/data-table/index.js"; +import DataTableActions from "./data-table-actions.svelte"; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: "code", + header: "Código", + }, + { + accessorKey: "description", + header: "Descripción", + }, + { + id: "actions", + cell: ({ row }) => + renderComponent(DataTableActions, { + unit: row.original, + onSuccess + }), + }, + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/create-edit-dialog.svelte new file mode 100644 index 00000000..b7b240c3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/create-edit-dialog.svelte @@ -0,0 +1,91 @@ + + + + + + {unit ? 'Editar' : 'Crear'} Unidad Americana + +
+
+ + +
+
+ + +
+ + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table-actions.svelte new file mode 100644 index 00000000..cb8a5ead --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table-actions.svelte @@ -0,0 +1,60 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + (dialogOpen = true)}> + + Editar + + + + + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/american/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/columns.ts new file mode 100644 index 00000000..5fcde59a --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/columns.ts @@ -0,0 +1,29 @@ +import type { ColumnDef } from "@tanstack/table-core"; +import type { UnitOfMeasureCustoms } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure"; +import { renderComponent } from "$lib/components/ui/data-table/index.js"; +import DataTableActions from "./data-table-actions.svelte"; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: "code", + header: "Código", + }, + { + accessorKey: "description", + header: "Descripción", + }, + { + accessorKey: "scaii_unit_code", + header: "Código SCAII", + }, + { + id: "actions", + cell: ({ row }) => + renderComponent(DataTableActions, { + unit: row.original, + onSuccess + }), + }, + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/create-edit-dialog.svelte new file mode 100644 index 00000000..7c59ae9c --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/create-edit-dialog.svelte @@ -0,0 +1,98 @@ + + + + + + {unit ? 'Editar' : 'Crear'} Unidad Aduanas MEX + +
+
+ + +
+
+ + +
+
+ + +
+ + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table-actions.svelte new file mode 100644 index 00000000..cb3bf251 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table-actions.svelte @@ -0,0 +1,60 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + (dialogOpen = true)}> + + Editar + + + + + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/customs/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/columns.ts new file mode 100644 index 00000000..a9edaf1c --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/columns.ts @@ -0,0 +1,29 @@ +import type { ColumnDef } from '@tanstack/table-core'; +import type { UnitOfMeasureGeneral } from '$lib/api/dashboard/a76/general_catalogs/units-of-measure'; +import { renderComponent } from '$lib/components/ui/data-table'; +import DataTableActions from './data-table-actions.svelte'; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: 'code', + header: 'Código', + cell: (info) => info.getValue() + }, + { + accessorKey: 'description', + header: 'Descripción', + cell: (info) => info.getValue() || '-' + }, + { + id: 'actions', + header: 'Acciones', + cell: ({ row }) => { + return renderComponent(DataTableActions, { + unit: row.original, + onSuccess + }); + } + } + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/create-edit-dialog.svelte new file mode 100644 index 00000000..6df9b8e5 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/create-edit-dialog.svelte @@ -0,0 +1,91 @@ + + + + + + {unit ? 'Editar' : 'Crear'} Unidad General + +
+
+ + +
+
+ + +
+ + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table-actions.svelte new file mode 100644 index 00000000..9139e11b --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table-actions.svelte @@ -0,0 +1,60 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + (dialogOpen = true)}> + + Editar + + + + + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte new file mode 100644 index 00000000..77c412d8 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/general/data-table.svelte @@ -0,0 +1,107 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ + +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/columns.ts b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/columns.ts new file mode 100644 index 00000000..b3f5c0b8 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/columns.ts @@ -0,0 +1,25 @@ +import type { ColumnDef } from "@tanstack/table-core"; +import type { UnitOfMeasureOMA } from "$lib/api/dashboard/a76/general_catalogs/units-of-measure"; +import { renderComponent } from "$lib/components/ui/data-table/index.js"; +import DataTableActions from "./data-table-actions.svelte"; + +export function createColumns(onSuccess?: () => void): ColumnDef[] { + return [ + { + accessorKey: "code", + header: "Código", + }, + { + accessorKey: "description", + header: "Descripción", + }, + { + id: "actions", + cell: ({ row }) => + renderComponent(DataTableActions, { + unit: row.original, + onSuccess + }), + }, + ]; +} diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/create-edit-dialog.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/create-edit-dialog.svelte new file mode 100644 index 00000000..71bf66f0 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/create-edit-dialog.svelte @@ -0,0 +1,91 @@ + + + + + + {unit ? 'Editar' : 'Crear'} Unidad OMA + +
+
+ + +
+
+ + +
+ + + + +
+
+
diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table-actions.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table-actions.svelte new file mode 100644 index 00000000..0d9a92c2 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table-actions.svelte @@ -0,0 +1,60 @@ + + + + + {#snippet child({ props })} + + {/snippet} + + + Acciones + (dialogOpen = true)}> + + Editar + + + + + Eliminar + + + + + diff --git a/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte new file mode 100644 index 00000000..72fb9bf3 --- /dev/null +++ b/frontend/src/lib/components/dashboard/general_catalogs/units_of_measure/oma/data-table.svelte @@ -0,0 +1,106 @@ + + +
+ + + {#each table.getHeaderGroups() as headerGroup (headerGroup.id)} + + {#each headerGroup.headers as header (header.id)} + + {#if !header.isPlaceholder} + + {/if} + + {/each} + + {/each} + + + {#each table.getRowModel().rows as row (row.id)} + + {#each row.getVisibleCells() as cell (cell.id)} + + + + {/each} + + {:else} + + + No hay resultados. + + + {/each} + + +
+ +
+
+ Total: {totalItems} registros +
+
+ + +
+
diff --git a/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte b/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte index a573c4b8..d981a4f0 100644 --- a/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte +++ b/frontend/src/lib/components/dashboard/packages/data-table-actions.svelte @@ -20,7 +20,12 @@ let selectedItem = $state(null); async function handleDelete() { - if (!confirm(`¿Estás seguro de eliminar el bulto "${item.key}"?`)) { + if (!confirm(`¿Estás seguro de eliminar el bulto "${item.key}"?\n\nNota: No se puede eliminar si tiene registros relacionados.`)) { + return; + } + + if (!companyStore.activeCompany) { + alert('❌ Error: No hay una compañía seleccionada'); return; } @@ -28,7 +33,7 @@ error = null; try { - const response = await deletePackage(item.id); + const response = await deletePackage(item.id, companyStore.activeCompany.id); if (response.error) { if (response.status === 401) { @@ -38,18 +43,21 @@ }, 1500); } else { error = response.error; - alert(`Error al eliminar: ${response.error}`); + alert(`❌ Error al eliminar:\n\n${response.error}`); } return; } // Éxito - if (onSuccess) { - onSuccess(); + if (response.status === 204 || response.status === 200 || !response.error) { + alert(`✅ Bulto "${item.key}" eliminado correctamente`); + if (onSuccess) { + onSuccess(); + } } } catch (e) { error = e instanceof Error ? e.message : "Error al eliminar"; - alert(`Error: ${error}`); + alert(`❌ Error: ${error}`); console.error("Error deleting:", e); } finally { loading = false; diff --git a/frontend/src/lib/components/dashboard/packages/data-table.svelte b/frontend/src/lib/components/dashboard/packages/data-table.svelte index ea8886c5..f32784d7 100644 --- a/frontend/src/lib/components/dashboard/packages/data-table.svelte +++ b/frontend/src/lib/components/dashboard/packages/data-table.svelte @@ -27,10 +27,14 @@ get data() { return data; }, - columns, + get columns() { + return columns; + }, getCoreRowModel: getCoreRowModel(), manualPagination: true, - pageCount: pageCount, + get pageCount() { + return pageCount; + }, }); function handlePageChange(newPage: number) { diff --git a/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.server.ts index 0348b6bc..d5aa261b 100644 --- a/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.server.ts @@ -19,7 +19,26 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { if (classification) filters.classification = classification; if (description) filters.description = description; - const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), ...filters }); + // Obtener company_id de la cookie o usar el primero disponible + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; + + if (!companyId) { + return { + error: 'No se encontró una compañía seleccionada', + classifications: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } + }; + } + + const queryParams = new URLSearchParams({ + company_id: companyId.toString(), + page: page.toString(), + page_size: pageSize.toString(), + ...filters + }); const response = await authenticatedFetch(`v1/a76/classification-concepts?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); if (!response.ok) { diff --git a/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.svelte index e3824ea0..6b781590 100644 --- a/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/classification_concepts/+page.svelte @@ -1,6 +1,7 @@
@@ -74,17 +72,15 @@
-
- -
+ diff --git a/frontend/src/routes/dashboard/general_catalogs/company_information/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/company_information/+page.server.ts index c774b40c..bf636cc9 100644 --- a/frontend/src/routes/dashboard/general_catalogs/company_information/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/company_information/+page.server.ts @@ -29,7 +29,7 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { const rfc = url.searchParams.get('rfc'); if (name) filters.name = name; - if (rfc) filters.rfc = rfc; + if (rfc) filters.rfc = rfc; // Construir URL con parámetros const queryParams = new URLSearchParams({ diff --git a/frontend/src/routes/dashboard/general_catalogs/company_information/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/company_information/+page.svelte index 9f73bd8a..d2a23635 100644 --- a/frontend/src/routes/dashboard/general_catalogs/company_information/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/company_information/+page.svelte @@ -1,6 +1,6 @@
@@ -76,7 +75,7 @@
- -
+ \ No newline at end of file diff --git a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.server.ts index e1cccc48..6ecfb299 100644 --- a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.server.ts @@ -2,35 +2,65 @@ import type { PageServerLoad } from './$types'; import { getAuthTokens, authenticatedFetch } from '$lib/server/api'; export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { - await parent(); - const { accessToken } = getAuthTokens(cookies); + await parent(); + const { accessToken } = getAuthTokens(cookies); - if (!accessToken) { - return { error: 'No authenticated', exchangeRates: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; - } + if (!accessToken) { + return { + error: 'No authenticated', + exchange_rates: { items: [], total: 0, page: 1, page_size: 10, pages: 0 } + }; + } - try { - const page = Number(url.searchParams.get('page')) || 1; - const pageSize = Number(url.searchParams.get('pageSize')) || 50; - const filters: Record = {}; - const date = url.searchParams.get('date'); - const localCurrency = url.searchParams.get('local_currency'); - const foreignCurrency = url.searchParams.get('foreign_currency'); + try { + const page = Number(url.searchParams.get('page')) || 1; + const pageSize = Number(url.searchParams.get('pageSize')) || 10; + const filters: Record = {}; - if (date) filters.date = date; - if (localCurrency) filters.local_currency = localCurrency; - if (foreignCurrency) filters.foreign_currency = foreignCurrency; + // Obtener company_id + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; - const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), ...filters }); - const response = await authenticatedFetch(`v1/a76/exchange-rate?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); + if (!companyId) { + return { + error: 'No company selected', + exchange_rates: { items: [], total: 0, page, page_size: pageSize, pages: 0 } + }; + } - if (!response.ok) { - return { error: 'Failed to load', exchangeRates: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; - } + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString(), + ...filters + }); - return { exchangeRates: await response.json() }; - } catch (error) { - console.error('Error loading exchange rates:', error); - return { error: 'Error loading', exchangeRates: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; - } + const response = await authenticatedFetch( + `v1/a76/exchange-rate/?${queryParams.toString()}`, + { + method: 'GET', + cache: 'no-store' + }, + cookies, + fetch + ); + + if (!response.ok) { + return { + error: 'Failed to load', + exchange_rates: { items: [], total: 0, page, page_size: pageSize, pages: 0 } + }; + } + + return { exchange_rates: await response.json() }; + } catch (error) { + console.error('Error loading exchange rates:', error); + return { + error: 'Error loading', + exchange_rates: { items: [], total: 0, page: 1, page_size: 10, pages: 0 } + }; + } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte index d018db7c..03525d76 100644 --- a/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/exchange-rate/+page.svelte @@ -1,192 +1,70 @@ - - Tipos de Cambio - Anexo 76 - +
+
+
+

Tipos de Cambio

+

+ Catálogo de tipos de cambio +

+
+
+ + +
+
-
-
-
-

Tipos de Cambio

-

Gestiona los tipos de cambio del sistema

-
- - -
+ + + + + - - - Filtros - - -
-
- - -
-
- - -
-
- - -
- -
-
-
- - {#if error} - - Error - {error} - - {/if} - -
- -
- - +
\ No newline at end of file diff --git a/frontend/src/routes/dashboard/general_catalogs/legends/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/legends/+page.server.ts index 7879b99f..abfae777 100644 --- a/frontend/src/routes/dashboard/general_catalogs/legends/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/legends/+page.server.ts @@ -19,7 +19,26 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { if (code) filters.code = code; if (description) filters.description = description; - const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), ...filters }); + // Obtener company_id de la cookie o usar el primero disponible + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; + + if (!companyId) { + return { + error: 'No se encontró una compañía seleccionada', + legends: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } + }; + } + + const queryParams = new URLSearchParams({ + company_id: companyId.toString(), + page: page.toString(), + page_size: pageSize.toString(), + ...filters + }); const response = await authenticatedFetch(`v1/a76/legends?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); if (!response.ok) { diff --git a/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte index 6bb3f573..72d02c06 100644 --- a/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/legends/+page.svelte @@ -1,6 +1,7 @@
@@ -74,17 +72,15 @@
-
- -
+ diff --git a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.server.ts index 854d9ec5..513af021 100644 --- a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.server.ts @@ -12,15 +12,28 @@ export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { try { const page = Number(url.searchParams.get('page')) || 1; const pageSize = Number(url.searchParams.get('pageSize')) || 50; - const filters: Record = {}; - const key = url.searchParams.get('key'); - const description = url.searchParams.get('description'); + + // Obtener company_id + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; - if (key) filters.key = key; - if (description) filters.description = description; + if (!companyId) { + return { + error: 'No company selected', + types: { items: [], total: 0, page, page_size: pageSize, pages: 0 } + }; + } - const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), ...filters }); - const response = await authenticatedFetch(`v1/a76/multi-currency-types?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString() + }); + + const response = await authenticatedFetch(`v1/a76/multi-currency-types/?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); if (!response.ok) { return { error: 'Failed to load', types: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte index 8aa6a1d1..57f16485 100644 --- a/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/multi_currency_types/+page.svelte @@ -3,40 +3,19 @@ import SimpleDataTable from '$lib/components/dashboard/general_catalogs/simple-data-table.svelte'; import CreateDialog from '$lib/components/dashboard/general_catalogs/multi_currency_types/create-edit-dialog.svelte'; import { Button } from '$lib/components/ui/button'; - import { Input } from '$lib/components/ui/input'; import { Plus } from 'lucide-svelte'; - import { goto } from '$app/navigation'; - import { browser } from '$app/environment'; + import { goto } from '$app/navigation'; let { data } = $props(); let dialogOpen = $state(false); - - // Filtros - let searchKey = $state($page.url.searchParams.get('key') || ''); - let searchDesc = $state($page.url.searchParams.get('description') || ''); - let timeout: ReturnType; const columns = [ - { key: 'key', label: 'Clave' }, - { key: 'description', label: 'Descripción' }, + { key: 'currency_type_code', label: 'Código Moneda' }, + { key: 'country_key', label: 'País' }, + { key: 'conversion_factor', label: 'Factor Conversión' }, + { key: 'publication_date', label: 'Fecha Publicación' }, ]; - function handleSearch() { - if (!browser) return; - clearTimeout(timeout); - timeout = setTimeout(() => { - const url = new URL($page.url); - if (searchKey) url.searchParams.set('key', searchKey); - else url.searchParams.delete('key'); - - if (searchDesc) url.searchParams.set('description', searchDesc); - else url.searchParams.delete('description'); - - url.searchParams.set('page', '1'); - goto(url, { keepFocus: true, noScroll: true }); - }, 500); - } - function handleSuccess() { const url = new URL($page.url); goto(url, { invalidateAll: true }); @@ -57,23 +36,6 @@ -
-
- -
-
- -
-
-
{ if (key) filters.key = key; if (description_es) filters.description_es = description_es; + // Obtener company_id de la cookie o usar el primero disponible + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; + + if (!companyId) { + return { + error: 'No se encontró una compañía seleccionada', + packages: { + items: [], + total: 0, + page: 1, + page_size: 50, + pages: 0 + } + }; + } + // Construir URL con parámetros const queryParams = new URLSearchParams({ + company_id: companyId.toString(), page: page.toString(), page_size: pageSize.toString(), ...filters diff --git a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.server.ts index 71e39338..ef681de7 100644 --- a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.server.ts @@ -2,28 +2,62 @@ import type { PageServerLoad } from './$types'; import { getAuthTokens, authenticatedFetch } from '$lib/server/api'; export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { - await parent(); - const { accessToken } = getAuthTokens(cookies); + await parent(); + const { accessToken } = getAuthTokens(cookies); - if (!accessToken) { - return { error: 'No authenticated', conversions: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; - } + if (!accessToken) { + return { + error: 'No authenticated', + conversions: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } + }; + } - try { - const page = Number(url.searchParams.get('page')) || 1; - const pageSize = Number(url.searchParams.get('pageSize')) || 50; - const filters: Record = {}; + try { + const page = Number(url.searchParams.get('page')) || 1; + const pageSize = Number(url.searchParams.get('pageSize')) || 50; + const filters: Record = {}; - const queryParams = new URLSearchParams({ page: page.toString(), page_size: pageSize.toString(), ...filters }); - const response = await authenticatedFetch(`v1/a76/unit-conversions?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); + // Obtener company_id + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; - if (!response.ok) { - return { error: 'Failed to load', conversions: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; - } + if (!companyId) { + return { + error: 'No company selected', + conversions: { items: [], total: 0, page, page_size: pageSize, pages: 0 } + }; + } - return { conversions: await response.json() }; - } catch (error) { - console.error('Error loading unit conversions:', error); - return { error: 'Error loading', conversions: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; - } + const queryParams = new URLSearchParams({ + page: page.toString(), + page_size: pageSize.toString(), + company_id: companyId.toString(), + ...filters + }); + + const response = await authenticatedFetch( + `v1/a76/unit-conversions/?${queryParams.toString()}`, + { method: 'GET' }, + cookies, + fetch + ); + + if (!response.ok) { + return { + error: 'Failed to load', + conversions: { items: [], total: 0, page, page_size: pageSize, pages: 0 } + }; + } + + return { conversions: await response.json() }; + } catch (error) { + console.error('Error loading unit conversions:', error); + return { + error: 'Error loading', + conversions: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } + }; + } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte index db08b9af..c61c4bad 100644 --- a/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/unit_conversions/+page.svelte @@ -1,53 +1,62 @@
-
-
-

Conversiones de Unidades

-

- Gestión del catálogo de conversiones de unidades de medida -

-
- -
+
+
+

Conversiones de Unidades

+

+ Catálogo de conversiones de unidades de medida +

+
+
+ + +
+
-
- -
+ + + + + - dialogOpen = false} - on:success={handleSuccess} - /> +
+ diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.server.ts index d0d95e61..07582ff2 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.server.ts @@ -1,57 +1,53 @@ -import { getServerApiUrl, getAuthTokens } from '$lib/server/api'; +import { getAuthTokens, authenticatedFetch } from '$lib/server/api'; import type { PageServerLoad } from './$types'; -import { redirect } from '@sveltejs/kit'; -export const load: PageServerLoad = async ({ cookies, fetch, url }) => { +export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { + await parent(); const { accessToken } = getAuthTokens(cookies); if (!accessToken) { - throw redirect(302, '/login'); + return { error: 'No authenticated', ace_units: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; } - const page = Number(url.searchParams.get('page')) || 1; - const pageSize = Number(url.searchParams.get('page_size')) || 50; - - const apiUrl = getServerApiUrl(); - // Note: apiUrl already ends with / - const endpoint = `${apiUrl}api/v1/a76/units-of-measure/ace?page=${page}&page_size=${pageSize}`; - try { - const response = await fetch(endpoint, { - headers: { - 'Authorization': `Bearer ${accessToken}` - } - }); + const page = Number(url.searchParams.get('page')) || 1; + const pageSize = Number(url.searchParams.get('pageSize')) || 50; + const filters: Record = {}; + const code = url.searchParams.get('code'); + const description = url.searchParams.get('description'); - if (!response.ok) { - console.error(`Error fetching ACE units: ${response.status} ${response.statusText}`); + if (code) filters.code = code; + if (description) filters.description = description; + + // Obtener company_id de la cookie o usar el primero disponible + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; + + if (!companyId) { return { - items: [], - total: 0, - page, - pageSize, - pages: 0, - error: `Error: ${response.statusText}` + error: 'No se encontró una compañía seleccionada', + ace_units: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; } - const data = await response.json(); - return { - items: data.items, - total: data.total, - page: data.page, - pageSize: data.page_size, - pages: data.pages - }; + const queryParams = new URLSearchParams({ + company_id: companyId.toString(), + page: page.toString(), + page_size: pageSize.toString(), + ...filters + }); + const response = await authenticatedFetch(`v1/a76/units-of-measure/ace/?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); + + if (!response.ok) { + return { error: 'Failed to load', ace_units: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; + } + + return { ace_units: await response.json() }; } catch (error) { - console.error('Error fetching ACE units:', error); - return { - items: [], - total: 0, - page, - pageSize, - pages: 0, - error: 'Failed to connect to server' - }; + console.error('Error loading ACE units:', error); + return { error: 'Error loading', ace_units: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte index a598c159..907ba264 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/ace/+page.svelte @@ -1,8 +1,8 @@
-
-
-

Unidades de Medida Aduanas MEX

-

- Catálogo de unidades de medida para aduanas mexicanas -

-
-
- - -
-
+
+
+

Unidades de Medida Aduanas MEX

+

+ Catálogo de unidades de medida para aduanas mexicanas +

+
+
+ + +
+
- - - - - + + + + + - -
+ +
\ No newline at end of file diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.server.ts b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.server.ts index b0490e54..bfb168e2 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.server.ts +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.server.ts @@ -1,56 +1,45 @@ -import { getServerApiUrl, getAuthTokens } from '$lib/server/api'; +import { getAuthTokens, authenticatedFetch } from '$lib/server/api'; import type { PageServerLoad } from './$types'; -import { redirect } from '@sveltejs/kit'; -export const load: PageServerLoad = async ({ cookies, fetch, url }) => { +export const load: PageServerLoad = async ({ cookies, fetch, url, parent }) => { + await parent(); const { accessToken } = getAuthTokens(cookies); if (!accessToken) { - throw redirect(302, '/login'); + return { error: 'No authenticated', general_units: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; } - const page = Number(url.searchParams.get('page')) || 1; - const pageSize = Number(url.searchParams.get('page_size')) || 50; - - const apiUrl = getServerApiUrl(); - const endpoint = `${apiUrl}api/v1/a76/units-of-measure?page=${page}&page_size=${pageSize}`; - try { - const response = await fetch(endpoint, { - headers: { - 'Authorization': `Bearer ${accessToken}` - } + const page = Number(url.searchParams.get('page')) || 1; + const pageSize = Number(url.searchParams.get('pageSize')) || 50; + const filters: Record = {}; + const code = url.searchParams.get('code'); + const description = url.searchParams.get('description'); + + if (code) filters.code = code; + if (description) filters.description = description; + + const parentData = await parent(); + const cookieCompanyId = cookies.get('active_company_id'); + const companyId = cookieCompanyId + ? parseInt(cookieCompanyId) + : parentData.companies?.[0]?.id; + + const queryParams = new URLSearchParams({ + company_id: companyId.toString(), + page: page.toString(), + page_size: pageSize.toString(), + ...filters }); + const response = await authenticatedFetch(`v1/a76/units-of-measure/general/?${queryParams.toString()}`, { method: 'GET' }, cookies, fetch); if (!response.ok) { - console.error(`Error fetching General units: ${response.status} ${response.statusText}`); - return { - items: [], - total: 0, - page, - pageSize, - pages: 0, - error: `Error: ${response.statusText}` - }; + return { error: 'Failed to load', general_units: { items: [], total: 0, page, page_size: pageSize, pages: 0 } }; } - const data = await response.json(); - return { - items: data.items, - total: data.total, - page: data.page, - pageSize: data.page_size, - pages: data.pages - }; + return { general_units: await response.json() }; } catch (error) { - console.error('Error fetching General units:', error); - return { - items: [], - total: 0, - page, - pageSize, - pages: 0, - error: 'Error al cargar datos' - }; + console.error('Error loading General units:', error); + return { error: 'Error loading', general_units: { items: [], total: 0, page: 1, page_size: 50, pages: 0 } }; } }; diff --git a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte index 1dbdf49b..acc04357 100644 --- a/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte +++ b/frontend/src/routes/dashboard/general_catalogs/units_of_measure/general/+page.svelte @@ -1,8 +1,8 @@