from __future__ import annotations from typing import TypeVar from uuid import UUID from sqlalchemy.orm import Session from fastapi import HTTPException, status from app.models.contact import Contact from app.models.customer import Customer from app.models.device import Device from app.models.equipment import Equipment from app.models.location import Location from app.models.user import User, UserRole from app.models.validation import Validation from app.repositories.base import Repository from app.repositories.domain import ( ContactRepository, CustomerRepository, DeviceRepository, EquipmentRepository, LocationRepository, UserRepository, ValidationRepository, ) ModelT = TypeVar("ModelT") class CrudService: def __init__(self, repository: Repository[ModelT]) -> None: self.repository = repository def list(self, page: int = 1, page_size: int = 20, search: str | None = None) -> dict: safe_page = max(page, 1) safe_page_size = min(max(page_size, 1), 100) offset = (safe_page - 1) * safe_page_size return { "items": self.repository.list(safe_page_size, offset, search), "total": self.repository.count(search), "page": safe_page, "page_size": safe_page_size, } def create(self, data: dict) -> ModelT: data = self._normalize(data) return self.repository.add(self.repository.model(**data)) def update(self, item_id: str, data: dict) -> ModelT: data = self._normalize(data) item = self.repository.get(item_id) if item is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Resource not found") if isinstance(item, Validation) and item.status in {"FREIGEGEBEN", "ABGESCHLOSSEN"}: raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail="Freigegebene oder abgeschlossene Validierungen sind schreibgeschuetzt") for key, value in data.items(): setattr(item, key, value) return item def _normalize(self, data: dict) -> dict: normalized = {} for key, value in data.items(): if key.endswith("_id") and value == "": normalized[key] = None elif isinstance(value, UUID): normalized[key] = str(value) elif isinstance(value, list): normalized[key] = [str(item) if isinstance(item, UUID) else item for item in value] else: normalized[key] = value return normalized def delete(self, item_id: str) -> None: item = self.repository.get(item_id) if item is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Resource not found") self.repository.delete(item) class DomainServices: def __init__(self, session: Session) -> None: self.users: CrudService[User] = CrudService(UserRepository(session)) self.customers: CrudService[Customer] = CrudService(CustomerRepository(session)) self.locations: CrudService[Location] = CrudService(LocationRepository(session)) self.contacts: CrudService[Contact] = CrudService(ContactRepository(session)) self.devices: CrudService[Device] = CrudService(DeviceRepository(session)) self.equipment: CrudService[Equipment] = CrudService(EquipmentRepository(session)) self.validations: CrudService[Validation] = CrudService(ValidationRepository(session))