• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

iplweb / bpp / #820

19 Oct 2025 06:59PM UTC coverage: 65.093% (+5.3%) from 59.791%
#820

push

coveralls-python

Michał Pasternak
Fixes

4215 of 9430 branches covered (44.7%)

Branch coverage included in aggregate %.

27562 of 39388 relevant lines covered (69.98%)

0.7 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.07
src/pbn_export_queue/views.py
1
import re
1✔
2
import sys
1✔
3

4
import rollbar
1✔
5
from django.contrib import messages
1✔
6
from django.contrib.auth.decorators import login_required
1✔
7
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
1✔
8
from django.db.models import F
1✔
9
from django.db.models.functions import Coalesce
1✔
10
from django.http import HttpResponseRedirect, JsonResponse
1✔
11
from django.shortcuts import get_object_or_404
1✔
12
from django.urls import reverse_lazy
1✔
13
from django.utils.safestring import mark_safe
1✔
14
from django.views import View
1✔
15
from django.views.decorators.http import require_POST
1✔
16
from django.views.generic import DetailView, ListView
1✔
17

18
from bpp.const import GR_WPROWADZANIE_DANYCH
1✔
19

20
from .models import PBN_Export_Queue
1✔
21

22

23
class PBNExportQueuePermissionMixin(UserPassesTestMixin):
1✔
24
    """Mixin for permission checking - user must be staff or have GR_WPROWADZANIE_DANYCH group"""
25

26
    def test_func(self):
1✔
27
        user = self.request.user
1✔
28
        return user.is_staff or user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
1✔
29

30

31
class PBNExportQueueListView(
1✔
32
    LoginRequiredMixin, PBNExportQueuePermissionMixin, ListView
33
):
34
    """ListView for PBN Export Queue with filtering by success status"""
35

36
    model = PBN_Export_Queue
1✔
37
    template_name = "pbn_export_queue/pbn_export_queue_list.html"
1✔
38
    context_object_name = "export_queue_items"
1✔
39
    paginate_by = 25
1✔
40

41
    def get_queryset(self):
1✔
42
        queryset = super().get_queryset()
1✔
43

44
        # Annotate with ostatnia_aktualizacja for sorting
45
        queryset = queryset.annotate(
1✔
46
            ostatnia_aktualizacja_sort=Coalesce(
47
                F("wysylke_zakonczono"), F("wysylke_podjeto"), F("zamowiono")
48
            )
49
        )
50

51
        # Filter by zakonczono_pomyslnie if parameter provided
52
        success_filter = self.request.GET.get("zakonczono_pomyslnie")
1✔
53
        if success_filter == "true":
1✔
54
            queryset = queryset.filter(zakonczono_pomyslnie=True)
1✔
55
        elif success_filter == "false":
1✔
56
            queryset = queryset.filter(zakonczono_pomyslnie=False)
1✔
57
        elif success_filter == "none":
1✔
58
            queryset = queryset.filter(zakonczono_pomyslnie=None)
1✔
59

60
        # Handle title search
61
        search_query = self.request.GET.get("q")
1✔
62
        if search_query:
1✔
63
            # Import Q for complex queries
64
            from django.db.models import Q
1✔
65

66
            # Search in cached description and original title of the related record
67
            # We need to get the content types for the models we're interested in
68
            # Create filters for searching in related models
69
            # Since we're using GenericForeignKey, we need to filter differently
70
            # We'll search for the query in the komunikat field which contains publication info
71
            # and also try to match against object IDs if they exist
72
            queryset = queryset.filter(Q(komunikat__icontains=search_query))
1✔
73

74
            # Additionally, we can filter by checking the actual related objects
75
            # This requires more complex filtering through the generic relation
76
            matching_ids = []
1✔
77

78
            # Get all content types that might be in the queue
79
            for item in queryset.select_related("content_type"):
1✔
80
                if item.rekord_do_wysylki:
1!
81
                    try:
1✔
82
                        record = item.rekord_do_wysylki
1✔
83
                        # Check if record has title fields
84
                        if (
1!
85
                            hasattr(record, "tytul_oryginalny")
86
                            and record.tytul_oryginalny
87
                        ):
88
                            if search_query.lower() in record.tytul_oryginalny.lower():
1!
89
                                matching_ids.append(item.pk)
×
90
                        elif (
1!
91
                            hasattr(record, "opis_bibliograficzny_cache")
92
                            and record.opis_bibliograficzny_cache
93
                        ):
94
                            if (
×
95
                                search_query.lower()
96
                                in record.opis_bibliograficzny_cache.lower()
97
                            ):
98
                                matching_ids.append(item.pk)
×
99
                    except BaseException:
×
100
                        pass
×
101

102
            # If we found matching IDs, filter by them
103
            if matching_ids:
1!
104
                queryset = queryset.filter(
1✔
105
                    Q(pk__in=matching_ids) | Q(komunikat__icontains=search_query)
106
                )
107

108
        # Handle sorting
109
        sort_by = self.request.GET.get(
1✔
110
            "sort", "-ostatnia_aktualizacja"
111
        )  # Default to newest update first
112
        allowed_sorts = {
1✔
113
            "pk": "pk",
114
            "-pk": "-pk",
115
            "zamowiono": "zamowiono",
116
            "-zamowiono": "-zamowiono",
117
            "ostatnia_aktualizacja": "ostatnia_aktualizacja_sort",
118
            "-ostatnia_aktualizacja": "-ostatnia_aktualizacja_sort",
119
            "ilosc_prob": "ilosc_prob",
120
            "-ilosc_prob": "-ilosc_prob",
121
            "zakonczono_pomyslnie": "zakonczono_pomyslnie",
122
            "-zakonczono_pomyslnie": "-zakonczono_pomyslnie",
123
        }
124
        if sort_by in allowed_sorts:
1✔
125
            queryset = queryset.order_by(allowed_sorts[sort_by])
1✔
126

127
        return queryset.select_related("zamowil", "content_type")
1✔
128

129
    def get_context_data(self, **kwargs):
1✔
130
        context = super().get_context_data(**kwargs)
1✔
131
        context["current_filter"] = self.request.GET.get("zakonczono_pomyslnie", "all")
1✔
132
        context["search_query"] = self.request.GET.get("q", "")
1✔
133
        # Add count of error records for the resend button
134
        context["error_count"] = PBN_Export_Queue.objects.filter(
1✔
135
            zakonczono_pomyslnie=False
136
        ).count()
137
        # Add count of waiting records for the resend button
138
        context["waiting_count"] = PBN_Export_Queue.objects.filter(
1✔
139
            retry_after_user_authorised=True
140
        ).count()
141
        # Add count of never sent records for the wake up button
142
        context["never_sent_count"] = PBN_Export_Queue.objects.filter(
1✔
143
            wysylke_podjeto=None,
144
            wysylke_zakonczono=None,
145
        ).count()
146
        # Add counts for filter buttons
147
        context["total_count"] = PBN_Export_Queue.objects.count()
1✔
148
        context["success_count"] = PBN_Export_Queue.objects.filter(
1✔
149
            zakonczono_pomyslnie=True
150
        ).count()
151
        context["pending_count"] = PBN_Export_Queue.objects.filter(
1✔
152
            zakonczono_pomyslnie=None
153
        ).count()
154
        # Add current sort parameter
155
        context["current_sort"] = self.request.GET.get("sort", "-ostatnia_aktualizacja")
1✔
156
        return context
1✔
157

158

159
class PBNExportQueueTableView(
1✔
160
    LoginRequiredMixin, PBNExportQueuePermissionMixin, ListView
161
):
162
    """Table-only view for HTMX auto-refresh"""
163

164
    model = PBN_Export_Queue
1✔
165
    template_name = "pbn_export_queue/pbn_export_queue_table.html"
1✔
166
    context_object_name = "export_queue_items"
1✔
167
    paginate_by = 25
1✔
168

169
    def get_queryset(self):
1✔
170
        queryset = super().get_queryset()
1✔
171

172
        # Annotate with ostatnia_aktualizacja for sorting
173
        queryset = queryset.annotate(
1✔
174
            ostatnia_aktualizacja_sort=Coalesce(
175
                F("wysylke_zakonczono"), F("wysylke_podjeto"), F("zamowiono")
176
            )
177
        )
178

179
        # Filter by zakonczono_pomyslnie if parameter provided
180
        success_filter = self.request.GET.get("zakonczono_pomyslnie")
1✔
181
        if success_filter == "true":
1!
182
            queryset = queryset.filter(zakonczono_pomyslnie=True)
1✔
183
        elif success_filter == "false":
1!
184
            queryset = queryset.filter(zakonczono_pomyslnie=False)
×
185
        elif success_filter == "none":
1!
186
            queryset = queryset.filter(zakonczono_pomyslnie=None)
1✔
187

188
        # Handle title search
189
        search_query = self.request.GET.get("q")
1✔
190
        if search_query:
1!
191
            # Import Q for complex queries
192
            from django.db.models import Q
×
193

194
            # Search in cached description and original title of the related record
195
            # We need to get the content types for the models we're interested in
196
            # Create filters for searching in related models
197
            # Since we're using GenericForeignKey, we need to filter differently
198
            # We'll search for the query in the komunikat field which contains publication info
199
            # and also try to match against object IDs if they exist
200
            queryset = queryset.filter(Q(komunikat__icontains=search_query))
×
201

202
            # Additionally, we can filter by checking the actual related objects
203
            # This requires more complex filtering through the generic relation
204
            matching_ids = []
×
205

206
            # Get all content types that might be in the queue
207
            for item in queryset.select_related("content_type"):
×
208
                if item.rekord_do_wysylki:
×
209
                    try:
×
210
                        record = item.rekord_do_wysylki
×
211
                        # Check if record has title fields
212
                        if (
×
213
                            hasattr(record, "tytul_oryginalny")
214
                            and record.tytul_oryginalny
215
                        ):
216
                            if search_query.lower() in record.tytul_oryginalny.lower():
×
217
                                matching_ids.append(item.pk)
×
218
                        elif (
×
219
                            hasattr(record, "opis_bibliograficzny_cache")
220
                            and record.opis_bibliograficzny_cache
221
                        ):
222
                            if (
×
223
                                search_query.lower()
224
                                in record.opis_bibliograficzny_cache.lower()
225
                            ):
226
                                matching_ids.append(item.pk)
×
227
                    except BaseException:
×
228
                        pass
×
229

230
            # If we found matching IDs, filter by them
231
            if matching_ids:
×
232
                queryset = queryset.filter(
1✔
233
                    Q(pk__in=matching_ids) | Q(komunikat__icontains=search_query)
234
                )
235

236
        # Handle sorting
237
        sort_by = self.request.GET.get(
1✔
238
            "sort", "-ostatnia_aktualizacja"
239
        )  # Default to newest update first
240
        allowed_sorts = {
1✔
241
            "pk": "pk",
242
            "-pk": "-pk",
243
            "zamowiono": "zamowiono",
244
            "-zamowiono": "-zamowiono",
245
            "ostatnia_aktualizacja": "ostatnia_aktualizacja_sort",
246
            "-ostatnia_aktualizacja": "-ostatnia_aktualizacja_sort",
247
            "ilosc_prob": "ilosc_prob",
248
            "-ilosc_prob": "-ilosc_prob",
249
            "zakonczono_pomyslnie": "zakonczono_pomyslnie",
250
            "-zakonczono_pomyslnie": "-zakonczono_pomyslnie",
251
        }
252
        if sort_by in allowed_sorts:
1!
253
            queryset = queryset.order_by(allowed_sorts[sort_by])
1✔
254

255
        return queryset.select_related("zamowil", "content_type")
1✔
256

257
    def get_context_data(self, **kwargs):
1✔
258
        context = super().get_context_data(**kwargs)
1✔
259
        context["current_filter"] = self.request.GET.get("zakonczono_pomyslnie", "all")
1✔
260
        context["search_query"] = self.request.GET.get("q", "")
1✔
261
        # Add count of error records for the resend button
262
        context["error_count"] = PBN_Export_Queue.objects.filter(
1✔
263
            zakonczono_pomyslnie=False
264
        ).count()
265
        # Add count of waiting records for the resend button
266
        context["waiting_count"] = PBN_Export_Queue.objects.filter(
1✔
267
            retry_after_user_authorised=True
268
        ).count()
269
        # Add count of never sent records for the wake up button
270
        context["never_sent_count"] = PBN_Export_Queue.objects.filter(
1✔
271
            wysylke_podjeto=None,
272
            wysylke_zakonczono=None,
273
        ).count()
274
        # Add counts for filter buttons
275
        context["total_count"] = PBN_Export_Queue.objects.count()
1✔
276
        context["success_count"] = PBN_Export_Queue.objects.filter(
1✔
277
            zakonczono_pomyslnie=True
278
        ).count()
279
        context["pending_count"] = PBN_Export_Queue.objects.filter(
1✔
280
            zakonczono_pomyslnie=None
281
        ).count()
282
        # Add current sort parameter
283
        context["current_sort"] = self.request.GET.get("sort", "-ostatnia_aktualizacja")
1✔
284
        return context
1✔
285

286

287
class PBNExportQueueDetailView(
1✔
288
    LoginRequiredMixin, PBNExportQueuePermissionMixin, DetailView
289
):
290
    """DetailView for PBN Export Queue showing logs and action buttons"""
291

292
    model = PBN_Export_Queue
1✔
293
    template_name = "pbn_export_queue/pbn_export_queue_detail.html"
1✔
294
    context_object_name = "export_queue_item"
1✔
295

296
    def get_queryset(self):
1✔
297
        return super().get_queryset().select_related("zamowil", "content_type")
1✔
298

299
    def parse_komunikat_links(self, komunikat):
1✔
300
        """Parse the komunikat field to extract and format links"""
301
        if not komunikat:
1✔
302
            return None
1✔
303

304
        # Find the SentData link
305
        sentdata_match = re.search(
1✔
306
            r'href="(/admin/pbn_api/sentdata/\d+/change/)"', komunikat
307
        )
308

309
        links = {}
1✔
310
        if sentdata_match:
1✔
311
            links["sentdata_url"] = sentdata_match.group(1)
1✔
312

313
            # Try to extract PBN publication ID from the komunikat
314
            # Looking for patterns like "PBN ID: xxx" or similar
315
            pbn_match = re.search(r"publication/([a-f0-9-]+)", komunikat)
1✔
316
            if pbn_match:
1!
317
                links["pbn_uid"] = pbn_match.group(1)
1✔
318
                links["pbn_url"] = (
1✔
319
                    f"https://pbn.nauka.gov.pl/works/publication/{pbn_match.group(1)}"
320
                )
321

322
        # Check if this was successful
323
        if "Wysłano poprawnie" in komunikat:
1!
324
            links["success"] = True
×
325
        else:
326
            links["success"] = False
1✔
327

328
        # Make the komunikat HTML-safe but preserve existing HTML
329
        links["formatted_komunikat"] = mark_safe(komunikat.replace("\n", "<br>"))
1✔
330

331
        return links
1✔
332

333
    def get_context_data(self, **kwargs):
1✔
334
        context = super().get_context_data(**kwargs)
1✔
335

336
        # Parse komunikat for links if the record was sent successfully
337
        if self.object.komunikat:
1✔
338
            context["parsed_links"] = self.parse_komunikat_links(self.object.komunikat)
1✔
339

340
        # Try to get the related SentData if it exists
341
        if self.object.zakonczono_pomyslnie:
1!
342
            try:
×
343
                from pbn_api.models.sentdata import SentData
×
344

345
                sent_data = SentData.objects.get(
×
346
                    content_type=self.object.content_type,
347
                    object_id=self.object.object_id,
348
                )
349
                context["sent_data"] = sent_data
×
350
                if sent_data.pbn_uid_id:
×
351
                    # pbn_uid is a ForeignKey to Publication, so we need to use pbn_uid_id or pbn_uid.pbn_uid
352
                    context["pbn_publication_url"] = (
×
353
                        f"https://pbn.nauka.gov.pl/works/publication/{sent_data.pbn_uid_id}"
354
                    )
355
            except SentData.DoesNotExist:
×
356
                pass
×
357

358
        # Generate admin URL for the record if it exists
359
        if self.object.rekord_do_wysylki:
1✔
360
            from django.urls import reverse
1✔
361

362
            content_type = self.object.content_type
1✔
363
            if content_type:
1!
364
                try:
1✔
365
                    # Generate admin change URL for the specific model
366
                    admin_url = reverse(
1✔
367
                        f"admin:{content_type.app_label}_{content_type.model}_change",
368
                        args=[self.object.object_id],
369
                    )
370
                    context["record_admin_url"] = admin_url
1✔
371
                except BaseException:
1✔
372
                    # If URL pattern doesn't exist, skip it
373
                    pass
×
374

375
        return context
1✔
376

377

378
@login_required
1✔
379
@require_POST
1✔
380
def resend_to_pbn(request, pk):
1✔
381
    """View to resend an export queue item to PBN (combines prepare and send)"""
382
    if not (
1✔
383
        request.user.is_staff
384
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
385
    ):
386
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
387
        return HttpResponseRedirect(
1✔
388
            reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
389
        )
390

391
    queue_item = get_object_or_404(PBN_Export_Queue, pk=pk)
1✔
392
    # First prepare for resend
393
    queue_item.prepare_for_resend(
1✔
394
        user=request.user, message_suffix=f" przez {request.user}"
395
    )
396
    # Then trigger the send
397
    queue_item.sprobuj_wyslac_do_pbn()
1✔
398
    messages.success(request, "Przygotowano i zlecono ponowną wysyłkę do PBN.")
1✔
399
    return HttpResponseRedirect(
1✔
400
        reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
401
    )
402

403

404
# Keep old views for backward compatibility but they won't be used in new UI
405
@login_required
1✔
406
@require_POST
1✔
407
def prepare_for_resend(request, pk):
1✔
408
    """View to prepare an export queue item for resending - DEPRECATED"""
409
    if not (
1✔
410
        request.user.is_staff
411
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
412
    ):
413
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
414
        return HttpResponseRedirect(
1✔
415
            reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
416
        )
417

418
    queue_item = get_object_or_404(PBN_Export_Queue, pk=pk)
1✔
419
    queue_item.prepare_for_resend(
1✔
420
        user=request.user, message_suffix=f" przez {request.user}"
421
    )
422
    messages.success(request, "Przygotowano rekord do ponownej wysyłki.")
1✔
423
    return HttpResponseRedirect(
1✔
424
        reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
425
    )
426

427

428
@login_required
1✔
429
@require_POST
1✔
430
def try_send_to_pbn(request, pk):
1✔
431
    """View to trigger sending an export queue item to PBN - DEPRECATED"""
432
    if not (
1✔
433
        request.user.is_staff
434
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
435
    ):
436
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
437
        return HttpResponseRedirect(
1✔
438
            reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
439
        )
440

441
    queue_item = get_object_or_404(PBN_Export_Queue, pk=pk)
1✔
442
    queue_item.sprobuj_wyslac_do_pbn()
1✔
443
    messages.success(request, "Zlecono ponowną wysyłkę do PBN.")
1✔
444
    return HttpResponseRedirect(
1✔
445
        reverse_lazy("pbn_export_queue:export-queue-detail", args=[pk])
446
    )
447

448

449
@login_required
1✔
450
@require_POST
1✔
451
def resend_all_waiting(request):
1✔
452
    """View to resend all export queue items waiting for authorization"""
453
    if not (
1✔
454
        request.user.is_staff
455
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
456
    ):
457
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
458
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
459

460
    # Get all items waiting for authorization (retry_after_user_authorised=True)
461
    waiting_items = PBN_Export_Queue.objects.filter(retry_after_user_authorised=True)
1✔
462
    count = waiting_items.count()
1✔
463

464
    if count == 0:
1✔
465
        messages.warning(request, "Brak rekordów oczekujących na autoryzację.")
1✔
466
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
467

468
    # Process each waiting item
469
    for queue_item in waiting_items:
1✔
470
        try:
1✔
471
            # Prepare for resend
472
            queue_item.prepare_for_resend(
1✔
473
                user=request.user,
474
                message_suffix=f" przez {request.user} (masowa wysyłka oczekujących)",
475
            )
476
            # Trigger the send
477
            queue_item.sprobuj_wyslac_do_pbn()
1✔
478
        except Exception:
×
479
            # Log the error but continue processing other items
480
            rollbar.report_exc_info(sys.exc_info())
×
481
            continue
×
482

483
    messages.success(
1✔
484
        request,
485
        f"Przygotowano i zlecono ponowną wysyłkę {count} rekordów oczekujących na autoryzację.",
486
    )
487
    return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
488

489

490
@login_required
1✔
491
@require_POST
1✔
492
def resend_all_errors(request):
1✔
493
    """View to resend all export queue items with error status"""
494
    if not (
1✔
495
        request.user.is_staff
496
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
497
    ):
498
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
499
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
500

501
    # Get all items with errors (zakonczono_pomyslnie=False)
502
    error_items = PBN_Export_Queue.objects.filter(zakonczono_pomyslnie=False)
1✔
503
    count = error_items.count()
1✔
504

505
    if count == 0:
1✔
506
        messages.warning(request, "Brak rekordów z błędami do ponownej wysyłki.")
1✔
507
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
508

509
    # Process each error item
510
    for queue_item in error_items:
1✔
511
        try:
1✔
512
            # Prepare for resend
513
            queue_item.prepare_for_resend(
1✔
514
                user=request.user,
515
                message_suffix=f" przez {request.user} (masowa wysyłka błędów)",
516
            )
517
            # Trigger the send
518
            queue_item.sprobuj_wyslac_do_pbn()
1✔
519
        except Exception:
1✔
520
            # Log the error but continue processing other items
521
            rollbar.report_exc_info(sys.exc_info())
×
522
            continue
1✔
523

524
    messages.success(
1✔
525
        request, f"Przygotowano i zlecono ponowną wysyłkę {count} rekordów z błędami."
526
    )
527
    return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
528

529

530
@login_required
1✔
531
@require_POST
1✔
532
def wake_up_queue(request):
1✔
533
    """View to wake up and start sending all export queue items that were never attempted"""
534
    if not (
1!
535
        request.user.is_staff
536
        or request.user.groups.filter(name=GR_WPROWADZANIE_DANYCH).exists()
537
    ):
538
        messages.error(request, "Brak uprawnień do wykonania tej operacji.")
1✔
539
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
1✔
540

541
    # Get all items that were never attempted to send
542
    # (wysylke_podjeto=None means sending was never started)
543
    never_sent_items = PBN_Export_Queue.objects.filter(
×
544
        wysylke_podjeto=None,
545
        wysylke_zakonczono=None,
546
    )
547
    count = never_sent_items.count()
×
548

549
    if count == 0:
×
550
        messages.warning(request, "Brak rekordów oczekujących na pierwszą wysyłkę.")
×
551
        return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
×
552

553
    # Process each never-sent item
554
    from pbn_export_queue.tasks import task_sprobuj_wyslac_do_pbn
×
555

556
    for queue_item in never_sent_items:
×
557
        try:
×
558
            # Trigger the send directly with Celery task
559
            task_sprobuj_wyslac_do_pbn.delay(queue_item.pk)
×
560
        except Exception:
×
561
            # Log the error but continue processing other items
562
            rollbar.report_exc_info(sys.exc_info())
×
563
            continue
×
564

565
    messages.success(
×
566
        request,
567
        f"Obudzono wysyłkę dla {count} rekordów które nigdy nie były wysyłane.",
568
    )
569
    return HttpResponseRedirect(reverse_lazy("pbn_export_queue:export-queue-list"))
×
570

571

572
class PBNExportQueueCountsView(LoginRequiredMixin, PBNExportQueuePermissionMixin, View):
1✔
573
    """JSON view that returns current counts for filter buttons"""
574

575
    def get(self, request, *args, **kwargs):
1✔
576
        """Return JSON response with current counts"""
577
        counts = {
1✔
578
            "total_count": PBN_Export_Queue.objects.count(),
579
            "success_count": PBN_Export_Queue.objects.filter(
580
                zakonczono_pomyslnie=True
581
            ).count(),
582
            "error_count": PBN_Export_Queue.objects.filter(
583
                zakonczono_pomyslnie=False
584
            ).count(),
585
            "pending_count": PBN_Export_Queue.objects.filter(
586
                zakonczono_pomyslnie=None
587
            ).count(),
588
            "waiting_count": PBN_Export_Queue.objects.filter(
589
                retry_after_user_authorised=True
590
            ).count(),
591
        }
592
        return JsonResponse(counts)
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc