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="Статус успешно удален")