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:
Ross Poulton 2011-01-29 06:02:03 +00:00
parent 4cb84ed4fb
commit 97886abc76
8 changed files with 147 additions and 59 deletions

View File

@ -23,6 +23,15 @@ class EditTicketForm(forms.ModelForm):
model = Ticket
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):
queue = forms.ChoiceField(
label=_('Queue'),

View File

@ -151,6 +151,7 @@ td {
div.followup {
width: 100%;
border-top: solid #666 1px;
padding:0 0 2px;
}
div.followup .title {
@ -257,3 +258,7 @@ span.priority5 {
background-color: #8c5;
color: #fff;
}
a.followup-edit {
float:right;
}

View File

@ -453,7 +453,8 @@ class FollowUp(models.Model):
ticket = models.ForeignKey(Ticket)
date = models.DateTimeField(
_('Date'),
_('Date'),
default = datetime.now()
)
title = models.CharField(
@ -505,7 +506,6 @@ class FollowUp(models.Model):
def save(self, force_insert=False, force_update=False):
t = self.ticket
t.modified = datetime.now()
self.date = datetime.now()
t.save()
super(FollowUp, self).save(force_insert, force_update)

View 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 %}

View File

@ -42,66 +42,18 @@
{% block helpdesk_body %}
<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>
{% include "helpdesk/ticket_desc_table.html" %}
{% if ticket.followup_set.all %}
<h3>{% trans "Follow-Ups" %}</h3>
{% load ticket_to_link %}
{% for followup in ticket.followup_set.all %}
<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>
{% if followup.comment %}{{ followup.comment|force_escape|num_to_link|linebreaksbr }}{% endif %}
<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>
<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 %}
{% 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>

View 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>

View File

@ -34,6 +34,10 @@ urlpatterns = patterns('helpdesk.views.staff',
url(r'^tickets/(?P<ticket_id>[0-9]+)/$',
'view_ticket',
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/$',
'edit_ticket',

View File

@ -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.template import loader, Context, RequestContext
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.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC
from helpdesk.settings import HAS_TAG_SUPPORT
@ -96,7 +97,40 @@ def delete_ticket(request, ticket_id):
return HttpResponseRedirect(reverse('helpdesk_home'))
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):
ticket = get_object_or_404(Ticket, id=ticket_id)
@ -749,7 +783,7 @@ def run_report(request, report):
'Dec',
)
month_columns = []
# Throw an error if there are no tickets
first_ticket = Ticket.objects.all().order_by('created')[0]
first_month = first_ticket.created.month
first_year = first_ticket.created.year