Update miniapp.py

This commit is contained in:
Egor
2026-01-12 17:58:25 +03:00
committed by GitHub
parent 6e8c9bda30
commit c350195bfc
+129
View File
@@ -197,6 +197,8 @@ from ..schemas.miniapp import (
MiniAppConnectedServer,
MiniAppTrafficTopupRequest,
MiniAppTrafficTopupResponse,
MiniAppDailySubscriptionToggleRequest,
MiniAppDailySubscriptionToggleResponse,
)
@@ -3414,6 +3416,26 @@ async def get_subscription_details(
devices_count, devices = await _load_devices_info(user)
# Загружаем данные суточного тарифа
is_daily_tariff = False
is_daily_paused = False
daily_tariff_name = None
daily_price_kopeks = None
daily_price_label = None
daily_next_charge_at = None
if subscription and getattr(subscription, "tariff_id", None):
tariff = await get_tariff_by_id(db, subscription.tariff_id)
if tariff and getattr(tariff, 'is_daily', False):
is_daily_tariff = True
is_daily_paused = getattr(subscription, 'is_daily_paused', False)
daily_tariff_name = tariff.name
daily_price_kopeks = getattr(tariff, 'daily_price_kopeks', 0)
daily_price_label = settings.format_price(daily_price_kopeks) + "/день" if daily_price_kopeks > 0 else None
# Следующее списание - через 24 часа от последнего обновления подписки или от start_date
if subscription.end_date and not is_daily_paused:
daily_next_charge_at = subscription.end_date
response_user = MiniAppSubscriptionUser(
telegram_id=user.telegram_id,
username=user.username,
@@ -3443,6 +3465,12 @@ async def get_subscription_details(
promo_offer_discount_percent=active_discount_percent,
promo_offer_discount_expires_at=active_discount_expires_at,
promo_offer_discount_source=promo_offer_source,
is_daily_tariff=is_daily_tariff,
is_daily_paused=is_daily_paused,
daily_tariff_name=daily_tariff_name,
daily_price_kopeks=daily_price_kopeks,
daily_price_label=daily_price_label,
daily_next_charge_at=daily_next_charge_at,
)
referral_info = await _build_referral_info(db, user)
@@ -6340,6 +6368,11 @@ async def _build_tariff_model(
is_upgrade = upgrade
is_switch_free = cost == 0
# Суточный тариф
is_daily = getattr(tariff, 'is_daily', False)
daily_price_kopeks = getattr(tariff, 'daily_price_kopeks', 0) if is_daily else 0
daily_price_label = settings.format_price(daily_price_kopeks) + "/день" if is_daily and daily_price_kopeks > 0 else None
return MiniAppTariff(
id=tariff.id,
name=tariff.name,
@@ -6358,6 +6391,9 @@ async def _build_tariff_model(
switch_cost_label=switch_cost_label,
is_upgrade=is_upgrade,
is_switch_free=is_switch_free,
is_daily=is_daily,
daily_price_kopeks=daily_price_kopeks,
daily_price_label=daily_price_label,
)
@@ -6378,6 +6414,11 @@ async def _build_current_tariff_model(db: AsyncSession, tariff, promo_group=None
except (TypeError, ValueError):
pass
# Суточный тариф
is_daily = getattr(tariff, 'is_daily', False)
daily_price_kopeks = getattr(tariff, 'daily_price_kopeks', 0) if is_daily else 0
daily_price_label = settings.format_price(daily_price_kopeks) + "/день" if is_daily and daily_price_kopeks > 0 else None
return MiniAppCurrentTariff(
id=tariff.id,
name=tariff.name,
@@ -6389,6 +6430,9 @@ async def _build_current_tariff_model(db: AsyncSession, tariff, promo_group=None
device_limit=tariff.device_limit,
servers_count=servers_count,
monthly_price_kopeks=monthly_price,
is_daily=is_daily,
daily_price_kopeks=daily_price_kopeks,
daily_price_label=daily_price_label,
)
@@ -7093,3 +7137,88 @@ async def purchase_traffic_topup_endpoint(
new_balance_kopeks=user.balance_kopeks,
charged_kopeks=final_price,
)
@router.post("/subscription/daily/toggle-pause")
async def toggle_daily_subscription_pause_endpoint(
payload: MiniAppDailySubscriptionToggleRequest,
db: AsyncSession = Depends(get_db_session),
):
"""Переключает паузу/активацию суточной подписки."""
from app.webapi.schemas.miniapp import MiniAppDailySubscriptionToggleResponse
from app.services.subscription_service import SubscriptionService
user = await _authorize_miniapp_user(payload.init_data, db)
subscription = user.subscription
if not subscription:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail={"code": "no_subscription", "message": "No subscription found"},
)
# Проверяем наличие тарифа
tariff_id = getattr(subscription, 'tariff_id', None)
if not tariff_id:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={"code": "no_tariff", "message": "Subscription has no tariff"},
)
tariff = await get_tariff_by_id(db, tariff_id)
if not tariff or not getattr(tariff, 'is_daily', False):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail={"code": "not_daily_tariff", "message": "Subscription is not on a daily tariff"},
)
# Переключаем состояние паузы
is_currently_paused = getattr(subscription, 'is_daily_paused', False)
new_paused_state = not is_currently_paused
subscription.is_daily_paused = new_paused_state
# Если снимаем с паузы и подписка активна, нужно проверить баланс для активации
if not new_paused_state:
daily_price = getattr(tariff, 'daily_price_kopeks', 0)
if daily_price > 0 and user.balance_kopeks < daily_price:
raise HTTPException(
status_code=status.HTTP_402_PAYMENT_REQUIRED,
detail={
"code": "insufficient_balance",
"message": "Insufficient balance to resume daily subscription",
"required": daily_price,
"balance": user.balance_kopeks,
},
)
await db.commit()
await db.refresh(subscription)
await db.refresh(user)
# Синхронизация с RemnaWave
try:
service = SubscriptionService()
if new_paused_state:
# При паузе отключаем пользователя в RemnaWave
if user.remnawave_uuid:
await service.disable_remnawave_user(user.remnawave_uuid)
else:
# При возобновлении включаем пользователя в RemnaWave
if user.remnawave_uuid:
await service.enable_remnawave_user(user.remnawave_uuid)
except Exception as e:
logger.error(f"Ошибка синхронизации с RemnaWave при паузе/возобновлении: {e}")
lang = getattr(user, "language", settings.DEFAULT_LANGUAGE)
if new_paused_state:
message = "Суточная подписка приостановлена" if lang == "ru" else "Daily subscription paused"
else:
message = "Суточная подписка возобновлена" if lang == "ru" else "Daily subscription resumed"
return MiniAppDailySubscriptionToggleResponse(
success=True,
message=message,
is_paused=new_paused_state,
balance_kopeks=user.balance_kopeks,
balance_label=settings.format_price(user.balance_kopeks),
)