import logging from sqlalchemy.ext.asyncio import AsyncSession from config import PAGE_SIZE from db.models.orders import OrderStatus from dto.cart import CartDTO, CartItemDTO from repositories.order_items import OrderItemRepository from repositories.orders import OrderRepository logger = logging.getLogger(__name__) class OrderServiceException(Exception): ... class OrderService: def __init__( self, order_repo: OrderRepository, order_items_repo: OrderItemRepository ): self.order_repo = order_repo self.order_items_repo = order_items_repo async def get_order_count(self, session: AsyncSession, customer: int) -> int: orders = await self.order_repo.get_orders_by_user(session, customer) return len(orders) async def add_to_cart( self, session: AsyncSession, *, customer: int, product_id: int, quantity: int = 1, ) -> int: order = await self.order_repo.get_draft_order_by_user(session, customer) if not order: order = await self.order_repo.create_order( session, customer, OrderStatus.DRAFT ) order_item = await self.order_items_repo.get_item_by_order_and_product( session, order_id=order.id, product_id=product_id ) if not order_item: order_item = await self.order_items_repo.create_order_item( session, order_id=order.id, product_id=product_id, quantity=quantity ) return quantity else: await self.order_items_repo.update_order_item_quantity( session, order_item.id, quantity=order_item.quantity + quantity ) return order_item.quantity + quantity async def remove_from_cart( self, session: AsyncSession, *, customer: int, product_id: int, quantity: int = 1, ) -> int: order = await self.order_repo.get_draft_order_by_user(session, customer) if not order: raise OrderServiceException( "attempt of removing product from non-existing cart, potential callback_query exploit, ignoring..." ) order_item = await self.order_items_repo.get_item_by_order_and_product( session, order_id=order.id, product_id=product_id ) if not order_item: raise OrderServiceException( "attempt of decreasing quantity of non-existing order_item, potential callback_query exploit, ignoring..." ) new_quantity = order_item.quantity - quantity if new_quantity > 0: await self.order_items_repo.update_order_item_quantity( session, order_item_id=order_item.id, quantity=new_quantity ) else: await self.order_items_repo.delete_item(session, order_item.id) return new_quantity async def clear_from_cart( self, session: AsyncSession, *, customer: int, product_id: int ): order = await self.order_repo.get_draft_order_by_user(session, customer) if not order: raise OrderServiceException( "attempt of removing product from non-existing cart, potential callback_query exploit, ignoring..." ) order_item = await self.order_items_repo.get_item_by_order_and_product( session, order_id=order.id, product_id=product_id ) if not order_item: raise OrderServiceException( "attempt of decreasing quantity of non-existing order_item, potential callback_query exploit, ignoring..." ) await self.order_items_repo.delete_item(session, item_id=order_item.id) async def get_cart_product_amount( self, session: AsyncSession, *, customer: int, product_id: int ) -> int: order = await self.order_repo.get_draft_order_by_user(session, customer) if not order: return 0 order_item = await self.order_items_repo.get_item_by_order_and_product( session, order_id=order.id, product_id=product_id ) if not order_item: return 0 return order_item.quantity async def build_pagination_cart_dto( self, session: AsyncSession, *, customer: int, limit: int = PAGE_SIZE + 1, offset: int = 0, ) -> CartDTO: order = await self.order_repo.get_draft_order_by_user(session, customer) cart_items = [] if not order: return CartDTO(items=cart_items, total=0) order_items = await self.order_items_repo.get_items_by_order( session, order_id=order.id, limit=limit, offset=offset ) total = 0 for item in order_items: if item.quantity <= 0: await self.order_items_repo.delete_item(session, item_id=item.id) continue cart_item = CartItemDTO( product_id=item.product_id, name=item.product.name, quantity=item.quantity, price=item.product.price, ) cart_items.append(cart_item) total += cart_item.total return CartDTO(items=cart_items, total=total, order_id=order.id) async def build_full_cart_dto(self, session: AsyncSession, customer: int): order = await self.order_repo.get_draft_order_by_user(session, customer) cart_items = [] total = 0 if not order: return CartDTO(items=cart_items, total=total) for cart_item in order.items: if cart_item.quantity <= 0: await self.order_items_repo.delete_item(session, item_id=cart_item.id) continue dto = CartItemDTO( product_id=cart_item.product.id, name=cart_item.product.name, quantity=cart_item.quantity, price=cart_item.product.price, ) cart_items.append(dto) total += dto.total return CartDTO(cart_items, total=total, order_id=order.id)