refactor
This commit is contained in:
3
src/handlers/__init__.py
Normal file
3
src/handlers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
"""
|
||||
Обработчики событий и команд: аккаунты, админ-панель.
|
||||
"""
|
||||
375
src/handlers/account_handlers.py
Normal file
375
src/handlers/account_handlers.py
Normal file
@@ -0,0 +1,375 @@
|
||||
"""
|
||||
Обработчики для работы со счетами в розыгрышах
|
||||
"""
|
||||
from aiogram import Router, F
|
||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardButton, InlineKeyboardMarkup
|
||||
from aiogram.filters import StateFilter
|
||||
from aiogram.fsm.context import FSMContext
|
||||
from aiogram.fsm.state import State, StatesGroup
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from ..core.config import ADMIN_IDS
|
||||
from ..core.database import async_session_maker
|
||||
from ..core.services import LotteryService
|
||||
from .account_services import AccountParticipationService
|
||||
from ..utils.account_utils import parse_accounts_from_message, validate_account_number
|
||||
from typing import List
|
||||
|
||||
|
||||
# Состояния FSM для работы со счетами
|
||||
class AccountStates(StatesGroup):
|
||||
waiting_for_lottery_choice = State() # Выбор розыгрыша для добавления счетов
|
||||
waiting_for_winner_lottery = State() # Выбор розыгрыша для установки победителя
|
||||
waiting_for_winner_place = State() # Выбор места победителя
|
||||
searching_accounts = State() # Поиск счетов
|
||||
|
||||
|
||||
# Создаем роутер
|
||||
account_router = Router()
|
||||
|
||||
|
||||
def is_admin(user_id: int) -> bool:
|
||||
"""Проверка прав администратора"""
|
||||
return user_id in ADMIN_IDS
|
||||
|
||||
|
||||
@account_router.message(
|
||||
F.text,
|
||||
StateFilter(None),
|
||||
~F.text.startswith('/') # Исключаем команды
|
||||
)
|
||||
async def detect_account_input(message: Message, state: FSMContext):
|
||||
"""
|
||||
Обнаружение ввода счетов в сообщении
|
||||
Активируется только для администраторов
|
||||
"""
|
||||
if not is_admin(message.from_user.id):
|
||||
return
|
||||
|
||||
# Парсим счета из сообщения
|
||||
accounts = parse_accounts_from_message(message.text)
|
||||
|
||||
if not accounts:
|
||||
return # Счета не обнаружены, пропускаем
|
||||
|
||||
# Сохраняем счета в состоянии
|
||||
await state.update_data(detected_accounts=accounts)
|
||||
|
||||
# Формируем сообщение
|
||||
accounts_text = "\n".join([f"• {acc}" for acc in accounts])
|
||||
count = len(accounts)
|
||||
|
||||
text = (
|
||||
f"🔍 <b>Обнаружен ввод счет{'а' if count == 1 else 'ов'}</b>\n\n"
|
||||
f"Найдено: <b>{count}</b>\n\n"
|
||||
f"{accounts_text}\n\n"
|
||||
f"Выберите действие:"
|
||||
)
|
||||
|
||||
# Кнопки выбора действия
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=[
|
||||
[InlineKeyboardButton(
|
||||
text="➕ Добавить в розыгрыш",
|
||||
callback_data="account_action:add_to_lottery"
|
||||
)],
|
||||
[InlineKeyboardButton(
|
||||
text="👑 Сделать победителем",
|
||||
callback_data="account_action:set_as_winner"
|
||||
)],
|
||||
[InlineKeyboardButton(
|
||||
text="❌ Отмена",
|
||||
callback_data="account_action:cancel"
|
||||
)]
|
||||
])
|
||||
|
||||
await message.answer(text, reply_markup=keyboard, parse_mode="HTML")
|
||||
|
||||
|
||||
@account_router.callback_query(F.data == "account_action:cancel")
|
||||
async def cancel_account_action(callback: CallbackQuery, state: FSMContext):
|
||||
"""Отмена действия со счетами"""
|
||||
await state.clear()
|
||||
await callback.message.edit_text("❌ Действие отменено")
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@account_router.callback_query(F.data == "account_action:add_to_lottery")
|
||||
async def choose_lottery_for_accounts(callback: CallbackQuery, state: FSMContext):
|
||||
"""Выбор розыгрыша для добавления счетов"""
|
||||
if not is_admin(callback.from_user.id):
|
||||
await callback.answer("⛔ Доступно только администраторам", show_alert=True)
|
||||
return
|
||||
|
||||
async with async_session_maker() as session:
|
||||
# Получаем активные розыгрыши
|
||||
lotteries = await LotteryService.get_active_lotteries(session, limit=20)
|
||||
|
||||
if not lotteries:
|
||||
await callback.message.edit_text(
|
||||
"❌ Нет активных розыгрышей.\n\n"
|
||||
"Сначала создайте розыгрыш через /admin"
|
||||
)
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Формируем кнопки с розыгрышами
|
||||
buttons = []
|
||||
for lottery in lotteries:
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text=f"🎲 {lottery.title[:40]}",
|
||||
callback_data=f"add_accounts_to:{lottery.id}"
|
||||
)])
|
||||
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text="❌ Отмена",
|
||||
callback_data="account_action:cancel"
|
||||
)])
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
await callback.message.edit_text(
|
||||
"📋 <b>Выберите розыгрыш:</b>",
|
||||
reply_markup=keyboard,
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await state.set_state(AccountStates.waiting_for_lottery_choice)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@account_router.callback_query(F.data.startswith("add_accounts_to:"))
|
||||
async def add_accounts_to_lottery(callback: CallbackQuery, state: FSMContext):
|
||||
"""Добавление счетов в выбранный розыгрыш"""
|
||||
if not is_admin(callback.from_user.id):
|
||||
await callback.answer("⛔ Доступно только администраторам", show_alert=True)
|
||||
return
|
||||
|
||||
lottery_id = int(callback.data.split(":")[1])
|
||||
|
||||
# Получаем сохраненные счета
|
||||
data = await state.get_data()
|
||||
accounts = data.get("detected_accounts", [])
|
||||
|
||||
if not accounts:
|
||||
await callback.message.edit_text("❌ Счета не найдены")
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Показываем процесс
|
||||
await callback.message.edit_text("⏳ Добавляем счета...")
|
||||
|
||||
async with async_session_maker() as session:
|
||||
# Получаем информацию о розыгрыше
|
||||
lottery = await LotteryService.get_lottery(session, lottery_id)
|
||||
|
||||
if not lottery:
|
||||
await callback.message.edit_text("❌ Розыгрыш не найден")
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Добавляем счета
|
||||
results = await AccountParticipationService.add_accounts_bulk(
|
||||
session, lottery_id, accounts
|
||||
)
|
||||
|
||||
# Формируем результат
|
||||
text = f"<b>Результаты добавления в розыгрыш:</b>\n<i>{lottery.title}</i>\n\n"
|
||||
text += f"✅ Добавлено: <b>{results['added']}</b>\n"
|
||||
text += f"⚠️ Пропущено: <b>{results['skipped']}</b>\n\n"
|
||||
|
||||
if results['details']:
|
||||
text += "<b>Детали:</b>\n"
|
||||
text += "\n".join(results['details'][:20]) # Показываем первые 20
|
||||
|
||||
if len(results['details']) > 20:
|
||||
text += f"\n... и ещё {len(results['details']) - 20}"
|
||||
|
||||
if results['errors']:
|
||||
text += f"\n\n<b>Ошибки:</b>\n"
|
||||
text += "\n".join(results['errors'][:10])
|
||||
|
||||
await callback.message.edit_text(text, parse_mode="HTML")
|
||||
await state.clear()
|
||||
await callback.answer("✅ Готово!")
|
||||
|
||||
|
||||
@account_router.callback_query(F.data == "account_action:set_as_winner")
|
||||
async def choose_lottery_for_winner(callback: CallbackQuery, state: FSMContext):
|
||||
"""Выбор розыгрыша для установки победителя"""
|
||||
if not is_admin(callback.from_user.id):
|
||||
await callback.answer("⛔ Доступно только администраторам", show_alert=True)
|
||||
return
|
||||
|
||||
# Проверяем, что у нас только один счет
|
||||
data = await state.get_data()
|
||||
accounts = data.get("detected_accounts", [])
|
||||
|
||||
if len(accounts) != 1:
|
||||
await callback.message.edit_text(
|
||||
"❌ Для установки победителя введите <b>один</b> счет",
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
async with async_session_maker() as session:
|
||||
# Получаем все розыгрыши (активные и завершенные)
|
||||
lotteries = await LotteryService.get_all_lotteries(session, limit=30)
|
||||
|
||||
if not lotteries:
|
||||
await callback.message.edit_text(
|
||||
"❌ Нет розыгрышей.\n\n"
|
||||
"Сначала создайте розыгрыш через /admin"
|
||||
)
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Формируем кнопки
|
||||
buttons = []
|
||||
for lottery in lotteries:
|
||||
status = "✅" if lottery.is_completed else "🎲"
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text=f"{status} {lottery.title[:35]}",
|
||||
callback_data=f"winner_lottery:{lottery.id}"
|
||||
)])
|
||||
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text="❌ Отмена",
|
||||
callback_data="account_action:cancel"
|
||||
)])
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
account = accounts[0]
|
||||
await callback.message.edit_text(
|
||||
f"👑 <b>Установка победителя</b>\n\n"
|
||||
f"Счет: <code>{account}</code>\n\n"
|
||||
f"Выберите розыгрыш:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await state.set_state(AccountStates.waiting_for_winner_lottery)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@account_router.callback_query(F.data.startswith("winner_lottery:"))
|
||||
async def choose_winner_place(callback: CallbackQuery, state: FSMContext):
|
||||
"""Выбор места для победителя"""
|
||||
if not is_admin(callback.from_user.id):
|
||||
await callback.answer("⛔ Доступно только администраторам", show_alert=True)
|
||||
return
|
||||
|
||||
lottery_id = int(callback.data.split(":")[1])
|
||||
|
||||
# Сохраняем ID розыгрыша
|
||||
await state.update_data(winner_lottery_id=lottery_id)
|
||||
|
||||
async with async_session_maker() as session:
|
||||
lottery = await LotteryService.get_lottery(session, lottery_id)
|
||||
|
||||
if not lottery:
|
||||
await callback.message.edit_text("❌ Розыгрыш не найден")
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Получаем призы
|
||||
prizes = lottery.prizes or []
|
||||
|
||||
# Формируем кнопки с местами
|
||||
buttons = []
|
||||
for i, prize in enumerate(prizes[:10], 1): # Максимум 10 мест
|
||||
prize_text = prize if isinstance(prize, str) else prize.get('description', f'Приз {i}')
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text=f"🏆 Место {i}: {prize_text[:30]}",
|
||||
callback_data=f"winner_place:{i}"
|
||||
)])
|
||||
|
||||
# Если призов нет, предлагаем места 1-5
|
||||
if not buttons:
|
||||
for i in range(1, 6):
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text=f"🏆 Место {i}",
|
||||
callback_data=f"winner_place:{i}"
|
||||
)])
|
||||
|
||||
buttons.append([InlineKeyboardButton(
|
||||
text="❌ Отмена",
|
||||
callback_data="account_action:cancel"
|
||||
)])
|
||||
|
||||
keyboard = InlineKeyboardMarkup(inline_keyboard=buttons)
|
||||
|
||||
data = await state.get_data()
|
||||
account = data.get("detected_accounts", [])[0]
|
||||
|
||||
await callback.message.edit_text(
|
||||
f"👑 <b>Установка победителя</b>\n\n"
|
||||
f"Розыгрыш: <i>{lottery.title}</i>\n"
|
||||
f"Счет: <code>{account}</code>\n\n"
|
||||
f"Выберите место:",
|
||||
reply_markup=keyboard,
|
||||
parse_mode="HTML"
|
||||
)
|
||||
await state.set_state(AccountStates.waiting_for_winner_place)
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@account_router.callback_query(F.data.startswith("winner_place:"))
|
||||
async def set_account_winner(callback: CallbackQuery, state: FSMContext):
|
||||
"""Установка счета как победителя"""
|
||||
if not is_admin(callback.from_user.id):
|
||||
await callback.answer("⛔ Доступно только администраторам", show_alert=True)
|
||||
return
|
||||
|
||||
place = int(callback.data.split(":")[1])
|
||||
|
||||
# Получаем данные
|
||||
data = await state.get_data()
|
||||
account = data.get("detected_accounts", [])[0]
|
||||
lottery_id = data.get("winner_lottery_id")
|
||||
|
||||
if not account or not lottery_id:
|
||||
await callback.message.edit_text("❌ Ошибка: данные не найдены")
|
||||
await state.clear()
|
||||
await callback.answer()
|
||||
return
|
||||
|
||||
# Показываем процесс
|
||||
await callback.message.edit_text("⏳ Устанавливаем победителя...")
|
||||
|
||||
async with async_session_maker() as session:
|
||||
lottery = await LotteryService.get_lottery(session, lottery_id)
|
||||
|
||||
# Получаем приз для этого места
|
||||
prize = None
|
||||
if lottery.prizes and len(lottery.prizes) >= place:
|
||||
prize_info = lottery.prizes[place - 1]
|
||||
prize = prize_info if isinstance(prize_info, str) else prize_info.get('description')
|
||||
|
||||
# Устанавливаем победителя
|
||||
result = await AccountParticipationService.set_account_as_winner(
|
||||
session, lottery_id, account, place, prize
|
||||
)
|
||||
|
||||
if result["success"]:
|
||||
text = (
|
||||
f"✅ <b>Победитель установлен!</b>\n\n"
|
||||
f"Розыгрыш: <i>{lottery.title}</i>\n"
|
||||
f"Счет: <code>{account}</code>\n"
|
||||
f"Место: <b>{place}</b>\n"
|
||||
)
|
||||
if prize:
|
||||
text += f"Приз: <i>{prize}</i>"
|
||||
|
||||
await callback.answer("✅ Победитель установлен!", show_alert=True)
|
||||
else:
|
||||
text = f"❌ {result['message']}"
|
||||
await callback.answer("❌ Ошибка", show_alert=True)
|
||||
|
||||
await callback.message.edit_text(text, parse_mode="HTML")
|
||||
await state.clear()
|
||||
287
src/handlers/account_services.py
Normal file
287
src/handlers/account_services.py
Normal file
@@ -0,0 +1,287 @@
|
||||
"""
|
||||
Сервис для работы с участием счетов в розыгрышах (без привязки к пользователям)
|
||||
"""
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy import select, delete, func
|
||||
from ..core.models import Lottery, Participation, Winner
|
||||
from ..utils.account_utils import validate_account_number, format_account_number, parse_accounts_from_message, search_accounts_by_pattern
|
||||
from typing import List, Optional, Dict, Any
|
||||
|
||||
|
||||
class AccountParticipationService:
|
||||
"""Сервис для работы с участием счетов в розыгрышах"""
|
||||
|
||||
@staticmethod
|
||||
async def add_account_to_lottery(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
account_number: str
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Добавить счет в розыгрыш
|
||||
|
||||
Returns:
|
||||
Dict с ключами: success, message, account_number
|
||||
"""
|
||||
# Валидируем и форматируем
|
||||
formatted_account = format_account_number(account_number)
|
||||
if not formatted_account:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Неверный формат счета: {account_number}",
|
||||
"account_number": account_number
|
||||
}
|
||||
|
||||
# Проверяем существование розыгрыша
|
||||
lottery = await session.get(Lottery, lottery_id)
|
||||
if not lottery:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Розыгрыш #{lottery_id} не найден",
|
||||
"account_number": formatted_account
|
||||
}
|
||||
|
||||
# Проверяем, не участвует ли уже этот счет
|
||||
existing = await session.execute(
|
||||
select(Participation).where(
|
||||
Participation.lottery_id == lottery_id,
|
||||
Participation.account_number == formatted_account
|
||||
)
|
||||
)
|
||||
if existing.scalar_one_or_none():
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Счет {formatted_account} уже участвует в розыгрыше",
|
||||
"account_number": formatted_account
|
||||
}
|
||||
|
||||
# Добавляем участие
|
||||
participation = Participation(
|
||||
lottery_id=lottery_id,
|
||||
account_number=formatted_account,
|
||||
user_id=None # Без привязки к пользователю
|
||||
)
|
||||
session.add(participation)
|
||||
await session.commit()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Счет {formatted_account} добавлен в розыгрыш",
|
||||
"account_number": formatted_account
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
async def add_accounts_bulk(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
account_numbers: List[str]
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Массовое добавление счетов в розыгрыш
|
||||
"""
|
||||
results = {
|
||||
"added": 0,
|
||||
"skipped": 0,
|
||||
"errors": [],
|
||||
"details": [],
|
||||
"added_accounts": [],
|
||||
"skipped_accounts": []
|
||||
}
|
||||
|
||||
for account in account_numbers:
|
||||
result = await AccountParticipationService.add_account_to_lottery(
|
||||
session, lottery_id, account
|
||||
)
|
||||
|
||||
if result["success"]:
|
||||
results["added"] += 1
|
||||
results["added_accounts"].append(result["account_number"])
|
||||
results["details"].append(f"✅ {result['account_number']}")
|
||||
else:
|
||||
results["skipped"] += 1
|
||||
results["skipped_accounts"].append(account)
|
||||
results["errors"].append(result["message"])
|
||||
results["details"].append(f"❌ {result['message']}")
|
||||
|
||||
return results
|
||||
|
||||
@staticmethod
|
||||
async def remove_account_from_lottery(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
account_number: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Удалить счет из розыгрыша"""
|
||||
formatted_account = format_account_number(account_number)
|
||||
if not formatted_account:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Неверный формат счета: {account_number}"
|
||||
}
|
||||
|
||||
participation = await session.execute(
|
||||
select(Participation).where(
|
||||
Participation.lottery_id == lottery_id,
|
||||
Participation.account_number == formatted_account
|
||||
)
|
||||
)
|
||||
participation = participation.scalar_one_or_none()
|
||||
|
||||
if not participation:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Счет {formatted_account} не участвует в розыгрыше"
|
||||
}
|
||||
|
||||
await session.delete(participation)
|
||||
await session.commit()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Счет {formatted_account} удален из розыгрыша"
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
async def get_lottery_accounts(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
limit: Optional[int] = None,
|
||||
offset: int = 0
|
||||
) -> List[str]:
|
||||
"""Получить все счета, участвующие в розыгрыше"""
|
||||
query = select(Participation.account_number).where(
|
||||
Participation.lottery_id == lottery_id,
|
||||
Participation.account_number.isnot(None)
|
||||
).order_by(Participation.created_at.desc())
|
||||
|
||||
if limit:
|
||||
query = query.offset(offset).limit(limit)
|
||||
|
||||
result = await session.execute(query)
|
||||
return [account for account in result.scalars().all() if account]
|
||||
|
||||
@staticmethod
|
||||
async def get_accounts_count(session: AsyncSession, lottery_id: int) -> int:
|
||||
"""Получить количество счетов в розыгрыше"""
|
||||
result = await session.scalar(
|
||||
select(func.count(Participation.id)).where(
|
||||
Participation.lottery_id == lottery_id,
|
||||
Participation.account_number.isnot(None)
|
||||
)
|
||||
)
|
||||
return result or 0
|
||||
|
||||
@staticmethod
|
||||
async def search_accounts_in_lottery(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
pattern: str,
|
||||
limit: int = 20
|
||||
) -> List[str]:
|
||||
"""
|
||||
Поиск счетов в розыгрыше по частичному совпадению
|
||||
|
||||
Args:
|
||||
lottery_id: ID розыгрыша
|
||||
pattern: Паттерн поиска (например "11-22" или "33")
|
||||
limit: Максимальное количество результатов
|
||||
"""
|
||||
# Получаем все счета розыгрыша
|
||||
all_accounts = await AccountParticipationService.get_lottery_accounts(
|
||||
session, lottery_id
|
||||
)
|
||||
|
||||
# Ищем совпадения
|
||||
return search_accounts_by_pattern(pattern, all_accounts)[:limit]
|
||||
|
||||
@staticmethod
|
||||
async def set_account_as_winner(
|
||||
session: AsyncSession,
|
||||
lottery_id: int,
|
||||
account_number: str,
|
||||
place: int,
|
||||
prize: Optional[str] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
Установить счет как победителя на указанное место
|
||||
"""
|
||||
formatted_account = format_account_number(account_number)
|
||||
if not formatted_account:
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Неверный формат счета: {account_number}"
|
||||
}
|
||||
|
||||
# Проверяем, участвует ли счет в розыгрыше
|
||||
participation = await session.execute(
|
||||
select(Participation).where(
|
||||
Participation.lottery_id == lottery_id,
|
||||
Participation.account_number == formatted_account
|
||||
)
|
||||
)
|
||||
if not participation.scalar_one_or_none():
|
||||
return {
|
||||
"success": False,
|
||||
"message": f"Счет {formatted_account} не участвует в розыгрыше"
|
||||
}
|
||||
|
||||
# Проверяем, не занято ли уже это место
|
||||
existing_winner = await session.execute(
|
||||
select(Winner).where(
|
||||
Winner.lottery_id == lottery_id,
|
||||
Winner.place == place
|
||||
)
|
||||
)
|
||||
existing_winner = existing_winner.scalar_one_or_none()
|
||||
|
||||
if existing_winner:
|
||||
# Обновляем существующего победителя
|
||||
existing_winner.account_number = formatted_account
|
||||
existing_winner.user_id = None
|
||||
existing_winner.is_manual = True
|
||||
if prize:
|
||||
existing_winner.prize = prize
|
||||
else:
|
||||
# Создаем нового победителя
|
||||
winner = Winner(
|
||||
lottery_id=lottery_id,
|
||||
account_number=formatted_account,
|
||||
user_id=None,
|
||||
place=place,
|
||||
prize=prize,
|
||||
is_manual=True
|
||||
)
|
||||
session.add(winner)
|
||||
|
||||
await session.commit()
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": f"Счет {formatted_account} установлен победителем на место {place}",
|
||||
"account_number": formatted_account,
|
||||
"place": place
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
async def get_lottery_winners_accounts(
|
||||
session: AsyncSession,
|
||||
lottery_id: int
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Получить всех победителей розыгрыша (счета)"""
|
||||
result = await session.execute(
|
||||
select(Winner).where(
|
||||
Winner.lottery_id == lottery_id,
|
||||
Winner.account_number.isnot(None)
|
||||
).order_by(Winner.place)
|
||||
)
|
||||
|
||||
winners = result.scalars().all()
|
||||
return [
|
||||
{
|
||||
"place": w.place,
|
||||
"account_number": w.account_number,
|
||||
"prize": w.prize,
|
||||
"is_manual": w.is_manual
|
||||
}
|
||||
for w in winners
|
||||
]
|
||||
2413
src/handlers/admin_panel.py
Normal file
2413
src/handlers/admin_panel.py
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user