currency/fast flow for everyone/optimization and cache/new payment system/and more

This commit is contained in:
Vladless
2025-09-15 21:55:31 +03:00
parent 6d9e1aba4a
commit d6b920ff4d
102 changed files with 3033 additions and 1710 deletions
+162
View File
@@ -0,0 +1,162 @@
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 InlineKeyboardMarkup, InlineKeyboardButton
from sqlalchemy.ext.asyncio import AsyncSession
from database import add_user, check_user_exists, get_key_count, get_temporary_data
from handlers.buttons import CUSTOM_AMOUNT, PAY_2, MAIN_MENU
from handlers.payments.keyboards import (
back_keyboard,
build_amounts_keyboard,
parse_amount_from_callback,
pay_keyboard as build_pay_keyboard,
payment_options_for_user,
)
from handlers.texts import DEFAULT_PAYMENT_MESSAGE, ENTER_SUM
from handlers.payments.currency_rates import format_for_user
from handlers.utils import edit_or_send_message
from logger import logger
from .service import create_and_store_robokassa_payment
router = Router()
class ReplenishBalanceState(StatesGroup):
choosing_amount_robokassa = State()
waiting_for_payment_confirmation_robokassa = State()
@router.callback_query(F.data == "pay_robokassa")
async def process_callback_pay_robokassa(callback_query: types.CallbackQuery, state: FSMContext, session: Any):
tg_id = callback_query.message.chat.id
b = await get_key_count(session, tg_id)
if b == 0 and not await check_user_exists(session, tg_id):
u = callback_query.from_user
await add_user(
tg_id=u.id,
username=u.username,
first_name=u.first_name,
last_name=u.last_name,
language_code=u.language_code,
is_bot=u.is_bot,
session=session,
)
logger.info(f"[DB] Новый пользователь {tg_id} создан через Robokassa.")
language_code = getattr(callback_query.from_user, "language_code", None)
opts = await payment_options_for_user(session, tg_id, language_code, force_currency="RUB")
markup = build_amounts_keyboard(
prefix="robokassa",
pattern="{prefix}_amount|{price}",
back_cb="balance",
custom_cb=(CUSTOM_AMOUNT, "enter_custom_amount_robokassa"),
per_row=2,
opts=opts,
)
await callback_query.message.delete()
m = await callback_query.message.answer(text="Выберите сумму пополнения:", reply_markup=markup)
await state.update_data(message_id=m.message_id, chat_id=m.chat.id)
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
@router.callback_query(F.data.startswith("robokassa_"))
async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext, session: AsyncSession):
amount = parse_amount_from_callback(callback_query.data, prefixes=["robokassa"])
if not amount or amount <= 0:
await edit_or_send_message(
target_message=callback_query.message,
text="Некорректная сумма.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
force_text=True,
)
return
tg_id = callback_query.message.chat.id
url, _ = await create_and_store_robokassa_payment(session, tg_id, amount, "Пополнение баланса", inv_id=0)
kb = build_pay_keyboard(
url,
pay_text=PAY_2,
back_cb="pay_robokassa",
)
language_code = getattr(callback_query.from_user, "language_code", None)
amount_text = await format_for_user(session, tg_id, float(amount), language_code, force_currency="RUB")
await edit_or_send_message(
target_message=callback_query.message,
text=DEFAULT_PAYMENT_MESSAGE.format(amount=amount_text),
reply_markup=kb,
force_text=True,
)
@router.callback_query(F.data == "enter_custom_amount_robokassa")
async def process_custom_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
b = back_keyboard("pay_robokassa")
await edit_or_send_message(target_message=callback_query.message, text=ENTER_SUM, reply_markup=b, force_text=True)
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_robokassa)
async def handle_custom_amount_input(
event: types.Message | types.CallbackQuery,
session: AsyncSession,
pay_button_text: str = PAY_2,
main_menu_text: str = MAIN_MENU,
):
if isinstance(event, types.CallbackQuery):
message = event.message
from_user = event.from_user
tg_id = from_user.id
temp_data = await get_temporary_data(session, tg_id)
if not temp_data or temp_data["state"] not in ["waiting_for_payment", "waiting_for_renewal_payment", "waiting_for_gift_payment"]:
await edit_or_send_message(target_message=message, text="❌ Не удалось получить данные для оплаты.")
return
amount = int(temp_data["data"].get("required_amount", 0))
if amount <= 0:
await edit_or_send_message(target_message=message, text="❌ Не удалось определить сумму оплаты.")
return
else:
message = event
from_user = message.from_user
tg_id = from_user.id
text = message.text
if not text or not text.isdigit():
await message.answer("Введите корректную сумму числом.")
return
amount = int(text)
if amount <= 0:
await message.answer("Сумма должна быть больше нуля.")
return
try:
url, _ = await create_and_store_robokassa_payment(session, tg_id, amount, "Пополнение баланса", inv_id=0)
markup = InlineKeyboardMarkup(
inline_keyboard=[
[InlineKeyboardButton(text=pay_button_text, url=url)],
[InlineKeyboardButton(text=main_menu_text, callback_data="profile")],
]
)
language_code = getattr(from_user, "language_code", None)
amount_text = await format_for_user(session, tg_id, float(amount), language_code, force_currency="RUB")
text_out = DEFAULT_PAYMENT_MESSAGE.format(amount=amount_text)
await edit_or_send_message(target_message=message, text=text_out, reply_markup=markup)
except Exception as e:
from logger import logger as _lg
_lg.error(f"Ошибка при создании платежа для пользователя {tg_id}: {e}")
await edit_or_send_message(
target_message=message,
text="Произошла ошибка при создании платежа. Попробуйте позже.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
)