from datetime import datetime from typing import Optional from sqlalchemy import select, and_, func from models import Board, Card from schemas.board import * from services.base import BaseService class BoardService(BaseService): async def _get_boards_for_project(self, project_id: int) -> list[Board]: stmt = ( select(Board) .where( and_( Board.is_deleted == False, Board.project_id == project_id, ) ) .order_by(Board.ordinal_number) ) boards = (await self.session.scalars(stmt)).all() return list(boards) async def get_boards(self, project_id: int) -> GetBoardsResponse: boards = await self._get_boards_for_project(project_id) return GetBoardsResponse(boards=boards) async def create_board(self, request: CreateBoardRequest) -> CreateBoardResponse: boards = await self._get_boards_for_project(request.board.project_id) if len(boards) == 0: ordinal_number = 1 else: ordinal_number = boards[-1].ordinal_number + 1 board = Board( **request.board.model_dump(), created_at=datetime.now(), ordinal_number=ordinal_number, ) self.session.add(board) await self.session.commit() return CreateBoardResponse(ok=True, message="Доска успешно создана") async def _get_board_by_id(self, board_id: int) -> Optional[Board]: return await self.session.get(Board, board_id) async def update_board(self, request: UpdateBoardRequest) -> UpdateBoardResponse: board = await self._get_board_by_id(request.board.id) if not board: return UpdateBoardResponse(ok=False, message=f"Доска с ID {request.board.id} не найдена") board.name = request.board.name await self.session.commit() return UpdateBoardResponse(ok=True, message="Доска успешно обновлена") async def update_board_order(self, request: UpdateBoardOrderRequest) -> UpdateBoardOrderResponse: boards = await self._get_boards_for_project(request.project_id) board_idx = 0 while board_idx < len(boards) and boards[board_idx].id != request.board_id: board_idx += 1 if board_idx == len(boards): return UpdateBoardOrderResponse(ok=False, message=f"Доска с ID {request.board_id} не найдена в проекте") board = boards.pop(board_idx) boards.insert(request.new_ordinal_number - 1, board) new_ordinal_number = 1 for board in boards: board.ordinal_number = new_ordinal_number new_ordinal_number += 1 await self.session.commit() return UpdateBoardOrderResponse(ok=True, message="Порядок досок изменен") async def _count_deals_in_progress(self, board_id: int) -> int: stmt = ( select(func.count(Card.id)) .where( and_( Card.board_id == board_id, Card.is_deleted == False, Card.is_completed == False, ) ) ) return (await self.session.scalars(stmt)).first() async def _count_deals(self, board_id: int) -> int: stmt = ( select(func.count(Card.id)) .where(Card.board_id == board_id) ) return (await self.session.scalars(stmt)).first() async def delete_board(self, board_id: int) -> DeleteBoardResponse: board = await self._get_board_by_id(board_id) if not board: return DeleteBoardResponse(ok=False, message=f"Доска с ID {board_id} не найдена") count_deals_in_progress = await self._count_deals_in_progress(board_id) if count_deals_in_progress != 0: return DeleteBoardResponse( ok=False, message=f"Нельзя удалить доску с активными сделками", ) count_deals = await self._count_deals(board_id) if count_deals == 0: await self.session.delete(board) else: board.is_deleted = True for status in board.statuses: status.is_deleted = True await self.session.commit() return DeleteBoardResponse(ok=True, message="Доска успешно удалена")