fix(traffic): исправлен баг с бесплатным переключением трафика

При наличии докупленного трафика (например 250 + 10 ГБ = 260 ГБ)
  система округляла текущий пакет до ближайшего (500 ГБ) и позволяла
  бесплатно переключиться на него.

  Исправления:
  - confirm_switch_traffic: используется базовый трафик для расчёта цены
  - get_traffic_switch_keyboard: добавлен параметр base_traffic_gb
  - handle_switch_traffic: показывает информацию о докупленном трафике
  - execute_switch_traffic: сбрасывает purchased_traffic_gb при переключении
This commit is contained in:
gy9vin
2025-12-26 11:18:16 +03:00
parent e71a3c1af7
commit 64ffffdf90
4 changed files with 37 additions and 7 deletions
+10 -2
View File
@@ -390,9 +390,15 @@ def get_traffic_switch_keyboard(
language: str = "ru",
subscription_end_date: datetime = None,
discount_percent: int = 0,
base_traffic_gb: int = None,
) -> InlineKeyboardMarkup:
from app.config import settings
# Если базовый трафик не передан, используем текущий
# (для обратной совместимости и случаев без докупленного трафика)
if base_traffic_gb is None:
base_traffic_gb = current_traffic_gb
months_multiplier = 1
period_text = ""
if subscription_end_date:
@@ -403,7 +409,8 @@ def get_traffic_switch_keyboard(
packages = settings.get_traffic_packages()
enabled_packages = [pkg for pkg in packages if pkg['enabled']]
current_price_per_month = settings.get_traffic_price(current_traffic_gb)
# Используем базовый трафик для определения цены текущего пакета
current_price_per_month = settings.get_traffic_price(base_traffic_gb)
discounted_current_per_month, _ = apply_percentage_discount(
current_price_per_month,
discount_percent,
@@ -422,7 +429,8 @@ def get_traffic_switch_keyboard(
price_diff_per_month = discounted_price_per_month - discounted_current_per_month
total_price_diff = price_diff_per_month * months_multiplier
if gb == current_traffic_gb:
# Сравниваем с базовым трафиком (без докупленного)
if gb == base_traffic_gb:
emoji = ""
action_text = " (текущий)"
price_text = ""
+21 -3
View File
@@ -609,6 +609,10 @@ async def handle_switch_traffic(
return
current_traffic = subscription.traffic_limit_gb
# Вычисляем базовый трафик (без докупленного) для корректного расчёта цен
purchased_traffic = getattr(subscription, 'purchased_traffic_gb', 0) or 0
base_traffic = current_traffic - purchased_traffic
period_hint_days = _get_period_hint_from_subscription(subscription)
traffic_discount_percent = _get_addon_discount_percent_for_user(
db_user,
@@ -616,18 +620,25 @@ async def handle_switch_traffic(
period_hint_days,
)
# Показываем информацию о докупленном трафике, если он есть
purchased_info = ""
if purchased_traffic > 0:
purchased_info = f"\n📦 Базовый пакет: {texts.format_traffic(base_traffic)}\n Докуплено: {texts.format_traffic(purchased_traffic)}"
await callback.message.edit_text(
f"🔄 <b>Переключение лимита трафика</b>\n\n"
f"Текущий лимит: {texts.format_traffic(current_traffic)}\n"
f"Текущий лимит: {texts.format_traffic(current_traffic)}{purchased_info}\n"
f"Выберите новый лимит трафика:\n\n"
f"💡 <b>Важно:</b>\n"
f"• При увеличении - доплата за разницу\n"
f"• При уменьшении - возврат средств не производится",
f"• При уменьшении - возврат средств не производится\n"
f"• Докупленный трафик будет сброшен",
reply_markup=get_traffic_switch_keyboard(
current_traffic,
db_user.language,
subscription.end_date,
traffic_discount_percent,
base_traffic_gb=base_traffic,
),
parse_mode="HTML"
)
@@ -645,11 +656,16 @@ async def confirm_switch_traffic(
current_traffic = subscription.traffic_limit_gb
# Вычисляем базовый трафик (без докупленного) для корректного расчёта цены
purchased_traffic = getattr(subscription, 'purchased_traffic_gb', 0) or 0
base_traffic = current_traffic - purchased_traffic
if new_traffic_gb == current_traffic:
await callback.answer("ℹ️ Лимит трафика не изменился", show_alert=True)
return
old_price_per_month = settings.get_traffic_price(current_traffic)
# Используем базовый трафик для определения текущей цены пакета
old_price_per_month = settings.get_traffic_price(base_traffic)
new_price_per_month = settings.get_traffic_price(new_traffic_gb)
months_remaining = get_remaining_months(subscription.end_date)
@@ -766,6 +782,8 @@ async def execute_switch_traffic(
)
subscription.traffic_limit_gb = new_traffic_gb
# Сбрасываем докупленный трафик при переключении пакета
subscription.purchased_traffic_gb = 0
subscription.updated_at = datetime.utcnow()
await db.commit()
+5 -2
View File
@@ -854,8 +854,9 @@ async def handle_ticket_reply(
await state.clear()
# Уведомить админов об ответе пользователя
logger.info(f"Attempting to notify admins about ticket reply #{ticket_id}")
await notify_admins_about_ticket_reply(ticket, reply_text, db)
except Exception as e:
logger.error(f"Error adding ticket reply: {e}")
texts = get_texts(db_user.language)
@@ -1020,6 +1021,7 @@ async def notify_admins_about_new_ticket(ticket: Ticket, db: AsyncSession):
async def notify_admins_about_ticket_reply(ticket: Ticket, reply_text: str, db: AsyncSession):
"""Уведомить админов об ответе пользователя на тикет"""
logger.info(f"notify_admins_about_ticket_reply called for ticket #{ticket.id}")
try:
from app.config import settings
if not settings.is_admin_notifications_enabled():
@@ -1059,7 +1061,8 @@ async def notify_admins_about_ticket_reply(ticket: Ticket, reply_text: str, db:
return
service = AdminNotificationService(bot)
await service.send_ticket_event_notification(notification_text, None)
result = await service.send_ticket_event_notification(notification_text, None)
logger.info(f"Ticket #{ticket.id} reply notification sent: {result}")
except Exception as e:
logger.error(f"Error notifying admins about ticket reply: {e}")
@@ -1510,6 +1510,7 @@ class AdminNotificationService:
except Exception:
runtime_enabled = True
if not (self._is_enabled() and runtime_enabled):
logger.info(f"Ticket notification skipped: _is_enabled={self._is_enabled()}, runtime_enabled={runtime_enabled}")
return False
return await self._send_message(text, reply_markup=keyboard, ticket_event=True)