fix: handle nullable traffic_limit_gb and end_date in subscription model

Add None-safety guards to Subscription model properties (is_active,
is_expired, should_be_expired, actual_status, days_left,
traffic_used_percent) and pricing handler comparisons to prevent
TypeError when nullable columns contain None values.
This commit is contained in:
Fringg
2026-02-10 20:35:42 +03:00
parent 019fbc12b6
commit e94b93d0c1
2 changed files with 23 additions and 13 deletions

View File

@@ -1159,17 +1159,25 @@ class Subscription(Base):
@property
def is_active(self) -> bool:
current_time = datetime.utcnow()
return self.status == SubscriptionStatus.ACTIVE.value and self.end_date > current_time
return (
self.status == SubscriptionStatus.ACTIVE.value
and self.end_date is not None
and self.end_date > current_time
)
@property
def is_expired(self) -> bool:
"""Проверяет, истёк ли срок подписки"""
return self.end_date <= datetime.utcnow()
return self.end_date is not None and self.end_date <= datetime.utcnow()
@property
def should_be_expired(self) -> bool:
current_time = datetime.utcnow()
return self.status == SubscriptionStatus.ACTIVE.value and self.end_date <= current_time
return (
self.status == SubscriptionStatus.ACTIVE.value
and self.end_date is not None
and self.end_date <= current_time
)
@property
def actual_status(self) -> str:
@@ -1182,12 +1190,12 @@ class Subscription(Base):
return 'disabled'
if self.status == SubscriptionStatus.ACTIVE.value:
if self.end_date <= current_time:
if self.end_date is None or self.end_date <= current_time:
return 'expired'
return 'active'
if self.status == SubscriptionStatus.TRIAL.value:
if self.end_date <= current_time:
if self.end_date is None or self.end_date <= current_time:
return 'expired'
return 'trial'
@@ -1230,6 +1238,8 @@ class Subscription(Base):
@property
def days_left(self) -> int:
if self.end_date is None:
return 0
current_time = datetime.utcnow()
if self.end_date <= current_time:
return 0
@@ -1255,11 +1265,10 @@ class Subscription(Base):
@property
def traffic_used_percent(self) -> float:
if self.traffic_limit_gb == 0:
if not self.traffic_limit_gb:
return 0.0
if self.traffic_limit_gb > 0:
return min((self.traffic_used_gb / self.traffic_limit_gb) * 100, 100.0)
return 0.0
used = self.traffic_used_gb or 0.0
return min((used / self.traffic_limit_gb) * 100, 100.0)
def extend_subscription(self, days: int):
if self.end_date > datetime.utcnow():

View File

@@ -404,15 +404,16 @@ async def get_subscription_info_text(subscription, texts, db_user, db: AsyncSess
status_text = '⌛ Истекла'
type_text = 'Платная подписка'
if subscription.traffic_limit_gb == 0:
traffic_limit = subscription.traffic_limit_gb or 0
if traffic_limit == 0:
if settings.is_traffic_fixed():
traffic_text = '∞ Безлимитный'
else:
traffic_text = '∞ Безлимитный'
elif settings.is_traffic_fixed():
traffic_text = f'{subscription.traffic_limit_gb} ГБ'
traffic_text = f'{traffic_limit} ГБ'
else:
traffic_text = f'{subscription.traffic_limit_gb} ГБ'
traffic_text = f'{traffic_limit} ГБ'
subscription_cost = await get_subscription_cost(subscription, db)
@@ -444,7 +445,7 @@ async def get_subscription_info_text(subscription, texts, db_user, db: AsyncSess
info_text += f'\n💰 <b>Стоимость подписки в месяц:</b> {texts.format_price(subscription_cost)}'
# Отображаем докупленный трафик
if subscription.traffic_limit_gb > 0: # Только для лимитированных тарифов
if (subscription.traffic_limit_gb or 0) > 0: # Только для лимитированных тарифов
from datetime import datetime
from sqlalchemy import select as sql_select