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 db.models.orders import OrderStatus
from dto.checkout import CheckoutContext
from misc.kb.admins import customer_contacts
from misc.kb.client import order_confirmation, order_specs_confirmation
from misc.kb.common import 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("👤 Укажите ваше имя:", 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"👤 Имя: {ctx.name}\n\n📱 Укажите ваш номер телефона:",
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"❌ {msg.text} не является действительным номером, попробуйте ещё раз.",
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"👤 Имя: {ctx.name}\n📱 Номер телефона: {ctx.phone}\n\n📍 Укажите ваш адрес (город, улица):",
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(
"‼️ Проверьте правильность ваших данных.\n\n"
"━━━━━━━━━━━━━━\n\n"
f"👤 Имя: {ctx.name}\n"
f"📱 Номер телефона: {ctx.phone}\n"
f"📍 Ваш адрес: {ctx.address}\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:
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"👤 Имя: {ctx.name}\n"
f"📱 Номер телефона: {ctx.phone}\n"
f"📍 Адрес: {ctx.address}\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.update_order_status(
session, cart.order_id, OrderStatus.CREATED
)
await cb.message.edit_text(
"🟢 Ваш заказ успешно отправлен!\n"
"📦 Мы свяжемся с вами для уточнения деталей в ближайшее время.\n\n"
"‼️ Чтобы убедиться, что вы общаетесь с доверенным контактом ШВЕЙТЕХЦЕНТР, перешлите любое сообщение человека в этот чат.",
reply_markup=return_menu,
)
except Exception as e:
await cb.message.edit_text(
"🍃 Что-то пошло не так, повторите попытку позже...",
reply_markup=return_menu,
)
logger.exception(e)
return