from typing import Any from aiogram import F, Router, types from aiogram.fsm.context import FSMContext from aiogram.fsm.state import State, StatesGroup from aiogram.types import InlineKeyboardButton, LabeledPrice, PreCheckoutQuery from aiogram.utils.keyboard import InlineKeyboardBuilder from config import RUB_TO_XTR from database import add_connection, add_payment, check_connection_exists, get_key_count, update_balance from handlers.payments.utils import send_payment_success_notification from handlers.texts import PAYMENT_OPTIONS from logger import logger router = Router() class ReplenishBalanceState(StatesGroup): choosing_amount_stars = State() waiting_for_payment_confirmation_stars = State() entering_custom_amount_stars = State() @router.callback_query(F.data == "pay_stars") async def process_callback_pay_stars(callback_query: types.CallbackQuery, state: FSMContext, session: Any): tg_id = callback_query.message.chat.id builder = InlineKeyboardBuilder() builder.row(InlineKeyboardButton(text="πŸ€– Π‘ΠΎΡ‚ для ΠΏΠΎΠΊΡƒΠΏΠΊΠΈ Π·Π²Π΅Π·Π΄", url="https://t.me/PremiumBot")) for i in range(0, len(PAYMENT_OPTIONS), 2): if i + 1 < len(PAYMENT_OPTIONS): builder.row( InlineKeyboardButton( text=PAYMENT_OPTIONS[i]["text"], callback_data=f'stars_{PAYMENT_OPTIONS[i]["callback_data"]}', ), InlineKeyboardButton( text=PAYMENT_OPTIONS[i + 1]["text"], callback_data=f'stars_{PAYMENT_OPTIONS[i + 1]["callback_data"]}', ), ) else: builder.row( InlineKeyboardButton( text=PAYMENT_OPTIONS[i]["text"], callback_data=f'stars_{PAYMENT_OPTIONS[i]["callback_data"]}', ) ) builder.row( InlineKeyboardButton( text="πŸ’° ВвСсти свою сумму", callback_data="enter_custom_amount_stars", ) ) builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay")) key_count = await get_key_count(tg_id) if key_count == 0: exists = await check_connection_exists(tg_id) if not exists: await add_connection(tg_id, balance=0.0, trial=0, session=session) try: await callback_query.message.delete() except Exception as e: logger.error(f"НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ сообщСниС: {e}") await callback_query.message.answer( text="Π’Ρ‹Π±Π΅Ρ€ΠΈΡ‚Π΅ сумму пополнСния:", reply_markup=builder.as_markup(), ) await state.set_state(ReplenishBalanceState.choosing_amount_stars) @router.callback_query(F.data.startswith("stars_amount|")) async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext): data = callback_query.data.split("|", 1) if len(data) != 2: try: await callback_query.message.delete() except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ сообщСния: {e}") await callback_query.message.answer("НСвСрныС Π΄Π°Π½Π½Ρ‹Π΅ для Π²Ρ‹Π±ΠΎΡ€Π° суммы.") return amount_str = data[1] try: amount = int(amount_str) except ValueError: try: await callback_query.message.delete() except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠΈ сообщСния: {e}") await callback_query.message.answer("НСкоррСктная сумма.") return await state.update_data(amount=amount) await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_stars) try: builder = InlineKeyboardBuilder() builder.row( InlineKeyboardButton(text="ΠŸΠΎΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ", pay=True), ) builder.row( InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"), ) await callback_query.message.answer_invoice( title=f"Π’Ρ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ ΠΏΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° {amount} Ρ€ΡƒΠ±Π»Π΅ΠΉ.", description=f"Π’Ρ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ ΠΏΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° {amount} Ρ€ΡƒΠ±Π»Π΅ΠΉ.", prices=[LabeledPrice(label="XTR", amount=int(amount // RUB_TO_XTR))], provider_token="", payload=f"{amount}_stars", currency="XTR", reply_markup=builder.as_markup(), ) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ создании ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°: {e}") await callback_query.message.answer("ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ создании ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°.") @router.callback_query(F.data == "enter_custom_amount_stars") async def process_enter_custom_amount(callback_query: types.CallbackQuery, state: FSMContext): await callback_query.message.answer(text="Π’Π²Π΅Π΄ΠΈΡ‚Π΅ сумму пополнСния:") await state.set_state(ReplenishBalanceState.entering_custom_amount_stars) @router.message(ReplenishBalanceState.entering_custom_amount_stars) async def process_custom_amount_input(message: types.Message, state: FSMContext): if message.text.isdigit(): amount = int(message.text) if amount // RUB_TO_XTR <= 0: await message.answer(f"Π‘ΡƒΠΌΠΌΠ° Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ большС {RUB_TO_XTR}. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ сумму Π΅Ρ‰Π΅ Ρ€Π°Π·:") return await state.update_data(amount=amount) await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_stars) try: builder = InlineKeyboardBuilder() builder.row( InlineKeyboardButton(text="ΠŸΠΎΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ", pay=True), ) builder.row( InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"), ) await message.answer_invoice( title=f"Π’Ρ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ ΠΏΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° {amount} Ρ€ΡƒΠ±Π»Π΅ΠΉ.", description=f"Π’Ρ‹ Π²Ρ‹Π±Ρ€Π°Π»ΠΈ ΠΏΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π° {amount} Ρ€ΡƒΠ±Π»Π΅ΠΉ.", prices=[LabeledPrice(label="XTR", amount=int(amount // RUB_TO_XTR))], provider_token="", payload=f"{amount}_stars", currency="XTR", reply_markup=builder.as_markup(), ) except Exception as e: logger.error(f"Ошибка ΠΏΡ€ΠΈ создании ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°: {e}") await message.answer("ΠŸΡ€ΠΎΠΈΠ·ΠΎΡˆΠ»Π° ошибка ΠΏΡ€ΠΈ создании ΠΏΠ»Π°Ρ‚Π΅ΠΆΠ°.") else: await message.answer("НСкоррСктная сумма. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, Π²Π²Π΅Π΄ΠΈΡ‚Π΅ сумму Π΅Ρ‰Π΅ Ρ€Π°Π·:") @router.pre_checkout_query() async def on_pre_checkout_query(pre_checkout_query: PreCheckoutQuery): await pre_checkout_query.answer(ok=True) @router.message(F.successful_payment) async def on_successful_payment( message: types.Message, ): try: user_id = int(message.chat.id) amount = float(message.successful_payment.invoice_payload.split("_")[0]) logger.debug(f"Payment succeeded for user_id: {user_id}, amount: {amount}") await add_payment(int(user_id), float(amount), "stars") await update_balance(user_id, amount) await send_payment_success_notification(user_id, amount) except ValueError as e: logger.error(f"Ошибка ΠΊΠΎΠ½Π²Π΅Ρ€Ρ‚Π°Ρ†ΠΈΠΈ user_id ΠΈΠ»ΠΈ amount: {e}")