From 9a12ddb6aff91db529a6681cf68c20584e8d762d Mon Sep 17 00:00:00 2001 From: admin Date: Tue, 22 Oct 2024 19:32:27 +0300 Subject: [PATCH] feat: total services amount and recalculating --- models/base.py | 5 +++- models/secondary.py | 6 +++-- routers/deal.py | 15 ++++++++++- schemas/deal.py | 10 ++++++- services/deal.py | 65 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 93 insertions(+), 8 deletions(-) diff --git a/models/base.py b/models/base.py index 07d499f..f8fdab1 100644 --- a/models/base.py +++ b/models/base.py @@ -3,7 +3,10 @@ from sqlalchemy.orm import declarative_base, DeclarativeBase class BaseModel(DeclarativeBase, AsyncAttrs): - pass + def __repr__(self): + if hasattr(self, 'id'): + return f'<{self.__class__.__name__} id={self.id}>' + return super().__repr__() metadata = BaseModel.metadata diff --git a/models/secondary.py b/models/secondary.py index 5be39a3..6b50710 100644 --- a/models/secondary.py +++ b/models/secondary.py @@ -1,5 +1,5 @@ from sqlalchemy import Table, Column, Integer, ForeignKey, ForeignKeyConstraint, UniqueConstraint -from sqlalchemy.orm import relationship +from sqlalchemy.orm import relationship, mapped_column, Mapped from models.base import BaseModel @@ -41,6 +41,7 @@ class DealService(BaseModel): quantity = Column(Integer, nullable=False, comment='Кол-во услуги') price = Column(Integer, nullable=False, server_default='0', comment='Цена услуги') + is_fixed_price: Mapped[bool] = mapped_column(default=False, server_default='0', comment='Фиксированная цена') employees = relationship('User', secondary=deal_service_employees) @@ -59,6 +60,8 @@ class DealProductService(BaseModel): price = Column(Integer, nullable=False, comment='Цена услуги') + is_fixed_price: Mapped[bool] = mapped_column(default=False, server_default='0', comment='Фиксированная цена') + deal_product = relationship('DealProduct', back_populates='services', primaryjoin="and_(DealProductService.deal_id == DealProduct.deal_id, " @@ -114,4 +117,3 @@ barcode_template_attribute_link = Table( Column('barcode_template_id', ForeignKey('barcode_templates.id')), Column('attribute_id', ForeignKey('barcode_template_attributes.id')) ) - diff --git a/routers/deal.py b/routers/deal.py index 599e026..580e6d3 100644 --- a/routers/deal.py +++ b/routers/deal.py @@ -59,7 +59,8 @@ async def complete( session: SessionDependency, user: CurrentUserDependency ): - return await DealService(session).complete(user,request) + return await DealService(session).complete(user, request) + @deal_router.post( '/quickCreate', @@ -221,6 +222,18 @@ async def post_prefill_deal( return await DealService(session).prefill_deal(user, request) +@deal_router.post( + '/recalculate-price', + response_model=DealRecalculatePriceResponse, + operation_id='recalculate_deal_price', +) +async def recalculate_deal_price( + session: SessionDependency, + request: DealRecalculatePriceRequest, +): + return await DealService(session).recalculate_price(request) + + # endregion # region Deal services diff --git a/schemas/deal.py b/schemas/deal.py index b84b21c..578a439 100644 --- a/schemas/deal.py +++ b/schemas/deal.py @@ -56,12 +56,13 @@ class DealServiceSchema(BaseSchema): quantity: int price: int employees: List[UserSchema] - + is_fixed_price: bool class DealProductServiceSchema(BaseSchema): service: ServiceSchema price: int employees: List[UserSchema] + is_fixed_price: bool class DealProductSchema(BaseSchema): @@ -243,6 +244,10 @@ class DealPrefillRequest(BaseSchema): new_deal_id: int +class DealRecalculatePriceRequest(BaseSchema): + deal_id: int + + # endregion Requests # region Responses @@ -347,4 +352,7 @@ class DealCompleteResponse(OkMessageSchema): class DealPrefillResponse(OkMessageSchema): pass + +class DealRecalculatePriceResponse(OkMessageSchema): + pass # endregion Responses diff --git a/services/deal.py b/services/deal.py index 86574f7..bfecf8f 100644 --- a/services/deal.py +++ b/services/deal.py @@ -6,7 +6,7 @@ from starlette import status import models.deal import models.secondary -from models import User, Service, Client +from models import User, Service, Client, DealProductService from models.deal import * from schemas.client import ClientDetailsSchema from schemas.deal import * @@ -732,7 +732,8 @@ class DealService(BaseService): 'deal_id': request.deal_id, 'product_id': deal_product.product_id, 'service_id': service.service.id, - 'price': service.price + 'price': service.price, + 'is_fixed_price': service.is_fixed_price }) if not insert_data: return DealServicesCopyResponse(ok=True, message='Услуги успешно перенесены') @@ -916,6 +917,7 @@ class DealService(BaseService): continue request_service = services_dict[service.service_id] service.price = request_service.price + service.is_fixed_price = request_service.is_fixed_price await self.session.flush() # Creating services @@ -1001,7 +1003,7 @@ class DealService(BaseService): 'deal_id': request.deal_id, 'product_id': deal_product.product_id, 'service_id': service.id, - 'price': service_price + 'price': service_price, }) if not insert_data: return DealProductAddKitResponse(ok=True, message='Набор услуг успешно добавлен к товару') @@ -1029,6 +1031,7 @@ class DealService(BaseService): return DealProductAddKitResponse(ok=False, message=str(e)) # endregion + async def complete(self, user: User, request: DealCompleteRequest) -> DealCompleteResponse: try: # check for admin @@ -1044,3 +1047,59 @@ class DealService(BaseService): except Exception as e: await self.session.rollback() return DealCompleteResponse(ok=False, message=str(e)) + + async def recalculate_price(self, request: DealRecalculatePriceRequest) -> DealRecalculatePriceResponse: + try: + deal_stmt = ( + select( + Deal + ) + .options( + selectinload(Deal.services) + .joinedload(models.DealService.service), + selectinload(Deal.products) + .selectinload(DealProduct.services) + .joinedload(DealProductService.service), + ) + .where(Deal.id == request.deal_id) + ) + deal: Deal = await self.session.scalar(deal_stmt) + services_quantity = defaultdict(lambda: 0) + for product in deal.products: + product: DealProduct + for service in product.services: + service: DealProductService + if service.is_fixed_price: + continue + services_quantity[service.service_id] += product.quantity + + services_prices = {} + for product in deal.products: + for service in product.services: + if service.is_fixed_price: + continue + quantity = services_quantity[service.service_id] + print(service.service_id, quantity) + if service.service_id in services_prices: + service.price = services_prices[service.service_id] + continue + price = self.get_service_price( + service=service.service, + quantity=quantity + ) + print(service.service_id, price) + service.price = price + services_prices[service.service_id] = price + for service in deal.services: + service: models.DealService + if service.is_fixed_price: + continue + price = self.get_service_price( + service=service.service, + quantity=service.quantity + ) + service.price = price + await self.session.commit() + return DealRecalculatePriceResponse(ok=True, message="Цены успешно пересчитаны") + except Exception as e: + return DealRecalculatePriceResponse(ok=False, message=str(e))