Update tariffs.py

This commit is contained in:
Egor
2026-01-10 20:32:57 +03:00
committed by GitHub
parent 8690d5fa8e
commit 69f4fd2b2a

View File

@@ -191,6 +191,9 @@ def get_tariff_view_keyboard(
InlineKeyboardButton(text="📱💰 Цена за устройство", callback_data=f"admin_tariff_edit_device_price:{tariff.id}"),
InlineKeyboardButton(text="⏰ Дни триала", callback_data=f"admin_tariff_edit_trial_days:{tariff.id}"),
])
buttons.append([
InlineKeyboardButton(text="📈 Докупка трафика", callback_data=f"admin_tariff_edit_traffic_topup:{tariff.id}"),
])
buttons.append([
InlineKeyboardButton(text="🌐 Серверы", callback_data=f"admin_tariff_edit_squads:{tariff.id}"),
InlineKeyboardButton(text="👥 Промогруппы", callback_data=f"admin_tariff_edit_promo:{tariff.id}"),
@@ -229,6 +232,23 @@ def get_tariff_view_keyboard(
return InlineKeyboardMarkup(inline_keyboard=buttons)
def _format_traffic_topup_packages(tariff: Tariff) -> str:
"""Форматирует пакеты докупки трафика для отображения."""
if not getattr(tariff, 'traffic_topup_enabled', False):
return "❌ Отключено"
packages = tariff.get_traffic_topup_packages() if hasattr(tariff, 'get_traffic_topup_packages') else {}
if not packages:
return "✅ Включено, но пакеты не настроены"
lines = ["✅ Включено"]
for gb in sorted(packages.keys()):
price = packages[gb]
lines.append(f"{gb} ГБ: {_format_price_kopeks(price)}")
return "\n".join(lines)
def format_tariff_info(tariff: Tariff, language: str, subs_count: int = 0) -> str:
"""Форматирует информацию о тарифе."""
texts = get_texts(language)
@@ -264,6 +284,9 @@ def format_tariff_info(tariff: Tariff, language: str, subs_count: int = 0) -> st
else:
device_price_display = "Недоступно"
# Форматируем докупку трафика
traffic_topup_display = _format_traffic_topup_packages(tariff)
return f"""📦 <b>Тариф: {tariff.name}</b>
{status}
@@ -277,6 +300,9 @@ def format_tariff_info(tariff: Tariff, language: str, subs_count: int = 0) -> st
• Триал: {trial_status}
• Дней триала: {trial_days_display}
<b>Докупка трафика:</b>
{traffic_topup_display}
<b>Цены:</b>
{prices_display}
@@ -1310,6 +1336,285 @@ async def process_edit_tariff_trial_days(
)
# ============ РЕДАКТИРОВАНИЕ ДОКУПКИ ТРАФИКА ============
def _parse_traffic_topup_packages(text: str) -> Dict[int, int]:
"""
Парсит строку с пакетами докупки трафика.
Формат: "5:5000, 10:9000, 20:15000" (ГБ:цена_в_копейках)
"""
packages = {}
text = text.replace(";", ",").replace("=", ":")
for part in text.split(","):
part = part.strip()
if not part:
continue
if ":" not in part:
continue
gb_str, price_str = part.split(":", 1)
try:
gb = int(gb_str.strip())
price = int(price_str.strip())
if gb > 0 and price > 0:
packages[gb] = price
except ValueError:
continue
return packages
def _format_traffic_topup_packages_for_edit(packages: Dict[int, int]) -> str:
"""Форматирует пакеты докупки для редактирования."""
if not packages:
return "5:5000, 10:9000, 20:15000"
parts = []
for gb in sorted(packages.keys()):
parts.append(f"{gb}:{packages[gb]}")
return ", ".join(parts)
@admin_required
@error_handler
async def start_edit_tariff_traffic_topup(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
state: FSMContext,
):
"""Показывает меню настройки докупки трафика."""
texts = get_texts(db_user.language)
tariff_id = int(callback.data.split(":")[1])
tariff = await get_tariff_by_id(db, tariff_id)
if not tariff:
await callback.answer("Тариф не найден", show_alert=True)
return
# Проверяем, безлимитный ли тариф
if tariff.is_unlimited_traffic:
await callback.answer("Докупка недоступна для безлимитного тарифа", show_alert=True)
return
is_enabled = getattr(tariff, 'traffic_topup_enabled', False)
packages = tariff.get_traffic_topup_packages() if hasattr(tariff, 'get_traffic_topup_packages') else {}
# Форматируем текущие настройки
if is_enabled:
status = "✅ Включено"
if packages:
packages_display = "\n".join(f"{gb} ГБ: {_format_price_kopeks(price)}" for gb, price in sorted(packages.items()))
else:
packages_display = " Пакеты не настроены"
else:
status = "❌ Отключено"
packages_display = " -"
buttons = []
# Переключение вкл/выкл
if is_enabled:
buttons.append([
InlineKeyboardButton(text="❌ Отключить", callback_data=f"admin_tariff_toggle_traffic_topup:{tariff_id}")
])
else:
buttons.append([
InlineKeyboardButton(text="✅ Включить", callback_data=f"admin_tariff_toggle_traffic_topup:{tariff_id}")
])
# Редактирование пакетов (только если включено)
if is_enabled:
buttons.append([
InlineKeyboardButton(text="📦 Настроить пакеты", callback_data=f"admin_tariff_edit_topup_packages:{tariff_id}")
])
buttons.append([
InlineKeyboardButton(text=texts.BACK, callback_data=f"admin_tariff_view:{tariff_id}")
])
await callback.message.edit_text(
f"📈 <b>Докупка трафика для «{tariff.name}»</b>\n\n"
f"Статус: {status}\n\n"
f"<b>Пакеты:</b>\n{packages_display}\n\n"
"Пользователи смогут докупать трафик по заданным ценам.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
parse_mode="HTML"
)
await callback.answer()
@admin_required
@error_handler
async def toggle_tariff_traffic_topup(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
):
"""Переключает включение/выключение докупки трафика."""
tariff_id = int(callback.data.split(":")[1])
tariff = await get_tariff_by_id(db, tariff_id)
if not tariff:
await callback.answer("Тариф не найден", show_alert=True)
return
is_enabled = getattr(tariff, 'traffic_topup_enabled', False)
new_value = not is_enabled
tariff = await update_tariff(db, tariff, traffic_topup_enabled=new_value)
status_text = "включена" if new_value else "отключена"
await callback.answer(f"Докупка трафика {status_text}")
# Перерисовываем меню
texts = get_texts(db_user.language)
packages = tariff.get_traffic_topup_packages() if hasattr(tariff, 'get_traffic_topup_packages') else {}
if new_value:
status = "✅ Включено"
if packages:
packages_display = "\n".join(f"{gb} ГБ: {_format_price_kopeks(price)}" for gb, price in sorted(packages.items()))
else:
packages_display = " Пакеты не настроены"
else:
status = "❌ Отключено"
packages_display = " -"
buttons = []
if new_value:
buttons.append([
InlineKeyboardButton(text="❌ Отключить", callback_data=f"admin_tariff_toggle_traffic_topup:{tariff_id}")
])
buttons.append([
InlineKeyboardButton(text="📦 Настроить пакеты", callback_data=f"admin_tariff_edit_topup_packages:{tariff_id}")
])
else:
buttons.append([
InlineKeyboardButton(text="✅ Включить", callback_data=f"admin_tariff_toggle_traffic_topup:{tariff_id}")
])
buttons.append([
InlineKeyboardButton(text=texts.BACK, callback_data=f"admin_tariff_view:{tariff_id}")
])
try:
await callback.message.edit_text(
f"📈 <b>Докупка трафика для «{tariff.name}»</b>\n\n"
f"Статус: {status}\n\n"
f"<b>Пакеты:</b>\n{packages_display}\n\n"
"Пользователи смогут докупать трафик по заданным ценам.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
parse_mode="HTML"
)
except TelegramBadRequest:
pass
@admin_required
@error_handler
async def start_edit_traffic_topup_packages(
callback: types.CallbackQuery,
db_user: User,
db: AsyncSession,
state: FSMContext,
):
"""Начинает редактирование пакетов докупки трафика."""
texts = get_texts(db_user.language)
tariff_id = int(callback.data.split(":")[1])
tariff = await get_tariff_by_id(db, tariff_id)
if not tariff:
await callback.answer("Тариф не найден", show_alert=True)
return
await state.set_state(AdminStates.editing_tariff_traffic_topup_packages)
await state.update_data(tariff_id=tariff_id, language=db_user.language)
packages = tariff.get_traffic_topup_packages() if hasattr(tariff, 'get_traffic_topup_packages') else {}
current_packages = _format_traffic_topup_packages_for_edit(packages)
if packages:
packages_display = "\n".join(f"{gb} ГБ: {_format_price_kopeks(price)}" for gb, price in sorted(packages.items()))
else:
packages_display = " Не настроены"
await callback.message.edit_text(
f"📦 <b>Настройка пакетов докупки трафика</b>\n\n"
f"Тариф: <b>{tariff.name}</b>\n\n"
f"<b>Текущие пакеты:</b>\n{packages_display}\n\n"
"Введите пакеты в формате:\n"
f"<code>{current_packages}</code>\n\n"
"(ГБ:цена_в_копейках, через запятую)\n"
"Например: <code>5:5000, 10:9000</code> = 5ГБ за 50₽, 10ГБ за 90₽",
reply_markup=InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text=texts.CANCEL, callback_data=f"admin_tariff_edit_traffic_topup:{tariff_id}")]
]),
parse_mode="HTML"
)
await callback.answer()
@admin_required
@error_handler
async def process_edit_traffic_topup_packages(
message: types.Message,
db_user: User,
db: AsyncSession,
state: FSMContext,
):
"""Обрабатывает новые пакеты докупки трафика."""
data = await state.get_data()
tariff_id = data.get("tariff_id")
tariff = await get_tariff_by_id(db, tariff_id)
if not tariff:
await message.answer("Тариф не найден")
await state.clear()
return
packages = _parse_traffic_topup_packages(message.text.strip())
if not packages:
await message.answer(
"Не удалось распознать пакеты.\n\n"
"Формат: <code>ГБ:цена_в_копейках</code>\n"
"Пример: <code>5:5000, 10:9000, 20:15000</code>",
parse_mode="HTML"
)
return
# Преобразуем в формат для JSON (строковые ключи)
packages_json = {str(gb): price for gb, price in packages.items()}
tariff = await update_tariff(db, tariff, traffic_topup_packages=packages_json)
await state.clear()
# Показываем обновленное меню
texts = get_texts(db_user.language)
packages_display = "\n".join(f"{gb} ГБ: {_format_price_kopeks(price)}" for gb, price in sorted(packages.items()))
buttons = [
[InlineKeyboardButton(text="❌ Отключить", callback_data=f"admin_tariff_toggle_traffic_topup:{tariff_id}")],
[InlineKeyboardButton(text="📦 Настроить пакеты", callback_data=f"admin_tariff_edit_topup_packages:{tariff_id}")],
[InlineKeyboardButton(text=texts.BACK, callback_data=f"admin_tariff_view:{tariff_id}")]
]
await message.answer(
f"✅ <b>Пакеты обновлены!</b>\n\n"
f"📈 <b>Докупка трафика для «{tariff.name}»</b>\n\n"
f"Статус: ✅ Включено\n\n"
f"<b>Пакеты:</b>\n{packages_display}\n\n"
"Пользователи смогут докупать трафик по заданным ценам.",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons),
parse_mode="HTML"
)
# ============ УДАЛЕНИЕ ТАРИФА ============
@admin_required
@@ -1855,6 +2160,12 @@ def register_handlers(dp: Dispatcher):
dp.callback_query.register(start_edit_tariff_trial_days, F.data.startswith("admin_tariff_edit_trial_days:"))
dp.message.register(process_edit_tariff_trial_days, AdminStates.editing_tariff_trial_days)
# Редактирование докупки трафика
dp.callback_query.register(start_edit_tariff_traffic_topup, F.data.startswith("admin_tariff_edit_traffic_topup:"))
dp.callback_query.register(toggle_tariff_traffic_topup, F.data.startswith("admin_tariff_toggle_traffic_topup:"))
dp.callback_query.register(start_edit_traffic_topup_packages, F.data.startswith("admin_tariff_edit_topup_packages:"))
dp.message.register(process_edit_traffic_topup_packages, AdminStates.editing_tariff_traffic_topup_packages)
# Удаление
dp.callback_query.register(confirm_delete_tariff, F.data.startswith("admin_tariff_delete:"))
dp.callback_query.register(delete_tariff_confirmed, F.data.startswith("admin_tariff_delete_confirm:"))