Files
Solo_bot/handlers/admin/tariffs/tariff_configurator/device_pricing.py
T

203 lines
7.7 KiB
Python

from datetime import datetime
from aiogram import F
from aiogram.fsm.context import FSMContext
from aiogram.types import CallbackQuery, Message
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from database.models import Tariff
from filters.admin import IsAdminFilter
from .. import router
from .common import (
TariffConfigState,
build_cancel_config_kb,
build_config_menu_kb,
build_config_summary_text,
build_device_overrides_screen,
calculate_device_formula_extra,
)
@router.callback_query(F.data.startswith("cfg_edit_device_step|"), TariffConfigState.choosing_section, IsAdminFilter())
async def ask_device_step(callback: CallbackQuery, state: FSMContext):
tariff_id = int(callback.data.split("|")[1])
await state.set_state(TariffConfigState.entering_device_step)
await state.update_data(tariff_id=tariff_id)
text = (
"💰 Базовый шаг доплаты за устройства.\n\n"
"Введите цену в рублях за КАЖДОЕ устройство сверх базового лимита.\n"
"Например: <code>50</code>\n\n"
"Чтобы выключить автоматическую доплату за устройства, отправьте <code>0</code>."
)
await callback.message.edit_text(text=text, reply_markup=build_cancel_config_kb(tariff_id))
@router.message(TariffConfigState.entering_device_step, IsAdminFilter())
async def save_device_step(message: Message, state: FSMContext, session: AsyncSession):
data = await state.get_data()
tariff_id = data["tariff_id"]
try:
price = int(message.text.strip())
if price < 0:
raise ValueError
except ValueError:
await message.answer(
"❌ Некорректное значение. Введите целое число 0 или больше.",
reply_markup=build_cancel_config_kb(tariff_id),
)
return
result = await session.execute(select(Tariff).where(Tariff.id == tariff_id))
tariff = result.scalar_one_or_none()
if not tariff:
await message.answer("❌ Тариф не найден.")
await state.clear()
return
tariff.device_step_rub = price
tariff.updated_at = datetime.utcnow()
await session.commit()
await state.set_state(TariffConfigState.choosing_section)
text = build_config_summary_text(tariff)
await message.answer(text=text, reply_markup=build_config_menu_kb(tariff_id))
@router.callback_query(F.data.startswith("cfg_edit_device_over|"), TariffConfigState.choosing_section, IsAdminFilter())
async def open_device_overrides_menu(callback: CallbackQuery, state: FSMContext, session: AsyncSession):
tariff_id = int(callback.data.split("|")[1])
result = await session.execute(select(Tariff).where(Tariff.id == tariff_id))
tariff = result.scalar_one_or_none()
if not tariff:
await callback.message.edit_text("❌ Тариф не найден.")
return
device_options = tariff.device_options or []
if not device_options:
await callback.message.edit_text(
"Сначала настройте варианты устройств (кнопка «📱 Варианты устройств»).",
reply_markup=build_config_menu_kb(tariff_id),
)
return
await state.set_state(TariffConfigState.entering_device_overrides)
await state.update_data(tariff_id=tariff_id, devices_override=None)
text, markup = build_device_overrides_screen(tariff)
await callback.message.edit_text(text=text, reply_markup=markup)
@router.callback_query(
F.data.startswith("cfg_dev_over_item|"), TariffConfigState.entering_device_overrides, IsAdminFilter()
)
async def choose_device_override_option(callback: CallbackQuery, state: FSMContext, session: AsyncSession):
parts = callback.data.split("|")
tariff_id = int(parts[1])
devices = int(parts[2])
await state.update_data(tariff_id=tariff_id, devices_override=devices)
result = await session.execute(select(Tariff).where(Tariff.id == tariff_id))
tariff = result.scalar_one_or_none()
if not tariff:
await callback.message.edit_text("❌ Тариф не найден.")
await state.clear()
return
overrides = getattr(tariff, "device_overrides", None) or {}
key = str(devices)
formula_extra = calculate_device_formula_extra(tariff, devices)
override_extra = overrides.get(key)
if override_extra is not None:
effective_extra = int(override_extra)
note = "индивидуальная доплата"
else:
effective_extra = formula_extra
note = "доплата по базовому шагу"
if devices == 0:
label = "безлимитное количество устройств"
else:
label = f"{devices} устройств"
text = (
f"📊 {label}.\n\n"
f"Текущая доплата для этого варианта: <b>{effective_extra}₽</b> ({note}).\n\n"
"Введите новую <u>доплату за устройства</u> для этого варианта в рублях.\n"
"Отправьте <code>0</code>, чтобы вернуть расчёт по базовому шагу."
)
await callback.message.edit_text(text=text, reply_markup=build_cancel_config_kb(tariff_id))
@router.callback_query(
F.data.startswith("cfg_dev_over_clear|"), TariffConfigState.entering_device_overrides, IsAdminFilter()
)
async def clear_device_overrides(callback: CallbackQuery, state: FSMContext, session: AsyncSession):
tariff_id = int(callback.data.split("|")[1])
result = await session.execute(select(Tariff).where(Tariff.id == tariff_id))
tariff = result.scalar_one_or_none()
if not tariff:
await callback.message.edit_text("❌ Тариф не найден.")
await state.clear()
return
tariff.device_overrides = None
tariff.updated_at = datetime.utcnow()
await session.commit()
text, markup = build_device_overrides_screen(tariff)
await callback.message.edit_text(text=text, reply_markup=markup)
@router.message(TariffConfigState.entering_device_overrides, IsAdminFilter())
async def save_device_override_price(message: Message, state: FSMContext, session: AsyncSession):
data = await state.get_data()
tariff_id = data.get("tariff_id")
devices = data.get("devices_override")
if not tariff_id or devices is None:
await message.answer("Сначала выберите вариант устройств из списка.")
return
try:
extra_price = int(message.text.strip())
if extra_price < 0:
raise ValueError
except ValueError:
await message.answer(
"❌ Некорректное значение. Введите целое число 0 или больше.",
reply_markup=build_cancel_config_kb(int(tariff_id)),
)
return
result = await session.execute(select(Tariff).where(Tariff.id == int(tariff_id)))
tariff = result.scalar_one_or_none()
if not tariff:
await message.answer("❌ Тариф не найден.")
await state.clear()
return
overrides = getattr(tariff, "device_overrides", None) or {}
key = str(int(devices))
if extra_price == 0:
overrides.pop(key, None)
else:
overrides[key] = extra_price
tariff.device_overrides = overrides or None
tariff.updated_at = datetime.utcnow()
await session.commit()
await state.update_data(devices_override=None)
text, markup = build_device_overrides_screen(tariff)
await message.answer(text=text, reply_markup=markup)