Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save refet-crypto/c8e2804a4878a011d8ccb5eab4d6a6c2 to your computer and use it in GitHub Desktop.

Select an option

Save refet-crypto/c8e2804a4878a011d8ccb5eab4d6a6c2 to your computer and use it in GitHub Desktop.
seen[crypto] = True
text += (
f"🪙 *{crypto}*\n"
f" Курс: `{float(d['current_course']):,.2f}` ₽\n"
f" Комиссия: {d['comission_percent']}%\n"
f" Мин: {d['min_amount']} ₽ | Макс: {d['max_amount']:,} ₽\n\n"
)
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="💱 Начать обмен", callback_data="start_exchange")],
[InlineKeyboardButton(text="🔙 Назад", callback_data="back_start")],
])
await call.message.edit_text(text, parse_mode="Markdown", reply_markup=kb)
except Exception as e:
await call.message.edit_text(f"❌ Ошибка: {e}")
# ─── Пополнение баланса ──────────────────────────────────────────────────────
@dp.callback_query(F.data == "deposit")
async def deposit_start(call: CallbackQuery, state: FSMContext):
await call.answer()
buttons = [[InlineKeyboardButton(text=lbl, callback_data=f"dep_pay:{key}")]
for key, lbl in PAYMENT_LABELS.items()]
buttons.append([InlineKeyboardButton(text="🔙 Назад", callback_data="back_start")])
await state.set_state(DepositStates.choosing_payment)
await call.message.edit_text(
"➕ *Пополнение баланса*\n\nВыбери способ оплаты:",
parse_mode="Markdown",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
)
@dp.callback_query(DepositStates.choosing_payment, F.data.startswith("dep_pay:"))
async def deposit_amount(call: CallbackQuery, state: FSMContext):
await call.answer()
pm = call.data.split(":", 1)[1]
await state.update_data(payment_method=pm)
label = PAYMENT_LABELS.get(pm, pm)
await state.set_state(DepositStates.entering_amount)
await call.message.edit_text(
f"✅ Способ: *{label}*\n\nВведи сумму пополнения в рублях (мин. 300 ₽):",
parse_mode="Markdown"
)
@dp.message(DepositStates.entering_amount)
async def deposit_create(message: Message, state: FSMContext):
text = message.text.strip().replace(" ", "").replace(",", ".")
try:
amount = float(text)
if amount < 300:
await message.answer("❌ Минимум 300 ₽:")
return
except ValueError:
await message.answer("❌ Введи число, например: 1000")
return
data = await state.get_data()
await message.answer("⏳ Создаю заявку...")
try:
result = await create_order(data["payment_method"], DEPOSIT_WALLET, str(int(amount)))
if result.get("response") != "success":
await message.answer(f"❌ {result.get('message', 'Ошибка')}\n\n/start")
await state.clear()
return
order = result["items"][0]
order_id = order["order_id"]
save_order(order_id, message.from_user.id, "deposit",
float(order["amount_payable"]), "0", "RUB",
data["payment_method"], DEPOSIT_WALLET)
active_orders[order_id] = {
"user_id": message.from_user.id,
"type": "deposit",
"status": "unconfirmed"
}
payment_info = order.get("wallet_payment", "—")
bank = order.get("bank_name", "")
fast_link = order.get("fast_link", "")
msg = (
f"✅ *Заявка на пополнение создана!*\n\n"
f"🆔 ID: `{order_id}`\n"
f"💸 К оплате: *{order['amount_payable']} ₽*\n\n"
)
if bank: msg += f"🏦 Банк: {bank}\n"
msg += f"💳 Реквизиты:\n`{payment_info}`\n\n"
if fast_link: msg += f"🔲 [QR-код]({fast_link})\n\n"
msg += "⏳ После оплаты баланс пополнится автоматически."
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="🔄 Проверить", callback_data=f"check:{order_id}")],
[InlineKeyboardButton(text="❌ Отменить", callback_data=f"cancel:{order_id}")],
])
await message.answer(msg, parse_mode="Markdown", reply_markup=kb)
await state.clear()
except Exception as e:
await message.answer(f"❌ Ошибка: {e}\n\n/start")
await state.clear()
# ─── Обмен → крипта ──────────────────────────────────────────────────────────
@dp.callback_query(F.data == "start_exchange")
async def exchange_start(call: CallbackQuery, state: FSMContext):
await call.answer()
await call.message.edit_text("⏳ Загружаю направления...")
try:
directions = await get_directions()
cryptos = {}
for d in directions:
c = parse_crypto(d["fullname"])
if c not in cryptos:
cryptos[c] = d["id"]
buttons = [[InlineKeyboardButton(text=f"🪙 {c}", callback_data=f"crypto:{did}:{c}")]
for c, did in cryptos.items()]
buttons.append([InlineKeyboardButton(text="🔙 Назад", callback_data="back_start")])
await state.set_state(ExchangeStates.choosing_direction)
await call.message.edit_text(
"💱 *Обмен → крипта*\n\nВыбери криптовалюту:",
parse_mode="Markdown",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
)
except Exception as e:
await call.message.edit_text(f"❌ Ошибка: {e}")
@dp.callback_query(ExchangeStates.choosing_direction, F.data.startswith("crypto:"))
async def exchange_pay(call: CallbackQuery, state: FSMContext):
await call.answer()
_, did, crypto = call.data.split(":", 2)
await state.update_data(crypto=crypto, direction_id=did)
buttons = [[InlineKeyboardButton(text=lbl, callback_data=f"xpay:{key}")]
for key, lbl in PAYMENT_LABELS.items()]
buttons.append([InlineKeyboardButton(text="🔙 Назад", callback_data="start_exchange")])
await state.set_state(ExchangeStates.choosing_payment)
await call.message.edit_text(
f"✅ Крипта: *{crypto}*\n\nВыбери способ оплаты:",
parse_mode="Markdown",
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
)
@dp.callback_query(ExchangeStates.choosing_payment, F.data.startswith("xpay:"))
async def exchange_amount(call: CallbackQuery, state: FSMContext):
await call.answer()
pm = call.data.split(":", 1)[1]
await state.update_data(payment_method=pm, use_balance=False)
label = PAYMENT_LABELS.get(pm, pm)
bal = get_balance(call.from_user.id)
await state.set_state(ExchangeStates.entering_amount)
buttons = []
if bal >= 300:
buttons.append([InlineKeyboardButton(
text=f"💰 Списать с баланса ({bal:,.0f} ₽)",
callback_data="use_balance"
)])
kb = InlineKeyboardMarkup(inline_keyboard=buttons) if buttons else None
await call.message.edit_text(
f"✅ Способ: *{label}*\n"
f"💰 Баланс: *{bal:,.2f} ₽*\n\n"
f"Введи сумму в рублях или спиши с баланса:",
parse_mode="Markdown", reply_markup=kb
)
@dp.callback_query(ExchangeStates.entering_amount, F.data == "use_balance")
async def use_balance_handler(call: CallbackQuery, state: FSMContext):
await call.answer()
bal = get_balance(call.from_user.id)
if bal < 300:
await call.message.answer("❌ Недостаточно средств (мин. 300 ₽).")
return
await state.update_data(amount=str(int(bal)), use_balance=True)
data = await state.get_data()
await state.set_state(ExchangeStates.entering_wallet)
await call.message.edit_text(
f"💰 Будет списано: *{bal:,.0f} ₽* с баланса\n\n"
f"Введи адрес кошелька для *{data['crypto']}*:",
parse_mode="Markdown"
)
@dp.message(ExchangeStates.entering_amount)
async def exchange_amount_typed(message: Message, state: FSMContext):
text = message.text.strip().replace(" ", "").replace(",", ".")
try:
amount = float(text)
if amount < 300:
await message.answer("❌ Минимум 300 ₽:")
return
except ValueError:
await message.answer("❌ Введи число:")
return
await state.update_data(amount=str(int(amount)), use_balance=False)
data = await state.get_data()
await state.set_state(ExchangeStates.entering_wallet)
await message.answer(
f"💰 Сумма: *{int(amount):,} ₽*\n\nВведи адрес кошелька для *{data['crypto']}*:",
parse_mode="Markdown"
)
@dp.message(ExchangeStates.entering_wallet)
async def exchange_create(message: Message, state: FSMContext):
wallet = message.text.strip()
if len(wallet) < 10:
await message.answer("❌ Адрес кошелька слишком короткий:")
return
data = await state.get_data()
use_balance = data.get("use_balance", False)
amount = int(data["amount"])
user_id = message.from_user.id
if use_balance:
bal = get_balance(user_id)
if bal < amount:
await message.answer(f"❌ Недостаточно средств. Баланс: {bal:,.2f} ₽\n\n/start")
await state.clear()
return
# Временно списываем (вернём при ошибке или отмене)
update_balance(user_id, -amount, "pending", "exchange",
f"Обмен {amount} ₽ → {data['crypto']}")
await message.answer("⏳ Создаю заявку...")
try:
result = await create_order(data["payment_method"], wallet, str(amount))
if result.get("response") != "success":
if use_balance:
update_balance(user_id, amount, "pending", "refund", "Ошибка создания")
await message.answer(f"❌ {result.get('message', 'Ошибка')}\n\n/start")
await state.clear()
return
order = result["items"][0]
order_id = order["order_id"]
order_type = "exchange_balance" if use_balance else "exchange"
save_order(order_id, user_id, order_type,
float(order["amount_payable"]), order["amount_receivable"],
data["crypto"], data["payment_method"], wallet)
active_orders[order_id] = {
"user_id": user_id,
"type": "exchange",
"crypto": data["crypto"],
"status": "unconfirmed"
}
payment_info = order.get("wallet_payment", "—")
bank = order.get("bank_name", "")
fast_link = order.get("fast_link", "")
msg = (
f"✅ *Заявка создана!*\n\n"
f"🆔 ID: `{order_id}`\n"
f"💸 Сумма: *{order['amount_payable']} ₽*"
)
if use_balance: msg += " *(с баланса)*"
msg += (
f"\n📦 Получишь: *{order['amount_receivable']} {data['crypto']}*\n"
f"📈 Курс: {float(order['exchange_rate']):,.2f} ₽\n\n"
)
if not use_balance:
if bank: msg += f"🏦 Банк: {bank}\n"
msg += f"💳 Реквизиты:\n`{payment_info}`\n\n"
if fast_link: msg += f"🔲 [QR-код]({fast_link})\n\n"
msg += "⏳ Крипта придёт автоматически после оплаты."
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="🔄 Проверить", callback_data=f"check:{order_id}")],
[InlineKeyboardButton(text="❌ Отменить", callback_data=f"cancel:{order_id}")],
])
await message.answer(msg, parse_mode="Markdown", reply_markup=kb)
await state.clear()
except Exception as e:
if use_balance:
update_balance(user_id, amount, "pending", "refund", "Ошибка")
await message.answer(f"❌ Ошибка: {e}\n\n/start")
await state.clear()
# ─── Статус заявки ───────────────────────────────────────────────────────────
@dp.callback_query(F.data.startswith("check:"))
async def check_status(call: CallbackQuery):
await call.answer("⏳")
order_id = call.data.split(":", 1)[1]
try:
result = await check_order_api(order_id)
orders = result.get("data", {}).get("orders", [])
if not orders:
await call.message.answer("❌ Заявка не найдена.")
return
order = orders[0]
status = order["order_status"]
label = STATUS_LABELS.get(status, status)
text = (
f"📋 *Статус заявки* `{order_id}`\n\n"
f"{label}\n"
f"💸 {order['amount_payable']} ₽ → {order['amount_receivable']}\n"
)
if status == "completed":
await call.message.answer(text + "\n🎉 Готово!", parse_mode="Markdown")
elif status in ("autocanceled", "canceled"):
await call.message.answer(text + "\n/start", parse_mode="Markdown")
else:
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="🔄 Обновить", callback_data=f"check:{order_id}")],
[InlineKeyboardButton(text="❌ Отменить", callback_data=f"cancel:{order_id}")],
])
await call.message.answer(text, parse_mode="Markdown", reply_markup=kb)
except Exception as e:
await call.message.answer(f"❌ Ошибка: {e}")
# ─── Отмена заявки ───────────────────────────────────────────────────────────
@dp.callback_query(F.data.startswith("cancel:"))
async def cancel_confirm(call: CallbackQuery):
await call.answer()
order_id = call.data.split(":", 1)[1]
kb = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text="✅ Да, отменить", callback_data=f"do_cancel:{order_id}")],
[InlineKeyboardButton(text="🔙 Нет", callback_data=f"check:{order_id}")],
])
await call.message.answer(f"❓ Отменить заявку `{order_id}`?",
parse_mode="Markdown", reply_markup=kb)
@dp.callback_query(F.data.startswith("do_cancel:"))
async def do_cancel(call: CallbackQuery):
await call.answer()
order_id = call.data.split(":", 1)[1]
try:
await cancel_order_api(order_id)
active_orders.pop(order_id, None)
update_order_status(order_id, "canceled")
db_order = get_order(order_id)
if db_order and db_order["type"] == "exchange_balance":
refund = db_order["amount_rub"]
update_balance(call.from_user.id, refund, order_id, "refund", f"Возврат #{order_id}")
bal = get_balance(call.from_user.id)
await call.message.answer(
f"🚫 Заявка отменена.\n💰 Возвращено: *{refund:,.0f} ₽*\nБаланс: *{bal:,.2f} ₽*",
parse_mode="Markdown"
)
else:
await call.message.answer(f"🚫 Заявка `{order_id}` отменена.\n\n/start",
parse_mode="Markdown")
except Exception as e:
await call.message.answer(f"❌ Ошибка: {e}")
# ─── Запуск ──────────────────────────────────────────────────────────────────
async def main():
db_init()
logger.info("Бот запущен")
loop = asyncio.get_event_loop()
loop.create_task(poll_orders())
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment