Files
Solo_bot/web/heleket_payment.py
T
2025-07-29 19:45:13 +03:00

127 lines
4.8 KiB
Python

import base64
import hashlib
import json
from aiohttp import web
from config import HELEKET_API_KEY, HELEKET_CURRENCY_RATE
from database import add_payment, async_session_maker, update_balance
from handlers.payments.utils import send_payment_success_notification
from logger import logger
processed_payments = set()
async def heleket_payment_webhook(request: web.Request):
"""
Обработчик вебхука от Heleket для подтверждения оплаты
"""
try:
data = await request.json()
logger.info(f"Heleket webhook received from {request.remote}")
logger.info(f"Heleket webhook data: {data}")
signature = data.get("sign", "")
if not verify_heleket_webhook_signature(data, signature):
logger.error("Heleket: Invalid signature")
return web.Response(status=400, text="Invalid signature")
uuid = data.get("uuid")
order_id = data.get("order_id")
payment_status = data.get("status")
amount = data.get("amount")
payment_amount = data.get("payment_amount")
additional_data = data.get("additional_data", "")
logger.info(
f"Heleket payment: uuid={uuid}, order_id={order_id}, status={payment_status}, amount={amount}, payment_amount={payment_amount}"
)
if payment_status != "paid":
logger.info(f"Heleket: Payment not completed, status={payment_status}")
return web.Response(status=200, text="OK")
if not amount or not uuid:
logger.error("Heleket: Missing amount or uuid")
return web.Response(status=400, text="Missing required fields")
if uuid in processed_payments:
logger.warning(f"Heleket: Duplicate payment uuid={uuid}")
return web.Response(status=200, text="OK")
if order_id and order_id in processed_payments:
logger.warning(f"Heleket: Duplicate payment order_id={order_id}")
return web.Response(status=200, text="OK")
tg_id = None
rub_amount = None
try:
if additional_data and "tg_id:" in additional_data:
parts = additional_data.split(",")
for part in parts:
if part.startswith("tg_id:"):
tg_id = int(part.split("tg_id:")[1])
elif part.startswith("rub_amount:"):
rub_amount = float(part.split("rub_amount:")[1])
elif order_id and "_" in order_id:
tg_id = int(order_id.split("_")[1])
usd_amount = float(amount)
rub_amount = usd_amount * HELEKET_CURRENCY_RATE
else:
logger.error("Heleket: Cannot extract tg_id from data")
return web.Response(status=400, text="Cannot extract user ID")
except (ValueError, IndexError) as e:
logger.error(f"Heleket: Error extracting tg_id or rub_amount: {e}")
return web.Response(status=400, text="Invalid user ID or amount format")
if not rub_amount:
logger.error("Heleket: Could not determine rub_amount")
return web.Response(status=400, text="Cannot determine amount")
async with async_session_maker() as session:
await update_balance(session, tg_id, rub_amount)
await send_payment_success_notification(tg_id, rub_amount, session)
await add_payment(session, tg_id, rub_amount, "heleket")
processed_payments.add(uuid)
if order_id:
processed_payments.add(order_id)
logger.info(f"✅ Heleket: Payment processed for user {tg_id}, amount {rub_amount} RUB (${amount}), uuid={uuid}")
return web.Response(status=200, text="OK")
except Exception as e:
logger.error(f"Heleket webhook error: {e}")
return web.Response(status=500, text="Internal server error")
def verify_heleket_webhook_signature(data: dict, signature: str) -> bool:
"""
Проверка подписи вебхука Heleket
"""
try:
data_without_sign = {k: v for k, v in data.items() if k != "sign"}
json_data = json.dumps(data_without_sign, separators=(",", ":"))
base64_data = base64.b64encode(json_data.encode("utf-8")).decode("utf-8")
sign_string = base64_data + HELEKET_API_KEY
expected_signature = hashlib.md5(sign_string.encode("utf-8")).hexdigest()
result = signature.upper() == expected_signature.upper()
if not result:
logger.error("Heleket webhook signature mismatch")
logger.error(f"Expected: {expected_signature}, Got: {signature}")
logger.error(f"Base64 data: {base64_data}")
logger.error(f"Sign string: {sign_string}")
return result
except Exception as e:
logger.error(f"Heleket signature verification error: {e}")
return False