diff --git a/helpdesk/lib.py b/helpdesk/lib.py
index 9080b210..b1e96620 100644
--- a/helpdesk/lib.py
+++ b/helpdesk/lib.py
@@ -119,104 +119,6 @@ def send_templated_mail(template_name, email_context, recipients, sender=None, b
return msg.send(fail_silently)
-def normalise_data(data, to=100):
- """
- Used for normalising data prior to graphing with Google charting API. EG:
-
- [1, 4, 10] becomes [10, 40, 100]
- [36, 54, 240] becomes [15, 23, 100]
- """
- max_value = max(data)
- if max_value > to:
- new_data = []
- for d in data:
- new_data.append(int(d/float(max_value)*to))
- data = new_data
- return data
-
-
-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 + 100 for headings.'.
- chart_url = 'http://chart.apis.google.com/chart?cht=lc&chs=%sx150&chd=t:' % (min(len(column_headings)*65+100, 1000))
- 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 '220px * number of months'.
- chart_url = 'http://chart.apis.google.com/chart?cht=bvg&chs=%sx150&chd=t:' % (min(len(column_headings) * 220, 1000))
- 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
-
-
def query_to_dict(results, descriptions):
"""
Replacement method for cursor.dictfetchall() as that method no longer
diff --git a/helpdesk/templates/helpdesk/report_index.html b/helpdesk/templates/helpdesk/report_index.html
index ac9df4b6..6159be06 100644
--- a/helpdesk/templates/helpdesk/report_index.html
+++ b/helpdesk/templates/helpdesk/report_index.html
@@ -3,33 +3,29 @@
{% block helpdesk_title %}{% trans "Reports & Statistics" %}{% endblock %}
{% block helpdesk_body %}
-{% ifequal number_tickets 0 %}{% blocktrans %}
-
Reports & Statistics
+{% trans "Reports & Statistics" %}
-You haven't created any tickets yet, so you cannot run any reports.
-{% endblocktrans %}
+{% ifequal number_tickets 0 %}
+{% trans "You haven't created any tickets yet, so you cannot run any reports." %}
{% else %}
-{% blocktrans %}
-Reports & Statistics
-
-- User
+ - {% trans "Reports By User" %}
-- Queue
+- {% trans "Reports By Queue" %}
-{% endblocktrans %}{% endifequal %}{% endblock %}
+{% endifequal %}{% endblock %}
diff --git a/helpdesk/views/staff.py b/helpdesk/views/staff.py
index 2fc1a53b..b3323a99 100644
--- a/helpdesk/views/staff.py
+++ b/helpdesk/views/staff.py
@@ -24,7 +24,7 @@ from django.utils.translation import ugettext as _
from django.utils.html import escape
from helpdesk.forms import TicketForm, UserSettingsForm, EmailIgnoreForm, EditTicketForm, TicketCCForm, EditFollowUpForm, TicketDependencyForm
-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, query_to_dict, apply_query, safe_template_context
from helpdesk.models import Ticket, Queue, FollowUp, TicketChange, PreSetReply, Attachment, SavedSearch, IgnoreEmail, TicketCC, TicketDependency
from helpdesk.settings import HAS_TAG_SUPPORT
@@ -745,54 +745,56 @@ rss_list = staff_member_required(rss_list)
def report_index(request):
number_tickets = Ticket.objects.all().count()
+ saved_query = request.GET.get('saved_query', None):
return render_to_response('helpdesk/report_index.html',
RequestContext(request, {
'number_tickets': number_tickets,
+ 'saved_query': saved_query,
}))
report_index = staff_member_required(report_index)
def run_report(request, report):
- if Ticket.objects.all().count() == 0:
+ if Ticket.objects.all().count() == 0 or report not in ('queuemonth', 'usermonth', 'queuestatus', 'queuepriority', 'userstatus', 'userpriority', 'userqueue'):
return HttpResponseRedirect(reverse("helpdesk_report_index"))
- 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]._proxy____unicode_cast()))
- priority_columns.append("%s" % p[1]._proxy____unicode_cast())
- 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]._proxy____unicode_cast()))
- status_columns.append("%s" % s[1]._proxy____unicode_cast())
- status_sql = ", ".join(status_sql)
+ report_queryset = Ticket.objects.all().select_related()
+
+ from_saved_query = False
+ saved_query = None
- 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)
+ if request.GET.get('saved_query', None):
+ from_saved_query = True
+ try:
+ saved_query = SavedSearch.objects.get(pk=request.GET.get('saved_query'))
+ except SavedSearch.DoesNotExist:
+ return HttpResponseRedirect(reverse('helpdesk_report_index'))
+ if not (saved_query.shared or saved_query.user == request.user):
+ return HttpResponseRedirect(reverse('helpdesk_report_index'))
+
+ import cPickle
+ from helpdesk.lib import b64decode
+ query_params = cPickle.loads(b64decode(str(saved_query.query)))
+ report_queryset = apply_query(report_queryset, query_params)
+
+ from collections import defaultdict
+ summarytable = defaultdict(int)
- month_sql = []
months = (
- 'Jan',
- 'Feb',
- 'Mar',
- 'Apr',
- 'May',
- 'Jun',
- 'Jul',
- 'Aug',
- 'Sep',
- 'Oct',
- 'Nov',
- 'Dec',
+ _('Jan'),
+ _('Feb'),
+ _('Mar'),
+ _('Apr'),
+ _('May'),
+ _('Jun'),
+ _('Jul'),
+ _('Aug'),
+ _('Sep'),
+ _('Oct'),
+ _('Nov'),
+ _('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
@@ -804,115 +806,114 @@ def run_report(request, report):
periods = []
year, month = first_year, first_month
working = True
+ periods.append("%s %s" % (months[month], year))
while working:
- temp = (year, month)
month += 1
if month > 12:
year += 1
month = 1
if (year > last_year) or (month > last_month and year >= last_year):
working = False
- periods.append((temp, (year, month)))
-
- for (low_bound, upper_bound) in periods:
- low_sqlmonth = '%s-%02i-01' % (low_bound[0], low_bound[1])
- upper_sqlmonth = '%s-%02i-01' % (upper_bound[0], upper_bound[1])
- desc = '%s %s' % (months[low_bound[1]-1], low_bound[0])
- month_sql.append("""
- COUNT(
- CASE 1 = 1
- WHEN (date(t.created) >= date('%s')
- AND date(t.created) < date('%s')) THEN t.id END) AS "%s"
- """ % (low_sqlmonth, upper_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;
- """
+ periods.append("%s %s" % (months[month], year))
if report == 'userpriority':
- sql = user_base_sql % priority_sql
- columns = ['username'] + priority_columns
- title = 'User by Priority'
+ title = _('User by Priority')
+ col1heading = _('User')
+ possible_options = [t[1].__unicode__() for t in Ticket.PRIORITY_CHOICES]
+ charttype = 'bar'
elif report == 'userqueue':
- sql = user_base_sql % queue_sql
- columns = ['username'] + queue_columns
- title = 'User by Queue'
+ title = _('User by Queue')
+ col1heading = _('User')
+ possible_options = [q.title.encode('utf-8') for q in Queue.objects.all()]
+ charttype = 'bar'
elif report == 'userstatus':
- sql = user_base_sql % status_sql
- columns = ['username'] + status_columns
- title = 'User by Status'
+ title = _('User by Status')
+ col1heading = _('User')
+ possible_options = [s[1].__unicode__() for s in Ticket.STATUS_CHOICES]
+ charttype = 'bar'
elif report == 'usermonth':
- sql = user_base_sql % month_sql
- columns = ['username'] + month_columns
- title = 'User by Month'
+ title = _('User by Month')
+ col1heading = _('User')
+ possible_options = periods
+ charttype = 'date'
elif report == 'queuepriority':
- sql = queue_base_sql % priority_sql
- columns = ['queue'] + priority_columns
- title = 'Queue by Priority'
+ title = _('Queue by Priority')
+ col1heading = _('Queue')
+ possible_options = [t[1].__unicode__() for t in Ticket.PRIORITY_CHOICES]
+ charttype = 'bar'
elif report == 'queuestatus':
- sql = queue_base_sql % status_sql
- columns = ['queue'] + status_columns
- title = 'Queue by Status'
+ title = _('Queue by Status')
+ col1heading = _('Queue')
+ possible_options = [s[1].__unicode__() for s in Ticket.STATUS_CHOICES]
+ charttype = 'bar'
elif report == 'queuemonth':
- sql = queue_base_sql % month_sql
- columns = ['queue'] + month_columns
- title = 'Queue by Month'
-
-
- cursor = connection.cursor()
- cursor.execute(sql)
- report_output = query_to_dict(cursor.fetchall(), cursor.description)
-
- data = []
-
- for record in report_output:
- line = []
- for c in columns:
- c = c.encode('utf-8')
- line.append(record[c])
- data.append(line)
-
- if report in ('queuemonth', 'usermonth'):
- chart_url = line_chart([columns] + data)
+ title = _('Queue by Month')
+ col1heading = _('Queue')
+ possible_options = periods
charttype = 'date'
- elif report in ('queuestatus', 'queuepriority', 'userstatus', 'userpriority'):
- chart_url = bar_chart([columns] + data)
- charttype = 'bar'
- else:
- chart_url = ''
- charttype = ''
+
+
+
+ for ticket in report_queryset:
+ if report == 'userpriority':
+ metric1 = u'%s' % ticket.get_assigned_to
+ metric2 = u'%s' % ticket.get_priority_display()
+
+ elif report == 'userqueue':
+ metric1 = u'%s' % ticket.get_assigned_to
+ metric2 = u'%s' % ticket.queue.title
+
+ elif report == 'userstatus':
+ metric1 = u'%s' % ticket.get_assigned_to
+ metric2 = u'%s' % ticket.get_status_display()
+
+ elif report == 'usermonth':
+ metric1 = u'%s' % ticket.get_assigned_to
+ metric2 = u'%s %s' % (months[ticket.created.month], ticket.created.year)
+
+ elif report == 'queuepriority':
+ metric1 = u'%s' % ticket.queue.title
+ metric2 = u'%s' % ticket.get_priority_display()
+
+ elif report == 'queuestatus':
+ metric1 = u'%s' % ticket.queue.title
+ metric2 = u'%s' % ticket.get_status_display()
+
+ elif report == 'queuemonth':
+ metric1 = u'%s' % ticket.queue.title
+ metric2 = u'%s %s' % (months[ticket.created.month], ticket.created.year)
+
+ summarytable[metric1, metric2] += 1
+
+ table = []
+
+ header1 = sorted(set(list( i.encode('utf-8') for i,_ in summarytable.keys() )))
+
+ column_headings = [col1heading] + possible_options
+
+ # Pivot the data so that 'header1' fields are always first column
+ # in the row, and 'possible_options' are always the 2nd - nth columns.
+ for item in header1:
+ data = []
+ for hdr in possible_options:
+ data.append(summarytable[item, hdr])
+ table.append([item] + data)
return render_to_response('helpdesk/report_output.html',
RequestContext(request, {
- 'headings': columns,
- 'data': data,
- 'chart': chart_url,
'title': title,
'charttype': charttype,
+ 'data': table,
+ 'headings': column_headings,
+ 'from_saved_query': from_saved_query,
+ 'saved_query': saved_query,
}))
run_report = staff_member_required(run_report)