HOTFIX "Консистентность касс"
- исправление edit_or_send_message в кассах - добавление ожидаемого платежа - исправление heleket (мусорил в базе)
This commit is contained in:
@@ -135,7 +135,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Ошибка: данные повреждены.",
|
text="Ошибка: данные повреждены.",
|
||||||
reply_markup=types.InlineKeyboardMarkup(),
|
reply_markup=types.InlineKeyboardMarkup(),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -150,7 +149,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Некорректная сумма.",
|
text="Некорректная сумма.",
|
||||||
reply_markup=types.InlineKeyboardMarkup(),
|
reply_markup=types.InlineKeyboardMarkup(),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -175,7 +173,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=DEFAULT_PAYMENT_MESSAGE.format(amount=amount),
|
text=DEFAULT_PAYMENT_MESSAGE.format(amount=amount),
|
||||||
reply_markup=confirm_keyboard,
|
reply_markup=confirm_keyboard,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
logger.info(f"Payment link sent to user {callback_query.message.chat.id}.")
|
logger.info(f"Payment link sent to user {callback_query.message.chat.id}.")
|
||||||
|
|
||||||
@@ -280,7 +277,6 @@ async def process_custom_amount_selection(callback_query: types.CallbackQuery, s
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=ENTER_SUM,
|
text=ENTER_SUM,
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_freekassa)
|
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_freekassa)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from logger import logger
|
|||||||
from ..constants import ALLOWED_TEMP_PAYMENT_STATES
|
from ..constants import ALLOWED_TEMP_PAYMENT_STATES
|
||||||
|
|
||||||
from .service import (
|
from .service import (
|
||||||
HELEKET_PAYMENT_METHODS,
|
get_heleket_methods,
|
||||||
generate_heleket_payment_link,
|
generate_heleket_payment_link,
|
||||||
process_callback_pay_heleket,
|
process_callback_pay_heleket,
|
||||||
router as service_router,
|
router as service_router,
|
||||||
@@ -75,7 +75,7 @@ async def handle_custom_amount_input_heleket(
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
enabled_methods = [m for m in HELEKET_PAYMENT_METHODS if m["enable"]]
|
enabled_methods = [m for m in get_heleket_methods() if m["enable"]]
|
||||||
if not enabled_methods:
|
if not enabled_methods:
|
||||||
await edit_or_send_message(
|
await edit_or_send_message(
|
||||||
target_message=message,
|
target_message=message,
|
||||||
|
|||||||
@@ -64,17 +64,28 @@ class ReplenishBalanceHeleket(StatesGroup):
|
|||||||
entering_custom_amount = State()
|
entering_custom_amount = State()
|
||||||
|
|
||||||
|
|
||||||
PROVIDERS = get_providers(PROVIDERS_ENABLED)
|
def _is_heleket_enabled() -> bool:
|
||||||
HELEKET_PAYMENT_METHODS = [
|
try:
|
||||||
{
|
from core.bootstrap import PAYMENTS_CONFIG
|
||||||
"enable": bool(PROVIDERS.get("HELEKET", {}).get("enabled")),
|
return bool(PAYMENTS_CONFIG.get("HELEKET", PROVIDERS_ENABLED.get("HELEKET", False)))
|
||||||
"currency": (PROVIDERS.get("HELEKET", {}).get("currency") or "USD"),
|
except ImportError:
|
||||||
"to_currency": None,
|
return bool(PROVIDERS_ENABLED.get("HELEKET", False))
|
||||||
"name": "crypto",
|
|
||||||
"button": HELEKET,
|
|
||||||
"desc": HELEKET_CRYPTO_DESCRIPTION,
|
def get_heleket_methods() -> list[dict]:
|
||||||
},
|
return [
|
||||||
]
|
{
|
||||||
|
"enable": _is_heleket_enabled(),
|
||||||
|
"currency": "USD",
|
||||||
|
"to_currency": None,
|
||||||
|
"name": "crypto",
|
||||||
|
"button": HELEKET,
|
||||||
|
"desc": HELEKET_CRYPTO_DESCRIPTION,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
HELEKET_PAYMENT_METHODS = get_heleket_methods()
|
||||||
|
|
||||||
|
|
||||||
async def process_callback_pay_heleket(
|
async def process_callback_pay_heleket(
|
||||||
@@ -86,18 +97,17 @@ async def process_callback_pay_heleket(
|
|||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
if not method_name:
|
if not method_name:
|
||||||
enabled_methods = [m["name"] for m in HELEKET_PAYMENT_METHODS if m["enable"]]
|
methods = get_heleket_methods()
|
||||||
|
enabled_methods = [m["name"] for m in methods if m["enable"]]
|
||||||
if len(enabled_methods) == 1:
|
if len(enabled_methods) == 1:
|
||||||
method_name = enabled_methods[0]
|
method_name = enabled_methods[0]
|
||||||
|
|
||||||
if method_name:
|
if method_name:
|
||||||
method = next((m for m in HELEKET_PAYMENT_METHODS if m["name"] == method_name and m["enable"]), None)
|
methods = get_heleket_methods()
|
||||||
|
method = next((m for m in methods if m["name"] == method_name and m["enable"]), None)
|
||||||
if not method:
|
if not method:
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
await callback_query.message.answer(
|
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
)
|
)
|
||||||
@@ -115,40 +125,36 @@ async def process_callback_pay_heleket(
|
|||||||
opts=opts
|
opts=opts
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
new_msg = await callback_query.message.answer(
|
|
||||||
text=method["desc"],
|
text=method["desc"],
|
||||||
reply_markup=builder,
|
reply_markup=builder,
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.update_data(
|
await state.update_data(
|
||||||
heleket_method=method_name,
|
heleket_method=method_name,
|
||||||
message_id=new_msg.message_id,
|
message_id=callback_query.message.message_id,
|
||||||
chat_id=new_msg.chat.id,
|
chat_id=callback_query.message.chat.id,
|
||||||
)
|
)
|
||||||
await state.set_state(ReplenishBalanceHeleket.choosing_amount)
|
await state.set_state(ReplenishBalanceHeleket.choosing_amount)
|
||||||
return
|
return
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
for method in HELEKET_PAYMENT_METHODS:
|
for method in get_heleket_methods():
|
||||||
if method["enable"]:
|
if method["enable"]:
|
||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(text=method["button"], callback_data=f"heleket_method|{method['name']}")
|
InlineKeyboardButton(text=method["button"], callback_data=f"heleket_method|{method['name']}")
|
||||||
)
|
)
|
||||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
||||||
|
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
new_msg = await callback_query.message.answer(
|
|
||||||
text="Выберите способ оплаты через Heleket:",
|
text="Выберите способ оплаты через Heleket:",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
)
|
)
|
||||||
await state.update_data(message_id=new_msg.message_id, chat_id=new_msg.chat.id)
|
await state.update_data(
|
||||||
|
message_id=callback_query.message.message_id,
|
||||||
|
chat_id=callback_query.message.chat.id,
|
||||||
|
)
|
||||||
await state.set_state(ReplenishBalanceHeleket.choosing_method)
|
await state.set_state(ReplenishBalanceHeleket.choosing_method)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -166,7 +172,6 @@ async def process_method_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -189,7 +194,6 @@ async def process_method_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=method["desc"],
|
text=method["desc"],
|
||||||
reply_markup=builder,
|
reply_markup=builder,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
await state.update_data(message_id=callback_query.message.message_id, chat_id=callback_query.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(ReplenishBalanceHeleket.choosing_amount)
|
await state.set_state(ReplenishBalanceHeleket.choosing_amount)
|
||||||
@@ -211,7 +215,6 @@ async def process_custom_amount_button(callback_query: types.CallbackQuery, stat
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=f"Пожалуйста, введите сумму пополнения в {currency_text}.",
|
text=f"Пожалуйста, введите сумму пополнения в {currency_text}.",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
await state.set_state(ReplenishBalanceHeleket.entering_custom_amount)
|
await state.set_state(ReplenishBalanceHeleket.entering_custom_amount)
|
||||||
|
|
||||||
@@ -227,7 +230,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -247,7 +249,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text=f"❌ Минимальная сумма для оплаты криптовалютой — {currency_symbol}{min_amount}.",
|
text=f"❌ Минимальная сумма для оплаты криптовалютой — {currency_symbol}{min_amount}.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -255,7 +256,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="❌ Некорректная сумма. Введите целое число больше 0.",
|
text="❌ Некорректная сумма. Введите целое число больше 0.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -273,7 +273,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -286,7 +285,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text=HELEKET_PAYMENT_MESSAGE.format(amount=amount_text),
|
text=HELEKET_PAYMENT_MESSAGE.format(amount=amount_text),
|
||||||
reply_markup=confirm_keyboard,
|
reply_markup=confirm_keyboard,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.set_state(ReplenishBalanceHeleket.waiting_for_payment_confirmation)
|
await state.set_state(ReplenishBalanceHeleket.waiting_for_payment_confirmation)
|
||||||
@@ -300,7 +298,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Некорректная сумма.",
|
text="Некорректная сумма.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -312,7 +309,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -321,7 +317,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="❌ Минимальная сумма для оплаты криптовалютой — 10₽ (≈0.1$).",
|
text="❌ Минимальная сумма для оплаты криптовалютой — 10₽ (≈0.1$).",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -333,7 +328,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -347,7 +341,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=HELEKET_PAYMENT_MESSAGE.format(amount=amount_text),
|
text=HELEKET_PAYMENT_MESSAGE.format(amount=amount_text),
|
||||||
reply_markup=confirm_keyboard,
|
reply_markup=confirm_keyboard,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.set_state(ReplenishBalanceHeleket.waiting_for_payment_confirmation)
|
await state.set_state(ReplenishBalanceHeleket.waiting_for_payment_confirmation)
|
||||||
@@ -371,17 +364,6 @@ async def generate_heleket_payment_link(amount: int, tg_id: int, method: dict) -
|
|||||||
rate = await get_rub_rate(pay_cur, session=session)
|
rate = await get_rub_rate(pay_cur, session=session)
|
||||||
payment_amount = (Decimal(str(amount)) * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
payment_amount = (Decimal(str(amount)) * rate).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP)
|
||||||
|
|
||||||
async with async_session_maker() as dbs:
|
|
||||||
await add_payment(
|
|
||||||
session=dbs,
|
|
||||||
tg_id=tg_id,
|
|
||||||
amount=float(amount),
|
|
||||||
payment_system="HELEKET",
|
|
||||||
status="pending",
|
|
||||||
currency="RUB",
|
|
||||||
payment_id=unique_order_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
"amount": str(payment_amount),
|
"amount": str(payment_amount),
|
||||||
"currency": method["currency"],
|
"currency": method["currency"],
|
||||||
@@ -412,6 +394,16 @@ async def generate_heleket_payment_link(amount: int, tg_id: int, method: dict) -
|
|||||||
if resp_json.get("state") == 0:
|
if resp_json.get("state") == 0:
|
||||||
payment_url = resp_json.get("result", {}).get("url")
|
payment_url = resp_json.get("result", {}).get("url")
|
||||||
if payment_url:
|
if payment_url:
|
||||||
|
async with async_session_maker() as dbs:
|
||||||
|
await add_payment(
|
||||||
|
session=dbs,
|
||||||
|
tg_id=tg_id,
|
||||||
|
amount=float(amount),
|
||||||
|
payment_system="HELEKET",
|
||||||
|
status="pending",
|
||||||
|
currency="RUB",
|
||||||
|
payment_id=unique_order_id,
|
||||||
|
)
|
||||||
logger.info(f"Heleket payment URL created for user {tg_id}")
|
logger.info(f"Heleket payment URL created for user {tg_id}")
|
||||||
return payment_url
|
return payment_url
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -124,26 +124,12 @@ async def process_heleket_webhook(data: dict) -> bool:
|
|||||||
payment = await get_payment_by_payment_id(session, order_id)
|
payment = await get_payment_by_payment_id(session, order_id)
|
||||||
if payment:
|
if payment:
|
||||||
if payment.get("status") == "success":
|
if payment.get("status") == "success":
|
||||||
logger.info(
|
logger.info(f"Heleket: платёж {order_id} уже обработан")
|
||||||
f"Heleket: платёж {order_id} уже обработан"
|
|
||||||
)
|
|
||||||
return True
|
return True
|
||||||
ok = await update_payment_status(
|
ok = await update_payment_status(session=session, internal_id=int(payment["id"]), new_status="success")
|
||||||
session=session,
|
|
||||||
internal_id=int(payment["id"]),
|
|
||||||
new_status="success",
|
|
||||||
)
|
|
||||||
if not ok:
|
if not ok:
|
||||||
logger.error(
|
logger.error(f"Heleket: не удалось обновить статус платежа {order_id}")
|
||||||
f"Heleket: не удалось обновить статус "
|
|
||||||
f"платежа {order_id}"
|
|
||||||
)
|
|
||||||
return False
|
return False
|
||||||
await update_balance(session, tg_id, balance_amount)
|
|
||||||
await send_payment_success_notification(
|
|
||||||
tg_id, balance_amount, session
|
|
||||||
)
|
|
||||||
await session.commit()
|
|
||||||
else:
|
else:
|
||||||
await add_payment(
|
await add_payment(
|
||||||
session=session,
|
session=session,
|
||||||
@@ -155,11 +141,9 @@ async def process_heleket_webhook(data: dict) -> bool:
|
|||||||
payment_id=order_id,
|
payment_id=order_id,
|
||||||
metadata=None,
|
metadata=None,
|
||||||
)
|
)
|
||||||
await update_balance(session, tg_id, balance_amount)
|
|
||||||
await send_payment_success_notification(
|
await update_balance(session, tg_id, balance_amount)
|
||||||
tg_id, balance_amount, session
|
await send_payment_success_notification(tg_id, balance_amount, session)
|
||||||
)
|
|
||||||
await session.commit()
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Heleket: платёж {order_id} для пользователя {tg_id} "
|
f"Heleket: платёж {order_id} для пользователя {tg_id} "
|
||||||
f"успешно обработан, баланс пополнен на {balance_amount} RUB"
|
f"успешно обработан, баланс пополнен на {balance_amount} RUB"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from logger import logger
|
|||||||
from ..constants import ALLOWED_TEMP_PAYMENT_STATES
|
from ..constants import ALLOWED_TEMP_PAYMENT_STATES
|
||||||
|
|
||||||
from .service import (
|
from .service import (
|
||||||
KASSAI_PAYMENT_METHODS,
|
get_kassai_methods,
|
||||||
generate_kassai_payment_link,
|
generate_kassai_payment_link,
|
||||||
process_callback_pay_kassai,
|
process_callback_pay_kassai,
|
||||||
router as service_router,
|
router as service_router,
|
||||||
@@ -105,11 +105,7 @@ async def _handle_custom_amount_input_kassai(
|
|||||||
return
|
return
|
||||||
|
|
||||||
method = next(
|
method = next(
|
||||||
(
|
(m for m in get_kassai_methods() if m["name"] == method_name and m["enable"]),
|
||||||
m
|
|
||||||
for m in KASSAI_PAYMENT_METHODS
|
|
||||||
if m["name"] == method_name and m["enable"]
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
if not method:
|
if not method:
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from config import (
|
|||||||
KASSAI_SUCCESS_URL,
|
KASSAI_SUCCESS_URL,
|
||||||
PROVIDERS_ENABLED,
|
PROVIDERS_ENABLED,
|
||||||
)
|
)
|
||||||
|
from database import add_payment, async_session_maker
|
||||||
from database.models import User
|
from database.models import User
|
||||||
from handlers.buttons import BACK, KASSAI_CARDS, KASSAI_SBP, PAY_2
|
from handlers.buttons import BACK, KASSAI_CARDS, KASSAI_SBP, PAY_2
|
||||||
from handlers.payments.currency_rates import (
|
from handlers.payments.currency_rates import (
|
||||||
@@ -63,23 +64,34 @@ class ReplenishBalanceKassaiState(StatesGroup):
|
|||||||
entering_custom_amount = State()
|
entering_custom_amount = State()
|
||||||
|
|
||||||
|
|
||||||
PROVIDERS = get_providers(PROVIDERS_ENABLED)
|
def _is_kassai_enabled(provider: str) -> bool:
|
||||||
KASSAI_PAYMENT_METHODS = [
|
try:
|
||||||
{
|
from core.bootstrap import PAYMENTS_CONFIG
|
||||||
"enable": bool(PROVIDERS.get("KASSAI_CARDS", {}).get("enabled")),
|
return bool(PAYMENTS_CONFIG.get(provider, PROVIDERS_ENABLED.get(provider, False)))
|
||||||
"method": 36,
|
except ImportError:
|
||||||
"name": "cards",
|
return bool(PROVIDERS_ENABLED.get(provider, False))
|
||||||
"button": KASSAI_CARDS,
|
|
||||||
"desc": KASSAI_CARDS_DESCRIPTION,
|
|
||||||
},
|
def get_kassai_methods() -> list[dict]:
|
||||||
{
|
return [
|
||||||
"enable": bool(PROVIDERS.get("KASSAI_SBP", {}).get("enabled")),
|
{
|
||||||
"method": 44,
|
"enable": _is_kassai_enabled("KASSAI_CARDS"),
|
||||||
"name": "sbp",
|
"method": 36,
|
||||||
"button": KASSAI_SBP,
|
"name": "cards",
|
||||||
"desc": KASSAI_SBP_DESCRIPTION,
|
"button": KASSAI_CARDS,
|
||||||
},
|
"desc": KASSAI_CARDS_DESCRIPTION,
|
||||||
]
|
},
|
||||||
|
{
|
||||||
|
"enable": _is_kassai_enabled("KASSAI_SBP"),
|
||||||
|
"method": 44,
|
||||||
|
"name": "sbp",
|
||||||
|
"button": KASSAI_SBP,
|
||||||
|
"desc": KASSAI_SBP_DESCRIPTION,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
KASSAI_PAYMENT_METHODS = get_kassai_methods()
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "pay_kassai")
|
@router.callback_query(F.data == "pay_kassai")
|
||||||
@@ -96,20 +108,14 @@ async def process_callback_pay_kassai(
|
|||||||
await state.clear()
|
await state.clear()
|
||||||
|
|
||||||
if method_name:
|
if method_name:
|
||||||
|
methods = get_kassai_methods()
|
||||||
method = next(
|
method = next(
|
||||||
(
|
(m for m in methods if m["name"] == method_name and m["enable"]),
|
||||||
m
|
|
||||||
for m in KASSAI_PAYMENT_METHODS
|
|
||||||
if m["name"] == method_name and m["enable"]
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
if not method:
|
if not method:
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
await callback_query.message.answer(
|
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
)
|
)
|
||||||
@@ -127,24 +133,21 @@ async def process_callback_pay_kassai(
|
|||||||
opts=opts,
|
opts=opts,
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
new_msg = await callback_query.message.answer(
|
|
||||||
text=method["desc"],
|
text=method["desc"],
|
||||||
reply_markup=builder,
|
reply_markup=builder,
|
||||||
)
|
)
|
||||||
await state.update_data(
|
await state.update_data(
|
||||||
kassai_method=method_name,
|
kassai_method=method_name,
|
||||||
message_id=new_msg.message_id,
|
message_id=callback_query.message.message_id,
|
||||||
chat_id=new_msg.chat.id,
|
chat_id=callback_query.message.chat.id,
|
||||||
)
|
)
|
||||||
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
||||||
return
|
return
|
||||||
|
|
||||||
builder = InlineKeyboardBuilder()
|
builder = InlineKeyboardBuilder()
|
||||||
for method in KASSAI_PAYMENT_METHODS:
|
for method in get_kassai_methods():
|
||||||
if method["enable"]:
|
if method["enable"]:
|
||||||
builder.row(
|
builder.row(
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
@@ -154,16 +157,14 @@ async def process_callback_pay_kassai(
|
|||||||
)
|
)
|
||||||
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
builder.row(InlineKeyboardButton(text=BACK, callback_data="balance"))
|
||||||
|
|
||||||
try:
|
await edit_or_send_message(
|
||||||
await callback_query.message.delete()
|
target_message=callback_query.message,
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
new_msg = await callback_query.message.answer(
|
|
||||||
text="Выберите способ оплаты через KassaAI:",
|
text="Выберите способ оплаты через KassaAI:",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
)
|
)
|
||||||
await state.update_data(
|
await state.update_data(
|
||||||
message_id=new_msg.message_id, chat_id=new_msg.chat.id
|
message_id=callback_query.message.message_id,
|
||||||
|
chat_id=callback_query.message.chat.id,
|
||||||
)
|
)
|
||||||
await state.set_state(ReplenishBalanceKassaiState.choosing_method)
|
await state.set_state(ReplenishBalanceKassaiState.choosing_method)
|
||||||
|
|
||||||
@@ -188,7 +189,6 @@ async def process_method_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -211,7 +211,6 @@ async def process_method_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=method["desc"],
|
text=method["desc"],
|
||||||
reply_markup=builder,
|
reply_markup=builder,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
await state.update_data(message_id=callback_query.message.message_id, chat_id=callback_query.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)
|
await state.set_state(ReplenishBalanceKassaiState.choosing_amount)
|
||||||
@@ -233,7 +232,6 @@ async def process_custom_amount_button(callback_query: types.CallbackQuery, stat
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=f"Пожалуйста, введите сумму пополнения в {currency_text}.",
|
text=f"Пожалуйста, введите сумму пополнения в {currency_text}.",
|
||||||
reply_markup=builder.as_markup(),
|
reply_markup=builder.as_markup(),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
await state.set_state(ReplenishBalanceKassaiState.entering_custom_amount)
|
await state.set_state(ReplenishBalanceKassaiState.entering_custom_amount)
|
||||||
|
|
||||||
@@ -249,7 +247,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -269,7 +266,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text=f"❌ Минимальная сумма для оплаты картой — {currency_symbol}{min_amount}.",
|
text=f"❌ Минимальная сумма для оплаты картой — {currency_symbol}{min_amount}.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
elif method_name == "sbp":
|
elif method_name == "sbp":
|
||||||
@@ -280,7 +276,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text=f"❌ Минимальная сумма для оплаты через СБП — {currency_symbol}{min_amount}.",
|
text=f"❌ Минимальная сумма для оплаты через СБП — {currency_symbol}{min_amount}.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -288,7 +283,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="❌ Некорректная сумма. Введите целое число больше 0.",
|
text="❌ Некорректная сумма. Введите целое число больше 0.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -306,7 +300,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -319,7 +312,6 @@ async def handle_custom_amount_input(message: types.Message, state: FSMContext,
|
|||||||
target_message=message,
|
target_message=message,
|
||||||
text=KASSAI_PAYMENT_MESSAGE.format(amount=amount_text),
|
text=KASSAI_PAYMENT_MESSAGE.format(amount=amount_text),
|
||||||
reply_markup=confirm_keyboard,
|
reply_markup=confirm_keyboard,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation)
|
await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation)
|
||||||
@@ -333,7 +325,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Некорректная сумма.",
|
text="Некорректная сумма.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -345,7 +336,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Ошибка: выбранный способ оплаты недоступен.",
|
text="Ошибка: выбранный способ оплаты недоступен.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -354,7 +344,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="❌ Минимальная сумма для оплаты картой — 50₽.",
|
text="❌ Минимальная сумма для оплаты картой — 50₽.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
elif method_name == "sbp" and amount < 10:
|
elif method_name == "sbp" and amount < 10:
|
||||||
@@ -362,7 +351,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="❌ Минимальная сумма для оплаты через СБП — 10₽.",
|
text="❌ Минимальная сумма для оплаты через СБП — 10₽.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -374,7 +362,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
text="❌ Произошла ошибка при создании платежа. Попробуйте позже или выберите другой способ оплаты.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -388,7 +375,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=KASSAI_PAYMENT_MESSAGE.format(amount=amount_text),
|
text=KASSAI_PAYMENT_MESSAGE.format(amount=amount_text),
|
||||||
reply_markup=confirm_keyboard,
|
reply_markup=confirm_keyboard,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation)
|
await state.set_state(ReplenishBalanceKassaiState.waiting_for_payment_confirmation)
|
||||||
@@ -434,6 +420,16 @@ async def generate_kassai_payment_link(amount: int, tg_id: int, method: dict) ->
|
|||||||
if resp_json.get("type") == "success":
|
if resp_json.get("type") == "success":
|
||||||
payment_url = resp_json.get("location")
|
payment_url = resp_json.get("location")
|
||||||
if payment_url:
|
if payment_url:
|
||||||
|
async with async_session_maker() as dbs:
|
||||||
|
await add_payment(
|
||||||
|
session=dbs,
|
||||||
|
tg_id=tg_id,
|
||||||
|
amount=float(amount),
|
||||||
|
payment_system="KASSAI",
|
||||||
|
status="pending",
|
||||||
|
currency="RUB",
|
||||||
|
payment_id=unique_payment_id,
|
||||||
|
)
|
||||||
logger.info(f"KassaAI payment URL created for user {tg_id}")
|
logger.info(f"KassaAI payment URL created for user {tg_id}")
|
||||||
return payment_url
|
return payment_url
|
||||||
logger.error(f"KassaAI: No location in response: {resp_json}")
|
logger.error(f"KassaAI: No location in response: {resp_json}")
|
||||||
|
|||||||
@@ -89,26 +89,12 @@ async def kassai_webhook(request: web.Request):
|
|||||||
payment = await get_payment_by_payment_id(session, order_id)
|
payment = await get_payment_by_payment_id(session, order_id)
|
||||||
if payment:
|
if payment:
|
||||||
if payment.get("status") == "success":
|
if payment.get("status") == "success":
|
||||||
logger.info(
|
logger.info(f"KassaAI: платёж {order_id} уже обработан")
|
||||||
f"KassaAI: платёж {order_id} уже обработан"
|
|
||||||
)
|
|
||||||
return web.Response(text=KASSAI_WEBHOOK_RESPONSE)
|
return web.Response(text=KASSAI_WEBHOOK_RESPONSE)
|
||||||
ok = await update_payment_status(
|
ok = await update_payment_status(session=session, internal_id=int(payment["id"]), new_status="success")
|
||||||
session=session,
|
|
||||||
internal_id=int(payment["id"]),
|
|
||||||
new_status="success",
|
|
||||||
)
|
|
||||||
if not ok:
|
if not ok:
|
||||||
logger.error(
|
logger.error(f"KassaAI: не удалось обновить статус платежа {order_id}")
|
||||||
f"KassaAI: не удалось обновить статус "
|
|
||||||
f"платежа {order_id}"
|
|
||||||
)
|
|
||||||
return web.Response(status=500)
|
return web.Response(status=500)
|
||||||
await update_balance(session, tg_id, amount)
|
|
||||||
await send_payment_success_notification(
|
|
||||||
tg_id, amount, session
|
|
||||||
)
|
|
||||||
await session.commit()
|
|
||||||
else:
|
else:
|
||||||
await add_payment(
|
await add_payment(
|
||||||
session=session,
|
session=session,
|
||||||
@@ -120,11 +106,9 @@ async def kassai_webhook(request: web.Request):
|
|||||||
payment_id=order_id,
|
payment_id=order_id,
|
||||||
metadata=None,
|
metadata=None,
|
||||||
)
|
)
|
||||||
await update_balance(session, tg_id, amount)
|
|
||||||
await send_payment_success_notification(
|
await update_balance(session, tg_id, amount)
|
||||||
tg_id, amount, session
|
await send_payment_success_notification(tg_id, amount, session)
|
||||||
)
|
|
||||||
await session.commit()
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"KassaAI: платёж {order_id} успешно обработан, "
|
f"KassaAI: платёж {order_id} успешно обработан, "
|
||||||
f"баланс пользователя {tg_id} пополнен на {amount} RUB"
|
f"баланс пользователя {tg_id} пополнен на {amount} RUB"
|
||||||
|
|||||||
@@ -61,9 +61,12 @@ async def process_callback_pay_robokassa(callback_query: types.CallbackQuery, st
|
|||||||
opts=opts,
|
opts=opts,
|
||||||
)
|
)
|
||||||
|
|
||||||
await callback_query.message.delete()
|
await edit_or_send_message(
|
||||||
m = await callback_query.message.answer(text="Выберите сумму пополнения:", reply_markup=markup)
|
target_message=callback_query.message,
|
||||||
await state.update_data(message_id=m.message_id, chat_id=m.chat.id)
|
text="Выберите сумму пополнения:",
|
||||||
|
reply_markup=markup,
|
||||||
|
)
|
||||||
|
await state.update_data(message_id=callback_query.message.message_id, chat_id=callback_query.message.chat.id)
|
||||||
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
|
await state.set_state(ReplenishBalanceState.choosing_amount_robokassa)
|
||||||
|
|
||||||
|
|
||||||
@@ -75,7 +78,6 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text="Некорректная сумма.",
|
text="Некорректная сумма.",
|
||||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
reply_markup=InlineKeyboardMarkup(inline_keyboard=[]),
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -95,14 +97,13 @@ async def process_amount_selection(callback_query: types.CallbackQuery, state: F
|
|||||||
target_message=callback_query.message,
|
target_message=callback_query.message,
|
||||||
text=DEFAULT_PAYMENT_MESSAGE.format(amount=amount_text),
|
text=DEFAULT_PAYMENT_MESSAGE.format(amount=amount_text),
|
||||||
reply_markup=kb,
|
reply_markup=kb,
|
||||||
force_text=True,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@router.callback_query(F.data == "enter_custom_amount_robokassa")
|
@router.callback_query(F.data == "enter_custom_amount_robokassa")
|
||||||
async def process_custom_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
|
async def process_custom_amount_selection(callback_query: types.CallbackQuery, state: FSMContext):
|
||||||
b = back_keyboard("pay_robokassa")
|
b = back_keyboard("pay_robokassa")
|
||||||
await edit_or_send_message(target_message=callback_query.message, text=ENTER_SUM, reply_markup=b, force_text=True)
|
await edit_or_send_message(target_message=callback_query.message, text=ENTER_SUM, reply_markup=b)
|
||||||
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_robokassa)
|
await state.set_state(ReplenishBalanceState.waiting_for_payment_confirmation_robokassa)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user