# notifications.py import logging from asgiref.sync import sync_to_async class NotificationService: def __init__(self, bot): """ Инициализация сервиса уведомлений. :param bot: экземпляр telegram.Bot, используемый для отправки сообщений. """ self.bot = bot self.logger = logging.getLogger(__name__) @sync_to_async def _get_all_clients(self): from webapp.models import Client # Возвращаем только клиентов, у которых telegram_id заполнен корректно return list(Client.objects.exclude(telegram_id__in=[None, "", "NULL"])) @sync_to_async def _prepare_results(self, results): # Принудительно загружаем связанные объекты через select_related return list(results.select_related('prize', 'participant__invoice')) async def notify_draw_start(self, lottery): """ Уведомляет всех клиентов о запуске розыгрыша. :param lottery: объект розыгрыша (например, модель Lottery) """ message_text = f"🎉 *Розыгрыш '{lottery.name}' начался!* Следите за обновлениями." clients = await self._get_all_clients() for client in clients: if not client.telegram_id: continue try: await self.bot.send_message( chat_id=client.telegram_id, text=message_text, parse_mode="Markdown" ) except Exception as e: self.logger.error(f"Ошибка отправки уведомления о запуске розыгрыша пользователю {client.telegram_id}: {e}") async def notify_draw_results(self, lottery, results): """ Отправляет результаты розыгрыша всем клиентам. :param lottery: объект розыгрыша (Lottery) :param results: QuerySet с результатами розыгрыша (например, объекты DrawResult) """ # Принудительно загружаем связанные объекты results_list = await self._prepare_results(results) message_text = f"🎉 *Результаты розыгрыша '{lottery.name}':*\n" for result in results_list: status = "✅ Подтвержден" if result.confirmed else "⏳ В ожидании подтверждения" prize = result.prize.reward if result.prize and hasattr(result.prize, "reward") else "неизвестно" account = (str(result.participant.invoice).split('/')[0].strip() if result.participant and hasattr(result.participant, "invoice") else "неизвестно") message_text += f"• Приз: *{prize}*, Счет: _{account}_, Статус: *{status}*\n" clients = await self._get_all_clients() for client in clients: if not client.telegram_id: continue try: await self.bot.send_message( chat_id=client.telegram_id, text=message_text, parse_mode="Markdown" ) except Exception as e: self.logger.error(f"Ошибка отправки результатов розыгрыша пользователю {client.telegram_id}: {e}") async def notify_prize_status_update(self, client, result): """ Отправляет конкретному пользователю обновление по статусу подтверждения приза. :param client: объект клиента (Client) :param result: объект результата розыгрыша (DrawResult) """ status = "✅ Подтвержден" if result.confirmed else "⏳ В ожидании подтверждения" prize = result.prize.reward if result.prize and hasattr(result.prize, "reward") else "неизвестно" message_text = f"🎉 *Обновление розыгрыша:*\nВаш приз *{prize}* имеет статус: *{status}*." try: if client.telegram_id: await self.bot.send_message( chat_id=client.telegram_id, text=message_text, parse_mode="Markdown" ) except Exception as e: self.logger.error(f"Ошибка отправки обновления статуса приза пользователю {client.telegram_id}: {e}") async def notify_binding_complete(self, client): """ Уведомляет пользователя об окончании привязки клубной карты к Telegram ID. :param client: объект клиента (Client) """ message_text = "✅ *Привязка завершена!* Ваша клубная карта успешно привязана к Telegram. Теперь вы можете участвовать в розыгрышах и чате." try: if client.telegram_id: await self.bot.send_message( chat_id=client.telegram_id, text=message_text, parse_mode="Markdown" ) except Exception as e: self.logger.error(f"Ошибка отправки уведомления о привязке пользователю {client.telegram_id}: {e}")