diff --git a/helpdesk/forms.py b/helpdesk/forms.py index 5559b32f..83a3de45 100644 --- a/helpdesk/forms.py +++ b/helpdesk/forms.py @@ -593,7 +593,26 @@ class TicketDependencyForm(forms.ModelForm): class Meta: model = TicketDependency - exclude = ('ticket',) + fields = ('depends_on',) + + def __init__(self, ticket, *args, **kwargs): + super(TicketDependencyForm,self).__init__(*args, **kwargs) + + # Only open tickets except myself, existing dependencies and parents + self.fields['depends_on'].queryset = Ticket.objects.filter(status__in=Ticket.OPEN_STATUSES).exclude(id=ticket.id).exclude(depends_on__ticket=ticket).exclude(ticketdependency__depends_on=ticket) + +class TicketResolvesForm(forms.ModelForm): + ''' Adds this ticket as a dependency for a different ticket ''' + + class Meta: + model = TicketDependency + fields = ('ticket',) + + def __init__(self, ticket, *args, **kwargs): + super(TicketResolvesForm,self).__init__(*args, **kwargs) + + # Only open tickets except myself, existing dependencies and parents + self.fields['ticket'].queryset = Ticket.objects.exclude(status__in=Ticket.OPEN_STATUSES).exclude(id=ticket.id).exclude(depends_on__ticket=ticket).exclude(ticketdependency__depends_on=ticket) class MultipleTicketSelectForm(forms.Form): diff --git a/helpdesk/templates/helpdesk/ticket_desc_table.html b/helpdesk/templates/helpdesk/ticket_desc_table.html index 21a46e5a..ec217264 100644 --- a/helpdesk/templates/helpdesk/ticket_desc_table.html +++ b/helpdesk/templates/helpdesk/ticket_desc_table.html @@ -12,7 +12,7 @@ -

{{ ticket.queue.slug }}-{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]

+

{{ ticket.queue.slug }}-{{ ticket.id }}. {{ ticket.title }}

{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %} @@ -117,24 +117,9 @@ - {% if helpdesk_settings.HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET != False and helpdesk_settings.HELPDESK_ENABLE_TIME_SPENT_ON_TICKET != False %} - - {% if helpdesk_settings.HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET %} - {% trans "Dependencies" %} - - - {% for dep in ticket.ticketdependency.all %} - {% if forloop.first %}

{% trans "This ticket cannot be resolved until the following ticket(s) are resolved" %}

{% endif %} - {% empty %} - {% trans "This ticket has no dependencies." %} - {% endfor %} - - {% else %} - - - {% endif %} + + {% trans "Status" %} + {{ ticket.get_status }} {% if helpdesk_settings.HELPDESK_ENABLE_TIME_SPENT_ON_TICKET %} {% trans "Total time spent" %} {{ ticket.time_spent_formated }} @@ -142,8 +127,64 @@ {% endif %} - - {% endif %} + + {% if helpdesk_settings.HELPDESK_ENABLE_DEPENDENCIES_ON_TICKET != False %} + + + {% trans "Resolves" %} + + + + + {% for resolves in ticket.depends_on.all %} + {% if forloop.first %}{% endif %} + + + + + + {% if forloop.last %}
+ + + {{ resolves.ticket.get_status_display }} + {{ resolves.ticket.ticket }} {{ resolves.ticket.title }} +
{% endif %} + {% empty %} + {% trans "This ticket does not resolve any other" %} + {% endfor %} + + + + + {% trans "Depends" %} + + + + + + {% for dep in dependencies %} + {% if forloop.first %}{% endif %} + + + + + {% if forloop.last %}
+ + + {{ dep.depends_on.get_status_display }} + {{ dep.depends_on.ticket }} {{ dep.depends_on.title }} + +
{% endif %} + {% empty %} + {% trans "This ticket has no dependencies." %} + {% endfor %} + + + {% endif %} {% if ticket.kbitem %} {% trans "Knowlegebase item" %} diff --git a/helpdesk/templates/helpdesk/ticket_resolves_add.html b/helpdesk/templates/helpdesk/ticket_resolves_add.html new file mode 100644 index 00000000..66165dd0 --- /dev/null +++ b/helpdesk/templates/helpdesk/ticket_resolves_add.html @@ -0,0 +1,37 @@ +{% extends "helpdesk/base.html" %}{% load i18n %} + +{% block helpdesk_title %}{% trans "Add Ticket as Dependency" %}{% endblock %} + +{% block helpdesk_breadcrumb %} + + + +{% endblock %} + +{% block helpdesk_body %}{% blocktrans %} +

Add Ticket as Dependency

+ +

Ticket: {{ depends_on }}

+ +

Adding this ticket as dependency will stop you resolving the selected ticket until this ticket has been resolved or closed.

{% endblocktrans %} + +
+ +
+
{% for field in form %} +
+
{{ field }}
+ {% if field.errors %}
{{ field.errors }}
{% endif %} + {% if field.help_text %}
{{ field.help_text }}
{% endif %} + {% endfor %}
+
+ + + +{% csrf_token %}
+ +{% endblock %} diff --git a/helpdesk/urls.py b/helpdesk/urls.py index 02345389..a374bce2 100644 --- a/helpdesk/urls.py +++ b/helpdesk/urls.py @@ -88,6 +88,16 @@ urlpatterns = [ staff.ticket_dependency_del, name="ticket_dependency_del", ), + path( + "tickets//resolves/add/", + staff.ticket_resolves_add, + name="ticket_resolves_add", + ), + path( + "tickets//resolves/delete//", + staff.ticket_resolves_del, + name="ticket_resolves_del", + ), path( "tickets//attachment_delete//", staff.attachment_del, diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py index 8abb9e7b..f89b5d08 100644 --- a/helpdesk/views/staff.py +++ b/helpdesk/views/staff.py @@ -20,7 +20,7 @@ from django.contrib.contenttypes.models import ContentType from django.core.exceptions import PermissionDenied from django.core.handlers.wsgi import WSGIRequest from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator -from django.db.models import Q +from django.db.models import Q, Case, When from django.forms import HiddenInput, inlineformset_factory, TextInput from django.http import Http404, HttpResponse, HttpResponseRedirect, JsonResponse from django.shortcuts import get_object_or_404, redirect, render @@ -54,6 +54,7 @@ from helpdesk.forms import ( TicketCCUserForm, TicketDependencyForm, TicketForm, + TicketResolvesForm, UserSettingsForm ) from helpdesk.lib import queue_template_context, safe_template_context @@ -422,8 +423,16 @@ def view_ticket(request, ticket_id): return redirect('helpdesk:edit_ticket_checklist', ticket.id, checklist.id) + # List open tickets on top + dependencies = ticket.ticketdependency.annotate( + rank=Case( + When(depends_on__status__in=Ticket.OPEN_STATUSES, then=1), + default=2 + )).order_by('rank') + return render(request, 'helpdesk/ticket.html', { 'ticket': ticket, + 'dependencies': dependencies, 'submitter_userprofile_url': submitter_userprofile_url, 'form': form, 'active_users': users, @@ -1664,15 +1673,15 @@ def ticket_dependency_add(request, ticket_id): ticket = get_object_or_404(Ticket, id=ticket_id) ticket_perm_check(request, ticket) if request.method == 'POST': - form = TicketDependencyForm(request.POST) + form = TicketDependencyForm(ticket, request.POST) if form.is_valid(): ticketdependency = form.save(commit=False) ticketdependency.ticket = ticket if ticketdependency.ticket != ticketdependency.depends_on: ticketdependency.save() - return HttpResponseRedirect(reverse('helpdesk:view', args=[ticket.id])) + return redirect(ticket.get_absolute_url()) else: - form = TicketDependencyForm() + form = TicketDependencyForm(ticket) return render(request, 'helpdesk/ticket_dependency_add.html', { 'ticket': ticket, 'form': form, @@ -1695,6 +1704,42 @@ def ticket_dependency_del(request, ticket_id, dependency_id): ticket_dependency_del = staff_member_required(ticket_dependency_del) +@helpdesk_staff_member_required +def ticket_resolves_add(request, ticket_id): + depends_on = get_object_or_404(Ticket, id=ticket_id) + ticket_perm_check(request, depends_on) + if request.method == 'POST': + form = TicketResolvesForm(depends_on, request.POST) + if form.is_valid(): + ticketdependency = form.save(commit=False) + ticketdependency.depends_on = depends_on + if ticketdependency.ticket != ticketdependency.depends_on: + ticketdependency.save() + return redirect(depends_on.get_absolute_url()) + else: + form = TicketResolvesForm(depends_on) + return render(request, 'helpdesk/ticket_resolves_add.html', { + 'depends_on': depends_on, + 'form': form, + }) + + +ticket_resolves_add = staff_member_required(ticket_resolves_add) + + +@helpdesk_staff_member_required +def ticket_resolves_del(request, ticket_id, dependency_id): + dependency = get_object_or_404( + TicketDependency, ticket__id=ticket_id, id=dependency_id) + depends_on_id = dependency.depends_on.id + if request.method == 'POST': + dependency.delete() + return HttpResponseRedirect(reverse('helpdesk:view', args=[depends_on_id])) + return render(request, 'helpdesk/ticket_dependency_del.html', {'dependency': dependency}) + +ticket_resolves_del = staff_member_required(ticket_resolves_del) + + @helpdesk_staff_member_required def attachment_del(request, ticket_id, attachment_id): ticket = get_object_or_404(Ticket, id=ticket_id)