Files
Solo_bot/web/kassai_payment.py
T
Boris Kovalskii b32a7ac20b Delete message about payment from Kassa AI
Delete message about payment from Kassa AI after success payment, if the message is available
2025-07-24 13:22:45 +10:00

119 lines
5.0 KiB
Python

import hashlib
import json
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 config import KASSAI_SECRET_KEY, KASSAI_SHOP_ID
from logger import logger
import bot
# Хранилище обработанных платежей для предотвращения дублирования
processed_payments = set()
async def kassai_payment_webhook(request: web.Request):
"""
Обработчик вебхука от KassaAI для подтверждения оплаты
"""
try:
data = await request.post()
data_dict = dict(data)
logger.info(f"KassaAI webhook received from {request.remote}")
signature = data_dict.get("SIGN")
if not signature:
logger.error("KassaAI: Missing SIGN in request")
return web.Response(status=400, text="Signature missing")
if not verify_kassai_webhook_signature(data_dict, signature):
logger.error("KassaAI: Invalid signature")
return web.Response(status=400, text="Invalid signature")
merchant_order_id = data_dict.get("MERCHANT_ORDER_ID")
amount = data_dict.get("AMOUNT")
p_email = data_dict.get("P_EMAIL")
if not amount:
logger.error(f"KassaAI: Missing AMOUNT")
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}")
return web.Response(status=200, text="YES")
try:
if p_email and "@" in p_email:
tg_id = int(p_email.split("@")[0])
else:
logger.error(f"KassaAI: Invalid email format: {p_email}")
return web.Response(status=400, text="Invalid email format")
amount_float = float(amount)
except (ValueError, TypeError) as e:
logger.error(f"KassaAI: Invalid data format: {e}")
return web.Response(status=400, text="Invalid data format")
async with async_session_maker() as session:
await update_balance(session, tg_id, amount_float)
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)
logger.info(f"✅ KassaAI: Payment processed for user {tg_id}, amount {amount_float}")
return web.Response(status=200, text="YES")
except Exception as e:
logger.error(f"KassaAI webhook error: {e}")
return web.Response(status=500, text="Internal server error")
def verify_kassai_webhook_signature(data: dict, signature: str) -> bool:
"""
Проверка подписи вебхука KassaAI согласно документации FreeKassa
"""
try:
sign_string = (
f"{data.get('MERCHANT_ID', '')}:"
f"{data.get('AMOUNT', '')}:"
f"{KASSAI_SECRET_KEY}:"
f"{data.get('MERCHANT_ORDER_ID', '')}"
)
expected_signature = hashlib.md5(sign_string.encode('utf-8')).hexdigest()
result = signature.upper() == expected_signature.upper()
if not result:
logger.error(f"KassaAI webhook signature mismatch")
return result
except Exception as e:
logger.error(f"KassaAI signature verification error: {e}")
return False