"""CRUD service for CustomFieldDefinition.""" from __future__ import annotations import uuid from typing import Any from sqlalchemy import select, delete from sqlalchemy.ext.asyncio import AsyncSession from app.core.visibility import apply_visibility_filter, check_single_entity_access from app.models.custom_field_definition import CustomFieldDefinition async def list_definitions( db: AsyncSession, tenant_id: uuid.UUID, entity: str | None = None, user_id: uuid.UUID | None = None, is_system_admin: bool = False, ) -> list[CustomFieldDefinition]: """List custom field definitions for a tenant, optionally filtered by entity.""" stmt = select(CustomFieldDefinition).where( CustomFieldDefinition.tenant_id == tenant_id, CustomFieldDefinition.is_active == True, # noqa: E712 ) if entity: stmt = stmt.where(CustomFieldDefinition.entity == entity) if user_id and not is_system_admin: stmt = await apply_visibility_filter( db, stmt, "custom_field_definition", CustomFieldDefinition, user_id, tenant_id, is_system_admin ) stmt = stmt.order_by(CustomFieldDefinition.sort_order, CustomFieldDefinition.name) result = await db.execute(stmt) return list(result.scalars().all()) async def get_definition( db: AsyncSession, tenant_id: uuid.UUID, definition_id: uuid.UUID, user_id: uuid.UUID | None = None, is_system_admin: bool = False, ) -> CustomFieldDefinition | None: """Get a single custom field definition by ID.""" stmt = select(CustomFieldDefinition).where( CustomFieldDefinition.id == definition_id, CustomFieldDefinition.tenant_id == tenant_id, ) result = await db.execute(stmt) definition = result.scalar_one_or_none() if definition is None: return None if user_id and not is_system_admin: has_access = await check_single_entity_access( db, "custom_field_definition", definition.id, user_id, tenant_id, "read", is_system_admin ) if not has_access: raise PermissionError("No access") return definition async def create_definition( db: AsyncSession, tenant_id: uuid.UUID, user_id: uuid.UUID, data: dict[str, Any], ) -> CustomFieldDefinition: """Create a new custom field definition.""" definition = CustomFieldDefinition( tenant_id=tenant_id, entity=data["entity"], name=data["name"], label=data["label"], field_type=data["field_type"], options=data.get("options"), default_value=data.get("default_value"), required=data.get("required", False), is_active=data.get("is_active", True), sort_order=data.get("sort_order", 0), created_by=user_id, updated_by=user_id, owner_id=user_id, ) db.add(definition) await db.flush() await db.refresh(definition) return definition async def update_definition( db: AsyncSession, tenant_id: uuid.UUID, definition_id: uuid.UUID, data: dict[str, Any], user_id: uuid.UUID | None = None, is_system_admin: bool = False, ) -> CustomFieldDefinition | None: """Update an existing custom field definition.""" definition = await get_definition(db, tenant_id, definition_id, user_id, is_system_admin) if definition is None: return None if not is_system_admin: has_access = await check_single_entity_access( db, "custom_field_definition", definition.id, user_id, tenant_id, "write", is_system_admin ) if not has_access: raise PermissionError("No access") update_fields = ["label", "field_type", "options", "default_value", "required", "is_active", "sort_order"] for field in update_fields: if field in data: setattr(definition, field, data[field]) if user_id is not None: definition.updated_by = user_id await db.flush() await db.refresh(definition) return definition async def delete_definition( db: AsyncSession, tenant_id: uuid.UUID, definition_id: uuid.UUID, user_id: uuid.UUID | None = None, is_system_admin: bool = False, ) -> bool: """Delete a custom field definition.""" stmt = select(CustomFieldDefinition).where( CustomFieldDefinition.id == definition_id, CustomFieldDefinition.tenant_id == tenant_id, ) result = await db.execute(stmt) definition = result.scalar_one_or_none() if definition is None: return False if not is_system_admin: has_access = await check_single_entity_access( db, "custom_field_definition", definition.id, user_id, tenant_id, "admin", is_system_admin ) if not has_access: raise PermissionError("No access") await db.delete(definition) await db.flush() return True