diff --git a/.env.example b/.env.example index cfcab541..36bdac6b 100644 --- a/.env.example +++ b/.env.example @@ -491,16 +491,11 @@ YOOKASSA_WEBHOOK_PORT=8082 YOOKASSA_MIN_AMOUNT_KOPEKS=5000 YOOKASSA_MAX_AMOUNT_KOPEKS=1000000 -# Быстрый выбор суммы пополнения через YooKassa -YOOKASSA_QUICK_AMOUNT_SELECTION_ENABLED=true - # Рекуррентные платежи YooKassa (автосохранение карты для автоплатежей) YOOKASSA_RECURRENT_ENABLED=false # true = карта сохраняется обязательно, false = пользователь решает (чекбокс на стороне YooKassa) YOOKASSA_RECURRENT_REQUIRED=true -# Отключить отображение кнопок выбора суммы пополнения (оставить только ввод вручную) -DISABLE_TOPUP_BUTTONS=false # Отключить пополнение баланса через поддержку SUPPORT_TOPUP_ENABLED=true diff --git a/app/config.py b/app/config.py index 751db510..214a6b81 100644 --- a/app/config.py +++ b/app/config.py @@ -353,10 +353,8 @@ class Settings(BaseSettings): YOOKASSA_TRUSTED_PROXY_NETWORKS: str = '' YOOKASSA_MIN_AMOUNT_KOPEKS: int = 5000 YOOKASSA_MAX_AMOUNT_KOPEKS: int = 1000000 - YOOKASSA_QUICK_AMOUNT_SELECTION_ENABLED: bool = False YOOKASSA_RECURRENT_ENABLED: bool = False YOOKASSA_RECURRENT_REQUIRED: bool = False - DISABLE_TOPUP_BUTTONS: bool = False SUPPORT_TOPUP_ENABLED: bool = True PAYMENT_VERIFICATION_AUTO_CHECK_ENABLED: bool = False PAYMENT_VERIFICATION_AUTO_CHECK_INTERVAL_MINUTES: int = 10 @@ -1254,10 +1252,6 @@ class Settings(BaseSettings): return bool(value) - def is_quick_amount_buttons_enabled(self) -> bool: - """Кнопки быстрого выбора суммы пополнения отключены.""" - return False - def get_available_languages(self) -> list[str]: defaults = ['ru', 'en', 'ua', 'zh', 'fa'] diff --git a/app/handlers/balance/cloudpayments.py b/app/handlers/balance/cloudpayments.py index aa34b137..a04da927 100644 --- a/app/handlers/balance/cloudpayments.py +++ b/app/handlers/balance/cloudpayments.py @@ -129,9 +129,9 @@ async def process_cloudpayments_payment_amount( state: FSMContext, ): """ - Process payment amount directly (called from quick_amount handlers). + Process payment amount directly. - Similar to process_heleket_payment_amount and other payment handlers. + Similar to other payment amount handlers. """ texts = get_texts(db_user.language) @@ -197,7 +197,7 @@ async def start_cloudpayments_payment( """ Start CloudPayments payment flow. - Shows amount input prompt or quick amount buttons. + Shows amount input prompt. """ texts = get_texts(db_user.language) @@ -377,121 +377,3 @@ async def process_cloudpayments_amount( logger.info('CloudPayments payment created: user amount=₽', telegram_id=db_user.telegram_id, amount_rub=amount_rub) -@error_handler -async def handle_cloudpayments_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """ - Handle quick amount selection for CloudPayments. - - Called when user clicks a predefined amount button. - """ - texts = get_texts(db_user.language) - - if not settings.is_cloudpayments_enabled(): - await callback.answer( - texts.t('CLOUDPAYMENTS_NOT_AVAILABLE', 'CloudPayments временно недоступен'), - show_alert=True, - ) - return - - # Extract amount from callback data: topup_amount|cloudpayments|{amount_kopeks} - try: - parts = callback.data.split('|') - if len(parts) >= 3: - amount_kopeks = int(parts[2]) - else: - await callback.answer('Invalid callback data', show_alert=True) - return - except (ValueError, IndexError): - await callback.answer('Invalid amount', show_alert=True) - return - - amount_rub = amount_kopeks / 100 - - # Validate amount - if amount_kopeks < settings.CLOUDPAYMENTS_MIN_AMOUNT_KOPEKS: - await callback.answer( - texts.t('AMOUNT_TOO_LOW_SHORT', 'Сумма слишком мала'), - show_alert=True, - ) - return - - if amount_kopeks > settings.CLOUDPAYMENTS_MAX_AMOUNT_KOPEKS: - await callback.answer( - texts.t('AMOUNT_TOO_HIGH_SHORT', 'Сумма слишком велика'), - show_alert=True, - ) - return - - await callback.answer() - - # Create payment - payment_service = PaymentService() - - description = settings.PAYMENT_BALANCE_TEMPLATE.format( - service_name=settings.PAYMENT_SERVICE_NAME, - description=settings.CLOUDPAYMENTS_DESCRIPTION, - ) - - result = await payment_service.create_cloudpayments_payment( - db=db, - user_id=db_user.id, - amount_kopeks=amount_kopeks, - description=description, - telegram_id=db_user.telegram_id, - language=db_user.language, - ) - - if not result: - await callback.message.edit_text( - texts.t( - 'PAYMENT_CREATE_ERROR', - 'Не удалось создать платёж. Попробуйте позже.', - ), - reply_markup=get_back_keyboard(db_user.language), - parse_mode='HTML', - ) - return - - payment_url = result.get('payment_url') - - # Create keyboard with payment button - keyboard = InlineKeyboardMarkup( - inline_keyboard=[ - [ - InlineKeyboardButton( - text=texts.t( - 'PAY_BUTTON', - '💳 Оплатить {amount}₽', - ).format(amount=f'{amount_rub:.0f}'), - url=payment_url, - ) - ], - [ - InlineKeyboardButton( - text=texts.t('BACK_BUTTON', '◀️ Назад'), - callback_data='menu_balance', - ) - ], - ] - ) - - await callback.message.edit_text( - texts.t( - 'CLOUDPAYMENTS_PAYMENT_CREATED', - '💳 Оплата банковской картой\n\n' - 'Сумма: {amount}₽\n\n' - 'Нажмите кнопку ниже для оплаты.\n' - 'После успешной оплаты баланс будет пополнен автоматически.', - ).format(amount=f'{amount_rub:.2f}'), - reply_markup=keyboard, - parse_mode='HTML', - ) - - logger.info( - 'CloudPayments payment created (quick): user amount=₽', telegram_id=db_user.telegram_id, amount_rub=amount_rub - ) diff --git a/app/handlers/balance/cryptobot.py b/app/handlers/balance/cryptobot.py index 738751fd..916eaeb1 100644 --- a/app/handlers/balance/cryptobot.py +++ b/app/handlers/balance/cryptobot.py @@ -53,41 +53,18 @@ async def start_cryptobot_payment(callback: types.CallbackQuery, db_user: User, available_assets = settings.get_cryptobot_assets() assets_text = ', '.join(available_assets) - # Формируем текст сообщения в зависимости от настройки - if settings.is_quick_amount_buttons_enabled(): - message_text = ( - f'🪙 Пополнение криптовалютой\n\n' - f'Выберите сумму пополнения или введите вручную сумму ' - f'от 100 до 100,000 ₽:\n\n' - f'💰 Доступные активы: {assets_text}\n' - f'⚡ Мгновенное зачисление на баланс\n' - f'🔒 Безопасная оплата через CryptoBot\n\n' - f'{rate_text}\n' - f'Сумма будет автоматически конвертирована в USD для оплаты.' - ) - else: - message_text = ( - f'🪙 Пополнение криптовалютой\n\n' - f'Введите сумму для пополнения от 100 до 100,000 ₽:\n\n' - f'💰 Доступные активы: {assets_text}\n' - f'⚡ Мгновенное зачисление на баланс\n' - f'🔒 Безопасная оплата через CryptoBot\n\n' - f'{rate_text}\n' - f'Сумма будет автоматически конвертирована в USD для оплаты.' - ) + message_text = ( + f'🪙 Пополнение криптовалютой\n\n' + f'Введите сумму для пополнения от 100 до 100,000 ₽:\n\n' + f'💰 Доступные активы: {assets_text}\n' + f'⚡ Мгновенное зачисление на баланс\n' + f'🔒 Безопасная оплата через CryptoBot\n\n' + f'{rate_text}\n' + f'Сумма будет автоматически конвертирована в USD для оплаты.' + ) - # Создаем клавиатуру keyboard = get_back_keyboard(db_user.language) - # Если включен быстрый выбор суммы и не отключены кнопки, добавляем кнопки - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - # Вставляем кнопки быстрого выбора перед кнопкой "Назад" - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text(message_text, reply_markup=keyboard, parse_mode='HTML') await state.set_state(BalanceStates.waiting_for_amount) diff --git a/app/handlers/balance/freekassa.py b/app/handlers/balance/freekassa.py index 838dd389..2699e5a4 100644 --- a/app/handlers/balance/freekassa.py +++ b/app/handlers/balance/freekassa.py @@ -154,7 +154,7 @@ async def process_freekassa_payment_amount( payment_method: str | None = None, ): """ - Process payment amount directly (called from quick_amount handlers). + Process payment amount directly. payment_method: 'freekassa', 'freekassa_sbp', 'freekassa_card' """ texts = get_texts(db_user.language) @@ -372,125 +372,3 @@ async def process_freekassa_custom_amount( ) -async def _process_freekassa_quick_amount_impl( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, - payment_method: str, -): - """ - Process quick amount selection for Freekassa payment. - Called when user clicks a predefined amount button. - payment_method: 'freekassa', 'freekassa_sbp', 'freekassa_card' - """ - texts = get_texts(db_user.language) - - if not settings.is_freekassa_enabled(): - await callback.answer( - texts.t('FREEKASSA_NOT_AVAILABLE', 'Freekassa временно недоступен'), - show_alert=True, - ) - return - - if payment_method == 'freekassa_sbp' and not settings.is_freekassa_sbp_enabled(): - await callback.answer( - texts.t('FREEKASSA_NOT_AVAILABLE', 'Freekassa временно недоступен'), - show_alert=True, - ) - return - - if payment_method == 'freekassa_card' and not settings.is_freekassa_card_enabled(): - await callback.answer( - texts.t('FREEKASSA_NOT_AVAILABLE', 'Freekassa временно недоступен'), - show_alert=True, - ) - return - - # Extract amount from callback data: topup_amount|{method}|{amount_kopeks} - try: - parts = callback.data.split('|') - if len(parts) >= 3: - amount_kopeks = int(parts[2]) - else: - await callback.answer('Invalid callback data', show_alert=True) - return - except (ValueError, IndexError): - await callback.answer('Invalid amount', show_alert=True) - return - - # Проверка ограничения на пополнение - if getattr(db_user, 'restriction_topup', False): - reason = getattr(db_user, 'restriction_reason', None) or 'Действие ограничено администратором' - support_url = settings.get_support_contact_url() - keyboard = [] - if support_url: - keyboard.append([InlineKeyboardButton(text='🆘 Обжаловать', url=support_url)]) - keyboard.append([InlineKeyboardButton(text=texts.BACK, callback_data='menu_balance')]) - - await callback.message.edit_text( - f'🚫 Пополнение ограничено\n\n{reason}', - parse_mode='HTML', - reply_markup=InlineKeyboardMarkup(inline_keyboard=keyboard), - ) - return - - # Validate amount - min_amount = settings.FREEKASSA_MIN_AMOUNT_KOPEKS - max_amount = settings.FREEKASSA_MAX_AMOUNT_KOPEKS - - if amount_kopeks < min_amount: - await callback.answer( - texts.t('AMOUNT_TOO_LOW_SHORT', 'Сумма слишком мала'), - show_alert=True, - ) - return - - if amount_kopeks > max_amount: - await callback.answer( - texts.t('AMOUNT_TOO_HIGH_SHORT', 'Сумма слишком велика'), - show_alert=True, - ) - return - - await callback.answer() - await state.clear() - - await _create_freekassa_payment_and_respond( - message_or_callback=callback.message, - db_user=db_user, - db=db, - amount_kopeks=amount_kopeks, - edit_message=True, - payment_method=payment_method, - ) - - -@error_handler -async def process_freekassa_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - await _process_freekassa_quick_amount_impl(callback, db_user, db, state, 'freekassa') - - -@error_handler -async def process_freekassa_sbp_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - await _process_freekassa_quick_amount_impl(callback, db_user, db, state, 'freekassa_sbp') - - -@error_handler -async def process_freekassa_card_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - await _process_freekassa_quick_amount_impl(callback, db_user, db, state, 'freekassa_card') diff --git a/app/handlers/balance/heleket.py b/app/handlers/balance/heleket.py index 205c3ac8..30082e23 100644 --- a/app/handlers/balance/heleket.py +++ b/app/handlers/balance/heleket.py @@ -72,13 +72,6 @@ async def start_heleket_payment( keyboard = get_back_keyboard(db_user.language) - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_buttons: - keyboard.inline_keyboard = quick_buttons + keyboard.inline_keyboard - await callback.message.edit_text( '\n'.join(filter(None, message_lines)), reply_markup=keyboard, diff --git a/app/handlers/balance/kassa_ai.py b/app/handlers/balance/kassa_ai.py index cce40352..b813a8be 100644 --- a/app/handlers/balance/kassa_ai.py +++ b/app/handlers/balance/kassa_ai.py @@ -168,7 +168,7 @@ async def process_kassa_ai_payment_amount( state: FSMContext, payment_method: str = 'kassa_ai', ): - """Process payment amount directly (called from custom_amount and quick_amount handlers).""" + """Process payment amount directly (called from custom_amount handlers).""" texts = get_texts(db_user.language) # Проверка ограничения на пополнение @@ -275,54 +275,6 @@ async def _start_kassa_ai_sub_topup( ) -async def _process_kassa_ai_sub_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, - payment_method: str, -): - """Generic quick amount handler for any KassaAI sub-method.""" - cfg = _KASSA_AI_METHOD_CONFIG[payment_method] - texts = get_texts(db_user.language) - - if not cfg['is_enabled'](): - await callback.answer(texts.t('KASSA_AI_NOT_AVAILABLE', cfg['unavailable_text']), show_alert=True) - return - - try: - parts = callback.data.split('|') - amount_kopeks = int(parts[2]) if len(parts) >= 3 else None - if amount_kopeks is None: - raise ValueError - except (ValueError, IndexError): - await callback.answer('Invalid amount', show_alert=True) - return - - if await _check_topup_restriction(callback, db_user): - return - - min_amount = settings.KASSA_AI_MIN_AMOUNT_KOPEKS - max_amount = settings.KASSA_AI_MAX_AMOUNT_KOPEKS - if amount_kopeks < min_amount: - await callback.answer(texts.t('AMOUNT_TOO_LOW_SHORT', 'Сумма слишком мала'), show_alert=True) - return - if amount_kopeks > max_amount: - await callback.answer(texts.t('AMOUNT_TOO_HIGH_SHORT', 'Сумма слишком велика'), show_alert=True) - return - - await callback.answer() - await state.clear() - await _create_kassa_ai_payment_and_respond( - message_or_callback=callback.message, - db_user=db_user, - db=db, - amount_kopeks=amount_kopeks, - edit_message=True, - payment_method=payment_method, - ) - - # --- Public handler functions (registered in main.py) --- @@ -376,17 +328,6 @@ async def process_kassa_ai_custom_amount( ) -@error_handler -async def process_kassa_ai_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """Process quick amount selection for KassaAI payment.""" - await _process_kassa_ai_sub_quick_amount(callback, db_user, db, state, 'kassa_ai') - - @error_handler async def start_kassa_ai_sbp_topup( callback: types.CallbackQuery, @@ -398,17 +339,6 @@ async def start_kassa_ai_sbp_topup( await _start_kassa_ai_sub_topup(callback, db_user, db, state, 'kassa_ai_sbp') -@error_handler -async def process_kassa_ai_sbp_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """Process quick amount for KassaAI SBP.""" - await _process_kassa_ai_sub_quick_amount(callback, db_user, db, state, 'kassa_ai_sbp') - - @error_handler async def start_kassa_ai_card_topup( callback: types.CallbackQuery, @@ -420,12 +350,3 @@ async def start_kassa_ai_card_topup( await _start_kassa_ai_sub_topup(callback, db_user, db, state, 'kassa_ai_card') -@error_handler -async def process_kassa_ai_card_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """Process quick amount for KassaAI Card.""" - await _process_kassa_ai_sub_quick_amount(callback, db_user, db, state, 'kassa_ai_card') diff --git a/app/handlers/balance/main.py b/app/handlers/balance/main.py index 03a5034d..0e880558 100644 --- a/app/handlers/balance/main.py +++ b/app/handlers/balance/main.py @@ -157,102 +157,6 @@ async def route_payment_by_method( return False -async def get_quick_amount_buttons(language: str, user: User) -> list: - """ - Generate quick amount buttons with user-specific pricing and discounts. - - Uses PricingEngine as the single source of truth for all price calculations, - including base period price, devices, servers, traffic, and per-category discounts. - - Args: - language: User's language for formatting - user: User object to calculate personalized discounts - - Returns: - List of button rows for inline keyboard - """ - if not settings.is_quick_amount_buttons_enabled(): - return [] - - from app.database.crud.subscription import get_subscription_by_user_id - from app.database.database import AsyncSessionLocal - from app.services.pricing_engine import pricing_engine - - texts = get_texts(language) - - buttons = [] - - async with AsyncSessionLocal() as db: - subscription = await get_subscription_by_user_id(db, user.id) - - tariff = None - tariff_periods = None - if settings.is_tariffs_mode() and subscription and subscription.tariff_id: - tariff = subscription.tariff - if tariff and tariff.period_prices: - tariff_periods = sorted(int(k) for k in tariff.period_prices.keys()) - - if tariff_periods: - periods = tariff_periods[:6] - else: - periods = settings.get_available_subscription_periods()[:6] - - for period in periods: - try: - if tariff and tariff_periods and period in tariff_periods: - result = await pricing_engine.calculate_tariff_purchase_price( - tariff, - period, - device_limit=subscription.device_limit if subscription else None, - user=user, - ) - elif subscription: - result = await pricing_engine.calculate_renewal_price(db, subscription, period, user=user) - else: - result = await pricing_engine.calculate_classic_new_subscription_price( - db, - period, - [], - 0, - settings.DEFAULT_DEVICE_LIMIT, - user=user, - ) - - total_price = result.final_total - original_total = result.original_total - - if total_price <= 0: - continue - - callback_data = f'quick_amount_{total_price}' - period_label = f'{period} дней' - - has_discount = original_total > total_price and original_total > 0 - if has_discount: - discount_pct = round((original_total - total_price) * 100 / original_total) - if discount_pct > 0: - button_text = ( - f'{texts.format_price(original_total)} ➜ ' - f'{texts.format_price(total_price)} ' - f'(-{discount_pct}%) • {period_label}' - ) - else: - button_text = f'{texts.format_price(total_price)} • {period_label}' - else: - button_text = f'{texts.format_price(total_price)} • {period_label}' - - buttons.append(types.InlineKeyboardButton(text=button_text, callback_data=callback_data)) - except Exception: - logger.warning('Failed to calculate price for period', period=period) - continue - - keyboard_rows = [] - for i in range(0, len(buttons), 2): - keyboard_rows.append(buttons[i : i + 2]) - - return keyboard_rows - - @error_handler async def show_balance_menu(callback: types.CallbackQuery, db_user: User, db: AsyncSession): # Проверяем, доступно ли сообщение @@ -640,37 +544,6 @@ async def handle_sbp_payment(callback: types.CallbackQuery, db: AsyncSession): await callback.answer('❌ Ошибка обработки платежа', show_alert=True) -@error_handler -async def handle_quick_amount_selection(callback: types.CallbackQuery, db_user: User, state: FSMContext): - """ - Обработчик выбора суммы через кнопки быстрого выбора - """ - # Проверяем, что пользователь в правильном состоянии FSM - current_state = await state.get_state() - if current_state != BalanceStates.waiting_for_amount: - await callback.answer('❌ Сначала выберите способ оплаты', show_alert=True) - return - - # Извлекаем сумму из callback_data - try: - amount_kopeks = int(callback.data.split('_')[-1]) - - # Получаем метод оплаты из состояния - data = await state.get_data() - payment_method = data.get('payment_method', 'yookassa') - - # Роутим платеж на соответствующий обработчик - if not await route_payment_by_method(callback.message, db_user, amount_kopeks, state, payment_method): - await callback.answer('❌ Неизвестный способ оплаты', show_alert=True) - return - - except ValueError: - await callback.answer('❌ Ошибка обработки суммы', show_alert=True) - except Exception as e: - logger.error('Ошибка обработки быстрого выбора суммы', error=e) - await callback.answer('❌ Ошибка обработки запроса', show_alert=True) - - @error_handler async def handle_topup_amount_callback( callback: types.CallbackQuery, @@ -797,52 +670,37 @@ def register_balance_handlers(dp: Dispatcher): dp.callback_query.register(start_heleket_payment, F.data == 'topup_heleket') dp.callback_query.register(check_heleket_payment_status, F.data.startswith('check_heleket_')) - from .cloudpayments import handle_cloudpayments_quick_amount, start_cloudpayments_payment + from .cloudpayments import start_cloudpayments_payment dp.callback_query.register(start_cloudpayments_payment, F.data == 'topup_cloudpayments') - dp.callback_query.register(handle_cloudpayments_quick_amount, F.data.startswith('topup_amount|cloudpayments|')) from .freekassa import ( - process_freekassa_card_quick_amount, - process_freekassa_quick_amount, - process_freekassa_sbp_quick_amount, start_freekassa_card_topup, start_freekassa_sbp_topup, start_freekassa_topup, ) dp.callback_query.register(start_freekassa_topup, F.data == 'topup_freekassa') - dp.callback_query.register(process_freekassa_quick_amount, F.data.startswith('topup_amount|freekassa|')) dp.callback_query.register(start_freekassa_sbp_topup, F.data == 'topup_freekassa_sbp') - dp.callback_query.register(process_freekassa_sbp_quick_amount, F.data.startswith('topup_amount|freekassa_sbp|')) dp.callback_query.register(start_freekassa_card_topup, F.data == 'topup_freekassa_card') - dp.callback_query.register(process_freekassa_card_quick_amount, F.data.startswith('topup_amount|freekassa_card|')) from .kassa_ai import ( - process_kassa_ai_card_quick_amount, - process_kassa_ai_quick_amount, - process_kassa_ai_sbp_quick_amount, start_kassa_ai_card_topup, start_kassa_ai_sbp_topup, start_kassa_ai_topup, ) dp.callback_query.register(start_kassa_ai_topup, F.data == 'topup_kassa_ai') - dp.callback_query.register(process_kassa_ai_quick_amount, F.data.startswith('topup_amount|kassa_ai|')) dp.callback_query.register(start_kassa_ai_sbp_topup, F.data == 'topup_kassa_ai_sbp') - dp.callback_query.register(process_kassa_ai_sbp_quick_amount, F.data.startswith('topup_amount|kassa_ai_sbp|')) dp.callback_query.register(start_kassa_ai_card_topup, F.data == 'topup_kassa_ai_card') - dp.callback_query.register(process_kassa_ai_card_quick_amount, F.data.startswith('topup_amount|kassa_ai_card|')) - from .riopay import process_riopay_quick_amount, start_riopay_topup + from .riopay import start_riopay_topup dp.callback_query.register(start_riopay_topup, F.data == 'topup_riopay') - dp.callback_query.register(process_riopay_quick_amount, F.data.startswith('topup_amount|riopay|')) - from .severpay import process_severpay_quick_amount, start_severpay_topup + from .severpay import start_severpay_topup dp.callback_query.register(start_severpay_topup, F.data == 'topup_severpay') - dp.callback_query.register(process_severpay_quick_amount, F.data.startswith('topup_amount|severpay|')) from .mulenpay import check_mulenpay_payment_status @@ -862,9 +720,6 @@ def register_balance_handlers(dp: Dispatcher): dp.callback_query.register(handle_payment_methods_unavailable, F.data == 'payment_methods_unavailable') - # Регистрируем обработчик для кнопок быстрого выбора суммы - dp.callback_query.register(handle_quick_amount_selection, F.data.startswith('quick_amount_')) - dp.callback_query.register(handle_topup_amount_callback, F.data.startswith('topup_amount|')) dp.callback_query.register(handle_saved_cards_list, F.data == 'saved_cards_list') diff --git a/app/handlers/balance/mulenpay.py b/app/handlers/balance/mulenpay.py index 04f308dd..8098b116 100644 --- a/app/handlers/balance/mulenpay.py +++ b/app/handlers/balance/mulenpay.py @@ -65,13 +65,6 @@ async def start_mulenpay_payment( keyboard = get_back_keyboard(db_user.language) - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text( message_text, reply_markup=keyboard, diff --git a/app/handlers/balance/pal24.py b/app/handlers/balance/pal24.py index f0cafe83..5114afad 100644 --- a/app/handlers/balance/pal24.py +++ b/app/handlers/balance/pal24.py @@ -303,13 +303,6 @@ async def start_pal24_payment( keyboard = get_back_keyboard(db_user.language) - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text( message_text, reply_markup=keyboard, diff --git a/app/handlers/balance/platega.py b/app/handlers/balance/platega.py index 708e125e..50a13e11 100644 --- a/app/handlers/balance/platega.py +++ b/app/handlers/balance/platega.py @@ -71,13 +71,6 @@ async def _prompt_amount( keyboard = get_back_keyboard(db_user.language) - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await message.edit_text( prompt_template.format( method_name=method_name, diff --git a/app/handlers/balance/riopay.py b/app/handlers/balance/riopay.py index 6b198b69..ab482aab 100644 --- a/app/handlers/balance/riopay.py +++ b/app/handlers/balance/riopay.py @@ -136,7 +136,7 @@ async def process_riopay_payment_amount( state: FSMContext, ): """ - Process payment amount directly (called from quick_amount handlers). + Process payment amount directly. """ texts = get_texts(db_user.language) @@ -284,73 +284,3 @@ async def process_riopay_custom_amount( ) -@error_handler -async def process_riopay_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """ - Process quick amount selection for RioPay payment. - Called when user clicks a predefined amount button. - """ - texts = get_texts(db_user.language) - - if not settings.is_riopay_enabled(): - await callback.answer( - texts.t('RIOPAY_NOT_AVAILABLE', 'RioPay временно недоступен'), - show_alert=True, - ) - return - - # Extract amount from callback data: topup_amount|riopay|{amount_kopeks} - try: - parts = callback.data.split('|') - if len(parts) >= 3: - amount_kopeks = int(parts[2]) - else: - await callback.answer('Invalid callback data', show_alert=True) - return - except (ValueError, IndexError): - await callback.answer('Invalid amount', show_alert=True) - return - - restriction_kb = _check_topup_restriction(db_user, texts) - if restriction_kb: - reason = getattr(db_user, 'restriction_reason', None) or 'Действие ограничено администратором' - await callback.message.edit_text( - f'🚫 Пополнение ограничено\n\n{reason}', - parse_mode='HTML', - reply_markup=restriction_kb, - ) - return - - # Validate amount - min_amount = settings.RIOPAY_MIN_AMOUNT_KOPEKS - max_amount = settings.RIOPAY_MAX_AMOUNT_KOPEKS - - if amount_kopeks < min_amount: - await callback.answer( - texts.t('AMOUNT_TOO_LOW_SHORT', 'Сумма слишком мала'), - show_alert=True, - ) - return - - if amount_kopeks > max_amount: - await callback.answer( - texts.t('AMOUNT_TOO_HIGH_SHORT', 'Сумма слишком велика'), - show_alert=True, - ) - return - - await callback.answer() - await state.clear() - - await _create_riopay_payment_and_respond( - message_or_callback=callback.message, - db_user=db_user, - db=db, - amount_kopeks=amount_kopeks, - edit_message=True, - ) diff --git a/app/handlers/balance/severpay.py b/app/handlers/balance/severpay.py index 7282571c..338b77b3 100644 --- a/app/handlers/balance/severpay.py +++ b/app/handlers/balance/severpay.py @@ -136,7 +136,7 @@ async def process_severpay_payment_amount( state: FSMContext, ): """ - Process payment amount directly (called from quick_amount handlers). + Process payment amount directly. """ texts = get_texts(db_user.language) @@ -245,73 +245,3 @@ async def start_severpay_topup( ) -@error_handler -async def process_severpay_quick_amount( - callback: types.CallbackQuery, - db_user: User, - db: AsyncSession, - state: FSMContext, -): - """ - Process quick amount selection for SeverPay payment. - Called when user clicks a predefined amount button. - """ - texts = get_texts(db_user.language) - - if not settings.is_severpay_enabled(): - await callback.answer( - texts.t('SEVERPAY_NOT_AVAILABLE', 'SeverPay временно недоступен'), - show_alert=True, - ) - return - - # Extract amount from callback data: topup_amount|severpay|{amount_kopeks} - try: - parts = callback.data.split('|') - if len(parts) >= 3: - amount_kopeks = int(parts[2]) - else: - await callback.answer('Invalid callback data', show_alert=True) - return - except (ValueError, IndexError): - await callback.answer('Invalid amount', show_alert=True) - return - - restriction_kb = _check_topup_restriction(db_user, texts) - if restriction_kb: - reason = getattr(db_user, 'restriction_reason', None) or 'Действие ограничено администратором' - await callback.message.edit_text( - f'🚫 Пополнение ограничено\n\n{reason}', - parse_mode='HTML', - reply_markup=restriction_kb, - ) - return - - # Validate amount - min_amount = settings.SEVERPAY_MIN_AMOUNT_KOPEKS - max_amount = settings.SEVERPAY_MAX_AMOUNT_KOPEKS - - if amount_kopeks < min_amount: - await callback.answer( - texts.t('AMOUNT_TOO_LOW_SHORT', 'Сумма слишком мала'), - show_alert=True, - ) - return - - if amount_kopeks > max_amount: - await callback.answer( - texts.t('AMOUNT_TOO_HIGH_SHORT', 'Сумма слишком велика'), - show_alert=True, - ) - return - - await callback.answer() - await state.clear() - - await _create_severpay_payment_and_respond( - message_or_callback=callback.message, - db_user=db_user, - db=db, - amount_kopeks=amount_kopeks, - edit_message=True, - ) diff --git a/app/handlers/balance/stars.py b/app/handlers/balance/stars.py index 13ef433c..bc1eb0ff 100644 --- a/app/handlers/balance/stars.py +++ b/app/handlers/balance/stars.py @@ -40,24 +40,10 @@ async def start_stars_payment(callback: types.CallbackQuery, db_user: User, stat await callback.answer() return - # Формируем текст сообщения в зависимости от настройки - if settings.is_quick_amount_buttons_enabled(): - message_text = '⭐ Пополнение через Telegram Stars\n\nВыберите сумму пополнения или введите вручную:' - else: - message_text = texts.TOP_UP_AMOUNT + message_text = texts.TOP_UP_AMOUNT - # Создаем клавиатуру keyboard = get_back_keyboard(db_user.language) - # Если включен быстрый выбор суммы и не отключены кнопки, добавляем кнопки - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - # Вставляем кнопки быстрого выбора перед кнопкой "Назад" - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text(message_text, reply_markup=keyboard) await state.update_data( diff --git a/app/handlers/balance/wata.py b/app/handlers/balance/wata.py index 362bba5c..c086abea 100644 --- a/app/handlers/balance/wata.py +++ b/app/handlers/balance/wata.py @@ -61,13 +61,6 @@ async def start_wata_payment( keyboard = get_back_keyboard(db_user.language) - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text( message_text, reply_markup=keyboard, diff --git a/app/handlers/balance/yookassa.py b/app/handlers/balance/yookassa.py index 08767133..a6f9e025 100644 --- a/app/handlers/balance/yookassa.py +++ b/app/handlers/balance/yookassa.py @@ -46,31 +46,13 @@ async def start_yookassa_payment(callback: types.CallbackQuery, db_user: User, s min_amount_rub = settings.YOOKASSA_MIN_AMOUNT_KOPEKS / 100 max_amount_rub = settings.YOOKASSA_MAX_AMOUNT_KOPEKS / 100 - # Формируем текст сообщения в зависимости от настройки - if settings.is_quick_amount_buttons_enabled(): - message_text = ( - f'💳 Оплата банковской картой\n\n' - f'Выберите сумму пополнения или введите вручную сумму ' - f'от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' - ) - else: - message_text = ( - f'💳 Оплата банковской картой\n\n' - f'Введите сумму для пополнения от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' - ) + message_text = ( + f'💳 Оплата банковской картой\n\n' + f'Введите сумму для пополнения от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' + ) - # Создаем клавиатуру keyboard = get_back_keyboard(db_user.language) - # Если включен быстрый выбор суммы и не отключены кнопки, добавляем кнопки - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - # Вставляем кнопки быстрого выбора перед кнопкой "Назад" - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text(message_text, reply_markup=keyboard, parse_mode='HTML') await state.set_state(BalanceStates.waiting_for_amount) @@ -110,31 +92,13 @@ async def start_yookassa_sbp_payment(callback: types.CallbackQuery, db_user: Use min_amount_rub = settings.YOOKASSA_MIN_AMOUNT_KOPEKS / 100 max_amount_rub = settings.YOOKASSA_MAX_AMOUNT_KOPEKS / 100 - # Формируем текст сообщения в зависимости от настройки - if settings.is_quick_amount_buttons_enabled(): - message_text = ( - f'🏦 Оплата через СБП\n\n' - f'Выберите сумму пополнения или введите вручную сумму ' - f'от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' - ) - else: - message_text = ( - f'🏦 Оплата через СБП\n\n' - f'Введите сумму для пополнения от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' - ) + message_text = ( + f'🏦 Оплата через СБП\n\n' + f'Введите сумму для пополнения от {min_amount_rub:.0f} до {max_amount_rub:,.0f} рублей:' + ) - # Создаем клавиатуру keyboard = get_back_keyboard(db_user.language) - # Если включен быстрый выбор суммы и не отключены кнопки, добавляем кнопки - if settings.is_quick_amount_buttons_enabled(): - from .main import get_quick_amount_buttons - - quick_amount_buttons = await get_quick_amount_buttons(db_user.language, db_user) - if quick_amount_buttons: - # Вставляем кнопки быстрого выбора перед кнопкой "Назад" - keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard - await callback.message.edit_text(message_text, reply_markup=keyboard, parse_mode='HTML') await state.set_state(BalanceStates.waiting_for_amount) diff --git a/app/services/system_settings_service.py b/app/services/system_settings_service.py index 063652f5..53b5adb0 100644 --- a/app/services/system_settings_service.py +++ b/app/services/system_settings_service.py @@ -275,7 +275,6 @@ class BotConfigurationService: 'SIMPLE_SUBSCRIPTION_DEVICE_LIMIT': 'SIMPLE_SUBSCRIPTION', 'SIMPLE_SUBSCRIPTION_TRAFFIC_GB': 'SIMPLE_SUBSCRIPTION', 'SIMPLE_SUBSCRIPTION_SQUAD_UUID': 'SIMPLE_SUBSCRIPTION', - 'DISABLE_TOPUP_BUTTONS': 'PAYMENT', 'SUPPORT_TOPUP_ENABLED': 'PAYMENT', 'ENABLE_NOTIFICATIONS': 'NOTIFICATIONS', 'NOTIFICATION_RETRY_ATTEMPTS': 'NOTIFICATIONS',