173 lines
6.2 KiB
Python
173 lines
6.2 KiB
Python
from aiogram import F, Router
|
|
from aiogram.fsm.context import FSMContext
|
|
from aiogram.types import LinkPreviewOptions, CallbackQuery, Message
|
|
from aiogram.fsm.state import State, StatesGroup
|
|
|
|
from config import ADMIN_ID, BOT_USERNAME
|
|
from db.storage import load_config, load_stats, save_config
|
|
from db.users import get, register, save
|
|
from keyboards.user import back_kb, activate_kb
|
|
from runtime import get_bot, get_log_bot
|
|
from services.withdrawals import create_crypto_check
|
|
from utils.logging import log_admin, safe_edit
|
|
|
|
router = Router(name="user")
|
|
|
|
|
|
class WithdrawState(StatesGroup):
|
|
waiting_for_amount = State()
|
|
|
|
|
|
def _get_profile(callback: CallbackQuery):
|
|
profile = get(callback.from_user.id)
|
|
if profile is None:
|
|
register(callback.from_user.id, callback.from_user.username)
|
|
profile = get(callback.from_user.id)
|
|
return profile
|
|
|
|
|
|
@router.callback_query(F.data == "profile")
|
|
async def cb_profile(callback: CallbackQuery, state: FSMContext):
|
|
await state.clear()
|
|
profile = _get_profile(callback)
|
|
cfg = load_config()
|
|
text = (
|
|
"👤 <b>Ваш профиль</b>\n\n"
|
|
f"ID: <code>{profile.user_id}</code>\n"
|
|
f"📅 Дата регистрации: {profile.registered}\n\n"
|
|
f"🍪 Загружено cookie: <b>{profile.cookies_loaded}</b>\n"
|
|
f"💰 Заработано всего: <b>{profile.total_earned:.2f} ₽</b>\n"
|
|
f"💸 С рефералов: <b>{profile.referral_earned:.2f} ₽</b>\n"
|
|
f"💳 Текущий баланс: <b>{profile.balance:.2f} ₽</b>\n\n"
|
|
f"🔗 Ваша реферальная ссылка:\nhttps://t.me/{BOT_USERNAME}?start=ref_{profile.user_id}\n\n"
|
|
f"💡 Реферальный процент: {cfg.referral_percent}%\n"
|
|
f"💳 Минимальный вывод: {cfg.min_withdraw:.2f} ₽"
|
|
)
|
|
await safe_edit(callback, text, reply_markup=back_kb())
|
|
await callback.answer()
|
|
|
|
|
|
@router.callback_query(F.data == "stats")
|
|
async def cb_stats(callback: CallbackQuery, state: FSMContext):
|
|
await state.clear()
|
|
stats = load_stats()
|
|
text = (
|
|
"📈 <b>Общая статистика</b>\n\n"
|
|
f"👥 Пользователей: <b>{stats.total_users}</b>\n"
|
|
f"🍪 Всего cookie: <b>{stats.total_cookies}</b>\n"
|
|
f"💰 Прямых выплат: <b>{stats.total_paid_direct:.2f} ₽</b>\n"
|
|
f"💸 Реферальных выплат: <b>{stats.total_paid_referral:.2f} ₽</b>"
|
|
)
|
|
await safe_edit(callback, text, reply_markup=back_kb())
|
|
await callback.answer()
|
|
|
|
|
|
@router.callback_query(F.data == "rates")
|
|
async def cb_rates(callback: CallbackQuery, state: FSMContext):
|
|
await state.clear()
|
|
cfg = load_config()
|
|
text = "💰 <b>Актуальные курсы</b>\n\n"
|
|
for rate in cfg.rates.values():
|
|
text += f"🔸 {rate.name}: {rate.price:.2f} ₽\n"
|
|
text += (
|
|
f"\n📊 <b>AVG-система (от {cfg.avg_min_cookies}+ донатных cookie):</b>\n"
|
|
f"Цена за cookie: {cfg.avg_min_price:.2f}-{cfg.avg_max_price:.2f} ₽."
|
|
)
|
|
await safe_edit(callback, text, reply_markup=back_kb())
|
|
await callback.answer()
|
|
|
|
|
|
@router.callback_query(F.data == "withdraw")
|
|
async def cb_withdraw(callback: CallbackQuery, state: FSMContext):
|
|
await state.clear()
|
|
profile = _get_profile(callback)
|
|
cfg = load_config()
|
|
|
|
if profile.balance < cfg.min_withdraw:
|
|
await safe_edit(
|
|
callback,
|
|
f"❌ Недостаточно средств. Баланс: <b>{profile.balance:.2f} ₽</b>\n"
|
|
f"📉 Минимум для вывода: <b>{cfg.min_withdraw:.2f} ₽</b>\n"
|
|
f"🏦 Казна: <b>{cfg.treasury:.2f} ₽</b>",
|
|
reply_markup=back_kb(),
|
|
)
|
|
await callback.answer()
|
|
return
|
|
|
|
await safe_edit(
|
|
callback,
|
|
f"💳 <b>Вывод средств</b>\n\n"
|
|
f"Ваш баланс: <b>{profile.balance:.2f} ₽</b>\n"
|
|
f"Минимум: <b>{cfg.min_withdraw:.2f} ₽</b>\n\n"
|
|
f"Введите сумму для вывода:",
|
|
reply_markup=back_kb(),
|
|
)
|
|
await state.set_state(WithdrawState.waiting_for_amount)
|
|
await callback.answer()
|
|
|
|
|
|
@router.message(WithdrawState.waiting_for_amount)
|
|
async def process_withdraw_amount(message: Message, state: FSMContext):
|
|
profile = _get_profile(message)
|
|
cfg = load_config()
|
|
|
|
try:
|
|
amount = float(message.text)
|
|
except ValueError:
|
|
await message.answer("❌ Введите корректную сумму числом.")
|
|
return
|
|
|
|
if amount <= 0:
|
|
await message.answer("❌ Сумма должна быть больше нуля.")
|
|
return
|
|
|
|
if amount < cfg.min_withdraw:
|
|
await message.answer(f"❌ Минимум для вывода: <b>{cfg.min_withdraw:.2f} ₽</b>.")
|
|
return
|
|
|
|
if amount > profile.balance:
|
|
await message.answer(
|
|
f"❌ Недостаточно средств. Ваш баланс: <b>{profile.balance:.2f} ₽</b>."
|
|
)
|
|
return
|
|
|
|
if amount > cfg.treasury:
|
|
await message.answer(
|
|
f"❌ Недостаточно средств в казне: <b>{cfg.treasury:.2f} ₽</b>."
|
|
)
|
|
return
|
|
|
|
await state.clear()
|
|
await message.answer("⏳ Создаю CryptoBot-чек, подождите...")
|
|
|
|
check_url, check_image_url = await create_crypto_check(amount)
|
|
if not check_url:
|
|
await message.answer(
|
|
"❌ Не удалось создать чек. Попробуйте позже.",
|
|
reply_markup=back_kb(),
|
|
)
|
|
return
|
|
|
|
profile.balance -= amount
|
|
save(profile.user_id, profile)
|
|
cfg.treasury = max(0.0, cfg.treasury - amount)
|
|
|
|
save_config(cfg)
|
|
|
|
await message.answer(
|
|
text=f"🦋 Чек на <b>{amount:.2f} ₽</b>.",
|
|
reply_markup=activate_kb(url=check_url, amount=amount),
|
|
link_preview_options=LinkPreviewOptions(
|
|
url=check_image_url, show_above_text=True
|
|
),
|
|
)
|
|
|
|
bot = get_bot() or message.bot
|
|
await log_admin(
|
|
bot,
|
|
ADMIN_ID,
|
|
f"💸 <b>Вывод средств</b>\n@{profile.username or '—'} (<code>{profile.user_id}</code>)\n"
|
|
f"Сумма: {amount:.2f} ₽\nЧек: {check_url}",
|
|
get_log_bot(),
|
|
)
|