diff --git a/handlers/keys/key_create.py b/handlers/keys/key_create.py index c3f2dc9b..dfa0acda 100644 --- a/handlers/keys/key_create.py +++ b/handlers/keys/key_create.py @@ -156,6 +156,7 @@ async def handle_key_creation( if tariffs: group_code = tariffs[0].get("group_code") + original_group_code = group_code if group_code: discount_info = await check_hot_lead_discount(session, tg_id) @@ -185,6 +186,19 @@ async def handle_key_creation( tariffs = [t for t in tariffs_data["tariffs"] if t.get("is_active")] subgroup_weights = tariffs_data["subgroup_weights"] + if not tariffs and discount_info and discount_info.get("available"): + logger.warning(f"[PURCHASE] Нет тарифов со скидкой {group_code}, fallback на {original_group_code}") + group_code = original_group_code + tariffs_data = await get_tariffs( + session, + group_code=group_code, + with_subgroup_weights=True, + ) + tariffs = [t for t in tariffs_data["tariffs"] if t.get("is_active")] + subgroup_weights = tariffs_data["subgroup_weights"] + discount_info = None + await state.update_data(discount_info=None) + if not tariffs: result = await session.execute(select(Admin).where(Admin.tg_id == tg_id)) is_admin = result.scalar_one_or_none() is not None diff --git a/handlers/keys/key_mode/key_discount_mode.py b/handlers/keys/key_mode/key_discount_mode.py index 7dcd7818..b6f2a747 100644 --- a/handlers/keys/key_mode/key_discount_mode.py +++ b/handlers/keys/key_mode/key_discount_mode.py @@ -9,13 +9,13 @@ from sqlalchemy.ext.asyncio import AsyncSession from config import DISCOUNT_ACTIVE_HOURS from core.bootstrap import NOTIFICATIONS_CONFIG -from database import get_keys, get_tariffs +from database import get_keys, get_tariffs, get_tariffs_for_cluster from database.models import Notification from handlers.buttons import MAIN_MENU, RENEW_KEY_NOTIFICATION from handlers.notifications.notify_kb import build_tariffs_keyboard from handlers.tariffs.buy.key_tariffs import select_tariff_plan from handlers.texts import DISCOUNT_TARIFF, DISCOUNT_TARIFF_MAX -from handlers.utils import format_discount_time_left +from handlers.utils import format_discount_time_left, get_least_loaded_cluster from logger import logger @@ -64,8 +64,20 @@ async def handle_discount_entry(callback: CallbackQuery, session: AsyncSession): else: tariffs = await get_tariffs(session=session, group_code="discounts") if not tariffs: - await callback.message.edit_text("❌ Скидочные тарифы временно недоступны.") - return + try: + cluster_name = await get_least_loaded_cluster(session) + cluster_tariffs = await get_tariffs_for_cluster(session, cluster_name) + if cluster_tariffs: + group_code = cluster_tariffs[0].get("group_code") + if group_code: + logger.warning(f"[DISCOUNT] Нет тарифов discounts, fallback на {group_code}") + tariffs = await get_tariffs(session=session, group_code=group_code) + except Exception as e: + logger.error(f"[DISCOUNT] Не удалось получить обычные тарифы: {e}") + + if not tariffs: + await callback.message.edit_text("❌ Тарифы временно недоступны.") + return await callback.message.edit_text( DISCOUNT_TARIFF, @@ -130,8 +142,20 @@ async def handle_ultra_discount(callback: CallbackQuery, session: AsyncSession): else: tariffs = await get_tariffs(session=session, group_code="discounts_max") if not tariffs: - await callback.message.edit_text("❌ Скидочные тарифы временно недоступны.") - return + try: + cluster_name = await get_least_loaded_cluster(session) + cluster_tariffs = await get_tariffs_for_cluster(session, cluster_name) + if cluster_tariffs: + group_code = cluster_tariffs[0].get("group_code") + if group_code: + logger.warning(f"[DISCOUNT_MAX] Нет тарифов discounts_max, fallback на {group_code}") + tariffs = await get_tariffs(session=session, group_code=group_code) + except Exception as e: + logger.error(f"[DISCOUNT_MAX] Не удалось получить обычные тарифы: {e}") + + if not tariffs: + await callback.message.edit_text("❌ Тарифы временно недоступны.") + return await callback.message.edit_text( DISCOUNT_TARIFF_MAX, diff --git a/handlers/keys/key_renew.py b/handlers/keys/key_renew.py index a480c771..fa350593 100644 --- a/handlers/keys/key_renew.py +++ b/handlers/keys/key_renew.py @@ -139,6 +139,7 @@ async def process_callback_renew_key(callback_query: CallbackQuery, state: FSMCo return group_code = row[0] + original_group_code = group_code if tariff_id: if await check_tariff_exists(session, tariff_id): @@ -150,6 +151,7 @@ async def process_callback_renew_key(callback_query: CallbackQuery, state: FSMCo if current_tariff["group_code"] not in forbidden_groups: group_code = current_tariff["group_code"] + original_group_code = group_code discount_info = await check_hot_lead_discount(session, tg_id) @@ -167,6 +169,14 @@ async def process_callback_renew_key(callback_query: CallbackQuery, state: FSMCo tariffs = [t for t in tariffs_data["tariffs"] if t.get("is_active")] subgroup_weights = tariffs_data["subgroup_weights"] + if not tariffs and discount_info.get("available"): + logger.warning(f"[RENEW] Нет тарифов со скидкой {group_code}, fallback на {original_group_code}") + group_code = original_group_code + tariffs_data = await get_tariffs(session, group_code=group_code, with_subgroup_weights=True) + tariffs = [t for t in tariffs_data["tariffs"] if t.get("is_active")] + subgroup_weights = tariffs_data["subgroup_weights"] + discount_info = {"available": False} + if not tariffs: await callback_query.message.answer("❌ Нет доступных тарифов для продления.") return @@ -289,6 +299,7 @@ async def show_tariffs_in_renew_subgroup(callback: CallbackQuery, state: FSMCont return group_code = row[0] + original_group_code = group_code tariff_id = record.get("tariff_id") if tariff_id: @@ -303,6 +314,7 @@ async def show_tariffs_in_renew_subgroup(callback: CallbackQuery, state: FSMCont if current_tariff and current_tariff["group_code"] not in forbidden_groups: group_code = current_tariff["group_code"] + original_group_code = group_code tg_id = callback.from_user.id language_code = callback.from_user.language_code @@ -326,6 +338,15 @@ async def show_tariffs_in_renew_subgroup(callback: CallbackQuery, state: FSMCont tariffs = await get_tariffs(session, group_code=group_code) filtered = [t for t in tariffs if t["subgroup_title"] == subgroup and t["is_active"]] + if not filtered and discount_info.get("available"): + logger.warning(f"[RENEW_SUBGROUP] Нет тарифов со скидкой {group_code} в подгруппе '{subgroup}', fallback на {original_group_code}") + group_code = original_group_code + subgroup = await find_subgroup_by_hash(session, subgroup_hash, group_code) + if subgroup: + tariffs = await get_tariffs(session, group_code=group_code) + filtered = [t for t in tariffs if t["subgroup_title"] == subgroup and t["is_active"]] + discount_info = {"available": False} + if not filtered: await edit_or_send_message( target_message=callback.message, diff --git a/handlers/notifications/hot_leads_notifications.py b/handlers/notifications/hot_leads_notifications.py index 41941b0b..1bb91f5f 100644 --- a/handlers/notifications/hot_leads_notifications.py +++ b/handlers/notifications/hot_leads_notifications.py @@ -8,6 +8,7 @@ from config import DISCOUNT_ACTIVE_HOURS, HOT_LEAD_INTERVAL_HOURS from core.bootstrap import NOTIFICATIONS_CONFIG from database import add_notification, check_notification_time, get_hot_leads from database.models import Notification +from database.tariffs import get_tariffs from handlers.buttons import MAIN_MENU from handlers.notifications.notify_kb import build_hot_lead_kb from handlers.notifications.notify_utils import send_notification @@ -51,6 +52,12 @@ async def notify_hot_leads(bot: Bot, session: AsyncSession): if not can_send: continue + discount_tariffs = await get_tariffs(session, group_code="discounts") + active_discount_tariffs = [t for t in discount_tariffs if t.get("is_active")] + if not active_discount_tariffs: + logger.warning(f"[HOT LEAD] Пропуск шага 2 для {tg_id}: нет активных тарифов со скидкой (discounts)") + continue + keyboard = build_hot_lead_kb() result = await send_notification(bot, tg_id, None, HOT_LEAD_MESSAGE, keyboard) if result: @@ -100,6 +107,12 @@ async def notify_hot_leads(bot: Bot, session: AsyncSession): if not can_send: continue + discount_max_tariffs = await get_tariffs(session, group_code="discounts_max") + active_discount_max_tariffs = [t for t in discount_max_tariffs if t.get("is_active")] + if not active_discount_max_tariffs: + logger.warning(f"[HOT LEAD] Пропуск шага 3 для {tg_id}: нет активных тарифов с максимальной скидкой (discounts_max)") + continue + keyboard = build_hot_lead_kb(final=True) result = await send_notification(bot, tg_id, None, HOT_LEAD_FINAL_MESSAGE, keyboard) if result: