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

128
services/status.py Normal file
View File

@@ -0,0 +1,128 @@
from typing import Optional
from sqlalchemy import select, and_, func
from models import DealStatus, Deal
from schemas.status import *
from services.base import BaseService
class StatusService(BaseService):
async def _get_statuses_for_board(self, board_id: int) -> list[DealStatus]:
stmt = (
select(DealStatus)
.where(
and_(
DealStatus.board_id == board_id,
DealStatus.is_deleted == False,
)
)
.order_by(DealStatus.ordinal_number)
)
statuses = (await self.session.scalars(stmt)).all()
return list(statuses)
async def _get_status_by_id(self, status_id: int) -> Optional[DealStatus]:
stmt = (
select(DealStatus)
.where(DealStatus.id == status_id)
)
status = await self.session.scalar(stmt)
return status
async def create_status(self, request: CreateStatusRequest) -> CreateStatusResponse:
statuses = await self._get_statuses_for_board(request.status.board_id)
if len(statuses) == 0:
ordinal_number = 1
else:
statuses[-1].is_finishing = False
ordinal_number = statuses[-1].ordinal_number + 1
status = DealStatus(
**request.status.model_dump(),
ordinal_number=ordinal_number,
is_finishing=True,
)
self.session.add(status)
await self.session.commit()
return CreateStatusResponse(ok=True, message="Статус успешно создан")
async def update_status(self, request: UpdateStatusRequest) -> UpdateStatusResponse:
status = await self._get_status_by_id(request.status.id)
if not status:
return UpdateStatusResponse(ok=False, message=f"Статус с ID {request.status.id} не найден")
status.name = request.status.name
await self.session.commit()
return UpdateStatusResponse(ok=True, message="Статус успешно изменен")
async def update_status_order(self, request: UpdateStatusOrderRequest) -> UpdateStatusOrderResponse:
statuses = await self._get_statuses_for_board(request.board_id)
status_idx = 0
while status_idx < len(statuses) and statuses[status_idx].id != request.status_id:
status_idx += 1
if status_idx == len(statuses):
return UpdateStatusOrderResponse(ok=False, message=f"Статус с ID {request.status_id} не найден")
status = statuses.pop(status_idx)
statuses.insert(request.new_ordinal_number - 1, status)
new_ordinal_number = 1
for status in statuses:
status.ordinal_number = new_ordinal_number
status.is_finishing = False
new_ordinal_number += 1
statuses[-1].is_finishing = True
await self.session.commit()
return UpdateStatusOrderResponse(ok=True, message="Порядок статусов изменен")
async def _count_deals_in_progress(self, status_id: int) -> int:
stmt = (
select(func.count(Deal.id))
.where(
and_(
Deal.current_status_id == status_id,
Deal.is_deleted == False,
Deal.is_completed == False,
)
)
)
return (await self.session.scalars(stmt)).first()
async def _count_deals(self, status_id: int) -> int:
stmt = (
select(func.count(Deal.id))
.where(Deal.current_status_id == status_id)
)
return (await self.session.scalars(stmt)).first()
async def _set_finishing_flag_to_prev_status(self, status: DealStatus):
statuses = await self._get_statuses_for_board(status.board_id)
if len(statuses) < 2:
return
statuses[-2].is_finishing = True
statuses[-1].is_finishing = False
async def delete_status(self, status_id: int) -> DeleteStatusResponse:
status = await self._get_status_by_id(status_id)
if not status:
return DeleteStatusResponse(ok=False, message=f"Статус с ID {status_id} не найден")
count_deals_in_progress = await self._count_deals_in_progress(status_id)
if count_deals_in_progress != 0:
return DeleteStatusResponse(ok=False, message="Нельзя удалить статус с активными сделками")
if status.is_finishing:
await self._set_finishing_flag_to_prev_status(status)
count_deals = await self._count_deals(status_id)
if count_deals == 0:
await self.session.delete(status)
else:
status.is_deleted = True
await self.session.commit()
return DeleteStatusResponse(ok=True, message="Статус успешно удален")