mirror of
https://github.com/django-helpdesk/django-helpdesk.git
synced 2024-12-13 18:31:10 +01:00
* Removed e-mail templates to the database
* Added statistics views, making use of Google Charts * Added initial data fixture, to automatically create e-mail templates at install-time
This commit is contained in:
parent
47afa9b45b
commit
7dfb38eab9
22
api.py
22
api.py
@ -20,7 +20,7 @@ from django.shortcuts import render_to_response
|
|||||||
from django.template import loader, Context
|
from django.template import loader, Context
|
||||||
from django import newforms as forms
|
from django import newforms as forms
|
||||||
|
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp
|
from helpdesk.models import Ticket, Queue, FollowUp
|
||||||
from helpdesk.forms import TicketForm
|
from helpdesk.forms import TicketForm
|
||||||
|
|
||||||
@ -174,19 +174,14 @@ class API:
|
|||||||
'comment': f.comment,
|
'comment': f.comment,
|
||||||
}
|
}
|
||||||
|
|
||||||
subject = '%s %s (Updated)' % (ticket.ticket, ticket.title)
|
|
||||||
|
|
||||||
if public and ticket.submitter_email:
|
if public and ticket.submitter_email:
|
||||||
template = 'helpdesk/emails/submitter_updated'
|
send_templated_mail('updated_submitter', context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template, context, subject, ticket.submitter_email, ticket.queue.from_address)
|
|
||||||
|
|
||||||
if ticket.queue.updated_ticket_cc:
|
if ticket.queue.updated_ticket_cc:
|
||||||
template_cc = 'helpdesk/emails/cc_updated'
|
send_templated_mail('updated_cc', context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template_cc, context, subject, q.updated_ticket_cc, ticket.queue.from_address)
|
|
||||||
|
|
||||||
if ticket.assigned_to and self.request.user != ticket.assigned_to:
|
if ticket.assigned_to and self.request.user != ticket.assigned_to:
|
||||||
template_owner = 'helpdesk/emails/owner_updated'
|
send_templated_mail('updated_owner', context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template_owner, context, subject, t.assigned_to.email, ticket.queue.from_address)
|
|
||||||
|
|
||||||
ticket.save()
|
ticket.save()
|
||||||
|
|
||||||
@ -216,16 +211,13 @@ class API:
|
|||||||
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
||||||
|
|
||||||
if ticket.submitter_email:
|
if ticket.submitter_email:
|
||||||
template = 'helpdesk/emails/submitter_resolved'
|
send_templated_mail('resolved_submitter', context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template, context, subject, ticket.submitter_email, ticket.queue.from_address)
|
|
||||||
|
|
||||||
if ticket.queue.updated_ticket_cc:
|
if ticket.queue.updated_ticket_cc:
|
||||||
template_cc = 'helpdesk/emails/cc_resolved'
|
send_templated_mail('resolved_cc', context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template_cc, context, subject, q.updated_ticket_cc, ticket.queue.from_address)
|
|
||||||
|
|
||||||
if ticket.assigned_to and self.request.user != ticket.assigned_to:
|
if ticket.assigned_to and self.request.user != ticket.assigned_to:
|
||||||
template_owner = 'helpdesk/emails/owner_resolved'
|
send_templated_mail('resolved_resolved', context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template_owner, context, subject, t.assigned_to.email, ticket.queue.from_address)
|
|
||||||
|
|
||||||
ticket.resoltuion = f.comment
|
ticket.resoltuion = f.comment
|
||||||
ticket.status = Ticket.RESOLVED_STATUS
|
ticket.status = Ticket.RESOLVED_STATUS
|
||||||
|
1
fixtures/initial_data.json
Normal file
1
fixtures/initial_data.json
Normal file
File diff suppressed because one or more lines are too long
18
forms.py
18
forms.py
@ -77,19 +77,19 @@ class TicketForm(forms.Form):
|
|||||||
'queue': q,
|
'queue': q,
|
||||||
}
|
}
|
||||||
|
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
|
|
||||||
if t.submitter_email:
|
if t.submitter_email:
|
||||||
send_multipart_mail('helpdesk/emails/submitter_newticket', context, '%s %s' % (t.ticket, t.title), t.submitter_email, q.from_address)
|
send_templated_mail('newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
if t.assigned_to and t.assigned_to != user:
|
if t.assigned_to and t.assigned_to != user:
|
||||||
send_multipart_mail('helpdesk/emails/owner_assigned', context, '%s %s (Opened)' % (t.ticket, t.title), t.assigned_to.email, q.from_address)
|
send_templated_mail('assigned_owner', context, recipients=t.assigned_to.email, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
if q.new_ticket_cc:
|
if q.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), q.updated_ticket_cc, q.from_address)
|
send_templated_mail('newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc:
|
if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), q.updated_ticket_cc, q.from_address)
|
send_templated_mail('newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
||||||
@ -146,13 +146,13 @@ class PublicTicketForm(forms.Form):
|
|||||||
'queue': q,
|
'queue': q,
|
||||||
}
|
}
|
||||||
|
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
send_multipart_mail('helpdesk/emails/submitter_newticket', context, '%s %s' % (t.ticket, t.title), t.submitter_email, q.from_address)
|
send_templated_mail('newticket_submitter', context, recipients=t.submitter_email, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
if q.new_ticket_cc:
|
if q.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), q.updated_ticket_cc, q.from_address)
|
send_templated_mail('newticket_cc', context, recipients=q.new_ticket_cc, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc:
|
if q.updated_ticket_cc and q.updated_ticket_cc != q.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), q.updated_ticket_cc, q.from_address)
|
send_templated_mail('newticket_cc', context, recipients=q.updated_ticket_cc, sender=q.from_address, fail_silently=True)
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
@ -11,7 +11,7 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#container {
|
#container {
|
||||||
width: 600px;
|
width: 700px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
@ -26,7 +26,34 @@ table {
|
|||||||
#header li {
|
#header li {
|
||||||
display: inline;
|
display: inline;
|
||||||
float: left;
|
float: left;
|
||||||
padding-left: 5px;
|
}
|
||||||
|
|
||||||
|
#header li a {
|
||||||
|
padding: 2px 3px;
|
||||||
|
margin: 2px;
|
||||||
|
border: solid #444 1px;
|
||||||
|
color: #000;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 10pt;
|
||||||
|
line-height: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchform .input {
|
||||||
|
border: solid #444 1px;
|
||||||
|
background-color: #fff;
|
||||||
|
color: #ccc;
|
||||||
|
padding: 2px 3px;
|
||||||
|
margin: 0px 2px;
|
||||||
|
font-size: 10pt;
|
||||||
|
line-height: 12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchform .input:focus {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header li a:hover {
|
||||||
|
background-color: #ccc;
|
||||||
}
|
}
|
||||||
|
|
||||||
#header, #body, #footer {
|
#header, #body, #footer {
|
||||||
|
121
lib.py
121
lib.py
@ -5,6 +5,39 @@ Jutda Helpdesk - A Django powered ticket tracker for small enterprise.
|
|||||||
|
|
||||||
lib.py - Common functions (eg multipart e-mail)
|
lib.py - Common functions (eg multipart e-mail)
|
||||||
"""
|
"""
|
||||||
|
def send_templated_mail(template_name, email_context, recipients, sender=None, bcc=None, fail_silently=False, files=None):
|
||||||
|
from helpdesk.models import EmailTemplate
|
||||||
|
from django.core.mail import EmailMultiAlternatives
|
||||||
|
from django.template import loader, Context
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
t = EmailTemplate.objects.get(template_name__iexact=template_name)
|
||||||
|
|
||||||
|
if not sender:
|
||||||
|
sender = settings.DEFAULT_FROM_EMAIL
|
||||||
|
|
||||||
|
context = Context(email_context)
|
||||||
|
|
||||||
|
text_part = loader.get_template_from_string("%s{%% include 'helpdesk/email_text_footer.txt' %%}" % t.plain_text).render(context)
|
||||||
|
html_part = loader.get_template_from_string("{%% extends 'helpdesk/email_html_base.html' %%}{%% block title %%}%s{%% endblock %%}{%% block content %%}%s{%% endblock %%}" % (t.heading, t.html)).render(context)
|
||||||
|
subject_part = loader.get_template_from_string("{{ ticket.ticket }} {{ ticket.title }} %s" % t.subject).render(context)
|
||||||
|
|
||||||
|
if type(recipients) != list:
|
||||||
|
recipients = [recipients,]
|
||||||
|
|
||||||
|
msg = EmailMultiAlternatives(subject_part, text_part, sender, recipients, bcc=bcc)
|
||||||
|
msg.attach_alternative(html_part, "text/html")
|
||||||
|
|
||||||
|
if files:
|
||||||
|
if type(files) != list:
|
||||||
|
files = [files,]
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
msg.attach_file(file)
|
||||||
|
|
||||||
|
return msg.send(fail_silently)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def send_multipart_mail(template_name, email_context, subject, recipients, sender=None, bcc=None, fail_silently=False, files=None):
|
def send_multipart_mail(template_name, email_context, subject, recipients, sender=None, bcc=None, fail_silently=False, files=None):
|
||||||
"""
|
"""
|
||||||
@ -58,14 +91,96 @@ def send_multipart_mail(template_name, email_context, subject, recipients, sende
|
|||||||
return msg.send(fail_silently)
|
return msg.send(fail_silently)
|
||||||
|
|
||||||
|
|
||||||
def normalise_to_100(data):
|
def normalise_data(data, to=100):
|
||||||
"""
|
"""
|
||||||
Used for normalising data prior to graphing with Google charting API
|
Used for normalising data prior to graphing with Google charting API
|
||||||
"""
|
"""
|
||||||
max_value = max(data)
|
max_value = max(data)
|
||||||
if max_value > 100:
|
if max_value > to:
|
||||||
new_data = []
|
new_data = []
|
||||||
for d in data:
|
for d in data:
|
||||||
new_data.append(int(d/float(max_value)*100))
|
new_data.append(int(d/float(max_value)*to))
|
||||||
data = new_data
|
data = new_data
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
chart_colours = ('80C65A', '990066', 'FF9900', '3399CC', 'BBCCED', '3399CC', 'FFCC33')
|
||||||
|
|
||||||
|
def line_chart(data):
|
||||||
|
"""
|
||||||
|
'data' is a list of lists making a table.
|
||||||
|
Row 1, columns 2-n are data headings (the time periods)
|
||||||
|
Rows 2-n are data, with column 1 being the line labels
|
||||||
|
"""
|
||||||
|
|
||||||
|
column_headings = data[0][1:]
|
||||||
|
max = 0
|
||||||
|
for row in data[1:]:
|
||||||
|
for field in row[1:]:
|
||||||
|
if field > max:
|
||||||
|
max = field
|
||||||
|
|
||||||
|
|
||||||
|
# Set width to '65px * number of months'.
|
||||||
|
chart_url = 'http://chart.apis.google.com/chart?cht=lc&chs=%sx90&chd=t:' % (len(column_headings)*65)
|
||||||
|
first_row = True
|
||||||
|
row_headings = []
|
||||||
|
for row in data[1:]:
|
||||||
|
# Add data to URL, normalised to the maximum for all lines on this chart
|
||||||
|
norm = normalise_data(row[1:], max)
|
||||||
|
if not first_row:
|
||||||
|
chart_url += '|'
|
||||||
|
chart_url += ','.join([str(num) for num in norm])
|
||||||
|
row_headings.append(row[0])
|
||||||
|
first_row = False
|
||||||
|
|
||||||
|
chart_url += '&chds='
|
||||||
|
rows = len(data)-1
|
||||||
|
first = True
|
||||||
|
for row in range(rows):
|
||||||
|
# Set maximum data ranges to '0:x' where 'x' is the maximum number in use.
|
||||||
|
if not first:
|
||||||
|
chart_url += ','
|
||||||
|
chart_url += '0,%s' % max
|
||||||
|
first = False
|
||||||
|
chart_url += '&chdl=%s' % '|'.join(row_headings) # Display legend/labels
|
||||||
|
chart_url += '&chco=%s' % ','.join(chart_colours) # Default colour set
|
||||||
|
chart_url += '&chxt=x,y' # Turn on axis labels
|
||||||
|
chart_url += '&chxl=0:|%s|1:|0|%s' % ('|'.join(column_headings), max) # Axis Label Text
|
||||||
|
|
||||||
|
return chart_url
|
||||||
|
|
||||||
|
def bar_chart(data):
|
||||||
|
"""
|
||||||
|
'data' is a list of lists making a table.
|
||||||
|
Row 1, columns 2-n are data headings
|
||||||
|
Rows 2-n are data, with column 1 being the line labels
|
||||||
|
"""
|
||||||
|
|
||||||
|
column_headings = data[0][1:]
|
||||||
|
max = 0
|
||||||
|
for row in data[1:]:
|
||||||
|
for field in row[1:]:
|
||||||
|
if field > max:
|
||||||
|
max = field
|
||||||
|
|
||||||
|
|
||||||
|
# Set width to '150px * number of months'.
|
||||||
|
chart_url = 'http://chart.apis.google.com/chart?cht=bvg&chs=%sx90&chd=t:' % (len(column_headings) * 150)
|
||||||
|
first_row = True
|
||||||
|
row_headings = []
|
||||||
|
for row in data[1:]:
|
||||||
|
# Add data to URL, normalised to the maximum for all lines on this chart
|
||||||
|
norm = normalise_data(row[1:], max)
|
||||||
|
if not first_row:
|
||||||
|
chart_url += '|'
|
||||||
|
chart_url += ','.join([str(num) for num in norm])
|
||||||
|
row_headings.append(row[0])
|
||||||
|
first_row = False
|
||||||
|
|
||||||
|
chart_url += '&chds=0,%s' % max
|
||||||
|
chart_url += '&chdl=%s' % '|'.join(row_headings) # Display legend/labels
|
||||||
|
chart_url += '&chco=%s' % ','.join(chart_colours) # Default colour set
|
||||||
|
chart_url += '&chxt=x,y' # Turn on axis labels
|
||||||
|
chart_url += '&chxl=0:|%s|1:|0|%s' % ('|'.join(column_headings), max) # Axis Label Text
|
||||||
|
|
||||||
|
return chart_url
|
||||||
|
31
models.py
31
models.py
@ -94,11 +94,11 @@ class Ticket(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
PRIORITY_CHOICES = (
|
PRIORITY_CHOICES = (
|
||||||
(1, '1 (Critical)'),
|
(1, '1. Critical'),
|
||||||
(2, '2 (High)'),
|
(2, '2. High'),
|
||||||
(3, '3 (Normal)'),
|
(3, '3. Normal'),
|
||||||
(4, '4 (Low)'),
|
(4, '4. Low'),
|
||||||
(5, '5 (Very Low)'),
|
(5, '5. Very Low'),
|
||||||
)
|
)
|
||||||
|
|
||||||
title = models.CharField(maxlength=200)
|
title = models.CharField(maxlength=200)
|
||||||
@ -342,3 +342,24 @@ class EscalationExclusion(models.Model):
|
|||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return u'%s' % self.name
|
return u'%s' % self.name
|
||||||
|
|
||||||
|
class EmailTemplate(models.Model):
|
||||||
|
"""
|
||||||
|
Since these are more likely to be changed than other templates, we store
|
||||||
|
them in the database.
|
||||||
|
"""
|
||||||
|
|
||||||
|
template_name = models.CharField(maxlength=100, unique=True)
|
||||||
|
|
||||||
|
subject = models.CharField(maxlength=100, help_text=u'This will be prefixed with "[ticket.ticket] ticket.title". We recommend something simple such as "(Updated") or "(Closed)" - the same context is available as in plain_text, below.')
|
||||||
|
heading = models.CharField(maxlength=100, help_text=u'In HTML e-mails, this will be the heading at the top of the email - the same context is available as in plain_text, below.')
|
||||||
|
plain_text = models.TextField(help_text=u'The context available to you includes {{ ticket }}, {{ queue }}, and depending on the time of the call: {{ resolution }} or {{ comment }}.')
|
||||||
|
html = models.TextField(help_text=u'The same context is available here as in plain_text, above.')
|
||||||
|
|
||||||
|
class Admin:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return u'%s' % self.template_name
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
ordering = ['template_name',]
|
||||||
|
@ -10,7 +10,7 @@ scripts/escalate_tickets.py - Easy way to escalate tickets based on their age,
|
|||||||
from datetime import datetime, timedelta, date
|
from datetime import datetime, timedelta, date
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange
|
from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
import sys, getopt
|
import sys, getopt
|
||||||
|
|
||||||
def escalate_tickets(queues, verbose):
|
def escalate_tickets(queues, verbose):
|
||||||
@ -48,13 +48,13 @@ def escalate_tickets(queues, verbose):
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t.submitter_email:
|
if t.submitter_email:
|
||||||
send_multipart_mail('helpdesk/emails/submitter_escalated', context, '%s %s' % (t.ticket, t.title), t.submitter_email, t.queue.from_address)
|
send_templated_mail('escalated_submitter', context, recipients=t.submitter_email, sender=t.queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if t.queue.updated_ticket_cc:
|
if t.queue.updated_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_escalated', context, '%s %s' % (t.ticket, t.title), t.queue.updated_ticket_cc, t.queue.from_address)
|
send_templated_mail('escalated_cc', context, recipients=t.queue.updated_ticket_cc, sender=t.queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if t.assigned_to:
|
if t.assigned_to:
|
||||||
send_multipart_mail('helpdesk/emails/owner_escalated', context, '%s %s' % (t.ticket, t.title), t.assigned_to, t.queue.from_address)
|
send_templated_mail('escalated_owner', context, recipients=t.assigned_to.email, sender=t.queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print " - Esclating %s from %s>%s" % (t.ticket, t.priority+1, t.priority)
|
print " - Esclating %s from %s>%s" % (t.ticket, t.priority+1, t.priority)
|
||||||
|
@ -15,7 +15,7 @@ from datetime import datetime, timedelta
|
|||||||
import email, mimetypes, re
|
import email, mimetypes, re
|
||||||
from email.Utils import parseaddr
|
from email.Utils import parseaddr
|
||||||
from helpdesk.models import Queue, Ticket, FollowUp, Attachment
|
from helpdesk.models import Queue, Ticket, FollowUp, Attachment
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail
|
||||||
|
|
||||||
def process_email():
|
def process_email():
|
||||||
for q in Queue.objects.filter(email_box_type__isnull=False):
|
for q in Queue.objects.filter(email_box_type__isnull=False):
|
||||||
@ -138,22 +138,22 @@ def ticket_from_message(message, queue):
|
|||||||
if new:
|
if new:
|
||||||
|
|
||||||
if sender_email:
|
if sender_email:
|
||||||
send_multipart_mail('helpdesk/emails/submitter_newticket', context, '%s %s' % (t.ticket, t.title), sender_email, queue.from_address, fail_silently=True)
|
send_templated_mail('newticket_submitter', context, recipients=sender_email, sender=queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if queue.new_ticket_cc:
|
if queue.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), queue.updated_ticket_cc, queue.from_address, fail_silently=True)
|
send_templated_mail('newticket_cc', context, recipients=queue.new_ticket_cc, sender=queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc:
|
if queue.updated_ticket_cc and queue.updated_ticket_cc != queue.new_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_newticket', context, '%s %s (Opened)' % (t.ticket, t.title), queue.updated_ticket_cc, queue.from_address, fail_silently=True)
|
send_templated_mail('newticket_cc', context, recipients=queue.updated_ticket_cc, sender=queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
update = " (Updated)"
|
update = " (Updated)"
|
||||||
|
|
||||||
if t.assigned_to:
|
if t.assigned_to:
|
||||||
send_multipart_mail('helpdesk/emails/owner_updated', context, '%s %s (Updated)' % (t.ticket, t.title), t.assigned_to.email, queue.from_address, file_silently=True)
|
send_templated_mail('updated_owner', context, recipients=t.assigned_to.email, sender=queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if queue.updated_ticket_cc:
|
if queue.updated_ticket_cc:
|
||||||
send_multipart_mail('helpdesk/emails/cc_updated', context, '%s %s (Updated)' % (t.ticket, t.title), queue.updated_ticket_cc, queue.from_address, fail_silently=True)
|
send_templated_mail('updated_cc', context, recipients=queue.updated_ticket_cc, sender=queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
f = FollowUp(
|
f = FollowUp(
|
||||||
ticket = t,
|
ticket = t,
|
||||||
|
@ -12,9 +12,10 @@
|
|||||||
<ul>
|
<ul>
|
||||||
<li><a href='{% url helpdesk_home %}'>Dashboard</a></li>
|
<li><a href='{% url helpdesk_home %}'>Dashboard</a></li>
|
||||||
<li><a href='{% url helpdesk_list %}'>Tickets</a></li>
|
<li><a href='{% url helpdesk_list %}'>Tickets</a></li>
|
||||||
<li><a href='{% url helpdesk_submit %}'>Submit Ticket</a></li>
|
<li><a href='{% url helpdesk_submit %}'>New Ticket</a></li>
|
||||||
|
<li><a href='{% url helpdesk_report_index %}'>Stats</a></li>
|
||||||
<li><a href='{% url logout %}'>Logout</a></li>
|
<li><a href='{% url logout %}'>Logout</a></li>
|
||||||
{% if not query %}<li><form method='get' action='{% url helpdesk_list %}'><input type='text' name='q' size='10' /><input type='hidden' name='status' value='1' /><input type='hidden' name='status' value='2' /><input type='hidden' name='status' value='3' /><input type='submit' value='Search' /></form></li>{% endif %}
|
{% if not query %}<li><form id='searchform' method='get' action='{% url helpdesk_list %}'><input type='text' name='q' size='10' class='input' value='Search...' id='search_query' onFocus='s = document.getElementById("search_query");if (s.value == "Search...") { s.value = ""; }' /><input type='hidden' name='status' value='1' /><input type='hidden' name='status' value='2' /><input type='hidden' name='status' value='3' /></form></li>{% endif %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div id='body'>
|
<div id='body'>
|
||||||
|
@ -9,9 +9,9 @@
|
|||||||
<tr class='row_columnheads'><th>Queue</th><th>Open</th><th>Resolved</th></tr>
|
<tr class='row_columnheads'><th>Queue</th><th>Open</th><th>Resolved</th></tr>
|
||||||
{% for queue in dash_tickets %}
|
{% for queue in dash_tickets %}
|
||||||
<tr class='row_{% cycle odd,even %} row_hover '>
|
<tr class='row_{% cycle odd,even %} row_hover '>
|
||||||
<th><a href='{% url helpdesk_list %}?queue={{ queue.queue.id }}'>{{ queue.queue }}</a></th>
|
<th><a href='{% url helpdesk_list %}?queue={{ queue.queue }}'>{{ queue.name }}</a></th>
|
||||||
<td>{% if queue.open %}<a href='{% url helpdesk_list %}?queue={{ queue.queue.id }}&status=1&status=2'>{% endif %}{{ queue.open }}{% if queue.open %}</a>{% endif %}</td>
|
<td>{% if queue.open %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=1&status=2'>{% endif %}{{ queue.open }}{% if queue.open %}</a>{% endif %}</td>
|
||||||
<td>{% if queue.resolved %}<a href='{% url helpdesk_list %}?queue={{ queue.queue.id }}&status=3'>{% endif %}{{ queue.resolved }}{% if queue.resolved %}</a>{% endif %}</td>
|
<td>{% if queue.resolved %}<a href='{% url helpdesk_list %}?queue={{ queue.queue }}&status=3'>{% endif %}{{ queue.resolved }}{% if queue.resolved %}</a>{% endif %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,10 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Re-Assigned{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is a courtesy e-mail to let you know that ticket <a href='{{ ticket.staff_url }}'><b>{{ ticket.ticket }}</b></a> (<em>{{ ticket.title }}</em>) has been {% if ticket.assigned_to %}assigned to {{ ticket.assigned_to %}{% else %}unassigned{% endif %}.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
This is a courtesy e-mail to let you know that ticket {{ ticket.ticket }} ("{{ ticket.title }}") has been {% if ticket.assigned_to %}assigned to {{ ticket.assigned_to }}{% else %}unassigned{% endif %}
|
|
||||||
|
|
||||||
You can view this online at {{ ticket.staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,12 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Closed{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Ticket <i>{{ ticket.title }}</i> ("{{ ticket.title }}") has been closed.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_staff_url }}">{{ ticket.get_staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
Ticket {{ ticket.title }} ("{{ ticket.title }}") has been closed.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,10 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Escalated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is a courtesy e-mail to let you know that ticket <a href='{{ ticket.staff_url }}'><b>{{ ticket.ticket }}</b></a> (<em>{{ ticket.title }}</em>) has been escalated automatically.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
This is a courtesy e-mail to let you know that ticket {{ ticket.ticket }} ("{{ ticket.title }}") has been escalated automatically.
|
|
||||||
|
|
||||||
You can view this online at {{ ticket.staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,10 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Re-Assigned{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is a courtesy e-mail to let you know that ticket <a href='{{ ticket.staff_url }}'><b>{{ ticket.ticket }}</b></a> (<em>{{ ticket.title }}</em>) has been opened.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
This is a courtesy e-mail to let you know that ticket {{ ticket.ticket }} ("{{ ticket.title }}") has been opened.
|
|
||||||
|
|
||||||
You can view this online at {{ ticket.staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Resolution{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Ticket {{ ticket.ticket }} (<i>{{ ticket.title }}</i>) has been resolved.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following resolution was added:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ resolution }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This resolution has been e-mailed to the submitter, who will verify it before you can close this ticket.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_staff_url }}">{{ ticket.get_staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
Ticket {{ ticket.ticket }} ({{ ticket.title }}) has been resolved.
|
|
||||||
|
|
||||||
The following resolution was added:
|
|
||||||
|
|
||||||
{{ resolution }}
|
|
||||||
|
|
||||||
This resolution has been e-mailed to the submitter, who will verify it before you can close this ticket.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Updated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Ticket <a href='{{ ticket.staff_url }}'>{{ ticket.ticket }}</a> (<em>{{ ticket.title }}</em>) has been updated.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following comment was added:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ comment }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This information has {% if private %}not {% endif %} been e-mailed to the submitter.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.staff_url }}">{{ ticket.staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
Ticket {{ ticket.ticket }} ({{ ticket.title }}) has been updated.
|
|
||||||
|
|
||||||
The following comment was added:
|
|
||||||
|
|
||||||
{{ comment }}
|
|
||||||
|
|
||||||
This information has {% if private %}not {% endif %} been e-mailed to the submitter.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,15 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Assigned To You{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is a courtesy e-mail to let you know that a ticket has been assigned to you.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>{% if ticket.submitter_email %}The ticket was submitted by {{ ticket.submitter_email }}, and the subject{% else %}The ticket subject{% endif%} is <i>{{ ticket.title }}</i>.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The ticket ID is <a href='{{ ticket.staff_url }}'><b>{{ ticket.ticket }}</a></b>. It's priority is {{ ticket.get_priority_display }}.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
This is a courtesy e-mail to let you know that a ticket has been assigned to you.
|
|
||||||
|
|
||||||
{% if ticket.submitter_email %}The ticket was submitted by {{ ticket.submitter_email }}, and the subject{% else %}The ticket subject{% endif%} is {{ ticket.title }}.
|
|
||||||
|
|
||||||
The ticket ID is {{ ticket.ticket }}, you can view it online at {{ ticket.staff_url }}. It's priority is {{ ticket.get_priority_display }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,12 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Closed{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>A ticket currently assigned to you with a subject of <i>{{ ticket.title }}</i> has been closed.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_staff_url }}">{{ ticket.get_staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,7 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
A ticket currently assigned to you with a subject of "{{ ticket.title }}" has been closed.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,14 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Escalated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>A ticket currently assigned to you with a subject of <i>{{ ticket.title }}</i> has been automatically escalated.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Please review this ticket and attempt to provide a resolution as soon as possible.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_staff_url }}">{{ ticket.get_staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
A ticket currently assigned to you with a subject of "{{ ticket.title }}" has been automatically escalated.
|
|
||||||
|
|
||||||
Please review this ticket and attempt to provide a resolution as soon as possible.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Resolution{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>A ticket currently assigned to you with a subject of <i>{{ ticket.title }}</i> has had a resolution added.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following resolution was added to ticket <b>{{ ticket.ticket }}</b>:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ resolution }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This resolution has been e-mailed to the submitter, who will verify it before you can close this ticket.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_staff_url }}">{{ ticket.get_staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
A ticket currently assigned to you with a subject of {{ ticket.title }} has had a resolution added.
|
|
||||||
|
|
||||||
The following resolution was added to ticket {{ ticket.ticket }}:
|
|
||||||
|
|
||||||
{{ resolution }}
|
|
||||||
|
|
||||||
This resolution has been e-mailed to the submitter, who will verify it before you can close this ticket.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Ticket Updated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Ticket <a href='{{ ticket.staff_url }}'>{{ ticket.ticket }}</a> (<em>{{ ticket.title }}</em>), which is assigned to you, has been updated.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following comment was added to ticket <b>{{ ticket.ticket }}</b>:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ comment }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This information has {% if private %}not {% endif %} been e-mailed to the submitter.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.staff_url }}">{{ ticket.staff_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
Ticket {{ ticket.ticket }} ({{ ticket.title }}), which is assigned to you, has been updated.
|
|
||||||
|
|
||||||
The following comment was added to ticket {{ ticket.ticket }}:
|
|
||||||
|
|
||||||
{{ comment }}
|
|
||||||
|
|
||||||
This information has {% if private %}not {% endif %} been e-mailed to the submitter.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.staff_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,9 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}E-Mail Heading Here{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Dear User,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is some content.</p>
|
|
||||||
{% endblock %}
|
|
@ -1,14 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Your Ticket Has Been Closed{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>You recently logged a ticket with a subject of <i>{{ ticket.title }}</i> with us. This e-mail is to confirm that this ticket has been closed.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you believe that further work is required on this ticket, please let us know by replying to this e-mail and keeping the subject intact.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_ticket_url }}">{{ ticket.get_ticket_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
You recently logged a ticket with a subject of "{{ ticket.title }}" with us. This e-mail is to confirm that this ticket has been closed.
|
|
||||||
|
|
||||||
If you believe that further work is required on this ticket, please let us know by replying to this e-mail and keeping the subject intact.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_ticket_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,14 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Your Ticket Has Been Escalated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>You recently logged a ticket with a subject of <i>{{ ticket.title }}</i> with us. This e-mail is to advise you of an automated escalation of that ticket.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>We will review your ticket shortly and attempt to provide a resolution as soon as possible.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_ticket_url }}">{{ ticket.get_ticket_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,9 +0,0 @@
|
|||||||
Hello,</p>
|
|
||||||
|
|
||||||
You recently logged a ticket with a subject of "{{ ticket.title }}" with us. This e-mail is to advise you of an automated escalation of that ticket.
|
|
||||||
|
|
||||||
We will review your ticket shortly and attempt to provide a resolution as soon as possible.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_ticket_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,19 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Thank You For Your Submission{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>This is a courtesy e-mail to let you know that we have received your helpdesk query with a subject of <i>{{ ticket.title }}</i>. </p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>You do not have to do anything further at this stage. Your ticket has been assigned a number of <b>{{ ticket.ticket }}</b>.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to send us further details, or if you have any queries about this ticket, please include the ticket id of <b>{{ ticket.ticket }}</b> in the subject. The easiest way to do this is just press 'reply' to this message.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_ticket_url }}">{{ ticket.get_ticket_url }}</a>.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>We will investigate your query and attempt to resolve it as soon as possible. You will receive further updates and a resolution via this e-mail address.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
This is a courtesy e-mail to let you know that we have received your helpdesk query with a subject of {{ ticket.title }}.
|
|
||||||
|
|
||||||
You do not have to do anything further at this stage. Your ticket has been assigned a number of {{ ticket.ticket }}.
|
|
||||||
|
|
||||||
If you wish to send us further details, or if you have any queries about this ticket, please include the ticket id of {{ ticket.ticket }} in the subject. The easiest way to do this is just press 'reply' to this message.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_ticket_url }}.
|
|
||||||
|
|
||||||
We will investigate your query and attempt to resolve it as soon as possible. You will receive further updates and a resolution via this e-mail address.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Your Ticket Has Been Resolved{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>You recently logged a ticket with a subject of <i>{{ ticket.title }}</i> with us. This e-mail is to advise you of a resolution to that ticket.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following resolution was added to ticket <b>{{ ticket.ticket }}</b>:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ resolution }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Can you please confirm that this resolution addresses your needs so we may close this ticket? If you have any further queries, or if you do not believe this resolution is adequate, please reply to this e-mail and keep the subject intact.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_ticket_url }}">{{ ticket.get_ticket_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
You recently logged a ticket with a subject of '{{ ticket.title }}' with us. This e-mail is to advise you of a resolution to that ticket.
|
|
||||||
|
|
||||||
The following resolution was added to ticket {{ ticket.ticket }}:
|
|
||||||
|
|
||||||
{{ resolution }}
|
|
||||||
|
|
||||||
Can you please confirm that this resolution addresses your needs so we may close this ticket? If you have any further queries, or if you do not believe this resolution is adequate, please reply to this e-mail and keep the subject intact.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_ticket_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
@ -1,18 +0,0 @@
|
|||||||
{% extends "helpdesk/emails/base.html" %}
|
|
||||||
|
|
||||||
{% block header %}Your Ticket Has Been Updated{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>Hello,</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>You recently logged a ticket with a subject of <i>{{ ticket.title }}</i> with us. This e-mail is to advise you of an update to that ticket.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>The following comment was added to ticket <b>{{ ticket.ticket }}</b>:</p>
|
|
||||||
|
|
||||||
<blockquote style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt; padding-left: 20px; border-left: solid #ccc 2px;'>{{ comment }}</blockquote>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>To provide us with further information, please reply to this e-mail.</p>
|
|
||||||
|
|
||||||
<p style='font-family: "Trebuchet MS", Arial, sans-serif; font-size: 11pt;'>If you wish to view this ticket online, you can visit <a href="{{ ticket.get_ticket_url }}">{{ ticket.get_ticket_url }}</a>.</p>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,13 +0,0 @@
|
|||||||
Hello,
|
|
||||||
|
|
||||||
You recently logged a ticket with a subject of '{{ ticket.title }}' with us. This e-mail is to advise you of an update to that ticket.
|
|
||||||
|
|
||||||
The following comment was added to ticket {{ ticket.ticket }}:
|
|
||||||
|
|
||||||
{{ comment }}
|
|
||||||
|
|
||||||
To provide us with further information, please reply to this e-mail.
|
|
||||||
|
|
||||||
If you wish to view this ticket online, you can visit {{ ticket.get_ticket_url }}.
|
|
||||||
|
|
||||||
{% include "helpdesk/emails/text_footer.txt" %}
|
|
27
templates/helpdesk/report_index.html
Normal file
27
templates/helpdesk/report_index.html
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}Reports & Statistics{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}
|
||||||
|
<h2>Reports & Statistics</h2>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>User<ul>
|
||||||
|
|
||||||
|
<li><a href='userpriority/'>by Priority</a></li>
|
||||||
|
<li><a href='userqueue/'>by Queue</a></li>
|
||||||
|
<li><a href='userstatus/'>by Status</a></li>
|
||||||
|
<li><a href='usermonth/'>by Month</a></li>
|
||||||
|
|
||||||
|
</ul></li>
|
||||||
|
|
||||||
|
<li>Queue<ul>
|
||||||
|
|
||||||
|
<li><a href='queuepriority/'>by Priority</a></li>
|
||||||
|
<li><a href='queuestatus/'>by Status</a></li>
|
||||||
|
<li><a href='queuemonth/'>by Month</a></li>
|
||||||
|
|
||||||
|
</ul></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
15
templates/helpdesk/report_output.html
Normal file
15
templates/helpdesk/report_output.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{% extends "helpdesk/base.html" %}
|
||||||
|
|
||||||
|
{% block helpdesk_title %}Reports & Statistics{% endblock %}
|
||||||
|
|
||||||
|
{% block helpdesk_body %}
|
||||||
|
<h2>Reports & Statistics</h2>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>{% for h in headings %}<th>{{ h }}</th>{% endfor %}</tr>
|
||||||
|
{% for d in data %}<tr>{% for f in d %}<td>{{ f }}</td>{% endfor %}</tr>{% endfor %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% if chart %}<img src='{{ chart }}' />{% endif %}
|
||||||
|
|
||||||
|
{% endblock %}
|
9
urls.py
9
urls.py
@ -59,6 +59,14 @@ urlpatterns = patterns('helpdesk.views',
|
|||||||
url(r'^rss/$',
|
url(r'^rss/$',
|
||||||
'rss_list',
|
'rss_list',
|
||||||
name='helpdesk_rss_index'),
|
name='helpdesk_rss_index'),
|
||||||
|
|
||||||
|
url(r'^reports/$',
|
||||||
|
'report_index',
|
||||||
|
name='helpdesk_report_index'),
|
||||||
|
|
||||||
|
url(r'^reports/(?P<report>\w+)/$',
|
||||||
|
'run_report',
|
||||||
|
name='helpdesk_run_report'),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += patterns('',
|
urlpatterns += patterns('',
|
||||||
@ -67,6 +75,7 @@ urlpatterns += patterns('',
|
|||||||
{'feed_dict': feed_setup},
|
{'feed_dict': feed_setup},
|
||||||
name='helpdesk_rss'),
|
name='helpdesk_rss'),
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns += patterns('',
|
urlpatterns += patterns('',
|
||||||
url(r'^api/(?P<method>[a-z_-]+)/$',
|
url(r'^api/(?P<method>[a-z_-]+)/$',
|
||||||
'helpdesk.api.api',
|
'helpdesk.api.api',
|
||||||
|
213
views.py
213
views.py
@ -17,7 +17,7 @@ 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 helpdesk.forms import TicketForm, PublicTicketForm
|
from helpdesk.forms import TicketForm, PublicTicketForm
|
||||||
from helpdesk.lib import send_multipart_mail
|
from helpdesk.lib import send_templated_mail, line_chart, bar_chart
|
||||||
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment
|
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment
|
||||||
|
|
||||||
def dashboard(request):
|
def dashboard(request):
|
||||||
@ -30,13 +30,20 @@ def dashboard(request):
|
|||||||
tickets = Ticket.objects.filter(assigned_to=request.user).exclude(status=Ticket.CLOSED_STATUS)
|
tickets = Ticket.objects.filter(assigned_to=request.user).exclude(status=Ticket.CLOSED_STATUS)
|
||||||
unassigned_tickets = Ticket.objects.filter(assigned_to__isnull=True).exclude(status=Ticket.CLOSED_STATUS)
|
unassigned_tickets = Ticket.objects.filter(assigned_to__isnull=True).exclude(status=Ticket.CLOSED_STATUS)
|
||||||
|
|
||||||
dash_tickets = []
|
from django.db import connection
|
||||||
for q in Queue.objects.all():
|
cursor = connection.cursor()
|
||||||
dash_tickets.append({
|
cursor.execute("""
|
||||||
'queue': q,
|
SELECT q.id as queue,
|
||||||
'open': q.ticket_set.filter(Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)).count(),
|
q.title AS name,
|
||||||
'resolved': q.ticket_set.filter(status=Ticket.RESOLVED_STATUS).count(),
|
COUNT(CASE t.status WHEN '1' THEN t.id WHEN '2' THEN t.id END) AS open,
|
||||||
})
|
COUNT(CASE t.status WHEN '3' THEN t.id END) AS resolved
|
||||||
|
FROM helpdesk_ticket t,
|
||||||
|
helpdesk_queue q
|
||||||
|
WHERE q.id = t.queue_id
|
||||||
|
GROUP BY queue, name
|
||||||
|
ORDER BY q.id;
|
||||||
|
""")
|
||||||
|
dash_tickets = cursor.dictfetchall()
|
||||||
|
|
||||||
return render_to_response('helpdesk/dashboard.html',
|
return render_to_response('helpdesk/dashboard.html',
|
||||||
RequestContext(request, {
|
RequestContext(request, {
|
||||||
@ -164,50 +171,38 @@ def update_ticket(request, ticket_id):
|
|||||||
'comment': f.comment,
|
'comment': f.comment,
|
||||||
}
|
}
|
||||||
if f.new_status == Ticket.RESOLVED_STATUS:
|
if f.new_status == Ticket.RESOLVED_STATUS:
|
||||||
template = 'helpdesk/emails/submitter_resolved'
|
template = 'resolved_submitter'
|
||||||
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
|
||||||
elif f.new_status == Ticket.CLOSED_STATUS:
|
elif f.new_status == Ticket.CLOSED_STATUS:
|
||||||
template = 'helpdesk/emails/submitter_closed'
|
template = 'closed_submitter'
|
||||||
subject = '%s %s (Closed)' % (ticket.ticket, ticket.title)
|
|
||||||
else:
|
else:
|
||||||
template = 'helpdesk/emails/submitter_updated'
|
template = 'updated_submitter'
|
||||||
subject = '%s %s (Updated)' % (ticket.ticket, ticket.title)
|
send_templated_mail(template, context, recipients=ticket.submitter_email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
send_multipart_mail(template, context, subject, ticket.submitter_email, ticket.queue.from_address, fail_silently=True)
|
|
||||||
|
|
||||||
if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email:
|
if ticket.assigned_to and request.user != ticket.assigned_to and ticket.assigned_to.email:
|
||||||
# We only send e-mails to staff members if the ticket is updated by
|
# We only send e-mails to staff members if the ticket is updated by
|
||||||
# another user.
|
# another user.
|
||||||
if reassigned:
|
if reassigned:
|
||||||
template_staff = 'helpdesk/emails/owner_assigned'
|
template_staff = 'assigned_owner'
|
||||||
subject = '%s %s (Assigned)' % (ticket.ticket, ticket.title)
|
|
||||||
elif f.new_status == Ticket.RESOLVED_STATUS:
|
elif f.new_status == Ticket.RESOLVED_STATUS:
|
||||||
template_staff = 'helpdesk/emails/owner_resolved'
|
template_staff = 'resolved_owner'
|
||||||
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
|
||||||
elif f.new_status == Ticket.CLOSED_STATUS:
|
elif f.new_status == Ticket.CLOSED_STATUS:
|
||||||
template_staff = 'helpdesk/emails/owner_closed'
|
template_staff = 'closed_owner'
|
||||||
subject = '%s %s (Closed)' % (ticket.ticket, ticket.title)
|
|
||||||
else:
|
else:
|
||||||
template_staff = 'helpdesk/emails/owner_updated'
|
template_staff = 'updated_owner'
|
||||||
subject = '%s %s (Updated)' % (ticket.ticket, ticket.title)
|
|
||||||
|
|
||||||
send_multipart_mail(template_staff, context, subject, ticket.assigned_to.email, ticket.queue.from_address, fail_silently=True)
|
|
||||||
|
|
||||||
|
send_templated_mail(template_staff, context, recipients=ticket.assigned_to.email, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if ticket.queue.updated_ticket_cc:
|
if ticket.queue.updated_ticket_cc:
|
||||||
if reassigned:
|
if reassigned:
|
||||||
template_cc = 'helpdesk/emails/cc_assigned'
|
template_cc = 'assigned_cc'
|
||||||
subject = '%s %s (Assigned)' % (ticket.ticket, ticket.title)
|
|
||||||
elif f.new_status == Ticket.RESOLVED_STATUS:
|
elif f.new_status == Ticket.RESOLVED_STATUS:
|
||||||
template_cc = 'helpdesk/emails/cc_resolved'
|
template_cc = 'resolved_cc'
|
||||||
subject = '%s %s (Resolved)' % (ticket.ticket, ticket.title)
|
|
||||||
elif f.new_status == Ticket.CLOSED_STATUS:
|
elif f.new_status == Ticket.CLOSED_STATUS:
|
||||||
template_cc = 'helpdesk/emails/cc_closed'
|
template_cc = 'closed_cc'
|
||||||
subject = '%s %s (Closed)' % (ticket.ticket, ticket.title)
|
|
||||||
else:
|
else:
|
||||||
template_cc = 'helpdesk/emails/cc_updated'
|
template_cc = 'updated_cc'
|
||||||
subject = '%s %s (Updated)' % (ticket.ticket, ticket.title)
|
|
||||||
|
|
||||||
send_multipart_mail(template_cc, context, subject, ticket.queue.updated_ticket_cc, ticket.queue.from_address, fail_silently=True)
|
send_templated_mail(template_cc, context, recipients=ticket.queue.updated_ticket_cc, sender=ticket.queue.from_address, fail_silently=True)
|
||||||
|
|
||||||
if request.FILES:
|
if request.FILES:
|
||||||
for file in request.FILES.getlist('attachment'):
|
for file in request.FILES.getlist('attachment'):
|
||||||
@ -363,3 +358,153 @@ def rss_list(request):
|
|||||||
'queues': Queue.objects.all(),
|
'queues': Queue.objects.all(),
|
||||||
}))
|
}))
|
||||||
rss_list = login_required(rss_list)
|
rss_list = login_required(rss_list)
|
||||||
|
|
||||||
|
def report_index(request):
|
||||||
|
return render_to_response('helpdesk/report_index.html',
|
||||||
|
RequestContext(request, {}))
|
||||||
|
report_index = login_required(report_index)
|
||||||
|
|
||||||
|
def run_report(request, report):
|
||||||
|
priority_sql = []
|
||||||
|
priority_columns = []
|
||||||
|
for p in Ticket.PRIORITY_CHOICES:
|
||||||
|
priority_sql.append("COUNT(CASE t.priority WHEN '%s' THEN t.id END) AS \"%s\"" % (p[0], p[1]))
|
||||||
|
priority_columns.append("%s" % p[1])
|
||||||
|
priority_sql = ", ".join(priority_sql)
|
||||||
|
|
||||||
|
status_sql = []
|
||||||
|
status_columns = []
|
||||||
|
for s in Ticket.STATUS_CHOICES:
|
||||||
|
status_sql.append("COUNT(CASE t.status WHEN '%s' THEN t.id END) AS \"%s\"" % (s[0], s[1]))
|
||||||
|
status_columns.append("%s" % s[1])
|
||||||
|
status_sql = ", ".join(status_sql)
|
||||||
|
|
||||||
|
queue_sql = []
|
||||||
|
queue_columns = []
|
||||||
|
for q in Queue.objects.all():
|
||||||
|
queue_sql.append("COUNT(CASE t.queue_id WHEN '%s' THEN t.id END) AS \"%s\"" % (q.id, q.title))
|
||||||
|
queue_columns.append(q.title)
|
||||||
|
queue_sql = ", ".join(queue_sql)
|
||||||
|
|
||||||
|
month_sql = []
|
||||||
|
months = (
|
||||||
|
'Jan',
|
||||||
|
'Feb',
|
||||||
|
'Mar',
|
||||||
|
'Apr',
|
||||||
|
'May',
|
||||||
|
'Jun',
|
||||||
|
'Jul',
|
||||||
|
'Aug',
|
||||||
|
'Sep',
|
||||||
|
'Oct',
|
||||||
|
'Nov',
|
||||||
|
'Dec',
|
||||||
|
)
|
||||||
|
month_columns = []
|
||||||
|
|
||||||
|
first_ticket = Ticket.objects.all().order_by('created')[0]
|
||||||
|
first_month = first_ticket.created.month
|
||||||
|
first_year = first_ticket.created.year
|
||||||
|
|
||||||
|
last_ticket = Ticket.objects.all().order_by('-created')[0]
|
||||||
|
last_month = last_ticket.created.month
|
||||||
|
last_year = last_ticket.created.year
|
||||||
|
|
||||||
|
periods = []
|
||||||
|
year, month = first_year, first_month
|
||||||
|
working = True
|
||||||
|
|
||||||
|
while working:
|
||||||
|
periods.append((year, month))
|
||||||
|
month += 1
|
||||||
|
if month > 12:
|
||||||
|
year += 1
|
||||||
|
month = 1
|
||||||
|
if month > last_month and year >= last_year:
|
||||||
|
working = False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (year, month) in periods:
|
||||||
|
sqlmonth = '%s-%s' % (year, months[month-1])
|
||||||
|
desc = '%s %s' % (months[month-1], year)
|
||||||
|
month_sql.append("COUNT(CASE to_char(t.created, 'YYYY-Mon') WHEN '%s' THEN t.id END) AS \"%s\"" % (sqlmonth, desc))
|
||||||
|
month_columns.append(desc)
|
||||||
|
month_sql = ", ".join(month_sql)
|
||||||
|
|
||||||
|
queue_base_sql = """
|
||||||
|
SELECT q.title as queue, %s
|
||||||
|
FROM helpdesk_ticket t,
|
||||||
|
helpdesk_queue q
|
||||||
|
WHERE q.id = t.queue_id
|
||||||
|
GROUP BY queue
|
||||||
|
ORDER BY queue;
|
||||||
|
"""
|
||||||
|
|
||||||
|
user_base_sql = """
|
||||||
|
SELECT u.username as username, %s
|
||||||
|
FROM helpdesk_ticket t,
|
||||||
|
auth_user u
|
||||||
|
WHERE u.id = t.assigned_to_id
|
||||||
|
GROUP BY u.username
|
||||||
|
ORDER BY u.username;
|
||||||
|
"""
|
||||||
|
|
||||||
|
if report == 'userpriority':
|
||||||
|
sql = user_base_sql % priority_sql
|
||||||
|
columns = ['username'] + priority_columns
|
||||||
|
|
||||||
|
elif report == 'userqueue':
|
||||||
|
sql = user_base_sql % queue_sql
|
||||||
|
columns = ['username'] + queue_columns
|
||||||
|
|
||||||
|
elif report == 'userstatus':
|
||||||
|
sql = user_base_sql % status_sql
|
||||||
|
columns = ['username'] + status_columns
|
||||||
|
|
||||||
|
elif report == 'usermonth':
|
||||||
|
sql = user_base_sql % month_sql
|
||||||
|
columns = ['username'] + month_columns
|
||||||
|
|
||||||
|
elif report == 'queuepriority':
|
||||||
|
sql = queue_base_sql % priority_sql
|
||||||
|
columns = ['queue'] + priority_columns
|
||||||
|
|
||||||
|
elif report == 'queuestatus':
|
||||||
|
sql = queue_base_sql % status_sql
|
||||||
|
columns = ['queue'] + status_columns
|
||||||
|
|
||||||
|
elif report == 'queuemonth':
|
||||||
|
sql = queue_base_sql % month_sql
|
||||||
|
columns = ['queue'] + month_columns
|
||||||
|
|
||||||
|
|
||||||
|
from django.db import connection
|
||||||
|
cursor = connection.cursor()
|
||||||
|
cursor.execute(sql)
|
||||||
|
report_output = cursor.dictfetchall()
|
||||||
|
|
||||||
|
data = []
|
||||||
|
|
||||||
|
for record in report_output:
|
||||||
|
line = []
|
||||||
|
for c in columns:
|
||||||
|
line.append(record[c])
|
||||||
|
data.append(line)
|
||||||
|
|
||||||
|
if report in ('queuemonth', 'usermonth'):
|
||||||
|
chart_url = line_chart([columns] + data)
|
||||||
|
elif report in ('queuestatus', 'queuepriority', 'userstatus', 'userpriority'):
|
||||||
|
chart_url = bar_chart([columns] + data)
|
||||||
|
else:
|
||||||
|
chart_url = ''
|
||||||
|
|
||||||
|
return render_to_response('helpdesk/report_output.html',
|
||||||
|
RequestContext(request, {
|
||||||
|
'headings': columns,
|
||||||
|
'data': data,
|
||||||
|
'sql': sql,
|
||||||
|
'chart': chart_url,
|
||||||
|
}))
|
||||||
|
run_report = login_required(run_report)
|
||||||
|
Loading…
Reference in New Issue
Block a user