diff --git a/src/handlers/admin_account_handlers.py b/src/handlers/admin_account_handlers.py index ade2b18..4d5d221 100644 --- a/src/handlers/admin_account_handlers.py +++ b/src/handlers/admin_account_handlers.py @@ -22,6 +22,14 @@ class AddAccountStates(StatesGroup): choosing_lottery = State() +@router.message(Command("cancel")) +@admin_only +async def cancel_command(message: Message, state: FSMContext): + """Отменить текущую операцию и сбросить состояние""" + await state.clear() + await message.answer("✅ Состояние сброшено. Все операции отменены.") + + @router.message(Command("add_account")) @admin_only async def add_account_command(message: Message, state: FSMContext): @@ -120,9 +128,30 @@ async def process_accounts_data(message: Message, state: FSMContext): return lines = message.text.strip().split('\n') + + # Ограничение: максимум 1000 счетов за раз + MAX_ACCOUNTS = 1000 + if len(lines) > MAX_ACCOUNTS: + await message.answer( + f"⚠️ Слишком много счетов!\n\n" + f"Максимум за раз: {MAX_ACCOUNTS}\n" + f"Вы отправили: {len(lines)} строк\n\n" + f"Разделите данные на несколько частей." + ) + await state.clear() + return + + # Отправляем начальное уведомление + progress_msg = await message.answer( + f"⏳ Обработка {len(lines)} строк...\n" + f"Пожалуйста, подождите..." + ) + accounts_data = [] errors = [] + BATCH_SIZE = 100 # Обрабатываем по 100 счетов за раз + # Универсальный парсер: поддержка однострочного и многострочного формата i = 0 while i < len(lines): @@ -176,6 +205,16 @@ async def process_accounts_data(message: Message, state: FSMContext): 'owner': owner, 'owner_id': owner.telegram_id if owner else None }) + + # Обновляем progress каждые 50 счетов + if len(accounts_data) % 50 == 0: + try: + await progress_msg.edit_text( + f"⏳ Обработано: {len(accounts_data)} / ~{len(lines)}\n" + f"❌ Ошибок: {len(errors)}" + ) + except: + pass # Игнорируем ошибки редактирования except ValueError as e: errors.append(f"Счет {account_number} (карта {club_card}): {str(e)}") @@ -184,6 +223,12 @@ async def process_accounts_data(message: Message, state: FSMContext): i += 1 + # Удаляем progress сообщение + try: + await progress_msg.delete() + except: + pass + # Группируем счета по владельцам и отправляем групповые уведомления if accounts_data: from collections import defaultdict @@ -203,8 +248,13 @@ async def process_accounts_data(message: Message, state: FSMContext): f"💳 `{account_numbers[0]}`\n\n" "Теперь вы можете участвовать в розыгрышах!" ) - else: - # Групповое уведомление + await message.bot.send_message( + owner_id, + notification_text, + parse_mode="Markdown" + ) + elif len(account_numbers) <= 50: + # Групповое уведомление (до 50 счетов) notification_text = ( f"✅ К вашему профилю добавлено счетов: *{len(account_numbers)}*\n\n" "💳 *Ваши счета:*\n" @@ -212,12 +262,37 @@ async def process_accounts_data(message: Message, state: FSMContext): for acc_num in account_numbers: notification_text += f"• `{acc_num}`\n" notification_text += "\nТеперь вы можете участвовать в розыгрышах!" - - await message.bot.send_message( - owner_id, - notification_text, - parse_mode="Markdown" - ) + + await message.bot.send_message( + owner_id, + notification_text, + parse_mode="Markdown" + ) + else: + # Много счетов - показываем первые 10 и кнопку + notification_text = ( + f"✅ К вашему профилю добавлено счетов: *{len(account_numbers)}*\n\n" + "💳 *Первые 10 счетов:*\n" + ) + for acc_num in account_numbers[:10]: + notification_text += f"• `{acc_num}`\n" + notification_text += f"\n_...и ещё {len(account_numbers) - 10} счетов_\n\n" + notification_text += "Теперь вы можете участвовать в розыгрышах!" + + # Кнопка для просмотра всех счетов + keyboard = InlineKeyboardMarkup(inline_keyboard=[ + [InlineKeyboardButton( + text="📋 Просмотреть все счета", + callback_data="view_my_accounts" + )] + ]) + + await message.bot.send_message( + owner_id, + notification_text, + parse_mode="Markdown", + reply_markup=keyboard + ) except Exception as e: pass # Игнорируем ошибки отправки уведомлений @@ -627,3 +702,43 @@ async def user_info_command(message: Message): except Exception as e: await message.answer(f"❌ Ошибка: {str(e)}") + + +@router.callback_query(F.data == "view_my_accounts") +async def view_my_accounts_callback(callback: CallbackQuery): + """Показать все счета пользователя""" + try: + async with async_session_maker() as session: + # Получаем пользователя + user_result = await session.execute( + select(User).where(User.telegram_id == callback.from_user.id) + ) + user = user_result.scalar_one_or_none() + + if not user: + await callback.answer("❌ Пользователь не найден", show_alert=True) + return + + # Получаем все счета + accounts = await AccountService.get_user_accounts(session, user.id) + + if not accounts: + await callback.answer("У вас нет счетов", show_alert=True) + return + + # Формируем сообщение с пагинацией (по 50 счетов на сообщение) + BATCH_SIZE = 50 + for i in range(0, len(accounts), BATCH_SIZE): + batch = accounts[i:i+BATCH_SIZE] + + text = f"💳 *Ваши счета ({i+1}-{min(i+BATCH_SIZE, len(accounts))} из {len(accounts)}):*\n\n" + for acc in batch: + status = "✅" if acc.is_active else "❌" + text += f"{status} `{acc.account_number}`\n" + + await callback.message.answer(text, parse_mode="Markdown") + + await callback.answer("✅ Список счетов отправлен") + + except Exception as e: + await callback.answer(f"❌ Ошибка: {str(e)}", show_alert=True)