feat: Implement multi-tenancy support in middleware and security layers
- Enhanced TenantMiddleware to validate tenant information from JWT tokens. - Added LicenseValidationMiddleware to check tenant licenses before processing requests. - Updated security utilities to extract tenant information from tokens and validate company access. - Introduced CompanyStore to manage active company state and handle company switching in the frontend. - Modified API routes to include company_id in requests for better resource management. - Improved logging and error handling throughout the middleware and API layers. - Updated frontend components to reflect changes in company management and selection. - Added new API route for fetching user's companies with proper authentication handling.
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
DTOs (Data Transfer Objects) para módulo de clientes y proveedores
|
||||
Reemplaza schemas.py siguiendo enfoque DDD y estilo NestJS
|
||||
"""
|
||||
|
||||
from pydantic import BaseModel, Field, EmailStr
|
||||
from typing import Optional
|
||||
from datetime import datetime
|
||||
@@ -11,11 +12,18 @@ from decimal import Decimal
|
||||
# DTOs para dirección
|
||||
class ClientProviderAddressDTO(BaseModel):
|
||||
"""DTO para dirección de cliente/proveedor"""
|
||||
municipality: Optional[str] = Field(None, max_length=150, description="Municipality")
|
||||
|
||||
municipality: Optional[str] = Field(
|
||||
None, max_length=150, description="Municipality"
|
||||
)
|
||||
streets: Optional[str] = Field(None, max_length=100, description="Streets")
|
||||
neighborhood: Optional[str] = Field(None, max_length=40, description="Neighborhood")
|
||||
interior_number: Optional[str] = Field(None, max_length=20, description="Interior number")
|
||||
exterior_number: Optional[str] = Field(None, max_length=20, description="Exterior number")
|
||||
interior_number: Optional[str] = Field(
|
||||
None, max_length=20, description="Interior number"
|
||||
)
|
||||
exterior_number: Optional[str] = Field(
|
||||
None, max_length=20, description="Exterior number"
|
||||
)
|
||||
postal_code: Optional[str] = Field(None, max_length=15, description="Postal code")
|
||||
city: Optional[str] = Field(None, max_length=30, description="City")
|
||||
state: Optional[str] = Field(None, max_length=30, description="State")
|
||||
@@ -33,26 +41,49 @@ class ClientProviderAddressDTO(BaseModel):
|
||||
# DTOs para programas
|
||||
class ClientProviderProgramsDTO(BaseModel):
|
||||
"""DTO para programas de cliente/proveedor"""
|
||||
|
||||
program: Optional[str] = Field(None, max_length=7, description="Program")
|
||||
program_number: Optional[str] = Field(None, max_length=40, description="Program number")
|
||||
program_number: Optional[str] = Field(
|
||||
None, max_length=40, description="Program number"
|
||||
)
|
||||
prosec: Optional[int] = Field(None, description="PROSEC")
|
||||
prosec_authorization: Optional[str] = Field(None, max_length=20, description="PROSEC authorization")
|
||||
prosec_authorization: Optional[str] = Field(
|
||||
None, max_length=20, description="PROSEC authorization"
|
||||
)
|
||||
secon_auth_date: Optional[int] = Field(None, description="SECON authorization date")
|
||||
manufacturer_id: Optional[str] = Field(None, max_length=25, description="Manufacturer ID")
|
||||
manufacturer_id: Optional[str] = Field(
|
||||
None, max_length=25, description="Manufacturer ID"
|
||||
)
|
||||
tax_id: Optional[str] = Field(None, max_length=30, description="Tax ID")
|
||||
broker: Optional[str] = Field(None, max_length=6, description="Broker")
|
||||
import_broker: Optional[str] = Field(None, max_length=6, description="Import broker")
|
||||
import_broker: Optional[str] = Field(
|
||||
None, max_length=6, description="Import broker"
|
||||
)
|
||||
transfer_key: Optional[str] = Field(None, max_length=8, description="Transfer key")
|
||||
secon_authorization: Optional[str] = Field(None, max_length=20, description="SECON authorization")
|
||||
applied_proportion: Optional[Decimal] = Field(None, description="Applied proportion")
|
||||
is_certified_company: Optional[str] = Field(None, max_length=1, description="Is certified company")
|
||||
certified_company_registry: Optional[str] = Field(None, max_length=40, description="Certified company registry")
|
||||
donation_auth_number: Optional[str] = Field(None, max_length=50, description="Donation authorization number")
|
||||
secon_authorization: Optional[str] = Field(
|
||||
None, max_length=20, description="SECON authorization"
|
||||
)
|
||||
applied_proportion: Optional[Decimal] = Field(
|
||||
None, description="Applied proportion"
|
||||
)
|
||||
is_certified_company: Optional[str] = Field(
|
||||
None, max_length=1, description="Is certified company"
|
||||
)
|
||||
certified_company_registry: Optional[str] = Field(
|
||||
None, max_length=40, description="Certified company registry"
|
||||
)
|
||||
donation_auth_number: Optional[str] = Field(
|
||||
None, max_length=50, description="Donation authorization number"
|
||||
)
|
||||
ctpat_svi: Optional[str] = Field(None, max_length=100, description="CTPAT SVI")
|
||||
tax_registry_number: Optional[str] = Field(None, max_length=40, description="Tax registry number")
|
||||
tax_registry_number: Optional[str] = Field(
|
||||
None, max_length=40, description="Tax registry number"
|
||||
)
|
||||
subassembly_service: Optional[int] = Field(None, description="Subassembly service")
|
||||
autse_dates: Optional[int] = Field(None, description="AUTSE dates")
|
||||
autse_number: Optional[str] = Field(None, max_length=300, description="AUTSE number")
|
||||
autse_number: Optional[str] = Field(
|
||||
None, max_length=300, description="AUTSE number"
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -61,26 +92,43 @@ class ClientProviderProgramsDTO(BaseModel):
|
||||
# DTOs principales
|
||||
class ClientProviderCreateDTO(BaseModel):
|
||||
"""DTO para crear cliente/proveedor"""
|
||||
|
||||
client_id: str = Field(..., max_length=8, description="Client ID")
|
||||
type_nat_foreign: Optional[str] = Field(None, max_length=1, description="Type national/foreign")
|
||||
type_nat_foreign: Optional[str] = Field(
|
||||
None, max_length=1, description="Type national/foreign"
|
||||
)
|
||||
name: Optional[str] = Field(None, max_length=256, description="Name")
|
||||
short_name: Optional[str] = Field(None, max_length=10, description="Short name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="RFC")
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
client_or_provider: Optional[str] = Field(None, max_length=1, description="Client or provider")
|
||||
client_or_provider: Optional[str] = Field(
|
||||
None, max_length=1, description="Client or provider"
|
||||
)
|
||||
linking: Optional[str] = Field(None, max_length=1, description="Linking")
|
||||
transform_subassembly: Optional[str] = Field(None, max_length=1, description="Transform subassembly")
|
||||
extra_information: Optional[str] = Field(None, max_length=399, description="Extra information")
|
||||
transform_subassembly: Optional[str] = Field(
|
||||
None, max_length=1, description="Transform subassembly"
|
||||
)
|
||||
extra_information: Optional[str] = Field(
|
||||
None, max_length=399, description="Extra information"
|
||||
)
|
||||
web_key: Optional[str] = Field(None, max_length=40, description="Web key")
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
responsible: Optional[str] = Field(
|
||||
None, max_length=80, description="Responsible person"
|
||||
)
|
||||
position: Optional[str] = Field(None, max_length=30, description="Position")
|
||||
incoterm: Optional[str] = Field(None, max_length=19, description="Incoterm")
|
||||
is_national_provider: Optional[str] = Field(None, max_length=2, description="Is national provider")
|
||||
is_national_provider: Optional[str] = Field(
|
||||
None, max_length=2, description="Is national provider"
|
||||
)
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = Field(None, description="Address information")
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(None, description="Programs information")
|
||||
address: Optional[ClientProviderAddressDTO] = Field(
|
||||
None, description="Address information"
|
||||
)
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(
|
||||
None, description="Programs information"
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -88,25 +136,42 @@ class ClientProviderCreateDTO(BaseModel):
|
||||
|
||||
class ClientProviderUpdateDTO(BaseModel):
|
||||
"""DTO para actualizar cliente/proveedor"""
|
||||
type_nat_foreign: Optional[str] = Field(None, max_length=1, description="Type national/foreign")
|
||||
|
||||
type_nat_foreign: Optional[str] = Field(
|
||||
None, max_length=1, description="Type national/foreign"
|
||||
)
|
||||
name: Optional[str] = Field(None, max_length=256, description="Name")
|
||||
short_name: Optional[str] = Field(None, max_length=10, description="Short name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="RFC")
|
||||
curp: Optional[str] = Field(None, max_length=19, description="CURP")
|
||||
client_or_provider: Optional[str] = Field(None, max_length=1, description="Client or provider")
|
||||
client_or_provider: Optional[str] = Field(
|
||||
None, max_length=1, description="Client or provider"
|
||||
)
|
||||
linking: Optional[str] = Field(None, max_length=1, description="Linking")
|
||||
transform_subassembly: Optional[str] = Field(None, max_length=1, description="Transform subassembly")
|
||||
extra_information: Optional[str] = Field(None, max_length=399, description="Extra information")
|
||||
transform_subassembly: Optional[str] = Field(
|
||||
None, max_length=1, description="Transform subassembly"
|
||||
)
|
||||
extra_information: Optional[str] = Field(
|
||||
None, max_length=399, description="Extra information"
|
||||
)
|
||||
web_key: Optional[str] = Field(None, max_length=40, description="Web key")
|
||||
responsible: Optional[str] = Field(None, max_length=80, description="Responsible person")
|
||||
responsible: Optional[str] = Field(
|
||||
None, max_length=80, description="Responsible person"
|
||||
)
|
||||
position: Optional[str] = Field(None, max_length=30, description="Position")
|
||||
incoterm: Optional[str] = Field(None, max_length=19, description="Incoterm")
|
||||
is_national_provider: Optional[str] = Field(None, max_length=2, description="Is national provider")
|
||||
is_national_provider: Optional[str] = Field(
|
||||
None, max_length=2, description="Is national provider"
|
||||
)
|
||||
enabled_disabled: Optional[int] = Field(None, description="Enabled/Disabled status")
|
||||
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = Field(None, description="Address information")
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(None, description="Programs information")
|
||||
address: Optional[ClientProviderAddressDTO] = Field(
|
||||
None, description="Address information"
|
||||
)
|
||||
programs: Optional[ClientProviderProgramsDTO] = Field(
|
||||
None, description="Programs information"
|
||||
)
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -114,6 +179,7 @@ class ClientProviderUpdateDTO(BaseModel):
|
||||
|
||||
class ClientProviderResponseDTO(BaseModel):
|
||||
"""DTO para respuesta de cliente/proveedor"""
|
||||
|
||||
client_id: str
|
||||
type_nat_foreign: Optional[str] = None
|
||||
name: Optional[str] = None
|
||||
@@ -130,7 +196,7 @@ class ClientProviderResponseDTO(BaseModel):
|
||||
incoterm: Optional[str] = None
|
||||
is_national_provider: Optional[str] = None
|
||||
enabled_disabled: Optional[int] = None
|
||||
|
||||
|
||||
# Nested DTOs
|
||||
address: Optional[ClientProviderAddressDTO] = None
|
||||
programs: Optional[ClientProviderProgramsDTO] = None
|
||||
@@ -142,6 +208,7 @@ class ClientProviderResponseDTO(BaseModel):
|
||||
# DTOs para respuestas específicas
|
||||
class ClientProviderBasicDTO(BaseModel):
|
||||
"""DTO para información básica de cliente/proveedor"""
|
||||
|
||||
client_id: str
|
||||
name: Optional[str] = None
|
||||
short_name: Optional[str] = None
|
||||
@@ -155,6 +222,7 @@ class ClientProviderBasicDTO(BaseModel):
|
||||
|
||||
class ClientProviderListDTO(BaseModel):
|
||||
"""DTO para lista de clientes/proveedores"""
|
||||
|
||||
clients: list[ClientProviderBasicDTO]
|
||||
total: int
|
||||
page: int
|
||||
@@ -162,4 +230,3 @@ class ClientProviderListDTO(BaseModel):
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user