Merge pull request #1961 from BEDOLAGA-DEV/revert-1959-bedolaga/remove-unnecessary-chat-messages-after-balance-refill-s863sv

Revert "Clean up Telegram Stars payment flow"
This commit is contained in:
Egor
2025-11-21 04:02:38 +03:00
committed by GitHub
3 changed files with 56 additions and 86 deletions

View File

@@ -1,10 +1,11 @@
import logging
from aiogram import types
from aiogram.fsm.context import FSMContext
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.database.models import User
from app.keyboards.inline import get_back_keyboard
from app.keyboards.inline import get_back_keyboard, get_payment_methods_keyboard
from app.localization.texts import get_texts
from app.services.payment_service import PaymentService
from app.states import BalanceStates
@@ -21,11 +22,11 @@ async def start_stars_payment(
state: FSMContext
):
texts = get_texts(db_user.language)
if not settings.TELEGRAM_STARS_ENABLED:
await callback.answer("❌ Пополнение через Stars временно недоступно", show_alert=True)
return
# Формируем текст сообщения в зависимости от настройки
if settings.YOOKASSA_QUICK_AMOUNT_SELECTION_ENABLED and not settings.DISABLE_TOPUP_BUTTONS:
message_text = (
@@ -34,10 +35,10 @@ async def start_stars_payment(
)
else:
message_text = texts.TOP_UP_AMOUNT
# Создаем клавиатуру
keyboard = get_back_keyboard(db_user.language)
# Если включен быстрый выбор суммы и не отключены кнопки, добавляем кнопки
if settings.YOOKASSA_QUICK_AMOUNT_SELECTION_ENABLED and not settings.DISABLE_TOPUP_BUTTONS:
from .main import get_quick_amount_buttons
@@ -45,17 +46,12 @@ async def start_stars_payment(
if quick_amount_buttons:
# Вставляем кнопки быстрого выбора перед кнопкой "Назад"
keyboard.inline_keyboard = quick_amount_buttons + keyboard.inline_keyboard
await callback.message.edit_text(
message_text,
reply_markup=keyboard
)
await state.update_data(
stars_prompt_message_id=callback.message.message_id,
stars_prompt_chat_id=callback.message.chat.id,
)
await state.set_state(BalanceStates.waiting_for_amount)
await state.update_data(payment_method="stars")
await callback.answer()
@@ -69,48 +65,29 @@ async def process_stars_payment_amount(
state: FSMContext
):
texts = get_texts(db_user.language)
if not settings.TELEGRAM_STARS_ENABLED:
await message.answer("⚠️ Оплата Stars временно недоступна")
return
try:
amount_rubles = amount_kopeks / 100
stars_amount = TelegramStarsService.calculate_stars_from_rubles(amount_rubles)
stars_rate = settings.get_stars_rate()
stars_rate = settings.get_stars_rate()
payment_service = PaymentService(message.bot)
invoice_link = await payment_service.create_stars_invoice(
amount_kopeks=amount_kopeks,
description=f"Пополнение баланса на {texts.format_price(amount_kopeks)}",
payload=f"balance_{db_user.id}_{amount_kopeks}"
)
keyboard = types.InlineKeyboardMarkup(inline_keyboard=[
[types.InlineKeyboardButton(text="⭐ Оплатить", url=invoice_link)],
[types.InlineKeyboardButton(text=texts.BACK, callback_data="balance_topup")]
])
state_data = await state.get_data()
prompt_message_id = state_data.get("stars_prompt_message_id")
prompt_chat_id = state_data.get("stars_prompt_chat_id", message.chat.id)
try:
await message.delete()
except Exception as delete_error: # pragma: no cover - зависит от прав бота
logger.warning("Не удалось удалить сообщение с суммой Stars: %s", delete_error)
if prompt_message_id:
try:
await message.bot.delete_message(prompt_chat_id, prompt_message_id)
except Exception as delete_error: # pragma: no cover - диагностический лог
logger.warning(
"Не удалось удалить сообщение с запросом суммы Stars: %s",
delete_error,
)
invoice_message = await message.answer(
await message.answer(
f"⭐ <b>Оплата через Telegram Stars</b>\n\n"
f"💰 Сумма: {texts.format_price(amount_kopeks)}\n"
f"К оплате: {stars_amount} звезд\n"
@@ -119,14 +96,9 @@ async def process_stars_payment_amount(
reply_markup=keyboard,
parse_mode="HTML"
)
await state.update_data(
stars_invoice_message_id=invoice_message.message_id,
stars_invoice_chat_id=invoice_message.chat.id,
)
await state.set_state(None)
await state.clear()
except Exception as e:
logger.error(f"Ошибка создания Stars invoice: {e}")
await message.answer("⚠️ Ошибка создания платежа")
await message.answer("⚠️ Ошибка создания платежа")

View File

@@ -1,10 +1,10 @@
import logging
from decimal import Decimal, ROUND_HALF_UP
from aiogram import Dispatcher, types, F
from aiogram.fsm.context import FSMContext
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
@@ -18,9 +18,7 @@ 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}"
)
logger.info(f"📋 Pre-checkout query от {query.from_user.id}: {query.total_amount} XTR, payload: {query.invoice_payload}")
allowed_prefixes = ("balance_", "admin_stars_test_", "simple_sub_")
@@ -37,7 +35,6 @@ async def handle_pre_checkout_query(query: types.PreCheckoutQuery):
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:
@@ -80,7 +77,6 @@ async def handle_pre_checkout_query(query: types.PreCheckoutQuery):
async def handle_successful_payment(
message: types.Message,
db: AsyncSession,
state: FSMContext,
**kwargs
):
texts = get_texts(DEFAULT_LANGUAGE)
@@ -110,27 +106,6 @@ async def handle_successful_payment(
return
payment_service = PaymentService(message.bot)
state_data = await state.get_data()
prompt_message_id = state_data.get("stars_prompt_message_id")
prompt_chat_id = state_data.get("stars_prompt_chat_id", message.chat.id)
invoice_message_id = state_data.get("stars_invoice_message_id")
invoice_chat_id = state_data.get("stars_invoice_chat_id", message.chat.id)
for chat_id, message_id, label in [
(prompt_chat_id, prompt_message_id, "запрос суммы"),
(invoice_chat_id, invoice_message_id, "инвойс Stars"),
]:
if message_id:
try:
await message.bot.delete_message(chat_id, message_id)
except Exception as delete_error: # pragma: no cover - зависит от прав бота
logger.warning(
"Не удалось удалить сообщение %s после оплаты Stars: %s",
label,
delete_error,
)
success = await payment_service.process_stars_payment(
db=db,
user_id=user.id,
@@ -138,14 +113,7 @@ async def handle_successful_payment(
payload=payment.invoice_payload,
telegram_payment_charge_id=payment.telegram_payment_charge_id
)
await state.update_data(
stars_prompt_message_id=None,
stars_prompt_chat_id=None,
stars_invoice_message_id=None,
stars_invoice_chat_id=None,
)
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))
@@ -204,15 +172,15 @@ async def handle_successful_payment(
def register_stars_handlers(dp: Dispatcher):
dp.pre_checkout_query.register(
handle_pre_checkout_query,
F.currency == "XTR"
F.currency == "XTR"
)
dp.message.register(
handle_successful_payment,
F.successful_payment
)
logger.info("🌟 Зарегистрированы обработчики Telegram Stars платежей")

View File

@@ -515,6 +515,36 @@ class TelegramStarsMixin:
exc_info=True,
)
if getattr(self, "bot", None):
try:
keyboard = await self.build_topup_success_keyboard(user)
charge_id_short = (telegram_payment_charge_id or getattr(transaction, "external_id", ""))[:8]
await self.bot.send_message(
user.telegram_id,
(
"✅ <b>Пополнение успешно!</b>\n\n"
f"⭐ Звезд: {stars_amount}\n"
f"💰 Сумма: {settings.format_price(amount_kopeks)}\n"
"🦊 Способ: Telegram Stars\n"
f"🆔 Транзакция: {charge_id_short}...\n\n"
"Баланс пополнен автоматически!"
),
parse_mode="HTML",
reply_markup=keyboard,
)
logger.info(
"✅ Отправлено уведомление пользователю %s о пополнении на %s",
user.telegram_id,
settings.format_price(amount_kopeks),
)
except Exception as error: # pragma: no cover - диагностический лог
logger.error(
"Ошибка отправки уведомления о пополнении Stars: %s",
error,
)
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
try:
from aiogram import types