From 16b22101af8946bb102e60a9d48d7888ca6a97c7 Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 12:53:49 +1000 Subject: [PATCH 1/6] Back callback fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Убрано лишнее меню из касс, при возвращении, сейчас возвращает сразу на вкладку balance --- handlers/payments/kassai.py | 2 +- handlers/payments/wata.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/handlers/payments/kassai.py b/handlers/payments/kassai.py index a07180bc..d54641da 100644 --- a/handlers/payments/kassai.py +++ b/handlers/payments/kassai.py @@ -76,7 +76,7 @@ async def process_callback_pay_kassai(callback_query: types.CallbackQuery, state ) ) builder.row(InlineKeyboardButton(text="Ввести сумму", callback_data=f"kassai_custom_amount|{method_name}")) - builder.row(InlineKeyboardButton(text=BACK, callback_data="pay")) + builder.row(InlineKeyboardButton(text=BACK, callback_data="balance")) await callback_query.message.delete() new_message = await callback_query.message.answer( diff --git a/handlers/payments/wata.py b/handlers/payments/wata.py index d873d260..bfedf043 100644 --- a/handlers/payments/wata.py +++ b/handlers/payments/wata.py @@ -131,7 +131,7 @@ async def process_cassa_selection(callback_query: types.CallbackQuery, state: FS callback_data=f'wata_amount|{cassa_name}|{PAYMENT_OPTIONS[i]["callback_data"]}', ) ) - builder.row(InlineKeyboardButton(text=BACK, callback_data="pay_wata")) + builder.row(InlineKeyboardButton(text=BACK, callback_data="balance")) await callback_query.message.delete() new_message = await callback_query.message.answer( text=cassa["desc"], From 7f35ec074555e92a6519e86d3d1324171c6a536a Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:22:45 +1000 Subject: [PATCH 2/6] Delete message about payment from Kassa AI Delete message about payment from Kassa AI after success payment, if the message is available --- handlers/payments/kassai.py | 22 +++++++++++++++++----- handlers/payments/wata.py | 4 ++-- web/kassai_payment.py | 25 +++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/handlers/payments/kassai.py b/handlers/payments/kassai.py index d54641da..4ddbca81 100644 --- a/handlers/payments/kassai.py +++ b/handlers/payments/kassai.py @@ -204,21 +204,27 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext): return await state.update_data(amount=amount) - payment_url = await generate_kassai_payment_link(amount, message.chat.id, method) + payment_url = await generate_kassai_payment_link(amount, callback_query.message.chat.id, method) confirm_keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton(text=PAY_2, url=payment_url)], - [InlineKeyboardButton(text=BACK, callback_data="pay_kassai")], + [InlineKeyboardButton(text=BACK, callback_data="balance")], ] ) - await edit_or_send_message( + payment_message = await edit_or_send_message( target_message=message, text=KASSAI_PAYMENT_MESSAGE.format(amount=amount), reply_markup=confirm_keyboard, force_text=True, ) + + # Сохраняем message_id для последующего удаления + await state.update_data( + payment_message_id=payment_message.message_id if hasattr(payment_message, 'message_id') else message.message_id, + payment_chat_id=message.chat.id + ) await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation) @@ -258,16 +264,22 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F confirm_keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton(text=PAY_2, url=payment_url)], - [InlineKeyboardButton(text=BACK, callback_data="pay_kassai")], + [InlineKeyboardButton(text=BACK, callback_data="balance")], ] ) - await edit_or_send_message( + payment_message = await edit_or_send_message( target_message=callback_query.message, text=KASSAI_PAYMENT_MESSAGE.format(amount=amount), reply_markup=confirm_keyboard, force_text=True, ) + + # Сохраняем message_id для последующего удаления + await state.update_data( + payment_message_id=payment_message.message_id if hasattr(payment_message, 'message_id') else callback_query.message.message_id, + payment_chat_id=callback_query.message.chat.id + ) await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation) diff --git a/handlers/payments/wata.py b/handlers/payments/wata.py index bfedf043..e2478a81 100644 --- a/handlers/payments/wata.py +++ b/handlers/payments/wata.py @@ -194,7 +194,7 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext): confirm_keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton(text=PAY_2, url=payment_url)], - [InlineKeyboardButton(text=BACK, callback_data="pay_wata")], + [InlineKeyboardButton(text=BACK, callback_data="balance")], ] ) await edit_or_send_message( @@ -237,7 +237,7 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F confirm_keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton(text=PAY_2, url=payment_url)], - [InlineKeyboardButton(text=BACK, callback_data="pay_wata")], + [InlineKeyboardButton(text=BACK, callback_data="balance")], ] ) await edit_or_send_message( diff --git a/web/kassai_payment.py b/web/kassai_payment.py index dd6cc603..eafbc09c 100644 --- a/web/kassai_payment.py +++ b/web/kassai_payment.py @@ -6,7 +6,9 @@ from handlers.payments.utils import send_payment_success_notification from handlers.payments.kassai import verify_kassai_signature from config import KASSAI_SECRET_KEY, KASSAI_SHOP_ID from logger import logger +import bot +# Хранилище обработанных платежей для предотвращения дублирования processed_payments = set() @@ -58,6 +60,29 @@ async def kassai_payment_webhook(request: web.Request): await send_payment_success_notification(tg_id, amount_float, session) await add_payment(session, tg_id, amount_float, "kassai") + # Попытка удалить сообщение с кнопкой оплаты + try: + from aiogram.fsm.context import FSMContext + from aiogram.fsm.storage.base import StorageKey + + # Получаем данные из FSM state пользователя + storage_key = StorageKey(bot_id=bot.bot.id, chat_id=tg_id, user_id=tg_id) + state_data = await bot.dp.storage.get_data(storage_key) + + if state_data and 'payment_message_id' in state_data: + payment_message_id = state_data['payment_message_id'] + try: + await bot.bot.delete_message(chat_id=tg_id, message_id=payment_message_id) + logger.info(f"Payment message deleted for user {tg_id}") + except Exception as e: + logger.warning(f"Could not delete payment message for user {tg_id}: {e}") + + # Очищаем state после успешной оплаты + await bot.dp.storage.set_state(storage_key, None) + await bot.dp.storage.set_data(storage_key, {}) + except Exception as e: + logger.warning(f"Error handling payment message deletion: {e}") + if merchant_order_id: processed_payments.add(merchant_order_id) From d5190ea07e0c53ebb89e0720f9b7b2685e303d8b Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:24:21 +1000 Subject: [PATCH 3/6] Clear code --- handlers/payments/kassai.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/handlers/payments/kassai.py b/handlers/payments/kassai.py index 4ddbca81..833344fa 100644 --- a/handlers/payments/kassai.py +++ b/handlers/payments/kassai.py @@ -220,7 +220,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext): force_text=True, ) - # Сохраняем message_id для последующего удаления await state.update_data( payment_message_id=payment_message.message_id if hasattr(payment_message, 'message_id') else message.message_id, payment_chat_id=message.chat.id @@ -275,7 +274,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F force_text=True, ) - # Сохраняем message_id для последующего удаления await state.update_data( payment_message_id=payment_message.message_id if hasattr(payment_message, 'message_id') else callback_query.message.message_id, payment_chat_id=callback_query.message.chat.id From b39ae1a1ee0afa732e2385f34e0b997b92b3323f Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:27:28 +1000 Subject: [PATCH 4/6] Small fixes --- web/kassai_payment.py | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/web/kassai_payment.py b/web/kassai_payment.py index eafbc09c..b9805163 100644 --- a/web/kassai_payment.py +++ b/web/kassai_payment.py @@ -4,11 +4,11 @@ from aiohttp import web from database import add_payment, async_session_maker, update_balance from handlers.payments.utils import send_payment_success_notification from handlers.payments.kassai import verify_kassai_signature +from aiogram.fsm.context import FSMContext +from aiogram.fsm.storage.base import StorageKey from config import KASSAI_SECRET_KEY, KASSAI_SHOP_ID from logger import logger -import bot -# Хранилище обработанных платежей для предотвращения дублирования processed_payments = set() @@ -60,12 +60,7 @@ async def kassai_payment_webhook(request: web.Request): await send_payment_success_notification(tg_id, amount_float, session) await add_payment(session, tg_id, amount_float, "kassai") - # Попытка удалить сообщение с кнопкой оплаты try: - from aiogram.fsm.context import FSMContext - from aiogram.fsm.storage.base import StorageKey - - # Получаем данные из FSM state пользователя storage_key = StorageKey(bot_id=bot.bot.id, chat_id=tg_id, user_id=tg_id) state_data = await bot.dp.storage.get_data(storage_key) @@ -77,7 +72,6 @@ async def kassai_payment_webhook(request: web.Request): except Exception as e: logger.warning(f"Could not delete payment message for user {tg_id}: {e}") - # Очищаем state после успешной оплаты await bot.dp.storage.set_state(storage_key, None) await bot.dp.storage.set_data(storage_key, {}) except Exception as e: From c5e89170438984be3f8b34049a1f0176d33314bf Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:34:07 +1000 Subject: [PATCH 5/6] Custom amount and deletion fixes --- handlers/payments/kassai.py | 2 +- web/kassai_payment.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/handlers/payments/kassai.py b/handlers/payments/kassai.py index 833344fa..8231ad0a 100644 --- a/handlers/payments/kassai.py +++ b/handlers/payments/kassai.py @@ -204,7 +204,7 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext): return await state.update_data(amount=amount) - payment_url = await generate_kassai_payment_link(amount, callback_query.message.chat.id, method) + payment_url = await generate_kassai_payment_link(amount, message.chat.id, method) confirm_keyboard = InlineKeyboardMarkup( inline_keyboard=[ diff --git a/web/kassai_payment.py b/web/kassai_payment.py index b9805163..89cde958 100644 --- a/web/kassai_payment.py +++ b/web/kassai_payment.py @@ -1,5 +1,6 @@ import hashlib import json +import bot from aiohttp import web from database import add_payment, async_session_maker, update_balance from handlers.payments.utils import send_payment_success_notification From 97234d8835bb7ff71cc58c4490595bb8c1ae8a18 Mon Sep 17 00:00:00 2001 From: Boris Kovalskii <36034823+JustYay@users.noreply.github.com> Date: Thu, 24 Jul 2025 13:53:33 +1000 Subject: [PATCH 6/6] Security bug fix Fix duplicate webhook accept --- web/kassai_payment.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/web/kassai_payment.py b/web/kassai_payment.py index 89cde958..d21169f2 100644 --- a/web/kassai_payment.py +++ b/web/kassai_payment.py @@ -35,13 +35,14 @@ async def kassai_payment_webhook(request: web.Request): merchant_order_id = data_dict.get("MERCHANT_ORDER_ID") amount = data_dict.get("AMOUNT") p_email = data_dict.get("P_EMAIL") + intid = data_dict.get("intid") - if not amount: - logger.error(f"KassaAI: Missing AMOUNT") + if not amount or not intid: + logger.error(f"KassaAI: Missing AMOUNT or intid") return web.Response(status=400, text="Missing required fields") - if merchant_order_id and merchant_order_id in processed_payments: - logger.warning(f"KassaAI: Duplicate payment {merchant_order_id}") + if intid in processed_payments: + logger.warning(f"KassaAI: Duplicate payment intid={intid}") return web.Response(status=200, text="YES") try: @@ -78,10 +79,9 @@ async def kassai_payment_webhook(request: web.Request): except Exception as e: logger.warning(f"Error handling payment message deletion: {e}") - if merchant_order_id: - processed_payments.add(merchant_order_id) + processed_payments.add(intid) - logger.info(f"✅ KassaAI: Payment processed for user {tg_id}, amount {amount_float}") + logger.info(f"✅ KassaAI: Payment processed for user {tg_id}, amount {amount_float}, intid={intid}") return web.Response(status=200, text="YES") except Exception as e: