import contextlib import logging import os from re import Match from aiogram import F, Router from aiogram.fsm.context import FSMContext from aiogram.types import CallbackQuery, FSInputFile from sqlalchemy.ext.asyncio import AsyncSession from config import VERIFIED_ACCOUNTS from misc.kb import admins from misc.kb.client import ( render_catalogue, render_product_interactions, ) from misc.texts import get_product_description from repositories.products import ProductRepository from services.catalogue import CatalogueService from services.orders import OrderService router = Router() logger = logging.getLogger(__name__) @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, catalogue_service: CatalogueService, ): await state.clear() pagination_data = pagination_match.groupdict() category_id = int(pagination_data.get("category_id")) page_id = int(pagination_data.get("page_id", 0)) is_admin = cb.from_user.id in VERIFIED_ACCOUNTS view = await catalogue_service.build_category_view( session, category_id, page=page_id, include_hidden=is_admin ) kb = render_catalogue(view, is_admin=is_admin) await cb.message.edit_reply_markup(reply_markup=kb) @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]) is_admin = cb.from_user.id in VERIFIED_ACCOUNTS product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin) if not product: await cb.answer("Товар недоступен.", show_alert=True) return if is_admin: kb = admins.edit_product(product) 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 not product.file_id and not (product.img_path and os.path.isfile(product.img_path)): await cb.message.edit_text( get_product_description(product), reply_markup=kb, ) return await cb.message.delete() if product.file_id: msg = await cb.message.answer_photo( product.file_id, caption=get_product_description(product), reply_markup=kb, ) return with contextlib.suppress(Exception): await cb.message.edit_text("⏳ Загружаем карточку товара...") msg = await cb.message.answer_photo( FSInputFile(product.img_path), caption=get_product_description(product), reply_markup=kb, ) if not msg.photo: logger.warning("didnt get a photo back wahhh :(") 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]) is_admin = cb.from_user.id in VERIFIED_ACCOUNTS product = await products_repo.get_product_by_id(session, product_id, include_hidden=is_admin) if not product: await cb.answer("Товар недоступен.", show_alert=True) return 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