184 lines
6.9 KiB
Python
184 lines
6.9 KiB
Python
import hashlib
|
|
import hmac
|
|
import logging
|
|
import time
|
|
import uuid
|
|
|
|
from aiogram import F, Router, types
|
|
from aiogram.fsm.context import FSMContext
|
|
from aiogram.fsm.state import State, StatesGroup
|
|
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
|
|
from aiogram.utils.keyboard import InlineKeyboardBuilder
|
|
from aiohttp import web
|
|
import requests
|
|
|
|
from config import FREEKASSA_API_KEY, FREEKASSA_SHOP_ID
|
|
from database import add_payment, update_balance
|
|
from handlers.payments.utils import send_payment_success_notification
|
|
from handlers.texts import PAYMENT_OPTIONS
|
|
|
|
router = Router()
|
|
logging.basicConfig(level=logging.DEBUG)
|
|
|
|
|
|
class ReplenishBalanceState(StatesGroup):
|
|
choosing_amount_freekassa = State()
|
|
waiting_for_payment_confirmation_freekassa = State()
|
|
entering_custom_amount_freekassa = State()
|
|
|
|
|
|
def generate_signature(params, api_key):
|
|
sorted_params = {k: params[k] for k in sorted(params)}
|
|
sign_string = "|".join(str(value) for value in sorted_params.values())
|
|
return hmac.new(api_key.encode(), sign_string.encode(), hashlib.sha256).hexdigest()
|
|
|
|
|
|
async def create_payment(user_id, amount, email, ip):
|
|
payment_id = str(uuid.uuid4())
|
|
nonce = int(time.time() * 1000)
|
|
params = {
|
|
"shopId": FREEKASSA_SHOP_ID,
|
|
"amount": amount,
|
|
"currency": "RUB",
|
|
"paymentId": payment_id,
|
|
"email": email,
|
|
"ip": ip,
|
|
"i": 6,
|
|
"nonce": nonce,
|
|
}
|
|
params["signature"] = generate_signature(params, FREEKASSA_API_KEY)
|
|
|
|
try:
|
|
response = requests.post("https://api.freekassa.com/v1/orders/create", json=params)
|
|
response_data = response.json()
|
|
|
|
logging.debug(f"Ответ от FreeKassa при создании платежа: {response_data}")
|
|
|
|
if response_data.get("type") == "success":
|
|
return response_data["location"]
|
|
else:
|
|
logging.error(f"Ошибка создания платежа: {response_data}")
|
|
return None
|
|
|
|
except Exception as e:
|
|
logging.error(f"Ошибка запроса к FreeKassa: {e}")
|
|
return None
|
|
|
|
|
|
async def freekassa_webhook(request):
|
|
data = await request.json()
|
|
logging.debug(f"Получен вебхук от FreeKassa: {data}")
|
|
|
|
logging.debug(f"Данные вебхука от FreeKassa: {data}")
|
|
|
|
if data["status"] == "completed":
|
|
user_id = data["metadata"]["user_id"]
|
|
amount = float(data["amount"])
|
|
await add_payment(int(user_id), float(amount), "freekassa")
|
|
|
|
await update_balance(user_id, amount)
|
|
await send_payment_success_notification(user_id, amount)
|
|
|
|
return web.Response(status=200)
|
|
|
|
|
|
@router.callback_query(lambda c: c.data == "pay_freekassa")
|
|
async def process_callback_pay_freekassa(callback_query: types.CallbackQuery, state: FSMContext):
|
|
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'freekassa_{PAYMENT_OPTIONS[i]["callback_data"]}',
|
|
),
|
|
InlineKeyboardButton(
|
|
text=PAYMENT_OPTIONS[i + 1]["text"],
|
|
callback_data=f'freekassa_{PAYMENT_OPTIONS[i + 1]["callback_data"]}',
|
|
),
|
|
)
|
|
else:
|
|
builder.row(
|
|
InlineKeyboardButton(
|
|
text=PAYMENT_OPTIONS[i]["text"],
|
|
callback_data=f'freekassa_{PAYMENT_OPTIONS[i]["callback_data"]}',
|
|
)
|
|
)
|
|
builder.row(
|
|
InlineKeyboardButton(
|
|
text="💰 Ввести свою сумму",
|
|
callback_data="enter_custom_amount_freekassa",
|
|
)
|
|
)
|
|
builder.row(InlineKeyboardButton(text="⬅️ Назад", callback_data="pay"))
|
|
|
|
await callback_query.message.answer(
|
|
text="Выберите сумму пополнения через FreeKassa:",
|
|
reply_markup=builder.as_markup(),
|
|
)
|
|
|
|
await state.set_state(ReplenishBalanceState.choosing_amount_freekassa)
|
|
|
|
|
|
@router.callback_query(F.data.startswith("freekassa_amount|"))
|
|
async def process_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
|
|
data = callback_query.data.split("|", 1)
|
|
amount_str = data[1]
|
|
try:
|
|
amount = int(amount_str)
|
|
except ValueError:
|
|
await callback_query.message.answer("Некорректная сумма.")
|
|
return
|
|
|
|
user_email = f"{callback_query.message.chat.id}@solo.net"
|
|
user_ip = callback_query.message.chat.id
|
|
payment_url = await create_payment(callback_query.message.chat.id, amount, user_email, user_ip)
|
|
|
|
if payment_url:
|
|
confirm_keyboard = InlineKeyboardMarkup(
|
|
inline_keyboard=[
|
|
[InlineKeyboardButton(text=f"Оплатить {amount} рублей", url=payment_url)],
|
|
[InlineKeyboardButton(text="⬅️ Назад", callback_data="pay")],
|
|
]
|
|
)
|
|
|
|
await callback_query.message.answer(
|
|
f"Вы выбрали оплату на {amount} рублей. Перейдите по ссылке для завершения оплаты:",
|
|
reply_markup=confirm_keyboard,
|
|
)
|
|
else:
|
|
await callback_query.message.answer(
|
|
"Ошибка при создании платежа. Попробуйте позже.",
|
|
)
|
|
|
|
|
|
@router.callback_query(F.data == "enter_custom_amount_freekassa")
|
|
async def process_enter_custom_amount(callback_query: types.CallbackQuery, state: FSMContext):
|
|
await callback_query.message.answer(text="Введите сумму пополнения:")
|
|
await state.set_state(ReplenishBalanceState.entering_custom_amount_freekassa)
|
|
|
|
|
|
@router.message(ReplenishBalanceState.entering_custom_amount_freekassa)
|
|
async def process_custom_amount_input(message: types.Message, state: FSMContext):
|
|
if message.text.isdigit():
|
|
amount = int(message.text)
|
|
if amount <= 0:
|
|
await message.answer("Сумма должна быть больше нуля. Пожалуйста, введите сумму еще раз:")
|
|
return
|
|
|
|
user_email = f"{message.chat.id}@solo.net"
|
|
user_ip = message.chat.id
|
|
payment_url = await create_payment(message.chat.id, amount, user_email, user_ip)
|
|
|
|
if payment_url:
|
|
keyboard = InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton("Оплатить", url=payment_url)]])
|
|
await message.answer(
|
|
f"Вы выбрали оплату на {amount} рублей. Перейдите по ссылке для завершения оплаты:",
|
|
reply_markup=keyboard,
|
|
)
|
|
else:
|
|
await message.answer("Ошибка при создании платежа. Попробуйте позже.")
|
|
|
|
else:
|
|
await message.answer("Пожалуйста, введите корректную сумму.")
|