diff --git a/lottery/draw/admin.py b/lottery/draw/admin.py index 26ebe3d..679eb8a 100644 --- a/lottery/draw/admin.py +++ b/lottery/draw/admin.py @@ -13,6 +13,9 @@ from webapp.models import Invoice, Client, BindingRequest from bot.notifications import NotificationService from bot.utils import create_bot_instance from .views import view_draw_results +from django import forms +from django.utils.dateparse import parse_datetime, parse_date +from datetime import datetime # Настройка логгера logger = logging.getLogger(__name__) @@ -37,11 +40,30 @@ def add_participants_view(request): deposit_min = request.GET.get("deposit_min") deposit_max = request.GET.get("deposit_max") + created_after = request.GET.get("created_after") + created_before = request.GET.get("created_before") + if deposit_min: qs = qs.filter(deposit_sum__gte=deposit_min) if deposit_max: qs = qs.filter(deposit_sum__lte=deposit_max) + if created_after: + try: + dt = parse_date(created_after) + if dt: + qs = qs.filter(created_at__gte=dt) + except ValueError: + pass + + if created_before: + try: + dt = parse_date(created_before) + if dt: + qs = qs.filter(created_at__lte=dt) + except ValueError: + pass + if request.method == "POST": form = AddParticipantsForm(request.POST) form.fields["invoices"].queryset = qs @@ -77,7 +99,6 @@ def start_draw(request, lottery_id): lottery = get_object_or_404(Lottery, id=lottery_id) logger.info("Запуск розыгрыша для лотереи: %s", lottery.name) - # Если лотерея уже завершена, кнопку запускать не показываем if lottery.finished: messages.warning(request, "Розыгрыш уже завершён.") return redirect("..") @@ -85,10 +106,19 @@ def start_draw(request, lottery_id): notifier = NotificationService(bot=create_bot_instance()) async_to_sync(notifier.notify_draw_start)(lottery) + # Собираем ID счетов вручную назначенных победителей + manually_assigned_invoice_ids = set() + for prize in lottery.prizes.all(): + if prize.winner and prize.winner.invoice: + manually_assigned_invoice_ids.add(prize.winner.invoice_id) + # Помечаем вручную выбранного участника как использованного + prize.winner.used = True + prize.winner.save() + for prize in lottery.prizes.all(): logger.info("Обработка приза: %s", prize.prize_place) - # Если для приза уже назначен победитель вручную, сохраняем его в таблице результатов + # Если у приза уже установлен победитель вручную — сохраняем его в таблицу результатов if prize.winner: logger.info("Приз '%s' имеет установленного вручную победителя. Сохраняем в таблице результатов.", prize.prize_place) try: @@ -115,7 +145,10 @@ def start_draw(request, lottery_id): except DrawResult.DoesNotExist: draw_result = None - participants = list(lottery.participants.filter(used=False)) + # Получаем всех неиспользованных участников, исключая вручную выбранных + participants = list( + lottery.participants.filter(used=False).exclude(invoice_id__in=manually_assigned_invoice_ids) + ) logger.info("Найдено свободных участников для приза '%s': %d", prize.prize_place, len(participants)) if not participants: logger.warning("Нет свободных участников для приза '%s'.", prize.prize_place) @@ -145,7 +178,6 @@ def start_draw(request, lottery_id): draw_results = lottery.draw_results.all() async_to_sync(notifier.notify_draw_results)(lottery, draw_results) - # Если все призы розыгрыша подтверждены, устанавливаем флаг завершения лотереи if not lottery.prizes.filter(winner__isnull=True).exists(): lottery.finished = True lottery.save() diff --git a/lottery/templates/admin/add_participants.html b/lottery/templates/admin/add_participants.html index c6fc7d1..d693b28 100644 --- a/lottery/templates/admin/add_participants.html +++ b/lottery/templates/admin/add_participants.html @@ -14,7 +14,7 @@ const selectAllCheckbox = document.getElementById("select-all"); if (selectAllCheckbox) { selectAllCheckbox.addEventListener("click", function(){ - const checkboxes = document.querySelectorAll("input[name='invoices']"); + const checkboxes = document.querySelectorAll("input[name='invoices[]']"); checkboxes.forEach(chk => chk.checked = selectAllCheckbox.checked); }); } @@ -23,64 +23,92 @@ {% endblock extrahead %} {% block content %} -
+

Добавление участников лотереи: {{ lottery.name }}

{{ lottery.description }}

- + -
+ -
- - +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
-
- - +
+
- - - -
- {% csrf_token %} -
- - + +

Найдено подходящих счетов: {{ invoice_count }}

+ + + + {% csrf_token %} +
+
+ + + + + + + + + + + + + + + + + {% for invoice in form.fields.invoices.queryset %} - - - - + + + + + + + + + + + - - - {% for invoice in form.fields.invoices.queryset %} - - - - - - - {% empty %} - - - - {% endfor %} - -
СозданЗакрытСчетКлиентНомер клиентаСумма счетаБонусФДДепозитПримечание
СчетВладелец счетаДепозит{{ invoice.created_at|date:"d.m.Y H:i" }} + {% if invoice.closed_at %} + {{ invoice.closed_at|date:"d.m.Y H:i" }} + {% else %} + — + {% endif %} + {{ invoice.ext_id|default:"—" }}{{ invoice.client.name|default:"Не указан" }}{{ invoice.client.club_card_number|default:"—" }}{{ invoice.sum|default:"—" }}{{ invoice.bonus|default:"—" }}{{ invoice.start_bonus|default:"—" }}{{ invoice.deposit_sum|default:"—" }}{{ invoice.notes|default:"—" }}
- - {{ invoice.ext_id }} - {% if invoice.client_name %} - {{ invoice.client_name }} - {% else %} - Не указан - {% endif %} - {{ invoice.deposit_sum }}
Нет доступных счетов
-
- -
- + {% empty %} + + Нет доступных счетов + + {% endfor %} + + +
+ + + + + Вернуться к списку участников
{% endblock content %} diff --git a/lottery/webapp/services.py b/lottery/webapp/services.py index a1f07c8..bf04e4f 100644 --- a/lottery/webapp/services.py +++ b/lottery/webapp/services.py @@ -95,14 +95,19 @@ class API_SYNC: self.logger.warning("Запись клиента %s пропущена: отсутствует club_card_num. Запись: %s", index, item) continue - # Используем update_or_create для обновления существующей записи + defaults = { + 'name': item.get("name"), + } + + telegram_id = item.get("telegram_id") + if telegram_id: + defaults['telegram_id'] = telegram_id # Обновим только если значение есть + obj, created = Client.objects.update_or_create( club_card_number=club_card_number, - defaults={ - 'name': item.get("name"), - 'telegram_id': item.get("telegram_id"), - } + defaults=defaults ) + new_or_updated += 1 if created: self.logger.info("Запись клиента %s создана: club_card_num %s.", index, club_card_number) @@ -112,6 +117,7 @@ class API_SYNC: self.logger.error("Запись клиента %s имеет неожиданный тип: %s. Значение: %s", index, type(item), item) return new_or_updated + def sync_invoices(self): api_client = APIClient() data = api_client.get_invoices()