212 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			212 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
from sqlalchemy import select, and_, delete, or_
 | 
						||
from sqlalchemy.orm import selectinload
 | 
						||
 | 
						||
from models import Department, DepartmentSection, User, UserDepartmentSection
 | 
						||
from schemas.department import *
 | 
						||
from services.base import BaseService
 | 
						||
 | 
						||
 | 
						||
class DepartmentService(BaseService):
 | 
						||
    async def get_departments(self) -> GetDepartmentsResponse:
 | 
						||
        sections_selectinload = selectinload(Department.sections)
 | 
						||
        for _ in range(10):
 | 
						||
            sections_selectinload = sections_selectinload.selectinload(DepartmentSection.sections)
 | 
						||
 | 
						||
        stmt = (
 | 
						||
            select(Department)
 | 
						||
            .options(
 | 
						||
                sections_selectinload,
 | 
						||
                selectinload(Department.sections)
 | 
						||
                .selectinload(DepartmentSection.users)
 | 
						||
                .selectinload(UserDepartmentSection.user)
 | 
						||
                .noload(User.department_sections),
 | 
						||
            )
 | 
						||
            .order_by(Department.name)
 | 
						||
        )
 | 
						||
        departments = (await self.session.execute(stmt)).scalars().all()
 | 
						||
        return GetDepartmentsResponse(departments=departments)
 | 
						||
 | 
						||
    async def _get_department(self, filter_condition) -> Optional[Department]:
 | 
						||
        stmt = (
 | 
						||
            select(Department)
 | 
						||
            .where(filter_condition)
 | 
						||
            .options(selectinload(Department.sections))
 | 
						||
        )
 | 
						||
        departments = (await self.session.execute(stmt)).one_or_none()
 | 
						||
        return departments[0] if departments else None
 | 
						||
 | 
						||
    async def _get_department_by_name(self, name: str) -> Optional[Department]:
 | 
						||
        return await self._get_department(Department.name == name)
 | 
						||
 | 
						||
    async def _get_department_by_id(self, department_id: int) -> Optional[Department]:
 | 
						||
        return await self._get_department(Department.id == department_id)
 | 
						||
 | 
						||
    async def create_department(self, request: CreateDepartmentRequest) -> CreateDepartmentResponse:
 | 
						||
        department = await self._get_department_by_name(request.department.name)
 | 
						||
        if department:
 | 
						||
            return CreateDepartmentResponse(ok=False, message="Департамент с таким названием уже существует")
 | 
						||
 | 
						||
        department = Department(name=request.department.name)
 | 
						||
        self.session.add(department)
 | 
						||
        await self.session.commit()
 | 
						||
        return CreateDepartmentResponse(ok=True, message="Департамент успешно создан")
 | 
						||
 | 
						||
    async def update_department(self, request: UpdateDepartmentRequest) -> UpdateDepartmentResponse:
 | 
						||
        department_same_name = await self._get_department_by_name(request.department.name)
 | 
						||
        if department_same_name and department_same_name.id != request.department.id:
 | 
						||
            return UpdateDepartmentResponse(ok=False, message="Департамент с данным именем уже существует")
 | 
						||
 | 
						||
        department = await self._get_department_by_id(request.department.id)
 | 
						||
        if not department:
 | 
						||
            return UpdateDepartmentResponse(ok=False, message=f"Департамент с ID {request.department.id} не найден")
 | 
						||
 | 
						||
        department.name = request.department.name
 | 
						||
        await self.session.commit()
 | 
						||
        return UpdateDepartmentResponse(ok=True, message="Департамент успешно изменен")
 | 
						||
 | 
						||
    async def delete_department(self, department_id: int) -> DeleteDepartmentResponse:
 | 
						||
        department = await self.session.get(Department, department_id)
 | 
						||
        if not department:
 | 
						||
            return CreateDepartmentResponse(ok=False, message=f"Департамент с ID {department_id} не найден")
 | 
						||
 | 
						||
        await self.session.delete(department)
 | 
						||
        await self.session.commit()
 | 
						||
        return DeleteDepartmentResponse(ok=True, message="Департамент успешно удален")
 | 
						||
 | 
						||
    async def get_sections(self) -> GetDepartmentSectionsResponse:
 | 
						||
        stmt = select(DepartmentSection)
 | 
						||
        sections = (await self.session.execute(stmt)).scalars().all()
 | 
						||
        return GetDepartmentSectionsResponse(department_sections=sections)
 | 
						||
 | 
						||
    async def _get_section(self, filter_condition) -> Optional[DepartmentSection]:
 | 
						||
        stmt = (
 | 
						||
            select(DepartmentSection)
 | 
						||
            .where(filter_condition)
 | 
						||
            .options(selectinload(DepartmentSection.users))
 | 
						||
        )
 | 
						||
        departments = (await self.session.execute(stmt)).one_or_none()
 | 
						||
        return departments[0] if departments else None
 | 
						||
 | 
						||
    async def _get_section_by_name(
 | 
						||
            self,
 | 
						||
            name: str,
 | 
						||
            department_id: int = None,
 | 
						||
            parent_section_id: int = None,
 | 
						||
    ) -> Optional[DepartmentSection]:
 | 
						||
        return await self._get_section(and_(
 | 
						||
            DepartmentSection.name == name,
 | 
						||
            and_(
 | 
						||
                or_(department_id is None, DepartmentSection.department_id == department_id),
 | 
						||
                or_(parent_section_id is None, DepartmentSection.parent_department_section_id == parent_section_id),
 | 
						||
            )
 | 
						||
        ))
 | 
						||
 | 
						||
    async def _get_section_by_id(self, section_id: int) -> Optional[DepartmentSection]:
 | 
						||
        return await self._get_section(DepartmentSection.id == section_id)
 | 
						||
 | 
						||
    async def create_department_section(self, request: CreateDepartmentSectionRequest) -> CreateDepartmentSectionResponse:
 | 
						||
        section = await self._get_section_by_name(
 | 
						||
            request.section.name,
 | 
						||
            department_id=request.section.department_id,
 | 
						||
            parent_section_id=request.section.parent_department_section_id,
 | 
						||
        )
 | 
						||
        if section:
 | 
						||
            return CreateDepartmentSectionResponse(
 | 
						||
                ok=False,
 | 
						||
                message="Отдел с таким названием уже существует в департаменте",
 | 
						||
            )
 | 
						||
 | 
						||
        section = DepartmentSection(
 | 
						||
            name=request.section.name,
 | 
						||
            department_id=request.section.department_id,
 | 
						||
            parent_department_section_id=request.section.parent_department_section_id,
 | 
						||
        )
 | 
						||
        self.session.add(section)
 | 
						||
        await self.session.commit()
 | 
						||
        return CreateDepartmentSectionResponse(ok=True, message="Отдел успешно создан")
 | 
						||
 | 
						||
    async def update_department_section(self, request: UpdateDepartmentSectionRequest) -> UpdateDepartmentSectionResponse:
 | 
						||
        section = await self._get_section_by_id(request.section.id)
 | 
						||
        if not section:
 | 
						||
            return UpdateDepartmentSectionResponse(ok=False, message=f"Отдел с ID {request.section.id} не найден")
 | 
						||
 | 
						||
        section_same_name = await self._get_section_by_name(
 | 
						||
            request.section.name,
 | 
						||
            department_id=request.section.department_id,
 | 
						||
            parent_section_id=request.section.parent_department_section_id,
 | 
						||
        )
 | 
						||
        if section_same_name:
 | 
						||
            return UpdateDepartmentSectionResponse(ok=False, message="Отдел с данным именем уже существует")
 | 
						||
 | 
						||
        section.parent_department_section_id = request.section.parent_department_section_id
 | 
						||
        section.department_id = request.section.department_id
 | 
						||
        section.name = request.section.name
 | 
						||
        await self.session.commit()
 | 
						||
        return UpdateDepartmentSectionResponse(ok=True, message="Отдел успешно изменен")
 | 
						||
 | 
						||
    async def get_available_users_for_section(self, section_id: int) -> GetAvailableUsersForDepartmentSectionResponse:
 | 
						||
        sub_user_ids_in_section = (
 | 
						||
            select(UserDepartmentSection.user_id.label("user_id"))
 | 
						||
            .where(UserDepartmentSection.section_id == section_id)
 | 
						||
            .group_by(UserDepartmentSection.user_id)
 | 
						||
            .subquery()
 | 
						||
        )
 | 
						||
        stmt = (
 | 
						||
            select(User)
 | 
						||
            .join(sub_user_ids_in_section, sub_user_ids_in_section.c.user_id == User.id, isouter=True)
 | 
						||
            .where(and_(
 | 
						||
                sub_user_ids_in_section.c.user_id == None,
 | 
						||
                User.is_deleted == False,
 | 
						||
            ))
 | 
						||
        )
 | 
						||
        users = (await self.session.execute(stmt)).scalars().all()
 | 
						||
        return GetAvailableUsersForDepartmentSectionResponse(users=users)
 | 
						||
 | 
						||
    async def delete_department_section(self, section_id: int) -> DeleteDepartmentSectionResponse:
 | 
						||
        section = await self._get_section_by_id(section_id)
 | 
						||
        if not section:
 | 
						||
            return DeleteDepartmentSectionResponse(ok=False, message=f"Отдел с ID {section_id} не найден")
 | 
						||
 | 
						||
        await self.session.delete(section)
 | 
						||
        await self.session.commit()
 | 
						||
        return DeleteDepartmentSectionResponse(ok=True, message="Отдел успешно удален")
 | 
						||
 | 
						||
    async def _modify_user(self, request: AddUserRequest | DeleteUserRequest, is_adding: bool) -> tuple[bool, str]:
 | 
						||
        section = await self._get_section_by_id(request.section_id)
 | 
						||
        if not section:
 | 
						||
            return False, f"Отдел с ID {request.section_id} не найден"
 | 
						||
 | 
						||
        user = await self.session.get(User, request.user_id)
 | 
						||
        if not user:
 | 
						||
            return False, f"Пользователь с ID {request.user_id} не найден"
 | 
						||
 | 
						||
        if is_adding:
 | 
						||
            user_department_section = UserDepartmentSection(
 | 
						||
                user_id=request.user_id,
 | 
						||
                section_id=section.id,
 | 
						||
                is_chief=request.is_chief,
 | 
						||
            )
 | 
						||
            section.users.append(user_department_section)
 | 
						||
            message = f"Пользователь успешно добавлен в отдел"
 | 
						||
        else:
 | 
						||
            delete_stmt = (
 | 
						||
                delete(UserDepartmentSection)
 | 
						||
                .where(and_(
 | 
						||
                    UserDepartmentSection.user_id == request.user_id,
 | 
						||
                    UserDepartmentSection.section_id == request.section_id,
 | 
						||
                ))
 | 
						||
            )
 | 
						||
            await self.session.execute(delete_stmt)
 | 
						||
            message = f"Пользователь успешно удален из отдела"
 | 
						||
 | 
						||
        await self.session.commit()
 | 
						||
        return True, message
 | 
						||
 | 
						||
    async def add_user(self, request: AddUserRequest) -> AddUserResponse:
 | 
						||
        ok, message = await self._modify_user(request, True)
 | 
						||
        return AddUserResponse(ok=ok, message=message)
 | 
						||
 | 
						||
    async def delete_user(self, request: DeleteUserRequest) -> DeleteUserResponse:
 | 
						||
        ok, message = await self._modify_user(request, False)
 | 
						||
        return DeleteUserResponse(ok=ok, message=message)
 |