from __future__ import annotations from aiogram import Bot, types from aiogram.utils.keyboard import InlineKeyboardBuilder from sqlalchemy import update from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker from config import NOTIFY_EXTRA_DAYS, NOTIFY_INACTIVE from core.bootstrap import NOTIFICATIONS_CONFIG from database import add_notification, check_notifications_bulk from database.models import User from database.tariffs import get_tariffs from handlers.buttons import MAIN_MENU, TRIAL_BONUS from handlers.notifications.sender import send_messages_with_limit from handlers.texts import TRIAL_INACTIVE_BONUS_MSG, TRIAL_INACTIVE_FIRST_MSG from handlers.utils import format_days from logger import logger async def process_inactive_trial( bot: Bot, session: AsyncSession, *, sessionmaker: async_sessionmaker | None = None, ): inactive_hours = int(NOTIFICATIONS_CONFIG.get("INACTIVE_USER_ENABLED", NOTIFY_INACTIVE)) extra_days = int(NOTIFICATIONS_CONFIG.get("EXTRA_DAYS_AFTER_EXPIRY", NOTIFY_EXTRA_DAYS)) if inactive_hours <= 0: return users = await check_notifications_bulk(session, "inactive_trial", inactive_hours) if not users: return logger.info(f"[InactiveTrial] {len(users)} неактивных пользователей") trial_tariffs = await get_tariffs(session, group_code="trial") if not trial_tariffs: logger.error("[InactiveTrial] Триальный тариф не найден") return trial_days = trial_tariffs[0]["duration_days"] messages = [] users_to_extend = [] for user in users: tg_id = user["tg_id"] display_name = user["username"] or user["first_name"] or user["last_name"] or "Пользователь" builder = InlineKeyboardBuilder() builder.row(types.InlineKeyboardButton(text=TRIAL_BONUS, callback_data="create_key")) builder.row(types.InlineKeyboardButton(text=MAIN_MENU, callback_data="profile")) keyboard = builder.as_markup() trial_extended = user["last_notification_time"] is not None if trial_extended and extra_days > 0: total_days = extra_days + trial_days message = TRIAL_INACTIVE_BONUS_MSG.format( display_name=display_name, extra_days_formatted=format_days(extra_days), total_days_formatted=format_days(total_days), ) users_to_extend.append(tg_id) else: message = TRIAL_INACTIVE_FIRST_MSG.format( display_name=display_name, trial_time_formatted=format_days(trial_days), ) messages.append({ "tg_id": tg_id, "text": message, "keyboard": keyboard, "notification_id": "inactive_trial", }) if users_to_extend: await session.execute(update(User).where(User.tg_id.in_(users_to_extend)).values(trial=-1)) logger.info(f"[InactiveTrial] {len(users_to_extend)} пользователей с расширенным триалом") if messages: results = await send_messages_with_limit(bot, messages, messages_per_second=25) sent_tg_ids = [msg["tg_id"] for msg, result in zip(messages, results, strict=False) if result] if sent_tg_ids: if sessionmaker is not None: async with sessionmaker() as fresh_session: for tg_id in sent_tg_ids: await add_notification(fresh_session, tg_id, "inactive_trial") await fresh_session.commit() else: for tg_id in sent_tg_ids: await add_notification(session, tg_id, "inactive_trial") logger.info(f"[InactiveTrial] Отправлено {len(sent_tg_ids)} уведомлений")