feat(withdraw): add user withdrawal flow using CryptoPay

This commit is contained in:
2026-07-20 20:29:36 +05:00
parent 8d4d75f7fd
commit 8ae14f415f
11 changed files with 269 additions and 137 deletions
+39 -14
View File
@@ -1,23 +1,22 @@
from __future__ import annotations
import asyncio
import os
import asyncio
from aiogram.enums import ParseMode
from aiogram.types import FSInputFile, InlineKeyboardButton, InlineKeyboardMarkup
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup
from config import ADMIN_ID, BOT_USERNAME, ROBSEC_FILE
from db.storage import load_config, save_config, load_stats, save_stats
from config import ADMIN_ID, ROBSEC_FILE
from utils.logging import safe_edit
from db.storage import load_config, save_config
from db.users import all_users, get, save, find_by_username
from keyboards.admin import admin_menu_kb
from models.user import UserProfile
from runtime import get_log_bot
from utils.logging import log_admin, log_admin_document, safe_edit
def is_admin(user_id: int) -> bool:
if user_id == ADMIN_ID:
return True
profile = get(user_id)
return bool(profile and profile.is_admin)
@@ -25,6 +24,7 @@ def is_admin(user_id: int) -> bool:
def toggle_shop() -> bool:
cfg = load_config()
cfg.shop_enabled = not cfg.shop_enabled
save_config(cfg)
return cfg.shop_enabled
@@ -32,6 +32,7 @@ def toggle_shop() -> bool:
def toggle_bot() -> bool:
cfg = load_config()
cfg.bot_enabled = not cfg.bot_enabled
save_config(cfg)
return cfg.bot_enabled
@@ -52,6 +53,7 @@ def update_min_withdraw(value: float) -> None:
def add_treasury(amount_rub: float) -> float:
cfg = load_config()
cfg.treasury += amount_rub
save_config(cfg)
return cfg.treasury
@@ -59,6 +61,7 @@ def add_treasury(amount_rub: float) -> float:
def subtract_treasury(amount_rub: float) -> float:
cfg = load_config()
cfg.treasury = max(0.0, cfg.treasury - amount_rub)
save_config(cfg)
return cfg.treasury
@@ -99,8 +102,12 @@ async def send_user_card(target, uid: int) -> None:
kb = InlineKeyboardMarkup(
inline_keyboard=[
[
InlineKeyboardButton(text=" Баланс", callback_data=f"u_bal_add_{uid}"),
InlineKeyboardButton(text=" Баланс", callback_data=f"u_bal_sub_{uid}"),
InlineKeyboardButton(
text=" Баланс", callback_data=f"u_bal_add_{uid}"
),
InlineKeyboardButton(
text=" Баланс", callback_data=f"u_bal_sub_{uid}"
),
],
[
InlineKeyboardButton(
@@ -110,7 +117,9 @@ async def send_user_card(target, uid: int) -> None:
],
[
InlineKeyboardButton(
text="👑 Убрать админку" if profile.is_admin else "👑 Выдать админку",
text=(
"👑 Убрать админку" if profile.is_admin else "👑 Выдать админку"
),
callback_data=f"u_admin_{uid}",
)
],
@@ -123,15 +132,24 @@ async def send_user_card(target, uid: int) -> None:
await safe_edit(target, text, reply_markup=kb)
async def broadcast(bot, text: str | None = None, photo_id: str | None = None, caption: str | None = None) -> tuple[int, int]:
async def broadcast(
bot,
text: str | None = None,
photo_id: str | None = None,
caption: str | None = None,
) -> tuple[int, int]:
ok = 0
fail = 0
for uid in all_users():
try:
if photo_id:
await bot.send_photo(uid, photo_id, caption=caption or "", parse_mode=ParseMode.HTML)
await bot.send_photo(
uid, photo_id, caption=caption or "", parse_mode=ParseMode.HTML
)
else:
await bot.send_message(uid, text or caption or "-", parse_mode=ParseMode.HTML)
await bot.send_message(
uid, text or caption or "-", parse_mode=ParseMode.HTML
)
ok += 1
except Exception:
fail += 1
@@ -143,6 +161,7 @@ def find_user(query: str) -> int | None:
if query.isdigit():
uid = int(query)
return uid if get(uid) else None
return find_by_username(query)
@@ -150,6 +169,7 @@ def set_balance(uid: int, value: float) -> None:
profile = get(uid)
if not profile:
return
profile.balance = value
save(uid, profile)
@@ -158,6 +178,7 @@ def add_balance(uid: int, amount: float) -> None:
profile = get(uid)
if not profile:
return
profile.balance += amount
save(uid, profile)
@@ -166,6 +187,7 @@ def sub_balance(uid: int, amount: float) -> None:
profile = get(uid)
if not profile:
return
profile.balance = max(0.0, profile.balance - amount)
save(uid, profile)
@@ -174,6 +196,7 @@ def toggle_user_admin(uid: int) -> bool:
profile = get(uid)
if not profile:
return False
profile.is_admin = not profile.is_admin
save(uid, profile)
return profile.is_admin
@@ -183,6 +206,7 @@ def ban_user(uid: int, reason: str) -> None:
profile = get(uid)
if not profile:
return
profile.is_banned = True
profile.ban_reason = reason
save(uid, profile)
@@ -192,6 +216,7 @@ def unban_user(uid: int) -> None:
profile = get(uid)
if not profile:
return
profile.is_banned = False
profile.ban_reason = ""
save(uid, profile)