From 97f5bd09a0fd3164cc1660ce47399ade264f3c56 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Sun, 7 Jun 2026 13:52:30 -0700 Subject: [PATCH] Peel off status filters in status_counts --- src/documents/tests/test_api_tasks.py | 44 +++++++++++++++++++++++++++ src/documents/views.py | 18 ++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/documents/tests/test_api_tasks.py b/src/documents/tests/test_api_tasks.py index 2ccc4b990..63be4943e 100644 --- a/src/documents/tests/test_api_tasks.py +++ b/src/documents/tests/test_api_tasks.py @@ -285,6 +285,50 @@ class TestGetTasksV10: "completed": 1, } + def test_status_counts_ignores_section_filters( + self, + admin_client: APIClient, + ) -> None: + """status_counts/ ignores status-like filters for the sections it counts.""" + PaperlessTaskFactory( + acknowledged=False, + status=PaperlessTask.Status.FAILURE, + input_data={"filename": "invoice-a.pdf"}, + ) + PaperlessTaskFactory( + acknowledged=False, + status=PaperlessTask.Status.PENDING, + input_data={"filename": "invoice-b.pdf"}, + ) + PaperlessTaskFactory( + acknowledged=False, + status=PaperlessTask.Status.SUCCESS, + input_data={"filename": "invoice-c.pdf"}, + ) + PaperlessTaskFactory( + acknowledged=False, + status=PaperlessTask.Status.FAILURE, + input_data={"filename": "unrelated.pdf"}, + ) + + response = admin_client.get( + f"{ENDPOINT}status_counts/", + { + "acknowledged": "false", + "name": "invoice", + "status": PaperlessTask.Status.FAILURE, + "is_complete": "false", + }, + ) + + assert response.status_code == status.HTTP_200_OK + assert response.data == { + "all": 3, + "needs_attention": 1, + "in_progress": 1, + "completed": 1, + } + def test_default_ordering_is_newest_first(self, admin_client: APIClient) -> None: """Tasks are returned in descending date_created order (newest first).""" base = timezone.now() diff --git a/src/documents/views.py b/src/documents/views.py index 9d24f43d6..9fd85841e 100644 --- a/src/documents/views.py +++ b/src/documents/views.py @@ -4137,6 +4137,7 @@ class TasksViewSet(ReadOnlyModelViewSet[PaperlessTask]): PaperlessTask.TaskType.SANITY_CHECK: (sanity_check, {"raise_on_error": False}), PaperlessTask.TaskType.LLM_INDEX: (llmindex_index, {"rebuild": False}), } + _STATUS_COUNT_EXCLUDED_FILTERS = frozenset({"status", "is_complete"}) def get_serializer_class(self): # v9: use backwards-compatible serializer with old field names @@ -4177,6 +4178,21 @@ class TasksViewSet(ReadOnlyModelViewSet[PaperlessTask]): queryset = queryset.filter(task_id=task_id) return queryset + def get_status_count_queryset(self): + """Apply task filters except the status dimensions represented by the counts.""" + query_params = self.request.query_params.copy() + for param in self._STATUS_COUNT_EXCLUDED_FILTERS: + query_params.pop(param, None) + + filterset = self.filterset_class( + data=query_params, + queryset=self.get_queryset(), + request=self.request, + ) + if not filterset.is_valid(): + raise ValidationError(filterset.errors) + return filterset.qs + @action( methods=["post"], detail=False, @@ -4242,7 +4258,7 @@ class TasksViewSet(ReadOnlyModelViewSet[PaperlessTask]): @action(methods=["get"], detail=False) def status_counts(self, request): """Aggregated task counts for task UI sections.""" - queryset = self.filter_queryset(self.get_queryset()) + queryset = self.get_status_count_queryset() counts = queryset.aggregate( all=Count("id"), needs_attention=Count(