Register all active platform services and base features in core DB so admin can manage them, add delivery/hospitality/sports-center backend phases, update apps catalog and production deploy tooling. Co-authored-by: Cursor <cursoragent@cursor.com>
304 lines
10 KiB
Python
304 lines
10 KiB
Python
"""Hospitality foundation repositories — Phase 12.0."""
|
|
from __future__ import annotations
|
|
|
|
from uuid import UUID
|
|
|
|
from sqlalchemy import select
|
|
|
|
from app.models.foundation import (
|
|
Branch,
|
|
BundleDefinition,
|
|
DiningArea,
|
|
DiningTable,
|
|
FeatureToggle,
|
|
HospitalityAuditLog,
|
|
HospitalityConfiguration,
|
|
HospitalityEvent,
|
|
HospitalityPermission,
|
|
HospitalityRole,
|
|
HospitalitySetting,
|
|
Menu,
|
|
MenuCategory,
|
|
MenuItem,
|
|
TenantBundle,
|
|
Venue,
|
|
)
|
|
from app.models.types import BundleKey, BundleStatus
|
|
from app.repositories.base import TenantBaseRepository
|
|
|
|
|
|
class VenueRepository(TenantBaseRepository[Venue]):
|
|
model = Venue
|
|
|
|
async def get_by_code(self, tenant_id: UUID, code: str) -> Venue | None:
|
|
stmt = select(Venue).where(
|
|
Venue.tenant_id == tenant_id,
|
|
Venue.code == code,
|
|
Venue.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class BranchRepository(TenantBaseRepository[Branch]):
|
|
model = Branch
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, venue_id: UUID, code: str
|
|
) -> Branch | None:
|
|
stmt = select(Branch).where(
|
|
Branch.tenant_id == tenant_id,
|
|
Branch.venue_id == venue_id,
|
|
Branch.code == code,
|
|
Branch.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class DiningAreaRepository(TenantBaseRepository[DiningArea]):
|
|
model = DiningArea
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, venue_id: UUID, code: str
|
|
) -> DiningArea | None:
|
|
stmt = select(DiningArea).where(
|
|
DiningArea.tenant_id == tenant_id,
|
|
DiningArea.venue_id == venue_id,
|
|
DiningArea.code == code,
|
|
DiningArea.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class DiningTableRepository(TenantBaseRepository[DiningTable]):
|
|
model = DiningTable
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, venue_id: UUID, code: str
|
|
) -> DiningTable | None:
|
|
stmt = select(DiningTable).where(
|
|
DiningTable.tenant_id == tenant_id,
|
|
DiningTable.venue_id == venue_id,
|
|
DiningTable.code == code,
|
|
DiningTable.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class MenuRepository(TenantBaseRepository[Menu]):
|
|
model = Menu
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, venue_id: UUID, code: str
|
|
) -> Menu | None:
|
|
stmt = select(Menu).where(
|
|
Menu.tenant_id == tenant_id,
|
|
Menu.venue_id == venue_id,
|
|
Menu.code == code,
|
|
Menu.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class MenuCategoryRepository(TenantBaseRepository[MenuCategory]):
|
|
model = MenuCategory
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, menu_id: UUID, code: str
|
|
) -> MenuCategory | None:
|
|
stmt = select(MenuCategory).where(
|
|
MenuCategory.tenant_id == tenant_id,
|
|
MenuCategory.menu_id == menu_id,
|
|
MenuCategory.code == code,
|
|
MenuCategory.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class MenuItemRepository(TenantBaseRepository[MenuItem]):
|
|
model = MenuItem
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, menu_id: UUID, code: str
|
|
) -> MenuItem | None:
|
|
stmt = select(MenuItem).where(
|
|
MenuItem.tenant_id == tenant_id,
|
|
MenuItem.menu_id == menu_id,
|
|
MenuItem.code == code,
|
|
MenuItem.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class BundleDefinitionRepository(TenantBaseRepository[BundleDefinition]):
|
|
model = BundleDefinition
|
|
|
|
async def get_by_key(
|
|
self, tenant_id: UUID, bundle_key: BundleKey
|
|
) -> BundleDefinition | None:
|
|
stmt = select(BundleDefinition).where(
|
|
BundleDefinition.tenant_id == tenant_id,
|
|
BundleDefinition.bundle_key == bundle_key,
|
|
BundleDefinition.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def get_by_code(self, tenant_id: UUID, code: str) -> BundleDefinition | None:
|
|
stmt = select(BundleDefinition).where(
|
|
BundleDefinition.tenant_id == tenant_id,
|
|
BundleDefinition.code == code,
|
|
BundleDefinition.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class TenantBundleRepository(TenantBaseRepository[TenantBundle]):
|
|
model = TenantBundle
|
|
|
|
async def get_active(
|
|
self, tenant_id: UUID, bundle_key: BundleKey, venue_id: UUID | None = None
|
|
) -> TenantBundle | None:
|
|
stmt = select(TenantBundle).where(
|
|
TenantBundle.tenant_id == tenant_id,
|
|
TenantBundle.bundle_key == bundle_key,
|
|
TenantBundle.venue_id == venue_id,
|
|
TenantBundle.status == BundleStatus.ACTIVE,
|
|
TenantBundle.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def list_active(self, tenant_id: UUID, venue_id: UUID | None = None):
|
|
clauses = [
|
|
TenantBundle.tenant_id == tenant_id,
|
|
TenantBundle.status == BundleStatus.ACTIVE,
|
|
TenantBundle.is_deleted.is_(False),
|
|
]
|
|
if venue_id is None:
|
|
clauses.append(TenantBundle.venue_id.is_(None))
|
|
else:
|
|
clauses.append(TenantBundle.venue_id == venue_id)
|
|
stmt = select(TenantBundle).where(*clauses)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalars().all()
|
|
|
|
|
|
class FeatureToggleRepository(TenantBaseRepository[FeatureToggle]):
|
|
model = FeatureToggle
|
|
|
|
async def get_by_key(
|
|
self, tenant_id: UUID, feature_key: str, venue_id: UUID | None = None
|
|
) -> FeatureToggle | None:
|
|
stmt = select(FeatureToggle).where(
|
|
FeatureToggle.tenant_id == tenant_id,
|
|
FeatureToggle.feature_key == feature_key,
|
|
FeatureToggle.venue_id == venue_id,
|
|
FeatureToggle.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
async def list_enabled(self, tenant_id: UUID, venue_id: UUID | None = None):
|
|
clauses = [
|
|
FeatureToggle.tenant_id == tenant_id,
|
|
FeatureToggle.enabled.is_(True),
|
|
FeatureToggle.is_deleted.is_(False),
|
|
]
|
|
if venue_id is None:
|
|
clauses.append(FeatureToggle.venue_id.is_(None))
|
|
else:
|
|
clauses.append(FeatureToggle.venue_id == venue_id)
|
|
stmt = select(FeatureToggle).where(*clauses)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalars().all()
|
|
|
|
|
|
class HospitalityRoleRepository(TenantBaseRepository[HospitalityRole]):
|
|
model = HospitalityRole
|
|
|
|
async def get_by_code(self, tenant_id: UUID, code: str) -> HospitalityRole | None:
|
|
stmt = select(HospitalityRole).where(
|
|
HospitalityRole.tenant_id == tenant_id,
|
|
HospitalityRole.code == code,
|
|
HospitalityRole.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class HospitalityPermissionRepository(TenantBaseRepository[HospitalityPermission]):
|
|
model = HospitalityPermission
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, code: str
|
|
) -> HospitalityPermission | None:
|
|
stmt = select(HospitalityPermission).where(
|
|
HospitalityPermission.tenant_id == tenant_id,
|
|
HospitalityPermission.code == code,
|
|
HospitalityPermission.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class HospitalityConfigurationRepository(TenantBaseRepository[HospitalityConfiguration]):
|
|
model = HospitalityConfiguration
|
|
|
|
async def get_by_code(
|
|
self, tenant_id: UUID, code: str
|
|
) -> HospitalityConfiguration | None:
|
|
stmt = select(HospitalityConfiguration).where(
|
|
HospitalityConfiguration.tenant_id == tenant_id,
|
|
HospitalityConfiguration.code == code,
|
|
HospitalityConfiguration.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class HospitalityEventRepository(TenantBaseRepository[HospitalityEvent]):
|
|
model = HospitalityEvent
|
|
|
|
|
|
class HospitalitySettingRepository(TenantBaseRepository[HospitalitySetting]):
|
|
model = HospitalitySetting
|
|
|
|
async def get_by_key(
|
|
self, tenant_id: UUID, key: str, venue_id: UUID | None = None
|
|
) -> HospitalitySetting | None:
|
|
stmt = select(HospitalitySetting).where(
|
|
HospitalitySetting.tenant_id == tenant_id,
|
|
HospitalitySetting.key == key,
|
|
HospitalitySetting.venue_id == venue_id,
|
|
HospitalitySetting.is_deleted.is_(False),
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalar_one_or_none()
|
|
|
|
|
|
class HospitalityAuditLogRepository(TenantBaseRepository[HospitalityAuditLog]):
|
|
model = HospitalityAuditLog
|
|
|
|
async def list_for_entity(
|
|
self, tenant_id: UUID, entity_type: str, entity_id: UUID, *, limit: int = 100
|
|
):
|
|
stmt = (
|
|
select(HospitalityAuditLog)
|
|
.where(
|
|
HospitalityAuditLog.tenant_id == tenant_id,
|
|
HospitalityAuditLog.entity_type == entity_type,
|
|
HospitalityAuditLog.entity_id == entity_id,
|
|
)
|
|
.limit(limit)
|
|
)
|
|
result = await self.session.execute(stmt)
|
|
return result.scalars().all()
|