Files
Fulfillment-Backend/services/deal.py
2024-03-28 08:22:14 +03:00

159 lines
6.2 KiB
Python

import models.secondary
from typing import Union
from fastapi import HTTPException
from sqlalchemy import select, func
from sqlalchemy.orm import joinedload, selectinload
from models import User, Service
from models.deal import *
from schemas.client import ClientDetailsSchema
from schemas.deal import *
from services.base import BaseService
from services.client import ClientService
class DealService(BaseService):
async def _get_deal_by_id(self, deal_id) -> Union[Deal, None]:
return await self.session.get(Deal, deal_id)
async def change_status(self, deal: Deal,
status: DealStatus,
user: User,
deadline: datetime.datetime = None) -> DealStatusHistory:
deadline = deadline
status_change = DealStatusHistory(
deal_id=deal.id,
user_id=user.id,
changed_at=datetime.datetime.now(),
from_status=deal.current_status,
to_status=status,
next_status_deadline=deadline
)
self.session.add(status_change)
await self.session.flush()
return status_change
async def create(self, request: DealCreateRequest, user: User) -> DealCreateResponse:
deal = Deal(
name=request.name,
created_at=datetime.datetime.now(),
current_status=DealStatus.CREATED
)
self.session.add(deal)
await self.session.flush()
# Append status history
await self.change_status(deal, DealStatus.AWAITING_ACCEPTANCE, user)
await self.session.commit()
return DealCreateResponse(ok=True)
async def quick_create(self, request: DealQuickCreateRequest, user: User) -> DealQuickCreateResponse:
client_service = ClientService(self.session)
client = await client_service.get_by_name(request.client_name)
if not client:
client = await client_service.create_client_raw(
user,
request.client_name,
ClientDetailsSchema(address=request.client_address))
await client_service.update_details(user, client, ClientDetailsSchema(address=request.client_address))
deal = Deal(
name=request.name,
created_at=datetime.datetime.now(),
client_id=client.id,
current_status=DealStatus.CREATED
)
self.session.add(deal)
await self.session.flush()
await self.change_status(deal, DealStatus.AWAITING_ACCEPTANCE, user, deadline=request.acceptance_date)
await self.session.commit()
return DealQuickCreateResponse(deal_id=deal.id)
async def change_status_manual(self, request: DealChangeStatusRequest, user: User) -> DealChangeStatusResponse:
# Changing current status
deal = await self._get_deal_by_id(request.deal_id)
if not deal:
return DealChangeStatusResponse(ok=False)
await self.change_status(deal, DealStatus(request.new_status), user)
await self.session.commit()
return DealChangeStatusResponse(ok=True)
async def get_summary(self) -> DealSummaryResponse:
service_subquery = (
select(
models.secondary.DealService.deal_id,
func.sum(models.secondary.DealService.quantity * Service.price).label('total_price')
)
.join(Service)
.group_by(models.secondary.DealService.deal_id)
.subquery()
)
q = (select(
Deal,
func.coalesce(service_subquery.c.total_price, 0)
)
.options(selectinload(Deal.status_history),
joinedload(Deal.client))
.outerjoin(service_subquery, Deal.id == service_subquery.c.deal_id)
.where(Deal.is_deleted == False,
Deal.is_completed == False))
deals_query = await self.session.execute(q)
summaries = []
for deal, total_price in deals_query.all():
deal: Deal
last_status: DealStatusHistory = max(deal.status_history, key=lambda status: status.changed_at)
summaries.append(
DealSummary(
id=deal.id,
client_name=deal.client.name,
name=deal.name,
changed_at=last_status.changed_at,
status=last_status.to_status,
total_price=total_price
)
)
return DealSummaryResponse(summaries=summaries)
async def add_services(self, request: DealAddServicesRequest):
# TODO refactor
deal: Deal = await self.session.scalar(
select(Deal)
.options(selectinload(Deal.services))
.where(Deal.id == request.deal_id)
)
if not deal:
raise HTTPException(status_code=404, detail="Deal is not found")
services_ids = [service.id for service in request.services]
existing_service_ids = {service.service_id for service in deal.services}
request_services_dict = {service.id: service.quantity for service in request.services}
services_query = await self.session.scalars(select(Service).where(Service.id.in_(services_ids)))
services = services_query.all()
if len(services) != len(services_ids):
raise HTTPException(status_code=404, detail="Some of services is not found")
# Adding quantity
for deal_service in deal.services:
deal_service: models.secondary.DealService
if deal_service.service_id not in services_ids:
continue
deal_service.quantity += request_services_dict[deal_service.service_id]
# Adding new services
for service in services:
if service.id in existing_service_ids:
continue
quantity = request_services_dict[service.id]
deal.services.append(
models.secondary.DealService(
service=service,
deal=deal,
quantity=quantity
)
)
await self.session.commit()
return DealAddServicesResponse(ok=True, message='Услуги успешно добавлены')