polina_tg #1

Merged
Arxip222 merged 6 commits from polina_tg into main 2025-12-22 21:41:08 +03:00
9 changed files with 289 additions and 272 deletions
Showing only changes of commit af78fc633f - Show all commits

View File

@ -3,6 +3,8 @@ pydantic-settings>=2.1.0
python-dotenv>=1.0.0 python-dotenv>=1.0.0
aiogram>=3.10.0 aiogram>=3.10.0
sqlalchemy>=2.0.0 sqlalchemy>=2.0.0
aiosqlite>=0.19.0
httpx>=0.25.0
yookassa>=2.4.0 yookassa>=2.4.0
fastapi>=0.104.0 fastapi>=0.104.0
uvicorn>=0.24.0 uvicorn>=0.24.0

View File

@ -1,29 +1,67 @@
from sqlalchemy.orm import Session from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from datetime import datetime, timedelta from datetime import datetime, timedelta
from typing import Optional
from tg_bot.infrastructure.database.models import UserModel from tg_bot.infrastructure.database.models import UserModel
class UserService: class UserService:
def __init__(self, session: Session): def __init__(self, session: AsyncSession):
self.session = session self.session = session
async def get_user_by_telegram_id(self, telegram_id: int) -> Optional[UserModel]:
result = await self.session.execute(
select(UserModel).filter_by(telegram_id=str(telegram_id))
)
return result.scalar_one_or_none()
async def get_or_create_user(
self,
telegram_id: int,
username: str = "",
first_name: str = "",
last_name: str = ""
) -> UserModel:
user = await self.get_user_by_telegram_id(telegram_id)
if not user:
user = UserModel(
telegram_id=str(telegram_id),
username=username,
first_name=first_name,
last_name=last_name
)
self.session.add(user)
await self.session.commit()
else:
user.username = username
user.first_name = first_name
user.last_name = last_name
await self.session.commit()
return user
async def update_user_questions(self, telegram_id: int) -> bool:
user = await self.get_user_by_telegram_id(telegram_id)
if user:
user.questions_used += 1
await self.session.commit()
return True
return False
async def activate_premium(self, telegram_id: int) -> bool: async def activate_premium(self, telegram_id: int) -> bool:
try: try:
user = self.session.query(UserModel) \ user = await self.get_user_by_telegram_id(telegram_id)
.filter(UserModel.telegram_id == str(telegram_id)) \
.first()
if user: if user:
user.is_premium = True user.is_premium = True
if user.premium_until and user.premium_until > datetime.now(): if user.premium_until and user.premium_until > datetime.now():
user.premium_until = user.premium_until + timedelta(days=30) user.premium_until = user.premium_until + timedelta(days=30)
else: else:
user.premium_until = datetime.now() + timedelta(days=30) user.premium_until = datetime.now() + timedelta(days=30)
self.session.commit() await self.session.commit()
return True return True
else: else:
return False return False
except Exception as e: except Exception as e:
print(f"Error activating premium: {e}") print(f"Error activating premium: {e}")
self.session.rollback() await self.session.rollback()
return False return False

View File

@ -1,15 +1,19 @@
from sqlalchemy import create_engine from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import sessionmaker
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
engine = create_engine( database_url = settings.DATABASE_URL
settings.DATABASE_URL, if database_url.startswith("sqlite:///"):
database_url = database_url.replace("sqlite:///", "sqlite+aiosqlite:///")
engine = create_async_engine(
database_url,
echo=settings.DEBUG echo=settings.DEBUG
) )
SessionLocal = sessionmaker(bind=engine) AsyncSessionLocal = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
def create_tables(): async def create_tables():
from .models import Base from .models import Base
Base.metadata.create_all(bind=engine) async with engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
print(f"Таблицы созданы: {settings.DATABASE_URL}") print(f"Таблицы созданы: {settings.DATABASE_URL}")

View File

@ -32,6 +32,7 @@ async def create_bot() -> tuple[Bot, Dispatcher]:
async def start_bot(): async def start_bot():
bot = None
try: try:
bot, dp = await create_bot() bot, dp = await create_bot()
@ -54,4 +55,5 @@ async def start_bot():
logger.error(f"Ошибка запуска: {e}") logger.error(f"Ошибка запуска: {e}")
raise raise
finally: finally:
await bot.session.close() if bot:
await bot.session.close()

View File

@ -4,8 +4,10 @@ from aiogram.types import Message, InlineKeyboardMarkup, InlineKeyboardButton
from decimal import Decimal from decimal import Decimal
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
from tg_bot.payment.yookassa.client import yookassa_client from tg_bot.payment.yookassa.client import yookassa_client
from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.database import AsyncSessionLocal
from tg_bot.infrastructure.database.models import PaymentModel, UserModel from tg_bot.infrastructure.database.models import PaymentModel
from tg_bot.domain.services.user_service import UserService
from sqlalchemy import select
import uuid import uuid
from datetime import datetime, timedelta from datetime import datetime, timedelta
@ -17,24 +19,23 @@ async def cmd_buy(message: Message):
user_id = message.from_user.id user_id = message.from_user.id
username = message.from_user.username or f"user_{user_id}" username = message.from_user.username or f"user_{user_id}"
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
user = session.query(UserModel).filter_by( user_service = UserService(session)
telegram_id=str(user_id) user = await user_service.get_user_by_telegram_id(user_id)
).first()
if user and user.is_premium and user.premium_until and user.premium_until > datetime.now(): if user and user.is_premium and user.premium_until and user.premium_until > datetime.now():
days_left = (user.premium_until - datetime.now()).days days_left = (user.premium_until - datetime.now()).days
await message.answer( await message.answer(
f"<b>У вас уже есть активная подписка!</b>\n\n" f"<b>У вас уже есть активная подписка!</b>\n\n"
f"• Статус: Premium активен\n" f"• Статус: Premium активен\n"
f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n" f"• Действует до: {user.premium_until.strftime('%d.%m.%Y')}\n"
f"• Осталось дней: {days_left}\n\n" f"• Осталось дней: {days_left}\n\n"
f"Новая подписка будет добавлена к текущей.", f"Новая подписка будет добавлена к текущей.",
parse_mode="HTML" parse_mode="HTML"
) )
finally: except Exception:
session.close() pass
await message.answer( await message.answer(
"*Создаю ссылку для оплаты...*\n\n" "*Создаю ссылку для оплаты...*\n\n"
@ -49,25 +50,23 @@ async def cmd_buy(message: Message):
user_id=user_id user_id=user_id
) )
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
payment = PaymentModel( payment = PaymentModel(
payment_id=str(uuid.uuid4()), payment_id=str(uuid.uuid4()),
user_id=user_id, user_id=user_id,
amount=str(settings.PAYMENT_AMOUNT), amount=str(settings.PAYMENT_AMOUNT),
currency="RUB", currency="RUB",
status="pending", status="pending",
yookassa_payment_id=payment_data["id"], yookassa_payment_id=payment_data["id"],
description="Оплата подписки VibeLawyerBot" description="Оплата подписки VibeLawyerBot"
) )
session.add(payment) session.add(payment)
session.commit() await session.commit()
print(f"Платёж сохранён в БД: {payment.payment_id}") print(f"Платёж сохранён в БД: {payment.payment_id}")
except Exception as e: except Exception as e:
print(f"Ошибка сохранения платежа в БД: {e}") print(f"Ошибка сохранения платежа в БД: {e}")
session.rollback() await session.rollback()
finally:
session.close()
keyboard = InlineKeyboardMarkup( keyboard = InlineKeyboardMarkup(
inline_keyboard=[ inline_keyboard=[
@ -140,49 +139,42 @@ async def check_payment_status(callback_query: types.CallbackQuery):
payment = YooPayment.find_one(yookassa_id) payment = YooPayment.find_one(yookassa_id)
if payment.status == "succeeded": if payment.status == "succeeded":
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
db_payment = session.query(PaymentModel).filter_by( result = await session.execute(
yookassa_payment_id=yookassa_id select(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(
"<b>Оплата подтверждена!</b>\n\n"
f"Ваш premium-доступ активирован до: "
f"<b>{user.premium_until.strftime('%d.%m.%Y')}</b>\n\n"
"Теперь вы можете:\n"
"• Задавать неограниченное количество вопросов\n"
"• Получать приоритетные ответы\n"
"• Использовать все функции бота\n\n"
"<i>Спасибо за покупку!</i>",
parse_mode="HTML"
) )
else: db_payment = result.scalar_one_or_none()
await callback_query.message.answer(
"<b>Платёж найден в ЮKассе, но не в нашей БД</b>\n\n" if db_payment:
"Пожалуйста, обратитесь к администратору.", db_payment.status = "succeeded"
parse_mode="HTML" user_service = UserService(session)
) success = await user_service.activate_premium(user_id)
finally: if success:
session.close() user = await user_service.get_user_by_telegram_id(user_id)
await session.commit()
if not user:
user = await user_service.get_user_by_telegram_id(user_id)
await callback_query.message.answer(
"<b>Оплата подтверждена!</b>\n\n"
f"Ваш premium-доступ активирован до: "
f"<b>{user.premium_until.strftime('%d.%m.%Y')}</b>\n\n"
"Теперь вы можете:\n"
"• Задавать неограниченное количество вопросов\n"
"• Получать приоритетные ответы\n"
"• Использовать все функции бота\n\n"
"<i>Спасибо за покупку!</i>",
parse_mode="HTML"
)
else:
await callback_query.message.answer(
"<b>Платёж найден в ЮKассе, но не в нашей БД</b>\n\n"
"Пожалуйста, обратитесь к администратору.",
parse_mode="HTML"
)
except Exception as e:
print(f"Ошибка обработки платежа: {e}")
elif payment.status == "pending": elif payment.status == "pending":
await callback_query.message.answer( await callback_query.message.answer(
@ -212,45 +204,44 @@ async def check_payment_status(callback_query: types.CallbackQuery):
parse_mode="HTML" parse_mode="HTML"
) )
@router.message(Command("mypayments")) @router.message(Command("mypayments"))
async def cmd_my_payments(message: Message): async def cmd_my_payments(message: Message):
user_id = message.from_user.id user_id = message.from_user.id
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
payments = session.query(PaymentModel).filter_by( result = await session.execute(
user_id=user_id select(PaymentModel).filter_by(user_id=user_id).order_by(PaymentModel.created_at.desc()).limit(10)
).order_by(PaymentModel.created_at.desc()).limit(10).all() )
payments = result.scalars().all()
if not payments:
await message.answer(
"<b>У вас пока нет платежей</b>\n\n"
"Используйте команду /buy чтобы оформить подписку.",
parse_mode="HTML"
)
return
response = ["<b>Ваши последние платежи:</b>\n"]
for i, payment in enumerate(payments, 1):
status_text = "Успешно" if payment.status == "succeeded" else "Ожидание" if payment.status == "pending" else "Ошибка"
response.append(
f"\n<b>{i}. {payment.amount} руб. ({status_text})</b>\n"
f"Статус: {payment.status}\n"
f"Дата: {payment.created_at.strftime('%d.%m.%Y %H:%M')}\n"
f"ID: <code>{payment.payment_id[:8]}...</code>"
)
response.append("\n\n<i>Полный доступ открывается после успешной оплаты</i>")
if not payments:
await message.answer( await message.answer(
"<b>У вас пока нет платежей</b>\n\n" "\n".join(response),
"Используйте команду /buy чтобы оформить подписку.",
parse_mode="HTML" parse_mode="HTML"
) )
return except Exception as e:
print(f"Ошибка получения платежей: {e}")
response = ["<b>Ваши последние платежи:</b>\n"]
for i, payment in enumerate(payments, 1):
status_text = "Успешно" if payment.status == "succeeded" else "Ожидание" if payment.status == "pending" else "Ошибка"
response.append(
f"\n<b>{i}. {payment.amount} руб. ({status_text})</b>\n"
f"Статус: {payment.status}\n"
f"Дата: {payment.created_at.strftime('%d.%m.%Y %H:%M')}\n"
f"ID: <code>{payment.payment_id[:8]}...</code>"
)
response.append("\n\n<i>Полный доступ открывается после успешной оплаты</i>")
await message.answer(
"\n".join(response),
parse_mode="HTML"
)
finally:
session.close()
@router.message(Command("testcards")) @router.message(Command("testcards"))

View File

@ -3,8 +3,9 @@ from aiogram.types import Message
from datetime import datetime from datetime import datetime
import aiohttp import aiohttp
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.database import AsyncSessionLocal
from tg_bot.infrastructure.database.models import UserModel from tg_bot.infrastructure.database.models import UserModel
from tg_bot.domain.services.user_service import UserService
from tg_bot.application.services.rag_service import RAGService from tg_bot.application.services.rag_service import RAGService
router = Router() router = Router()
@ -18,41 +19,35 @@ async def handle_question(message: Message):
if question_text.startswith('/'): if question_text.startswith('/'):
return return
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
user = session.query(UserModel).filter_by( user_service = UserService(session)
telegram_id=str(user_id) user = await user_service.get_user_by_telegram_id(user_id)
).first()
if not user: if not user:
user = UserModel( user = await user_service.get_or_create_user(
telegram_id=str(user_id), user_id,
username=message.from_user.username or "", message.from_user.username or "",
first_name=message.from_user.first_name or "", message.from_user.first_name or "",
last_name=message.from_user.last_name or "" message.from_user.last_name or ""
)
await ensure_user_in_backend(str(user_id), message.from_user)
if user.is_premium:
await process_premium_question(message, user, question_text, user_service)
elif user.questions_used < settings.FREE_QUESTIONS_LIMIT:
await process_free_question(message, user, question_text, user_service)
else:
await handle_limit_exceeded(message, user)
except Exception as e:
print(f"Error processing question: {e}")
await message.answer(
"Произошла ошибка. Попробуйте позже.",
parse_mode="HTML"
) )
session.add(user)
session.commit()
await ensure_user_in_backend(str(user_id), message.from_user)
if user.is_premium:
await process_premium_question(message, user, question_text, session)
elif user.questions_used < settings.FREE_QUESTIONS_LIMIT:
await process_free_question(message, user, question_text, session)
else:
await handle_limit_exceeded(message, user)
except Exception as e:
print(f"Error processing question: {e}")
await message.answer(
"Произошла ошибка. Попробуйте позже.",
parse_mode="HTML"
)
finally:
session.close()
async def ensure_user_in_backend(telegram_id: str, telegram_user): async def ensure_user_in_backend(telegram_id: str, telegram_user):
@ -74,9 +69,8 @@ async def ensure_user_in_backend(telegram_id: str, telegram_user):
print(f"Error creating user in backend: {e}") print(f"Error creating user in backend: {e}")
async def process_premium_question(message: Message, user: UserModel, question_text: str, session): async def process_premium_question(message: Message, user: UserModel, question_text: str, user_service: UserService):
user.questions_used += 1 await user_service.update_user_questions(user.telegram_id)
session.commit()
await message.bot.send_chat_action(message.chat.id, "typing") await message.bot.send_chat_action(message.chat.id, "typing")
@ -135,10 +129,10 @@ async def process_premium_question(message: Message, user: UserModel, question_t
await message.answer(response, parse_mode="HTML") await message.answer(response, parse_mode="HTML")
async def process_free_question(message: Message, user: UserModel, question_text: str, session): async def process_free_question(message: Message, user: UserModel, question_text: str, user_service: UserService):
user.questions_used += 1 await user_service.update_user_questions(user.telegram_id)
user = await user_service.get_user_by_telegram_id(user.telegram_id)
remaining = settings.FREE_QUESTIONS_LIMIT - user.questions_used remaining = settings.FREE_QUESTIONS_LIMIT - user.questions_used
session.commit()
await message.bot.send_chat_action(message.chat.id, "typing") await message.bot.send_chat_action(message.chat.id, "typing")

View File

@ -4,8 +4,8 @@ from aiogram.types import Message
from datetime import datetime from datetime import datetime
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.database import AsyncSessionLocal
from tg_bot.infrastructure.database.models import UserModel from tg_bot.domain.services.user_service import UserService
router = Router() router = Router()
@ -16,33 +16,22 @@ async def cmd_start(message: Message):
username = message.from_user.username or "" username = message.from_user.username or ""
first_name = message.from_user.first_name or "" first_name = message.from_user.first_name or ""
last_name = message.from_user.last_name or "" last_name = message.from_user.last_name or ""
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
user = session.query(UserModel).filter_by( user_service = UserService(session)
telegram_id=str(user_id) existing_user = await user_service.get_user_by_telegram_id(user_id)
).first() user = await user_service.get_or_create_user(
user_id,
if not user: username,
user = UserModel( first_name,
telegram_id=str(user_id), last_name
username=username,
first_name=first_name,
last_name=last_name
) )
session.add(user) if not existing_user:
session.commit() print(f"Новый пользователь: {user_id}")
print(f"Новый пользователь: {user_id}")
else:
user.username = username
user.first_name = first_name
user.last_name = last_name
session.commit()
except Exception as e: except Exception as e:
print(f"Ошибка сохранения пользователя: {e}") print(f"Ошибка сохранения пользователя: {e}")
session.rollback() await session.rollback()
finally:
session.close()
welcome_text = ( welcome_text = (
f"<b>Привет, {first_name}!</b>\n\n" f"<b>Привет, {first_name}!</b>\n\n"
f"Я <b>VibeLawyerBot</b> - ваш помощник в юридических вопросах.\n\n" f"Я <b>VibeLawyerBot</b> - ваш помощник в юридических вопросах.\n\n"

View File

@ -4,8 +4,8 @@ from aiogram.filters import Command
from aiogram.types import Message from aiogram.types import Message
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.database import AsyncSessionLocal
from tg_bot.infrastructure.database.models import UserModel from tg_bot.domain.services.user_service import UserService
router = Router() router = Router()
@ -14,52 +14,48 @@ router = Router()
async def cmd_stats(message: Message): async def cmd_stats(message: Message):
user_id = message.from_user.id user_id = message.from_user.id
session = SessionLocal() async with AsyncSessionLocal() as session:
try: try:
user = session.query(UserModel).filter_by( user_service = UserService(session)
telegram_id=str(user_id) user = await user_service.get_user_by_telegram_id(user_id)
).first()
if user: if user:
stats_text = ( stats_text = (
f"<b>Ваша статистика</b>\n\n" f"<b>Ваша статистика</b>\n\n"
f"<b>Основное:</b>\n" f"<b>Основное:</b>\n"
f"• ID: <code>{user_id}</code>\n" f"• ID: <code>{user_id}</code>\n"
f"• Premium: {'Да' if user.is_premium else 'Нет'}\n" f"• Premium: {'Да' if user.is_premium else 'Нет'}\n"
f"• Вопросов использовано: {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n\n" f"• Вопросов использовано: {user.questions_used}/{settings.FREE_QUESTIONS_LIMIT}\n\n"
)
if user.is_premium:
stats_text += (
f"<b>Premium статус:</b>\n"
f"• Активен до: {user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}\n"
f"• Лимит вопросов: безлимитно\n\n"
) )
if user.is_premium:
stats_text += (
f"<b>Premium статус:</b>\n"
f"• Активен до: {user.premium_until.strftime('%d.%m.%Y') if user.premium_until else 'Не указано'}\n"
f"• Лимит вопросов: безлимитно\n\n"
)
else:
remaining = max(0, settings.FREE_QUESTIONS_LIMIT - user.questions_used)
stats_text += (
f"<b>Бесплатный доступ:</b>\n"
f"• Осталось вопросов: {remaining}\n"
f"• Для безлимита: /buy\n\n"
)
else: else:
remaining = max(0, settings.FREE_QUESTIONS_LIMIT - user.questions_used) stats_text = (
stats_text += ( f"<b>Добро пожаловать!</b>\n\n"
f"<b>Бесплатный доступ:</b>\n" f"Вы новый пользователь.\n"
f"• Осталось вопросов: {remaining}\n" f"• Ваш ID: <code>{user_id}</code>\n"
f"• Для безлимита: /buy\n\n" f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n"
f"• Для начала работы просто задайте вопрос!\n\n"
f"<i>Используйте /buy для получения полного доступа</i>"
) )
else: await message.answer(stats_text, parse_mode="HTML")
stats_text = (
f"<b>Добро пожаловать!</b>\n\n" except Exception as e:
f"Вы новый пользователь.\n" await message.answer(
f"• Ваш ID: <code>{user_id}</code>\n" f"<b>Ошибка получения статистики</b>\n\n"
f"• Бесплатных вопросов: {settings.FREE_QUESTIONS_LIMIT}\n" f"Попробуйте позже.",
f"• Для начала работы просто задайте вопрос!\n\n" parse_mode="HTML"
f"<i>Используйте /buy для получения полного доступа</i>"
) )
await message.answer(stats_text, parse_mode="HTML")
except Exception as e:
await message.answer(
f"<b>Ошибка получения статистики</b>\n\n"
f"Попробуйте позже.",
parse_mode="HTML"
)
finally:
session.close()

View File

@ -19,47 +19,48 @@ async def handle_yookassa_webhook(request: Request):
try: try:
from tg_bot.config.settings import settings from tg_bot.config.settings import settings
from tg_bot.domain.services.user_service import UserService from tg_bot.domain.services.user_service import UserService
from tg_bot.infrastructure.database.database import SessionLocal from tg_bot.infrastructure.database.database import AsyncSessionLocal
from tg_bot.infrastructure.database.models import UserModel from tg_bot.infrastructure.database.models import UserModel
from sqlalchemy import select
from aiogram import Bot from aiogram import Bot
session = SessionLocal()
if event_type == "payment.succeeded": if event_type == "payment.succeeded":
payment = data.get("object", {}) payment = data.get("object", {})
user_id = payment.get("metadata", {}).get("user_id") user_id = payment.get("metadata", {}).get("user_id")
if user_id: if user_id:
user_service = UserService(session) async with AsyncSessionLocal() as session:
success = await user_service.activate_premium(int(user_id)) user_service = UserService(session)
if success: success = await user_service.activate_premium(int(user_id))
print(f"Premium activated for user {user_id}") if success:
print(f"Premium activated for user {user_id}")
user = session.query(UserModel).filter_by( result = await session.execute(
telegram_id=str(user_id) select(UserModel).filter_by(telegram_id=str(user_id))
).first() )
user = result.scalar_one_or_none()
if user and settings.TELEGRAM_BOT_TOKEN: if user and settings.TELEGRAM_BOT_TOKEN:
try: try:
bot = Bot(token=settings.TELEGRAM_BOT_TOKEN) bot = Bot(token=settings.TELEGRAM_BOT_TOKEN)
premium_until = user.premium_until or datetime.now() + timedelta(days=30) premium_until = user.premium_until or datetime.now() + timedelta(days=30)
notification = ( notification = (
f"<b>Оплата подтверждена!</b>\n\n" f"<b>Оплата подтверждена!</b>\n\n"
f"Premium активирован до {premium_until.strftime('%d.%m.%Y')}" f"Premium активирован до {premium_until.strftime('%d.%m.%Y')}"
) )
await bot.send_message( await bot.send_message(
chat_id=int(user_id), chat_id=int(user_id),
text=notification, text=notification,
parse_mode="HTML" parse_mode="HTML"
) )
print(f"Notification sent to user {user_id}") print(f"Notification sent to user {user_id}")
await bot.session.close() await bot.session.close()
except Exception as e: except Exception as e:
print(f"Error sending notification: {e}") print(f"Error sending notification: {e}")
else: else:
print(f"User {user_id} not found") print(f"User {user_id} not found")
session.close()
except ImportError as e: except ImportError as e:
print(f"Import error: {e}") print(f"Import error: {e}")