Files
new_lottery_bot/account_services.py
2025-11-15 20:03:49 +09:00

288 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Сервис для работы с участием счетов в розыгрышах (без привязки к пользователям)
"""
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, delete, func
from models import Lottery, Participation, Winner
from 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
]