mirror of
https://gitea.mueller.network/extern/django-helpdesk.git
synced 2025-02-16 18:20:48 +01:00
Add ability for FollowUp records to be edited by staff. Closes Google Code issue #131; Github issue #5. Thanks to Google user 'alecs.box' for the patch.
This commit is contained in:
parent
4cb84ed4fb
commit
97886abc76
@ -23,6 +23,15 @@ class EditTicketForm(forms.ModelForm):
|
|||||||
model = Ticket
|
model = Ticket
|
||||||
exclude = ('created', 'modified', 'status', 'on_hold', 'resolution', 'last_escalation', 'assigned_to')
|
exclude = ('created', 'modified', 'status', 'on_hold', 'resolution', 'last_escalation', 'assigned_to')
|
||||||
|
|
||||||
|
class EditFollowUpForm(forms.ModelForm):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"Filter not openned tickets here."
|
||||||
|
super(EditFollowUpForm, self).__init__(*args, **kwargs)
|
||||||
|
self.fields["ticket"].queryset = Ticket.objects.filter(status__in=(Ticket.OPEN_STATUS, Ticket.REOPENED_STATUS))
|
||||||
|
class Meta:
|
||||||
|
model = FollowUp
|
||||||
|
exclude = ('date', 'user',)
|
||||||
|
|
||||||
class TicketForm(forms.Form):
|
class TicketForm(forms.Form):
|
||||||
queue = forms.ChoiceField(
|
queue = forms.ChoiceField(
|
||||||
label=_('Queue'),
|
label=_('Queue'),
|
||||||
|
@ -151,6 +151,7 @@ td {
|
|||||||
div.followup {
|
div.followup {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border-top: solid #666 1px;
|
border-top: solid #666 1px;
|
||||||
|
padding:0 0 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.followup .title {
|
div.followup .title {
|
||||||
@ -257,3 +258,7 @@ span.priority5 {
|
|||||||
background-color: #8c5;
|
background-color: #8c5;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a.followup-edit {
|
||||||
|
float:right;
|
||||||
|
}
|
@ -453,7 +453,8 @@ class FollowUp(models.Model):
|
|||||||
ticket = models.ForeignKey(Ticket)
|
ticket = models.ForeignKey(Ticket)
|
||||||
|
|
||||||
date = models.DateTimeField(
|
date = models.DateTimeField(
|
||||||
_('Date'),
|
_('Date'),
|
||||||
|
default = datetime.now()
|
||||||
)
|
)
|
||||||
|
|
||||||
title = models.CharField(
|
title = models.CharField(
|
||||||
@ -505,7 +506,6 @@ class FollowUp(models.Model):
|
|||||||
def save(self, force_insert=False, force_update=False):
|
def save(self, force_insert=False, force_update=False):
|
||||||
t = self.ticket
|
t = self.ticket
|
||||||
t.modified = datetime.now()
|
t.modified = datetime.now()
|
||||||
self.date = datetime.now()
|
|
||||||
t.save()
|
t.save()
|
||||||
super(FollowUp, self).save(force_insert, force_update)
|
super(FollowUp, self).save(force_insert, force_update)
|
||||||
|
|
||||||
|
31
helpdesk/templates/helpdesk/followup_edit.html
Normal file
31
helpdesk/templates/helpdesk/followup_edit.html
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}{% load i18n %}
|
||||||
|
{% block helpdesk_title %}{% trans "Edit followup" %}{% endblock %}
|
||||||
|
{% block helpdesk_head %}{% endblock helpdesk_head %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}
|
||||||
|
|
||||||
|
{% include "helpdesk/ticket_desc_table.html" %}
|
||||||
|
|
||||||
|
<h3>{% trans "Edit FollowUp" %}</h3>
|
||||||
|
<form action="." method="POST" name="edit_followup_form">
|
||||||
|
{{ form.non_field_errors }}
|
||||||
|
<fieldset>
|
||||||
|
<dl>
|
||||||
|
<dt><label for='id_ticket'>{% trans "Reassign ticket:" %}</label></dt>
|
||||||
|
<dd>{{ form.ticket }}</dd>
|
||||||
|
<dt><label for="id_title">{% trans "Title:" %}</label></dt>
|
||||||
|
<dd>{{ form.title }}</dd>
|
||||||
|
</dt>
|
||||||
|
<dt><label for="id_comment">{% trans "Comment:" %}</label></dt>
|
||||||
|
<dd>{{ form.comment }}</dd>
|
||||||
|
</dt>
|
||||||
|
<dt><label for="id_public">Public:</label></dt>
|
||||||
|
<dd>{{ form.public }}</dd>
|
||||||
|
<p>Public tickets are viewable by the submitter and all staff, but non-public tickets can only be seen by staff.</p>
|
||||||
|
<dt><label for="id_new_status">New Status:</label></dt>
|
||||||
|
<dd>{{ form.new_status }}</dd>
|
||||||
|
<p>If the status was changed, what was it changed to?</p>
|
||||||
|
</fieldset>
|
||||||
|
<p><input type="submit" value="Submit"></p>{% csrf_token %}
|
||||||
|
</form>
|
||||||
|
{% endblock helpdesk_body %}
|
@ -42,66 +42,18 @@
|
|||||||
|
|
||||||
{% block helpdesk_body %}
|
{% block helpdesk_body %}
|
||||||
|
|
||||||
<table width='100%'>
|
{% include "helpdesk/ticket_desc_table.html" %}
|
||||||
<tr class='row_tablehead'><td>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</td><td align='right'><a href='{% url helpdesk_edit ticket.id %}'><img src='{{ MEDIA_URL }}helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a><a href='{% url helpdesk_delete ticket.id %}'><img src='{{ MEDIA_URL }}helpdesk/buttons/delete.png' alt='Delete' title='Delete' width='60' height='15' /></a>{% if ticket.on_hold %}<a href='unhold/'>{% trans "Unhold" %}</a>{% else %}<a href='hold/'>{% trans "Hold" %}</a>{% endif %}</td></tr>
|
|
||||||
<tr class='row_columnheads'><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
|
||||||
|
|
||||||
<tr class='row_odd'>
|
|
||||||
<th>{% trans "Submitted On" %}</th>
|
|
||||||
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|timesince }} ago)</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class='row_even'>
|
|
||||||
<th>{% trans "Assigned To" %}</th>
|
|
||||||
<td>{{ ticket.get_assigned_to }}{% ifequal ticket.get_assigned_to _('Unassigned') %} <strong><a href='?take'><span class='button button_take'>{% trans "Take" %}</span></a></strong>{% endifequal %}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class='row_odd'>
|
|
||||||
<th>{% trans "Submitter E-Mail" %}</th>
|
|
||||||
<td>{{ ticket.submitter_email }}{% if user.is_superuser %} <strong><a href='{% url helpdesk_email_ignore_add %}?email={{ ticket.submitter_email }}'>{% trans "Ignore" %}</a></strong>{% endif %}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class='row_even'>
|
|
||||||
<th>{% trans "Priority" %}</th>
|
|
||||||
<td>{{ ticket.get_priority_display }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
<tr class='row_odd'>
|
|
||||||
<th>{% trans "Copies To" %}</th>
|
|
||||||
<td>{% for ticketcc in ticket.ticketcc_set.all %}{{ ticketcc.display }}{% if not forloop.last %}, {% endif %}{% endfor %} <strong><a href='{% url helpdesk_ticket_cc ticket.id %}'>{% trans "Manage" %}</a></strong></td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% if tags_enabled %}
|
|
||||||
<tr class='row_even'>
|
|
||||||
<th>{% trans "Tags" %}</th>
|
|
||||||
<td>{{ ticket.tags }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<tr class='row_even'>
|
|
||||||
<tr class='row_{% if tags_enabled %}odd{% else %}even{% endif %}'>
|
|
||||||
<th colspan='2'>{% trans "Description" %}</th>
|
|
||||||
</tr>
|
|
||||||
<tr class='row_{% if tags_enabled %}even{% else %}odd{% endif %}'>
|
|
||||||
<td colspan='2'>{{ ticket.description|force_escape|linebreaksbr }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% if ticket.resolution %}<tr class='row_{% if tags_enabled %}odd{% else %}even{% endif %}'>
|
|
||||||
<th colspan='2'>{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}helpdesk/buttons/accept.png' alt='{% trans "Accept" %}' title='{% trans "Accept and Close" %}' width='60' height='15' /></a>{% endifequal %}</th>
|
|
||||||
</tr>
|
|
||||||
<tr class='row_{% if tags_enabled %}even{% else %}odd{% endif %}'>
|
|
||||||
<td colspan='2'>{{ ticket.resolution|force_escape }}</td>
|
|
||||||
</tr>{% endif %}
|
|
||||||
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% if ticket.followup_set.all %}
|
{% if ticket.followup_set.all %}
|
||||||
<h3>{% trans "Follow-Ups" %}</h3>
|
<h3>{% trans "Follow-Ups" %}</h3>
|
||||||
{% load ticket_to_link %}
|
{% load ticket_to_link %}
|
||||||
{% for followup in ticket.followup_set.all %}
|
{% for followup in ticket.followup_set.all %}
|
||||||
<div class='followup'>
|
<div class='followup'>
|
||||||
<div class='title'>{{ followup.title }} <span class='byline'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"r" }}'>{{ followup.date|timesince }} ago</span>{% if not followup.public %} <span class='private'>({% trans "Private" %})</span>{% endif %}</span></div>
|
<div class='title'>
|
||||||
{% if followup.comment %}{{ followup.comment|force_escape|num_to_link|linebreaksbr }}{% endif %}
|
{{ followup.title }} <span class='byline'>{% if followup.user %}by {{ followup.user }}{% endif %} <span title='{{ followup.date|date:"r" }}'>{{ followup.date|timesince }} ago</span>{% if not followup.public %} <span class='private'>({% trans "Private" %})</span>{% endif %}</span>
|
||||||
|
<a href="{% url helpdesk_followup_edit ticket.id followup.id %}" class='followup-edit'><img width="60" height="15" title="Edit" alt="Edit" src="{{ MEDIA_URL }}helpdesk/buttons/edit.png"></a>
|
||||||
|
</div>
|
||||||
|
<span class='followup-desc'>{% if followup.comment %}{{ followup.comment|force_escape|num_to_link|linebreaksbr }}{% endif %}</span>
|
||||||
{% for change in followup.ticketchange_set.all %}
|
{% for change in followup.ticketchange_set.all %}
|
||||||
{% if forloop.first %}<div class='changes'><ul>{% endif %}
|
{% if forloop.first %}<div class='changes'><ul>{% endif %}
|
||||||
<li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li>
|
<li>{% blocktrans with change.field as field and change.old_value as old_value and change.new_value as new_value %}Changed {{ field }} from {{ old_value }} to {{ new_value }}.{% endblocktrans %}</li>
|
||||||
|
53
helpdesk/templates/helpdesk/ticket_desc_table.html
Normal file
53
helpdesk/templates/helpdesk/ticket_desc_table.html
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
<table width='100%'>
|
||||||
|
<tr class='row_tablehead'><td>{{ ticket.id }}. {{ ticket.title }} [{{ ticket.get_status }}]</td><td align='right'><a href='{% url helpdesk_edit ticket.id %}'><img src='{{ MEDIA_URL }}helpdesk/buttons/edit.png' alt='Edit' title='Edit' width='60' height='15' /></a><a href='{% url helpdesk_delete ticket.id %}'><img src='{{ MEDIA_URL }}helpdesk/buttons/delete.png' alt='Delete' title='Delete' width='60' height='15' /></a>{% if ticket.on_hold %}<a href='unhold/'>{% trans "Unhold" %}</a>{% else %}<a href='hold/'>{% trans "Hold" %}</a>{% endif %}</td></tr>
|
||||||
|
<tr class='row_columnheads'><th colspan='2'>{% blocktrans with ticket.queue as queue %}Queue: {{ queue }}{% endblocktrans %}</th></tr>
|
||||||
|
|
||||||
|
<tr class='row_odd'>
|
||||||
|
<th>{% trans "Submitted On" %}</th>
|
||||||
|
<td>{{ ticket.created|date:"r" }} ({{ ticket.created|timesince }} ago)</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class='row_even'>
|
||||||
|
<th>{% trans "Assigned To" %}</th>
|
||||||
|
<td>{{ ticket.get_assigned_to }}{% ifequal ticket.get_assigned_to _('Unassigned') %} <strong><a href='?take'><span class='button button_take'>{% trans "Take" %}</span></a></strong>{% endifequal %}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class='row_odd'>
|
||||||
|
<th>{% trans "Submitter E-Mail" %}</th>
|
||||||
|
<td>{{ ticket.submitter_email }}{% if user.is_superuser %} <strong><a href='{% url helpdesk_email_ignore_add %}?email={{ ticket.submitter_email }}'>{% trans "Ignore" %}</a></strong>{% endif %}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class='row_even'>
|
||||||
|
<th>{% trans "Priority" %}</th>
|
||||||
|
<td>{{ ticket.get_priority_display }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr class='row_odd'>
|
||||||
|
<th>{% trans "Copies To" %}</th>
|
||||||
|
<td>{% for ticketcc in ticket.ticketcc_set.all %}{{ ticketcc.display }}{% if not forloop.last %}, {% endif %}{% endfor %} <strong><a href='{% url helpdesk_ticket_cc ticket.id %}'>{% trans "Manage" %}</a></strong></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% if tags_enabled %}
|
||||||
|
<tr class='row_even'>
|
||||||
|
<th>{% trans "Tags" %}</th>
|
||||||
|
<td>{{ ticket.tags }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<tr class='row_even'>
|
||||||
|
<tr class='row_{% if tags_enabled %}odd{% else %}even{% endif %}'>
|
||||||
|
<th colspan='2'>{% trans "Description" %}</th>
|
||||||
|
</tr>
|
||||||
|
<tr class='row_{% if tags_enabled %}even{% else %}odd{% endif %}'>
|
||||||
|
<td colspan='2'>{{ ticket.description|force_escape|linebreaksbr }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% if ticket.resolution %}<tr class='row_{% if tags_enabled %}odd{% else %}even{% endif %}'>
|
||||||
|
<th colspan='2'>{% trans "Resolution" %}{% ifequal ticket.get_status_display "Resolved" %} <a href='?close'><img src='{{ MEDIA_URL }}helpdesk/buttons/accept.png' alt='{% trans "Accept" %}' title='{% trans "Accept and Close" %}' width='60' height='15' /></a>{% endifequal %}</th>
|
||||||
|
</tr>
|
||||||
|
<tr class='row_{% if tags_enabled %}even{% else %}odd{% endif %}'>
|
||||||
|
<td colspan='2'>{{ ticket.resolution|force_escape }}</td>
|
||||||
|
</tr>{% endif %}
|
||||||
|
|
||||||
|
</table>
|
@ -34,6 +34,10 @@ urlpatterns = patterns('helpdesk.views.staff',
|
|||||||
url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
|
url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
|
||||||
'view_ticket',
|
'view_ticket',
|
||||||
name='helpdesk_view'),
|
name='helpdesk_view'),
|
||||||
|
|
||||||
|
url(r'^tickets/(?P<ticket_id>[0-9]+)/followup_edit/(?P<followup_id>[0-9]+)/$',
|
||||||
|
'followup_edit',
|
||||||
|
name='helpdesk_followup_edit'),
|
||||||
|
|
||||||
url(r'^tickets/(?P<ticket_id>[0-9]+)/edit/$',
|
url(r'^tickets/(?P<ticket_id>[0-9]+)/edit/$',
|
||||||
'edit_ticket',
|
'edit_ticket',
|
||||||
|
@ -21,8 +21,9 @@ from django.http import HttpResponseRedirect, Http404, HttpResponse, HttpRespons
|
|||||||
from django.shortcuts import render_to_response, get_object_or_404
|
from django.shortcuts import render_to_response, get_object_or_404
|
||||||
from django.template import loader, Context, RequestContext
|
from django.template import loader, Context, RequestContext
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.utils.html import escape
|
||||||
|
|
||||||
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm
|
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, EditFollowUpForm
|
||||||
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict, apply_query, safe_template_context
|
from helpdesk.lib import send_templated_mail, line_chart, bar_chart, query_to_dict, apply_query, safe_template_context
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC
|
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC
|
||||||
from helpdesk.settings import HAS_TAG_SUPPORT
|
from helpdesk.settings import HAS_TAG_SUPPORT
|
||||||
@ -96,7 +97,40 @@ def delete_ticket(request, ticket_id):
|
|||||||
return HttpResponseRedirect(reverse('helpdesk_home'))
|
return HttpResponseRedirect(reverse('helpdesk_home'))
|
||||||
delete_ticket = staff_member_required(delete_ticket)
|
delete_ticket = staff_member_required(delete_ticket)
|
||||||
|
|
||||||
|
def followup_edit(request, ticket_id, followup_id, ):
|
||||||
|
"Edit followup options with an ability to change the ticket."
|
||||||
|
followup = get_object_or_404(FollowUp, id=followup_id)
|
||||||
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
|
if request.method == 'GET':
|
||||||
|
form = EditFollowUpForm(initial=
|
||||||
|
{'title': escape(followup.title),
|
||||||
|
'ticket': followup.ticket,
|
||||||
|
'comment': escape(followup.comment),
|
||||||
|
'public': followup.public,
|
||||||
|
'new_status': followup.new_status,
|
||||||
|
})
|
||||||
|
|
||||||
|
return render_to_response('helpdesk/followup_edit.html',
|
||||||
|
RequestContext(request, {
|
||||||
|
'followup': followup,
|
||||||
|
'ticket': ticket,
|
||||||
|
'form': form,
|
||||||
|
}))
|
||||||
|
elif request.method == 'POST':
|
||||||
|
form = EditFollowUpForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
title = form.cleaned_data['title']
|
||||||
|
_ticket = form.cleaned_data['ticket']
|
||||||
|
comment = form.cleaned_data['comment']
|
||||||
|
public = form.cleaned_data['public']
|
||||||
|
new_status = form.cleaned_data['new_status']
|
||||||
|
#will save previous date
|
||||||
|
old_date = followup.date
|
||||||
|
followup.delete()
|
||||||
|
new_followup = FollowUp(title=title, date=old_date, ticket=_ticket, comment=comment, public=public, new_status=new_status, )
|
||||||
|
new_followup.save()
|
||||||
|
return HttpResponseRedirect(reverse('helpdesk_view', args=[ticket.id]))
|
||||||
|
|
||||||
def view_ticket(request, ticket_id):
|
def view_ticket(request, ticket_id):
|
||||||
ticket = get_object_or_404(Ticket, id=ticket_id)
|
ticket = get_object_or_404(Ticket, id=ticket_id)
|
||||||
|
|
||||||
@ -749,7 +783,7 @@ def run_report(request, report):
|
|||||||
'Dec',
|
'Dec',
|
||||||
)
|
)
|
||||||
month_columns = []
|
month_columns = []
|
||||||
|
# Throw an error if there are no tickets
|
||||||
first_ticket = Ticket.objects.all().order_by('created')[0]
|
first_ticket = Ticket.objects.all().order_by('created')[0]
|
||||||
first_month = first_ticket.created.month
|
first_month = first_ticket.created.month
|
||||||
first_year = first_ticket.created.year
|
first_year = first_ticket.created.year
|
||||||
|
Loading…
Reference in New Issue
Block a user