Данный бот предназначен для скупи токенов Функции Функции пользователя: Регистрация через /start; Указание профиля lolz (обязательно); Загрузка .txt с Twitch-токенами; Автоматическая проверка на уникальность токенов; Получение уведомления о количестве уникальных и дубликатов; Начисление выплат после ручной проверки админом; Просмотр баланса и профиля; Запрос на вывод средств с баланса. Функции администратора: Получение .txt файла с уникальными токенами; Кнопки “Начислить” и “Отклонить”; Ввод суммы вручную; Обработка заявок на вывод (выплата / отказ); Просмотр статистики (токены, заявки, пользователи); Выдача баланса по Telegram ID. import os import asyncio import logging from datetime import datetime from typing import Dict from aiogram import Bot, Dispatcher, F, types from aiogram.enums import ParseMode from aiogram.filters import Command, CommandStart from aiogram.types import Message, CallbackQuery, FSInputFile, ReplyKeyboardMarkup, KeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder from aiogram.fsm.storage.memory import MemoryStorage from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, func, create_engine from sqlalchemy.orm import declarative_base, relationship, sessionmaker from dotenv import load_dotenv # Загрузка .env переменных load_dotenv() BOT_TOKEN = os.getenv("BOT_TOKEN") ADMIN_ID = int(os.getenv("ADMIN_ID", "0")) # Настройка ***** logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # --- База данных --- Base = declarative_base() engine = create_engine("sqlite:///db.sqlite3") SessionLocal = sessionmaker(bind=engine) class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True) telegram_id = Column(Integer, unique=True) username = Column(String) balance = Column(Integer, default=0) lolz_profile = Column(String) uploaded_files = Column(Integer, default=0) class Token(Base): __tablename__ = "tokens" id = Column(Integer, primary_key=True) value = Column(String, unique=True) owner_id = Column(Integer, ForeignKey("users.id")) uploaded_at = Column(DateTime, default=func.now()) review_id = Column(Integer, ForeignKey("token_reviews.id")) class TokenReviewRequest(Base): __tablename__ = "token_reviews" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id")) file_name = Column(String) amount = Column(Integer, nullable=True) status = Column(String, default="pending") created_at = Column(DateTime, default=func.now()) user = relationship("User", backref="token_reviews") tokens = relationship("Token", backref="review") class WithdrawalRequest(Base): __tablename__ = "withdrawals" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id")) amount = Column(Integer) status = Column(String, default="pending") created_at = Column(DateTime, default=func.now()) user = relationship("User", backref="withdrawals") Base.metadata.create_all(bind=engine) # --- Telegram бот --- bot = Bot(token=BOT_TOKEN, parse_mode=ParseMode.HTML) dp = Dispatcher(storage=MemoryStorage()) pending_reviews: Dict[int, int] = {} pending_manual_balance: Dict[int, Dict[str, int]] = {} def format_number(num: int) -> str: return f"{num:,}".replace(",", ".") def main_menu_kb() -> ReplyKeyboardMarkup: return ReplyKeyboardMarkup(keyboard=[ [KeyboardButton(text="Личный кабинет")], [KeyboardButton(text="Указать профиль lolz")], [KeyboardButton(text=" Вывести средства")] ], resize_keyboard=True) @dp.message(CommandStart()) async def start(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if not user: user = User(telegram_id=message.from_user.id, username=message.from_user.username) session.add(user) session.commit() await message.answer("Привет! Укажи профиль lolz и можешь отправить .txt с токенами.", reply_markup=main_menu_kb()) session.close() @dp.message(F.text.lower() == "указать профиль lolz") async def ask_lolz(message: Message): await message.answer("Отправь ссылку на профиль lolz:") @dp.message(F.text.startswith("https://lolz.guru/")) async def save_lolz(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() user.lolz_profile = message.text.strip() session.commit() session.close() await message.answer(" Профиль сохранён.") @dp.message(F.text.lower() == "личный кабинет") async def profile(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() await message.answer( f" @{user.username}\nБаланс: {user.balance}₽\nLolz: {user.lolz_profile or 'не указан'}" ) session.close() @dp.message(F.text == " Вывести средства") async def withdraw(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if user.balance <= 0: await message.answer("Недостаточно средств.") session.close() return if session.query(WithdrawalRequest).filter_by(user_id=user.id, status="pending").first(): await message.answer("У вас уже есть активный запрос.") session.close() return session.add(WithdrawalRequest(user_id=user.id, amount=user.balance)) session.commit() await message.answer(" Запрос на вывод отправлен. Ожидайте.") await bot.send_message(ADMIN_ID, f" Запрос на вывод: @{user.username} | {user.balance}₽\nLolz: {user.lolz_profile}") session.close() @dp.message(F.document) async def handle_file(message: Message): if not message.document.file_name.endswith(".txt"): await message.answer("Принимаются только .txt файлы.") return session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if not user.lolz_profile: await message.answer("Сначала укажи профиль lolz.") session.close() return file = await bot.get_file(message.document.file_id) fbytes = await bot.download_file(file.file_path) lines = set(line.strip() for line in fbytes.read().decode().splitlines() if line.strip()) added = [] for token_str in lines: if not session.query(Token).filter_by(value=token_str).first(): token = Token(value=token_str, owner_id=user.id) session.add(token) added.append(token_str) session.commit() if not added: await message.answer(" Все токены уже были загружены ранее.") session.close() return review = TokenReviewRequest(user_id=user.id, file_name=message.document.file_name) session.add(review) session.commit() for token_str in added: token = session.query(Token).filter_by(value=token_str).first() token.review_id = review.id session.commit() os.makedirs("admin_tokens", exist_ok=True) filename = f"{user.username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" filepath = f"admin_tokens/{filename}" with open(filepath, "w", encoding="utf-8") as f: f.write("\n".join(added)) file_to_send = FSInputFile(filepath) caption = ( f" Заявка на проверку\n@{user.username}\nLolz: {user.lolz_profile}\n" f"Файл: {message.document.file_name}\n Уникальных токенов: {len(added)}" ) kb = InlineKeyboardBuilder() kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}") kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}") await bot.send_document(ADMIN_ID, document=file_to_send, caption=caption, reply_markup=kb.as_markup()) total = len(lines) duplicates = total - len(added) await message.answer( f" Файл получен.\nВсего: {total}\nУникальных: {len(added)}\nДубликатов: {duplicates}" ) session.close() @dp.callback_query(F.data.startswith("review_pay:")) async def review_pay(callback: CallbackQuery): rid = int(callback.data.split(":")[1]) pending_reviews[callback.from_user.id] = rid await callback.message.answer("Введите сумму выплаты пользователю:") @dp.message(F.text.regexp(r"^\d+$")) async def assign_review_or_manual(message: Message): aid = message.from_user.id session = SessionLocal() if aid in pending_reviews: rid = pending_reviews.pop(aid) amount = int(message.text) review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first() if review: review.amount = amount review.status = "paid" review.user.balance += amount session.commit() await message.answer(f" Начислено {amount}₽ пользователю @{review.user.username}.") await bot.send_message(review.user.telegram_id, f" Вам начислено {amount}₽ за токены.") session.close() return if aid in pending_manual_balance and "user_id" in pending_manual_balance[aid]: uid = pending_manual_balance[aid]["user_id"] amount = int(message.text) user = session.query(User).filter_by(telegram_id=uid).first() if user: user.balance += amount session.commit() await message.answer(f" Пользователю @{user.username} выдано {amount}₽.") await bot.send_message(uid, f" Вам начислено {amount}₽ администратором.") session.close() pending_manual_balance.pop(aid, None) @dp.callback_query(F.data.startswith("review_reject:")) async def review_reject(callback: CallbackQuery): rid = int(callback.data.split(":")[1]) session = SessionLocal() review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first() if review: review.status = "rejected" session.commit() await callback.message.answer(" Заявка отклонена.") await bot.send_message(review.user.telegram_id, " Заявка отклонена администратором.") session.close() @dp.message(Command("admin")) async def admin_panel(message: Message): if message.from_user.id != ADMIN_ID: return kb = InlineKeyboardBuilder() kb.button(text=" Активные заявки", callback_data="token_checks") kb.button(text=" Активные выводы", callback_data="active_withdrawals") kb.button(text=" Статистика", callback_data="admin_stats") kb.button(text=" Выдать баланс", callback_data="give_balance_manual") await message.answer("Панель администратора:", reply_markup=kb.as_markup()) @dp.callback_query(F.data == "token_checks") async def token_checks(callback: CallbackQuery): session = SessionLocal() reviews = session.query(TokenReviewRequest).filter_by(status="pending").all() for review in reviews: text = ( f" Заявка #{review.id}\n@{review.user.username}\n" f"Lolz: {review.user.lolz_profile}\nID: {review.user.telegram_id}\n" f" Уникальных токенов: {len(review.tokens)}" ) kb = InlineKeyboardBuilder() kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}") kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}") await callback.message.answer(text, reply_markup=kb.as_markup()) session.close() @dp.callback_query(F.data == "active_withdrawals") async def show_withdrawals(callback: CallbackQuery): session = SessionLocal() requests = session.query(WithdrawalRequest).filter_by(status="pending").all() for req in requests: text = ( f"Запрос #{req.id}\n@{req.user.username} — {req.amount}₽\n" f"Lolz: {req.user.lolz_profile}\nID: {req.user.telegram_id}" ) kb = InlineKeyboardBuilder() kb.button(text=" Выплачено", callback_data=f"mark_paid:{req.id}") kb.button(text=" Отклонить", callback_data=f"reject_withdrawal:{req.id}") await callback.message.answer(text, reply_markup=kb.as_markup()) session.close() @dp.callback_query(F.data.startswith("mark_paid:")) async def mark_paid(callback: CallbackQuery): wid = int(callback.data.split(":")[1]) session = SessionLocal() req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first() if req and req.user.balance >= req.amount: req.status = "paid" req.user.balance -= req.amount session.commit() await callback.message.answer(" Выплата завершена.") await bot.send_message(req.user.telegram_id, f" Выплата {req.amount}₽ выполнена.") session.close() @dp.callback_query(F.data.startswith("reject_withdrawal:")) async def reject_w(callback: CallbackQuery): wid = int(callback.data.split(":")[1]) session = SessionLocal() req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first() if req: req.status = "rejected" session.commit() await callback.message.answer(" Заявка отклонена.") await bot.send_message(req.user.telegram_id, " Заявка на вывод отклонена.") session.close() @dp.callback_query(F.data == "admin_stats") async def show_stats(callback: CallbackQuery): session = SessionLocal() users = session.query(User).count() tokens = session.query(Token).count() reviews = session.query(TokenReviewRequest).count() session.close() await callback.message.answer( f" Статистика:\nПользователей: {format_number(users)}\n" f"Токенов: {format_number(tokens)}\n" f"Заявок: {format_number(reviews)}" ) @dp.callback_query(F.data == "give_balance_manual") async def start_manual_give(callback: CallbackQuery): pending_manual_balance[callback.from_user.id] = {} await callback.message.answer("Введите Telegram ID пользователя:") @dp.message(F.text.regexp(r"^\d{6,}$")) async def save_manual_user_id(message: Message): admin_id = message.from_user.id if admin_id not in pending_manual_balance or "user_id" in pending_manual_balance[admin_id]: return user_id = int(message.text) session = SessionLocal() user = session.query(User).filter_by(telegram_id=user_id).first() session.close() if not user: await message.answer(" Пользователь не найден.") pending_manual_balance.pop(admin_id, None) return pending_manual_balance[admin_id]["user_id"] = user_id await message.answer(f"Пользователь @{user.username} найден. Введите сумму:") # --- Запуск --- async def main(): await dp.start_polling(bot) if __name__ == "__main__": asyncio.run(main()) Python import os import asyncio import logging from datetime import datetime from typing import Dict from aiogram import Bot, Dispatcher, F, types from aiogram.enums import ParseMode from aiogram.filters import Command, CommandStart from aiogram.types import Message, CallbackQuery, FSInputFile, ReplyKeyboardMarkup, KeyboardButton from aiogram.utils.keyboard import InlineKeyboardBuilder from aiogram.fsm.storage.memory import MemoryStorage from sqlalchemy import Column, Integer, String, ForeignKey, DateTime, func, create_engine from sqlalchemy.orm import declarative_base, relationship, sessionmaker from dotenv import load_dotenv # Загрузка .env переменных load_dotenv() BOT_TOKEN = os.getenv("BOT_TOKEN") ADMIN_ID = int(os.getenv("ADMIN_ID", "0")) # Настройка ***** logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # --- База данных --- Base = declarative_base() engine = create_engine("sqlite:///db.sqlite3") SessionLocal = sessionmaker(bind=engine) class User(Base): __tablename__ = "users" id = Column(Integer, primary_key=True) telegram_id = Column(Integer, unique=True) username = Column(String) balance = Column(Integer, default=0) lolz_profile = Column(String) uploaded_files = Column(Integer, default=0) class Token(Base): __tablename__ = "tokens" id = Column(Integer, primary_key=True) value = Column(String, unique=True) owner_id = Column(Integer, ForeignKey("users.id")) uploaded_at = Column(DateTime, default=func.now()) review_id = Column(Integer, ForeignKey("token_reviews.id")) class TokenReviewRequest(Base): __tablename__ = "token_reviews" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id")) file_name = Column(String) amount = Column(Integer, nullable=True) status = Column(String, default="pending") created_at = Column(DateTime, default=func.now()) user = relationship("User", backref="token_reviews") tokens = relationship("Token", backref="review") class WithdrawalRequest(Base): __tablename__ = "withdrawals" id = Column(Integer, primary_key=True) user_id = Column(Integer, ForeignKey("users.id")) amount = Column(Integer) status = Column(String, default="pending") created_at = Column(DateTime, default=func.now()) user = relationship("User", backref="withdrawals") Base.metadata.create_all(bind=engine) # --- Telegram бот --- bot = Bot(token=BOT_TOKEN, parse_mode=ParseMode.HTML) dp = Dispatcher(storage=MemoryStorage()) pending_reviews: Dict[int, int] = {} pending_manual_balance: Dict[int, Dict[str, int]] = {} def format_number(num: int) -> str: return f"{num:,}".replace(",", ".") def main_menu_kb() -> ReplyKeyboardMarkup: return ReplyKeyboardMarkup(keyboard=[ [KeyboardButton(text="Личный кабинет")], [KeyboardButton(text="Указать профиль lolz")], [KeyboardButton(text=" Вывести средства")] ], resize_keyboard=True) @dp.message(CommandStart()) async def start(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if not user: user = User(telegram_id=message.from_user.id, username=message.from_user.username) session.add(user) session.commit() await message.answer("Привет! Укажи профиль lolz и можешь отправить .txt с токенами.", reply_markup=main_menu_kb()) session.close() @dp.message(F.text.lower() == "указать профиль lolz") async def ask_lolz(message: Message): await message.answer("Отправь ссылку на профиль lolz:") @dp.message(F.text.startswith("https://lolz.guru/")) async def save_lolz(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() user.lolz_profile = message.text.strip() session.commit() session.close() await message.answer(" Профиль сохранён.") @dp.message(F.text.lower() == "личный кабинет") async def profile(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() await message.answer( f" @{user.username}\nБаланс: {user.balance}₽\nLolz: {user.lolz_profile or 'не указан'}" ) session.close() @dp.message(F.text == " Вывести средства") async def withdraw(message: Message): session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if user.balance <= 0: await message.answer("Недостаточно средств.") session.close() return if session.query(WithdrawalRequest).filter_by(user_id=user.id, status="pending").first(): await message.answer("У вас уже есть активный запрос.") session.close() return session.add(WithdrawalRequest(user_id=user.id, amount=user.balance)) session.commit() await message.answer(" Запрос на вывод отправлен. Ожидайте.") await bot.send_message(ADMIN_ID, f" Запрос на вывод: @{user.username} | {user.balance}₽\nLolz: {user.lolz_profile}") session.close() @dp.message(F.document) async def handle_file(message: Message): if not message.document.file_name.endswith(".txt"): await message.answer("Принимаются только .txt файлы.") return session = SessionLocal() user = session.query(User).filter_by(telegram_id=message.from_user.id).first() if not user.lolz_profile: await message.answer("Сначала укажи профиль lolz.") session.close() return file = await bot.get_file(message.document.file_id) fbytes = await bot.download_file(file.file_path) lines = set(line.strip() for line in fbytes.read().decode().splitlines() if line.strip()) added = [] for token_str in lines: if not session.query(Token).filter_by(value=token_str).first(): token = Token(value=token_str, owner_id=user.id) session.add(token) added.append(token_str) session.commit() if not added: await message.answer(" Все токены уже были загружены ранее.") session.close() return review = TokenReviewRequest(user_id=user.id, file_name=message.document.file_name) session.add(review) session.commit() for token_str in added: token = session.query(Token).filter_by(value=token_str).first() token.review_id = review.id session.commit() os.makedirs("admin_tokens", exist_ok=True) filename = f"{user.username}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt" filepath = f"admin_tokens/{filename}" with open(filepath, "w", encoding="utf-8") as f: f.write("\n".join(added)) file_to_send = FSInputFile(filepath) caption = ( f" Заявка на проверку\n@{user.username}\nLolz: {user.lolz_profile}\n" f"Файл: {message.document.file_name}\n Уникальных токенов: {len(added)}" ) kb = InlineKeyboardBuilder() kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}") kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}") await bot.send_document(ADMIN_ID, document=file_to_send, caption=caption, reply_markup=kb.as_markup()) total = len(lines) duplicates = total - len(added) await message.answer( f" Файл получен.\nВсего: {total}\nУникальных: {len(added)}\nДубликатов: {duplicates}" ) session.close() @dp.callback_query(F.data.startswith("review_pay:")) async def review_pay(callback: CallbackQuery): rid = int(callback.data.split(":")[1]) pending_reviews[callback.from_user.id] = rid await callback.message.answer("Введите сумму выплаты пользователю:") @dp.message(F.text.regexp(r"^\d+$")) async def assign_review_or_manual(message: Message): aid = message.from_user.id session = SessionLocal() if aid in pending_reviews: rid = pending_reviews.pop(aid) amount = int(message.text) review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first() if review: review.amount = amount review.status = "paid" review.user.balance += amount session.commit() await message.answer(f" Начислено {amount}₽ пользователю @{review.user.username}.") await bot.send_message(review.user.telegram_id, f" Вам начислено {amount}₽ за токены.") session.close() return if aid in pending_manual_balance and "user_id" in pending_manual_balance[aid]: uid = pending_manual_balance[aid]["user_id"] amount = int(message.text) user = session.query(User).filter_by(telegram_id=uid).first() if user: user.balance += amount session.commit() await message.answer(f" Пользователю @{user.username} выдано {amount}₽.") await bot.send_message(uid, f" Вам начислено {amount}₽ администратором.") session.close() pending_manual_balance.pop(aid, None) @dp.callback_query(F.data.startswith("review_reject:")) async def review_reject(callback: CallbackQuery): rid = int(callback.data.split(":")[1]) session = SessionLocal() review = session.query(TokenReviewRequest).filter_by(id=rid, status="pending").first() if review: review.status = "rejected" session.commit() await callback.message.answer(" Заявка отклонена.") await bot.send_message(review.user.telegram_id, " Заявка отклонена администратором.") session.close() @dp.message(Command("admin")) async def admin_panel(message: Message): if message.from_user.id != ADMIN_ID: return kb = InlineKeyboardBuilder() kb.button(text=" Активные заявки", callback_data="token_checks") kb.button(text=" Активные выводы", callback_data="active_withdrawals") kb.button(text=" Статистика", callback_data="admin_stats") kb.button(text=" Выдать баланс", callback_data="give_balance_manual") await message.answer("Панель администратора:", reply_markup=kb.as_markup()) @dp.callback_query(F.data == "token_checks") async def token_checks(callback: CallbackQuery): session = SessionLocal() reviews = session.query(TokenReviewRequest).filter_by(status="pending").all() for review in reviews: text = ( f" Заявка #{review.id}\n@{review.user.username}\n" f"Lolz: {review.user.lolz_profile}\nID: {review.user.telegram_id}\n" f" Уникальных токенов: {len(review.tokens)}" ) kb = InlineKeyboardBuilder() kb.button(text=" Начислить", callback_data=f"review_pay:{review.id}") kb.button(text=" Отклонить", callback_data=f"review_reject:{review.id}") await callback.message.answer(text, reply_markup=kb.as_markup()) session.close() @dp.callback_query(F.data == "active_withdrawals") async def show_withdrawals(callback: CallbackQuery): session = SessionLocal() requests = session.query(WithdrawalRequest).filter_by(status="pending").all() for req in requests: text = ( f"Запрос #{req.id}\n@{req.user.username} — {req.amount}₽\n" f"Lolz: {req.user.lolz_profile}\nID: {req.user.telegram_id}" ) kb = InlineKeyboardBuilder() kb.button(text=" Выплачено", callback_data=f"mark_paid:{req.id}") kb.button(text=" Отклонить", callback_data=f"reject_withdrawal:{req.id}") await callback.message.answer(text, reply_markup=kb.as_markup()) session.close() @dp.callback_query(F.data.startswith("mark_paid:")) async def mark_paid(callback: CallbackQuery): wid = int(callback.data.split(":")[1]) session = SessionLocal() req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first() if req and req.user.balance >= req.amount: req.status = "paid" req.user.balance -= req.amount session.commit() await callback.message.answer(" Выплата завершена.") await bot.send_message(req.user.telegram_id, f" Выплата {req.amount}₽ выполнена.") session.close() @dp.callback_query(F.data.startswith("reject_withdrawal:")) async def reject_w(callback: CallbackQuery): wid = int(callback.data.split(":")[1]) session = SessionLocal() req = session.query(WithdrawalRequest).filter_by(id=wid, status="pending").first() if req: req.status = "rejected" session.commit() await callback.message.answer(" Заявка отклонена.") await bot.send_message(req.user.telegram_id, " Заявка на вывод отклонена.") session.close() @dp.callback_query(F.data == "admin_stats") async def show_stats(callback: CallbackQuery): session = SessionLocal() users = session.query(User).count() tokens = session.query(Token).count() reviews = session.query(TokenReviewRequest).count() session.close() await callback.message.answer( f" Статистика:\nПользователей: {format_number(users)}\n" f"Токенов: {format_number(tokens)}\n" f"Заявок: {format_number(reviews)}" ) @dp.callback_query(F.data == "give_balance_manual") async def start_manual_give(callback: CallbackQuery): pending_manual_balance[callback.from_user.id] = {} await callback.message.answer("Введите Telegram ID пользователя:") @dp.message(F.text.regexp(r"^\d{6,}$")) async def save_manual_user_id(message: Message): admin_id = message.from_user.id if admin_id not in pending_manual_balance or "user_id" in pending_manual_balance[admin_id]: return user_id = int(message.text) session = SessionLocal() user = session.query(User).filter_by(telegram_id=user_id).first() session.close() if not user: await message.answer(" Пользователь не найден.") pending_manual_balance.pop(admin_id, None) return pending_manual_balance[admin_id]["user_id"] = user_id await message.answer(f"Пользователь @{user.username} найден. Введите сумму:") # --- Запуск --- async def main(): await dp.start_polling(bot) if __name__ == "__main__": asyncio.run(main())