diff --git a/app/config.py b/app/config.py
index 2877faff..788bc8e6 100644
--- a/app/config.py
+++ b/app/config.py
@@ -83,7 +83,6 @@ class Settings(BaseSettings):
TRIAL_ADD_REMAINING_DAYS_TO_PAID: bool = False
DEFAULT_TRAFFIC_LIMIT_GB: int = 100
DEFAULT_DEVICE_LIMIT: int = 1
- DEVICES_SELECTION_ENABLED: bool = True
TRIAL_SQUAD_UUID: Optional[str] = None
DEFAULT_TRAFFIC_RESET_STRATEGY: str = "MONTH"
RESET_TRAFFIC_ON_PAYMENT: bool = False
@@ -798,12 +797,9 @@ class Settings(BaseSettings):
def is_traffic_fixed(self) -> bool:
return self.TRAFFIC_SELECTION_MODE.lower() == "fixed"
-
+
def get_fixed_traffic_limit(self) -> int:
return self.FIXED_TRAFFIC_LIMIT_GB
-
- def is_devices_selection_enabled(self) -> bool:
- return bool(self.DEVICES_SELECTION_ENABLED)
def is_yookassa_enabled(self) -> bool:
return (self.YOOKASSA_ENABLED and
diff --git a/app/handlers/subscription/autopay.py b/app/handlers/subscription/autopay.py
index 73afa5d1..7921bb1f 100644
--- a/app/handlers/subscription/autopay.py
+++ b/app/handlers/subscription/autopay.py
@@ -208,33 +208,6 @@ async def handle_subscription_config_back(
await state.set_state(SubscriptionStates.selecting_period)
elif current_state == SubscriptionStates.selecting_devices.state:
- if not settings.is_devices_selection_enabled():
- if await _should_show_countries_management(db_user):
- countries = await _get_available_countries(db_user.promo_group_id)
- data = await state.get_data()
- selected_countries = data.get('countries', [])
-
- await callback.message.edit_text(
- texts.SELECT_COUNTRIES,
- reply_markup=get_countries_keyboard(countries, selected_countries, db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_countries)
- elif settings.is_traffic_selectable():
- await callback.message.edit_text(
- texts.SELECT_TRAFFIC,
- reply_markup=get_traffic_packages_keyboard(db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_traffic)
- else:
- await callback.message.edit_text(
- await _build_subscription_period_prompt(db_user, texts, db),
- reply_markup=get_subscription_period_keyboard(db_user.language),
- parse_mode="HTML",
- )
- await state.set_state(SubscriptionStates.selecting_period)
- await callback.answer()
- return
-
if await _should_show_countries_management(db_user):
countries = await _get_available_countries(db_user.promo_group_id)
data = await state.get_data()
@@ -261,36 +234,13 @@ async def handle_subscription_config_back(
elif current_state == SubscriptionStates.confirming_purchase.state:
data = await state.get_data()
- if settings.is_devices_selection_enabled():
- selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
+ selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
- await callback.message.edit_text(
- texts.SELECT_DEVICES,
- reply_markup=get_devices_keyboard(selected_devices, db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_devices)
- elif await _should_show_countries_management(db_user):
- countries = await _get_available_countries(db_user.promo_group_id)
- selected_countries = data.get('countries', [])
-
- await callback.message.edit_text(
- texts.SELECT_COUNTRIES,
- reply_markup=get_countries_keyboard(countries, selected_countries, db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_countries)
- elif settings.is_traffic_selectable():
- await callback.message.edit_text(
- texts.SELECT_TRAFFIC,
- reply_markup=get_traffic_packages_keyboard(db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_traffic)
- else:
- await callback.message.edit_text(
- await _build_subscription_period_prompt(db_user, texts, db),
- reply_markup=get_subscription_period_keyboard(db_user.language),
- parse_mode="HTML",
- )
- await state.set_state(SubscriptionStates.selecting_period)
+ await callback.message.edit_text(
+ texts.SELECT_DEVICES,
+ reply_markup=get_devices_keyboard(selected_devices, db_user.language)
+ )
+ await state.set_state(SubscriptionStates.selecting_devices)
else:
from app.handlers.menu import show_main_menu
diff --git a/app/handlers/subscription/countries.py b/app/handlers/subscription/countries.py
index a0a4336a..1e964189 100644
--- a/app/handlers/subscription/countries.py
+++ b/app/handlers/subscription/countries.py
@@ -79,7 +79,6 @@ from app.utils.promo_offer import (
)
from .common import _get_addon_discount_percent_for_user, _get_period_hint_from_subscription, logger
-from .workflow import present_subscription_summary
async def handle_add_countries(
callback: types.CallbackQuery,
@@ -589,21 +588,15 @@ async def countries_continue(
await callback.answer("⚠️ Выберите хотя бы одну страну!", show_alert=True)
return
- if settings.is_devices_selection_enabled():
- selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
+ selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
- await callback.message.edit_text(
- texts.SELECT_DEVICES,
- reply_markup=get_devices_keyboard(selected_devices, db_user.language)
- )
+ await callback.message.edit_text(
+ texts.SELECT_DEVICES,
+ reply_markup=get_devices_keyboard(selected_devices, db_user.language)
+ )
- await state.set_state(SubscriptionStates.selecting_devices)
- await callback.answer()
- return
-
- success = await present_subscription_summary(callback, state, db_user, texts)
- if success:
- await callback.answer()
+ await state.set_state(SubscriptionStates.selecting_devices)
+ await callback.answer()
async def _get_available_countries(promo_group_id: Optional[int] = None):
from app.utils.cache import cache, cache_key
diff --git a/app/handlers/subscription/devices.py b/app/handlers/subscription/devices.py
index 0cbb809b..3ca44442 100644
--- a/app/handlers/subscription/devices.py
+++ b/app/handlers/subscription/devices.py
@@ -183,16 +183,6 @@ async def handle_change_devices(
texts = get_texts(db_user.language)
subscription = db_user.subscription
- if not settings.is_devices_selection_enabled():
- await callback.answer(
- texts.t(
- "DEVICES_SELECTION_DISABLED",
- "⚠️ Изменение количества устройств недоступно",
- ),
- show_alert=True,
- )
- return
-
if not subscription or subscription.is_trial:
await callback.answer(
texts.t("PAID_FEATURE_ONLY", "⚠️ Эта функция доступна только для платных подписок"),
@@ -243,16 +233,6 @@ async def confirm_change_devices(
texts = get_texts(db_user.language)
subscription = db_user.subscription
- if not settings.is_devices_selection_enabled():
- await callback.answer(
- texts.t(
- "DEVICES_SELECTION_DISABLED",
- "⚠️ Изменение количества устройств недоступно",
- ),
- show_alert=True,
- )
- return
-
current_devices = subscription.device_limit
if new_devices_count == current_devices:
@@ -399,16 +379,6 @@ async def execute_change_devices(
subscription = db_user.subscription
current_devices = subscription.device_limit
- if not settings.is_devices_selection_enabled():
- await callback.answer(
- texts.t(
- "DEVICES_SELECTION_DISABLED",
- "⚠️ Изменение количества устройств недоступно",
- ),
- show_alert=True,
- )
- return
-
try:
if price > 0:
success = await subtract_user_balance(
@@ -893,16 +863,6 @@ async def confirm_add_devices(
texts = get_texts(db_user.language)
subscription = db_user.subscription
- if not settings.is_devices_selection_enabled():
- await callback.answer(
- texts.t(
- "DEVICES_SELECTION_DISABLED",
- "⚠️ Изменение количества устройств недоступно",
- ),
- show_alert=True,
- )
- return
-
resume_callback = None
new_total_devices = subscription.device_limit + devices_count
diff --git a/app/handlers/subscription/purchase.py b/app/handlers/subscription/purchase.py
index 572917dd..d9f8bbcc 100644
--- a/app/handlers/subscription/purchase.py
+++ b/app/handlers/subscription/purchase.py
@@ -140,7 +140,6 @@ from .traffic import (
handle_switch_traffic,
select_traffic,
)
-from .workflow import present_subscription_summary
async def show_subscription_info(
callback: types.CallbackQuery,
@@ -1257,15 +1256,12 @@ async def select_period(
reply_markup=get_countries_keyboard(countries, [], db_user.language)
)
await state.set_state(SubscriptionStates.selecting_countries)
- await callback.answer()
- return
+ else:
+ countries = await _get_available_countries(db_user.promo_group_id)
+ available_countries = [c for c in countries if c.get('is_available', True)]
+ data['countries'] = [available_countries[0]['uuid']] if available_countries else []
+ await state.set_data(data)
- countries = await _get_available_countries(db_user.promo_group_id)
- available_countries = [c for c in countries if c.get('is_available', True)]
- data['countries'] = [available_countries[0]['uuid']] if available_countries else []
- await state.set_data(data)
-
- if settings.is_devices_selection_enabled():
selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
await callback.message.edit_text(
@@ -1273,13 +1269,6 @@ async def select_period(
reply_markup=get_devices_keyboard(selected_devices, db_user.language)
)
await state.set_state(SubscriptionStates.selecting_devices)
- await callback.answer()
- return
-
- success = await present_subscription_summary(callback, state, db_user, texts)
- if success:
- await callback.answer()
- return
await callback.answer()
@@ -1292,17 +1281,6 @@ async def select_devices(
await callback.answer("❌ Некорректный запрос", show_alert=True)
return
- if not settings.is_devices_selection_enabled():
- texts = get_texts(db_user.language)
- await callback.answer(
- texts.t(
- "DEVICES_SELECTION_DISABLED",
- "⚠️ Изменение количества устройств недоступно",
- ),
- show_alert=True,
- )
- return
-
try:
devices = int(callback.data.split('_')[1])
except (ValueError, IndexError):
@@ -1346,9 +1324,24 @@ async def devices_continue(
data = await state.get_data()
texts = get_texts(db_user.language)
- success = await present_subscription_summary(callback, state, db_user, texts)
- if success:
- await callback.answer()
+ try:
+ summary_text, prepared_data = await _prepare_subscription_summary(db_user, data, texts)
+ except ValueError:
+ logger.error(f"Ошибка в расчете цены подписки для пользователя {db_user.telegram_id}")
+ await callback.answer("Ошибка расчета цены. Обратитесь в поддержку.", show_alert=True)
+ return
+
+ await state.set_data(prepared_data)
+ await save_subscription_checkout_draft(db_user.id, prepared_data)
+
+ await callback.message.edit_text(
+ summary_text,
+ reply_markup=get_subscription_confirm_keyboard(db_user.language),
+ parse_mode="HTML",
+ )
+
+ await state.set_state(SubscriptionStates.confirming_purchase)
+ await callback.answer()
async def confirm_purchase(
callback: types.CallbackQuery,
diff --git a/app/handlers/subscription/traffic.py b/app/handlers/subscription/traffic.py
index dbd40bef..6733db4b 100644
--- a/app/handlers/subscription/traffic.py
+++ b/app/handlers/subscription/traffic.py
@@ -80,7 +80,6 @@ from app.utils.promo_offer import (
from .common import _apply_addon_discount, _get_addon_discount_percent_for_user, _get_period_hint_from_subscription, get_confirm_switch_traffic_keyboard, get_traffic_switch_keyboard, logger
from .countries import _get_available_countries, _should_show_countries_management
-from .workflow import present_subscription_summary
async def handle_add_traffic(
callback: types.CallbackQuery,
@@ -353,29 +352,19 @@ async def select_traffic(
reply_markup=get_countries_keyboard(countries, [], db_user.language)
)
await state.set_state(SubscriptionStates.selecting_countries)
- await callback.answer()
- return
else:
countries = await _get_available_countries(db_user.promo_group_id)
available_countries = [c for c in countries if c.get('is_available', True)]
data['countries'] = [available_countries[0]['uuid']] if available_countries else []
await state.set_data(data)
- if settings.is_devices_selection_enabled():
- selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
+ selected_devices = data.get('devices', settings.DEFAULT_DEVICE_LIMIT)
- await callback.message.edit_text(
- texts.SELECT_DEVICES,
- reply_markup=get_devices_keyboard(selected_devices, db_user.language)
- )
- await state.set_state(SubscriptionStates.selecting_devices)
- await callback.answer()
- return
-
- success = await present_subscription_summary(callback, state, db_user, texts)
- if success:
- await callback.answer()
- return
+ await callback.message.edit_text(
+ texts.SELECT_DEVICES,
+ reply_markup=get_devices_keyboard(selected_devices, db_user.language)
+ )
+ await state.set_state(SubscriptionStates.selecting_devices)
await callback.answer()
diff --git a/app/handlers/subscription/workflow.py b/app/handlers/subscription/workflow.py
deleted file mode 100644
index 88b6c831..00000000
--- a/app/handlers/subscription/workflow.py
+++ /dev/null
@@ -1,49 +0,0 @@
-import logging
-from typing import Any
-
-from aiogram import types
-from aiogram.fsm.context import FSMContext
-
-from app.database.models import User
-from app.keyboards.inline import get_subscription_confirm_keyboard
-from app.services.subscription_checkout_service import save_subscription_checkout_draft
-from app.states import SubscriptionStates
-
-from .pricing import _prepare_subscription_summary
-
-
-logger = logging.getLogger(__name__)
-
-
-async def present_subscription_summary(
- callback: types.CallbackQuery,
- state: FSMContext,
- db_user: User,
- texts: Any,
-) -> bool:
- data = await state.get_data()
-
- try:
- summary_text, prepared_data = await _prepare_subscription_summary(db_user, data, texts)
- except ValueError:
- logger.error(
- "Ошибка в расчете цены подписки для пользователя %s",
- db_user.telegram_id,
- )
- await callback.answer(
- "Ошибка расчета цены. Обратитесь в поддержку.",
- show_alert=True,
- )
- return False
-
- await state.set_data(prepared_data)
- await save_subscription_checkout_draft(db_user.id, prepared_data)
-
- await callback.message.edit_text(
- summary_text,
- reply_markup=get_subscription_confirm_keyboard(db_user.language),
- parse_mode="HTML",
- )
- await state.set_state(SubscriptionStates.confirming_purchase)
-
- return True
diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py
index 43611507..2656392f 100644
--- a/app/keyboards/inline.py
+++ b/app/keyboards/inline.py
@@ -2091,25 +2091,15 @@ def get_updated_subscription_settings_keyboard(language: str = DEFAULT_LANGUAGE,
InlineKeyboardButton(text=texts.t("ADD_COUNTRIES_BUTTON", "🌐 Добавить страны"), callback_data="subscription_add_countries")
])
- settings_buttons = []
-
- if settings.is_devices_selection_enabled():
- settings_buttons.append([
- InlineKeyboardButton(
- text=texts.t("CHANGE_DEVICES_BUTTON", "📱 Изменить устройства"),
- callback_data="subscription_change_devices",
- )
- ])
-
- settings_buttons.append([
- InlineKeyboardButton(
- text=texts.t("MANAGE_DEVICES_BUTTON", "🔧 Управление устройствами"),
- callback_data="subscription_manage_devices",
- )
+ keyboard.extend([
+ [
+ InlineKeyboardButton(text=texts.t("CHANGE_DEVICES_BUTTON", "📱 Изменить устройства"), callback_data="subscription_change_devices")
+ ],
+ [
+ InlineKeyboardButton(text=texts.t("MANAGE_DEVICES_BUTTON", "🔧 Управление устройствами"), callback_data="subscription_manage_devices")
+ ]
])
- keyboard.extend(settings_buttons)
-
if settings.is_traffic_selectable():
keyboard.insert(-2, [
InlineKeyboardButton(text=texts.t("SWITCH_TRAFFIC_BUTTON", "🔄 Переключить трафик"), callback_data="subscription_switch_traffic")
diff --git a/app/localization/locales/en.json b/app/localization/locales/en.json
index 7c8326b1..b4d0666e 100644
--- a/app/localization/locales/en.json
+++ b/app/localization/locales/en.json
@@ -796,7 +796,6 @@
"CANCEL_REPLY": "❌ Cancel reply",
"CANCEL_TICKET_CREATION": "❌ Cancel ticket creation",
"CHANGE_DEVICES_BUTTON": "📱 Change devices",
- "DEVICES_SELECTION_DISABLED": "⚠️ Changing the number of devices is disabled",
"CHANGE_DEVICES_CONFIRM": "\n📱 Confirm change\n\nCurrent amount: {current_devices} devices\nNew amount: {new_devices} devices\n\nAction: {action}\n💰 {cost}\n\nApply this change?\n",
"CHANGE_DEVICES_INFO": "\n📱 Adjust device limit\n\nCurrent limit: {current_devices} devices\n\nChoose the new number of devices:\n\n💡 Important:\n• Increasing — extra charge proportional to the remaining time\n• Decreasing — funds are not refunded\n",
"CHANGE_DEVICES_PROMPT": "📱 Adjust device limit\n\nCurrent limit: {current_devices} devices\nChoose the new number of devices:\n\n💡 Important:\n• Increasing — extra cost prorated by remaining time\n• Decreasing — payments are not refunded",
diff --git a/app/localization/locales/ru.json b/app/localization/locales/ru.json
index 4ee977be..aa75bdd6 100644
--- a/app/localization/locales/ru.json
+++ b/app/localization/locales/ru.json
@@ -796,7 +796,6 @@
"CANCEL_REPLY": "❌ Отменить ответ",
"CANCEL_TICKET_CREATION": "❌ Отменить создание тикета",
"CHANGE_DEVICES_BUTTON": "📱 Изменить устройства",
- "DEVICES_SELECTION_DISABLED": "⚠️ Изменение количества устройств недоступно",
"CHANGE_DEVICES_CONFIRM": "\n 📱 Подтверждение изменения\n\n Текущее количество: {current_devices} устройств\n Новое количество: {new_devices} устройств\n\n Действие: {action}\n 💰 {cost}\n\n Подтвердить изменение?\n ",
"CHANGE_DEVICES_INFO": "\n 📱 Изменение количества устройств\n\n Текущий лимит: {current_devices} устройств\n\n Выберите новое количество устройств:\n\n 💡 Важно:\n • При увеличении - доплата пропорционально оставшемуся времени\n • При уменьшении - возврат средств не производится\n ",
"CHANGE_DEVICES_PROMPT": "📱 Изменение количества устройств\n\nТекущий лимит: {current_devices} устройств\nВыберите новое количество устройств:\n\n💡 Важно:\n• При увеличении - доплата пропорционально оставшемуся времени\n• При уменьшении - возврат средств не производится",
diff --git a/app/webapi/routes/miniapp.py b/app/webapi/routes/miniapp.py
index 81639dc6..24c54603 100644
--- a/app/webapi/routes/miniapp.py
+++ b/app/webapi/routes/miniapp.py
@@ -4133,21 +4133,20 @@ async def _build_subscription_settings(
)
devices_options: List[MiniAppSubscriptionDeviceOption] = []
- if settings.is_devices_selection_enabled():
- for value in range(1, max_devices + 1):
- chargeable = max(0, value - default_device_limit)
- discounted_per_month, _ = apply_percentage_discount(
- chargeable * settings.PRICE_PER_DEVICE,
- devices_discount,
- )
- devices_options.append(
- MiniAppSubscriptionDeviceOption(
- value=value,
- label=None,
- price_kopeks=discounted_per_month,
- price_label=None,
- )
+ for value in range(1, max_devices + 1):
+ chargeable = max(0, value - default_device_limit)
+ discounted_per_month, _ = apply_percentage_discount(
+ chargeable * settings.PRICE_PER_DEVICE,
+ devices_discount,
+ )
+ devices_options.append(
+ MiniAppSubscriptionDeviceOption(
+ value=value,
+ label=None,
+ price_kopeks=discounted_per_month,
+ price_label=None,
)
+ )
settings_payload = MiniAppSubscriptionSettings(
subscription_id=subscription.id,
@@ -4172,7 +4171,7 @@ async def _build_subscription_settings(
),
devices=MiniAppSubscriptionDevicesSettings(
options=devices_options,
- can_update=settings.is_devices_selection_enabled(),
+ can_update=True,
min=1,
max=max_devices_setting or 0,
step=1,
@@ -5012,15 +5011,6 @@ async def update_subscription_devices_endpoint(
subscription = _ensure_paid_subscription(user)
_validate_subscription_id(payload.subscription_id, subscription)
- if not settings.is_devices_selection_enabled():
- raise HTTPException(
- status.HTTP_403_FORBIDDEN,
- detail={
- "code": "devices_selection_disabled",
- "message": "Изменение количества устройств отключено",
- },
- )
-
raw_value = payload.devices if payload.devices is not None else payload.device_limit
if raw_value is None:
raise HTTPException(