New enterprise feature

This commit is contained in:
Urtzi Alfaro
2025-11-30 09:12:40 +01:00
parent f9d0eec6ec
commit 972db02f6d
176 changed files with 19741 additions and 1361 deletions

View File

@@ -381,3 +381,188 @@ class TenantRepository(TenantBaseRepository):
async def activate_tenant(self, tenant_id: str) -> Optional[Tenant]:
"""Activate a tenant"""
return await self.activate_record(tenant_id)
async def get_child_tenants(self, parent_tenant_id: str) -> List[Tenant]:
"""Get all child tenants for a parent tenant"""
try:
return await self.get_multi(
filters={"parent_tenant_id": parent_tenant_id, "is_active": True},
order_by="created_at",
order_desc=False
)
except Exception as e:
logger.error("Failed to get child tenants",
parent_tenant_id=parent_tenant_id,
error=str(e))
raise DatabaseError(f"Failed to get child tenants: {str(e)}")
async def get_child_tenant_count(self, parent_tenant_id: str) -> int:
"""Get count of child tenants for a parent tenant"""
try:
child_tenants = await self.get_child_tenants(parent_tenant_id)
return len(child_tenants)
except Exception as e:
logger.error("Failed to get child tenant count",
parent_tenant_id=parent_tenant_id,
error=str(e))
return 0
async def get_user_tenants_with_hierarchy(self, user_id: str) -> List[Dict[str, Any]]:
"""
Get all tenants a user has access to, organized in hierarchy.
Returns parent tenants with their children nested.
"""
try:
# Get all tenants where user is owner or member
query_text = """
SELECT DISTINCT t.*
FROM tenants t
LEFT JOIN tenant_members tm ON t.id = tm.tenant_id
WHERE (t.owner_id = :user_id OR tm.user_id = :user_id)
AND t.is_active = true
ORDER BY t.tenant_type DESC, t.created_at ASC
"""
result = await self.session.execute(text(query_text), {"user_id": user_id})
tenants = []
for row in result.fetchall():
record_dict = dict(row._mapping)
tenant = self.model(**record_dict)
tenants.append(tenant)
# Organize into hierarchy
tenant_hierarchy = []
parent_map = {}
# First pass: collect all parent/standalone tenants
for tenant in tenants:
if tenant.tenant_type in ['parent', 'standalone']:
tenant_dict = {
'id': str(tenant.id),
'name': tenant.name,
'subdomain': tenant.subdomain,
'tenant_type': tenant.tenant_type,
'business_type': tenant.business_type,
'business_model': tenant.business_model,
'city': tenant.city,
'is_active': tenant.is_active,
'children': [] if tenant.tenant_type == 'parent' else None
}
tenant_hierarchy.append(tenant_dict)
parent_map[str(tenant.id)] = tenant_dict
# Second pass: attach children to their parents
for tenant in tenants:
if tenant.tenant_type == 'child' and tenant.parent_tenant_id:
parent_id = str(tenant.parent_tenant_id)
if parent_id in parent_map:
child_dict = {
'id': str(tenant.id),
'name': tenant.name,
'subdomain': tenant.subdomain,
'tenant_type': 'child',
'parent_tenant_id': parent_id,
'city': tenant.city,
'is_active': tenant.is_active
}
parent_map[parent_id]['children'].append(child_dict)
return tenant_hierarchy
except Exception as e:
logger.error("Failed to get user tenants with hierarchy",
user_id=user_id,
error=str(e))
return []
async def get_tenants_by_session_id(self, session_id: str) -> List[Tenant]:
"""
Get tenants associated with a specific demo session using the demo_session_id field.
"""
try:
return await self.get_multi(
filters={
"demo_session_id": session_id,
"is_active": True
},
order_by="created_at",
order_desc=True
)
except Exception as e:
logger.error("Failed to get tenants by session ID",
session_id=session_id,
error=str(e))
raise DatabaseError(f"Failed to get tenants by session ID: {str(e)}")
async def get_professional_demo_tenants(self, session_id: str) -> List[Tenant]:
"""
Get professional demo tenants filtered by session.
Args:
session_id: Required demo session ID to filter tenants
Returns:
List of professional demo tenants for this specific session
"""
try:
filters = {
"business_model": "professional_bakery",
"is_demo": True,
"is_active": True,
"demo_session_id": session_id # Always filter by session
}
return await self.get_multi(
filters=filters,
order_by="created_at",
order_desc=True
)
except Exception as e:
logger.error("Failed to get professional demo tenants",
session_id=session_id,
error=str(e))
raise DatabaseError(f"Failed to get professional demo tenants: {str(e)}")
async def get_enterprise_demo_tenants(self, session_id: str) -> List[Tenant]:
"""
Get enterprise demo tenants (parent and children) filtered by session.
Args:
session_id: Required demo session ID to filter tenants
Returns:
List of enterprise demo tenants (1 parent + 3 children) for this specific session
"""
try:
# Get enterprise demo parent tenants for this session
parent_tenants = await self.get_multi(
filters={
"tenant_type": "parent",
"is_demo": True,
"is_active": True,
"demo_session_id": session_id # Always filter by session
},
order_by="created_at",
order_desc=True
)
# Get child tenants for the enterprise demo session
child_tenants = await self.get_multi(
filters={
"tenant_type": "child",
"is_demo": True,
"is_active": True,
"demo_session_id": session_id # Always filter by session
},
order_by="created_at",
order_desc=True
)
# Combine parent and child tenants
return parent_tenants + child_tenants
except Exception as e:
logger.error("Failed to get enterprise demo tenants",
session_id=session_id,
error=str(e))
raise DatabaseError(f"Failed to get enterprise demo tenants: {str(e)}")