Skip to content

Instantly share code, notes, and snippets.

@bmccormack
Last active January 24, 2018 15:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bmccormack/5e5ee833623a73e40bc6 to your computer and use it in GitHub Desktop.
Save bmccormack/5e5ee833623a73e40bc6 to your computer and use it in GitHub Desktop.

#Random Assignment for Help Scout

When you have conversations that are handled by multiple individuals on a team, it can be difficult to distribute the tasks evenly to each member without cherry picking or having someone manage the queue.

This script helps by taking unassigned conversations and re-assigning them randomly to the members of the team, based on a specified weight.

##Set up

  1. Download help_scout_conversation.py, help_scout_helper.py, and settings.py to a directory.
  2. Install the python requests library.
  3. In help_scout_conversations.py, edit the following:
    • ID_MAILBOX - the ID of the mailbox whose conversations you want to update
    • ID_FOLDER - The ID of the Unassigned folder in that mailbox
    • TEAM_MEMBERS - A list of team members who should receive a share of unassigned inbox cases. Edit id, name, and share. The higher the share value, the higher the chance the person will be assigned the conversation.
  4. In settings.py, paste in your API key from Help Scout. I recommend setting up a dedicated API user for these sorts of things, but any user with access to that mailbox will do.
    • NOTE: Ignore the settings.py file from source control
  5. You can run the script from the command line using:

> python help_scout_conversation_assignment.py

You can optionally supply --debug and --quiet parameters. Pass --help to see what those do, or read the code.

BONUS: Schedule the script to run regularly using cron.

##Credits

ID_MAILBOX = 33333 # Support Mailbox
ID_FOLDER = 444444 # Unassigned Folder
TEAM_MEMBERS = [{"id": 11111, "name": "Bert" , "share": 0},
{"id": 22222, "name": "Ernie" , "share": 1},
{"id": 33333, "name": "George", "share": 1}]
import re
import random
import requests
import json
from datetime import datetime
from help_scout_helper import query_helpscout, query_helpscout_all_pages
################### COMMAND LINE OPTIONS #################################
#using optparse instead of argparse b/c of older versions of python, <=2.6
from optparse import OptionParser
parser = OptionParser()
parser.add_option('--quiet',dest='quiet',action='store_true', help="don't print final output")
parser.add_option('--debug',dest='debug',action='store_true', help="doesn't make any changes to cases")
parser.set_defaults(quiet=False, debug=False)
(options, args) = parser. parse_args()
quiet = options.quiet
debug = options.debug
###########################################################################
############## SET UP RANDOM LOTTERY OF REP IDS ###########################
team = TEAM_MEMBERS
#lottery is an array to help with randomness
lottery = []
#this will fill the lottery array with the id values in each rep,
#one for each "share" value above
for rep in team:
lottery.extend([rep["id"]] * rep["share"])
#shuffle the list
random.shuffle(lottery)
###########################################################################
############ GET CONVERSATIONS, ASSIGN THEM TO PEOPLE #####################
url = 'mailboxes/%s/folders/%s/conversations.json' % (ID_MAILBOX, ID_FOLDER)
resp, conversations = query_helpscout_all_pages('GET', url)
i = 0
for conversation in conversations:
######################## GET PERSON WHO LAST EDITED CONVERSATION ######################
#
# For each conversation returned, we have to query the API again to get the full
# list of threads. The first thread tells us who last edited it.
#
url = 'conversations/%s.json' % conversation["id"]
resp = query_helpscout('GET', url)
conversation_detail = resp.json()
id_person_last_edited_by = -1
if 'threads' in conversation_detail['item'] and len(conversation_detail['item']['threads']) > 0:
most_recent_thread = conversation_detail['item']['threads'][0]
if 'createdBy' in most_recent_thread and most_recent_thread['createdBy']['type'] == 'user':
id_person_last_edited_by = most_recent_thread['createdBy']['id']
target_rep = id_person_last_edited_by
###########################################################################
# If the person who last edited the conversation assigned it to 'Anyone',
# we want to keep iterating through the lottery until we get a different user.
tries = 0
max_tries = 10
while target_rep == id_person_last_edited_by and tries < max_tries:
target_rep = lottery[i % len(lottery)]
i += 1
tries += 1
# if target_rep is still -1, this means that we don't have anyone to assign it to, usually
# because there's only 1 person with an inbox share and that person assigned the case to
# Anyone. Just skip it.
if target_rep == -1:
continue
# If the debug flag is sent, don't actually update the conversation. Good for testing.
if not debug:
# You can't just supply the id of the owner. You have to supply a dummy person object.
data = {"owner": {'id': target_rep, 'type': 'user'}}
resp = query_helpscout('PUT', url, data)
if not quiet:
if resp.status_code == requests.codes.ok:
print "live: assign %s to %s" % (conversation['id'], target_rep)
else:
print "failed: assign %s to %s" % (conversation['id'], target_rep)
print resp.status_code
print resp.text
elif not quiet:
print "debug: assign %s to %s" % (conversation['id'], target_rep)
###########################################################################
from settings import HELP_SCOUT_API_KEY
import requests
import base64
import json
from requests import Request, Session
def query_helpscout(method, url, data=None, params=None):
BASE_URL = "https://api.helpscout.net/v1/"
auth = "Basic " + base64.b64encode(HELP_SCOUT_API_KEY + ":X")
headers = {'Content-Type': 'application/json'
, 'Accept' : 'application-json'
, 'Authorization' : str(auth)
, 'Accept-Encoding' : 'gzip, deflate'
}
s = Session()
req = Request(method, BASE_URL + url,
data=json.dumps(data),
headers=headers,
params=params
)
prepped = s.prepare_request(req)
# do something with prepped.body
# do something with prepped.headers
resp = s.send(prepped
)
return resp
#returns the last response as well as a collection
#of all items.
def query_helpscout_all_pages(method, url, data=None):
n_pages = 1
page = 1
items = []
resp = None
while page <= n_pages:
page_url_piece = "%s?page=%s"
if "?" in url:
page_url_piece = "%s&page=%s"
resp = query_helpscout(method, page_url_piece % (url, page))
if resp.status_code != requests.codes.ok:
return resp, items
resp_object = resp.json()
if page == 1:
n_pages = resp_object["pages"]
items.extend(resp_object["items"])
page += 1
return resp, items
#Exclude this file from source control
HELP_SCOUT_API_KEY = 'paste your API key here'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment