feat: projects and boards

This commit is contained in:
2025-02-07 20:08:14 +04:00
parent 2aa84837e4
commit 9ee3f87de9
25 changed files with 1312 additions and 387 deletions

119
services/board.py Normal file
View File

@@ -0,0 +1,119 @@
from datetime import datetime
from typing import Optional
from sqlalchemy import select, and_, func
from models import Board, Deal
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(Deal.id))
.where(
and_(
Deal.board_id == board_id,
Deal.is_deleted == False,
Deal.is_completed == False,
)
)
)
return (await self.session.scalars(stmt)).first()
async def _count_deals(self, board_id: int) -> int:
stmt = (
select(func.count(Deal.id))
.where(Deal.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.deal_statuses:
status.is_deleted = True
await self.session.commit()
return DeleteBoardResponse(ok=True, message="Доска успешно удалена")