import base64 import json import logging from datetime import datetime, timedelta from typing import Dict, List, Any, Tuple, Optional from urllib.parse import quote from aiogram import Dispatcher, types, F from aiogram.fsm.context import FSMContext from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings, PERIOD_PRICES, get_traffic_prices from app.database.crud.discount_offer import ( get_offer_by_id, mark_offer_claimed, ) from app.database.crud.promo_offer_template import get_promo_offer_template_by_id from app.database.crud.subscription import ( create_trial_subscription, create_paid_subscription, add_subscription_traffic, add_subscription_devices, update_subscription_autopay ) from app.database.crud.transaction import create_transaction from app.database.crud.user import subtract_user_balance from app.database.models import ( User, TransactionType, SubscriptionStatus, Subscription ) from app.keyboards.inline import ( get_subscription_keyboard, get_trial_keyboard, get_subscription_period_keyboard, get_traffic_packages_keyboard, get_countries_keyboard, get_devices_keyboard, get_subscription_confirm_keyboard, get_autopay_keyboard, get_autopay_days_keyboard, get_back_keyboard, get_add_traffic_keyboard, get_change_devices_keyboard, get_reset_traffic_confirm_keyboard, get_manage_countries_keyboard, get_device_selection_keyboard, get_connection_guide_keyboard, get_app_selection_keyboard, get_specific_app_keyboard, get_updated_subscription_settings_keyboard, get_insufficient_balance_keyboard, get_extend_subscription_keyboard_with_prices, get_confirm_change_devices_keyboard, get_devices_management_keyboard, get_device_management_help_keyboard, get_happ_cryptolink_keyboard, get_happ_download_platform_keyboard, get_happ_download_link_keyboard, get_happ_download_button_row, get_payment_methods_keyboard_with_cart, get_subscription_confirm_keyboard_with_cart, get_insufficient_balance_keyboard_with_cart ) from app.localization.texts import get_texts from app.services.admin_notification_service import AdminNotificationService from app.services.remnawave_service import RemnaWaveService from app.services.subscription_checkout_service import ( clear_subscription_checkout_draft, get_subscription_checkout_draft, save_subscription_checkout_draft, should_offer_checkout_resume, ) from app.services.subscription_service import SubscriptionService from app.utils.miniapp_buttons import build_miniapp_or_callback_button from app.services.promo_offer_service import promo_offer_service from app.states import SubscriptionStates from app.utils.pagination import paginate_list from app.utils.pricing_utils import ( calculate_months_from_days, get_remaining_months, calculate_prorated_price, validate_pricing_calculation, format_period_description, apply_percentage_discount, ) from app.utils.subscription_utils import ( get_display_subscription_link, get_happ_cryptolink_redirect_link, convert_subscription_link_to_happ_scheme, ) from app.utils.promo_offer import ( build_promo_offer_hint, get_user_active_promo_discount_percent, ) from .common import logger async def send_trial_notification(callback: types.CallbackQuery, db: AsyncSession, db_user: User, subscription: Subscription): try: notification_service = AdminNotificationService(callback.bot) await notification_service.send_trial_activation_notification(db, db_user, subscription) except Exception as e: logger.error(f"Ошибка отправки уведомления о триале: {e}") async def send_purchase_notification( callback: types.CallbackQuery, db: AsyncSession, db_user: User, subscription: Subscription, transaction_id: int, period_days: int, was_trial_conversion: bool = False ): try: from app.database.crud.transaction import get_transaction_by_id transaction = await get_transaction_by_id(db, transaction_id) if transaction: notification_service = AdminNotificationService(callback.bot) await notification_service.send_subscription_purchase_notification( db, db_user, subscription, transaction, period_days, was_trial_conversion ) except Exception as e: logger.error(f"Ошибка отправки уведомления о покупке: {e}") async def send_extension_notification( callback: types.CallbackQuery, db: AsyncSession, db_user: User, subscription: Subscription, transaction_id: int, extended_days: int, old_end_date: datetime ): try: from app.database.crud.transaction import get_transaction_by_id transaction = await get_transaction_by_id(db, transaction_id) if transaction: notification_service = AdminNotificationService(callback.bot) await notification_service.send_subscription_extension_notification( db, db_user, subscription, transaction, extended_days, old_end_date ) except Exception as e: logger.error(f"Ошибка отправки уведомления о продлении: {e}")