From 980c913d4613a50e68b2c80d71eb34a73096eef8 Mon Sep 17 00:00:00 2001 From: Galindo97 Date: Tue, 24 Feb 2026 17:41:40 -0600 Subject: [PATCH] fix(customs-brokers): update VU and personnel for multi-tenancy support --- .gitignore | 1 + .../api/v1/modules/a76/customs_brokers/dto.py | 9 +- .../v1/modules/a76/customs_brokers/routes.py | 6 +- .../modules/a76/customs_brokers/services.py | 42 +++++++-- .../lib/api/dashboard/a76/customs-brokers.ts | 44 ++++++++-- .../dashboard/customs_brokers/+page.svelte | 87 +++++++++---------- 6 files changed, 124 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index 48bbc048..60db8bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ # Python __pycache__/ +.mypy_cache/ *.py[cod] *$py.class *.so diff --git a/backend/api/v1/modules/a76/customs_brokers/dto.py b/backend/api/v1/modules/a76/customs_brokers/dto.py index e7f38cba..9f1309c7 100644 --- a/backend/api/v1/modules/a76/customs_brokers/dto.py +++ b/backend/api/v1/modules/a76/customs_brokers/dto.py @@ -43,7 +43,7 @@ class CustomsBrokerResponseDTO(CustomsBrokerBaseDTO): broker_key: str tenant_id: int company_id: int - vu: Optional["CustomsBrokerVUCreateDTO"] = None + vu: Optional["CustomsBrokerVUResponseDTO"] = None class Config: from_attributes = True @@ -95,6 +95,11 @@ class CustomsBrokerVUCreateDTO(BaseModel): doda_web_service_access_key: Optional[str] = None doda_fiel_access_key: Optional[str] = None doda_xml_files_path: Optional[str] = None + tenant_id: Optional[int] = None + company_id: Optional[int] = None + +class CustomsBrokerVUResponseDTO(CustomsBrokerVUCreateDTO): + customs_broker_id: int class Config: from_attributes = True @@ -112,6 +117,8 @@ class CustomsBrokerPersonnelDTO(BaseModel): last_name: Optional[str] = None middle_name: Optional[str] = None email: Optional[str] = None + tenant_id: Optional[int] = None + company_id: Optional[int] = None class Config: from_attributes = True diff --git a/backend/api/v1/modules/a76/customs_brokers/routes.py b/backend/api/v1/modules/a76/customs_brokers/routes.py index e968ac78..541f41d9 100644 --- a/backend/api/v1/modules/a76/customs_brokers/routes.py +++ b/backend/api/v1/modules/a76/customs_brokers/routes.py @@ -62,7 +62,7 @@ def update_customs_broker( @router.put( "/customs-broker-vu/{broker_key}", - response_model=dto.CustomsBrokerVUCreateDTO, + response_model=dto.CustomsBrokerVUResponseDTO, ) def update_customs_broker_vu( broker_key: str, @@ -77,7 +77,7 @@ def update_customs_broker_vu( if not broker: raise HTTPException(status_code=404, detail="Customs Broker not found") - updated_vu = services.CustomsBrokerVUService.update_vu(db, broker_key, vu_data) + updated_vu = services.CustomsBrokerVUService.update_vu(db, broker_key, vu_data, tenant_id, company_id) if not updated_vu: raise HTTPException(status_code=404, detail="Customs Broker VU not found") return updated_vu @@ -102,7 +102,7 @@ def update_customs_broker_personnel( raise HTTPException(status_code=404, detail="Customs Broker not found") updated_personnel = services.CustomsBrokerPersonnelService.update_personnel( - db, broker_key, line, personnel_data + db, broker_key, line, personnel_data, tenant_id, company_id ) if not updated_personnel: raise HTTPException( diff --git a/backend/api/v1/modules/a76/customs_brokers/services.py b/backend/api/v1/modules/a76/customs_brokers/services.py index c1c10d68..dc00f352 100644 --- a/backend/api/v1/modules/a76/customs_brokers/services.py +++ b/backend/api/v1/modules/a76/customs_brokers/services.py @@ -90,9 +90,17 @@ class CustomsBrokerVUService: return new_vu @staticmethod - def update_vu(db: Session, broker_key: str, vu_data: dto.CustomsBrokerVUCreateDTO): + def update_vu(db: Session, broker_key: str, vu_data: dto.CustomsBrokerVUCreateDTO, tenant_id: int, company_id: int): # We need the custom broker ID to insert a new VU - broker = db.query(models.CustomsBroker).filter(models.CustomsBroker.broker_key == broker_key).first() + broker = ( + db.query(models.CustomsBroker) + .filter( + models.CustomsBroker.broker_key == broker_key, + models.CustomsBroker.tenant_id == tenant_id, + models.CustomsBroker.company_id == company_id, + ) + .first() + ) if not broker: return None @@ -108,6 +116,8 @@ class CustomsBrokerVUService: else: # Create new new_vu_data = vu_data.model_dump() + new_vu_data["tenant_id"] = tenant_id + new_vu_data["company_id"] = company_id new_vu = models.CustomsBrokerVU(customs_broker_id=broker.id, **new_vu_data) db.add(new_vu) db.commit() @@ -125,24 +135,36 @@ class CustomsBrokerVUService: class CustomsBrokerPersonnelService: @staticmethod - def get_by_broker_key_and_line(db: Session, broker_key: str, line: int): + def get_by_broker_key_and_line(db: Session, broker_key: str, line: int, tenant_id: int, company_id: int): return ( db.query(models.CustomsBrokerPersonnel) .join(models.CustomsBroker) .filter( models.CustomsBroker.broker_key == broker_key, models.CustomsBrokerPersonnel.line == line, + models.CustomsBroker.tenant_id == tenant_id, + models.CustomsBroker.company_id == company_id, ) .first() ) @staticmethod - def create_personnel(db: Session, broker_key: str, personnel_data: dto.CustomsBrokerPersonnelDTO): - broker = db.query(models.CustomsBroker).filter(models.CustomsBroker.broker_key == broker_key).first() + def create_personnel(db: Session, broker_key: str, personnel_data: dto.CustomsBrokerPersonnelDTO, tenant_id: int, company_id: int): + broker = ( + db.query(models.CustomsBroker) + .filter( + models.CustomsBroker.broker_key == broker_key, + models.CustomsBroker.tenant_id == tenant_id, + models.CustomsBroker.company_id == company_id, + ) + .first() + ) if not broker: return None new_personnel_data = personnel_data.model_dump() + new_personnel_data["tenant_id"] = tenant_id + new_personnel_data["company_id"] = company_id new_personnel = models.CustomsBrokerPersonnel(customs_broker_id=broker.id, **new_personnel_data) db.add(new_personnel) db.commit() @@ -155,16 +177,22 @@ class CustomsBrokerPersonnelService: broker_key: str, line: int, personnel_data: dto.CustomsBrokerPersonnelDTO, + tenant_id: int, + company_id: int, ): personnel = CustomsBrokerPersonnelService.get_by_broker_key_and_line( - db, broker_key, line + db, broker_key, line, tenant_id, company_id ) if personnel: for key, value in personnel_data.model_dump(exclude_unset=True).items(): setattr(personnel, key, value) db.commit() db.refresh(personnel) - return personnel + return personnel + else: + return CustomsBrokerPersonnelService.create_personnel( + db, broker_key, personnel_data, tenant_id, company_id + ) @staticmethod def delete_personnel(db: Session, broker_key: str, line: int): diff --git a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts index f08c1726..1362a11a 100644 --- a/frontend/src/lib/api/dashboard/a76/customs-brokers.ts +++ b/frontend/src/lib/api/dashboard/a76/customs-brokers.ts @@ -1,4 +1,5 @@ import { api } from '$lib/api'; +import { companyStore } from '$lib/stores/company.svelte'; // <--- NUEVO: Importamos el store para el fallback import type { ApiResponse } from '$lib/api'; export interface CustomsBroker { @@ -26,6 +27,8 @@ export interface CustomsBroker { } export interface CustomsBrokerVU { + tenant_id?: string | null; + company_id?: string | null; certificate_path?: string | null; key_path?: string | null; access_key?: string | null; @@ -95,7 +98,9 @@ export interface CustomsBrokerListResponse { */ export const customsBrokersApi = { list: (companyId: string, page = 1, pageSize = 50) => { - return api.get(`/v1/a76/customs-brokers?company_id=${companyId}&page=${page}&page_size=${pageSize}`); + return api.get( + `/v1/a76/customs-brokers?company_id=${companyId}&page=${page}&page_size=${pageSize}` + ); }, get: (brokerKey: string, companyId: string) => { @@ -111,20 +116,47 @@ export const customsBrokersApi = { */ update: (brokerKey: string, data: CreateCustomsBrokerData) => { const companyId = data.company_id; - return api.put(`/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`, data); + return api.put( + `/v1/a76/customs-brokers/${brokerKey}/?company_id=${companyId}`, + data + ); }, /** * Elimina un agente aduanal */ delete: (brokerKey: string, companyId: string) => { - return api.delete(`/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}`); + return api.delete( + `/v1/a76/customs-brokers/${brokerKey}?company_id=${companyId}` + ); }, - - + /** + * Actualiza la información de Ventanilla Única (VU) + */ updateVU: (brokerKey: string, data: CustomsBrokerVU, companyId: string) => { - return api.put(`/v1/a76/customs-broker-vu/${brokerKey}?company_id=${companyId}`, data); + // LOGICA DE RESCATE: + // Si companyId llega nulo/undefined, intentamos obtenerlo del store global + let finalCompanyId = companyId; + + if (!finalCompanyId && companyStore.activeCompany?.id) { + finalCompanyId = companyStore.activeCompany.id.toString(); + console.warn("WARN: companyId no fue provisto a updateVU, usando companyStore:", finalCompanyId); + } + + // Aseguramos que el payload tenga los IDs + const payload = { + ...data, + company_id: finalCompanyId, + tenant_id: finalCompanyId + }; + + console.log('[DEBUG] Enviando payload VU:', payload); + + return api.put( + `/v1/a76/customs-broker-vu/${brokerKey}?company_id=${finalCompanyId}`, + payload + ); }, updatePersonnel: (brokerKey: string, line: number, data: CustomsBrokerPersonnel, companyId: string) => { diff --git a/frontend/src/routes/dashboard/customs_brokers/+page.svelte b/frontend/src/routes/dashboard/customs_brokers/+page.svelte index 5a92b518..611ce839 100644 --- a/frontend/src/routes/dashboard/customs_brokers/+page.svelte +++ b/frontend/src/routes/dashboard/customs_brokers/+page.svelte @@ -187,8 +187,7 @@ const brokerColumns = createBrokerColumns(handleActionSuccess); -
- +

GESTIÓN ADUANAL

@@ -196,17 +195,17 @@
- - + + Agentes Aduanales Secciones Aduanales @@ -214,13 +213,11 @@ - -
- -
-
+
+
+

Filtros

Busque por nombre o patente @@ -244,23 +241,20 @@ oninput={handleSearch} />
-
- -
+
- -
-
+
+

Listado

{filteredItems.length} registros
@@ -275,9 +269,8 @@ idField="broker_key" />
- {#if totalItems > pageSize} -
+
- + Página {currentPage} de {Math.ceil(totalItems / pageSize)}
-
-
-

+

+

Detalles del Agente

{selectedItem?.name || '---'}

-
- + Patente: {selectedItem?.broker_key || ''}
-
+
{#if selectedItem}
@@ -338,21 +330,21 @@ {#if selectedItem.tax_id}
-

{selectedItem.tax_id}

+

{selectedItem.tax_id}

{/if} -
+
-
+

{selectedItem.address || ''}

{[selectedItem.city, selectedItem.state].filter(Boolean).join(', ')} @@ -363,9 +355,9 @@

-
+
@@ -391,9 +383,9 @@
{:else}
- +

Selecciona un agente

{/if} @@ -401,9 +393,8 @@
- - - + +
-
+
{#if activeTab === 'brokers'} - {:else} {/if}