fix: close remaining daily subscription expire paths
- get_all_subscriptions: add selectinload(tariff) so validate_and_fix guard works - get_subscriptions_batch: add selectinload(tariff) for sync flows - get_expiring_subscriptions: exclude active daily subs (prevents spurious notifications) - update_remnawave_user: add daily guard to prevent expire during panel sync - _handle_user_disabled webhook: add daily guard to prevent deactivation
This commit is contained in:
@@ -763,18 +763,26 @@ async def reactivate_subscription(db: AsyncSession, subscription: Subscription)
|
||||
|
||||
|
||||
async def get_expiring_subscriptions(db: AsyncSession, days_before: int = 3) -> list[Subscription]:
|
||||
from app.database.models import Tariff
|
||||
|
||||
threshold_date = datetime.now(UTC) + timedelta(days=days_before)
|
||||
|
||||
result = await db.execute(
|
||||
select(Subscription)
|
||||
.join(User, Subscription.user_id == User.id)
|
||||
.options(selectinload(Subscription.user))
|
||||
.outerjoin(Tariff, Subscription.tariff_id == Tariff.id)
|
||||
.options(selectinload(Subscription.user), selectinload(Subscription.tariff))
|
||||
.where(
|
||||
and_(
|
||||
Subscription.status == SubscriptionStatus.ACTIVE.value,
|
||||
User.status == UserStatus.ACTIVE.value,
|
||||
Subscription.end_date <= threshold_date,
|
||||
Subscription.end_date > datetime.now(UTC),
|
||||
# Не включаем активные суточные подписки — у них end_date всегда +24ч
|
||||
~and_(
|
||||
Tariff.is_daily.is_(True),
|
||||
Subscription.is_daily_paused.is_(False),
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -1048,7 +1056,7 @@ async def get_all_subscriptions(db: AsyncSession, page: int = 1, limit: int = 10
|
||||
|
||||
result = await db.execute(
|
||||
select(Subscription)
|
||||
.options(selectinload(Subscription.user))
|
||||
.options(selectinload(Subscription.user), selectinload(Subscription.tariff))
|
||||
.order_by(Subscription.created_at.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
@@ -1064,10 +1072,10 @@ async def get_subscriptions_batch(
|
||||
offset: int = 0,
|
||||
limit: int = 500,
|
||||
) -> list[Subscription]:
|
||||
"""Получает подписки пачками для синхронизации. Загружает связанных пользователей."""
|
||||
"""Получает подписки пачками для синхронизации. Загружает связанных пользователей и тарифы."""
|
||||
result = await db.execute(
|
||||
select(Subscription)
|
||||
.options(selectinload(Subscription.user))
|
||||
.options(selectinload(Subscription.user), selectinload(Subscription.tariff))
|
||||
.order_by(Subscription.id)
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
|
||||
@@ -330,10 +330,23 @@ class MonitoringService:
|
||||
is_active = subscription.status == SubscriptionStatus.ACTIVE.value and subscription.end_date > current_time
|
||||
|
||||
if subscription.status == SubscriptionStatus.ACTIVE.value and subscription.end_date <= current_time:
|
||||
subscription.status = SubscriptionStatus.EXPIRED.value
|
||||
await db.commit()
|
||||
is_active = False
|
||||
logger.info("📝 Статус подписки обновлен на 'expired'", subscription_id=subscription.id)
|
||||
# Суточные подписки управляются DailySubscriptionService — не экспайрим
|
||||
tariff = getattr(subscription, 'tariff', None)
|
||||
is_active_daily = (
|
||||
tariff is not None
|
||||
and getattr(tariff, 'is_daily', False)
|
||||
and not getattr(subscription, 'is_daily_paused', False)
|
||||
)
|
||||
if is_active_daily:
|
||||
logger.debug(
|
||||
'update_remnawave_user: пропуск expire для суточной подписки',
|
||||
subscription_id=subscription.id,
|
||||
)
|
||||
else:
|
||||
subscription.status = SubscriptionStatus.EXPIRED.value
|
||||
await db.commit()
|
||||
is_active = False
|
||||
logger.info("📝 Статус подписки обновлен на 'expired'", subscription_id=subscription.id)
|
||||
|
||||
if not self.subscription_service.is_configured:
|
||||
logger.warning(
|
||||
|
||||
@@ -499,6 +499,23 @@ class RemnaWaveWebhookService:
|
||||
self, db: AsyncSession, user: User, subscription: Subscription | None, data: dict
|
||||
) -> None:
|
||||
if subscription:
|
||||
# Суточные подписки управляются DailySubscriptionService — не деактивируем
|
||||
tariff = getattr(subscription, 'tariff', None)
|
||||
is_active_daily = (
|
||||
tariff is not None
|
||||
and getattr(tariff, 'is_daily', False)
|
||||
and not getattr(subscription, 'is_daily_paused', False)
|
||||
)
|
||||
if is_active_daily:
|
||||
logger.info(
|
||||
'Webhook: пропуск disabled для суточной подписки',
|
||||
subscription_id=subscription.id,
|
||||
user_id=user.id,
|
||||
)
|
||||
self._stamp_webhook_update(subscription)
|
||||
await db.commit()
|
||||
return
|
||||
|
||||
self._stamp_webhook_update(subscription)
|
||||
if subscription.status != SubscriptionStatus.DISABLED.value:
|
||||
await deactivate_subscription(db, subscription)
|
||||
|
||||
Reference in New Issue
Block a user