mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-02-25 13:51:50 +00:00
183 lines
7.2 KiB
Python
183 lines
7.2 KiB
Python
import logging
|
|
from decimal import Decimal, ROUND_HALF_UP
|
|
from aiogram import Dispatcher, types, F
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.config import settings
|
|
from app.database.models import User
|
|
from app.services.payment_service import PaymentService
|
|
from app.external.telegram_stars import TelegramStarsService
|
|
from app.database.crud.user import get_user_by_telegram_id
|
|
from app.localization.loader import DEFAULT_LANGUAGE
|
|
from app.localization.texts import get_texts
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
async def handle_pre_checkout_query(query: types.PreCheckoutQuery):
|
|
texts = get_texts(DEFAULT_LANGUAGE)
|
|
|
|
try:
|
|
logger.info(f"📋 Pre-checkout query от {query.from_user.id}: {query.total_amount} XTR, payload: {query.invoice_payload}")
|
|
|
|
allowed_prefixes = ("balance_", "admin_stars_test_")
|
|
|
|
if not query.invoice_payload or not query.invoice_payload.startswith(allowed_prefixes):
|
|
logger.warning(f"Невалидный payload: {query.invoice_payload}")
|
|
await query.answer(
|
|
ok=False,
|
|
error_message=texts.t(
|
|
"STARS_PRECHECK_INVALID_PAYLOAD",
|
|
"Ошибка валидации платежа. Попробуйте еще раз.",
|
|
),
|
|
)
|
|
return
|
|
|
|
try:
|
|
from app.database.database import get_db
|
|
async for db in get_db():
|
|
user = await get_user_by_telegram_id(db, query.from_user.id)
|
|
if not user:
|
|
logger.warning(f"Пользователь {query.from_user.id} не найден в БД")
|
|
await query.answer(
|
|
ok=False,
|
|
error_message=texts.t(
|
|
"STARS_PRECHECK_USER_NOT_FOUND",
|
|
"Пользователь не найден. Обратитесь в поддержку.",
|
|
),
|
|
)
|
|
return
|
|
texts = get_texts(user.language or DEFAULT_LANGUAGE)
|
|
break
|
|
except Exception as db_error:
|
|
logger.error(f"Ошибка подключения к БД в pre_checkout_query: {db_error}")
|
|
await query.answer(
|
|
ok=False,
|
|
error_message=texts.t(
|
|
"STARS_PRECHECK_TECHNICAL_ERROR",
|
|
"Техническая ошибка. Попробуйте позже.",
|
|
),
|
|
)
|
|
return
|
|
|
|
await query.answer(ok=True)
|
|
logger.info(f"✅ Pre-checkout одобрен для пользователя {query.from_user.id}")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Ошибка в pre_checkout_query: {e}", exc_info=True)
|
|
await query.answer(
|
|
ok=False,
|
|
error_message=texts.t(
|
|
"STARS_PRECHECK_TECHNICAL_ERROR",
|
|
"Техническая ошибка. Попробуйте позже.",
|
|
),
|
|
)
|
|
|
|
|
|
async def handle_successful_payment(
|
|
message: types.Message,
|
|
db: AsyncSession,
|
|
**kwargs
|
|
):
|
|
texts = get_texts(DEFAULT_LANGUAGE)
|
|
|
|
try:
|
|
payment = message.successful_payment
|
|
user_id = message.from_user.id
|
|
|
|
logger.info(
|
|
f"💳 Успешный Stars платеж от {user_id}: "
|
|
f"{payment.total_amount} XTR, "
|
|
f"payload: {payment.invoice_payload}, "
|
|
f"charge_id: {payment.telegram_payment_charge_id}"
|
|
)
|
|
|
|
user = await get_user_by_telegram_id(db, user_id)
|
|
texts = get_texts(user.language if user and user.language else DEFAULT_LANGUAGE)
|
|
|
|
if not user:
|
|
logger.error(f"Пользователь {user_id} не найден при обработке Stars платежа")
|
|
await message.answer(
|
|
texts.t(
|
|
"STARS_PAYMENT_USER_NOT_FOUND",
|
|
"❌ Ошибка: пользователь не найден. Обратитесь в поддержку.",
|
|
)
|
|
)
|
|
return
|
|
|
|
payment_service = PaymentService(message.bot)
|
|
success = await payment_service.process_stars_payment(
|
|
db=db,
|
|
user_id=user.id,
|
|
stars_amount=payment.total_amount,
|
|
payload=payment.invoice_payload,
|
|
telegram_payment_charge_id=payment.telegram_payment_charge_id
|
|
)
|
|
|
|
if success:
|
|
rubles_amount = TelegramStarsService.calculate_rubles_from_stars(payment.total_amount)
|
|
amount_kopeks = int((rubles_amount * Decimal(100)).to_integral_value(rounding=ROUND_HALF_UP))
|
|
amount_text = settings.format_price(amount_kopeks).replace(" ₽", "")
|
|
|
|
keyboard = await payment_service.build_topup_success_keyboard(user)
|
|
|
|
transaction_id_short = payment.telegram_payment_charge_id[:8]
|
|
|
|
await message.answer(
|
|
texts.t(
|
|
"STARS_PAYMENT_SUCCESS",
|
|
"🎉 <b>Платеж успешно обработан!</b>\n\n"
|
|
"⭐ Потрачено звезд: {stars_spent}\n"
|
|
"💰 Зачислено на баланс: {amount} ₽\n"
|
|
"🆔 ID транзакции: {transaction_id}...\n\n"
|
|
"Спасибо за пополнение! 🚀",
|
|
).format(
|
|
stars_spent=payment.total_amount,
|
|
amount=amount_text,
|
|
transaction_id=transaction_id_short,
|
|
),
|
|
parse_mode="HTML",
|
|
reply_markup=keyboard,
|
|
)
|
|
|
|
logger.info(
|
|
"✅ Stars платеж успешно обработан: пользователь %s, %s звезд → %s",
|
|
user.id,
|
|
payment.total_amount,
|
|
settings.format_price(amount_kopeks),
|
|
)
|
|
else:
|
|
logger.error(f"Ошибка обработки Stars платежа для пользователя {user.id}")
|
|
await message.answer(
|
|
texts.t(
|
|
"STARS_PAYMENT_ENROLLMENT_ERROR",
|
|
"❌ Произошла ошибка при зачислении средств. "
|
|
"Обратитесь в поддержку, платеж будет проверен вручную.",
|
|
)
|
|
)
|
|
|
|
except Exception as e:
|
|
logger.error(f"Ошибка в successful_payment: {e}", exc_info=True)
|
|
await message.answer(
|
|
texts.t(
|
|
"STARS_PAYMENT_PROCESSING_ERROR",
|
|
"❌ Техническая ошибка при обработке платежа. "
|
|
"Обратитесь в поддержку для решения проблемы.",
|
|
)
|
|
)
|
|
|
|
|
|
def register_stars_handlers(dp: Dispatcher):
|
|
|
|
dp.pre_checkout_query.register(
|
|
handle_pre_checkout_query,
|
|
F.currency == "XTR"
|
|
)
|
|
|
|
dp.message.register(
|
|
handle_successful_payment,
|
|
F.successful_payment
|
|
)
|
|
|
|
logger.info("🌟 Зарегистрированы обработчики Telegram Stars платежей")
|