feature/permisos-reference-data

This commit is contained in:
2026-05-06 08:13:53 -06:00
parent c96184da90
commit 73b2eb222e
45 changed files with 437 additions and 154 deletions

View File

@@ -8,11 +8,16 @@ from sqlalchemy.orm import Session
from .dto import AgencyTariffCodeDTO
from .models import AgencyTariffCode
from ..rbac import require_ref_view
router = APIRouter(prefix="/agency-tariff-codes")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_pedimento_codes.view"))],
)
async def list_agency_tariff_codes(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -61,7 +66,11 @@ async def list_agency_tariff_codes(
}
@router.get("/{id}", response_model=AgencyTariffCodeDTO)
@router.get(
"/{id}",
response_model=AgencyTariffCodeDTO,
dependencies=[Depends(require_ref_view("ref_pedimento_codes.view"))],
)
async def get_agency_tariff_code(
id: int,
db: Session = Depends(get_core_db),

View File

@@ -9,11 +9,16 @@ from sqlalchemy.orm import Session
from .dto import CartaPorteDTO
from .models import CartaPorte
from ..rbac import require_ref_view
router = APIRouter(prefix="/carta-porte")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
async def list_carta_porte(
page: int = Query(1, ge=1),
page_size: int = Query(50, ge=1, le=100),
@@ -55,7 +60,11 @@ async def list_carta_porte(
}
@router.get("/{id}", response_model=CartaPorteDTO)
@router.get(
"/{id}",
response_model=CartaPorteDTO,
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
async def get_carta_porte(
id: int,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import CodePedimentoRegimenDTO
from .models import CodePedimentoRegimen
from ..rbac import require_ref_view
router = APIRouter(prefix="/code-pedimento-regimens")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
def list_code_pedimento_regimens(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -51,7 +56,11 @@ def list_code_pedimento_regimens(
}
@router.get("/{id}", response_model=CodePedimentoRegimenDTO)
@router.get(
"/{id}",
response_model=CodePedimentoRegimenDTO,
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
def get_code_pedimento_regimen(
id: int,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import ContainerDTO
from .models import Container
from ..rbac import require_ref_view
router = APIRouter(prefix="/containers")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_containers.view"))],
)
async def list_containers(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ async def list_containers(
}
@router.get("/{key}", response_model=ContainerDTO)
@router.get(
"/{key}",
response_model=ContainerDTO,
dependencies=[Depends(require_ref_view("ref_containers.view"))],
)
async def get_container(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -7,18 +7,23 @@ from sqlalchemy.orm import Session
from .dto import CountryDTO
from .models import Country
from ..rbac import require_ref_view
router = APIRouter(prefix="/countries")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_countries.view"))],
)
async def list_countries(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
search: str = Query(None, description="Término de búsqueda"),
db: Session = Depends(get_core_db),
):
"""Endpoint público para obtener lista de países - no requiere autenticación"""
"""Lista de países protegida por permiso ref_countries.view"""
skip = (page - 1) * page_size
query = db.query(Country)
@@ -43,7 +48,11 @@ async def list_countries(
}
@router.get("/{m3_key}", response_model=CountryDTO)
@router.get(
"/{m3_key}",
response_model=CountryDTO,
dependencies=[Depends(require_ref_view("ref_countries.view"))],
)
async def get_country(
m3_key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import CurrencyTypeDTO
from .models import CurrencyType
from ..rbac import require_ref_view
router = APIRouter(prefix="/currency-types")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_currency_types.view"))],
)
async def list_currency_types(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -42,7 +47,11 @@ async def list_currency_types(
}
@router.get("/{code}", response_model=CurrencyTypeDTO)
@router.get(
"/{code}",
response_model=CurrencyTypeDTO,
dependencies=[Depends(require_ref_view("ref_currency_types.view"))],
)
async def get_currency_type(
code: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import CustomsSectionDTO
from .models import CustomsSection
from ..rbac import require_ref_view
router = APIRouter(prefix="/customs-sections")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_customs_sections.view"))],
)
def list_customs_sections(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ def list_customs_sections(
}
@router.get("/{customs_code}", response_model=CustomsSectionDTO)
@router.get(
"/{customs_code}",
response_model=CustomsSectionDTO,
dependencies=[Depends(require_ref_view("ref_customs_sections.view"))],
)
def get_customs_section(
customs_code: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import CustomsWarehouseDTO
from .models import CustomsWarehouse
from ..rbac import require_ref_view
router = APIRouter(prefix="/customs-warehouses")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_customs_warehouses.view"))],
)
def list_customs_warehouses(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -42,7 +47,11 @@ def list_customs_warehouses(
}
@router.get("/{key}/{customs}", response_model=CustomsWarehouseDTO)
@router.get(
"/{key}/{customs}",
response_model=CustomsWarehouseDTO,
dependencies=[Depends(require_ref_view("ref_customs_warehouses.view"))],
)
def get_customs_warehouse(
key: str,
customs: str,

View File

@@ -8,11 +8,16 @@ from sqlalchemy.orm import Session
from .dto import IdentifierDTO
from .models import IdentifierCatalog
from ..rbac import require_ref_view
router = APIRouter(prefix="/identifiers")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("cat_identifiers.view"))],
)
async def list_identifiers(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -59,7 +64,11 @@ async def list_identifiers(
}
@router.get("/{key}", response_model=IdentifierDTO)
@router.get(
"/{key}",
response_model=IdentifierDTO,
dependencies=[Depends(require_ref_view("cat_identifiers.view"))],
)
async def get_identifier(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import IncotermDTO
from .models import Incoterm
from ..rbac import require_ref_view
router = APIRouter(prefix="/incoterms")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_incoterms.view"))],
)
async def list_incoterms(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -53,7 +58,11 @@ async def list_incoterms(
}
@router.get("/{key}", response_model=IncotermDTO)
@router.get(
"/{key}",
response_model=IncotermDTO,
dependencies=[Depends(require_ref_view("ref_incoterms.view"))],
)
async def get_incoterm(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import InvoiceTypeDTO
from .models import InvoiceType
from ..rbac import require_ref_view
router = APIRouter(prefix="/invoice-types")
@router.get("/", response_model=dict)
@router.get(
"/",
response_model=dict,
dependencies=[Depends(require_ref_view("ref_invoice_types.view"))],
)
def list_invoice_types(
page: int = Query(1, ge=1),
page_size: int = Query(50, ge=1, le=100),
@@ -55,7 +60,11 @@ def list_invoice_types(
}
@router.get("/{key}", response_model=InvoiceTypeDTO)
@router.get(
"/{key}",
response_model=InvoiceTypeDTO,
dependencies=[Depends(require_ref_view("ref_invoice_types.view"))],
)
def get_invoice_type(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy.orm import Session
from .dto import LicenseExceptionDTO
from .models import LicenseException
from ..rbac import require_ref_view
router = APIRouter(prefix="/license-exceptions")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
async def list_license_exceptions(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -52,7 +57,11 @@ async def list_license_exceptions(
}
@router.get("/{key}", response_model=LicenseExceptionDTO)
@router.get(
"/{key}",
response_model=LicenseExceptionDTO,
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
async def get_license_exception(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import MaterialTypeDTO
from .models import MaterialType
from ..rbac import require_ref_view
router = APIRouter(prefix="/material-types")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_material_types.view"))],
)
async def list_material_types(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -48,7 +53,11 @@ async def list_material_types(
}
@router.get("/{key}", response_model=MaterialTypeDTO)
@router.get(
"/{key}",
response_model=MaterialTypeDTO,
dependencies=[Depends(require_ref_view("ref_material_types.view"))],
)
async def get_material_type(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import PaymentMethodDTO
from .models import PaymentMethod
from ..rbac import require_ref_view
router = APIRouter(prefix="/payment-methods")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_payment_methods.view"))],
)
def list_payment_methods(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ def list_payment_methods(
}
@router.get("/{key}", response_model=PaymentMethodDTO)
@router.get(
"/{key}",
response_model=PaymentMethodDTO,
dependencies=[Depends(require_ref_view("ref_payment_methods.view"))],
)
def get_payment_method(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import PedimentoCodeDTO
from .models import PedimentoCode
from ..rbac import require_ref_view
router = APIRouter(prefix="/pedimento-codes")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_pedimento_codes.view"))],
)
def list_pedimento_codes(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=1000, description="Tamaño de página"),
@@ -41,7 +46,11 @@ def list_pedimento_codes(
}
@router.get("/{code}", response_model=PedimentoCodeDTO)
@router.get(
"/{code}",
response_model=PedimentoCodeDTO,
dependencies=[Depends(require_ref_view("ref_pedimento_codes.view"))],
)
def get_pedimento_code(
code: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import RegimenPedimentoDTO
from .models import RegimenPedimento
from ..rbac import require_ref_view
router = APIRouter(prefix="/pedimento-regimens")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
def list_pedimento_regimens(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ def list_pedimento_regimens(
}
@router.get("/{key}", response_model=RegimenPedimentoDTO)
@router.get(
"/{key}",
response_model=RegimenPedimentoDTO,
dependencies=[Depends(require_ref_view("ref_pedimento_regimens.view"))],
)
def get_pedimento_regimen(
key: str,
db: Session = Depends(get_core_db),

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import PedimentoTransportCatalogDTO
from .models import PedimentoTransportCatalog
from ..rbac import require_ref_view
router = APIRouter(prefix="/pedimento-transport-catalog")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
async def list_pedimento_transport_catalog(
page: int = Query(1, ge=1, description="Numero de pagina"),
page_size: int = Query(100, ge=1, le=200, description="Tamano de pagina"),
@@ -42,7 +47,11 @@ async def list_pedimento_transport_catalog(
}
@router.get("/{code}", response_model=PedimentoTransportCatalogDTO)
@router.get(
"/{code}",
response_model=PedimentoTransportCatalogDTO,
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
async def get_pedimento_transport_catalog(code: str, db: Session = Depends(get_core_db)):
obj = (
db.query(PedimentoTransportCatalog)

View File

@@ -0,0 +1,25 @@
from typing import Callable
from core.database import get_core_db
from core.security import get_current_user, validate_access_to_resource
from fastapi import Depends, Query
from sqlalchemy.orm import Session
def require_ref_view(permission_code: str) -> Callable:
"""
Dependency factory to enforce reference-data view permissions per company.
Endpoints using this dependency must receive `company_id` in query params.
"""
async def _dep(
company_id: int = Query(..., description="Company ID"),
db: Session = Depends(get_core_db),
current_user: dict = Depends(get_current_user),
) -> bool:
validate_access_to_resource(db, company_id, current_user, [permission_code])
return True
return _dep

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import StateDTO
from .models import State
from ..rbac import require_ref_view
router = APIRouter(prefix="/states")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_states.view"))],
)
async def list_states(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ async def list_states(
}
@router.get("/{m3_key}", response_model=StateDTO)
@router.get(
"/{m3_key}",
response_model=StateDTO,
dependencies=[Depends(require_ref_view("ref_states.view"))],
)
async def get_state(
m3_key: str,
db: Session = Depends(get_core_db),

View File

@@ -5,11 +5,16 @@ from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy.orm import Session
from . import dto, services
from ..rbac import require_ref_view
router = APIRouter()
@router.get("/trailer-types/", response_model=Dict[str, Any])
@router.get(
"/trailer-types/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("trailers.view"))],
)
def list_trailer_types(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -27,7 +32,9 @@ def list_trailer_types(
@router.get(
"/trailer-types/{trailer_type_key}", response_model=dto.TrailerTypeResponseDTO
"/trailer-types/{trailer_type_key}",
response_model=dto.TrailerTypeResponseDTO,
dependencies=[Depends(require_ref_view("trailers.view"))],
)
def get_trailer_type(trailer_type_key: str, db: Session = Depends(get_core_db)):
trailer_type = services.TrailerTypeService.get_trailer_type_by_key(

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import TransportModeDTO
from .models import TransportMode
from ..rbac import require_ref_view
router = APIRouter(prefix="/transport-modes")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_transport_modes.view"))],
)
async def list_transport_modes(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -40,7 +45,11 @@ async def list_transport_modes(
}
@router.get("/{key}", response_model=TransportModeDTO)
@router.get(
"/{key}",
response_model=TransportModeDTO,
dependencies=[Depends(require_ref_view("ref_transport_modes.view"))],
)
async def get_transport_mode(key: str, db: Session = Depends(get_core_db)):
obj = db.query(TransportMode).filter(TransportMode.key == key).first()
if not obj:

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import TransportTypeDTO
from .models import TransportType
from ..rbac import require_ref_view
router = APIRouter(prefix="/transport-types")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
def list_transport_types(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -40,7 +45,11 @@ def list_transport_types(
}
@router.get("/{transport_code}", response_model=TransportTypeDTO)
@router.get(
"/{transport_code}",
response_model=TransportTypeDTO,
dependencies=[Depends(require_ref_view("ref_transport_types.view"))],
)
def get_transport_type(transport_code: str, db: Session = Depends(get_core_db)):
obj = (
db.query(TransportType)

View File

@@ -8,11 +8,16 @@ from sqlalchemy import or_
from .dto import ValuationMethodDTO
from .models import ValuationMethod
from ..rbac import require_ref_view
router = APIRouter(prefix="/valuation-methods")
@router.get("/", response_model=Dict[str, Any])
@router.get(
"/",
response_model=Dict[str, Any],
dependencies=[Depends(require_ref_view("ref_valuation_methods.view"))],
)
async def list_valuation_methods(
page: int = Query(1, ge=1, description="Número de página"),
page_size: int = Query(50, ge=1, le=100, description="Tamaño de página"),
@@ -41,7 +46,11 @@ async def list_valuation_methods(
}
@router.get("/{key}", response_model=ValuationMethodDTO)
@router.get(
"/{key}",
response_model=ValuationMethodDTO,
dependencies=[Depends(require_ref_view("ref_valuation_methods.view"))],
)
async def get_valuation_method(
key: str,
db: Session = Depends(get_core_db),