import os from re import Match from aiogram import Router, F from aiogram.types import CallbackQuery, FSInputFile from aiogram.fsm.context import FSMContext from sqlalchemy.ext.asyncio import AsyncSession from config import PAGE_SIZE, VERIFIED_ACCOUNTS from misc.kb import admins from misc.kb.client import ( render_product_interactions, render_products, ) from misc.texts import get_product_description from repositories.categories import CategoriesRepository from repositories.products import ProductRepository from services.orders import OrderService router = Router() @router.callback_query( F.data.regexp(r"products:(?P.*):(?P\d+)").as_( "pagination_match" ) ) async def products_pagination( cb: CallbackQuery, state: FSMContext, pagination_match: Match[str], session: AsyncSession, products_repo: ProductRepository, categories_repo: CategoriesRepository, ): await state.clear() pagination_data = pagination_match.groupdict() category_id = int(pagination_data.get("category_id")) category = await categories_repo.get_category_by_id(session, category_id) page_id = int(pagination_data.get("page_id", 0)) products = await products_repo.get_product_by_category( session, category_id, limit=PAGE_SIZE + 1, offset=page_id * PAGE_SIZE ) products_len = len(products) await cb.message.edit_reply_markup( reply_markup=render_products( products[:PAGE_SIZE], product_cb_factory=lambda p: f"product:{p.id}", back_cb=f"cat:{category.parent_id}", prev_cb=(f"products:{category_id}:{page_id - 1}" if page_id > 0 else None), next_cb=( f"products:{category_id}:{page_id + 1}" if products_len > PAGE_SIZE else None ), columns=2, ), ) @router.callback_query(F.data.startswith("product:")) async def product_card( cb: CallbackQuery, state: FSMContext, session: AsyncSession, products_repo: ProductRepository, order_service: OrderService, ): await state.clear() product_id = int(cb.data.split(":")[1]) product = await products_repo.get_product_by_id(session, product_id) if cb.from_user.id in VERIFIED_ACCOUNTS: kb = admins.edit_product(product_id=product.id, category_id=product.category_id) else: order_item = await order_service.get_cart_product_amount( session, customer=cb.from_user.id, product_id=product_id ) kb = render_product_interactions( product_id=product.id, category_id=product.category_id, show_cart=bool(order_item), cart_amount=order_item, ) if product.file_id: await cb.message.delete() msg = await cb.message.answer_photo( product.file_id, caption=get_product_description(product), reply_markup=kb, ) return if not os.path.isfile(product.img_path): await cb.message.edit_text( get_product_description(product), reply_markup=kb, ) return await cb.message.delete() msg = await cb.message.answer_photo( FSInputFile(product.img_path), caption=get_product_description(product), reply_markup=kb, ) if not msg.photo: return # TODO: Add logging await products_repo.add_product_file_id( session, product_id, file_id=msg.photo[-1].file_id ) @router.callback_query(F.data.startswith("cart_action:")) async def cart_action( cb: CallbackQuery, state: FSMContext, session: AsyncSession, order_service: OrderService, products_repo: ProductRepository, ): await state.clear() action = cb.data.split(":")[1] product_id = int(cb.data.split(":")[2]) product = await products_repo.get_product_by_id(session, product_id) show_cart = True if action == "add": quantity = await order_service.add_to_cart( session, customer=cb.from_user.id, product_id=product_id ) elif action == "remove": quantity = await order_service.remove_from_cart( session, customer=cb.from_user.id, product_id=product_id ) show_cart = bool(quantity) else: show_cart = False quantity = 0 await order_service.clear_from_cart( session, customer=cb.from_user.id, product_id=product_id ) try: await cb.message.edit_reply_markup( reply_markup=render_product_interactions( product_id=product_id, category_id=product.category_id, show_cart=show_cart, cart_amount=quantity, ) ) except Exception as e: await cb.answer("🍃") raise e