feat: deal product services

This commit is contained in:
2024-05-19 04:08:10 +03:00
parent 30886d223c
commit e2de43064a
6 changed files with 233 additions and 30 deletions

View File

@@ -4,7 +4,7 @@ import models.secondary
from typing import Union
import models.deal
from fastapi import HTTPException
from sqlalchemy import select, func
from sqlalchemy import select, func, update
from sqlalchemy.orm import joinedload, selectinload
from models import User, Service, Client
@@ -118,20 +118,42 @@ class DealService(BaseService):
await self.session.commit()
return DealChangeStatusResponse(ok=True)
async def get_summary(self) -> DealSummaryResponse:
service_subquery = (
def _get_price_subquery(self):
deal_services_subquery = (
select(
models.secondary.DealService.deal_id,
func.sum(models.secondary.DealService.quantity * Service.price).label('total_price')
func.sum(models.secondary.DealService.quantity * models.secondary.DealService.price).label(
'total_price')
)
.join(Service)
.group_by(models.secondary.DealService.deal_id)
)
product_services_subquery = select(
select(
models.secondary.DealProductService.deal_id,
func.sum(models.DealProduct.quantity * models.secondary.DealProductService.price).label('total_price')
)
.join(models.secondary.DealProduct)
.group_by(models.secondary.DealProductService.deal_id)
.subquery()
)
union_subqueries = deal_services_subquery.union(product_services_subquery).subquery()
final_subquery = (
select(
union_subqueries.c.deal_id,
func.sum(union_subqueries.c.total_price).label('total_price')
)
.group_by(union_subqueries.c.deal_id)
.subquery()
)
return final_subquery
async def get_summary(self) -> DealSummaryResponse:
price_subquery = self._get_price_subquery()
q = (
select(
Deal,
func.coalesce(service_subquery.c.total_price, 0),
func.coalesce(price_subquery.c.total_price, 0),
func.row_number().over(
partition_by=Deal.current_status,
order_by=Deal.lexorank
@@ -142,7 +164,7 @@ class DealService(BaseService):
joinedload(Deal.client)
)
.outerjoin(
service_subquery, Deal.id == service_subquery.c.deal_id)
price_subquery, Deal.id == price_subquery.c.deal_id)
.where(
Deal.is_deleted == False,
Deal.is_completed == False
@@ -177,6 +199,7 @@ class DealService(BaseService):
return DealGetAllResponse(deals=result)
async def get_by_id(self, deal_id: int) -> DealSchema:
deal = await self.session.scalar(
select(Deal)
.options(
@@ -190,13 +213,17 @@ class DealService(BaseService):
selectinload(Deal.products)
.joinedload(models.secondary.DealProduct.product)
.joinedload(models.Product.barcodes),
selectinload(Deal.products)
.joinedload(models.secondary.DealProduct.services)
.joinedload(models.secondary.DealProductService.service),
selectinload(Deal.status_history)
.joinedload(DealStatusHistory.user),
selectinload(Deal.status_history)
.noload(DealStatusHistory.deal)
.noload(DealStatusHistory.deal),
)
.where(Deal.id == deal_id)
)
if not deal:
raise HTTPException(status_code=404, detail="Сделка не найдена")
return DealSchema.model_validate(deal)
@@ -328,7 +355,7 @@ class DealService(BaseService):
deal = await self.session.scalar(select(Deal).where(Deal.id == request.deal_id))
if not deal:
raise HTTPException(status_code=404, detail="Сделка не найдена")
service = await self.session.scalar(select(Service).where(Service.id == request.service_id))
service: models.Service = await self.session.scalar(select(Service).where(Service.id == request.service_id))
if not service:
raise HTTPException(status_code=404, detail="Услуга не найдена")
# Preventing duplicates
@@ -342,7 +369,8 @@ class DealService(BaseService):
deal_service = models.secondary.DealService(
deal_id=request.deal_id,
service_id=request.service_id,
quantity=request.quantity
quantity=request.quantity,
price=request.price
)
self.session.add(deal_service)
await self.session.commit()
@@ -382,6 +410,30 @@ class DealService(BaseService):
await self.session.rollback()
return DealDeleteServicesResponse(ok=False, message=str(e))
async def update_service(self, request: DealUpdateServiceRequest) -> DealUpdateServiceResponse:
try:
deal_service = await self.session.scalar(
select(models.secondary.DealService)
.where(models.secondary.DealService.deal_id == request.deal_id,
models.secondary.DealService.service_id == request.service.service.id)
)
if not deal_service:
raise HTTPException(status_code=404, detail="Сделка не найдена")
service_dict = request.service.dict()
del service_dict['service']
service_dict['service_id'] = request.service.service.id
await self.session.execute(
update(models.secondary.DealService)
.where(models.secondary.DealService.deal_id == request.deal_id,
models.secondary.DealService.service_id == request.service.service.id)
.values(**service_dict)
)
await self.session.commit()
return DealUpdateServiceQuantityResponse(ok=True, message='Количество успешно обновлено')
except Exception as e:
await self.session.rollback()
return DealUpdateServiceQuantityResponse(ok=False, message=str(e))
# endregion
# region Deal products
@@ -408,23 +460,33 @@ class DealService(BaseService):
deal = await self.session.scalar(select(Deal).where(Deal.id == request.deal_id))
if not deal:
raise HTTPException(status_code=404, detail="Сделка не найдена")
product = await self.session.scalar(select(models.Product).where(models.Product.id == request.product_id))
product = await self.session.scalar(
select(models.Product).where(models.Product.id == request.product.product.id))
if not product:
raise HTTPException(status_code=404, detail="Товар не найден")
# Preventing duplicates
deal_product = await self.session.scalar(
select(models.secondary.DealProduct)
.where(models.secondary.DealProduct.deal_id == request.deal_id,
models.secondary.DealProduct.product_id == request.product_id)
models.secondary.DealProduct.product_id == request.product.product.id)
)
if deal_product:
raise HTTPException(status_code=400, detail="Товар уже добавлен")
deal_product = models.secondary.DealProduct(
deal_id=request.deal_id,
product_id=request.product_id,
quantity=request.quantity
product_id=request.product.product.id,
quantity=request.product.quantity
)
self.session.add(deal_product)
await self.session.flush()
for service in request.product.services:
deal_product_service = models.secondary.DealProductService(
deal_id=request.deal_id,
product_id=request.product.product.id,
service_id=service.service.id,
price=service.price
)
self.session.add(deal_product_service)
await self.session.commit()
return DealAddProductResponse(ok=True, message='Товар успешно добавлен')
except Exception as e:
@@ -461,4 +523,56 @@ class DealService(BaseService):
except Exception as e:
await self.session.rollback()
return DealDeleteProductsResponse(ok=False, message=str(e))
async def update_product(self, request: DealUpdateProductRequest):
try:
deal_product: models.DealProduct = await self.session.scalar(
select(models.secondary.DealProduct)
.where(models.secondary.DealProduct.deal_id == request.deal_id,
models.secondary.DealProduct.product_id == request.product.product.id)
)
if not deal_product:
raise HTTPException(status_code=404, detail="Указанный товар не найден")
# getting new services and deleted
database_services = set([service.service_id for service in deal_product.services])
request_services = set([service.service.id for service in request.product.services])
new_services = request_services.difference(database_services)
deleted_services = database_services.difference(request_services)
services_dict = {service.service.id: service for service in request.product.services}
# Deleting and updating existing services
for service in deal_product.services:
service: models.DealProductService
if service.service_id in deleted_services:
await self.session.delete(service)
await self.session.flush()
continue
request_service = services_dict[service.service_id]
service.price = request_service.price
await self.session.flush()
# Creating services
for service in request.product.services:
if service.service.id not in new_services:
continue
deal_product_service = models.DealProductService(
deal_id=request.deal_id,
product_id=request.product.product.id,
service_id=service.service.id,
price=service.price
)
self.session.add(deal_product_service)
await self.session.flush()
# Updating product
deal_product.quantity = request.product.quantity
await self.session.commit()
return DealUpdateProductResponse(ok=True, message='Товар успешно обновлен')
except Exception as e:
await self.session.rollback()
return DealUpdateProductResponse(ok=False, message=str(e))
# endregion