194 lines
6.3 KiB
Python
194 lines
6.3 KiB
Python
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 clear_cart_item(
|
|
self, session: AsyncSession, *, customer: int, product_id: int
|
|
) -> None:
|
|
order = await self.order_repo.get_draft_order_by_user(session, customer)
|
|
|
|
if not order:
|
|
raise OrderServiceException(
|
|
"attempt of clearing a 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 clearing an order_item that isn't in a cart, potential callback_query exploit, ignoring..."
|
|
)
|
|
|
|
await self.order_items_repo.update_order_item_quantity(
|
|
session, order_item_id=order_item.id, quantity=0
|
|
)
|
|
|
|
async def get_cart_items_count(self, session: AsyncSession, customer: int) -> int:
|
|
order = await self.order_repo.get_draft_order_by_user(session, customer)
|
|
if not order:
|
|
return 0
|
|
|
|
return await self.order_items_repo.get_items_count(session, order_id=order.id)
|
|
|
|
async def build_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)
|