diff --git a/repositories/deal.py b/repositories/deal.py index 5241a21..7994d3e 100644 --- a/repositories/deal.py +++ b/repositories/deal.py @@ -1,9 +1,16 @@ +from sqlalchemy import func from sqlalchemy.orm import joinedload from models import Deal, Board, DealStatusHistory +from modules.fulfillment_base.models import ( + DealService, + Service, + DealProductService, + DealProduct, +) from repositories.mixins import * from schemas.base import SortDir -from schemas.deal import UpdateDealSchema, CreateDealSchema +from schemas.deal import UpdateDealSchema, CreateDealSchema, DealSchema from utils.sorting import apply_sorting @@ -17,6 +24,49 @@ class DealRepository( entity_class = Deal entity_not_found_msg = "Сделка не найдена" + def _get_price_subquery(self): + deal_services_subquery = ( + select( + DealService.deal_id, + func.sum(DealService.quantity * DealService.price).label("total_price"), + ) + .join(Service) + .group_by(DealService.deal_id) + ) + product_services_subquery = select( + select( + DealProductService.deal_id, + func.sum(DealProduct.quantity * DealProductService.price).label( + "total_price" + ), + ) + .join(DealProduct) + .group_by(DealProductService.deal_id) + .subquery() + ) + union_subqueries = deal_services_subquery.union_all( + 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 + + def _get_products_quantity_subquery(self): + return ( + select( + DealProduct.deal_id, + func.sum(DealProduct.quantity).label("products_quantity"), + ) + .group_by(DealProduct.deal_id) + .subquery() + ) + async def get_all( self, page: Optional[int], @@ -28,9 +78,23 @@ class DealRepository( status_id: Optional[int], id: Optional[int], name: Optional[str], - ) -> tuple[list[Deal], int]: + ) -> tuple[list[tuple[Deal, int, int]], int]: + price_subquery = self._get_price_subquery() + products_quantity_subquery = self._get_products_quantity_subquery() stmt = ( - select(Deal) + select( + Deal, + func.coalesce(price_subquery.c.total_price, 0), + func.coalesce(products_quantity_subquery.c.products_quantity, 0), + ) + .outerjoin( + price_subquery, + Deal.id == price_subquery.c.deal_id, + ) + .outerjoin( + products_quantity_subquery, + Deal.id == products_quantity_subquery.c.deal_id, + ) .options(joinedload(Deal.status), joinedload(Deal.board)) .where(Deal.is_deleted.is_(False)) ) @@ -56,8 +120,8 @@ class DealRepository( if page and items_per_page: stmt = self._apply_pagination(stmt, page, items_per_page) - result = await self.session.execute(stmt) - return list(result.scalars().all()), total_items + rows: list[tuple[Deal, int, int]] = (await self.session.execute(stmt)).all() + return rows, total_items def _process_get_by_id_stmt(self, stmt: Select) -> Select: return stmt.options(joinedload(Deal.status), joinedload(Deal.board)) diff --git a/schemas/deal.py b/schemas/deal.py index 99e1ea2..c3ed83b 100644 --- a/schemas/deal.py +++ b/schemas/deal.py @@ -17,6 +17,10 @@ class DealSchema(BaseSchema): status: StatusSchema board: BoardSchema created_at: datetime + # FF module + products_quantity: int = 0 + total_price: float = 0 + # clients module client: Optional[ClientSchema] = None diff --git a/services/deal.py b/services/deal.py index b70f476..a15a761 100644 --- a/services/deal.py +++ b/services/deal.py @@ -26,7 +26,7 @@ class DealService( sorting: SortingSchema, *filters, ) -> GetDealsResponse: - deals, total_items = await self.repository.get_all( + rows, total_items = await self.repository.get_all( pagination.page, pagination.items_per_page, sorting.field, @@ -38,8 +38,17 @@ class DealService( if pagination.items_per_page: total_pages = math.ceil(total_items / pagination.items_per_page) + deals = [ + DealSchema( + **deal.__dict__, + products_quantity=products_quantity, + total_price=total_price, + ) + for deal, total_price, products_quantity in rows + ] + return GetDealsResponse( - items=[DealSchema.model_validate(deal) for deal in deals], + items=deals, pagination_info=PaginationInfoSchema( total_pages=total_pages, total_items=total_items ),