feat(company): add tenant_id support for hub_admin in company creation and updates
This commit is contained in:
@@ -12,6 +12,9 @@ from pydantic import BaseModel, ConfigDict, Field, field_validator
|
||||
class CompanyCreateDTO(BaseModel):
|
||||
"""DTO para crear una empresa"""
|
||||
|
||||
# Solo requerido cuando hub_admin crea una empresa (no tiene tenant_id en token)
|
||||
tenant_id: Optional[int] = Field(None, description="Tenant ID (requerido para hub_admin)")
|
||||
|
||||
name: Optional[str] = Field(None, max_length=255, description="Company name")
|
||||
rfc: Optional[str] = Field(None, max_length=30, description="Company RFC")
|
||||
main_activity: Optional[str] = Field(
|
||||
|
||||
@@ -10,7 +10,7 @@ from typing import List, Optional
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, status, File, UploadFile
|
||||
from fastapi import APIRouter, Depends, HTTPException, Request, status, File, UploadFile
|
||||
from fastapi.responses import FileResponse, Response
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
@@ -116,6 +116,7 @@ router = APIRouter(prefix="/company")
|
||||
summary="Create a new company",
|
||||
)
|
||||
async def create_company(
|
||||
request: Request,
|
||||
data: CompanyCreateDTO,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
@@ -124,10 +125,18 @@ async def create_company(
|
||||
|
||||
tenant_id = resolve_tenant_id_required(current_user, db=db)
|
||||
if tenant_id is None:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Hub admin: debe especificar tenant_id para crear una empresa",
|
||||
)
|
||||
# Prioridad: X-Tenant-Override del header (tenant seleccionado en el sidebar)
|
||||
override = request.headers.get("X-Tenant-Override")
|
||||
if override and str(override).strip().isdigit():
|
||||
tenant_id = int(override)
|
||||
# Fallback: campo tenant_id en el body (enviado por el frontend como respaldo)
|
||||
elif data.tenant_id:
|
||||
tenant_id = data.tenant_id
|
||||
else:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="Hub admin: selecciona un tenant en el sidebar antes de crear una empresa",
|
||||
)
|
||||
|
||||
service = CompanyService(db)
|
||||
new_company = service.create_company_manually(data, tenant_id=tenant_id)
|
||||
@@ -140,6 +149,7 @@ async def create_company(
|
||||
summary="Get companies with pagination",
|
||||
)
|
||||
async def list_companies(
|
||||
request: Request,
|
||||
page: int = 1,
|
||||
page_size: int = 50,
|
||||
name: Optional[str] = None,
|
||||
@@ -151,6 +161,11 @@ async def list_companies(
|
||||
_assert_permission_any_company(db, current_user, "cat_company.view")
|
||||
|
||||
tenant_id = resolve_tenant_id_required(current_user, db=db)
|
||||
# Hub admin: si hay X-Tenant-Override y aún no se resolvió tenant, filtra por ese tenant
|
||||
if tenant_id is None and is_hub_admin(current_user):
|
||||
override = request.headers.get("X-Tenant-Override")
|
||||
if override and str(override).strip().isdigit():
|
||||
tenant_id = int(override)
|
||||
|
||||
skip = (page - 1) * page_size
|
||||
filters = {}
|
||||
@@ -189,28 +204,27 @@ async def list_companies(
|
||||
summary="Get all companies for current tenant",
|
||||
)
|
||||
async def get_my_companies(
|
||||
request: Request,
|
||||
db: Session = Depends(get_core_db),
|
||||
current_user: dict = Depends(get_current_user),
|
||||
):
|
||||
"""
|
||||
Compañías accesibles: tenant del token/Hub (si existe) unión con membership en BD
|
||||
(``user_company_roles``, ``user_company_permissions``, ``user_tenants``).
|
||||
Un usuario solo con roles de app y sin ``tenant_id`` en /auth/me sigue pudiendo
|
||||
listar sus compañías asignadas.
|
||||
Hub admin: si hay X-Tenant-Override muestra solo ese tenant; si no, muestra todos.
|
||||
"""
|
||||
from core.security import collect_user_role_names
|
||||
user_roles = collect_user_role_names(current_user)
|
||||
|
||||
# Hub admin: visibilidad global sobre todas las compañías sin restricciones
|
||||
# de tenant ni licencia. El Hub ya validó el rol en /auth/me.
|
||||
# Hub admin: respeta X-Tenant-Override para filtrar por tenant seleccionado;
|
||||
# sin override devuelve todo (visibilidad global).
|
||||
if "hub_admin" in user_roles:
|
||||
service = CompanyService(db)
|
||||
all_companies = (
|
||||
db.query(Company)
|
||||
.filter(Company.deleted_at.is_(None))
|
||||
.order_by(Company.name)
|
||||
.all()
|
||||
)
|
||||
override = request.headers.get("X-Tenant-Override")
|
||||
query = db.query(Company).filter(Company.deleted_at.is_(None))
|
||||
if override and str(override).strip().isdigit():
|
||||
query = query.filter(Company.tenant_id == int(override))
|
||||
all_companies = query.order_by(Company.name).all()
|
||||
return [
|
||||
CompanyResponseDTO.model_validate(service.flatten_company_dto(c))
|
||||
for c in all_companies
|
||||
|
||||
Reference in New Issue
Block a user