2008-02-06 05:36:07 +01:00
|
|
|
#!/usr/bin/python
|
|
|
|
"""
|
2011-04-20 01:02:33 +02:00
|
|
|
django-helpdesk - A Django powered ticket tracker for small enterprise.
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-02-06 05:36:07 +01:00
|
|
|
(c) Copyright 2008 Jutda. All Rights Reserved. See LICENSE for details.
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
scripts/escalate_tickets.py - Easy way to escalate tickets based on their age,
|
2008-02-06 05:36:07 +01:00
|
|
|
designed to be run from Cron or similar.
|
2008-01-16 05:38:24 +01:00
|
|
|
"""
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-05-07 11:04:18 +02:00
|
|
|
|
2022-07-22 03:26:41 +02:00
|
|
|
from datetime import date, timedelta
|
2011-11-09 16:37:37 +01:00
|
|
|
from django.core.management.base import BaseCommand, CommandError
|
2008-01-16 05:38:24 +01:00
|
|
|
from django.db.models import Q
|
2018-12-28 09:13:52 +01:00
|
|
|
from django.utils import timezone
|
2022-07-22 03:26:41 +02:00
|
|
|
from django.utils.translation import gettext as _
|
|
|
|
import getopt
|
2018-10-31 16:24:57 +01:00
|
|
|
from helpdesk.lib import safe_template_context
|
2022-07-22 03:26:41 +02:00
|
|
|
from helpdesk.models import EscalationExclusion, FollowUp, Queue, Ticket, TicketChange
|
|
|
|
from optparse import make_option
|
|
|
|
import sys
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-08-18 23:29:31 +02:00
|
|
|
|
|
|
|
class Command(BaseCommand):
|
2016-10-23 22:09:17 +02:00
|
|
|
|
2008-08-18 23:29:31 +02:00
|
|
|
def __init__(self):
|
|
|
|
BaseCommand.__init__(self)
|
|
|
|
|
2019-02-03 18:59:17 +01:00
|
|
|
self.option_list = (
|
2008-08-18 23:29:31 +02:00
|
|
|
make_option(
|
2011-02-02 08:49:44 +01:00
|
|
|
'--queues',
|
2008-08-18 23:29:31 +02:00
|
|
|
help='Queues to include (default: all). Use queue slugs'),
|
|
|
|
make_option(
|
2011-02-02 08:49:44 +01:00
|
|
|
'--verboseescalation',
|
2008-08-18 23:29:31 +02:00
|
|
|
action='store_true',
|
|
|
|
default=False,
|
|
|
|
help='Display a list of dates excluded'),
|
2016-10-23 22:09:17 +02:00
|
|
|
)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-08-18 23:29:31 +02:00
|
|
|
def handle(self, *args, **options):
|
|
|
|
verbose = False
|
|
|
|
queue_slugs = None
|
|
|
|
queues = []
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2019-02-03 19:03:27 +01:00
|
|
|
if 'verboseescalation' in options:
|
2008-08-18 23:29:31 +02:00
|
|
|
verbose = True
|
2019-02-03 19:03:27 +01:00
|
|
|
if 'queues' in options:
|
2008-08-18 23:29:31 +02:00
|
|
|
queue_slugs = options['queues']
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-08-18 23:29:31 +02:00
|
|
|
if queue_slugs is not None:
|
|
|
|
queue_set = queue_slugs.split(',')
|
|
|
|
for queue in queue_set:
|
|
|
|
try:
|
2016-10-21 17:14:12 +02:00
|
|
|
Queue.objects.get(slug__exact=queue)
|
2008-08-18 23:29:31 +02:00
|
|
|
except Queue.DoesNotExist:
|
|
|
|
raise CommandError("Queue %s does not exist." % queue)
|
|
|
|
queues.append(queue)
|
|
|
|
|
|
|
|
escalate_tickets(queues=queues, verbose=verbose)
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
def escalate_tickets(queues, verbose):
|
|
|
|
""" Only include queues with escalation configured """
|
2022-07-12 12:34:19 +02:00
|
|
|
queryset = Queue.objects.filter(
|
|
|
|
escalate_days__isnull=False).exclude(escalate_days=0)
|
2008-01-22 06:54:22 +01:00
|
|
|
if queues:
|
|
|
|
queryset = queryset.filter(slug__in=queues)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
for q in queryset:
|
|
|
|
last = date.today() - timedelta(days=q.escalate_days)
|
|
|
|
today = date.today()
|
|
|
|
workdate = last
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
days = 0
|
|
|
|
|
|
|
|
while workdate < today:
|
|
|
|
if EscalationExclusion.objects.filter(date=workdate).count() == 0:
|
|
|
|
days += 1
|
|
|
|
workdate = workdate + timedelta(days=1)
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
req_last_escl_date = date.today() - timedelta(days=days)
|
|
|
|
|
|
|
|
if verbose:
|
2016-03-01 21:01:58 +01:00
|
|
|
print("Processing: %s" % q)
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2024-02-01 15:38:02 +01:00
|
|
|
Q_OPEN_STATUSES = Q()
|
|
|
|
for open_status in Ticket.OPEN_STATUSES:
|
2024-02-01 15:43:56 +01:00
|
|
|
Q_OPEN_STATUSES |= Q(status=open_status)
|
2024-02-01 15:38:02 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
for t in q.ticket_set.filter(
|
2024-02-01 15:38:02 +01:00
|
|
|
Q_OPEN_STATUSES
|
2016-10-23 22:09:17 +02:00
|
|
|
).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)
|
|
|
|
):
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2013-01-23 01:35:18 +01:00
|
|
|
t.last_escalation = timezone.now()
|
2008-01-16 05:38:24 +01:00
|
|
|
t.priority -= 1
|
|
|
|
t.save()
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2011-11-09 16:37:37 +01:00
|
|
|
context = safe_template_context(t)
|
2008-01-22 07:10:48 +01:00
|
|
|
|
2018-10-31 16:24:57 +01:00
|
|
|
t.send(
|
|
|
|
{'submitter': ('escalated_submitter', context),
|
|
|
|
'ticket_cc': ('escalated_cc', context),
|
2020-01-07 02:23:35 +01:00
|
|
|
'assigned_to': ('escalated_owner', context)},
|
2018-10-31 16:24:57 +01:00
|
|
|
fail_silently=True,
|
|
|
|
)
|
2008-01-16 05:38:24 +01:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
if verbose:
|
2016-03-01 21:01:58 +01:00
|
|
|
print(" - Esclating %s from %s>%s" % (
|
2008-08-19 10:50:38 +02:00
|
|
|
t.ticket,
|
2016-10-23 22:09:17 +02:00
|
|
|
t.priority + 1,
|
2008-08-19 10:50:38 +02:00
|
|
|
t.priority
|
2016-10-23 22:09:17 +02:00
|
|
|
)
|
2016-03-01 21:01:58 +01:00
|
|
|
)
|
2008-01-22 06:54:22 +01:00
|
|
|
|
2008-01-16 05:38:24 +01:00
|
|
|
f = FollowUp(
|
2016-10-21 17:14:12 +02:00
|
|
|
ticket=t,
|
|
|
|
title='Ticket Escalated',
|
2013-01-23 01:35:18 +01:00
|
|
|
date=timezone.now(),
|
2008-01-16 05:38:24 +01:00
|
|
|
public=True,
|
2008-05-07 11:04:18 +02:00
|
|
|
comment=_('Ticket escalated after %s days' % q.escalate_days),
|
2008-01-16 05:38:24 +01:00
|
|
|
)
|
|
|
|
f.save()
|
|
|
|
|
|
|
|
tc = TicketChange(
|
2016-10-21 17:14:12 +02:00
|
|
|
followup=f,
|
|
|
|
field=_('Priority'),
|
|
|
|
old_value=t.priority + 1,
|
|
|
|
new_value=t.priority,
|
2008-01-16 05:38:24 +01:00
|
|
|
)
|
|
|
|
tc.save()
|
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
def usage():
|
2016-03-01 21:01:58 +01:00
|
|
|
print("Options:")
|
|
|
|
print(" --queues: Queues to include (default: all). Use queue slugs")
|
|
|
|
print(" --verboseescalation: Display a list of dates excluded")
|
2008-01-22 06:54:22 +01:00
|
|
|
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-16 05:38:24 +01:00
|
|
|
if __name__ == '__main__':
|
2008-01-22 06:54:22 +01:00
|
|
|
try:
|
2022-07-12 12:34:19 +02:00
|
|
|
opts, args = getopt.getopt(
|
|
|
|
sys.argv[1:], ['queues=', 'verboseescalation'])
|
2008-01-22 06:54:22 +01:00
|
|
|
except getopt.GetoptError:
|
|
|
|
usage()
|
|
|
|
sys.exit(2)
|
|
|
|
|
|
|
|
verbose = False
|
|
|
|
queue_slugs = None
|
|
|
|
queues = []
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
for o, a in opts:
|
2011-02-02 08:49:44 +01:00
|
|
|
if o == '--verboseescalation':
|
2008-01-22 06:54:22 +01:00
|
|
|
verbose = True
|
2011-02-02 08:49:44 +01:00
|
|
|
if o == '--queues':
|
2008-01-22 06:54:22 +01:00
|
|
|
queue_slugs = a
|
2008-08-19 10:50:38 +02:00
|
|
|
|
2008-01-22 06:54:22 +01:00
|
|
|
if queue_slugs is not None:
|
|
|
|
queue_set = queue_slugs.split(',')
|
|
|
|
for queue in queue_set:
|
|
|
|
try:
|
|
|
|
q = Queue.objects.get(slug__exact=queue)
|
2008-08-18 23:29:31 +02:00
|
|
|
except Queue.DoesNotExist:
|
2016-03-01 21:01:58 +01:00
|
|
|
print("Queue %s does not exist." % queue)
|
2008-01-22 06:54:22 +01:00
|
|
|
sys.exit(2)
|
|
|
|
queues.append(queue)
|
|
|
|
|
|
|
|
escalate_tickets(queues=queues, verbose=verbose)
|