From 4eaedd33bf697469fe9ed6a1bfe8b59ca43b46fb Mon Sep 17 00:00:00 2001 From: Fringg Date: Fri, 27 Feb 2026 09:57:37 +0300 Subject: [PATCH] feat: add RESET_TRAFFIC_ON_TARIFF_SWITCH admin setting New boolean setting (default: True) controls whether user traffic is reset when switching between tariff plans. Changes: - config.py: add RESET_TRAFFIC_ON_TARIFF_SWITCH setting - system_settings_service.py: category override (TRAFFIC) + hints - pricing.py: admin bot handler toggle entry - cabinet/routes/subscription.py: pass reset_traffic to RemnaWave on switch - webapi/routes/miniapp.py: same for miniapp tariff switch - tariff_purchase.py: use setting in 3 switch handlers (was hardcoded) - subscription_auto_purchase_service.py: separate tariff switch vs payment logic - crud/subscription.py: conditional traffic_used_gb reset on tariff change --- app/cabinet/routes/subscription.py | 17 +++++++++++++--- app/config.py | 1 + app/database/crud/subscription.py | 7 ++++++- app/handlers/admin/pricing.py | 7 +++++++ app/handlers/subscription/tariff_purchase.py | 10 +++++----- .../subscription_auto_purchase_service.py | 7 +++++-- app/services/system_settings_service.py | 20 +++++++++++++++++++ app/webapi/routes/miniapp.py | 10 ++++++++-- 8 files changed, 66 insertions(+), 13 deletions(-) diff --git a/app/cabinet/routes/subscription.py b/app/cabinet/routes/subscription.py index 42942159..0bbcff33 100644 --- a/app/cabinet/routes/subscription.py +++ b/app/cabinet/routes/subscription.py @@ -4082,13 +4082,24 @@ async def switch_tariff( user.subscription.updated_at = datetime.now(UTC) await db.commit() - # Sync with RemnaWave + # Sync with RemnaWave (optionally reset traffic based on admin setting) + should_reset_traffic = settings.RESET_TRAFFIC_ON_TARIFF_SWITCH try: subscription_service = SubscriptionService() if getattr(user, 'remnawave_uuid', None): - await subscription_service.update_remnawave_user(db, user.subscription) + await subscription_service.update_remnawave_user( + db, + user.subscription, + reset_traffic=should_reset_traffic, + reset_reason='смена тарифа', + ) else: - await subscription_service.create_remnawave_user(db, user.subscription) + await subscription_service.create_remnawave_user( + db, + user.subscription, + reset_traffic=should_reset_traffic, + reset_reason='смена тарифа', + ) except Exception as e: logger.error('Failed to sync tariff switch with RemnaWave', error=e) diff --git a/app/config.py b/app/config.py index 156a609c..2edfa251 100644 --- a/app/config.py +++ b/app/config.py @@ -134,6 +134,7 @@ class Settings(BaseSettings): DEFAULT_DEVICE_LIMIT: int = 1 DEFAULT_TRAFFIC_RESET_STRATEGY: str = 'MONTH' RESET_TRAFFIC_ON_PAYMENT: bool = False + RESET_TRAFFIC_ON_TARIFF_SWITCH: bool = True MAX_DEVICES_LIMIT: int = 20 TRIAL_WARNING_HOURS: int = 2 diff --git a/app/database/crud/subscription.py b/app/database/crud/subscription.py index fbcc42a5..dd71847a 100644 --- a/app/database/crud/subscription.py +++ b/app/database/crud/subscription.py @@ -444,7 +444,12 @@ async def extend_subscription( if traffic_limit_gb is not None: old_traffic = subscription.traffic_limit_gb - subscription.traffic_used_gb = 0.0 + # Сброс использованного трафика: при смене тарифа — по настройке, при продлении — всегда + if is_tariff_change: + if settings.RESET_TRAFFIC_ON_TARIFF_SWITCH: + subscription.traffic_used_gb = 0.0 + else: + subscription.traffic_used_gb = 0.0 if is_tariff_change: # При СМЕНЕ тарифа сбрасываем все докупки трафика diff --git a/app/handlers/admin/pricing.py b/app/handlers/admin/pricing.py index d6d95666..76efc007 100644 --- a/app/handlers/admin/pricing.py +++ b/app/handlers/admin/pricing.py @@ -180,6 +180,13 @@ CORE_PRICING_ENTRIES: tuple[SettingEntry, ...] = ( label_en='🔄 Reset traffic on payment', action='toggle', ), + SettingEntry( + key='RESET_TRAFFIC_ON_TARIFF_SWITCH', + section='core', + label_ru='🔄 Сбрасывать трафик при смене тарифа', + label_en='🔄 Reset traffic on tariff switch', + action='toggle', + ), SettingEntry( key='DEFAULT_TRAFFIC_RESET_STRATEGY', section='core', diff --git a/app/handlers/subscription/tariff_purchase.py b/app/handlers/subscription/tariff_purchase.py index 30463b9d..8883981c 100644 --- a/app/handlers/subscription/tariff_purchase.py +++ b/app/handlers/subscription/tariff_purchase.py @@ -2274,7 +2274,7 @@ async def confirm_tariff_switch( await subscription_service.create_remnawave_user( db, subscription, - reset_traffic=True, + reset_traffic=settings.RESET_TRAFFIC_ON_TARIFF_SWITCH, reset_reason='переключение тарифа', ) except Exception as e: @@ -2446,13 +2446,13 @@ async def confirm_daily_tariff_switch( await db.commit() await db.refresh(subscription) - # Обновляем пользователя в Remnawave (create_remnawave_user также сбрасывает устройства) + # Обновляем пользователя в Remnawave (сброс трафика по админ-настройке) try: subscription_service = SubscriptionService() await subscription_service.create_remnawave_user( db, subscription, - reset_traffic=True, + reset_traffic=settings.RESET_TRAFFIC_ON_TARIFF_SWITCH, reset_reason='смена на суточный тариф', ) except Exception as e: @@ -3023,13 +3023,13 @@ async def confirm_instant_switch( await db.commit() await db.refresh(subscription) - # Обновляем пользователя в Remnawave + # Обновляем пользователя в Remnawave (сброс трафика по админ-настройке) try: subscription_service = SubscriptionService() await subscription_service.create_remnawave_user( db, subscription, - reset_traffic=False, # Не сбрасываем трафик при переключении + reset_traffic=settings.RESET_TRAFFIC_ON_TARIFF_SWITCH, reset_reason='мгновенное переключение тарифа', ) except Exception as e: diff --git a/app/services/subscription_auto_purchase_service.py b/app/services/subscription_auto_purchase_service.py index 2d442cd7..1c42b6f5 100644 --- a/app/services/subscription_auto_purchase_service.py +++ b/app/services/subscription_auto_purchase_service.py @@ -454,8 +454,11 @@ async def _auto_extend_subscription( ) subscription_service = SubscriptionService() - # При смене тарифа ВСЕГДА сбрасываем трафик, иначе по настройке - should_reset_traffic = is_tariff_change or settings.RESET_TRAFFIC_ON_PAYMENT + # Сброс трафика: при смене тарифа — по RESET_TRAFFIC_ON_TARIFF_SWITCH, при оплате — по RESET_TRAFFIC_ON_PAYMENT + should_reset_traffic = ( + (is_tariff_change and settings.RESET_TRAFFIC_ON_TARIFF_SWITCH) + or settings.RESET_TRAFFIC_ON_PAYMENT + ) try: await subscription_service.update_remnawave_user( db, diff --git a/app/services/system_settings_service.py b/app/services/system_settings_service.py index bfe07a8a..9dda23a5 100644 --- a/app/services/system_settings_service.py +++ b/app/services/system_settings_service.py @@ -220,6 +220,7 @@ class BotConfigurationService: 'SALES_MODE': 'SUBSCRIPTIONS_CORE', 'DEFAULT_TRAFFIC_RESET_STRATEGY': 'TRAFFIC', 'RESET_TRAFFIC_ON_PAYMENT': 'TRAFFIC', + 'RESET_TRAFFIC_ON_TARIFF_SWITCH': 'TRAFFIC', 'TRAFFIC_SELECTION_MODE': 'TRAFFIC', 'FIXED_TRAFFIC_LIMIT_GB': 'TRAFFIC', 'AVAILABLE_SUBSCRIPTION_PERIODS': 'PERIODS', @@ -879,6 +880,25 @@ class BotConfigurationService: 'format': 'Булево значение.', 'example': 'true', }, + 'RESET_TRAFFIC_ON_TARIFF_SWITCH': { + 'description': ( + 'Автоматически сбрасывает счётчик использованного трафика ' + 'при переключении пользователя на другой тарифный план. ' + 'Сброс происходит через RemnaWave API.' + ), + 'format': 'Булево значение: выберите "Включить" или "Выключить".', + 'example': 'Включено — трафик обнуляется при каждой смене тарифа.', + 'warning': 'При отключении использованный трафик сохранится после смены тарифа.', + }, + 'RESET_TRAFFIC_ON_PAYMENT': { + 'description': ( + 'Автоматически сбрасывает счётчик использованного трафика ' + 'при любой оплате или продлении подписки.' + ), + 'format': 'Булево значение: выберите "Включить" или "Выключить".', + 'example': 'Выключено по умолчанию.', + 'warning': 'При включении трафик будет обнуляться при каждом продлении подписки.', + }, } @classmethod diff --git a/app/webapi/routes/miniapp.py b/app/webapi/routes/miniapp.py index e227111a..94956739 100644 --- a/app/webapi/routes/miniapp.py +++ b/app/webapi/routes/miniapp.py @@ -6991,10 +6991,16 @@ async def switch_tariff_endpoint( await db.refresh(subscription) await db.refresh(user) - # Синхронизируем с RemnaWave + # Синхронизируем с RemnaWave (опционально сбрасываем трафик по настройке) + should_reset_traffic = settings.RESET_TRAFFIC_ON_TARIFF_SWITCH try: service = SubscriptionService() - await service.update_remnawave_user(db, subscription) + await service.update_remnawave_user( + db, + subscription, + reset_traffic=should_reset_traffic, + reset_reason='смена тарифа', + ) except Exception as e: logger.error('Ошибка синхронизации с RemnaWave при смене тарифа', error=e)