129 lines
4.8 KiB
Python
129 lines
4.8 KiB
Python
from typing import Optional
|
||
|
||
from sqlalchemy import select, and_, func
|
||
|
||
from models import CardStatus, Card
|
||
from schemas.status import *
|
||
from services.base import BaseService
|
||
|
||
|
||
class StatusService(BaseService):
|
||
async def _get_statuses_for_board(self, board_id: int) -> list[CardStatus]:
|
||
stmt = (
|
||
select(CardStatus)
|
||
.where(
|
||
and_(
|
||
CardStatus.board_id == board_id,
|
||
CardStatus.is_deleted == False,
|
||
)
|
||
)
|
||
.order_by(CardStatus.ordinal_number)
|
||
)
|
||
statuses = (await self.session.scalars(stmt)).all()
|
||
return list(statuses)
|
||
|
||
async def _get_status_by_id(self, status_id: int) -> Optional[CardStatus]:
|
||
stmt = (
|
||
select(CardStatus)
|
||
.where(CardStatus.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 = CardStatus(
|
||
**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(Card.id))
|
||
.where(
|
||
and_(
|
||
Card.current_status_id == status_id,
|
||
Card.is_deleted == False,
|
||
Card.is_completed == False,
|
||
)
|
||
)
|
||
)
|
||
return (await self.session.scalars(stmt)).first()
|
||
|
||
async def _count_deals(self, status_id: int) -> int:
|
||
stmt = (
|
||
select(func.count(Card.id))
|
||
.where(Card.current_status_id == status_id)
|
||
)
|
||
return (await self.session.scalars(stmt)).first()
|
||
|
||
async def _set_finishing_flag_to_prev_status(self, status: CardStatus):
|
||
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="Статус успешно удален")
|