diff --git a/backend/apps/tickets/api.py b/backend/apps/tickets/api.py index 40ab327..ff28ef6 100644 --- a/backend/apps/tickets/api.py +++ b/backend/apps/tickets/api.py @@ -1,4 +1,5 @@ import csv +from datetime import timedelta from math import ceil from django.contrib.auth import get_user_model @@ -146,6 +147,8 @@ def list_tickets( related_system: str | None = None, assignee_id: int | None = None, view: str = "all", + status_group: str | None = None, + resolved_within_days: int | None = None, ): require_permission(request, "ticket.view") queryset = Ticket.objects.select_related("requester", "assignee", "category").all() @@ -175,6 +178,18 @@ def list_tickets( queryset = queryset.filter(created_by=request.user) if view == "high_priority": queryset = queryset.filter(priority__in=["high", "urgent"]) + if status_group == "active": + queryset = queryset.exclude(status__in=["resolved", "closed"]) + elif status_group == "completed": + queryset = queryset.filter(status__in=["resolved", "closed"]) + elif status_group: + raise HttpError(400, "Unknown status group") + if resolved_within_days is not None: + days = min(max(resolved_within_days, 1), 365) + cutoff = timezone.now() - timedelta(days=days) + queryset = queryset.filter( + Q(resolved_at__gte=cutoff) | Q(closed_at__gte=cutoff) + ) page = max(page, 1) page_size = min(max(page_size, 1), 100) diff --git a/backend/apps/tickets/tests/test_ticket_api.py b/backend/apps/tickets/tests/test_ticket_api.py index 8b10663..d8f16af 100644 --- a/backend/apps/tickets/tests/test_ticket_api.py +++ b/backend/apps/tickets/tests/test_ticket_api.py @@ -1,4 +1,7 @@ +from datetime import timedelta + from django.contrib.auth import get_user_model +from django.utils import timezone from apps.tickets.models import Ticket, TicketCategory, TicketEvent @@ -102,6 +105,43 @@ def test_list_tickets_filters_by_priority_related_system_and_view(admin_client, assert payload["items"][0]["ticket_no"] == "TK202607010101" +def test_list_tickets_filters_profile_status_group_and_completion_window(admin_client, db): + current_user = get_user_model().objects.get(username="admin") + Ticket.objects.create( + ticket_no="TK202607010201", + title="Active assigned", + description="A", + status="in_progress", + assignee=current_user, + ) + Ticket.objects.create( + ticket_no="TK202607010202", + title="Recently completed", + description="B", + status="resolved", + assignee=current_user, + resolved_at=timezone.now() - timedelta(days=2), + ) + Ticket.objects.create( + ticket_no="TK202607010203", + title="Old completed", + description="C", + status="closed", + assignee=current_user, + closed_at=timezone.now() - timedelta(days=60), + ) + + active = admin_client.get( + "/api/tickets?view=assigned_to_me&status_group=active" + ).json() + recent = admin_client.get( + "/api/tickets?view=assigned_to_me&status_group=completed&resolved_within_days=30" + ).json() + + assert [item["ticket_no"] for item in active["items"]] == ["TK202607010201"] + assert [item["ticket_no"] for item in recent["items"]] == ["TK202607010202"] + + def test_transition_ticket_status_creates_event(admin_client, db): ticket = Ticket.objects.create( ticket_no="TK202606300003",