mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-19 05:59:44 -04:00
Triage tickets based on time of day and services
TL;DR, as much as possible we should work out how to prioritise tickets and not put that burden on the user. However, there are some cases where we can’t. In business hours all tickets are high priority, ie we will at least acknowledge them within 30 mins. If we are not in business hours then we need to know if a ticket is serious enough to get someone out of bed. Only the user can tell us this, but we can give them some examples to help them decide. In addition, out-of-hours tickets are only a priority if the user has live services. Normally we can determine this and do the priority-setting in the background. If they can’t log in then we can’t determine what services they have. So in this case they will need to use the emergency email address, which only users with live services will have. The logic for this gets fairly complex. It might be to easier to understand what’s going on by walking through the test cases, which are a bit more declarative. N.B. Deskpro’s ‘urgency’ is descending, eg 10 is the most urgent and 1 is the least.
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
import requests
|
||||
from flask import render_template, url_for, redirect, flash, current_app, abort
|
||||
import pytz
|
||||
from flask import render_template, url_for, redirect, flash, current_app, abort, request
|
||||
from flask_login import current_user
|
||||
from app import convert_to_boolean, current_service, service_api_client
|
||||
from app.main import main
|
||||
from app.main.forms import SupportType, Support
|
||||
from app.main.forms import SupportType, Support, Triage
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
@main.route('/support', methods=['GET', 'POST'])
|
||||
@@ -16,11 +19,46 @@ def support():
|
||||
return render_template('views/support/index.html', form=form)
|
||||
|
||||
|
||||
@main.route('/support/contact/<ticket_type>', methods=['GET', 'POST'])
|
||||
@main.route('/support/triage', methods=['GET', 'POST'])
|
||||
def triage():
|
||||
form = Triage()
|
||||
if form.validate_on_submit():
|
||||
return redirect(url_for(
|
||||
'.feedback',
|
||||
ticket_type='problem',
|
||||
severe=(form.severe.data == 'yes')
|
||||
))
|
||||
return render_template(
|
||||
'views/support/triage.html',
|
||||
form=form
|
||||
)
|
||||
|
||||
|
||||
@main.route('/support/submit/<ticket_type>', methods=['GET', 'POST'])
|
||||
def feedback(ticket_type):
|
||||
if ticket_type not in ['problem', 'question']:
|
||||
|
||||
if ticket_type not in ['question', 'problem']:
|
||||
abort(404)
|
||||
|
||||
form = Support()
|
||||
severe = request.args.get('severe')
|
||||
|
||||
urgent = any((
|
||||
in_business_hours(),
|
||||
(ticket_type == 'problem' and convert_to_boolean(severe))
|
||||
))
|
||||
|
||||
anonymous = all((
|
||||
(not form.email_address.data),
|
||||
(not current_user.is_authenticated),
|
||||
))
|
||||
|
||||
if needs_triage(ticket_type, severe):
|
||||
return redirect(url_for('.triage'))
|
||||
|
||||
if needs_escalation(ticket_type, severe):
|
||||
return redirect(url_for('.bat_phone'))
|
||||
|
||||
if form.validate_on_submit():
|
||||
if current_user.is_authenticated:
|
||||
user_email = current_user.email_address
|
||||
@@ -41,6 +79,7 @@ def feedback(ticket_type):
|
||||
'subject': 'Notify feedback',
|
||||
'message': feedback_msg,
|
||||
'label': ticket_type,
|
||||
'urgency': 10 if urgent else 1,
|
||||
}
|
||||
headers = {
|
||||
"X-DeskPRO-API-Key": current_app.config.get('DESKPRO_API_KEY'),
|
||||
@@ -63,5 +102,92 @@ def feedback(ticket_type):
|
||||
return render_template(
|
||||
'views/support/{}.html'.format(ticket_type),
|
||||
form=form,
|
||||
ticket_type=ticket_type
|
||||
ticket_type=ticket_type,
|
||||
)
|
||||
|
||||
|
||||
@main.route('/support/escalate', methods=['GET', 'POST'])
|
||||
def bat_phone():
|
||||
|
||||
if current_user.is_authenticated:
|
||||
return redirect(url_for('main.feedback', ticket_type='problem'))
|
||||
|
||||
return render_template('views/support/bat-phone.html')
|
||||
|
||||
|
||||
@main.route('/support/thanks', methods=['GET', 'POST'])
|
||||
def thanks():
|
||||
return render_template(
|
||||
'views/support/thanks.html',
|
||||
ticket_type=request.args.get('ticket_type'),
|
||||
)
|
||||
|
||||
|
||||
def in_business_hours():
|
||||
|
||||
now = datetime.now().replace(tzinfo=pytz.timezone('Europe/London'))
|
||||
|
||||
if is_weekend(now) or is_bank_holiday(now):
|
||||
return False
|
||||
|
||||
opening_time = now.replace(hour=9, minute=30, second=0, tzinfo=pytz.timezone('Europe/London'))
|
||||
closing_time = now.replace(hour=17, minute=30, second=0, tzinfo=pytz.timezone('Europe/London'))
|
||||
|
||||
return opening_time <= now < closing_time
|
||||
|
||||
|
||||
def is_weekend(time):
|
||||
return time.strftime('%A') in {
|
||||
'Saturday',
|
||||
'Sunday',
|
||||
}
|
||||
|
||||
|
||||
def is_bank_holiday(time):
|
||||
return time.strftime('%d/%m/%Y') in {
|
||||
# taken from
|
||||
# https://github.com/alphagov/calendars/blob/7f6512b0a95d77aa22accef105860074c19f1ec0/lib/data/bank-holidays.json
|
||||
"01/01/2016",
|
||||
"25/03/2016",
|
||||
"28/03/2016",
|
||||
"02/05/2016",
|
||||
"30/05/2016",
|
||||
"29/08/2016",
|
||||
"26/12/2016",
|
||||
"27/12/2016",
|
||||
"02/01/2017",
|
||||
"14/04/2017",
|
||||
"17/04/2017",
|
||||
"01/05/2017",
|
||||
"29/05/2017",
|
||||
"28/08/2017",
|
||||
"25/12/2017",
|
||||
"26/12/2017",
|
||||
}
|
||||
|
||||
|
||||
def has_live_services(user_id):
|
||||
return any(
|
||||
service['restricted'] is False
|
||||
for service in service_api_client.get_services({'user_id': user_id})['data']
|
||||
)
|
||||
|
||||
|
||||
def needs_triage(ticket_type, severe):
|
||||
return all((
|
||||
ticket_type == 'problem',
|
||||
severe is None,
|
||||
(
|
||||
not current_user.is_authenticated or has_live_services(current_user.id)
|
||||
),
|
||||
not in_business_hours(),
|
||||
))
|
||||
|
||||
|
||||
def needs_escalation(ticket_type, severe):
|
||||
return all((
|
||||
ticket_type == 'problem',
|
||||
convert_to_boolean(severe),
|
||||
not current_user.is_authenticated,
|
||||
not in_business_hours(),
|
||||
))
|
||||
|
||||
Reference in New Issue
Block a user