feat: Implement license and tenant management APIs

- Added endpoints for license management including creation, retrieval, update, validation, and usage tracking.
- Developed service layer for business logic related to licenses.
- Introduced tenant management APIs for creating, updating, listing, and deleting tenants.
- Implemented user-tenant relationship management with endpoints for adding, removing, and updating user roles in tenants.
- Created DTOs for data transfer between layers and models for ORM mapping.
- Enhanced logging and error handling across services.
This commit is contained in:
2025-12-09 11:51:18 -06:00
parent 3992a9436b
commit 44eef08445
23 changed files with 25 additions and 25 deletions

View File

@@ -31,7 +31,7 @@ class Company(Base, TimestampMixin):
# Primary key
id: Mapped[int] = mapped_column(Integer, primary_key=True)
tenant_id: Mapped[int] = mapped_column(Integer, ForeignKey("a76.tenants.id"), nullable=False, index=True)
tenant_id: Mapped[int] = mapped_column(Integer, ForeignKey("core.tenants.id"), nullable=False, index=True)
# Información básica de la empresa
name: Mapped[Optional[str]] = mapped_column(String(255))

View File

@@ -8,7 +8,7 @@ from fastapi import APIRouter
from .customs_brokers.routes import router as customs_broker_router
# Importar routers de módulos
from .auth import router as auth_router
from ..core.auth import router as auth_router
from .classes import router as classes_router
from .clients_and_providers import router as client_and_provider_router
from .general_catalogs.company import router as company_router
@@ -17,7 +17,7 @@ from .transportation.drivers.routes import router as drivers_router
from .general_catalogs.exchange_rate.routes import router as exchange_rate_router
from .general_catalogs.identifiers.routes import router as identifiers_router
from .fraction_rule_octave.routes import router as fraction_rule_octave_router
from .licenses import router as licenses_router
from ..core.licenses import router as licenses_router
from .general_catalogs.packages.routes import router as package_router
from .general_catalogs.ports.routes import router as ports_router
from .parts import router as parts_router
@@ -38,10 +38,10 @@ from .general_catalogs.error_catalogs.routes import router as error_catalogs_rou
from .general_catalogs.doda.routes import router as doda_router
from .general_catalogs.prevalidators.routes import router as prevalidators_router
from .general_catalogs.electronic_notices.routes import router as electronic_notices_router
from .tenants import router as tenants_router
from ..core.tenants import router as tenants_router
from .transportation.trailers.routes import router as trailers_router
from .transportation.transporters.routes import router as transporters_router
from .user_tenant.routes import router as user_tenant_router
from ..core.user_tenant.routes import router as user_tenant_router
from .transportation.vehicles.routes import router as vehicles_router
# Router principal

View File

@@ -4,8 +4,8 @@ Servicio de autenticación con Keycloak
import logging
from api.v1.modules.a76.tenants.service import TenantService
from api.v1.modules.a76.user_tenant.service import UserTenantService
from api.v1.modules.core.tenants.service import TenantService
from api.v1.modules.core.user_tenant.service import UserTenantService
from core.config import settings
from fastapi import HTTPException
from keycloak import KeycloakAdmin, KeycloakOpenID
@@ -266,7 +266,7 @@ class AuthService:
"""
try:
# Verificar que el tenant existe
from api.v1.modules.a76.tenants.service import TenantService
from api.v1.modules.core.tenants.service import TenantService
tenant_service = TenantService(self.db)
tenant = tenant_service.get_tenant_by_slug(register_data.tenant_slug)
@@ -319,7 +319,7 @@ class AuthService:
# Agregar el usuario al tenant en la base de datos
try:
from api.v1.modules.a76.user_tenant.service import UserTenantService
from api.v1.modules.core.user_tenant.service import UserTenantService
user_tenant_service = UserTenantService(self.db)
user_tenant_service.add_user_to_tenant(

View File

@@ -36,11 +36,11 @@ class License(Base, TimestampMixin):
"""
__tablename__ = "licenses"
__table_args__ = {"schema": "a76"}
__table_args__ = {"schema": "core"}
id = Column(Integer, primary_key=True, index=True)
tenant_id = Column(
Integer, ForeignKey("a76.tenants.id"), nullable=False, unique=True, index=True
Integer, ForeignKey("core.tenants.id"), nullable=False, unique=True, index=True
)
# Plan y características
@@ -74,11 +74,11 @@ class LicenseUsage(Base, TimestampMixin):
"""
__tablename__ = "license_usage"
__table_args__ = {"schema": "a76"}
__table_args__ = {"schema": "core"}
id = Column(Integer, primary_key=True, index=True)
tenant_id = Column(
Integer, ForeignKey("a76.tenants.id"), nullable=False, index=True
Integer, ForeignKey("core.tenants.id"), nullable=False, index=True
)
# Métricas de uso

View File

@@ -13,7 +13,7 @@ from sqlalchemy import Integer, String, Text
from sqlalchemy.orm import Mapped, relationship
if TYPE_CHECKING:
from api.v1.modules.a76.user_tenant.models import UserTenant
from api.v1.modules.core.user_tenant.models import UserTenant
class TenantType(enum.Enum):
@@ -30,7 +30,7 @@ class Tenant(Base, TimestampMixin):
"""
__tablename__ = "tenants"
__table_args__ = {"schema": "a76", "extend_existing": True}
__table_args__ = {"schema": "core", "extend_existing": True}
id = Column(Integer, primary_key=True, index=True)
name = Column(String(255), nullable=False, index=True)

View File

@@ -10,7 +10,7 @@ from sqlalchemy import Boolean, ForeignKeyConstraint, String, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column, relationship
if TYPE_CHECKING:
from api.v1.modules.a76.tenants.models import Tenant
from api.v1.modules.core.tenants.models import Tenant
class UserTenant(Base, TenantScopedMixin, TimestampMixin):
@@ -26,7 +26,7 @@ class UserTenant(Base, TenantScopedMixin, TimestampMixin):
UniqueConstraint(
"keycloak_user_id", "tenant_id", "company_id", name="uq_user_tenant"
),
{"schema": "a76", "extend_existing": True},
{"schema": "core", "extend_existing": True},
)
# Primary Key