Add configurable traffic reset on payments

This commit is contained in:
Egor
2025-09-29 14:40:36 +03:00
parent 70f190501b
commit ca81b32502
8 changed files with 101 additions and 15 deletions

View File

@@ -91,6 +91,8 @@ DEFAULT_TRAFFIC_LIMIT_GB=100
# ===== ГЛОБАЛЬНЫЙ ПАРАМЕТР ДЛЯ ВСЕХ ПОДПИСОК =====
DEFAULT_TRAFFIC_RESET_STRATEGY=MONTH
# Сбрасывать трафик при каждой оплате подписки
RESET_TRAFFIC_ON_PAYMENT=false
# ===== НАСТРОЙКИ ТРАФИКА =====
# Режим выбора трафика:

View File

@@ -335,6 +335,8 @@ DEFAULT_TRAFFIC_LIMIT_GB=100
# ===== ГЛОБАЛЬНЫЙ ПАРАМЕТР ДЛЯ ВСЕХ ПОДПИСОК =====
DEFAULT_TRAFFIC_RESET_STRATEGY=MONTH
# Сбрасывать трафик при каждой оплате подписки
RESET_TRAFFIC_ON_PAYMENT=false
# ===== НАСТРОЙКИ ТРАФИКА =====
# Режим выбора трафика:

View File

@@ -71,6 +71,7 @@ class Settings(BaseSettings):
DEFAULT_DEVICE_LIMIT: int = 1
TRIAL_SQUAD_UUID: str = ""
DEFAULT_TRAFFIC_RESET_STRATEGY: str = "MONTH"
RESET_TRAFFIC_ON_PAYMENT: bool = False
MAX_DEVICES_LIMIT: int = 20
TRIAL_WARNING_HOURS: int = 2

View File

@@ -120,9 +120,13 @@ async def extend_subscription(
if subscription.status == SubscriptionStatus.EXPIRED.value:
subscription.status = SubscriptionStatus.ACTIVE.value
logger.info(f"🔄 Статус изменён с EXPIRED на ACTIVE")
if settings.RESET_TRAFFIC_ON_PAYMENT:
subscription.traffic_used_gb = 0.0
logger.info("🔄 Сбрасываем использованный трафик согласно настройке RESET_TRAFFIC_ON_PAYMENT")
subscription.updated_at = current_time
await db.commit()
await db.refresh(subscription)
await clear_notifications(db, subscription.id)

View File

@@ -2625,7 +2625,12 @@ async def confirm_extend_subscription(
await add_subscription_servers(db, subscription, server_ids, server_prices_for_period)
try:
remnawave_result = await subscription_service.update_remnawave_user(db, subscription)
remnawave_result = await subscription_service.update_remnawave_user(
db,
subscription,
reset_traffic=settings.RESET_TRAFFIC_ON_PAYMENT,
reset_reason="продление подписки",
)
if remnawave_result:
logger.info("✅ RemnaWave обновлен успешно")
else:
@@ -3516,13 +3521,28 @@ async def confirm_purchase(
subscription_service = SubscriptionService()
if db_user.remnawave_uuid:
remnawave_user = await subscription_service.update_remnawave_user(db, subscription)
remnawave_user = await subscription_service.update_remnawave_user(
db,
subscription,
reset_traffic=settings.RESET_TRAFFIC_ON_PAYMENT,
reset_reason="покупка подписки",
)
else:
remnawave_user = await subscription_service.create_remnawave_user(db, subscription)
remnawave_user = await subscription_service.create_remnawave_user(
db,
subscription,
reset_traffic=settings.RESET_TRAFFIC_ON_PAYMENT,
reset_reason="покупка подписки",
)
if not remnawave_user:
logger.error(f"Не удалось создать/обновить RemnaWave пользователя для {db_user.telegram_id}")
remnawave_user = await subscription_service.create_remnawave_user(db, subscription)
remnawave_user = await subscription_service.create_remnawave_user(
db,
subscription,
reset_traffic=settings.RESET_TRAFFIC_ON_PAYMENT,
reset_reason="покупка подписки (повторная попытка)",
)
transaction = await create_transaction(
db=db,

View File

@@ -795,7 +795,12 @@ class MonitoringService:
if success:
await extend_subscription(db, subscription, 30)
await self.subscription_service.update_remnawave_user(db, subscription)
await self.subscription_service.update_remnawave_user(
db,
subscription,
reset_traffic=settings.RESET_TRAFFIC_ON_PAYMENT,
reset_reason="автопродление подписки",
)
if self.bot:
await self._send_autopay_success_notification(user, renewal_cost, 30)

View File

@@ -87,9 +87,12 @@ class SubscriptionService:
)
async def create_remnawave_user(
self,
db: AsyncSession,
subscription: Subscription
self,
db: AsyncSession,
subscription: Subscription,
*,
reset_traffic: bool = False,
reset_reason: Optional[str] = None,
) -> Optional[RemnaWaveUser]:
try:
@@ -130,6 +133,14 @@ class SubscriptionService:
active_internal_squads=subscription.connected_squads
)
if reset_traffic:
await self._reset_user_traffic(
api,
updated_user.uuid,
user.telegram_id,
reset_reason,
)
else:
logger.info(f"🆕 Создаем нового пользователя в панели для {user.telegram_id}")
username = f"user_{user.telegram_id}"
@@ -148,7 +159,15 @@ class SubscriptionService:
),
active_internal_squads=subscription.connected_squads
)
if reset_traffic:
await self._reset_user_traffic(
api,
updated_user.uuid,
user.telegram_id,
reset_reason,
)
subscription.remnawave_short_uuid = updated_user.short_uuid
subscription.subscription_url = updated_user.subscription_url
subscription.subscription_crypto_link = updated_user.happ_crypto_link
@@ -172,7 +191,10 @@ class SubscriptionService:
async def update_remnawave_user(
self,
db: AsyncSession,
subscription: Subscription
subscription: Subscription,
*,
reset_traffic: bool = False,
reset_reason: Optional[str] = None,
) -> Optional[RemnaWaveUser]:
try:
@@ -210,6 +232,14 @@ class SubscriptionService:
active_internal_squads=subscription.connected_squads
)
if reset_traffic:
await self._reset_user_traffic(
api,
user.remnawave_uuid,
user.telegram_id,
reset_reason,
)
subscription.subscription_url = updated_user.subscription_url
subscription.subscription_crypto_link = updated_user.happ_crypto_link
await db.commit()
@@ -219,16 +249,37 @@ class SubscriptionService:
strategy_name = settings.DEFAULT_TRAFFIC_RESET_STRATEGY
logger.info(f"📊 Стратегия сброса трафика: {strategy_name}")
return updated_user
except RemnaWaveAPIError as e:
logger.error(f"Ошибка RemnaWave API: {e}")
return None
except Exception as e:
logger.error(f"Ошибка обновления RemnaWave пользователя: {e}")
return None
async def _reset_user_traffic(
self,
api: RemnaWaveAPI,
user_uuid: str,
telegram_id: int,
reset_reason: Optional[str] = None,
) -> None:
if not user_uuid:
return
try:
await api.reset_user_traffic(user_uuid)
reason_text = f" ({reset_reason})" if reset_reason else ""
logger.info(
f"🔄 Сброшен трафик RemnaWave для пользователя {telegram_id}{reason_text}"
)
except Exception as exc:
logger.warning(
f"⚠️ Не удалось сбросить трафик RemnaWave для пользователя {telegram_id}: {exc}"
)
async def disable_remnawave_user(self, user_uuid: str) -> bool:
try:
async with self.api as api:
await api.disable_user(user_uuid)

View File

@@ -113,6 +113,7 @@ class BotConfigurationService:
"MAX_DEVICES_LIMIT": "PAID_SUBSCRIPTION",
"PRICE_PER_DEVICE": "PAID_SUBSCRIPTION",
"DEFAULT_TRAFFIC_RESET_STRATEGY": "SUBSCRIPTIONS_GLOBAL",
"RESET_TRAFFIC_ON_PAYMENT": "SUBSCRIPTIONS_GLOBAL",
"TRAFFIC_SELECTION_MODE": "TRAFFIC",
"FIXED_TRAFFIC_LIMIT_GB": "TRAFFIC",
"AVAILABLE_SUBSCRIPTION_PERIODS": "PERIODS",