forked from HSE_team/BetterCallPraskovia
227 lines
11 KiB
Python
227 lines
11 KiB
Python
from aiogram import Router, types
|
||
from aiogram.filters import Command
|
||
from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
|
||
from decimal import Decimal
|
||
import aiohttp
|
||
from tg_bot.config.settings import settings
|
||
from tg_bot.payment.yookassa.client import yookassa_client
|
||
from tg_bot.domain.user_service import UserService
|
||
from datetime import datetime
|
||
|
||
router = Router()
|
||
user_service = UserService()
|
||
|
||
|
||
@router.message(Command("buy"))
|
||
async def cmd_buy(message: Message):
|
||
user_id = message.from_user.id
|
||
username = message.from_user.username or f"user_{user_id}"
|
||
|
||
try:
|
||
user = await user_service.get_user_by_telegram_id(user_id)
|
||
|
||
if user and user.is_premium and user.premium_until and user.premium_until > datetime.now():
|
||
days_left = (user.premium_until - datetime.now()).days
|
||
await message.answer(
|
||
f"<b>У вас уже есть активная подписка!</b>\n\n"
|
||
f"• Статус: Premium активен\n"
|
||
f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n"
|
||
f"• Осталось дней: {days_left}\n\n"
|
||
f"Новая подписка будет добавлена к текущей.",
|
||
parse_mode="HTML"
|
||
)
|
||
except aiohttp.ClientError as e:
|
||
print(f"Не удалось подключиться к backend при проверке подписки: {e}")
|
||
except Exception as e:
|
||
print(f"Ошибка при проверке подписки: {e}")
|
||
|
||
await message.answer(
|
||
"*Создаю ссылку для оплаты...*\n\n"
|
||
"Пожалуйста, подождите несколько секунд.",
|
||
parse_mode="Markdown"
|
||
)
|
||
|
||
try:
|
||
payment_data = await yookassa_client.create_payment(
|
||
amount=Decimal(str(settings.PAYMENT_AMOUNT)),
|
||
description=f"Подписка VibeLawyerBot для @{username}",
|
||
user_id=user_id
|
||
)
|
||
|
||
print(f"Платёж создан в ЮKассе: {payment_data['id']}")
|
||
|
||
keyboard = InlineKeyboardMarkup(
|
||
inline_keyboard=[
|
||
[
|
||
InlineKeyboardButton(
|
||
text="Оплатить онлайн",
|
||
url=payment_data["confirmation_url"]
|
||
)
|
||
],
|
||
[
|
||
InlineKeyboardButton(
|
||
text="Проверить статус оплаты",
|
||
callback_data=f"check_payment:{payment_data['id']}"
|
||
)
|
||
]
|
||
]
|
||
)
|
||
response_text = (
|
||
f"<b>Оплата подписки VibeLawyerBot</b>\n\n"
|
||
f"<b>Детали платежа:</b>\n"
|
||
f"• Сумма: {settings.PAYMENT_AMOUNT} руб.\n"
|
||
f"• Описание: Подписка на 30 дней\n"
|
||
f"• ID платежа: <code>{payment_data['id'][:20]}...</code>\n\n"
|
||
f"<b>Что даёт подписка:</b>\n"
|
||
f"• Неограниченное число вопросов\n"
|
||
f"• Приоритетная обработка\n"
|
||
f"• Доступ ко всем функциям\n\n"
|
||
f"<i>После оплаты доступ активируется автоматически в течение 1-2 минут.</i>"
|
||
)
|
||
|
||
await message.answer(
|
||
response_text,
|
||
parse_mode="HTML",
|
||
reply_markup=keyboard,
|
||
disable_web_page_preview=True
|
||
)
|
||
await message.answer(
|
||
"<b>Инструкция по оплате:</b>\n\n"
|
||
"1. Нажмите кнопку 'Оплатить онлайн'\n"
|
||
"2. Введите данные банковской карты\n"
|
||
"3. Подтвердите оплату\n"
|
||
"4. После успешной оплаты нажмите 'Проверить статус оплаты'\n\n"
|
||
"<b>Тестовые карты для проверки:</b>\n"
|
||
"• <code>5555 5555 5555 4477</code> - успешная оплата\n"
|
||
" Срок: <b>любой будущий</b> (напр. 12/30)\n"
|
||
" CVV: <b>любые 3 цифры</b> (напр. 123)\n\n"
|
||
"<i>Это тестовые карты, реальные деньги не списываются!</i>",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
except Exception as e:
|
||
print(f"Ошибка создания платежа: {e}")
|
||
await message.answer(
|
||
"<b>Произошла ошибка при создании платежа</b>\n\n"
|
||
"Пожалуйста, попробуйте позже или обратитесь к администратору.\n\n"
|
||
f"<code>Ошибка: {str(e)[:100]}</code>",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
|
||
@router.callback_query(lambda c: c.data.startswith("check_payment:"))
|
||
async def check_payment_status(callback_query: types.CallbackQuery):
|
||
yookassa_id = callback_query.data.split(":")[1]
|
||
user_id = callback_query.from_user.id
|
||
|
||
await callback_query.answer("Проверяю статус оплаты...")
|
||
|
||
try:
|
||
from yookassa import Payment as YooPayment
|
||
payment = YooPayment.find_one(yookassa_id)
|
||
|
||
if payment.status == "succeeded":
|
||
try:
|
||
success = await user_service.activate_premium(user_id)
|
||
if success:
|
||
user = await user_service.get_user_by_telegram_id(user_id)
|
||
if user:
|
||
await callback_query.message.answer(
|
||
"<b>Оплата подтверждена!</b>\n\n"
|
||
f"Ваш premium-доступ активирован до: "
|
||
f"<b>{user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}</b>\n\n"
|
||
"Теперь вы можете:\n"
|
||
"• Задавать неограниченное количество вопросов\n"
|
||
"• Получать приоритетные ответы\n"
|
||
"• Использовать все функции бота\n\n"
|
||
"<i>Спасибо за покупку!</i>",
|
||
parse_mode="HTML"
|
||
)
|
||
else:
|
||
await callback_query.message.answer(
|
||
"<b>Оплата подтверждена, но не удалось активировать premium</b>\n\n"
|
||
"Пожалуйста, обратитесь к администратору.",
|
||
parse_mode="HTML"
|
||
)
|
||
else:
|
||
await callback_query.message.answer(
|
||
"<b>Оплата подтверждена, но не удалось активировать premium</b>\n\n"
|
||
"Пожалуйста, обратитесь к администратору.",
|
||
parse_mode="HTML"
|
||
)
|
||
except Exception as e:
|
||
print(f"Ошибка обработки платежа: {e}")
|
||
await callback_query.message.answer(
|
||
"<b>Ошибка активации premium</b>\n\n"
|
||
"Пожалуйста, обратитесь к администратору.",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
elif payment.status == "pending":
|
||
await callback_query.message.answer(
|
||
"<b>Платёж ещё не завершён</b>\n\n"
|
||
"Если вы уже оплатили, пожалуйста, подождите 1-2 минуты "
|
||
"и проверьте статус снова.\n\n"
|
||
"<i>Проверьте правильность данных карты:</i>\n"
|
||
"• Срок действия должен быть <b>будущим</b>\n"
|
||
"• CVV - <b>3 цифры</b> на обратной стороне карты",
|
||
parse_mode="HTML"
|
||
)
|
||
else:
|
||
await callback_query.message.answer(
|
||
f"<b>Статус платежа: {payment.status}</b>\n\n"
|
||
"Попробуйте оплатить ещё раз или обратитесь в поддержку.\n\n"
|
||
"<i>Для теста используйте карту:</i>\n"
|
||
"<code>5555 5555 5555 4477</code>\n"
|
||
"Срок: <b>12/30</b>, CVV: <b>123</b>",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
except Exception as e:
|
||
print(f"Ошибка проверки статуса: {e}")
|
||
await callback_query.message.answer(
|
||
"<b>Не удалось проверить статус платежа</b>\n\n"
|
||
"Попробуйте позже или обратитесь к администратору.",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
@router.message(Command("mypayments"))
|
||
async def cmd_my_payments(message: Message):
|
||
await message.answer(
|
||
"<b>История платежей</b>\n\n"
|
||
"История платежей хранится в системе оплаты ЮKassa.\n"
|
||
"Для проверки статуса подписки используйте команду /stats.\n\n"
|
||
"Для оформления новой подписки используйте команду /buy",
|
||
parse_mode="HTML"
|
||
)
|
||
|
||
|
||
@router.message(Command("testcards"))
|
||
async def cmd_testcards(message: Message):
|
||
testcards_text = (
|
||
f"<b>Тестовые банковские карты для оплаты</b>\n\n"
|
||
|
||
f"<b>Для тестирования оплаты используйте:</b>\n\n"
|
||
|
||
f"<b>Карта для успешной оплаты:</b>\n"
|
||
f"• Номер: <code>5555 5555 5555 4477</code>\n"
|
||
f"• Срок действия: <b>ЛЮБОЙ будущий</b> (например: 12/30)\n"
|
||
f"• CVV код: <b>ЛЮБЫЕ 3 цифры</b> (например: 123)\n"
|
||
f"• Результат: Оплата пройдёт успешно\n\n"
|
||
|
||
f"<b>Карта для отказа в оплате:</b>\n"
|
||
f"• Номер: <code>5555 5555 5555 4445</code>\n"
|
||
f"• Срок действия: <b>ЛЮБОЙ будущий</b>\n"
|
||
f"• CVV код: <b>ЛЮБЫЕ 3 цифры</b>\n"
|
||
f"• Результат: Оплата будет отклонена\n\n"
|
||
|
||
f"<b>Важно:</b>\n"
|
||
f"• Это тестовые карты, реальные деньги не списываются\n"
|
||
f"• Используются только для проверки работы оплаты\n"
|
||
f"• После успешной тестовой оплаты premium активируется\n\n"
|
||
|
||
f"Для оплаты подписки используйте команду /buy"
|
||
)
|
||
|
||
await message.answer(testcards_text, parse_mode="HTML")
|