Merge pull request #220 from JustYay/dev
Fix paymentid and success and fail urls
This commit is contained in:
+65
-62
@@ -12,7 +12,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from config import (
|
||||
KASSAI_ENABLE, KASSAI_API_KEY, KASSAI_SECRET_KEY, KASSAI_DOMAIN, KASSAI_SHOP_ID,
|
||||
REDIRECT_LINK, FAIL_REDIRECT_LINK, WEBHOOK_HOST, KASSAI_IP
|
||||
REDIRECT_LINK, FAIL_REDIRECT_LINK, WEBHOOK_HOST, KASSAI_IP, KASSAI_SUCCESS_URL, KASSAI_FAILURE_URL
|
||||
)
|
||||
|
||||
from handlers.buttons import BACK, PAY_2, KASSAI_CARDS, KASSAI_SBP
|
||||
@@ -41,65 +41,73 @@ KASSAI_PAYMENT_METHODS = [
|
||||
|
||||
@router.callback_query(F.data == "pay_kassai")
|
||||
async def process_callback_pay_kassai(callback_query: types.CallbackQuery, state: FSMContext, session: AsyncSession, method_name: str = None):
|
||||
tg_id = callback_query.message.chat.id
|
||||
logger.info(f"User {tg_id} initiated KassaAI payment.")
|
||||
|
||||
if method_name:
|
||||
method = next((m for m in KASSAI_PAYMENT_METHODS if m["name"] == method_name and m["enable"]), None)
|
||||
if not method:
|
||||
try:
|
||||
tg_id = callback_query.message.chat.id
|
||||
logger.info(f"User {tg_id} initiated KassaAI payment.")
|
||||
|
||||
await state.clear()
|
||||
|
||||
if method_name:
|
||||
method = next((m for m in KASSAI_PAYMENT_METHODS if m["name"] == method_name and m["enable"]), None)
|
||||
if not method:
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||
reply_markup=types.InlineKeyboardMarkup(),
|
||||
force_text=True,
|
||||
)
|
||||
return
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
for i in range(0, len(PAYMENT_OPTIONS), 2):
|
||||
if i + 1 < len(PAYMENT_OPTIONS):
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i]["callback_data"].split("|")[1]}',
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i + 1]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i + 1]["callback_data"].split("|")[1]}',
|
||||
),
|
||||
)
|
||||
else:
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i]["callback_data"].split("|")[1]}',
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Ввести сумму", callback_data=f"kassai_custom_amount|{method_name}"))
|
||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
||||
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||
reply_markup=types.InlineKeyboardMarkup(),
|
||||
text=method["desc"],
|
||||
reply_markup=builder.as_markup(),
|
||||
force_text=True,
|
||||
)
|
||||
await state.update_data(kassai_method=method_name)
|
||||
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
||||
return
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
for i in range(0, len(PAYMENT_OPTIONS), 2):
|
||||
if i + 1 < len(PAYMENT_OPTIONS):
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i]["callback_data"].split("|")[1]}',
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i + 1]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i + 1]["callback_data"].split("|")[1]}',
|
||||
),
|
||||
)
|
||||
else:
|
||||
builder.row(
|
||||
InlineKeyboardButton(
|
||||
text=PAYMENT_OPTIONS[i]["text"],
|
||||
callback_data=f'kassai_amount|{method_name}|{PAYMENT_OPTIONS[i]["callback_data"].split("|")[1]}',
|
||||
)
|
||||
)
|
||||
builder.row(InlineKeyboardButton(text="Ввести сумму", callback_data=f"kassai_custom_amount|{method_name}"))
|
||||
for method in KASSAI_PAYMENT_METHODS:
|
||||
if method["enable"]:
|
||||
builder.row(InlineKeyboardButton(text=method["button"], callback_data=f'kassai_method|{method["name"]}'))
|
||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
||||
|
||||
await callback_query.message.delete()
|
||||
new_message = await callback_query.message.answer(
|
||||
text=method["desc"],
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text="Выберите способ оплаты через KassaAI:",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id, kassai_method=method_name)
|
||||
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
||||
return
|
||||
|
||||
builder = InlineKeyboardBuilder()
|
||||
for method in KASSAI_PAYMENT_METHODS:
|
||||
if method["enable"]:
|
||||
builder.row(InlineKeyboardButton(text=method["button"], callback_data=f'kassai_method|{method["name"]}'))
|
||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
||||
|
||||
await callback_query.message.delete()
|
||||
new_message = await callback_query.message.answer(
|
||||
text="Выберите способ оплаты через KassaAI:",
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id)
|
||||
await state.set_state(ReplenishBalanceKassaiState.choosing_method)
|
||||
await state.update_data(message_id=callback_query.message.message_id, chat_id=callback_query.message.chat.id)
|
||||
await state.set_state(ReplenishBalanceKassaiState.choosing_method)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in process_callback_pay_kassai for user {callback_query.message.chat.id}: {e}")
|
||||
await callback_query.answer("Произошла ошибка при инициализации платежа. Попробуйте позже.", show_alert=True)
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("kassai_method|"))
|
||||
@@ -141,12 +149,12 @@ async def process_method_selection(callback_query: types.CallbackQuery, state: F
|
||||
builder.row(InlineKeyboardButton(text="Ввести сумму", callback_data=f"kassai_custom_amount|{method_name}"))
|
||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="pay_kassai"))
|
||||
|
||||
await callback_query.message.delete()
|
||||
new_message = await callback_query.message.answer(
|
||||
await edit_or_send_message(
|
||||
target_message=callback_query.message,
|
||||
text=method["desc"],
|
||||
reply_markup=builder.as_markup(),
|
||||
)
|
||||
await state.update_data(message_id=new_message.message_id, chat_id=new_message.chat.id)
|
||||
await state.update_data(message_id=callback_query.message.message_id, chat_id=callback_query.message.chat.id)
|
||||
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
||||
|
||||
|
||||
@@ -220,10 +228,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext):
|
||||
force_text=True,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -274,10 +278,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
||||
force_text=True,
|
||||
)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
@@ -287,7 +287,7 @@ async def generate_kassai_payment_link(amount: int, tg_id: int, method: dict) ->
|
||||
"""
|
||||
nonce = int(time.time())
|
||||
unique_payment_id = f"{nonce}_{tg_id}"
|
||||
url = f"https://api.fk.life/v1/orders/create?paymentId={unique_payment_id}"
|
||||
url = "https://api.fk.life/v1/orders/create"
|
||||
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
@@ -303,7 +303,10 @@ async def generate_kassai_payment_link(amount: int, tg_id: int, method: dict) ->
|
||||
"email": client_email,
|
||||
"ip": client_ip,
|
||||
"amount": int(amount),
|
||||
"currency": "RUB"
|
||||
"currency": "RUB",
|
||||
"success_url": KASSAI_SUCCESS_URL,
|
||||
"failure_url": KASSAI_FAILURE_URL,
|
||||
"paymentId": unique_payment_id
|
||||
}
|
||||
|
||||
sorted_keys = sorted(data_for_signature.keys())
|
||||
|
||||
+9
-21
@@ -1,12 +1,9 @@
|
||||
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 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
|
||||
|
||||
@@ -37,6 +34,8 @@ async def kassai_payment_webhook(request: web.Request):
|
||||
p_email = data_dict.get("P_EMAIL")
|
||||
intid = data_dict.get("intid")
|
||||
|
||||
logger.info(f"KassaAI payment: intid={intid}, MERCHANT_ORDER_ID={merchant_order_id}, amount={amount}")
|
||||
|
||||
if not amount or not intid:
|
||||
logger.error(f"KassaAI: Missing AMOUNT or intid")
|
||||
return web.Response(status=400, text="Missing required fields")
|
||||
@@ -45,6 +44,10 @@ async def kassai_payment_webhook(request: web.Request):
|
||||
logger.warning(f"KassaAI: Duplicate payment intid={intid}")
|
||||
return web.Response(status=200, text="YES")
|
||||
|
||||
if merchant_order_id and merchant_order_id in processed_payments:
|
||||
logger.warning(f"KassaAI: Duplicate payment MERCHANT_ORDER_ID={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])
|
||||
@@ -62,26 +65,11 @@ 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:
|
||||
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}")
|
||||
|
||||
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}")
|
||||
|
||||
processed_payments.add(intid)
|
||||
if merchant_order_id:
|
||||
processed_payments.add(merchant_order_id)
|
||||
|
||||
logger.info(f"✅ KassaAI: Payment processed for user {tg_id}, amount {amount_float}, intid={intid}")
|
||||
logger.info(f"✅ KassaAI: Payment processed for user {tg_id}, amount {amount_float}, intid={intid}, MERCHANT_ORDER_ID={merchant_order_id}")
|
||||
return web.Response(status=200, text="YES")
|
||||
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user