fix: correct cart notification after balance top-up
- Remove misleading "Важно" and "При наличии корзины" warnings from all payment success notifications - Fix cart total bug: show actual cart price from Redis instead of top-up amount, and suppress "insufficient funds" when balance is enough - Extract shared send_cart_notification_after_topup() in common.py to replace duplicated code across all 10 payment providers
This commit is contained in:
@@ -515,15 +515,17 @@ async def handle_successful_topup_with_cart(user_id: int, amount_kopeks: int, bo
|
||||
]
|
||||
)
|
||||
|
||||
if 0 < total_price <= user.balance_kopeks:
|
||||
balance_hint = 'Средств на балансе достаточно для оформления.'
|
||||
else:
|
||||
missing = max(total_price - user.balance_kopeks, 0)
|
||||
balance_hint = f'Не хватает: {texts.format_price(missing)}'
|
||||
|
||||
success_text = (
|
||||
f'✅ Баланс пополнен на {texts.format_price(amount_kopeks)}!\n\n'
|
||||
f'💰 Текущий баланс: {texts.format_price(user.balance_kopeks)}\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n'
|
||||
f'🛒 У вас есть сохраненная корзина подписки\n'
|
||||
f'Стоимость: {texts.format_price(total_price)}\n\n'
|
||||
f'🛒 У вас есть сохранённая корзина на {texts.format_price(total_price)}\n'
|
||||
f'{balance_hint}\n\n'
|
||||
f'Хотите продолжить оформление?'
|
||||
)
|
||||
|
||||
|
||||
@@ -453,10 +453,6 @@ async def handle_successful_payment(message: types.Message, db: AsyncSession, st
|
||||
'⭐ Потрачено звезд: {stars_spent}\n'
|
||||
'💰 Зачислено на баланс: {amount} ₽\n'
|
||||
'🆔 ID транзакции: {transaction_id}...\n\n'
|
||||
'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
'Обязательно активируйте подписку отдельно!\n\n'
|
||||
'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
'подписка будет приобретена автоматически после пополнения баланса.\n\n'
|
||||
'Спасибо за пополнение! 🚀',
|
||||
).format(
|
||||
stars_spent=payment.total_amount,
|
||||
|
||||
@@ -124,10 +124,7 @@ async def handle_successful_payment(message: types.Message):
|
||||
|
||||
await message.answer(
|
||||
f'✅ Баланс успешно пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.'
|
||||
'Средства зачислены на ваш баланс!'
|
||||
)
|
||||
|
||||
logger.info(
|
||||
|
||||
@@ -1368,7 +1368,7 @@
|
||||
"SKIP_BUTTON": "Skip ➡️",
|
||||
"STARS_PAYMENT_ENROLLMENT_ERROR": "❌ Failed to credit funds. Please contact support; the payment will be verified manually.",
|
||||
"STARS_PAYMENT_PROCESSING_ERROR": "❌ Technical error processing the payment. Please contact support for assistance.",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Payment processed successfully!</b>\n\n⭐ Stars spent: {stars_spent}\n💰 Added to balance: {amount} ₽\n🆔 Transaction ID: {transaction_id}...\n\n⚠️ <b>Important:</b> Balance top-up does not automatically activate your subscription. Please activate your subscription separately!\n\n🔄 If you have a saved subscription cart and auto-purchase is enabled, your subscription will be automatically purchased after balance top-up.\n\nThank you for topping up! 🚀",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Payment processed successfully!</b>\n\n⭐ Stars spent: {stars_spent}\n💰 Added to balance: {amount} ₽\n🆔 Transaction ID: {transaction_id}...\n\nThank you for topping up! 🚀",
|
||||
"STARS_PAYMENT_USER_NOT_FOUND": "❌ Error: user not found. Please contact support.",
|
||||
"STARS_PRECHECK_INVALID_PAYLOAD": "Payment validation error. Please try again.",
|
||||
"STARS_PRECHECK_TECHNICAL_ERROR": "Technical error. Please try again later.",
|
||||
|
||||
@@ -1389,7 +1389,7 @@
|
||||
"SKIP_BUTTON": "⏭️ Пропустить",
|
||||
"STARS_PAYMENT_ENROLLMENT_ERROR": "❌ Произошла ошибка при зачислении средств. Обратитесь в поддержку, платеж будет проверен вручную.",
|
||||
"STARS_PAYMENT_PROCESSING_ERROR": "❌ Техническая ошибка при обработке платежа. Обратитесь в поддержку для решения проблемы.",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Платеж успешно обработан!</b>\n\n⭐ Потрачено звезд: {stars_spent}\n💰 Зачислено на баланс: {amount} ₽\n\n🆔 ID транзакции: {transaction_id}...\n\n⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. Обязательно активируйте подписку отдельно!\n\n🔄 При наличии сохранённой корзины подписки и включенной автопокупке, подписка будет приобретена автоматически после пополнения баланса.\n\nСпасибо за пополнение! 🚀",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Платеж успешно обработан!</b>\n\n⭐ Потрачено звезд: {stars_spent}\n💰 Зачислено на баланс: {amount} ₽\n🆔 ID транзакции: {transaction_id}...\n\nСпасибо за пополнение! 🚀",
|
||||
"STARS_PAYMENT_USER_NOT_FOUND": "❌ Ошибка: пользователь не найден. Обратитесь в поддержку.",
|
||||
"STARS_PRECHECK_INVALID_PAYLOAD": "Ошибка валидации платежа. Попробуйте еще раз.",
|
||||
"STARS_PRECHECK_TECHNICAL_ERROR": "Техническая ошибка. Попробуйте позже.",
|
||||
|
||||
@@ -1299,7 +1299,7 @@
|
||||
"SKIP_BUTTON": "⏭️ Пропустити",
|
||||
"STARS_PAYMENT_ENROLLMENT_ERROR": "❌ Сталася помилка при зарахуванні коштів. Зверніться до підтримки, платіж буде перевірено вручну.",
|
||||
"STARS_PAYMENT_PROCESSING_ERROR": "❌ Технічна помилка при обробці платежу. Зверніться до підтримки для вирішення проблеми.",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Платіж успішно оброблено!</b>\n\n⭐ Витрачено зірок: {stars_spent}\n💰 Зараховано на баланс: {amount} ₽\n\n🆔 ID транзакції: {transaction_id}...\n\n⚠️ <b>Важливо:</b> Поповнення балансу не активує підписку автоматично. Обов'язково активуйте підписку окремо!\n\n🔄 За наявності збереженого кошика підписки та увімкненої автопокупки, підписка буде придбана автоматично після поповнення балансу.\n\nДякуємо за поповнення! 🚀",
|
||||
"STARS_PAYMENT_SUCCESS": "🎉 <b>Платіж успішно оброблено!</b>\n\n⭐ Витрачено зірок: {stars_spent}\n💰 Зараховано на баланс: {amount} ₽\n🆔 ID транзакції: {transaction_id}...\n\nДякуємо за поповнення! 🚀",
|
||||
"STARS_PAYMENT_USER_NOT_FOUND": "❌ Помилка: користувача не знайдено. Зверніться до підтримки.",
|
||||
"STARS_PRECHECK_INVALID_PAYLOAD": "Помилка валідації платежу. Спробуйте ще раз.",
|
||||
"STARS_PRECHECK_TECHNICAL_ERROR": "Технічна помилка. Спробуйте пізніше.",
|
||||
|
||||
@@ -1297,7 +1297,7 @@
|
||||
"SKIP_BUTTON":"⏭️跳过",
|
||||
"STARS_PAYMENT_ENROLLMENT_ERROR":"❌资金存入时发生错误。请联系支持,付款将手动检查。",
|
||||
"STARS_PAYMENT_PROCESSING_ERROR":"❌处理付款时发生技术错误。请联系支持解决问题。",
|
||||
"STARS_PAYMENT_SUCCESS":"🎉<b>付款已成功处理!</b>\n\n⭐已花费Stars:{stars_spent}\n💰已存入余额:{amount}₽\n\n🆔交易ID:{transaction_id}...\n\n⚠️<b>重要提示:</b>充值余额不会自动激活订阅。请务必单独激活订阅!\n\n🔄如果有已保存的订阅购物车并启用了自动购买,充值余额后将自动购买订阅。\n\n感谢您的充值!🚀",
|
||||
"STARS_PAYMENT_SUCCESS":"🎉<b>付款已成功处理!</b>\n\n⭐已花费Stars:{stars_spent}\n💰已存入余额:{amount}₽\n🆔交易ID:{transaction_id}...\n\n感谢您的充值!🚀",
|
||||
"STARS_PAYMENT_USER_NOT_FOUND":"❌错误:未找到用户。请联系支持。",
|
||||
"STARS_PRECHECK_INVALID_PAYLOAD":"付款验证失败。请重试。",
|
||||
"STARS_PRECHECK_TECHNICAL_ERROR":"技术错误。请稍后再试。",
|
||||
@@ -1632,7 +1632,7 @@
|
||||
"SKIP_BUTTON":"⏭️跳过",
|
||||
"STARS_PAYMENT_ENROLLMENT_ERROR":"❌资金存入时发生错误。请联系支持,付款将手动检查。",
|
||||
"STARS_PAYMENT_PROCESSING_ERROR":"❌处理付款时发生技术错误。请联系支持解决问题。",
|
||||
"STARS_PAYMENT_SUCCESS":"🎉<b>付款已成功处理!</b>\n\n⭐已花费Stars:{stars_spent}\n💰已存入余额:{amount}₽\n\n🆔交易ID:{transaction_id}...\n\n⚠️<b>重要提示:</b>充值余额不会自动激活订阅。请务必单独激活订阅!\n\n🔄如果有已保存的订阅购物车并启用了自动购买,充值余额后将自动购买订阅。\n\n感谢您的充值!🚀",
|
||||
"STARS_PAYMENT_SUCCESS":"🎉<b>付款已成功处理!</b>\n\n⭐已花费Stars:{stars_spent}\n💰已存入余额:{amount}₽\n🆔交易ID:{transaction_id}...\n\n感谢您的充值!🚀",
|
||||
"STARS_PAYMENT_USER_NOT_FOUND":"❌错误:未找到用户。请联系支持。",
|
||||
"STARS_PRECHECK_INVALID_PAYLOAD":"付款验证失败。请重试。",
|
||||
"STARS_PRECHECK_TECHNICAL_ERROR":"技术错误。请稍后再试。",
|
||||
|
||||
@@ -11,9 +11,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.cloudpayments_service import CloudPaymentsAPIError
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -258,9 +255,11 @@ class CloudPaymentsPaymentMixin:
|
||||
except Exception as error:
|
||||
logger.exception('Ошибка отправки уведомления CloudPayments', error=error)
|
||||
|
||||
# Auto-purchase if enabled
|
||||
# Автопокупка из сохранённой корзины и уведомление о корзине
|
||||
try:
|
||||
await auto_purchase_saved_cart_after_topup(db, user, bot=getattr(self, 'bot', None))
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
await send_cart_notification_after_topup(user, amount_kopeks, db, getattr(self, 'bot', None))
|
||||
except Exception as error:
|
||||
logger.exception('Ошибка автопокупки после CloudPayments', error=error)
|
||||
|
||||
|
||||
@@ -197,11 +197,7 @@ class PaymentCommonMixin:
|
||||
'✅ <b>Платеж успешно завершен!</b>\n\n'
|
||||
f'💰 Сумма: {settings.format_price(amount_kopeks)}\n'
|
||||
f'💳 Способ: {payment_method}\n\n'
|
||||
'Средства зачислены на ваш баланс!\n\n'
|
||||
'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.'
|
||||
'Средства зачислены на ваш баланс!'
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
@@ -295,3 +291,102 @@ class PaymentCommonMixin:
|
||||
except Exception as error:
|
||||
logger.error('Ошибка обработки платежа', payment_id=payment_id, error=error)
|
||||
return False
|
||||
|
||||
|
||||
async def send_cart_notification_after_topup(
|
||||
user: Any,
|
||||
amount_kopeks: int,
|
||||
db: AsyncSession,
|
||||
bot: Any | None,
|
||||
) -> bool:
|
||||
"""Handle saved cart after balance top-up: try auto-purchase, then send notification.
|
||||
|
||||
Returns True if a cart notification was sent.
|
||||
"""
|
||||
from aiogram import types
|
||||
|
||||
from app.database.crud.user import get_user_by_id
|
||||
from app.services.subscription_auto_purchase_service import auto_purchase_saved_cart_after_topup
|
||||
|
||||
cart_data = await user_cart_service.get_user_cart(user.id)
|
||||
if not cart_data:
|
||||
return False
|
||||
|
||||
cart_total = cart_data.get('total_price', 0)
|
||||
if not cart_total:
|
||||
return False
|
||||
|
||||
# Try auto-purchase first
|
||||
auto_purchase_success = False
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(db, user, bot=bot)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
return False
|
||||
|
||||
if not bot or not getattr(user, 'telegram_id', None):
|
||||
return False
|
||||
|
||||
# Refresh balance from DB to account for any changes during auto-purchase attempt
|
||||
refreshed_user = await get_user_by_id(db, user.id)
|
||||
balance = getattr(refreshed_user or user, 'balance_kopeks', 0)
|
||||
|
||||
texts = get_texts(getattr(user, 'language', 'ru'))
|
||||
|
||||
# Build message based on whether balance is sufficient
|
||||
if balance >= cart_total:
|
||||
message_text = (
|
||||
f'✅ Баланс пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
f'💰 Текущий баланс: {settings.format_price(balance)}\n\n'
|
||||
f'🛒 У вас есть сохранённая корзина на {settings.format_price(cart_total)}\n'
|
||||
f'Средств на балансе достаточно для оформления.'
|
||||
)
|
||||
else:
|
||||
missing = cart_total - balance
|
||||
message_text = (
|
||||
f'✅ Баланс пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
f'💰 Текущий баланс: {settings.format_price(balance)}\n\n'
|
||||
f'🛒 У вас есть сохранённая корзина на {settings.format_price(cart_total)}\n'
|
||||
f'Не хватает: {settings.format_price(missing)}'
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT,
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[types.InlineKeyboardButton(text='💰 Мой баланс', callback_data='menu_balance')],
|
||||
[types.InlineKeyboardButton(text='🏠 Главное меню', callback_data='back_to_menu')],
|
||||
]
|
||||
)
|
||||
|
||||
sent = False
|
||||
try:
|
||||
await bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=message_text,
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML',
|
||||
)
|
||||
sent = True
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю', user_id=user.id
|
||||
)
|
||||
except Exception as send_error:
|
||||
logger.error(
|
||||
'Ошибка отправки уведомления о корзине пользователю',
|
||||
user_id=user.id,
|
||||
error=send_error,
|
||||
)
|
||||
|
||||
return sent
|
||||
|
||||
@@ -13,9 +13,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.database import AsyncSessionLocal
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.services.subscription_renewal_service import (
|
||||
RenewalPaymentDescriptor,
|
||||
SubscriptionRenewalChargeError,
|
||||
@@ -293,7 +290,6 @@ class CryptoBotPaymentMixin:
|
||||
|
||||
admin_notification: _AdminNotificationContext | None = None
|
||||
user_notification: _UserNotificationPayload | None = None
|
||||
saved_cart_notification: _SavedCartNotificationPayload | None = None
|
||||
|
||||
bot_instance = getattr(self, 'bot', None)
|
||||
if bot_instance:
|
||||
@@ -326,64 +322,17 @@ class CryptoBotPaymentMixin:
|
||||
except Exception as error:
|
||||
logger.error('Ошибка подготовки уведомления о пополнении CryptoBot', error=error)
|
||||
|
||||
if admin_notification:
|
||||
await self._deliver_admin_topup_notification(admin_notification)
|
||||
|
||||
if user_notification and bot_instance:
|
||||
await self._deliver_user_topup_notification(user_notification)
|
||||
|
||||
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=bot_instance,
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and bot_instance:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.BALANCE_TOPUP_CART_REMINDER_DETAILED.format(
|
||||
total_amount=settings.format_price(amount_kopeks)
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT, callback_data='return_to_saved_cart'
|
||||
)
|
||||
],
|
||||
[types.InlineKeyboardButton(text='💰 Мой баланс', callback_data='menu_balance')],
|
||||
[types.InlineKeyboardButton(text='🏠 Главное меню', callback_data='back_to_menu')],
|
||||
]
|
||||
)
|
||||
|
||||
saved_cart_notification = _SavedCartNotificationPayload(
|
||||
telegram_id=user.telegram_id,
|
||||
text=(
|
||||
f'✅ Баланс пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n{cart_message}'
|
||||
),
|
||||
reply_markup=keyboard,
|
||||
user_id=user.id,
|
||||
)
|
||||
await send_cart_notification_after_topup(user, amount_kopeks, db, bot_instance)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя',
|
||||
@@ -392,15 +341,6 @@ class CryptoBotPaymentMixin:
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if admin_notification:
|
||||
await self._deliver_admin_topup_notification(admin_notification)
|
||||
|
||||
if user_notification and bot_instance:
|
||||
await self._deliver_user_topup_notification(user_notification)
|
||||
|
||||
if saved_cart_notification and bot_instance:
|
||||
await self._deliver_saved_cart_reminder(saved_cart_notification)
|
||||
|
||||
return True
|
||||
|
||||
except Exception as error:
|
||||
|
||||
@@ -13,9 +13,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.freekassa_service import freekassa_service
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -379,67 +376,13 @@ class FreekassaPaymentMixin:
|
||||
except Exception as error:
|
||||
logger.error('Ошибка отправки уведомления пользователю Freekassa', error=error)
|
||||
|
||||
# Автопокупка подписки
|
||||
# Автопокупка подписки и уведомление о корзине
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER',
|
||||
'У вас есть незавершенное оформление подписки. Вернуться?',
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.t(
|
||||
'BALANCE_TOPUP_CART_BUTTON',
|
||||
'🛒 Продолжить оформление',
|
||||
),
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=(f'✅ Баланс пополнен на {settings.format_price(payment.amount_kopeks)}!\n\n{cart_message}'),
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
await send_cart_notification_after_topup(
|
||||
user, payment.amount_kopeks, db, getattr(self, 'bot', None)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя', user_id=user.id, error=error, exc_info=True
|
||||
|
||||
@@ -12,9 +12,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -416,30 +413,13 @@ class HeleketPaymentMixin:
|
||||
else:
|
||||
logger.info('Пропуск Telegram-уведомления Heleket для email-пользователя', user_id=user.id)
|
||||
|
||||
# Автопокупка из сохранённой корзины и умная автоактивация
|
||||
# Автопокупка из сохранённой корзины и уведомление о корзине
|
||||
try:
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
await send_cart_notification_after_topup(
|
||||
user, updated_payment.amount_kopeks, db, getattr(self, 'bot', None)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с автоактивацией для пользователя', user_id=user.id, error=error, exc_info=True
|
||||
|
||||
@@ -13,9 +13,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.kassa_ai_service import kassa_ai_service
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -351,67 +348,13 @@ class KassaAiPaymentMixin:
|
||||
except Exception as error:
|
||||
logger.error('Ошибка отправки уведомления пользователю KassaAI', error=error)
|
||||
|
||||
# Автопокупка подписки
|
||||
# Автопокупка подписки и уведомление о корзине
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER',
|
||||
'У вас есть незавершенное оформление подписки. Вернуться?',
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.t(
|
||||
'BALANCE_TOPUP_CART_BUTTON',
|
||||
'🛒 Продолжить оформление',
|
||||
),
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=(f'✅ Баланс пополнен на {settings.format_price(payment.amount_kopeks)}!\n\n{cart_message}'),
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
await send_cart_notification_after_topup(
|
||||
user, payment.amount_kopeks, db, getattr(self, 'bot', None)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя', user_id=user.id, error=error, exc_info=True
|
||||
|
||||
@@ -10,9 +10,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -346,68 +343,11 @@ class MulenPayPaymentMixin:
|
||||
|
||||
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
# Если у пользователя есть сохраненная корзина,
|
||||
# отправляем ему уведомление с кнопкой вернуться к оформлению
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER_DETAILED',
|
||||
'🛒 У вас есть неоформленный заказ.\n\n'
|
||||
'Вы можете продолжить оформление с теми же параметрами.',
|
||||
).format(total_amount=settings.format_price(payment.amount_kopeks))
|
||||
|
||||
# Создаем клавиатуру с кнопками
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT, callback_data='return_to_saved_cart'
|
||||
)
|
||||
],
|
||||
[types.InlineKeyboardButton(text='💰 Мой баланс', callback_data='menu_balance')],
|
||||
[types.InlineKeyboardButton(text='🏠 Главное меню', callback_data='back_to_menu')],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=f'✅ Баланс пополнен на {settings.format_price(payment.amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n{cart_message}',
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю',
|
||||
user_id=user.id,
|
||||
)
|
||||
await send_cart_notification_after_topup(
|
||||
user, payment.amount_kopeks, db, getattr(self, 'bot', None)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя',
|
||||
|
||||
@@ -12,9 +12,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.pal24_service import Pal24APIError
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -443,76 +440,9 @@ class Pal24PaymentMixin:
|
||||
logger.error('Ошибка отправки уведомления пользователю Pal24', error=error)
|
||||
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER',
|
||||
'У вас есть незавершенное оформление подписки. Вернуться?',
|
||||
)
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.t(
|
||||
'BALANCE_TOPUP_CART_BUTTON',
|
||||
'🛒 Продолжить оформление',
|
||||
),
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=(
|
||||
'✅ Баланс пополнен на '
|
||||
f'{settings.format_price(payment.amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n{cart_message}'
|
||||
),
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю', user_id=user.id
|
||||
)
|
||||
else:
|
||||
logger.info('У пользователя нет сохраненной корзины или автопокупка выполнена', user_id=user.id)
|
||||
await send_cart_notification_after_topup(user, payment.amount_kopeks, db, getattr(self, 'bot', None))
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя', user_id=user.id, error=error, exc_info=True
|
||||
|
||||
@@ -12,9 +12,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.platega_service import PlategaService
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -440,74 +437,9 @@ class PlategaPaymentMixin:
|
||||
logger.error('Ошибка отправки уведомления пользователю Platega', error=error)
|
||||
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER_DETAILED',
|
||||
'🛒 У вас есть неоформленный заказ.\n\nВы можете продолжить оформление с теми же параметрами.',
|
||||
).format(total_amount=settings.format_price(payment.amount_kopeks))
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT,
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='💰 Мой баланс',
|
||||
callback_data='menu_balance',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=(
|
||||
f'✅ Баланс пополнен на {settings.format_price(payment.amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n'
|
||||
f'{cart_message}'
|
||||
),
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
await send_cart_notification_after_topup(user, payment.amount_kopeks, db, getattr(self, 'bot', None))
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя',
|
||||
|
||||
@@ -18,9 +18,6 @@ from app.database.crud.transaction import create_transaction
|
||||
from app.database.crud.user import get_user_by_id
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.external.telegram_stars import TelegramStarsService
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -465,73 +462,9 @@ class TelegramStarsMixin:
|
||||
|
||||
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.localization.texts import get_texts
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error: # pragma: no cover - диагностический лог
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER_DETAILED',
|
||||
'🛒 У вас есть неоформленный заказ.\n\nВы можете продолжить оформление с теми же параметрами.',
|
||||
).format(total_amount=settings.format_price(amount_kopeks))
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT,
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='💰 Мой баланс',
|
||||
callback_data='menu_balance',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=f'✅ Баланс пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n{cart_message}',
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю', user_id=user.id
|
||||
)
|
||||
await send_cart_notification_after_topup(user, amount_kopeks, db, getattr(self, 'bot', None))
|
||||
except Exception as error: # pragma: no cover - диагностический лог
|
||||
logger.error(
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя', user_id=user.id, error=error, exc_info=True
|
||||
|
||||
@@ -11,9 +11,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.services.wata_service import WataAPIError, WataService
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
@@ -517,10 +514,6 @@ class WataPaymentMixin:
|
||||
f'💰 Сумма: {settings.format_price(payment.amount_kopeks)}\n'
|
||||
'🦊 Способ: WATA\n'
|
||||
f'🆔 Транзакция: {transaction.id}\n\n'
|
||||
'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
'Обязательно активируйте подписку отдельно!\n\n'
|
||||
'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
'подписка будет приобретена автоматически после пополнения баланса.\n\n'
|
||||
'Баланс пополнен автоматически!'
|
||||
),
|
||||
parse_mode='HTML',
|
||||
@@ -530,67 +523,9 @@ class WataPaymentMixin:
|
||||
logger.error('Ошибка отправки уведомления пользователю WATA', error=error)
|
||||
|
||||
try:
|
||||
from aiogram import types
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.t(
|
||||
'BALANCE_TOPUP_CART_REMINDER_DETAILED',
|
||||
'🛒 У вас есть неоформленный заказ.\n\nВы можете продолжить оформление с теми же параметрами.',
|
||||
).format(total_amount=settings.format_price(payment.amount_kopeks))
|
||||
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT,
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='💰 Мой баланс',
|
||||
callback_data='menu_balance',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
user.telegram_id,
|
||||
cart_message,
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
await send_cart_notification_after_topup(user, payment.amount_kopeks, db, getattr(self, 'bot', None))
|
||||
except Exception as error:
|
||||
logger.debug('Не удалось отправить напоминание о корзине после WATA', error=error)
|
||||
|
||||
|
||||
@@ -15,9 +15,6 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.config import settings
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.payment_logger import payment_logger as logger
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
@@ -823,94 +820,15 @@ class YooKassaPaymentMixin:
|
||||
|
||||
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
|
||||
# ВАЖНО: этот код должен выполняться даже при ошибках в уведомлениях
|
||||
logger.info('Проверяем наличие сохраненной корзины для пользователя', user_id=user.id)
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
|
||||
try:
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
logger.info(
|
||||
'Результат проверки корзины для пользователя',
|
||||
user_id=user.id,
|
||||
has_saved_cart=has_saved_cart,
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
await send_cart_notification_after_topup(
|
||||
user, payment.amount_kopeks, db, getattr(self, 'bot', None)
|
||||
)
|
||||
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
db,
|
||||
user,
|
||||
bot=getattr(self, 'bot', None),
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
if has_saved_cart and getattr(self, 'bot', None) and user.telegram_id:
|
||||
# Если у пользователя есть сохраненная корзина,
|
||||
# отправляем ему уведомление с кнопкой вернуться к оформлению
|
||||
from aiogram import types
|
||||
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.BALANCE_TOPUP_CART_REMINDER_DETAILED.format(
|
||||
total_amount=settings.format_price(payment.amount_kopeks)
|
||||
)
|
||||
|
||||
# Создаем клавиатуру с кнопками
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT,
|
||||
callback_data='return_to_saved_cart',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='💰 Мой баланс',
|
||||
callback_data='menu_balance',
|
||||
)
|
||||
],
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text='🏠 Главное меню',
|
||||
callback_data='back_to_menu',
|
||||
)
|
||||
],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user.telegram_id,
|
||||
text=f'✅ Баланс пополнен на {settings.format_price(payment.amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n{cart_message}',
|
||||
reply_markup=keyboard,
|
||||
parse_mode='HTML',
|
||||
)
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю',
|
||||
user_id=user.id,
|
||||
)
|
||||
else:
|
||||
logger.info(
|
||||
'У пользователя нет сохраненной корзины, бот недоступен или покупка уже выполнена',
|
||||
user_id=user.id,
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
'Критическая ошибка при работе с сохраненной корзиной для пользователя',
|
||||
'Ошибка при работе с сохраненной корзиной для пользователя',
|
||||
user_id=user.id,
|
||||
error=e,
|
||||
exc_info=True,
|
||||
@@ -961,10 +879,6 @@ class YooKassaPaymentMixin:
|
||||
if getattr(self, 'bot', None) and user.telegram_id:
|
||||
from aiogram import types
|
||||
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
|
||||
success_message = (
|
||||
f'✅ <b>Подписка успешно активирована!</b>\n\n'
|
||||
f'📅 Период: {subscription_period} дней\n'
|
||||
|
||||
@@ -13,9 +13,6 @@ from app.database.database import get_db
|
||||
from app.database.models import PaymentMethod, TransactionType
|
||||
from app.external.tribute import TributeService as TributeAPI
|
||||
from app.services.payment_service import PaymentService
|
||||
from app.services.subscription_auto_purchase_service import (
|
||||
auto_purchase_saved_cart_after_topup,
|
||||
)
|
||||
from app.utils.user_utils import format_referrer_info
|
||||
|
||||
|
||||
@@ -289,74 +286,15 @@ class TributeService:
|
||||
f'💰 Сумма: {int(amount_rubles)} ₽\n'
|
||||
f'💳 Способ оплаты: Tribute\n'
|
||||
f'🎉 Средства зачислены на баланс!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n'
|
||||
f'🔄 При наличии сохранённой корзины подписки и включенной автопокупке, '
|
||||
f'подписка будет приобретена автоматически после пополнения баланса.\n\n'
|
||||
f'Спасибо за оплату! 🙏'
|
||||
)
|
||||
|
||||
await self.bot.send_message(user_id, text, reply_markup=keyboard, parse_mode='Markdown')
|
||||
|
||||
# Проверяем наличие сохраненной корзины для возврата к оформлению подписки
|
||||
from app.services.user_cart_service import user_cart_service
|
||||
from app.services.payment.common import send_cart_notification_after_topup
|
||||
|
||||
has_saved_cart = await user_cart_service.has_user_cart(user.id)
|
||||
auto_purchase_success = False
|
||||
if has_saved_cart:
|
||||
try:
|
||||
auto_purchase_success = await auto_purchase_saved_cart_after_topup(
|
||||
session,
|
||||
user,
|
||||
bot=self.bot,
|
||||
)
|
||||
except Exception as auto_error:
|
||||
logger.error(
|
||||
'Ошибка автоматической покупки подписки для пользователя',
|
||||
user_id=user.id,
|
||||
auto_error=auto_error,
|
||||
exc_info=True,
|
||||
)
|
||||
|
||||
if auto_purchase_success:
|
||||
has_saved_cart = False
|
||||
|
||||
# Отправляем уведомление только если есть сохранённая корзина и telegram_id
|
||||
if has_saved_cart and self.bot and user_id:
|
||||
# Если у пользователя есть сохраненная корзина,
|
||||
# отправляем ему уведомление с кнопкой вернуться к оформлению
|
||||
from aiogram import types
|
||||
|
||||
from app.localization.texts import get_texts
|
||||
|
||||
texts = get_texts(user.language)
|
||||
cart_message = texts.BALANCE_TOPUP_CART_REMINDER_DETAILED.format(
|
||||
total_amount=settings.format_price(amount_kopeks)
|
||||
)
|
||||
|
||||
# Создаем клавиатуру с кнопками
|
||||
keyboard = types.InlineKeyboardMarkup(
|
||||
inline_keyboard=[
|
||||
[
|
||||
types.InlineKeyboardButton(
|
||||
text=texts.RETURN_TO_SUBSCRIPTION_CHECKOUT, callback_data='subscription_resume_checkout'
|
||||
)
|
||||
],
|
||||
[types.InlineKeyboardButton(text='💰 Мой баланс', callback_data='menu_balance')],
|
||||
[types.InlineKeyboardButton(text='🏠 Главное меню', callback_data='back_to_menu')],
|
||||
]
|
||||
)
|
||||
|
||||
await self.bot.send_message(
|
||||
chat_id=user_id,
|
||||
text=f'✅ Баланс пополнен на {settings.format_price(amount_kopeks)}!\n\n'
|
||||
f'⚠️ <b>Важно:</b> Пополнение баланса не активирует подписку автоматически. '
|
||||
f'Обязательно активируйте подписку отдельно!\n\n{cart_message}',
|
||||
reply_markup=keyboard,
|
||||
)
|
||||
logger.info(
|
||||
'Отправлено уведомление с кнопкой возврата к оформлению подписки пользователю', user_id=user_id
|
||||
)
|
||||
await send_cart_notification_after_topup(user, amount_kopeks, session, self.bot)
|
||||
|
||||
except Exception as e:
|
||||
logger.error('Ошибка отправки уведомления об успешном платеже', error=e)
|
||||
|
||||
Reference in New Issue
Block a user