from aiogram import Router, types from aiogram.filters import Command from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton from decimal import Decimal from tg_bot.config.settings import settings from tg_bot.payment.yookassa.client import yookassa_client from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.models import PaymentModel, UserModel import uuid from datetime import datetime, timedelta router = Router() @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}" session = SessionLocal() try: user = session.query(UserModel).filter_by( telegram_id=str(user_id) ).first() 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"У вас уже есть активная подписка!\n\n" f"• Статус: Premium активен\n" f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n" f"• Осталось дней: {days_left}\n\n" f"Новая подписка будет добавлена к текущей.", parse_mode="HTML" ) finally: session.close() 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 ) session = SessionLocal() try: payment = PaymentModel( payment_id=str(uuid.uuid4()), user_id=user_id, amount=str(settings.PAYMENT_AMOUNT), currency="RUB", status="pending", yookassa_payment_id=payment_data["id"], description="Оплата подписки VibeLawyerBot" ) session.add(payment) session.commit() print(f"Платёж сохранён в БД: {payment.payment_id}") except Exception as e: print(f"Ошибка сохранения платежа в БД: {e}") session.rollback() finally: session.close() keyboard = InlineKeyboardMarkup( inline_keyboard=[ [ InlineKeyboardButton( text="Оплатить онлайн", url=payment_data["confirmation_url"] ) ], [ InlineKeyboardButton( text="Проверить статус оплаты", callback_data=f"check_payment:{payment_data['id']}" ) ] ] ) response_text = ( f"Оплата подписки VibeLawyerBot\n\n" f"Детали платежа:\n" f"• Сумма: {settings.PAYMENT_AMOUNT} руб.\n" f"• Описание: Подписка на 30 дней\n" f"• ID платежа: {payment_data['id'][:20]}...\n\n" f"Что даёт подписка:\n" f"• Неограниченное число вопросов\n" f"• Приоритетная обработка\n" f"• Доступ ко всем функциям\n\n" f"После оплаты доступ активируется автоматически в течение 1-2 минут." ) await message.answer( response_text, parse_mode="HTML", reply_markup=keyboard, disable_web_page_preview=True ) await message.answer( "Инструкция по оплате:\n\n" "1. Нажмите кнопку 'Оплатить онлайн'\n" "2. Введите данные банковской карты\n" "3. Подтвердите оплату\n" "4. После успешной оплаты нажмите 'Проверить статус оплаты'\n\n" "Тестовые карты для проверки:\n" "• 5555 5555 5555 4477 - успешная оплата\n" " Срок: любой будущий (напр. 12/30)\n" " CVV: любые 3 цифры (напр. 123)\n\n" "Это тестовые карты, реальные деньги не списываются!", parse_mode="HTML" ) except Exception as e: print(f"Ошибка создания платежа: {e}") await message.answer( "Произошла ошибка при создании платежа\n\n" "Пожалуйста, попробуйте позже или обратитесь к администратору.\n\n" f"Ошибка: {str(e)[:100]}", 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": session = SessionLocal() try: db_payment = session.query(PaymentModel).filter_by( yookassa_payment_id=yookassa_id ).first() if db_payment: db_payment.status = "succeeded" user = session.query(UserModel).filter_by( telegram_id=str(user_id) ).first() if user: user.is_premium = True if user.premium_until and user.premium_until > datetime.now(): user.premium_until = user.premium_until + timedelta(days=30) else: user.premium_until = datetime.now() + timedelta(days=30) session.commit() user = session.query(UserModel).filter_by( telegram_id=str(user_id) ).first() await callback_query.message.answer( "Оплата подтверждена!\n\n" f"Ваш premium-доступ активирован до: " f"{user.premium_until.strftime('%d.%m.%Y')}\n\n" "Теперь вы можете:\n" "• Задавать неограниченное количество вопросов\n" "• Получать приоритетные ответы\n" "• Использовать все функции бота\n\n" "Спасибо за покупку!", parse_mode="HTML" ) else: await callback_query.message.answer( "Платёж найден в ЮKассе, но не в нашей БД\n\n" "Пожалуйста, обратитесь к администратору.", parse_mode="HTML" ) finally: session.close() elif payment.status == "pending": await callback_query.message.answer( "Платёж ещё не завершён\n\n" "Если вы уже оплатили, пожалуйста, подождите 1-2 минуты " "и проверьте статус снова.\n\n" "Проверьте правильность данных карты:\n" "• Срок действия должен быть будущим\n" "• CVV - 3 цифры на обратной стороне карты", parse_mode="HTML" ) else: await callback_query.message.answer( f"Статус платежа: {payment.status}\n\n" "Попробуйте оплатить ещё раз или обратитесь в поддержку.\n\n" "Для теста используйте карту:\n" "5555 5555 5555 4477\n" "Срок: 12/30, CVV: 123", parse_mode="HTML" ) except Exception as e: print(f"Ошибка проверки статуса: {e}") await callback_query.message.answer( "Не удалось проверить статус платежа\n\n" "Попробуйте позже или обратитесь к администратору.", parse_mode="HTML" ) @router.message(Command("mypayments")) async def cmd_my_payments(message: Message): user_id = message.from_user.id session = SessionLocal() try: payments = session.query(PaymentModel).filter_by( user_id=user_id ).order_by(PaymentModel.created_at.desc()).limit(10).all() if not payments: await message.answer( "У вас пока нет платежей\n\n" "Используйте команду /buy чтобы оформить подписку.", parse_mode="HTML" ) return response = ["Ваши последние платежи:\n"] for i, payment in enumerate(payments, 1): status_text = "Успешно" if payment.status == "succeeded" else "Ожидание" if payment.status == "pending" else "Ошибка" response.append( f"\n{i}. {payment.amount} руб. ({status_text})\n" f"Статус: {payment.status}\n" f"Дата: {payment.created_at.strftime('%d.%m.%Y %H:%M')}\n" f"ID: {payment.payment_id[:8]}..." ) response.append("\n\nПолный доступ открывается после успешной оплаты") await message.answer( "\n".join(response), parse_mode="HTML" ) finally: session.close() @router.message(Command("testcards")) async def cmd_testcards(message: Message): testcards_text = ( f"Тестовые банковские карты для оплаты\n\n" f"Для тестирования оплаты используйте:\n\n" f"Карта для успешной оплаты:\n" f"• Номер: 5555 5555 5555 4477\n" f"• Срок действия: ЛЮБОЙ будущий (например: 12/30)\n" f"• CVV код: ЛЮБЫЕ 3 цифры (например: 123)\n" f"• Результат: Оплата пройдёт успешно\n\n" f"Карта для отказа в оплате:\n" f"• Номер: 5555 5555 5555 4445\n" f"• Срок действия: ЛЮБОЙ будущий\n" f"• CVV код: ЛЮБЫЕ 3 цифры\n" f"• Результат: Оплата будет отклонена\n\n" f"Важно:\n" f"• Это тестовые карты, реальные деньги не списываются\n" f"• Используются только для проверки работы оплаты\n" f"• После успешной тестовой оплаты premium активируется\n\n" f"Для оплаты подписки используйте команду /buy" ) await message.answer(testcards_text, parse_mode="HTML")