From 1524c37941029e16c456ce517e53935dd4f5b244 Mon Sep 17 00:00:00 2001 From: Ross Poulton Date: Wed, 16 Jan 2008 04:38:24 +0000 Subject: [PATCH] * Add queue-based automatic ticket escalation --- README | 14 ++++++-- models.py | 2 ++ scripts/escalate_tickets.py | 69 +++++++++++++++++++++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 scripts/escalate_tickets.py diff --git a/README b/README index 4a0bd5a4..afeac51f 100644 --- a/README +++ b/README @@ -99,11 +99,21 @@ See the file 'LICENSE' for licensing terms and conditions. inbox, set up a cronjob to run scripts/get_email.py on a regular basis. Don't forget to set the relevant Django environment variables in your - crnotab: + crontab: - 5 * * * * DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/get_email.py + */5 * * * * DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/get_email.py + + This will run the e-mail import every 5 minutes IMPORTANT NOTE: Any tickets created via POP3 or IMAP mailboxes will DELETE the original e-mail from the mail server. +4. If you wish to automatically escalate tickets based on their age, set up + a cronjob to run scripts/escalate_tickets.py on a regular basis: + + 0 * * * * DJANGO_SETTINGS_MODULE='myproject.settings' python /path/to/helpdesk/scripts/escalate_tickets.py + + This will run the escalation process hourly, using the 'Escalation Hours' + setting for each queue to determine which tickets to escalate. + You're now up and running! diff --git a/models.py b/models.py index 73045831..3d675d30 100644 --- a/models.py +++ b/models.py @@ -46,6 +46,8 @@ class Queue(models.Model): title = models.CharField(maxlength=100) slug = models.SlugField(help_text='This slug is used when building ticket ID\'s. Once set, try not to change it or e-mailing may get messy.') email_address = models.EmailField(blank=True, null=True, help_text='All outgoing e-mails for this queue will use this e-mail address. If you use IMAP or POP3, this shoul be the e-mail address for that mailbox.') + escalate_hours = models.IntegerField(blank=True, null=True, help_text='For tickets which are not held, how often do you wish to increase their priority? Set to 0 for no escalation.') + last_escalation = models.DateTimeField(blank=True, null=True, editable=False) def _from_address(self): if not self.email_address: diff --git a/scripts/escalate_tickets.py b/scripts/escalate_tickets.py new file mode 100644 index 00000000..899bd105 --- /dev/null +++ b/scripts/escalate_tickets.py @@ -0,0 +1,69 @@ +""" .. + .,::;:::::: + ..,::::::::,,,,::: Jutda Helpdesk - A Django + .,,::::::,,,,,,,,,,,,,:: powered ticket tracker for + .,::::::,,,,,,,,,,,,,,,,,,:;r. small enterprise + .::::,,,,,,,,,,,,,,,,,,,,,,:;;rr. + .:::,,,,,,,,,,,,,,,,,,,,,,,:;;;;;rr (c) Copyright 2008 + .:::,,,,,,,,,,,,,,,,,,,,,,,:;;;:::;;rr + .:::,,,,,,,,,,,,,,,,,,,,. ,;;;::::::;;rr Jutda + .:::,,,,,,,,,,,,,,,,,,. .:;;:::::::::;;rr + .:::,,,,,,,,,,,,,,,. .;r;::::::::::::;r; All Rights Reserved + .:::,,,,,,,,,,,,,,, .;r;;:::::::::::;;:. + .:::,,,,,,,,,,,,,,,. .;r;;::::::::::::;:. + .;:,,,,,,,,,,,,,,, .,;rr;::::::::::::;:. This software is released +.,:,,,,,,,,,,,,,. .,:;rrr;;::::::::::::;;. under a limited-use license that + :,,,,,,,,,,,,,..:;rrrrr;;;::::::::::::;;. allows you to freely download this + :,,,,,,,:::;;;rr;;;;;;:::::::::::::;;, software from it's manufacturer and + ::::;;;;;;;;;;;:::::::::::::::::;;, use it yourself, however you may not + .r;;;;:::::::::::::::::::::::;;;, distribute it. For further details, see + .r;::::::::::::::::::::;;;;;:, the enclosed LICENSE file. + .;;::::::::::::::;;;;;:,. + .;;:::::::;;;;;;:,. Please direct people who wish to download this + .r;;;;;;;;:,. software themselves to www.jutda.com.au. + ,,,.. + +$Id$ + +""" +from datetime import datetime, timedelta +from django.db.models import Q +from helpdesk.models import Queue, Ticket, FollowUp +from helpdesk.lib import send_multipart_mail + +def escalate_tickets(): + for q in Queue.objects.filter(escalate_hours__isnull=False).exclude(escalate_hours=0): + + if not q.last_escalation: q.last_escalation = datetime.now()-timedelta(hours=q.escalate_hours) + + if (q.last_escalation + timedelta(hours=q.escalate_hours) - timedelta(minutes=2)) > datetime.now(): + continue + + print "Processing: %s" % q + + q.last_escalation = datetime.now() + q.save() + + for t in q.ticket_set.filter(Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS)).exclude(priority=1): + t.priority -= 1 + t.save() + + f = FollowUp( + ticket = t, + title = 'Ticket Escalated', + date=q.last_escalation, + public=True, + comment='Ticket escalated after %s hours' % q.escalate_hours, + ) + f.save() + + tc = TicketChange( + followup = f, + field = 'priority', + old_value = t.priority + 1, + new_value = t.priority, + ) + tc.save() + +if __name__ == '__main__': + escalate_tickets()