import json import logging from typing import Optional from aiogram import F, Router, types from sqlalchemy.ext.asyncio import AsyncSession from bot.keyboards.inline.user_keyboards import get_payment_url_keyboard from bot.middlewares.i18n import JsonI18n from bot.services.platega_service import PlategaService from config.settings import Settings from db.dal import payment_dal router = Router(name="user_subscription_payments_platega_router") @router.callback_query( F.data.startswith("pay_platega_sbp:") | F.data.startswith("pay_platega_crypto:") | F.data.startswith("pay_platega:") ) async def pay_platega_callback_handler( callback: types.CallbackQuery, settings: Settings, i18n_data: dict, platega_service: PlategaService, session: AsyncSession, ): callback_prefix, _, _ = (callback.data or "").partition(":") if callback_prefix == "pay_platega_crypto": platega_method_id = settings.PLATEGA_CRYPTO_METHOD platega_variant = "crypto" if not settings.PLATEGA_CRYPTO_ENABLED: try: await callback.answer() except Exception: pass return elif callback_prefix == "pay_platega_sbp": platega_method_id = settings.platega_sbp_method_resolved platega_variant = "sbp" if not settings.PLATEGA_SBP_ENABLED: try: await callback.answer() except Exception: pass return else: # Legacy callback (pre-split): keep working as SBP platega_method_id = settings.platega_sbp_method_resolved platega_variant = "sbp" current_lang = i18n_data.get("current_language", settings.DEFAULT_LANGUAGE) i18n: Optional[JsonI18n] = i18n_data.get("i18n_instance") get_text = lambda key, **kwargs: i18n.gettext(current_lang, key, **kwargs) if i18n else key if not i18n or not callback.message: try: await callback.answer(get_text("error_occurred_try_again"), show_alert=True) except Exception: pass return if not platega_service or not platega_service.configured: logging.error("Platega service is not configured or unavailable.") try: await callback.answer(get_text("payment_service_unavailable_alert"), show_alert=True) except Exception: pass try: await callback.message.edit_text(get_text("payment_service_unavailable")) except Exception: pass return try: _, data_payload = callback.data.split(":", 1) parts = data_payload.split(":") months = float(parts[0]) price_rub = float(parts[1]) sale_mode = parts[2] if len(parts) > 2 else "subscription" except (ValueError, IndexError): logging.error(f"Invalid pay_platega data in callback: {callback.data}") try: await callback.answer(get_text("error_try_again"), show_alert=True) except Exception: pass return user_id = callback.from_user.id human_value = str(int(months)) if float(months).is_integer() else f"{months:g}" sale_base = sale_mode.split("@", 1)[0].split("|", 1)[0] payment_description = ( get_text("payment_description_traffic", traffic_gb=human_value) if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"} else ( get_text("payment_description_hwid_devices", count=int(months)) if sale_base in {"hwid_device", "hwid_devices"} else get_text("payment_description_subscription", months=int(months)) ) ) currency_code = settings.DEFAULT_CURRENCY_SYMBOL or "RUB" payment_record_payload = { "user_id": user_id, "amount": price_rub, "currency": currency_code, "status": "pending_platega", "description": payment_description, "subscription_duration_months": int(months) if sale_base == "subscription" else None, "provider": "platega", "sale_mode": sale_mode, "tariff_key": sale_mode.split("@", 1)[1] if "@" in sale_mode else None, "purchased_gb": float(months) if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"} else None, "purchased_hwid_devices": int(months) if sale_base in {"hwid_device", "hwid_devices"} else None, } try: payment_record = await payment_dal.create_payment_record(session, payment_record_payload) await session.commit() except Exception as e_db_create: await session.rollback() logging.error( f"Platega: failed to create payment record for user {user_id}: {e_db_create}", exc_info=True, ) try: await callback.message.edit_text(get_text("error_creating_payment_record")) except Exception: pass try: await callback.answer(get_text("error_try_again"), show_alert=True) except Exception: pass return payload_meta = json.dumps( { "payment_db_id": payment_record.payment_id, "user_id": user_id, "months": months, "sale_mode": sale_mode, "platega_variant": platega_variant, } ) success, response_data = await platega_service.create_transaction( payment_db_id=payment_record.payment_id, user_id=user_id, months=months, amount=price_rub, currency=currency_code, description=payment_description, payload=payload_meta, payment_method=platega_method_id, ) if success: transaction_id = response_data.get("transactionId") or response_data.get("id") redirect_url = ( response_data.get("redirect") or response_data.get("url") or response_data.get("paymentUrl") ) provider_status = response_data.get("status", payment_record.status) if transaction_id and redirect_url: try: await payment_dal.update_provider_payment_and_status( session, payment_record.payment_id, str(transaction_id), str(provider_status), ) await session.commit() except Exception as e_status: await session.rollback() logging.error( f"Platega: failed to store transaction id for payment {payment_record.payment_id}: {e_status}", # noqa: E501 exc_info=True, ) try: await callback.message.edit_text( get_text( key="payment_link_message_traffic" if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"} else "payment_link_message", months=int(months), traffic_gb=human_value, ), reply_markup=get_payment_url_keyboard( redirect_url, current_lang, i18n, back_callback=f"subscribe_period:{human_value}", back_text_key="back_to_payment_methods_button", ), disable_web_page_preview=False, ) except Exception as e_edit: logging.warning( f"Platega: failed to display payment link ({e_edit}), sending new message." ) try: await callback.message.answer( get_text( key="payment_link_message_traffic" if sale_base in {"traffic", "traffic_package", "topup", "premium_topup"} else "payment_link_message", months=int(months), traffic_gb=human_value, ), reply_markup=get_payment_url_keyboard( redirect_url, current_lang, i18n, back_callback=f"subscribe_period:{human_value}", back_text_key="back_to_payment_methods_button", ), disable_web_page_preview=False, ) except Exception: pass try: await callback.answer() except Exception: pass return logging.error( "Platega: transaction created but missing transaction id or payment link for payment %s. Response: %s", # noqa: E501 payment_record.payment_id, response_data, ) try: await payment_dal.update_payment_status_by_db_id( session, payment_record.payment_id, "failed_creation", ) await session.commit() except Exception as e_status: await session.rollback() logging.error( f"Platega: failed to mark payment {payment_record.payment_id} as failed_creation: {e_status}", # noqa: E501 exc_info=True, ) try: await callback.message.edit_text(get_text("error_payment_gateway")) except Exception: pass try: await callback.answer(get_text("error_payment_gateway"), show_alert=True) except Exception: pass