184 lines
6.5 KiB
Python
184 lines
6.5 KiB
Python
import logging
|
||
from typing import Optional
|
||
from aiogram import Router, F
|
||
from aiogram.types import CallbackQuery, Message
|
||
from aiogram.fsm.context import FSMContext
|
||
from sqlalchemy.ext.asyncio import AsyncSession
|
||
|
||
from config import NOTIFICATION_CHANNEL
|
||
from dto.checkout import CheckoutContext
|
||
from misc.kb.admins import customer_contacts
|
||
from misc.kb.client import (
|
||
order_confirmation,
|
||
order_specs_confirmation,
|
||
return_menu,
|
||
)
|
||
from misc.states import CheckoutStorage
|
||
from misc.texts import get_order_item_list
|
||
from misc.utils import is_valid_phone
|
||
from repositories.orders import OrderRepository
|
||
from services.orders import OrderService
|
||
|
||
router = Router()
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
@router.callback_query(F.data == "checkout")
|
||
async def checkout(
|
||
cb: CallbackQuery,
|
||
state: FSMContext,
|
||
session: AsyncSession,
|
||
order_service: OrderService,
|
||
):
|
||
await state.clear()
|
||
|
||
cart = await order_service.build_full_cart_dto(session, cb.from_user.id)
|
||
await cb.message.edit_text(
|
||
text=get_order_item_list(cart), reply_markup=order_confirmation(cart.order_id)
|
||
)
|
||
|
||
|
||
@router.callback_query(F.data.startswith("confirm_order:"))
|
||
async def order_confirm(
|
||
cb: CallbackQuery,
|
||
state: FSMContext,
|
||
session: AsyncSession,
|
||
order_repo: OrderRepository,
|
||
):
|
||
await state.clear()
|
||
|
||
order_id = cb.data.split(":")[1]
|
||
if not order_id.isdigit():
|
||
await cb.message.edit_text("🍃 Что-то пошло не так.", reply_markup=return_menu)
|
||
return
|
||
|
||
order = await order_repo.get_order_by_id(session, int(order_id))
|
||
if not order or order.customer != cb.from_user.id:
|
||
await cb.message.edit_text("🍃 Что-то пошло не так.", reply_markup=return_menu)
|
||
return
|
||
|
||
await cb.message.edit_text("<b>👤 Укажите ваше имя:</b>", reply_markup=return_menu)
|
||
|
||
ctx = CheckoutContext(orig_msg=cb.message, order_id=order.id)
|
||
await state.set_state(CheckoutStorage.name)
|
||
await state.set_data({"ctx": ctx})
|
||
|
||
|
||
@router.message(CheckoutStorage.name)
|
||
async def checkout_name(msg: Message, state: FSMContext):
|
||
data = await state.get_data()
|
||
ctx: CheckoutContext = data.get("ctx", CheckoutContext)
|
||
await state.clear()
|
||
|
||
ctx.name = msg.text
|
||
await msg.delete()
|
||
|
||
await ctx.orig_msg.edit_text(
|
||
f"<i>👤 Имя: {ctx.name}</i>\n\n<b>📱 Укажите ваш номер телефона:</b>",
|
||
reply_markup=return_menu,
|
||
)
|
||
|
||
await state.set_state(CheckoutStorage.phone)
|
||
await state.set_data({"ctx": ctx})
|
||
|
||
|
||
@router.message(CheckoutStorage.phone)
|
||
async def checkout_phone(msg: Message, state: FSMContext):
|
||
data = await state.get_data()
|
||
ctx: CheckoutContext = data.get("ctx", CheckoutContext)
|
||
await state.clear()
|
||
|
||
await msg.delete()
|
||
if not is_valid_phone(msg.text):
|
||
await ctx.orig_msg.edit_text(
|
||
f"❌ <i>{msg.text}</i> не является действительным номером, попробуйте ещё раз.",
|
||
reply_markup=return_menu,
|
||
)
|
||
await state.set_state(CheckoutStorage.phone)
|
||
await state.set_data({"ctx": ctx})
|
||
return
|
||
|
||
ctx.phone = msg.text
|
||
await ctx.orig_msg.edit_text(
|
||
f"<i>👤 Имя: {ctx.name}</i>\n<i>📱 Номер телефона: {ctx.phone}</i>\n\n<b>📍 Укажите ваш адрес (город, улица):</b>",
|
||
reply_markup=return_menu,
|
||
)
|
||
await state.set_state(CheckoutStorage.address)
|
||
await state.set_data({"ctx": ctx})
|
||
|
||
|
||
@router.message(CheckoutStorage.address)
|
||
async def checkout_address(msg: Message, state: FSMContext):
|
||
data = await state.get_data()
|
||
ctx: CheckoutContext = data.get("ctx", CheckoutContext)
|
||
await state.clear()
|
||
|
||
await msg.delete()
|
||
|
||
ctx.address = msg.text
|
||
await ctx.orig_msg.edit_text(
|
||
"<b>‼️ Проверьте правильность ваших данных.</b>\n\n"
|
||
"━━━━━━━━━━━━━━\n\n"
|
||
f"<i>👤 Имя: {ctx.name}</i>\n"
|
||
f"<i>📱 Номер телефона: {ctx.phone}</i>\n"
|
||
f"<i>📍 Ваш адрес: {ctx.address}</i>\n\n"
|
||
"━━━━━━━━━━━━━━",
|
||
reply_markup=order_specs_confirmation(ctx.order_id),
|
||
)
|
||
|
||
await state.set_state(CheckoutStorage.confirmation)
|
||
await state.set_data({"ctx": ctx})
|
||
|
||
|
||
@router.callback_query(CheckoutStorage.confirmation)
|
||
@router.callback_query(F.data.startswith("payment:"))
|
||
async def payment_create(
|
||
cb: CallbackQuery,
|
||
state: FSMContext,
|
||
session: AsyncSession,
|
||
order_service: OrderService,
|
||
order_repo: OrderRepository,
|
||
):
|
||
data = await state.get_data()
|
||
ctx: Optional[CheckoutContext] = data.get("ctx")
|
||
if not ctx:
|
||
await cb.message.edit_text(
|
||
"🍃 Что-то пошло не так, повторите попытку позже...",
|
||
reply_markup=return_menu,
|
||
)
|
||
logger.warning("ctx not found on confirmation screen")
|
||
return
|
||
|
||
await state.clear()
|
||
|
||
try:
|
||
await cb.message.edit_text(
|
||
"<b>🟢 Ваш заказ успешно отправлен!</b>\n"
|
||
"<i>📦 Мы свяжемся с вами для уточнения деталей в ближайшее время.</i>\n\n"
|
||
"<b>‼️ Чтобы убедиться, что вы общаетесь с доверенным контактом ШВЕЙТЕХЦЕНТР, перешлите любое сообщение человека в этот чат.</b>",
|
||
reply_markup=return_menu,
|
||
)
|
||
|
||
cart = await order_service.build_full_cart_dto(session, cb.from_user.id)
|
||
await cb.bot.send_message(
|
||
NOTIFICATION_CHANNEL,
|
||
"🟢 Новый заказ.\n\n"
|
||
"━━━━━━━━━━━━━━\n\n"
|
||
f"<i>👤 Имя: {ctx.name}</i>\n"
|
||
f"<i>📱 Номер телефона: {ctx.phone}</i>\n"
|
||
f"<i>📍 Адрес: {ctx.address}</i>\n\n"
|
||
"━━━━━━━━━━━━━━\n"
|
||
f"{get_order_item_list(cart)}",
|
||
reply_markup=customer_contacts(
|
||
cb.from_user.id, bool(cb.from_user.username), cb.from_user.username
|
||
),
|
||
)
|
||
await order_repo.remove_order_by_customer(session, cb.from_user.id)
|
||
except Exception as e:
|
||
await cb.message.edit_text(
|
||
"🍃 Что-то пошло не так, повторите попытку позже...",
|
||
reply_markup=return_menu,
|
||
)
|
||
logger.exception(e)
|
||
return
|