Page tree
Skip to end of metadata
Go to start of metadata

This page is about Time to SLA for Jira Server users.

Requirements

Users want to create a "shared SLA Goal" for issues that fit certain criteria. In this use case, issues belong to the "Goal" project and created this month will have a total of 1 hour SLA Goal.

If existing issues have a total working duration of 5 minutes, then the next issue created will have a 55 minutes SLA Goal. The SLA Goal will be automatically adjusted for every new issue. 

Solution

"Dynamic Duration" feature will be used for this use case.

  1. Add the dynamic Duration custom field as explained here.
  2. Create an SLA (named First Response here) with dynamic duration as the SLA Goal (refer to here), this will be your SLA with the 1-hour quota.
  3. Add a scripted post function to the Create transition in your workflow and use the following script. Put this post function to the 2nd place.


import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder
import com.atlassian.jira.issue.ModifiedValue

def changeHolder = new DefaultIssueChangeHolder()
def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchService = ComponentAccessor.getComponent(SearchService)
def issueManager = ComponentAccessor.getIssueManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def searchProvider = ComponentAccessor.getComponent(SearchProvider)

// Edit this query to suit you use case. To only include finished SLAs add slaFunction=isFinished() to the query
def query = jqlQueryParser.parseQuery("project = Goal and created >= startOfMonth()")

def results = searchService.search(user, query, PagerFilter.getUnlimitedFilter())

def totalWorkingDurationAsSeconds = 0L

results.getResults().each { documentIssue ->

    MutableIssue foundIssue = issueManager.getIssueObject(documentIssue.id)

// Replace 10303 with the id of the SLA Overview custom field in your instance
    def overviewField = customFieldManager.getCustomFieldObject("customfield_10303")
    def overviewFieldValue = foundIssue.getCustomFieldValue(overviewField)


    if (overviewFieldValue && overviewFieldValue.size() > 0) {
        overviewFieldValue.each {
            String slaName = it.sla.description

            if (slaName.equals("SLA-Resolution")) {
                long workingDurationAsSeconds = it.workingDurationAsSeconds

                totalWorkingDurationAsSeconds += workingDurationAsSeconds
            } else {
                log.warn("This SLA is not eligible")
            }
        }

    }
}
MutableIssue issue = issue

// Replace 3600  (60*60 seconds) with the SLA duration you want
long dynamicSLAGoal = 3600L - totalWorkingDurationAsSeconds

// Replace 10301 with the id of TTS-Dynamic Duration field id
def dynamicDurationField = customFieldManager.getCustomFieldObject(10301)
String remainingSlaDuration = Long.toString(Math.round(dynamicSLAGoal / 60)) + "m"
if (remainingSlaDuration.equals("0m") || remainingSlaDuration.contains("-")) {
    dynamicDurationField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(dynamicDurationField), "0m"), changeHolder)
} else {
    dynamicDurationField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(dynamicDurationField), remainingSlaDuration), changeHolder)
}


4. Put "Stores updates to an issue (no change history is created)." post function after the custom post function you've just created. Your post functions should look like this:

5. Publish your workflow.

6. You're done.