Getting the Most Out of Service Management
We've been using Service Management for some time, and have found a few irritations and annoyances that get in the way of us firing on all cylinders.
Here we share how we've overcome them, to maximize productivity.
Finding the reporter's company
We like to see who the reporter works for, sometimes it gives us a good feeling. We also want to identify when multiple different users from the same company are asking for help - perhaps it's part of a theme.
The way to get this info is to hover over the reporter, then quickly click on the display name before the dialog closes, which is easier said than done. However, I've just noticed that this has been improved in the latest version of Service Management where it shows the reporter email address. So this is not as useful as previously, but still worthwhile.
issue.reporter?.emailAddress?.replaceAll(/.*@/, "")We can improve this a little by creating a link to a JQL function which will show us all tickets reported by this domain. We want to keep the returned value the same as that's what we want indexed, but we'll tweak the displayed value a little by choosing a Custom template, with the following code:
<a target="_blank" href="jira/issues/?jql='Reporter Domain' ~ '$value'">$value</a>We can go a bit further by creating a bunch of links to google them for company info, and take a look at their home page. This is mostly for curiosity's sake.
$value - <a target="_blank"
href="$applicationProperties.getString("jira.baseurl")/issues/?jql='Reporter Domain' ~ '$value'">
Find similar
</a>
|
<a target="_blank" href="http://$value">Company home</a>
|
<a target="_blank" href="http://google.com/#q=$value">Google them</a>On the ticket you should see:
Canned Comments
We often find ourselves asking people to provide logs, or version information and screenshots etc. After doing this five or six times in a day you can find yourself getting a little terse.
In order to preserve the illusion of courtesy, we can pick from a template comment. These are processed on the server using groovy templates, so you can include substitutions like the user and agent's first name.
SEN Integration
If you are a marketplace vendor you may be interested in validating the user's Support Entitlement Number (SEN). Even if not, perhaps users of your product have some sort of token that they need to provide to show they are entitled to support. You might want to look this up in your CRM database and verify that the customer is within their maintenance agreement.
The following post-function, which we put on the Create action, validates the SEN and gets information from the marketplace API, which is used to populate the fields.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.config.properties.JiraProperties
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.MutableIssue
import com.onresolve.scriptrunner.runner.customisers.ContextBaseScript
import groovy.sql.Sql
import groovy.transform.BaseScript
import groovyx.net.http.ContentType
import groovyx.net.http.HTTPBuilder
import groovyx.net.http.Method
import org.apache.http.HttpRequest
import org.apache.http.HttpRequestInterceptor
import org.apache.http.protocol.HttpContext
import java.sql.Driver
import java.sql.Timestamp
import java.text.SimpleDateFormat
def http = new HTTPBuilder("https://marketplace.atlassian.com")
def jiraProperties = ComponentAccessor.getComponent(JiraProperties)
/**
* system properties defined like -Dplugin.marketplace.basic.auth.credential=user@example.com:password
*/
def cred = jiraProperties.getProperty("plugin.marketplace.basic.auth.credential")
def dbPassword = jiraProperties.getProperty("plugin.marketplace.database.password")
if (!cred) {
log.warn("Set plugin.marketplace.database.password as system prop")
}
http.client.addRequestInterceptor(new HttpRequestInterceptor() {
void process(HttpRequest httpRequest, HttpContext httpContext) {
httpRequest.addHeader("Authorization", "Basic " + cred.bytes.encodeBase64().toString())
}
})
@BaseScript ContextBaseScript baseScript
def issue = getIssueOrDefault("SD-12") as MutableIssue
def customFieldManager = ComponentAccessor.getComponent(CustomFieldManager)
def senCf = customFieldManager.getCustomFieldObjectByName("SEN")
def sen = issue.getCustomFieldValue(senCf) as String
// note: all the following fields shown here are required - see comment for type // <1>
def licenceTypeCf = customFieldManager.getCustomFieldObjectByName("Licence Type") // short text
def licenceSizeCf = customFieldManager.getCustomFieldObjectByName("Licence Size") // short text
def licensedProductCf = customFieldManager.getCustomFieldObjectByName("Licensed Product") // short text
def licensee = customFieldManager.getCustomFieldObjectByName("Licensee") // short text
def mainStartDateCf = customFieldManager.getCustomFieldObjectByName("Maintenance Start Date") // date
def mainEndDateCf = customFieldManager.getCustomFieldObjectByName("Maintenance End Date") // date
try {
if (!sen.startsWith("SEN-L")) {
def response = http.request(Method.GET, ContentType.JSON) {
uri.path = "/rest/1.0/vendors/81/sales"
uri.query = [limit: 1, "sort-by": "date", order: "desc", q: sen]
}
def dateFormat = new SimpleDateFormat("yyyy-MM-dd")
def licence = response.sales.find { it.licenseId == sen } as Map
if (licence) {
issue.setCustomFieldValue(licenceTypeCf, licence.licenseType)
issue.setCustomFieldValue(licenceSizeCf, licence.licenseSize)
issue.setCustomFieldValue(licensee, licence.organisationName)
issue.setCustomFieldValue(licensedProductCf, licence.pluginKey)
issue.setCustomFieldValue(mainStartDateCf, new Timestamp(dateFormat.parse(licence.maintenanceStartDate as String).time))
issue.setCustomFieldValue(mainEndDateCf, new Timestamp(dateFormat.parse(licence.maintenanceEndDate as String).time))
} else {
// couldn't find licence
}
}}
catch (any) {
log.warn("Failed to get SEN details", any)
}Line 47: All of these fields must exist with the type as shown
Updating Tickets when bugs are Fixed
When a user reports a bug, either already known or not yet known, we link to the public bug (creating it if necessary). Then we close the support ticket as a Known Issue, asking the user to watch the linked bug report. Sometimes they do, sometimes they don't.
To ensure they are aware when the bug is fixed and released, we add a post-function on the Release transition for the bug workflow which adds a comment to all support tickets that link to it:
The issue <% out << issue.key %> which causes the problem in this support request has now been released
bq. <% out << issue.summary %>When the bug is released, the service desk tickets are updated with the following comment (and a mail is sent, etc):
Adding organizations when a Service Management issue gets created
What are organizations in Jira?
In a Jira Service Desk project you can configure organizations to group your customers together (see the Atlassian documentation for Adding customers to organizations). When you add an organization to a project, it's members can raise requests in the project and share them with the organization. The organizations are added to an issue through the custom field named Organizations.
Use case
You want to automatically add certain organizations to new issues created in your service desk project. Using the script below, you can configure a custom Listener to listen for the Issue Created event and automatically add the organizations you specify in the script.
import com.atlassian.jira.project.type.ProjectTypeKeys
// get the issue that triggered the event
def issue = event.issue
// exit early if the issue is not in a Service Desk project
if (issue.projectObject.projectTypeKey.key != ProjectTypeKeys.SERVICE_DESK.key) {
log.warn('Cannot add organizations to a non-service desk issue')
return
}
// update the issues organizations
issue.update {
setOrganizations {
add('fooOrg', 'barOrg')
}
}Automatically Clone an Issue
This tutorial will take you through the steps needed to create a new issue in another project and transfer the information needed, once your original request is resolved.
Use Cases:
- When a user raises a bug report, if it is verified, you want to automatically add it to your backlog in your development project.
- When a request for an item is approved by your manager, you want it to be placed in another project so that the appropriate team can can acquire it.
- When a person has been successfully hired, you want to auto raise a ticket to IT so that their login and basic IT is provided for them.
- When an incident has been fixed and you need to file a Root Cause Analysis(RCA) ticket in another project.
Steps
We need to setup a Clones an issue, and links post function in the transition that closes your ticket.
Create RCA Confluence Page
This tutorial will show you a complex example on how to move data from Jira Service Management to Confluence.
Use Cases:
RCA analysis usually needs a sharing of information and document collaboration that is very hard to achieve in Jira. That's why a Confluence integration is a better idea for this particular example.
Steps
We need to setup a "Custom Scripted Function". Also, in order for this to work, you must have a reciprocal appLink between your Confluence and Jira.
Email Linked Issue Watchers, Request Participants & Organizations
Email Reporter, Watchers, Request Participants and Organizations of Linked Issues When Transitioning
This Post-Function script will allow you to trigger notifications users/customers (reporter, watchers, request participants and organizations) for a linked issue. This was written assuming this would be most helpful to notify users when the linked issues were being resolved, but could fit anywhere in the workflow.
Use Cases:
- Your helpdesk team is receiving issues related to a software bug. Your customers' organizations can be added to the helpdesk issue and then receive an email when the software team has closed their linked issue.
- Business users may have an IT issue linked as a blocker, but might have no interest in watching an IT team's issues for updates due to the volume of comments/edit. If they would like to receive a notification only when it is finished, this script can shield them from all the rest of the Jira notifications.