81 lines
5.9 KiB
Python
81 lines
5.9 KiB
Python
from django.db.models import Case, Exists, IntegerField, OuterRef, Q, Value, When
|
|
from django.utils import timezone
|
|
from django.utils.dateparse import parse_date
|
|
from .models import Ticket, TicketReadState
|
|
from .policies import TicketPolicy
|
|
def customer_tickets(user): return Ticket.objects.filter(customer=user).select_related("category","owner__staff_profile","selected_expert__staff_profile")
|
|
def staff_ticket_rows(user):
|
|
qs=Ticket.objects.select_related("customer__customer_profile","category","owner__staff_profile","selected_expert__staff_profile","owning_unit","assigned_unit","group_dispatch")
|
|
if user.is_superuser or user.has_perm("tickets.view_all_tickets"): return qs
|
|
return qs.filter(TicketPolicy.viewable_q(user)).distinct()
|
|
|
|
def filter_staff_tickets(qs, user, params):
|
|
search=params.get("q", "").strip()
|
|
if search:
|
|
matches=Q(ticket_number__icontains=search)|Q(subject__icontains=search)|Q(customer__mobile__icontains=search)|Q(customer__customer_profile__first_name__icontains=search)|Q(customer__customer_profile__last_name__icontains=search)
|
|
if params.get("tab") == "shared":
|
|
from .staff_conversation import received_messages
|
|
matches |= Q(pk__in=received_messages(user).filter(message__body__icontains=search).values("message__ticket_id"))
|
|
qs=qs.filter(matches)
|
|
if params.get("status") in Ticket.Status.values: qs=qs.filter(status=params["status"])
|
|
if params.get("priority") in Ticket.Priority.values: qs=qs.filter(priority=params["priority"])
|
|
if params.get("category", "").isdigit(): qs=qs.filter(category_id=params["category"])
|
|
if params.get("owner", "").isdigit(): qs=qs.filter(owner_id=params["owner"])
|
|
if params.get("unit", "").isdigit(): qs=qs.filter(Q(owning_unit_id=params["unit"])|Q(assigned_unit_id=params["unit"]))
|
|
if params.get("owning_unit", "").isdigit(): qs=qs.filter(owning_unit_id=params["owning_unit"])
|
|
if params.get("assigned_unit", "").isdigit(): qs=qs.filter(assigned_unit_id=params["assigned_unit"])
|
|
if params.get("delivery_type") in Ticket.DeliveryType.values: qs=qs.filter(delivery_type=params["delivery_type"])
|
|
stakeholder_type=params.get("stakeholder_type", "")
|
|
if stakeholder_type: qs=qs.filter(customer__customer_profile__stakeholder_type=stakeholder_type)
|
|
recipient=params.get("recipient", "").strip()
|
|
if recipient: qs=qs.filter(Q(customer__mobile__icontains=recipient)|Q(customer__customer_profile__first_name__icontains=recipient)|Q(customer__customer_profile__last_name__icontains=recipient)|Q(customer__customer_profile__organization_name__icontains=recipient))
|
|
group_ids=[value for value in params.getlist("contact_group") if value.isdigit()] if hasattr(params,"getlist") else []
|
|
if group_ids: qs=qs.filter(Q(group_dispatch__contact_group_id__in=group_ids)|Q(customer__customer_profile__groups__id__in=group_ids))
|
|
tag_ids=[value for value in params.getlist("tag") if value.isdigit()] if hasattr(params,"getlist") else []
|
|
if tag_ids: qs=qs.filter(tags__id__in=tag_ids)
|
|
created_from=parse_date(params.get("created_from", ""))
|
|
created_to=parse_date(params.get("created_to", ""))
|
|
if created_from: qs=qs.filter(created_at__date__gte=created_from)
|
|
if created_to: qs=qs.filter(created_at__date__lte=created_to)
|
|
updated_from=parse_date(params.get("updated_from", ""))
|
|
updated_to=parse_date(params.get("updated_to", ""))
|
|
if updated_from: qs=qs.filter(updated_at__date__gte=updated_from)
|
|
if updated_to: qs=qs.filter(updated_at__date__lte=updated_to)
|
|
tab=params.get("tab", "")
|
|
if tab=="new": qs=qs.filter(status=Ticket.Status.NEW,owner__isnull=True,selected_expert__isnull=True)
|
|
elif tab=="selected": qs=qs.filter(selected_expert=user,owner__isnull=True)
|
|
elif tab=="mine": qs=qs.filter(owner=user)
|
|
elif tab=="shared":
|
|
from .staff_conversation import received_messages
|
|
qs=qs.filter(Q(access_grants__user=user,access_grants__revoked_at__isnull=True) | Q(pk__in=received_messages(user).values("message__ticket_id")))
|
|
elif tab=="waiting_staff": qs=qs.filter(status__in=[Ticket.Status.WAITING_STAFF,Ticket.Status.REOPENED])
|
|
elif tab=="waiting_customer": qs=qs.filter(status=Ticket.Status.WAITING_CUSTOMER)
|
|
elif tab=="resolved": qs=qs.filter(status=Ticket.Status.RESOLVED)
|
|
elif tab=="closed": qs=qs.filter(status=Ticket.Status.CLOSED)
|
|
if params.get("unread"):
|
|
if tab == "shared":
|
|
qs=qs.filter(Q(access_grants__user=user,access_grants__revoked_at__isnull=True,access_grants__first_viewed_at__isnull=True) | Q(pk__in=received_messages(user).filter(first_viewed_at__isnull=True).values("message__ticket_id")))
|
|
else:
|
|
read_by_user=TicketReadState.objects.filter(ticket_id=OuterRef('pk'),user=user,last_read_at__gte=OuterRef('last_activity_at'))
|
|
qs=qs.alias(_read_by_current_user=Exists(read_by_user)).filter(_read_by_current_user=False)
|
|
qs=qs.distinct()
|
|
if tab in ("", "waiting_staff"):
|
|
return qs.annotate(
|
|
_action_rank=Case(
|
|
When(status__in=[Ticket.Status.NEW,Ticket.Status.WAITING_STAFF,Ticket.Status.REOPENED],then=Value(0)),
|
|
When(status=Ticket.Status.OPEN,then=Value(1)),
|
|
When(status=Ticket.Status.WAITING_CUSTOMER,then=Value(2)),
|
|
default=Value(3),output_field=IntegerField(),
|
|
),
|
|
).order_by("_action_rank","-last_activity_at","-created_at","-id")
|
|
return qs.order_by("-last_activity_at","-created_at","-id")
|
|
|
|
def dashboard_counts(user):
|
|
qs=staff_ticket_rows(user)
|
|
return {
|
|
"new":qs.filter(status=Ticket.Status.NEW,owner__isnull=True,selected_expert__isnull=True).count(),
|
|
"mine":qs.filter(owner=user).count(),
|
|
"waiting":qs.filter(status__in=[Ticket.Status.WAITING_STAFF,Ticket.Status.REOPENED]).count(),
|
|
"overdue":qs.filter(Q(first_response_at__isnull=True,first_response_due_at__lt=timezone.now())|Q(resolved_at__isnull=True,resolution_due_at__lt=timezone.now())).count(),
|
|
}
|