243 lines
7.8 KiB
Python
243 lines
7.8 KiB
Python
from datetime import datetime, timedelta
|
|
from typing import Any
|
|
|
|
import pytz
|
|
from aiogram import F, Router
|
|
from aiogram.fsm.context import FSMContext
|
|
from aiogram.types import CallbackQuery, InlineKeyboardButton, Message
|
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
|
|
from config import (
|
|
NOTIFY_EXTRA_DAYS,
|
|
TRIAL_CONFIG,
|
|
TRIAL_TIME_DISABLE,
|
|
USE_COUNTRY_SELECTION,
|
|
USE_NEW_PAYMENT_FLOW,
|
|
)
|
|
from database import (
|
|
add_user,
|
|
check_user_exists,
|
|
create_temporary_data,
|
|
get_balance,
|
|
get_tariff_by_id,
|
|
get_tariffs_for_cluster,
|
|
get_trial,
|
|
)
|
|
from handlers.buttons import MAIN_MENU, PAYMENT
|
|
from handlers.payments.robokassa_pay import handle_custom_amount_input
|
|
from handlers.payments.stars_pay import process_custom_amount_input_stars
|
|
from handlers.payments.yookassa_pay import process_custom_amount_input
|
|
from handlers.payments.yoomoney_pay import process_custom_amount_input_yoomoney
|
|
from handlers.texts import (
|
|
CREATING_CONNECTION_MSG,
|
|
INSUFFICIENT_FUNDS_MSG,
|
|
SELECT_TARIFF_PLAN_MSG,
|
|
)
|
|
from handlers.utils import edit_or_send_message, get_least_loaded_cluster
|
|
from logger import logger
|
|
|
|
from .key_cluster_mode import key_cluster_mode
|
|
from .key_country_mode import key_country_mode
|
|
|
|
router = Router()
|
|
|
|
moscow_tz = pytz.timezone("Europe/Moscow")
|
|
|
|
|
|
class Form(FSMContext):
|
|
waiting_for_server_selection = "waiting_for_server_selection"
|
|
|
|
|
|
@router.callback_query(F.data == "create_key")
|
|
async def confirm_create_new_key(
|
|
callback_query: CallbackQuery, state: FSMContext, session: Any
|
|
):
|
|
tg_id = callback_query.message.chat.id
|
|
await handle_key_creation(tg_id, state, session, callback_query)
|
|
|
|
|
|
async def handle_key_creation(
|
|
tg_id: int,
|
|
state: FSMContext,
|
|
session: Any,
|
|
message_or_query: Message | CallbackQuery,
|
|
):
|
|
current_time = datetime.now(moscow_tz)
|
|
|
|
if not TRIAL_TIME_DISABLE:
|
|
trial_status = await get_trial(session, tg_id)
|
|
if trial_status in [0, -1]:
|
|
base_days = TRIAL_CONFIG["duration_days"]
|
|
extra_days = NOTIFY_EXTRA_DAYS if trial_status == -1 else 0
|
|
total_days = base_days + extra_days
|
|
expiry_time = current_time + timedelta(days=total_days)
|
|
|
|
logger.info(f"[Trial] Доступен {total_days}-дневный триал для пользователя {tg_id}")
|
|
|
|
await edit_or_send_message(
|
|
target_message=(
|
|
message_or_query.message
|
|
if isinstance(message_or_query, CallbackQuery)
|
|
else message_or_query
|
|
),
|
|
text=CREATING_CONNECTION_MSG,
|
|
reply_markup=None,
|
|
)
|
|
|
|
await state.update_data(is_trial=True)
|
|
await create_key(tg_id, expiry_time, state, session, message_or_query)
|
|
return
|
|
|
|
cluster_name = await get_least_loaded_cluster(session)
|
|
tariffs = await get_tariffs_for_cluster(session, cluster_name)
|
|
|
|
if not tariffs:
|
|
await edit_or_send_message(
|
|
target_message=(
|
|
message_or_query.message
|
|
if isinstance(message_or_query, CallbackQuery)
|
|
else message_or_query
|
|
),
|
|
text="❌ Нет доступных тарифов для выбранного кластера.",
|
|
reply_markup=None,
|
|
)
|
|
return
|
|
|
|
builder = InlineKeyboardBuilder()
|
|
for t in tariffs:
|
|
builder.row(
|
|
InlineKeyboardButton(
|
|
text=f"{t['name']} — {t['price_rub']}₽",
|
|
callback_data=f"select_tariff_plan|{t['id']}",
|
|
)
|
|
)
|
|
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
|
|
|
target_message = (
|
|
message_or_query.message
|
|
if isinstance(message_or_query, CallbackQuery)
|
|
else message_or_query
|
|
)
|
|
|
|
await edit_or_send_message(
|
|
target_message=target_message,
|
|
text=SELECT_TARIFF_PLAN_MSG,
|
|
reply_markup=builder.as_markup(),
|
|
)
|
|
|
|
await state.update_data(tg_id=tg_id)
|
|
await state.set_state(Form.waiting_for_server_selection)
|
|
|
|
|
|
@router.callback_query(F.data.startswith("select_tariff_plan|"))
|
|
async def select_tariff_plan(
|
|
callback_query: CallbackQuery, session: Any, state: FSMContext
|
|
):
|
|
tg_id = callback_query.from_user.id
|
|
tariff_id = int(callback_query.data.split("|")[1])
|
|
|
|
tariff = await get_tariff_by_id(session, tariff_id)
|
|
if not tariff:
|
|
await callback_query.message.edit_text("❌ Указанный тариф не найден.")
|
|
return
|
|
|
|
duration_days = tariff["duration_days"]
|
|
price_rub = tariff["price_rub"]
|
|
|
|
balance = round(await get_balance(session, tg_id))
|
|
price_rub = round(tariff["price_rub"])
|
|
|
|
if balance < price_rub:
|
|
required_amount = max(price_rub - balance, 0)
|
|
await create_temporary_data(
|
|
session,
|
|
tg_id,
|
|
"waiting_for_payment",
|
|
{
|
|
"tariff_id": tariff_id,
|
|
"duration_days": duration_days,
|
|
"required_amount": required_amount,
|
|
},
|
|
)
|
|
|
|
if USE_NEW_PAYMENT_FLOW == "YOOKASSA":
|
|
await process_custom_amount_input(callback_query, session)
|
|
elif USE_NEW_PAYMENT_FLOW == "ROBOKASSA":
|
|
await handle_custom_amount_input(callback_query, session)
|
|
elif USE_NEW_PAYMENT_FLOW == "STARS":
|
|
await process_custom_amount_input_stars(callback_query, session)
|
|
elif USE_NEW_PAYMENT_FLOW == "YOOMONEY":
|
|
await process_custom_amount_input_yoomoney(callback_query, session)
|
|
else:
|
|
builder = InlineKeyboardBuilder()
|
|
builder.row(InlineKeyboardButton(text=PAYMENT, callback_data="pay"))
|
|
builder.row(InlineKeyboardButton(text=MAIN_MENU, callback_data="profile"))
|
|
await edit_or_send_message(
|
|
target_message=callback_query.message,
|
|
text=INSUFFICIENT_FUNDS_MSG.format(required_amount=required_amount),
|
|
reply_markup=builder.as_markup(),
|
|
)
|
|
return
|
|
|
|
builder = InlineKeyboardBuilder()
|
|
builder.row(
|
|
InlineKeyboardButton(text="⏳ Подождите...", callback_data="creating_key")
|
|
)
|
|
await edit_or_send_message(
|
|
target_message=callback_query.message,
|
|
text=CREATING_CONNECTION_MSG,
|
|
reply_markup=builder.as_markup(),
|
|
)
|
|
|
|
expiry_time = datetime.now(moscow_tz) + timedelta(days=duration_days)
|
|
await state.update_data(tariff_id=tariff_id)
|
|
await create_key(tg_id, expiry_time, state, session, callback_query, plan=tariff_id)
|
|
|
|
|
|
async def create_key(
|
|
tg_id: int,
|
|
expiry_time,
|
|
state,
|
|
session,
|
|
message_or_query=None,
|
|
old_key_name: str = None,
|
|
plan: int = None,
|
|
):
|
|
if not await check_user_exists(session, tg_id):
|
|
from_user = (
|
|
message_or_query.from_user
|
|
if isinstance(message_or_query, CallbackQuery | Message)
|
|
else None
|
|
)
|
|
if from_user:
|
|
await add_user(
|
|
tg_id=from_user.id,
|
|
username=from_user.username,
|
|
first_name=from_user.first_name,
|
|
last_name=from_user.last_name,
|
|
language_code=from_user.language_code,
|
|
is_bot=from_user.is_bot,
|
|
session=session,
|
|
)
|
|
logger.info(f"[User] Новый пользователь {tg_id} добавлен")
|
|
|
|
if USE_COUNTRY_SELECTION:
|
|
await key_country_mode(
|
|
tg_id=tg_id,
|
|
expiry_time=expiry_time,
|
|
state=state,
|
|
session=session,
|
|
message_or_query=message_or_query,
|
|
old_key_name=old_key_name,
|
|
plan=plan,
|
|
)
|
|
else:
|
|
await key_cluster_mode(
|
|
tg_id=tg_id,
|
|
expiry_time=expiry_time,
|
|
state=state,
|
|
session=session,
|
|
message_or_query=message_or_query,
|
|
plan=plan,
|
|
)
|