invix_test_task/bot/app/handlers.py

129 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from aiogram import F, Router
from aiogram.filters import Command, CommandStart
from aiogram.types import CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup, Message
from app.api import ApiError, ShopApi
router = Router()
def _catalog_keyboard(products: list[dict]) -> InlineKeyboardMarkup:
rows = [
[InlineKeyboardButton(text=f"{item['title']} — {item['price']} ₽", callback_data=f"prod:{item['id']}")]
for item in products
]
return InlineKeyboardMarkup(inline_keyboard=rows)
def _product_keyboard(product_id: int) -> InlineKeyboardMarkup:
return InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(text="В корзину", callback_data=f"add:{product_id}"),
InlineKeyboardButton(text="Оформить", callback_data="checkout"),
]
]
)
def _cart_text(cart: dict) -> str:
if not cart["items"]:
return "Корзина пуста."
lines = [f"{item['title']} × {item['qty']} = {item['line_total']} ₽" for item in cart["items"]]
lines.append(f"Итого: {cart['total']} ₽")
lines.append("Оформление: /checkout")
return "\n".join(lines)
@router.message(CommandStart())
async def start(message: Message) -> None:
await message.answer("Магазин. /catalog — товары, /cart — корзина, /checkout — заказ без оплаты.")
@router.message(Command("catalog"))
async def catalog(message: Message, api: ShopApi) -> None:
products = await api.products()
if not products:
await message.answer("Каталог пуст.")
return
await message.answer("Каталог", reply_markup=_catalog_keyboard(products))
@router.callback_query(F.data.startswith("prod:"))
async def show_product(query: CallbackQuery, api: ShopApi) -> None:
product_id = int(query.data.split(":", 1)[1])
try:
product = await api.product(product_id)
except ApiError as exc:
await query.answer(exc.detail, show_alert=True)
return
text = f"{product['title']}\n{product['description']}\n{product['price']} ₽\n{product['category_name']}"
if query.message is not None:
await query.message.answer(text, reply_markup=_product_keyboard(product_id))
await query.answer()
@router.callback_query(F.data.startswith("add:"))
async def add_product(query: CallbackQuery, api: ShopApi) -> None:
if query.from_user is None:
await query.answer()
return
product_id = int(query.data.split(":", 1)[1])
try:
cart = await api.add(query.from_user.id, product_id)
except ApiError as exc:
await query.answer(exc.detail, show_alert=True)
return
await query.answer("Добавлено")
if query.message is not None:
await query.message.answer(_cart_text(cart))
@router.message(Command("cart"))
async def cart(message: Message, api: ShopApi) -> None:
if message.from_user is None:
return
data = await api.cart(message.from_user.id)
await message.answer(_cart_text(data))
@router.message(Command("checkout"))
@router.callback_query(F.data == "checkout")
async def checkout_start(event: Message | CallbackQuery, api: ShopApi) -> None:
user = event.from_user
if user is None:
return
await api.save_dialog(user.id, "name", None)
text = "Как вас зовут?"
if isinstance(event, CallbackQuery):
await event.answer()
if event.message is not None:
await event.message.answer(text)
return
await event.answer(text)
@router.message(F.text)
async def dialog(message: Message, api: ShopApi) -> None:
if message.from_user is None or message.text is None or message.text.startswith("/"):
return
state = await api.dialog(message.from_user.id)
if state is None:
return
if state["step"] == "name":
await api.save_dialog(message.from_user.id, "phone", message.text.strip()[:120])
await message.answer("Телефон? Можно цифры, пробелы и +()-.")
return
if state["step"] != "phone" or not state.get("name"):
await api.clear_dialog(message.from_user.id)
return
try:
order = await api.order(message.from_user.id, state["name"], message.text.strip())
except ApiError as exc:
await message.answer(exc.detail)
return
await api.clear_dialog(message.from_user.id)
await message.answer(
f"Заказ {order['id']} создан, без оплаты.\nСумма: {order['total']} ₽\nИмя: {order['customer_name']}"
)