#!/usr/bin/python """ Jutda Helpdesk - A Django powered ticket tracker for small enterprise. (c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details. scripts/escalate_tickets.py - Easy way to escalate tickets based on their age, designed to be run from Cron or similar. """ from datetime import datetime, timedelta, date import getopt from optparse import make_option import sys from django.core.management.base import BaseCommand from django.db.models import Q from django.utils.translation import ugettext as _ from helpdesk.models import Queue, Ticket, FollowUp, EscalationExclusion, TicketChange from helpdesk.lib import send_templated_mail class Command(BaseCommand): def __init__(self): BaseCommand.__init__(self) self.option_list += ( make_option( '--queues', help='Queues to include (default: all). Use queue slugs'), make_option( '--verboseescalation', action='store_true', default=False, help='Display a list of dates excluded'), ) def handle(self, *args, **options): verbose = False queue_slugs = None queues = [] if options['verboseescalation']: verbose = True if options['queues']: queue_slugs = options['queues'] if queue_slugs is not None: queue_set = queue_slugs.split(',') for queue in queue_set: try: q = Queue.objects.get(slug__exact=queue) except Queue.DoesNotExist: raise CommandError("Queue %s does not exist." % queue) queues.append(queue) escalate_tickets(queues=queues, verbose=verbose) def escalate_tickets(queues, verbose): """ Only include queues with escalation configured """ queryset = Queue.objects.filter(escalate_days__isnull=False).exclude(escalate_days=0) if queues: queryset = queryset.filter(slug__in=queues) for q in queryset: last = date.today() - timedelta(days=q.escalate_days) today = date.today() workdate = last days = 0 while workdate < today: if EscalationExclusion.objects.filter(date=workdate).count() == 0: days += 1 workdate = workdate + timedelta(days=1) req_last_escl_date = date.today() - timedelta(days=days) if verbose: print "Processing: %s" % q for t in q.ticket_set.filter( Q(status=Ticket.OPEN_STATUS) | Q(status=Ticket.REOPENED_STATUS) ).exclude( priority=1 ).filter( Q(on_hold__isnull=True) | Q(on_hold=False) ).filter( Q(last_escalation__lte=req_last_escl_date) | Q(last_escalation__isnull=True, created__lte=req_last_escl_date) ): t.last_escalation = datetime.now() t.priority -= 1 t.save() context = { 'ticket': t, 'queue': q, } if t.submitter_email: send_templated_mail( 'escalated_submitter', context, recipients=t.submitter_email, sender=t.queue.from_address, fail_silently=True, ) if t.queue.updated_ticket_cc: send_templated_mail( 'escalated_cc', context, recipients=t.queue.updated_ticket_cc, sender=t.queue.from_address, fail_silently=True, ) if t.assigned_to: send_templated_mail( 'escalated_owner', context, recipients=t.assigned_to.email, sender=t.queue.from_address, fail_silently=True, ) if verbose: print " - Esclating %s from %s>%s" % ( t.ticket, t.priority+1, t.priority ) f = FollowUp( ticket = t, title = 'Ticket Escalated', date=datetime.now(), public=True, comment=_('Ticket escalated after %s days' % q.escalate_days), ) f.save() tc = TicketChange( followup = f, field = _('Priority'), old_value = t.priority + 1, new_value = t.priority, ) tc.save() def usage(): print "Options:" print " --queues: Queues to include (default: all). Use queue slugs" print " --verboseescalation: Display a list of dates excluded" if __name__ == '__main__': try: opts, args = getopt.getopt(sys.argv[1:], ['queues=', 'verboseescalation']) except getopt.GetoptError: usage() sys.exit(2) verbose = False queue_slugs = None queues = [] for o, a in opts: if o == '--verboseescalation': verbose = True if o == '--queues': queue_slugs = a if queue_slugs is not None: queue_set = queue_slugs.split(',') for queue in queue_set: try: q = Queue.objects.get(slug__exact=queue) except Queue.DoesNotExist: print "Queue %s does not exist." % queue sys.exit(2) queues.append(queue) escalate_tickets(queues=queues, verbose=verbose)