Fix text dialog routing and club card registration recovery
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
"""Админские обработчики для управления счетами и верификации"""
|
||||
from src.utils.account_input import parse_account_records
|
||||
from src.utils.text_output import answer_plain_pages
|
||||
from src.utils.input_validation import numeric_id
|
||||
from src.filters.dialog_input import NotCommand
|
||||
from src.utils.errors import public_error
|
||||
from aiogram import Router, F, Bot
|
||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from aiogram.filters import Command
|
||||
from src.filters.case_insensitive import CaseInsensitiveCommand as Command
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from sqlalchemy import select, and_
|
||||
@@ -121,7 +125,7 @@ async def process_single_account(message: Message, club_card: str, account_numbe
|
||||
await state.clear()
|
||||
|
||||
|
||||
@router.message(AddAccountStates.waiting_for_data, F.text)
|
||||
@router.message(AddAccountStates.waiting_for_data, F.text, NotCommand())
|
||||
async def process_accounts_data(message: Message, state: FSMContext):
|
||||
"""Обработка данных счетов (один или несколько)"""
|
||||
if message.text.strip().lower() == '/cancel':
|
||||
@@ -140,7 +144,6 @@ async def process_accounts_data(message: Message, state: FSMContext):
|
||||
f"Вы отправили: {len(lines)} строк\n\n"
|
||||
f"Разделите данные на несколько частей."
|
||||
)
|
||||
await state.clear()
|
||||
return
|
||||
|
||||
# Отправляем начальное уведомление
|
||||
@@ -150,46 +153,17 @@ async def process_accounts_data(message: Message, state: FSMContext):
|
||||
)
|
||||
|
||||
accounts_data = []
|
||||
errors = []
|
||||
entries, errors = parse_account_records(message.text)
|
||||
|
||||
BATCH_SIZE = 100 # Обрабатываем по 100 счетов за раз
|
||||
|
||||
# Универсальный парсер: поддержка однострочного и многострочного формата
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i].strip()
|
||||
|
||||
# Пропускаем пустые строки и строки с названиями/датами
|
||||
if not line or any(x in line.lower() for x in ['viposnova', '0.00', ':']):
|
||||
i += 1
|
||||
for entry in entries:
|
||||
parts = entry.split()
|
||||
if len(parts) != 2:
|
||||
errors.append("Для счёта не указана клубная карта: " + entry)
|
||||
continue
|
||||
|
||||
# Проверяем, есть ли в строке пробел (однострочный формат: "карта счет")
|
||||
if ' ' in line:
|
||||
# Однострочный формат: разделяем по первому пробелу
|
||||
parts = line.split(maxsplit=1)
|
||||
if len(parts) == 2:
|
||||
club_card, account_number = parts
|
||||
else:
|
||||
errors.append(f"Строка {i+1}: неверный формат")
|
||||
i += 1
|
||||
continue
|
||||
else:
|
||||
# Многострочный формат: текущая строка - счет, следующая - карта
|
||||
account_number = line
|
||||
i += 1
|
||||
if i >= len(lines):
|
||||
errors.append(f"Строка {i}: отсутствует номер карты после счета {account_number}")
|
||||
break
|
||||
|
||||
club_card = lines[i].strip()
|
||||
# Пропускаем, если следующая строка содержит мусор
|
||||
if not club_card or any(x in club_card.lower() for x in ['viposnova', '0.00', ':']):
|
||||
errors.append(f"Строка {i}: некорректный номер карты после счета {account_number}")
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Создаем счет
|
||||
club_card, account_number = parts
|
||||
try:
|
||||
async with async_session_maker() as session:
|
||||
account = await AccountService.create_account(
|
||||
@@ -223,7 +197,6 @@ async def process_accounts_data(message: Message, state: FSMContext):
|
||||
except Exception as e:
|
||||
errors.append(f"Счет {account_number}: {public_error(e)}")
|
||||
|
||||
i += 1
|
||||
|
||||
# Удаляем progress сообщение
|
||||
try:
|
||||
@@ -317,12 +290,11 @@ async def process_accounts_data(message: Message, state: FSMContext):
|
||||
text += f"\n... и еще {len(errors) - 5} ошибок\n"
|
||||
|
||||
if not accounts_data:
|
||||
await message.answer(text)
|
||||
await state.clear()
|
||||
await answer_plain_pages(message, text)
|
||||
return
|
||||
|
||||
# Сохраняем данные и предлагаем добавить в розыгрыш
|
||||
await state.update_data(accounts=accounts_data)
|
||||
await state.update_data(accounts=[{key: value for key, value in account.items() if key != "owner"} for account in accounts_data])
|
||||
await show_lottery_selection(message, text, state)
|
||||
|
||||
|
||||
@@ -332,7 +304,7 @@ async def show_lottery_selection(message: Message, prev_text: str, state: FSMCon
|
||||
lotteries = await LotteryService.get_active_lotteries(session)
|
||||
|
||||
if not lotteries:
|
||||
await message.answer(
|
||||
await answer_plain_pages(message,
|
||||
prev_text + "ℹ️ Нет активных розыгрышей для добавления счетов"
|
||||
)
|
||||
await state.clear()
|
||||
@@ -353,7 +325,7 @@ async def show_lottery_selection(message: Message, prev_text: str, state: FSMCon
|
||||
InlineKeyboardButton(text="❌ Пропустить", callback_data="skip_lottery_add")
|
||||
])
|
||||
|
||||
await message.answer(
|
||||
await answer_plain_pages(message,
|
||||
prev_text + "➕ **Добавить счета в розыгрыш?**\n\n"
|
||||
"Выберите розыгрыш из списка:",
|
||||
reply_markup=InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
@@ -503,7 +475,7 @@ async def verify_winner_command(message: Message):
|
||||
verification_code = parts[1].upper()
|
||||
|
||||
try:
|
||||
lottery_id = int(parts[2])
|
||||
lottery_id = numeric_id(parts[2], maximum=2**31 - 1)
|
||||
except ValueError:
|
||||
await message.answer("❌ lottery_id должен быть числом")
|
||||
return
|
||||
@@ -588,7 +560,7 @@ async def winner_status_command(message: Message):
|
||||
return
|
||||
|
||||
try:
|
||||
lottery_id = int(parts[1])
|
||||
lottery_id = numeric_id(parts[1], maximum=2**31 - 1)
|
||||
except ValueError:
|
||||
await message.answer("❌ lottery_id должен быть числом")
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user