mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-26 14:21:25 +00:00
152 lines
6.6 KiB
Python
152 lines
6.6 KiB
Python
import logging
|
||
|
||
from aiogram import Bot, types
|
||
from aiohttp import web
|
||
|
||
from app.config import settings
|
||
from app.database.crud.transaction import create_transaction, get_transaction_by_external_id
|
||
from app.database.crud.user import add_user_balance, get_user_by_id
|
||
from app.database.database import AsyncSessionLocal
|
||
from app.database.models import PaymentMethod, TransactionType
|
||
from app.external.tribute import TributeService
|
||
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# Глобальная ссылка на бота для отправки уведомлений
|
||
_bot_instance: Bot | None = None
|
||
|
||
|
||
def set_webhook_bot(bot: Bot) -> None:
|
||
"""Устанавливает экземпляр бота для отправки уведомлений об ошибках в webhook."""
|
||
global _bot_instance
|
||
_bot_instance = bot
|
||
|
||
|
||
async def tribute_webhook(request):
|
||
try:
|
||
signature = request.headers.get('trbt-signature', '')
|
||
payload = await request.text()
|
||
|
||
tribute_service = TributeService()
|
||
|
||
if not tribute_service.verify_webhook_signature(payload, signature):
|
||
logger.warning('Неверная подпись Tribute webhook')
|
||
return web.Response(status=400, text='Invalid signature')
|
||
|
||
webhook_data = await request.json()
|
||
processed_data = await tribute_service.process_webhook(webhook_data)
|
||
|
||
if not processed_data:
|
||
logger.error('Ошибка обработки Tribute webhook')
|
||
return web.Response(status=400, text='Invalid webhook data')
|
||
|
||
async with AsyncSessionLocal() as db:
|
||
try:
|
||
existing_transaction = await get_transaction_by_external_id(
|
||
db, processed_data['payment_id'], PaymentMethod.TRIBUTE
|
||
)
|
||
|
||
if existing_transaction:
|
||
logger.info(f'Платеж {processed_data["payment_id"]} уже обработан')
|
||
return web.Response(status=200, text='Already processed')
|
||
|
||
if processed_data['status'] == 'completed':
|
||
user = await get_user_by_id(db, processed_data['user_id'])
|
||
|
||
if user:
|
||
await add_user_balance(
|
||
db,
|
||
user,
|
||
processed_data['amount_kopeks'],
|
||
f'Пополнение через Tribute: {processed_data["payment_id"]}',
|
||
)
|
||
|
||
await create_transaction(
|
||
db=db,
|
||
user_id=user.id,
|
||
type=TransactionType.DEPOSIT,
|
||
amount_kopeks=processed_data['amount_kopeks'],
|
||
description='Пополнение через Tribute',
|
||
payment_method=PaymentMethod.TRIBUTE,
|
||
external_id=processed_data['payment_id'],
|
||
)
|
||
|
||
logger.info(f'✅ Обработан Tribute платеж: {processed_data["payment_id"]}')
|
||
|
||
await db.commit()
|
||
return web.Response(status=200, text='OK')
|
||
|
||
except Exception as e:
|
||
logger.error(f'Ошибка обработки Tribute webhook: {e}')
|
||
await db.rollback()
|
||
return web.Response(status=500, text='Internal error')
|
||
|
||
except Exception as e:
|
||
logger.error(f'Ошибка в Tribute webhook: {e}')
|
||
return web.Response(status=500, text='Internal error')
|
||
|
||
|
||
async def handle_successful_payment(message: types.Message):
|
||
try:
|
||
payment = message.successful_payment
|
||
|
||
payload_parts = payment.invoice_payload.split('_')
|
||
if len(payload_parts) >= 3 and payload_parts[0] == 'balance':
|
||
user_id = int(payload_parts[1])
|
||
amount_kopeks = int(payload_parts[2])
|
||
|
||
async with AsyncSessionLocal() as db:
|
||
try:
|
||
existing_transaction = await get_transaction_by_external_id(
|
||
db, payment.telegram_payment_charge_id, PaymentMethod.TELEGRAM_STARS
|
||
)
|
||
|
||
if existing_transaction:
|
||
logger.info(f'Stars платеж {payment.telegram_payment_charge_id} уже обработан')
|
||
return
|
||
|
||
user = await get_user_by_id(db, user_id)
|
||
|
||
if user:
|
||
await add_user_balance(db, user, amount_kopeks, 'Пополнение через Telegram Stars')
|
||
|
||
await create_transaction(
|
||
db=db,
|
||
user_id=user.id,
|
||
type=TransactionType.DEPOSIT,
|
||
amount_kopeks=amount_kopeks,
|
||
description='Пополнение через Telegram Stars',
|
||
payment_method=PaymentMethod.TELEGRAM_STARS,
|
||
external_id=payment.telegram_payment_charge_id,
|
||
)
|
||
|
||
await message.answer(
|
||
f'✅ Баланс успешно пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||
'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||
'Обязательно активируйте подписку отдельно!\n\n'
|
||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||
f'подписка будет приобретена автоматически после пополнения баланса.'
|
||
)
|
||
|
||
logger.info(f'✅ Обработан Stars платеж: {payment.telegram_payment_charge_id}')
|
||
|
||
await db.commit()
|
||
|
||
except Exception as e:
|
||
logger.error(f'Ошибка обработки Stars платежа: {e}')
|
||
await db.rollback()
|
||
|
||
except Exception as e:
|
||
logger.error(f'Ошибка в обработчике Stars платежа: {e}')
|
||
|
||
|
||
async def handle_pre_checkout_query(pre_checkout_query: types.PreCheckoutQuery):
|
||
try:
|
||
await pre_checkout_query.answer(ok=True)
|
||
logger.info(f'Pre-checkout query принят: {pre_checkout_query.id}')
|
||
|
||
except Exception as e:
|
||
logger.error(f'Ошибка в pre-checkout query: {e}')
|
||
await pre_checkout_query.answer(ok=False, error_message='Ошибка обработки платежа')
|