This commit is contained in:
2025-11-16 12:36:02 +09:00
parent 3a25e6a4cb
commit eb3f3807fd
61 changed files with 1438 additions and 1139 deletions

View 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
]