diff --git a/app/bot.py b/app/bot.py
index 36532569..649208c3 100644
--- a/app/bot.py
+++ b/app/bot.py
@@ -33,6 +33,7 @@ from app.handlers.admin import (
maintenance as admin_maintenance,
promo_groups as admin_promo_groups,
campaigns as admin_campaigns,
+ tariffs as admin_tariffs,
user_messages as admin_user_messages,
updates as admin_updates,
backup as admin_backup,
@@ -126,7 +127,8 @@ async def setup_bot() -> tuple[Bot, Dispatcher]:
admin_main.register_handlers(dp)
admin_users.register_handlers(dp)
admin_subscriptions.register_handlers(dp)
- admin_servers.register_handlers(dp)
+ admin_servers.register_handlers(dp)
+ admin_tariffs.register_handlers(dp)
admin_promocodes.register_handlers(dp)
admin_messages.register_handlers(dp)
admin_monitoring.register_handlers(dp)
diff --git a/app/handlers/admin/main.py b/app/handlers/admin/main.py
index c6f2bbe1..3e08c109 100644
--- a/app/handlers/admin/main.py
+++ b/app/handlers/admin/main.py
@@ -11,6 +11,7 @@ from app.keyboards.admin import (
get_admin_promo_submenu_keyboard,
get_admin_communications_submenu_keyboard,
get_admin_support_submenu_keyboard,
+ get_admin_tariffs_submenu_keyboard,
get_admin_settings_submenu_keyboard,
get_admin_system_submenu_keyboard
)
@@ -147,6 +148,24 @@ async def show_support_submenu(
await callback.answer()
+@admin_required
+@error_handler
+async def show_tariffs_submenu(
+ callback: types.CallbackQuery,
+ db_user: User,
+ db: AsyncSession
+):
+ texts = get_texts(db_user.language)
+
+ await callback.message.edit_text(
+ texts.t("ADMIN_TARIFFS_SUBMENU_TITLE", "🧾 **Тарифы**\n\n") +
+ texts.t("ADMIN_TARIFFS_SUBMENU_DESCRIPTION", "Управление тарифным режимом и подготовка функций:"),
+ reply_markup=get_admin_tariffs_submenu_keyboard(db_user.language),
+ parse_mode="Markdown"
+ )
+ await callback.answer()
+
+
# Moderator panel entry (from main menu quick button)
async def show_moderator_panel(
callback: types.CallbackQuery,
@@ -402,7 +421,12 @@ def register_handlers(dp: Dispatcher):
show_promo_submenu,
F.data == "admin_submenu_promo"
)
-
+
+ dp.callback_query.register(
+ show_tariffs_submenu,
+ F.data == "admin_submenu_tariffs"
+ )
+
dp.callback_query.register(
show_communications_submenu,
F.data == "admin_submenu_communications"
diff --git a/app/handlers/admin/tariffs.py b/app/handlers/admin/tariffs.py
new file mode 100644
index 00000000..ca631e9d
--- /dev/null
+++ b/app/handlers/admin/tariffs.py
@@ -0,0 +1,101 @@
+from aiogram import Dispatcher, F, types
+from sqlalchemy.ext.asyncio import AsyncSession
+
+from app.database.models import User
+from app.keyboards.admin import get_admin_tariffs_submenu_keyboard
+from app.localization.texts import get_texts
+from app.utils.decorators import admin_required, error_handler
+
+
+async def _show_placeholder(
+ callback: types.CallbackQuery,
+ db_user: User,
+ text_key: str,
+ default_text: str,
+ *,
+ parse_mode: str = "HTML",
+) -> None:
+ """Render a placeholder message with shared tariffs header."""
+
+ texts = get_texts(db_user.language)
+ header = texts.t("ADMIN_TARIFFS_PLACEHOLDER_TITLE", "🧾 Тарифы\n\n")
+ body = texts.t(text_key, default_text)
+
+ await callback.message.edit_text(
+ header + body,
+ reply_markup=get_admin_tariffs_submenu_keyboard(db_user.language),
+ parse_mode=parse_mode,
+ )
+ await callback.answer()
+
+
+@admin_required
+@error_handler
+async def show_tariff_mode_activation(
+ callback: types.CallbackQuery,
+ db_user: User,
+ db: AsyncSession,
+) -> None:
+ await _show_placeholder(
+ callback,
+ db_user,
+ "ADMIN_TARIFFS_ACTIVATE_PLACEHOLDER",
+ (
+ "⚙️ Режим тарифов пока в разработке.\n\n"
+ "После запуска режим заменит слово 'сервера' на 'тарифы' в клиентском интерфейсе"
+ " и откроет дополнительные настройки продаж."
+ ),
+ )
+
+
+@admin_required
+@error_handler
+async def show_tariff_creation_placeholder(
+ callback: types.CallbackQuery,
+ db_user: User,
+ db: AsyncSession,
+) -> None:
+ await _show_placeholder(
+ callback,
+ db_user,
+ "ADMIN_TARIFFS_CREATE_PLACEHOLDER",
+ "➕ Создание тарифов появится здесь. Подготовьте список параметров заранее.",
+ )
+
+
+@admin_required
+@error_handler
+async def show_tariff_list_placeholder(
+ callback: types.CallbackQuery,
+ db_user: User,
+ db: AsyncSession,
+) -> None:
+ await _show_placeholder(
+ callback,
+ db_user,
+ "ADMIN_TARIFFS_LIST_PLACEHOLDER",
+ "📋 Просмотр тарифов скоро будет доступен. Список покажет активные и скрытые тарифы.",
+ )
+
+
+@admin_required
+@error_handler
+async def show_tariff_stats_placeholder(
+ callback: types.CallbackQuery,
+ db_user: User,
+ db: AsyncSession,
+) -> None:
+ await _show_placeholder(
+ callback,
+ db_user,
+ "ADMIN_TARIFFS_STATS_PLACEHOLDER",
+ "📊 Статистика тарифов появится здесь и поможет отслеживать продажи по тарифам.",
+ )
+
+
+def register_handlers(dp: Dispatcher) -> None:
+ dp.callback_query.register(show_tariff_mode_activation, F.data == "admin_tariffs_activate")
+ dp.callback_query.register(show_tariff_creation_placeholder, F.data == "admin_tariffs_create")
+ dp.callback_query.register(show_tariff_list_placeholder, F.data == "admin_tariffs_list")
+ dp.callback_query.register(show_tariff_stats_placeholder, F.data == "admin_tariffs_stats")
+
diff --git a/app/keyboards/admin.py b/app/keyboards/admin.py
index ee7729af..bea28080 100644
--- a/app/keyboards/admin.py
+++ b/app/keyboards/admin.py
@@ -15,6 +15,7 @@ def get_admin_main_keyboard(language: str = "ru") -> InlineKeyboardMarkup:
return InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_USERS_SUBSCRIPTIONS", "👥 Юзеры/Подписки"), callback_data="admin_submenu_users")],
[InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_PROMO_STATS", "💰 Промокоды/Статистика"), callback_data="admin_submenu_promo")],
+ [InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_TARIFFS", "🧾 Тарифы"), callback_data="admin_submenu_tariffs")],
[InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_SUPPORT", "🛟 Поддержка"), callback_data="admin_submenu_support")],
[InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_MESSAGES", "📨 Сообщения"), callback_data="admin_submenu_communications")],
[InlineKeyboardButton(text=_t(texts, "ADMIN_MAIN_SETTINGS", "⚙️ Настройки"), callback_data="admin_submenu_settings")],
@@ -111,6 +112,40 @@ def get_admin_support_submenu_keyboard(language: str = "ru") -> InlineKeyboardMa
])
+def get_admin_tariffs_submenu_keyboard(language: str = "ru") -> InlineKeyboardMarkup:
+ texts = get_texts(language)
+
+ return InlineKeyboardMarkup(inline_keyboard=[
+ [
+ InlineKeyboardButton(
+ text=_t(texts, "ADMIN_TARIFFS_ACTIVATE_BUTTON", "⚙️ Активировать режим тарифов"),
+ callback_data="admin_tariffs_activate"
+ )
+ ],
+ [
+ InlineKeyboardButton(
+ text=_t(texts, "ADMIN_TARIFFS_CREATE_BUTTON", "➕ Создать тариф"),
+ callback_data="admin_tariffs_create"
+ )
+ ],
+ [
+ InlineKeyboardButton(
+ text=_t(texts, "ADMIN_TARIFFS_LIST_BUTTON", "📋 Список тарифов"),
+ callback_data="admin_tariffs_list"
+ )
+ ],
+ [
+ InlineKeyboardButton(
+ text=_t(texts, "ADMIN_TARIFFS_STATS_BUTTON", "📊 Статистика тарифов"),
+ callback_data="admin_tariffs_stats"
+ )
+ ],
+ [
+ InlineKeyboardButton(text=texts.BACK, callback_data="admin_panel")
+ ]
+ ])
+
+
def get_admin_settings_submenu_keyboard(language: str = "ru") -> InlineKeyboardMarkup:
texts = get_texts(language)
diff --git a/app/localization/default_locales/en.yml b/app/localization/default_locales/en.yml
index 95bb4709..5751a153 100644
--- a/app/localization/default_locales/en.yml
+++ b/app/localization/default_locales/en.yml
@@ -32,3 +32,16 @@ RULES_TEXT: |
2. Do not distribute spam or malicious content.
3. Respect other community members.
+ADMIN_MAIN_TARIFFS: "🧾 Tariffs"
+ADMIN_TARIFFS_SUBMENU_TITLE: "🧾 **Tariffs**\\n\\n"
+ADMIN_TARIFFS_SUBMENU_DESCRIPTION: "Manage the tariff mode and upcoming features:\\n\\nChoose an action:"
+ADMIN_TARIFFS_ACTIVATE_BUTTON: "⚙️ Activate tariff mode"
+ADMIN_TARIFFS_CREATE_BUTTON: "➕ Create tariff"
+ADMIN_TARIFFS_LIST_BUTTON: "📋 Tariff list"
+ADMIN_TARIFFS_STATS_BUTTON: "📊 Tariff statistics"
+ADMIN_TARIFFS_PLACEHOLDER_TITLE: "🧾 Tariffs\\n\\n"
+ADMIN_TARIFFS_ACTIVATE_PLACEHOLDER: "⚙️ Tariff mode is still under development.\\n\\nOnce launched it will rename 'servers' to 'tariffs' in the client interface and unlock additional sales settings."
+ADMIN_TARIFFS_CREATE_PLACEHOLDER: "➕ Tariff creation will appear here. Prepare the parameter list in advance."
+ADMIN_TARIFFS_LIST_PLACEHOLDER: "📋 Tariff browsing is coming soon. The list will show both active and hidden tariffs."
+ADMIN_TARIFFS_STATS_PLACEHOLDER: "📊 Tariff statistics will appear here to help track sales per tariff."
+
diff --git a/app/localization/default_locales/ru.yml b/app/localization/default_locales/ru.yml
index fc173e56..af23af41 100644
--- a/app/localization/default_locales/ru.yml
+++ b/app/localization/default_locales/ru.yml
@@ -32,3 +32,16 @@ RULES_TEXT: |
2. Не распространяйте спам и вредоносный контент.
3. Уважайте других пользователей.
+ADMIN_MAIN_TARIFFS: "🧾 Тарифы"
+ADMIN_TARIFFS_SUBMENU_TITLE: "🧾 **Тарифы**\\n\\n"
+ADMIN_TARIFFS_SUBMENU_DESCRIPTION: "Управление тарифным режимом и подготовка функций:\\n\\nВыберите действие:"
+ADMIN_TARIFFS_ACTIVATE_BUTTON: "⚙️ Активировать режим тарифов"
+ADMIN_TARIFFS_CREATE_BUTTON: "➕ Создать тариф"
+ADMIN_TARIFFS_LIST_BUTTON: "📋 Список тарифов"
+ADMIN_TARIFFS_STATS_BUTTON: "📊 Статистика тарифов"
+ADMIN_TARIFFS_PLACEHOLDER_TITLE: "🧾 Тарифы\\n\\n"
+ADMIN_TARIFFS_ACTIVATE_PLACEHOLDER: "⚙️ Режим тарифов пока в разработке.\\n\\nПосле запуска режим заменит слово 'сервера' на 'тарифы' в клиентском интерфейсе и откроет дополнительные настройки продаж."
+ADMIN_TARIFFS_CREATE_PLACEHOLDER: "➕ Создание тарифов появится здесь. Подготовьте список параметров заранее."
+ADMIN_TARIFFS_LIST_PLACEHOLDER: "📋 Просмотр тарифов скоро будет доступен. Список покажет активные и скрытые тарифы."
+ADMIN_TARIFFS_STATS_PLACEHOLDER: "📊 Статистика тарифов появится здесь и поможет отслеживать продажи по тарифам."
+
diff --git a/app/localization/locales/en.json b/app/localization/locales/en.json
index 84750376..d5186a55 100644
--- a/app/localization/locales/en.json
+++ b/app/localization/locales/en.json
@@ -16,6 +16,18 @@
"COUNTRY_CHANGES_ACTIVE_COUNT": "🌐 Active countries: {count}",
"ADMIN_MAIN_MENU": "🏠 Main menu",
"ADMIN_CAMPAIGNS": "📣 Promotional campaigns",
+ "ADMIN_MAIN_TARIFFS": "🧾 Tariffs",
+ "ADMIN_TARIFFS_SUBMENU_TITLE": "🧾 **Tariffs**\n\n",
+ "ADMIN_TARIFFS_SUBMENU_DESCRIPTION": "Manage the tariff mode and upcoming features:\n\nChoose an action:",
+ "ADMIN_TARIFFS_ACTIVATE_BUTTON": "⚙️ Activate tariff mode",
+ "ADMIN_TARIFFS_CREATE_BUTTON": "➕ Create tariff",
+ "ADMIN_TARIFFS_LIST_BUTTON": "📋 Tariff list",
+ "ADMIN_TARIFFS_STATS_BUTTON": "📊 Tariff statistics",
+ "ADMIN_TARIFFS_PLACEHOLDER_TITLE": "🧾 Tariffs\n\n",
+ "ADMIN_TARIFFS_ACTIVATE_PLACEHOLDER": "⚙️ Tariff mode is still under development.\n\nOnce launched it will rename 'servers' to 'tariffs' in the client interface and unlock additional sales settings.",
+ "ADMIN_TARIFFS_CREATE_PLACEHOLDER": "➕ Tariff creation will appear here. Prepare the parameter list in advance.",
+ "ADMIN_TARIFFS_LIST_PLACEHOLDER": "📋 Tariff browsing is coming soon. The list will show both active and hidden tariffs.",
+ "ADMIN_TARIFFS_STATS_PLACEHOLDER": "📊 Tariff statistics will appear here to help track sales per tariff.",
"AUTOPAY_BUTTON": "💳 Auto payment",
"AUTOPAY_SET_DAYS_BUTTON": "⚙️ Configure days",
"AUTOPAY_STATUS_ENABLED": "enabled",
diff --git a/app/localization/locales/ru.json b/app/localization/locales/ru.json
index 4ca51d14..5ea1fc0c 100644
--- a/app/localization/locales/ru.json
+++ b/app/localization/locales/ru.json
@@ -93,6 +93,18 @@
"ADMIN_PROMO_GROUP_DELETE_CONFIRM": "Удалить промогруппу «{name}»? Все пользователи будут переведены в базовую группу.",
"ADMIN_PROMO_GROUP_DELETED": "Промогруппа «{name}» удалена.",
"ADMIN_SUBSCRIPTIONS": "📱 Подписки",
+ "ADMIN_MAIN_TARIFFS": "🧾 Тарифы",
+ "ADMIN_TARIFFS_SUBMENU_TITLE": "🧾 **Тарифы**\n\n",
+ "ADMIN_TARIFFS_SUBMENU_DESCRIPTION": "Управление тарифным режимом и подготовка функций:\n\nВыберите действие:",
+ "ADMIN_TARIFFS_ACTIVATE_BUTTON": "⚙️ Активировать режим тарифов",
+ "ADMIN_TARIFFS_CREATE_BUTTON": "➕ Создать тариф",
+ "ADMIN_TARIFFS_LIST_BUTTON": "📋 Список тарифов",
+ "ADMIN_TARIFFS_STATS_BUTTON": "📊 Статистика тарифов",
+ "ADMIN_TARIFFS_PLACEHOLDER_TITLE": "🧾 Тарифы\n\n",
+ "ADMIN_TARIFFS_ACTIVATE_PLACEHOLDER": "⚙️ Режим тарифов пока в разработке.\n\nПосле запуска режим заменит слово 'сервера' на 'тарифы' в клиентском интерфейсе и откроет дополнительные настройки продаж.",
+ "ADMIN_TARIFFS_CREATE_PLACEHOLDER": "➕ Создание тарифов появится здесь. Подготовьте список параметров заранее.",
+ "ADMIN_TARIFFS_LIST_PLACEHOLDER": "📋 Просмотр тарифов скоро будет доступен. Список покажет активные и скрытые тарифы.",
+ "ADMIN_TARIFFS_STATS_PLACEHOLDER": "📊 Статистика тарифов появится здесь и поможет отслеживать продажи по тарифам.",
"ADMIN_USERS": "👥 Пользователи",
"ADMIN_TICKETS_TITLE_OPEN": "🎫 Открытые тикеты поддержки:",
"ADMIN_TICKETS_TITLE_CLOSED": "🎫 Закрытые тикеты поддержки:",