Advertisement
Dsidorenko779

main.py

Mar 19th, 2025 (edited)
136
0
364 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 66.69 KB | Gaming | 0 0
  1. import random
  2. import os
  3. import string
  4. import logging
  5. import re
  6. from database import get_all_users  # Импортируем функцию
  7. from database import execute_query  # или другой модуль, где эта функция
  8. from aiogram import Bot, Dispatcher, types
  9. from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery
  10. from aiogram.dispatcher.filters import Command  # Импорт Command
  11. from aiogram.utils import executor
  12. import time
  13. from aiogram.dispatcher.filters import Text
  14. from apscheduler.schedulers.asyncio import AsyncIOScheduler
  15. from aiogram.dispatcher.filters.state import StatesGroup, State
  16. from aiogram.dispatcher.filters.state import State, StatesGroup
  17. class BalanceInput(StatesGroup):
  18.     waiting_for_number_and_amount = State()
  19. from aiogram.dispatcher import FSMContext
  20. import sqlite3
  21. from datetime import datetime
  22. from datetime import timedelta
  23. from database import get_user_numbers
  24. from aiogram.types import ChatPermissions
  25. from collections import defaultdict
  26. from stats import user_stats, update_statistics  # Импортируем из stats.py
  27. import pytz
  28. from aiogram.contrib.fsm_storage.memory import MemoryStorage
  29. import json
  30.  
  31. logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
  32.  
  33. # Функция для логирования user_stats и user_numbers
  34. def log_data(tag="DEBUG"):
  35.     logging.info(f"🟡 {tag} | user_numbers = {json.dumps(user_numbers, default=str, indent=2)}")
  36.     logging.info(f"🟡 {tag} | user_stats = {json.dumps(user_stats, default=str, indent=2)}")
  37.  
  38. logging.basicConfig(level=logging.INFO)
  39. confirmed_numbers = []
  40. rejected_numbers = []
  41. # === 🔧 Настройки ===
  42. TOKEN = ""  # Укажи свой токен
  43. ADMIN_GROUP_ID = -1002329021975  # ID группы админов
  44. REPORTS_CHAT_ID = -4795044900  # ID чата для отчётов (замени на нужный)
  45. ADMIN_USER_IDS = {8101813488, 987654321}  # Выдача прав админа
  46. WITHDRAW_GROUP_ID = -1002290860098  # ID группы для заявок на вывод
  47. CHANNEL_USERNAME = "@legionWA_Rent"  # ID вашего канала (например, "@your_channel")
  48.  
  49. # Функция для подключения к базе данных
  50. def get_db_connection():
  51.     return sqlite3.connect("stats.db")
  52.  
  53. # Создание таблицы, если её нет
  54. with get_db_connection() as conn:
  55.     cursor = conn.cursor()
  56.     cursor.execute('''CREATE TABLE IF NOT EXISTS stats (
  57.                        user_id INTEGER PRIMARY KEY,
  58.                        confirmed INTEGER DEFAULT 0,
  59.                        skipped INTEGER DEFAULT 0,
  60.                        dropped INTEGER DEFAULT 0,
  61.                        errors INTEGER DEFAULT 0,
  62.                        all_numbers INTEGER DEFAULT 0,
  63.                        balance INTEGER DEFAULT 0,
  64.                        daily_earnings INTEGER DEFAULT 0)''')
  65.     conn.commit()
  66.  
  67. # Функция для получения статистики пользователя
  68. def get_user_stats(user_id):
  69.     with get_db_connection() as conn:
  70.         cursor = conn.cursor()
  71.         cursor.execute("SELECT * FROM stats WHERE user_id = ?", (user_id,))
  72.         stats = cursor.fetchone()
  73.         if not stats:
  74.             cursor.execute("INSERT INTO stats (user_id) VALUES (?)", (user_id,))
  75.             conn.commit()
  76.             return get_user_stats(user_id)
  77.         return stats
  78.  
  79. # Функция обновления статистики
  80. def update_stat(user_id, column, value):
  81.     with get_db_connection() as conn:
  82.         cursor = conn.cursor()
  83.         cursor.execute(f"UPDATE stats SET {column} = {column} + ? WHERE user_id = ?", (value, user_id))
  84.         conn.commit()
  85.         logging.info(f"User {user_id}: {column} updated by {value}")
  86.  
  87. # Структура для хранения статистики пользователей
  88. user_stats = defaultdict(lambda: {"hold": 0, "failed": 0, "skipped": 0, "added": 0})
  89. user_numbers = {}
  90.  
  91. # Функция обновления статистики
  92. async def update_user_stats(user_id):
  93.     user_stats[user_id]['added'] += 1  # Увеличиваем количество добавленных номеров
  94.  
  95. # Функция сброса статистики в 00:00 МСК
  96. async def reset_stats():
  97.     while True:
  98.         now = datetime.now()
  99.         moscow_time = now + timedelta(hours=3)  # Перевод на МСК
  100.         reset_time = moscow_time.replace(hour=0, minute=0, second=0, microsecond=0)
  101.         sleep_time = (reset_time - moscow_time).total_seconds()
  102.         if sleep_time < 0:
  103.             sleep_time += 86400  # Перекатываем на следующий день
  104.         await asyncio.sleep(sleep_time)
  105.         user_stats.clear()
  106.         logging.info("Статистика сброшена")
  107.  
  108.  
  109. bot = Bot(token=TOKEN)
  110. storage = MemoryStorage()  # Хранилище состояний
  111. dp = Dispatcher(bot, storage=storage)  # Передаем storage в Dispatcher
  112.  
  113.  
  114. # Список пользователей и их балансов
  115. # Инициализация user_info как словаря для хранения информации о пользователе
  116. user_info = {}
  117. user_statistics = {}
  118. user_stats = {}
  119. user_balances = {}  # Основной баланс
  120. user_bonus_balances = {}  # Бонусный баланс
  121. user_numbers = {}   # {номер: {"user_id": id, "msg_id": msg_id, "photo_sent": False, "confirmed": False}}
  122.  
  123. # Словарь для хранения статистики пользователей
  124. user_stats = {}
  125.  
  126. @dp.callback_query_handler(lambda c: c.data == "update_stats")
  127. async def refresh_stats(callback_query: types.CallbackQuery):
  128.     user_id = callback_query.from_user.id
  129.  
  130.     # Проверяем, если статистика пользователя существует
  131.     if user_id not in user_stats:
  132.         await callback_query.answer("❌ Статистика не найдена.")
  133.         return
  134.  
  135.     stats = user_stats[user_id]
  136.     stats_message = (
  137.         f"📊 Ваша статистика:\n"
  138.         f"🔹 Добавлено номеров: {stats['added']}\n"
  139.         f"🔹 В холде: {stats['hold']}\n"
  140.         f"🔹 Пропущено номеров: {stats['skipped']}\n"
  141.         f"🔹 Слетевших номеров: {stats['dropped']}\n"
  142.         f"🔹 Слеты: {stats['failed']}"
  143.     )
  144.  
  145.     # Отправляем сообщение с обновленной статистикой
  146.     await callback_query.answer(stats_message)
  147.  
  148. def get_user_stats(user_id: int):
  149.     """ Функция получения статистики пользователя, если её нет — создаем. """
  150.     if user_id not in user_stats:
  151.         user_stats[user_id] = {
  152.             "hold": 0,     # В холде
  153.             "failed": 0,   # Слеты
  154.             "skipped": 0,  # Пропуски
  155.             "dropped": 0,  # Слеты
  156.             "added": 0     # Добавлено
  157.         }
  158.     return user_stats[user_id]
  159.  
  160. # Определение состояний
  161. class ReportForm(StatesGroup):
  162.     waiting_for_number = State()  # Состояние для ввода номера
  163.  
  164. # === 🎛 Классы для состояний ===
  165. class ReportForm(StatesGroup):
  166.     waiting_for_number = State()
  167.     waiting_for_time = State()
  168.  
  169. # === Подключение к базе данных ===
  170. def get_user_numbers(user_id, status):
  171.     conn = sqlite3.connect("database.db")
  172.     cursor = conn.cursor()
  173.     cursor.execute("SELECT phone FROM user_numbers WHERE user_id=? AND status=?", (user_id, status))
  174.     numbers = cursor.fetchall()
  175.     conn.close()
  176.     return [num[0] for num in numbers]
  177.  
  178. # === Проверка на администратора ===
  179. def is_admin(user_id):
  180.     return user_id in ADMIN_IDS
  181.  
  182. #Словарь для хранения информации о подписке пользователей
  183. subscribed_users = {}
  184.  
  185. # Проверка подписки на канал
  186. async def is_subscribed(user_id: int) -> bool:
  187.     try:
  188.         # Проверка, является ли пользователь подписчиком канала
  189.         member = await bot.get_chat_member(CHANNEL_ID, user_id)
  190.         # Если статус пользователя "member" или выше, то он подписан
  191.         return member.status in ['member', 'administrator', 'creator']
  192.     except Exception:
  193.         return False
  194.        
  195. #Инициализация базы данных SQLite
  196. def init_db():
  197.     conn = sqlite3.connect("users.db")
  198.     cursor = conn.cursor()
  199.     cursor.execute('''CREATE TABLE IF NOT EXISTS users (
  200.        user_id INTEGER PRIMARY KEY,
  201.        username TEXT,
  202.        referral_code TEXT,
  203.        referred_by INTEGER,
  204.        balance REAL DEFAULT 0.0
  205.    )''')
  206.     conn.commit()
  207.     conn.close()
  208.    
  209. #Функция для создания нового пользователя в базе данных
  210. def add_user(user_id, username, referral_code, referred_by=None):
  211.     conn = sqlite3.connect('users.db')
  212.     cursor = conn.cursor()
  213.     cursor.execute("""
  214.    CREATE TABLE IF NOT EXISTS users (
  215.        user_id INTEGER PRIMARY KEY,
  216.        username TEXT,
  217.        referral_code TEXT,
  218.        referred_by INTEGER,
  219.        balance REAL DEFAULT 0
  220.    )
  221.    """)
  222.     cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
  223.                    (user_id, username, referral_code, referred_by))
  224.     conn.commit()
  225.     conn.close()
  226.  
  227. # Функция для получения информации о пользователе по ID
  228. def get_user(user_id):
  229.     conn = sqlite3.connect('users.db')
  230.     cursor = conn.cursor()
  231.     cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
  232.     user = cursor.fetchone()
  233.     conn.close()
  234.     return user
  235.  
  236. # Функция для получения пользователя по реферальному коду
  237. def get_user_by_referral_code(referral_code):
  238.     conn = sqlite3.connect('users.db')
  239.     cursor = conn.cursor()
  240.     cursor.execute("SELECT * FROM users WHERE referral_code=?", (referral_code,))
  241.     user = cursor.fetchone()
  242.     conn.close()
  243.     return user
  244.  
  245. # Функция для обновления баланса пользователя
  246. def update_balance(user_id, amount):
  247.     conn = sqlite3.connect('users.db')
  248.     cursor = conn.cursor()
  249.     cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id=?", (amount, user_id))
  250.     conn.commit()
  251.     conn.close()
  252.  
  253. # Генерация случайного реферального кода
  254. def generate_referral_code():
  255.     return ''.join(random.choices(string.ascii_uppercase + string.digits, k=8))
  256.    
  257. def get_all_users():
  258.     conn = sqlite3.connect("bot_database.db")
  259.     cursor = conn.cursor()
  260.     cursor.execute("SELECT user_id FROM users")
  261.     users = [row[0] for row in cursor.fetchall()]
  262.     conn.close()
  263.     return users
  264.  
  265. # Обновленный main_menu с кнопкой "Статистика"
  266. def main_menu():
  267.     menu = InlineKeyboardMarkup(row_width=2)
  268.     menu.add(
  269.         InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
  270.         InlineKeyboardButton("📊 Статистика", callback_data="stats_today")
  271.     )
  272.     menu.add(
  273.         InlineKeyboardButton("📋 Отчёт", callback_data="send_report"),
  274.         InlineKeyboardButton("💰 Баланс", callback_data="withdraw")
  275.     )
  276.     menu.add(
  277.         InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system"),
  278.         InlineKeyboardButton("❓ FAQ", callback_data="faq")
  279.     )
  280.     return menu
  281.  
  282. # === 📌 Обработчик команды /start ===
  283. @dp.message_handler(commands=['start'])
  284. async def start(message: types.Message):
  285.     user_id = message.from_user.id
  286.  
  287.     if user_id not in subscribed_users or not subscribed_users[user_id]:
  288.         keyboard = InlineKeyboardMarkup()
  289.         keyboard.add(InlineKeyboardButton("🔗 Подписаться на канал", url="https://t.me/legionWA_Rent"))
  290.         keyboard.add(InlineKeyboardButton("🔄 Проверить подписку", callback_data="check_subscription"))
  291.        
  292.         # Запрашиваем подписку перед тем, как показывать главное меню
  293.         await message.answer("Для того, чтобы продолжить, подпишитесь на наш канал:", reply_markup=keyboard)
  294.         subscribed_users[user_id] = False
  295.     else:
  296.         # Если подписка выполнена, показываем главное меню
  297.         await message.answer("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
  298.  
  299. @dp.message_handler(state=ReportForm.waiting_for_number)
  300. async def get_number(message: types.Message, state: FSMContext):
  301.     if not message.text.startswith("+7") or not message.text[1:].isdigit():
  302.         await message.answer("❌ Неверный формат номера! Введите в формате: `+7XXXXXXXXXX`", parse_mode="Markdown")
  303.         return
  304.  
  305.     await state.update_data(number=message.text)
  306.     await message.answer("⏰ Теперь введите время связки (МСК) в формате `HH:MM`")
  307.     await ReportForm.waiting_for_time.set()
  308.  
  309. @dp.message_handler(state=ReportForm.waiting_for_time)
  310. async def get_time(message: types.Message, state: FSMContext):
  311.     user_data = await state.get_data()
  312.     number = user_data["number"]
  313.     time = message.text.strip()
  314.  
  315.     if not time.replace(":", "").isdigit() or len(time) not in [4, 5]:
  316.         await message.answer("❌ Неверный формат! Введите время в формате `HH:MM`")
  317.         return
  318.  
  319.     report_text = f"📢 Новый отчёт!\n📞 Номер: {number}\n⏰ Время связки (МСК): {time}"
  320.     await bot.send_message(REPORTS_CHAT_ID, report_text)
  321.  
  322.     await message.answer("✅ Отчёт отправлен администраторам!", reply_markup=main_menu())
  323.     await state.finish()
  324.  
  325. # Обработчик команды /start с реферальной ссылкой
  326. @dp.message_handler(commands=['start'])
  327. async def start(message: types.Message):
  328.     referral_code = message.text.split()[-1]  # Получаем реферальный код
  329.     user_id = message.from_user.id
  330.  
  331.     # Проверяем, если пользователь перешел по реферальной ссылке
  332.     if referral_code:
  333.         referred_by_user = get_user_by_referral_code(referral_code)
  334.         if referred_by_user:
  335.             add_user(user_id, message.from_user.username, generate_referral_code(), referred_by=referred_by_user[0])
  336.             await message.answer(f"Вы зарегистрированы через реферальную ссылку @{referred_by_user[1]}.")
  337.             await message.answer("Добро пожаловать в систему!")
  338.  
  339.             # Отчисляем 10% владельцу ссылки
  340.             referral_bonus = 10  # 10% от суммы, которую мы хотим начислить
  341.             update_balance(referred_by_user[0], referral_bonus)
  342.  
  343.             # Отправляем владельцу ссылки информацию о новом пользователе
  344.             await bot.send_message(referred_by_user[0], f"Получено {referral_bonus} долларов за реферала @{message.from_user.username}!")
  345.  
  346.         else:
  347.             await message.answer("❌ Неверная реферальная ссылка.")
  348.     else:
  349.         # Если реферальной ссылки нет, то просто генерируем новый код
  350.         referral_code = generate_referral_code()
  351.         add_user(user_id, message.from_user.username, referral_code)
  352.         await message.answer("Привет, добро пожаловать в наш бот! Используйте /referral для получения своей реферальной ссылки.")
  353.  
  354. @dp.callback_query_handler(lambda c: c.data == "referral_system")
  355. async def referral_system(call: types.CallbackQuery):
  356.     user_id = call.from_user.id
  357.  
  358.     # Получаем username бота
  359.     bot_username = (await bot.get_me()).username
  360.  
  361.     if bot_username:
  362.         referral_link = f"https://t.me/{bot_username}?start={user_id}"  # Генерируем ссылку для пользователя
  363.     else:
  364.         referral_link = "Ошибка: имя пользователя бота не настроено."
  365.  
  366.     # Создаем клавиатуру с кнопкой "Назад"
  367.     keyboard = InlineKeyboardMarkup(row_width=1)
  368.     keyboard.add(
  369.         InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  370.     )
  371.  
  372.     # Редактируем текущее сообщение, а не отправляем новое
  373.     await call.message.edit_text(
  374.         f"Если вы пригласите своего друга, то будете получать с каждого его отстоявшего номера по 10%.\n\n"
  375.         f"Вот ваша реферальная ссылка: {referral_link}",
  376.         reply_markup=keyboard
  377.     )
  378.     await call.answer()  # Закрываем индикатор загрузки
  379.  
  380. @dp.callback_query_handler(lambda c: c.data == "stats_today")
  381. async def show_stats(callback_query: types.CallbackQuery):
  382.     user_id = callback_query.from_user.id
  383.     stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0})
  384.  
  385.     # Логируем статистику перед формированием текста
  386.     logging.info(f"Показ статистики для пользователя {user_id}: {stats}")
  387.  
  388.     # Формируем текст с актуальной статистикой
  389.     text = (
  390.         f"📊 *Ваша статистика:*\n"
  391.         f"├ В холде: {stats['hold']}\n"
  392.         f"├ Слетов: {stats['failed']}\n"
  393.         f"├ Пропущено: {stats['skipped']}\n"
  394.         f"├ Слетело: {stats['dropped']}\n"
  395.         f"└ Добавлено: {stats['added']}\n"  # Добавлена строка для статистики по добавленным номерам
  396.     )
  397.  
  398.     # Обновляем клавиатуру
  399.     keyboard = InlineKeyboardMarkup().add(
  400.         InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
  401.         InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  402.     )
  403.  
  404.     await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
  405.     await callback_query.answer()
  406.  
  407. # Обновление статистики вручную
  408. @dp.callback_query_handler(lambda c: c.data == "update_stats")
  409. async def refresh_stats(callback_query: types.CallbackQuery):
  410.     user_id = callback_query.from_user.id
  411.     # Получаем статистику пользователя
  412.     stats = user_stats.get(user_id, {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0})  # Добавлено "added"
  413.  
  414.     # Формируем текст с актуальной статистикой
  415.     text = (
  416.         f"📊 *Ваша статистика:*\n"
  417.         f"├ В холде: {stats['hold']}\n"
  418.         f"├ Слетов: {stats['failed']}\n"
  419.         f"├ Пропущено: {stats['skipped']}\n"
  420.         f"├ Слетело: {stats['dropped']}\n"
  421.         f"└ Добавлено: {stats['added']}\n"  # Добавлена строка для статистики по добавленным номерам
  422.     )
  423.  
  424.     # Обновляем клавиатуру
  425.     keyboard = InlineKeyboardMarkup().add(
  426.         InlineKeyboardButton("🔄 Обновить статистику", callback_data="update_stats"),
  427.         InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  428.     )
  429.    
  430.     # Обновляем сообщение с актуальной статистикой
  431.     await callback_query.message.edit_text(text, reply_markup=keyboard, parse_mode="Markdown")
  432.     await callback_query.answer()  # Подтверждаем обработку кнопки
  433.  
  434. # === Обработчик проверки подписки ===
  435. @dp.callback_query_handler(lambda c: c.data == "check_subscription")
  436. async def check_subscription(call: types.CallbackQuery):
  437.     user_id = call.from_user.id
  438.  
  439.     try:
  440.         chat_member = await bot.get_chat_member(CHANNEL_USERNAME, user_id)
  441.         if chat_member.status in ['member', 'administrator', 'creator']:
  442.             subscribed_users[user_id] = True
  443.             # Кнопка для начала работы
  444.             start_keyboard = InlineKeyboardMarkup().add(
  445.                 InlineKeyboardButton("🚀 Начать работу", callback_data="start_work")
  446.             )
  447.             await call.message.answer("✅ Вы подписаны на канал. Теперь можно использовать все функции бота.", reply_markup=start_keyboard)
  448.         else:
  449.             await call.message.answer("❌ Вы не подписаны на канал. Пожалуйста, подпишитесь, чтобы продолжить.")
  450.     except Exception as e:
  451.         await call.message.answer(f"❌ Ошибка при проверке подписки: {e}")
  452.  
  453.     await call.answer()
  454.  
  455. # === 📌 Обработчик кнопки "Начать работу" ===
  456. @dp.callback_query_handler(lambda c: c.data == "start_work")
  457. async def start_work(callback_query: types.CallbackQuery):
  458.     # Действия, которые выполняются при нажатии на кнопку "Начать работу"
  459.    
  460.     # Подтверждение действия
  461.     await callback_query.answer("👨‍💻 Вы начали работу!")
  462.  
  463.     # Отправляем главное меню с кнопкой "Статистика"
  464.     await callback_query.message.edit_text("🚀 Добро пожаловать! Выберите действие:", reply_markup=main_menu())
  465.        
  466. #=== 📤 Сдать номер ===
  467. # Обработчик нажатия кнопки "submit_number"
  468. @dp.callback_query_handler(lambda c: c.data == "submit_number")
  469. async def submit_number(call: types.CallbackQuery):
  470.     # Создаем клавиатуру с кнопкой "Назад"
  471.     keyboard = InlineKeyboardMarkup(row_width=1)
  472.     keyboard.add(
  473.         InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  474.     )
  475.    
  476.     # Редактируем текущее сообщение вместо отправки нового
  477.     await call.message.edit_text("📲 Введите номер в формате: `+7XXXXXXXXXX`", parse_mode="Markdown", reply_markup=keyboard)
  478.     await call.answer()
  479.  
  480. # Обработчик на ввод номера
  481. @dp.message_handler(lambda message: message.text.startswith("+7"))
  482. async def receive_number(message: types.Message):
  483.     user_id = message.from_user.id
  484.     username = message.from_user.username or "Без имени"
  485.     number = message.text.strip()
  486.  
  487.     logging.info(f"📌 Пользователь {user_id} ({username}) ввел номер: {number}")
  488.  
  489.     # Проверка на уникальность номера
  490.     if number in user_numbers and user_numbers[number].get("confirmed"):
  491.         await message.answer("❌ Этот номер уже подтвержден.")
  492.         return
  493.  
  494.     # Добавляем номер в user_numbers с флагом, что он еще не подтвержден
  495.     user_numbers[number] = {"user_id": user_id, "confirmed": False}
  496.  
  497.     admin_message = f"📞 *Новый номер от @{username} (ID: `{user_id}`):*\n📲 `{number}`"
  498.  
  499.     # Создание кнопок для администратора
  500.     keyboard = InlineKeyboardMarkup(row_width=2)
  501.     keyboard.add(
  502.         InlineKeyboardButton("Взять номер", callback_data=f"take_number_{number}"),
  503.         InlineKeyboardButton("Пропустить", callback_data=f"skip_number_{number}")
  504.     )
  505.  
  506.     try:
  507.         # Отправляем сообщение в группу администраторов
  508.         msg = await bot.send_message(ADMIN_GROUP_ID, admin_message, parse_mode="Markdown", reply_markup=keyboard)
  509.         user_numbers[number]["msg_id"] = msg.message_id
  510.         logging.info(f"✅ Номер {number} отправлен в очередь для администратора.")
  511.         await message.answer("✅ Номер отправлен в очередь, ожидайте.")
  512.     except Exception as e:
  513.         await message.answer("❌ Ошибка отправки номера. Проверь настройки группы.")
  514.         logging.error(f"Ошибка отправки в группу: {e}")
  515.  
  516. # Обработчик нажатия кнопки "Взять номер"
  517. @dp.callback_query_handler(lambda c: c.data.startswith("take_number_"))
  518. async def take_number(call: types.CallbackQuery):
  519.     number = call.data.split("_")[-1]
  520.     user_info = user_numbers.get(number)
  521.  
  522.     if not user_info:
  523.         await call.answer("❌ Номер не найден.")
  524.         return
  525.  
  526.     user_id = user_info["user_id"]
  527.  
  528.     # Логируем информацию о пользователе
  529.     logging.info(f"Номер {number} найден для пользователя {user_id}. Обновляем его статус.")
  530.  
  531.     # Обновляем статус номера на "added"
  532.     user_info["status"] = "added"
  533.     logging.info(f"Статус номера {number} изменён на 'added'.")
  534.  
  535.     # Обновляем статистику пользователя для действия "added"
  536.     logging.info(f"Обновляем статистику для пользователя {user_id} с действием 'added'.")
  537.     update_statistics(user_id, "added")
  538.     logging.info(f"Статистика для пользователя {user_id} обновлена после добавления номера {number}.")
  539.  
  540.     # Уведомляем пользователя о том, что номер добавлен
  541.     await bot.send_message(user_id, f"✅ Ваш номер {number} был добавлен в систему.")
  542.  
  543.     # Логирование действия
  544.     logging.info(f"Номер {number} был добавлен для пользователя {user_id}.")
  545.  
  546.     # Отправляем уведомление администратору
  547.     await bot.send_message(ADMIN_GROUP_ID, f"✅ Номер {number} был добавлен и принят в систему.")
  548.  
  549.     # Удаляем сообщение с кнопками
  550.     await call.message.delete()
  551.  
  552.     # Отвечаем на callback
  553.     await call.answer()
  554.  
  555. # Обработчик для пропуска номера
  556. @dp.callback_query_handler(lambda c: c.data.startswith("skip_number_"))
  557. async def skip_number(call: types.CallbackQuery):
  558.     number = call.data.split("_")[-1]
  559.     user_info = user_numbers.get(number)
  560.  
  561.     if not user_info:
  562.         await call.answer("❌ Номер не найден.")
  563.         return
  564.  
  565.     # Удаляем сообщение с номером
  566.     await bot.delete_message(chat_id=ADMIN_GROUP_ID, message_id=user_info["msg_id"])
  567.  
  568.     # Уведомляем администратора о пропуске
  569.     await bot.send_message(ADMIN_GROUP_ID, f"❌ Номер {number} был пропущен.")
  570.  
  571.     # Отвечаем на callback
  572.     await call.answer()
  573.  
  574.     # Удаляем номер из системы
  575.     del user_numbers[number]
  576.  
  577. # Обработчик для получения номера от администратора
  578. @dp.message_handler(content_types=["photo"])
  579. async def admin_reply_photo(message: types.Message):
  580.     if not message.reply_to_message or message.chat.id != ADMIN_GROUP_ID:
  581.         return
  582.  
  583.     text = message.reply_to_message.text or ""
  584.     number = re.search(r"\+7\d{10}", text)
  585.  
  586.     if not number:
  587.         await message.reply("❌ Ошибка: номер не найден в сообщении.")
  588.         return
  589.  
  590.     number = number.group(0)
  591.  
  592.     if number not in user_numbers:
  593.         user_numbers[number] = {"user_id": message.from_user.id, "status": "pending"}
  594.  
  595.     user_id = user_numbers[number]["user_id"]
  596.  
  597.     keyboard = InlineKeyboardMarkup()
  598.     keyboard.add(
  599.         InlineKeyboardButton("✅ Код введен", callback_data=f"code_entered_{number}"),
  600.         InlineKeyboardButton("❌ Код не введен", callback_data=f"code_not_entered_{number}")
  601.     )
  602.  
  603.     try:
  604.         photo = message.photo[-1].file_id
  605.         msg = await bot.send_photo(user_id, photo=photo, caption="🔑 Введите полученный код:", reply_markup=keyboard)
  606.  
  607.         user_numbers[number]["msg_id"] = msg.message_id
  608.         user_numbers[number]["photo_sent"] = True
  609.  
  610.         await message.reply("✅ Код отправлен пользователю.")
  611.     except Exception as e:
  612.         logging.exception(f"Ошибка отправки фото пользователю: {e}")
  613.         await message.reply("❌ Ошибка отправки фото пользователю.")
  614.  
  615. # Функции для извлечения номера
  616. def normalize_number(number: str) -> str:
  617.     """Приводит номер к единому формату +7XXXXXXXXXX"""
  618.     number = number.replace(" ", "").strip()
  619.     if number.startswith("8"):
  620.         number = "+7" + number[1:]
  621.     return number
  622.  
  623. def get_number_from_message(message: types.Message) -> str:
  624.     """Извлекает номер телефона из ответа администратора."""
  625.     if message.reply_to_message:
  626.         match = re.search(r"\+7\d{10}", message.reply_to_message.text or "")
  627.         return match.group(0) if match else None
  628.     return None
  629.        
  630. @dp.callback_query_handler(lambda c: c.data == "send_report")
  631. async def send_report(call: types.CallbackQuery):
  632.     # Ссылка на чат для отчетов
  633.     report_chat_link = "https://t.me/report_legion"  # Укажите правильную ссылку на ваш чат
  634.  
  635.     # Создаем клавиатуру с кнопкой "Назад"
  636.     keyboard = InlineKeyboardMarkup(row_width=1)
  637.     keyboard.add(
  638.         InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  639.     )
  640.  
  641.     # Редактируем текущее сообщение, а не отправляем новое
  642.     await call.message.edit_text(
  643.         f"📌 Для отправки отчета, пожалуйста, перейдите в [чат для отчетов]({report_chat_link})",
  644.         parse_mode="Markdown",
  645.         reply_markup=keyboard
  646.     )
  647.  
  648.     # Завершаем обработку callback
  649.     await call.answer()
  650.  
  651. @dp.message_handler(commands=['get_chat_id'])
  652. async def get_chat_id(message: types.Message):
  653.     chat_id = message.chat.id
  654.     await message.answer(f"Chat ID: {chat_id}")
  655.  
  656. @dp.message_handler(Command('ban'))
  657. async def ban_user(message: types.Message):
  658.     """Бан пользователя с указанием времени и причины."""
  659.    
  660.     # Проверяем, является ли пользователь администратором
  661.     if message.chat.type != "private":
  662.         admins = await bot.get_chat_administrators(message.chat.id)
  663.         if message.from_user.id not in [admin.user.id for admin in admins]:
  664.             await message.answer("❌ Вы не являетесь администратором.")
  665.             return
  666.  
  667.     # Разбираем команду, ожидаем формат: /ban @username 10m причина
  668.     parts = message.text.split(' ')
  669.     if len(parts) < 3:
  670.         await message.answer("❌ Неверный формат команды. Используйте: `/ban @username <время> <причина>`", parse_mode="Markdown")
  671.         return
  672.    
  673.     username = parts[1]  # @username
  674.     time_duration = parts[2]  # Время (например, 10m, 1h, 1d)
  675.     reason = " ".join(parts[3:]) if len(parts) > 3 else "Не указана"  # Причина (если указана)
  676.  
  677.     # Проверка на правильность времени
  678.     try:
  679.         if time_duration[-1] == 'm':  # минуты
  680.             ban_time = timedelta(minutes=int(time_duration[:-1]))
  681.         elif time_duration[-1] == 'h':  # часы
  682.             ban_time = timedelta(hours=int(time_duration[:-1]))
  683.         elif time_duration[-1] == 'd':  # дни
  684.             ban_time = timedelta(days=int(time_duration[:-1]))
  685.         else:
  686.             raise ValueError
  687.     except ValueError:
  688.         await message.answer("❌ Неверный формат времени. Используйте 'm' для минут, 'h' для часов, 'd' для дней.")
  689.         return
  690.  
  691.     # Получаем ID пользователя по username
  692.     try:
  693.         user = await bot.get_chat_member(message.chat.id, username)
  694.         user_id = user.user.id
  695.     except Exception as e:
  696.         await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
  697.         return
  698.  
  699.     # Дата окончания бана
  700.     ban_until = datetime.now(pytz.UTC) + ban_time
  701.  
  702.     try:
  703.         # Баним пользователя на определенное время
  704.         await bot.ban_chat_member(chat_id=message.chat.id, user_id=user_id, until_date=ban_until)
  705.         await message.answer(f"✅ Пользователь {username} забанен на {time_duration}. Причина: {reason}")
  706.     except Exception as e:
  707.         await message.answer(f"❌ Не удалось забанить пользователя. Ошибка: {str(e)}")
  708.  
  709. @dp.message_handler(Command('unban'))
  710. async def unban_user(message: types.Message):
  711.     """Разбан пользователя."""
  712.    
  713.     # Проверяем, является ли пользователь администратором
  714.     if message.chat.type != "private":
  715.         admins = await bot.get_chat_administrators(message.chat.id)
  716.         if message.from_user.id not in [admin.user.id for admin in admins]:
  717.             await message.answer("❌ Вы не являетесь администратором.")
  718.             return
  719.  
  720.     # Разбираем команду, ожидаем формат: /unban @username
  721.     parts = message.text.split(' ')
  722.     if len(parts) < 2:
  723.         await message.answer("❌ Неверный формат команды. Используйте: `/unban @username`", parse_mode="Markdown")
  724.         return
  725.    
  726.     username = parts[1]  # @username
  727.  
  728.     # Получаем ID пользователя по username
  729.     try:
  730.         user = await bot.get_chat_member(message.chat.id, username)
  731.         user_id = user.user.id
  732.     except Exception as e:
  733.         await message.answer(f"❌ Ошибка при получении информации о пользователе: {str(e)}")
  734.         return
  735.  
  736.     try:
  737.         # Разбаниваем пользователя
  738.         await bot.unban_chat_member(chat_id=message.chat.id, user_id=user_id, only_if_banned=True)
  739.         await message.answer(f"✅ Пользователь {username} был разбанен.")
  740.     except Exception as e:
  741.         await message.answer(f"❌ Не удалось разбанить пользователя. Ошибка: {str(e)}")
  742.  
  743. #Обработка кнопки "Вернуться в меню"
  744. # Основное меню
  745. def main_menu():
  746.     menu = InlineKeyboardMarkup(row_width=2)
  747.    
  748.     # Первый ряд: две кнопки
  749.     menu.add(
  750.         InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
  751.         InlineKeyboardButton("📋 Отчёт", callback_data="send_report")
  752.     )
  753.    
  754.     # Второй ряд: две кнопки
  755.     menu.add(
  756.         InlineKeyboardButton("💰 Вывести", callback_data="withdraw"),
  757.         InlineKeyboardButton("📈 Реферальная система", callback_data="referral_system")
  758.     )
  759.    
  760.     # Третий ряд: одна кнопка
  761.     menu.add(
  762.         InlineKeyboardButton("❓ FAQ", callback_data="faq")
  763.     )
  764.    
  765.     return menu  # Возвращаем сформированное меню
  766.  
  767. # Отправляем главное меню
  768. async def main():
  769.     result = await some_coroutine()
  770.     print(result)
  771.  
  772. @dp.callback_query_handler(lambda c: c.data.startswith("code_"))
  773. async def handle_code_confirmation(callback_query: types.CallbackQuery):
  774.     action, number = callback_query.data.split("_")[-2], callback_query.data.split("_")[-1]
  775.    
  776.     logging.info(f"Кнопка нажата: {callback_query.data}")
  777.    
  778.     if number not in user_numbers:
  779.         logging.error(f"❌ Ошибка: номер {number} не найден в системе.")
  780.         return await callback_query.answer("❌ Ошибка: номер не найден в системе.")
  781.  
  782.     user_info = user_numbers[number]
  783.     user_id = user_info["user_id"]
  784.     timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  785.     user_info["confirmed_time"] = datetime.now()
  786.  
  787.     # Обновляем статус номера в холд
  788.     if action == "entered":
  789.         # Здесь будет передача номера в холд
  790.         user_info["status"] = "hold"  # Помечаем номер как "hold"
  791.         logging.info(f"Номер {number} добавлен в холд.")
  792.     elif action == "not_entered":
  793.         user_info["status"] = "rejected"
  794.  
  795.     logging.info(f"Обновлен статус номера: {number} для пользователя: {user_id}, статус: {user_info['status']}")
  796.  
  797.     # Обновляем статистику для пользователя
  798.     update_statistics(user_id, action)  # Здесь обновляется статистика с действием, например "hold"
  799.  
  800.     # Создаем клавиатуру с кнопкой "Назад"
  801.     back_button = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
  802.  
  803.     # Отправляем соответствующие сообщения пользователю
  804.     if action == "entered":
  805.         await callback_query.answer("✅ Код подтвержден.")
  806.         await bot.send_message(user_info["user_id"], "✅ Ваш код был успешно подтвержден и теперь находится в холде.", reply_markup=back_button)
  807.         text = f"✅ Код подтвержден и добавлен в холд!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
  808.    
  809.     elif action == "not_entered":
  810.         await callback_query.answer("❌ Код не введен.")
  811.         await bot.send_message(user_info["user_id"], "❌ Ваш код не был подтвержден.", reply_markup=back_button)
  812.         text = f"❌ Код не введен!\n📲 Номер: {number}\n⏰ Время: {timestamp}"
  813.  
  814.     # Кнопки для админов
  815.     skip_button = InlineKeyboardButton("⏭️ Пропустить номер", callback_data=f"skip_{number}")
  816.     drop_button = InlineKeyboardButton("⚠️ Слет", callback_data=f"drop_{number}")
  817.     action_keyboard = InlineKeyboardMarkup().add(skip_button, drop_button)
  818.  
  819.     # Отправка сообщения в группу администраторов с кнопками
  820.     await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=action_keyboard)
  821.    
  822.     # Обновление кнопок для текущего сообщения
  823.     await callback_query.message.edit_reply_markup()
  824.  
  825. # Функция для записи данных в таблицу (или базу данных)
  826. async def log_action_to_db(user_id: int, action: str, timestamp: str):
  827.     """Асинхронно записываем статистику в базу данных."""
  828.     db_data = {
  829.         "user_id": user_id,
  830.         "action": action,
  831.         "timestamp": timestamp,
  832.         "hold": user_stats[user_id]["hold"],
  833.         "failed": user_stats[user_id]["failed"],
  834.         "skipped": user_stats[user_id]["skipped"],
  835.         "dropped": user_stats[user_id]["dropped"],
  836.         "added": user_stats[user_id]["added"],
  837.     }
  838.     # Пример асинхронной записи в базу данных
  839.     await db.insert_user_data(db_data)  # Замените на вашу асинхронную функцию
  840.     logging.info(f"Статистика для user_id={user_id} записана в БД: {db_data}")
  841.  
  842. async def handle_code_entered(callback_query: types.CallbackQuery):
  843.     number = callback_query.data.split("_")[-1]
  844.     timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # Используйте datetime.now()
  845.  
  846.     logging.info(f"📌 Код введен для номера: {number}")
  847.  
  848.     # Проверяем, существует ли номер в системе
  849.     if number not in user_numbers:
  850.         logging.error(f"❌ Номер {number} не найден в системе.")
  851.         return await callback_query.answer("❌ Номер не найден в системе.")
  852.    
  853.     # Получаем информацию о пользователе по номеру
  854.     user_info = user_numbers[number]
  855.     user_id = user_info["user_id"]
  856.  
  857.     # Если пользователь еще не добавлен в статистику, создаем запись
  858.     if user_id not in user_stats:
  859.         logging.warning(f"⚠️ Статистика для пользователя {user_id} не найдена, создаём запись.")
  860.         user_stats[user_id] = {"hold": 0, "failed": 0, "skipped": 0, "dropped": 0, "added": 0}
  861.  
  862.     # Логируем информацию о пользователе
  863.     logging.info(f"Найден пользователь: {user_id}, статус: {user_info['status']}")
  864.  
  865.     # Обновляем статус номера на "hold"
  866.     user_info["status"] = "hold"
  867.     logging.info(f"✅ Обновлено: user_id={user_id}, статус={user_info['status']}")
  868.  
  869.     # Обновляем статистику с действием 'hold' (в холде)
  870.     update_statistics(user_id, "hold")  # Добавляем статистику для действия "hold"
  871.     logging.info(f"Номер {number} добавлен в холд для пользователя {user_id}. Статистика обновлена.")
  872.  
  873.     # Запись статистики в базу данных после обновления
  874.     log_action_to_db(user_id, "hold", timestamp)  # Записываем в базу
  875.  
  876.     # Отправляем сообщение пользователю и администратору
  877.     await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
  878.     await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер {number} добавлен в холд.\n⏰ Время: {timestamp}")
  879.  
  880.     # Отвечаем на запрос callback
  881.     await callback_query.answer("✅ Код подтвержден, номер добавлен в холд.")
  882.     await callback_query.message.edit_reply_markup()
  883.  
  884. @dp.callback_query_handler(lambda c: c.data.startswith("drop_"))
  885. async def handle_drop(callback_query: types.CallbackQuery):
  886.     number = callback_query.data.split("_")[-1]
  887.     timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  888.  
  889.     log_data("BEFORE DROP")  # 🔥 Логируем перед выполнением
  890.  
  891.     # Проверяем, есть ли номер в системе
  892.     if number not in user_numbers:
  893.         return await callback_query.answer("❌ Номер не найден в системе.")
  894.  
  895.     # Получаем user_id и информацию о номере
  896.     user_info = user_numbers[number]
  897.     user_id = user_info["user_id"]
  898.  
  899.     # 🔥 Исправление: Если user_stats[user_id] не существует — создаем!
  900.     if user_id not in user_stats:
  901.         logging.warning(f"⚠️ Пользователь {user_id} отсутствует в user_stats! Создаю запись...")
  902.         user_stats[user_id] = {
  903.             "hold": 0,
  904.             "failed": 0,
  905.             "skipped": 0,
  906.             "dropped": 0,
  907.         }
  908.  
  909.     # 🔍 Проверяем, был ли номер в холде
  910.     if user_info.get("status") != "hold":
  911.         logging.warning(f"⚠️ Попытка удалить номер {number}, но он не был в холде!")
  912.         return await callback_query.answer("❌ Ошибка: этот номер не был в холде!")
  913.  
  914.     # Уменьшаем счётчик "В холде" и увеличиваем "Слеты"
  915.     if user_stats[user_id]["hold"] > 0:
  916.         user_stats[user_id]["hold"] -= 1
  917.     user_stats[user_id]["dropped"] += 1
  918.  
  919.     # Обновляем статус номера
  920.     user_numbers[number]["status"] = "dropped"
  921.  
  922.     log_data("AFTER DROP")  # 🔥 Логируем после выполнения
  923.  
  924.     # Отправляем уведомления
  925.     await bot.send_message(user_id, f"⚠️ Ваш номер слетел.\n📞 Номер: {number}\n⏰ Время: {timestamp}")
  926.     await bot.send_message(ADMIN_GROUP_ID, f"⚠️ Номер {number} слетел!\n⏰ Время: {timestamp}")
  927.    
  928.     await callback_query.answer("✅ Слет зафиксирован, статистика обновлена.")
  929.     await callback_query.message.edit_reply_markup()
  930.  
  931. @dp.callback_query_handler(lambda c: c.data == "back_to_main_menu")
  932. async def back_to_main_menu(call: types.CallbackQuery):
  933.     # Создаем клавиатуру с двумя столбцами
  934.     keyboard = InlineKeyboardMarkup(row_width=2)  # Устанавливаем 2 кнопки в строке
  935.    
  936.     # Добавляем кнопки
  937.     keyboard.add(
  938.         InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
  939.         InlineKeyboardButton("📊 Статистика", callback_data="stats_today"),
  940.         InlineKeyboardButton("🎁 Реферальная система", callback_data="referral_system"),
  941.         InlineKeyboardButton("📌 Отправить отчет", callback_data="send_report"),
  942.         InlineKeyboardButton("💰 Баланс", callback_data="withdraw"),
  943.         InlineKeyboardButton("❓ FAQ", callback_data="faq")
  944.     )
  945.  
  946.     # Отправляем сообщение с клавиатурой
  947.     await call.message.edit_text("🏠 Главное меню:", reply_markup=keyboard)
  948.     await call.answer()
  949.  
  950. logging.info(f"📊 user_numbers ДО обработки: {user_numbers}")
  951. logging.info(f"📊 user_stats ДО обработки: {user_stats}")
  952.  
  953. # Функция обновления статистики
  954. async def update_user_stats(user_id):
  955.     user_stats[user_id]['hold'] += 1  # Увеличиваем количество номеров в холде
  956.  
  957. # Обработчик кнопки "Код введен"
  958. @dp.callback_query_handler(lambda c: c.data.startswith("code_entered_"))
  959. async def handle_code_entered(callback_query: types.CallbackQuery):
  960.     user_id = callback_query.from_user.id
  961.     timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  962.     update_stat(user_id, "confirmed", 1)
  963.     log_action_to_db(user_id, "code_entered", timestamp)
  964.     await bot.send_message(user_id, f"✅ Ваш номер в обработке.\n⏰ Время: {timestamp}")
  965.     await bot.send_message("ADMIN_GROUP_ID", f"✅ Номер добавлен в Подтвержденные.\n⏰ Время: {timestamp}")
  966.     await callback_query.answer("✅ Код подтвержден, номер добавлен в Подтвержденные")
  967.     await callback_query.message.edit_reply_markup()
  968.  
  969. #=== 💰 Вывести средства ===
  970. @dp.callback_query_handler(lambda c: c.data == "withdraw")
  971. async def withdraw_request(call: types.CallbackQuery):
  972.     user_id = call.from_user.id
  973.     balance = user_balances.get(user_id, 0)  # Основной баланс
  974.     bonus_balance = user_bonus_balances.get(user_id, 0)  # Бонусный баланс
  975.  
  976.     if balance <= 0 and bonus_balance <= 0:
  977.         await call.message.edit_text("❌ У вас нет средств на вывод.", reply_markup=InlineKeyboardMarkup().add(
  978.             InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu")
  979.         ))
  980.         await call.answer()
  981.         return
  982.  
  983.     # Создаем клавиатуру с кнопками вывода
  984.     keyboard = InlineKeyboardMarkup(row_width=1)
  985.     if balance > 0:
  986.         keyboard.add(InlineKeyboardButton("💸 Вывести с основного баланса", callback_data="withdraw_main"))
  987.     if bonus_balance > 0:
  988.         keyboard.add(InlineKeyboardButton("🎁 Вывести с бонусного баланса", callback_data="withdraw_bonus"))
  989.     keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
  990.  
  991.     # Отображаем балансы и клавиатуру
  992.     await call.message.edit_text(
  993.         f"💰 *Ваш баланс:*\n"
  994.         f"💵 Основной баланс: {balance} USD\n"
  995.         f"🎁 Бонусный баланс: {bonus_balance} USD",
  996.         parse_mode="Markdown",
  997.         reply_markup=keyboard
  998.     )
  999.     await call.answer()
  1000.  
  1001. # Обработчик выбора вывода с основного баланса
  1002. @dp.callback_query_handler(lambda c: c.data == "withdraw_main")
  1003. async def withdraw_main(call: types.CallbackQuery):
  1004.     await start_withdraw(call, "main")
  1005.  
  1006. # Обработчик выбора вывода с бонусного баланса
  1007. @dp.callback_query_handler(lambda c: c.data == "withdraw_bonus")
  1008. async def withdraw_bonus(call: types.CallbackQuery):
  1009.     await start_withdraw(call, "bonus")
  1010.  
  1011. # Универсальный обработчик начала вывода
  1012. async def start_withdraw(call: types.CallbackQuery, balance_type: str):
  1013.     user_id = call.from_user.id
  1014.     balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
  1015.  
  1016.     if balance <= 0:
  1017.         await call.message.edit_text("❌ Недостаточно средств для вывода.", reply_markup=InlineKeyboardMarkup().add(
  1018.             InlineKeyboardButton("⬅️ Назад", callback_data="withdraw")
  1019.         ))
  1020.         await call.answer()
  1021.         return
  1022.  
  1023.     keyboard = InlineKeyboardMarkup().add(
  1024.         InlineKeyboardButton("❌ Отменить", callback_data="withdraw")
  1025.     )
  1026.  
  1027.     await call.message.edit_text(
  1028.         f"💰 Введите сумму для вывода в долларах ({'основной' if balance_type == 'main' else 'бонусный'} баланс):",
  1029.         reply_markup=keyboard
  1030.     )
  1031.     await call.answer()
  1032.  
  1033.     # Сохраняем тип баланса, чтобы знать, откуда списывать средства
  1034.     user_withdraw_requests[user_id] = balance_type
  1035.  
  1036. # Обработчик ввода суммы для вывода
  1037. user_withdraw_requests = {}  # Временное хранилище запросов вывода
  1038.  
  1039. @dp.message_handler(lambda message: message.text.replace('.', '', 1).isdigit())
  1040. async def handle_withdraw_amount(message: types.Message):
  1041.     user_id = message.from_user.id
  1042.     amount = float(message.text)
  1043.  
  1044.     # Определяем, с какого баланса идет вывод
  1045.     balance_type = user_withdraw_requests.get(user_id)
  1046.     if not balance_type:
  1047.         await message.answer("❌ Ошибка: неизвестный источник вывода.")
  1048.         return
  1049.  
  1050.     balance = user_balances.get(user_id, 0) if balance_type == "main" else user_bonus_balances.get(user_id, 0)
  1051.  
  1052.     if amount > balance:
  1053.         await message.answer("❌ У вас недостаточно средств для вывода.")
  1054.         return
  1055.  
  1056.     if amount <= 0:
  1057.         await message.answer("❌ Сумма вывода должна быть положительной.")
  1058.         return
  1059.  
  1060.     # Обновляем баланс пользователя
  1061.     if balance_type == "main":
  1062.         user_balances[user_id] -= amount
  1063.     else:
  1064.         user_bonus_balances[user_id] -= amount
  1065.  
  1066.     # Отправляем заявку на вывод в группу администраторов
  1067.     await bot.send_message(
  1068.         WITHDRAW_GROUP_ID,
  1069.         f"💰 @{message.from_user.username} (ID: {user_id}) хочет вывести {amount} USD с {'основного' if balance_type == 'main' else 'бонусного'} баланса."
  1070.     )
  1071.  
  1072.     keyboard = InlineKeyboardMarkup().add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
  1073.     await message.answer(f"✅ Запрос на вывод {amount} USD отправлен на проверку.", reply_markup=keyboard)
  1074.  
  1075.     # Удаляем временные данные
  1076.     user_withdraw_requests.pop(user_id, None)
  1077.  
  1078. # === ❓ FAQ ===
  1079. @dp.callback_query_handler(lambda c: c.data == "faq")
  1080. async def faq(call: types.CallbackQuery):
  1081.     faq_text = """**❓ FAQ ❓**
  1082. 1️⃣ Мы не несем ответственность за аккаунты.  
  1083. 2️⃣ В случае скама офиса, выплаты не гарантируются.  
  1084. 3️⃣ Если номер отстоял 59 мин вместо 1 часа — оплаты не будет.  
  1085. 4️⃣ Выплаты в течение 7 дней.  
  1086. 5️⃣ Постоянный «Скип» может привести к блокировке.  
  1087. 6️⃣ Принимаются только РФ номера 6+ месяцев.  
  1088. 7️⃣ Администрация имеет право исключить вас без объяснений."""
  1089.  
  1090.     # Создаем инлайн кнопку "⬅️ Назад"
  1091.     keyboard = InlineKeyboardMarkup()
  1092.     keyboard.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
  1093.  
  1094.     # Редактируем текущее сообщение вместо отправки нового
  1095.     await call.message.edit_text(faq_text, parse_mode="Markdown", reply_markup=keyboard)
  1096.     await call.answer()
  1097.    
  1098. @dp.message_handler(commands=["broadcast"])
  1099. async def start_broadcast(message: types.Message):
  1100.     if message.from_user.id not in ADMIN_USER_IDS:
  1101.         return await message.answer("❌ У вас нет прав для рассылки.")
  1102.    
  1103.     await message.answer("Введите текст для рассылки:")
  1104.     await dp.current_state(user=message.from_user.id).set_state("waiting_for_broadcast")
  1105.  
  1106. @dp.message_handler(state="waiting_for_broadcast")
  1107. async def send_broadcast(message: types.Message, state):
  1108.     text = message.text
  1109.     users = get_all_users()
  1110.  
  1111.     sent_count = 0
  1112.     failed_count = 0
  1113.  
  1114.     for user_id in users:
  1115.         try:
  1116.             await bot.send_message(user_id, text)
  1117.             sent_count += 1
  1118.             await asyncio.sleep(0.5)  # Антиспам-задержка
  1119.         except Exception:
  1120.             failed_count += 1
  1121.  
  1122.     await message.answer(f"✅ Рассылка завершена! Отправлено: {sent_count}, Ошибок: {failed_count}.")
  1123.     await state.finish()
  1124.    
  1125. # Убедитесь, что эта функция не принимает никаких аргументов
  1126. def admin_panel():
  1127.     menu = InlineKeyboardMarkup(row_width=2)
  1128.     menu.add(
  1129.         InlineKeyboardButton("📊 Общая статистика", callback_data="admin_stats"),
  1130.         InlineKeyboardButton("📜 Список", callback_data="admin_list"),  # список
  1131.         #InlineKeyboardButton("📤 Сдать номер", callback_data="submit_number"),
  1132.         #InlineKeyboardButton("💰 Вывести", callback_data="withdraw")
  1133.     )
  1134.     return menu
  1135.  
  1136.  #Функция для получения ТОЛЬКО подтвержденных номеров
  1137. def get_confirmed_numbers():
  1138.     connection = sqlite3.connect('your_database.db')
  1139.     cursor = connection.cursor()
  1140.  
  1141.     try:
  1142.         cursor.execute("SELECT number, time FROM confirmed_numbers")
  1143.         confirmed_numbers = cursor.fetchall()
  1144.  
  1145.         logging.info(f"📂 Данные из базы: {confirmed_numbers}")  # Логируем, что возвращает БД
  1146.  
  1147.         return confirmed_numbers
  1148.     except Exception as e:
  1149.         logging.error(f"❌ Ошибка при запросе данных: {e}")
  1150.         return []
  1151.     finally:
  1152.         connection.close()
  1153.  
  1154. conn = sqlite3.connect("bot_database.db")
  1155. cursor = conn.cursor()
  1156.  
  1157. cursor.execute("SELECT * FROM confirmed_numbers")  
  1158. numbers = cursor.fetchall()
  1159.  
  1160. if numbers:
  1161.     print("✅ Подтвержденные номера:", numbers)
  1162. else:
  1163.     print("⚠️ В таблице confirmed_numbers нет данных!")
  1164.  
  1165. conn.close()
  1166.  
  1167. # Функция для создания таблицы, если ее еще нет
  1168. def create_table():
  1169.     connection = sqlite3.connect('your_database.db')  # Путь к базе данных
  1170.     cursor = connection.cursor()
  1171.  
  1172.     # Запрос для создания таблицы
  1173.     cursor.execute('''
  1174.    CREATE TABLE IF NOT EXISTS confirmed_numbers (
  1175.        id INTEGER PRIMARY KEY AUTOINCREMENT,
  1176.        number TEXT NOT NULL,
  1177.        time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
  1178.    );
  1179.    ''')
  1180.  
  1181.     connection.commit()  # Применяем изменения
  1182.     connection.close()  # Закрываем соединение
  1183.  
  1184. # Вызов функции для создания таблицы
  1185. create_table()
  1186.  
  1187. # Функция для добавления номера в базу данных
  1188. def add_number_to_db(number):
  1189.     connection = sqlite3.connect('your_database.db')  # Указывай путь к своей базе данных
  1190.     cursor = connection.cursor()
  1191.  
  1192.     # Проверка на существование номера в базе данных (если нужно)
  1193.     cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
  1194.     if cursor.fetchone()[0] > 0:
  1195.         return False  # Номер уже существует в базе данных
  1196.  
  1197.     # Добавление номера в базу данных
  1198.     cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
  1199.     connection.commit()
  1200.     connection.close()
  1201.     return True
  1202.  
  1203. def add_number_to_db(number):
  1204.     connection = sqlite3.connect('your_database.db')
  1205.     cursor = connection.cursor()
  1206.  
  1207.     # Проверяем, есть ли номер в базе
  1208.     cursor.execute("SELECT COUNT(*) FROM confirmed_numbers WHERE number = ?", (number,))
  1209.     if cursor.fetchone()[0] > 0:
  1210.         logging.info(f"Номер {number} уже есть в базе.")
  1211.         return False  # Номер уже существует
  1212.  
  1213.     # Добавляем номер
  1214.     cursor.execute("INSERT INTO confirmed_numbers (number) VALUES (?)", (number,))
  1215.     connection.commit()
  1216.     logging.info(f"✅ Номер {number} добавлен в базу.")
  1217.     connection.close()
  1218.     return True
  1219.  
  1220.  
  1221. @dp.callback_query_handler(lambda c: c.data == "admin_list")
  1222. async def admin_list(call: types.CallbackQuery):
  1223.     confirmed_numbers = get_confirmed_numbers()  # Получаем подтвержденные номера
  1224.  
  1225.     logging.info(f"Полученные данные о номерах: {confirmed_numbers}")  # Логируем результат
  1226.  
  1227.     # Проверка, что данные получены корректно
  1228.     if not confirmed_numbers or not isinstance(confirmed_numbers, list):
  1229.         await call.message.answer("⚠️ Ошибка: Не удалось загрузить подтвержденные номера.")
  1230.         await call.answer()
  1231.         return
  1232.  
  1233.     if len(confirmed_numbers) == 0:
  1234.         await call.message.answer("⚠️ Подтвержденных номеров нет.")
  1235.         await call.answer()
  1236.         return
  1237.  
  1238.     # Формируем список номеров
  1239.     try:
  1240.         list_text = "📜 **Список подтвержденных номеров:**\n\n"
  1241.         list_text += "\n".join([f"📞 {num[0]} - 🕒 {num[1]}" for num in confirmed_numbers])
  1242.     except (IndexError, TypeError):
  1243.         await call.message.answer("⚠️ Ошибка: Неверный формат данных о номерах.")
  1244.         await call.answer()
  1245.         return
  1246.  
  1247.     # Отправляем список
  1248.     await call.message.answer(list_text, parse_mode="Markdown")
  1249.     await call.answer()
  1250.  
  1251.  
  1252. @dp.message_handler(commands=['admin'])
  1253. async def admin_menu(message: types.Message):
  1254.     if message.from_user.id not in ADMIN_USER_IDS:
  1255.         return await message.answer("❌ У вас нет доступа к админ-панели.")
  1256.     markup = InlineKeyboardMarkup().add(
  1257.         InlineKeyboardButton("📋 Список номеров", callback_data="admin_list"),
  1258.         InlineKeyboardButton("💰 Засчитать баланс", callback_data="admin_add_balance")
  1259.     )
  1260.     await message.answer("🔧 Админ-панель:", reply_markup=markup)
  1261.  
  1262. @dp.callback_query_handler(lambda c: c.data == "admin_add_balance")
  1263. async def admin_add_balance_prompt(call: types.CallbackQuery):
  1264.     await call.message.answer("Введите номер и сумму через пробел (пример: 1234567890 10)")
  1265.     await BalanceInput.waiting_for_number_and_amount.set()
  1266.  
  1267. # Обработчик для ввода номера и суммы
  1268. @dp.message_handler(state=BalanceInput.waiting_for_number_and_amount)
  1269. async def process_balance_input(message: types.Message, state: FSMContext):
  1270.     text = message.text.strip()
  1271.  
  1272.     # Регулярное выражение для номера и суммы
  1273.     match = re.match(r"^(\+?\d{10,15})\s+(\d+)$", text)
  1274.     if not match:
  1275.         await message.reply("❌ Ошибка: некорректный формат. Введите номер и сумму через пробел.\nПример: `1234567890 10`", parse_mode="Markdown")
  1276.         return
  1277.  
  1278.     phone_number, amount = match.groups()
  1279.     amount = float(amount)
  1280.  
  1281.     # Создаем клавиатуру с кнопкой "Назад"
  1282.     back_button = InlineKeyboardMarkup()
  1283.     back_button.add(InlineKeyboardButton("⬅️ Назад", callback_data="back_to_main_menu"))
  1284.  
  1285.     try:
  1286.         if phone_number not in user_numbers:
  1287.             await message.reply("❌ Ошибка: номер не найден.")
  1288.             return
  1289.  
  1290.         user_id = user_numbers[phone_number]["user_id"]
  1291.         user_balances[user_id] = user_balances.get(user_id, 0.0) + amount
  1292.  
  1293.         # Отправляем сообщение пользователю с кнопкой "Назад"
  1294.         await bot.send_message(user_id, f"✅ Вам начислено {amount:.2f} USD.", reply_markup=back_button)
  1295.  
  1296.         # Отправляем сообщение обратно в чат с кнопкой "Назад"
  1297.         await message.answer(f"✅ Пользователю {user_id} начислено {amount:.2f} USD.", reply_markup=back_button)
  1298.  
  1299.     except KeyError:
  1300.         await message.reply("❌ Ошибка: проблема с базой данных номеров.")
  1301.     except ValueError:
  1302.         await message.reply("❌ Ошибка: некорректная сумма.")
  1303.     finally:
  1304.         await state.finish()
  1305.  
  1306. # Функция для добавления пользователя в базу данных
  1307. def add_user(user_id, username, referral_code=None, referred_by=None):
  1308.     conn = sqlite3.connect("users.db")
  1309.     cursor = conn.cursor()
  1310.     cursor.execute("INSERT INTO users (user_id, username, referral_code, referred_by) VALUES (?, ?, ?, ?)",
  1311.                    (user_id, username, referral_code, referred_by))
  1312.     conn.commit()
  1313.     conn.close()
  1314.    
  1315. # Функция для получения информации о пользователе
  1316. def get_user(user_id):
  1317.     conn = sqlite3.connect("users.db")
  1318.     cursor = conn.cursor()
  1319.     cursor.execute("SELECT * FROM users WHERE user_id=?", (user_id,))
  1320.     user = cursor.fetchone()
  1321.     conn.close()
  1322.     return user
  1323.    
  1324. # Функция для обновления баланса пользователя
  1325. def update_balance(user_id, amount):
  1326.     conn = sqlite3.connect("users.db")
  1327.     cursor = conn.cursor()
  1328.     cursor.execute("UPDATE users SET balance = balance + ? WHERE user_id = ?", (amount, user_id))
  1329.     conn.commit()
  1330.     conn.close()
  1331.    
  1332. # Главная кнопка меню с реферальной ссылкой
  1333. @dp.callback_query_handler(lambda c: c.data == "referral_link")
  1334. async def referral_link(call: types.CallbackQuery):
  1335.     user_id = call.from_user.id
  1336.     user = get_user(user_id)
  1337.    
  1338.     if not user:
  1339.         # Если пользователь еще не зарегистрирован в базе, то добавляем его
  1340.         referral_code = generate_referral_code()
  1341.         add_user(user_id, call.from_user.username, referral_code)
  1342.    
  1343.     referral_url = f"t.me/{BOT_USERNAME}?start={user[2]}"  # Пример реферальной ссылки
  1344.     await call.message.answer(f"Ваша реферальная ссылка: {referral_url}")
  1345.    
  1346.     await call.answer()
  1347.  
  1348. from datetime import datetime
  1349. import sqlite3
  1350.  
  1351. @dp.callback_query_handler(lambda c: c.data.startswith("code_entered_") or c.data.startswith("code_not_entered_"))
  1352. async def handle_code_confirmation(callback_query: types.CallbackQuery):
  1353.     number = callback_query.data.split("_")[-1]
  1354.     user_id = user_numbers.get(number, {}).get("user_id")
  1355.  
  1356.     if not user_id:
  1357.         return await callback_query.answer("Ошибка: номер не найден!")
  1358.  
  1359.     now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
  1360.  
  1361.     if callback_query.data.startswith("code_entered_"):
  1362.         save_confirmed_number(number, now)
  1363.         text = f"✅ Номер {number} подтверждён в {now}!"
  1364.     else:
  1365.         save_rejected_number(number, now)
  1366.         text = f"❌ Номер {number} отклонён в {now}!"
  1367.  
  1368.     save_user(user_id)
  1369.  
  1370.     # Отправка сообщения в админ-чат с кнопками
  1371.     admin_keyboard = InlineKeyboardMarkup().row(
  1372.         InlineKeyboardButton("📩 Взять номер", callback_data=f"take_{number}"),
  1373.         InlineKeyboardButton("⏭ Пропустить номер", callback_data=f"skip_{number}")
  1374.     )
  1375.  
  1376.     await bot.send_message(ADMIN_GROUP_ID, text, reply_markup=admin_keyboard)
  1377.     await callback_query.answer("✅ Данные сохранены и статистика обновлена!")
  1378.  
  1379. # === 🔥 Запуск бота ===
  1380. if __name__ == "__main__":
  1381.     logging.basicConfig(level=logging.INFO)
  1382.     executor.start_polling(dp, skip_updates=False)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement