Uploaded image for project: 'Jira Service Management Data Center'
  1. Jira Service Management Data Center
  2. JSDSERVER-78

Ability to view Elapsed Time as a column in Issue Navigator or in Export

    • 56
    • 4
    • We collect Jira Service Desk feedback from various sources, and we evaluate what we've collected when planning our product roadmap. To understand how this piece of feedback will be reviewed, see our Implementation of New Features Policy.

      NOTE: This suggestion is for JIRA Service Desk Server. Using JIRA Service Desk Cloud? See the corresponding suggestion.

      Currently only Remaining Time is displayed, but we also need the Elapsed Time (on the last cycle) in order to export the data for further processing.

        1. ScriptCode.jpg
          ScriptCode.jpg
          153 kB
        2. ScriptCodeError1.jpg
          ScriptCodeError1.jpg
          160 kB
        3. ScriptCodeError2.jpg
          ScriptCodeError2.jpg
          159 kB

          Form Name

            [JSDSERVER-78] Ability to view Elapsed Time as a column in Issue Navigator or in Export

            We already released Toolbox for JIRA Service Desk plugin https://marketplace.atlassian.com/plugins/com.kostebekteknoloji.plugins.jira.jira-service-desk-toolbox/server/overview and you can display SLA elapsed times as a custom field with different formats,

            • Default View ( dd:hh:mm )
            • Friendly ( XXd XXh XXm )
            • Millisecond ( XXXXXX msec )
              Moreover, You can contact with info@kostebekteknoloji.com for your other format requests and new requests for JIRA Service Desk functionality to extend our plugin.
              Best regards,

            Mert Karadağlı _ Köstebek Teknoloji _ added a comment - - edited We already released Toolbox for JIRA Service Desk plugin https://marketplace.atlassian.com/plugins/com.kostebekteknoloji.plugins.jira.jira-service-desk-toolbox/server/overview and you can display SLA elapsed times as a custom field with different formats, Default View ( dd:hh:mm ) Friendly ( XXd XXh XXm ) Millisecond ( XXXXXX msec ) Moreover, You can contact with info@kostebekteknoloji.com for your other format requests and new requests for JIRA Service Desk functionality to extend our plugin. Best regards,

            Hi, Hector,

            The first error was solved by an easy cast in the parameter to 'long' type: getCustomFieldObject((long)10500)
            For the second, I * didn't find* the method getCompleteSLAData() in any place (even hardly looking on Google tool...).
            As you said, may be the new version of JSD changed it to another new method.

            Thanks for your comments and help.

            Antonio.

            Antonio Duarte added a comment - Hi, Hector, The first error was solved by an easy cast in the parameter to 'long' type: getCustomFieldObject((long)10500) For the second, I * didn't find* the method getCompleteSLAData() in any place (even hardly looking on Google tool...). As you said, may be the new version of JSD changed it to another new method. Thanks for your comments and help. Antonio.

            Hi Antonio

            You need to find the method to obtain the object of the Time to Resolution custom field (Service Desk plugin)
            I think you have a newer version and maybe the method has changed.
            Please try with some of these: https://docs.atlassian.com/jira/latest/com/atlassian/jira/issue/CustomFieldManager.html

            Hector Flores added a comment - Hi Antonio You need to find the method to obtain the object of the Time to Resolution custom field (Service Desk plugin) I think you have a newer version and maybe the method has changed. Please try with some of these: https://docs.atlassian.com/jira/latest/com/atlassian/jira/issue/CustomFieldManager.html

            Hi, Hector,

            I'm using your simplest code (see attachement ScriptCode.jpg).
            In the other images you can see the error messages informed by Script Runner.
            Thanks for your attention.
            Antonio.

            Antonio Duarte added a comment - Hi, Hector, I'm using your simplest code (see attachement ScriptCode.jpg). In the other images you can see the error messages informed by Script Runner. Thanks for your attention. Antonio.

            There are 2 custom fields above, which one gives you that error?
            In the first one you need to call libraries

            import com.atlassian.jira.component.ComponentAccessor
            import com.atlassian.jira.issue.CustomFieldManager
            import com.atlassian.jira.issue.fields.CustomField
            import com.atlassian.jira.issue.MutableIssue
            import com.atlassian.jira.issue.fields.CustomField
            import com.atlassian.jira.ComponentManager

            Hector Flores added a comment - There are 2 custom fields above, which one gives you that error? In the first one you need to call libraries import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.ComponentManager

            Hi, Hector,

            I tried your piece of code above, but script runner shows this error:

            [Static type checking] - Cannot find matching method
            com.atlassian.jira.issue.CustomFieldManager#getCustomFieldObject(int)

            and the same with

            java.lang.Object#getCompleteSLAData()

            and also

            java.lang.Object#getOngoingSLAData()

            Can you help checking your code, please?

            Antonio Duarte added a comment - Hi, Hector, I tried your piece of code above, but script runner shows this error: [Static type checking] - Cannot find matching method com.atlassian.jira.issue.CustomFieldManager#getCustomFieldObject(int) and the same with java.lang.Object#getCompleteSLAData() and also java.lang.Object#getOngoingSLAData() Can you help checking your code, please?

            Hi
            I think I found the solution, at least the solution appropriate for me.
            Sorry my code, I've never have code with groovy.
            I had to decompile the service-desk .jar to know how many methods I could call.
            I could NOT find how to know the goal time of every issue so I made a function that get me the goal minutes depending of the issue type and priority. Goal times are hard-coded, (it hurts) but it works. Could anyone help with this???

            When I get the Time to Resolution custom field (timeToResolution in the code), in fact I have an SLAValue.class object. From this class we need 2 classes: OngoingSLAData and CompletedSLAData. More info in the comments in the code.

            Create a custom field -> Groovy script
            Go to Script Fields and put the following code

            If you want to know the spent time in an issue when the SLA clock is stopped

            We only need to get the elapsed time from the CompleteSLAData class

            CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
            def componentManager = ComponentManager.getInstance()
            def changeHistoryManager = componentManager.getChangeHistoryManager()
            
            // Time to Resolution custom field from SLA calculations (Service desk plugin)
            CustomField cf_timeToResolution = customFieldManager.getCustomFieldObject(11704)  //Put your Time to Resolution custom field ID
            def timeToResolution = issue.getCustomFieldValue(cf_timeToResolution)
            
                if (timeToResolution != null)  
                {
                    //Get elapsed time from Service Desk plugin libraries after have decompiled the .jar
                    long timeToResolutionMillis = timeToResolution.getCompleteSLAData().get(0).getElapsedTime()
                    // Convert time to minutes
                    double timeToResolutionMinutes = timeToResolutionMillis / (1000*60)
                    // Rounding and return the value
                    return timeToResolutionMinutes.round().toString();
                }
            

            If you want to know the spent time when the SLA clock is stopped or PAUSED

            In this case different classes in the SLAValue.class have to been checked CompletedSLAData and OngoingSLAData
            The result is only showed when the status are Solved, Resolved, Done or Closed (depending on the type of issue)
            In my SLA clock configuration when Solved, Resolved or Done the clock is paused, and when Closed the clock is stopped.

            import com.atlassian.jira.component.ComponentAccessor
            import com.atlassian.jira.issue.CustomFieldManager
            import com.atlassian.jira.issue.fields.CustomField
            import com.atlassian.jira.issue.MutableIssue
            import com.atlassian.jira.issue.fields.CustomField
            import com.atlassian.jira.ComponentManager
            
            // ------- FUNCTIONS 
            
            // Get minutes per type of issue and priority/urgency
            long goalMinutesPerPriorityOrUrgency(type, value) {
                       
                def valueCopied = value
                switch (type) {
                    case "Incident":
                        result = goalMinutesPerIncidentPriority(valueCopied)
                        break
                    case "Request for Change":
                        result = goalMinutesPerRfCPriority(valueCopied)
                        break
                    case "Task":
                        result = goalMinutesPerTaskUrgency(valueCopied)
                        break
                    default:
                        result = 0
                }
                result
            }
            
            // Minutes per incident by priority
            long goalMinutesPerIncidentPriority(priority) {
                
                switch (priority) {
                    case "Blocker":
                       result = 240 //4h
                        break
                    // more cases ...
            
                    default:
                        result = 0
                } 
                result
            }
            
            // Minutes per RfC by priority
            long goalMinutesPerRfCPriority(priority) {
                
               switch (priority) {
                    case "Blocker":
                        result = 240 //4h
                        break
                   // more cases ...
                    default:
                        result = 0
                }
                result
            }
            
            // Minutes per task by urgency
            long goalMinutesPerTaskUrgency(urgency) {
                  
                switch (urgency) {
                    case "Critical":
                        result = 480 //8h
                        break
                 // more cases...
                    default:
                        result = 0
                }
                result
            }
            
            // ------- MAIN 
            // Return every value in minutes
            
            // Status of the issue is saved
            def statusName = issue.getStatusObject().getSimpleStatus().getName();
            
            if ((statusName == 'Solved') || (statusName == 'Resolved') || (statusName == 'Done') || (statusName == 'Closed')) 
            {
                CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager()
                def componentManager = ComponentManager.getInstance()
                def changeHistoryManager = componentManager.getChangeHistoryManager()
                
                // Time to Resolution custom field from SLA calculations (Service desk plugin)
                CustomField cf_timeToResolution = customFieldManager.getCustomFieldObject(11704) //Put your Time to Resolution custom field ID
                def timeToResolution = issue.getCustomFieldValue(cf_timeToResolution)
                long result = 0
                def issueTypeName = issue.getIssueTypeObject().getName() // Incident, Request for Change, Task
                def priorityOrUrgency = ""
                
                // I use urgency for tasks instead of Priority
                if (issueTypeName == "Task")
                {
                    // Get Urgency field from issue of type Task
                    CustomField cf_urgency = customFieldManager.getCustomFieldObject(12502) // I use Urgency for task instead of Priority
                	priorityOrUrgency = issue.getCustomFieldValue(cf_urgency)
                }
                else
                {
                    // Get Priority value from issue of type Incident or Request for Change
                    priorityOrUrgency = issue.getPriority().getString("name")
                }
                       
                /* 	
                    CompleteSLAData is only filled when the issue has the SLA clock stopped (passed through 'Solved' or 'Resolved' to 'Closed')
                    OngoingSLAData is only filled when the issue has the SLA clock running or paused.
                */
                if (timeToResolution != null)  
                {
                    // SLA clock stopped - get from CompleteSLAData
                    if (timeToResolution.getCompleteSLAData().size() > 0)
                    {
                        // Get elapsed time from Service Desk plugin libraries after have decompiled the .jar
                        long timeToResolutionMillis = timeToResolution.getCompleteSLAData().get(0).getElapsedTime()
                        // Convert time to minutes
                        double timeToResolutionMinutes = timeToResolutionMillis / (1000*60)
                        return timeToResolutionMinutes.round().toString();
                    }
                    // SLA clock paused - get from OngoingSLAData
                    else
                    {
                        double elapsedTime = 0;
                        if (timeToResolution.getOngoingSLAData() != null)
                        {
                            // Get StarTime from OngoingSLAData
                            double remainingTimeMin = (timeToResolution.getOngoingSLAData().getThresholdData().get().getRemainingTime().get()) / (1000*60)
                            long remainingTimeMinLong = remainingTimeMin.round().longValue() 
                                           
                            if (remainingTimeMin < 0) // RemainingTime is negative
                            {
                                elapsedTime = elapsedTime.sum(goalMinutesPerPriorityOrUrgency(issueTypeName, priorityOrUrgency), remainingTimeMinLong.abs())
                            }
                            else
                            {
                                elapsedTime = goalMinutesPerPriorityOrUrgency(issueTypeName, priorityOrUrgency).doubleValue() - remainingTimeMin
                            }
                        }
                        return elapsedTime.round().toString() 
                    }
                    
                } 
            

            Hope it helps!

            Hector Flores

            Hector Flores added a comment - Hi I think I found the solution, at least the solution appropriate for me. Sorry my code, I've never have code with groovy. I had to decompile the service-desk .jar to know how many methods I could call. I could NOT find how to know the goal time of every issue so I made a function that get me the goal minutes depending of the issue type and priority. Goal times are hard-coded, (it hurts) but it works. Could anyone help with this??? When I get the Time to Resolution custom field (timeToResolution in the code), in fact I have an SLAValue.class object. From this class we need 2 classes: OngoingSLAData and CompletedSLAData. More info in the comments in the code. Create a custom field -> Groovy script Go to Script Fields and put the following code If you want to know the spent time in an issue when the SLA clock is stopped We only need to get the elapsed time from the CompleteSLAData class CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() def componentManager = ComponentManager.getInstance() def changeHistoryManager = componentManager.getChangeHistoryManager() // Time to Resolution custom field from SLA calculations (Service desk plugin) CustomField cf_timeToResolution = customFieldManager.getCustomFieldObject(11704) //Put your Time to Resolution custom field ID def timeToResolution = issue.getCustomFieldValue(cf_timeToResolution) if (timeToResolution != null ) { //Get elapsed time from Service Desk plugin libraries after have decompiled the .jar long timeToResolutionMillis = timeToResolution.getCompleteSLAData().get(0).getElapsedTime() // Convert time to minutes double timeToResolutionMinutes = timeToResolutionMillis / (1000*60) // Rounding and return the value return timeToResolutionMinutes.round().toString(); } If you want to know the spent time when the SLA clock is stopped or PAUSED In this case different classes in the SLAValue.class have to been checked CompletedSLAData and OngoingSLAData The result is only showed when the status are Solved, Resolved, Done or Closed (depending on the type of issue) In my SLA clock configuration when Solved, Resolved or Done the clock is paused, and when Closed the clock is stopped. import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.ComponentManager // ------- FUNCTIONS // Get minutes per type of issue and priority/urgency long goalMinutesPerPriorityOrUrgency(type, value) { def valueCopied = value switch (type) { case "Incident" : result = goalMinutesPerIncidentPriority(valueCopied) break case "Request for Change" : result = goalMinutesPerRfCPriority(valueCopied) break case "Task" : result = goalMinutesPerTaskUrgency(valueCopied) break default : result = 0 } result } // Minutes per incident by priority long goalMinutesPerIncidentPriority(priority) { switch (priority) { case "Blocker" : result = 240 //4h break // more cases ... default : result = 0 } result } // Minutes per RfC by priority long goalMinutesPerRfCPriority(priority) { switch (priority) { case "Blocker" : result = 240 //4h break // more cases ... default : result = 0 } result } // Minutes per task by urgency long goalMinutesPerTaskUrgency(urgency) { switch (urgency) { case "Critical" : result = 480 //8h break // more cases... default : result = 0 } result } // ------- MAIN // Return every value in minutes // Status of the issue is saved def statusName = issue.getStatusObject().getSimpleStatus().getName(); if ((statusName == 'Solved' ) || (statusName == 'Resolved' ) || (statusName == 'Done' ) || (statusName == 'Closed' )) { CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager() def componentManager = ComponentManager.getInstance() def changeHistoryManager = componentManager.getChangeHistoryManager() // Time to Resolution custom field from SLA calculations (Service desk plugin) CustomField cf_timeToResolution = customFieldManager.getCustomFieldObject(11704) //Put your Time to Resolution custom field ID def timeToResolution = issue.getCustomFieldValue(cf_timeToResolution) long result = 0 def issueTypeName = issue.getIssueTypeObject().getName() // Incident, Request for Change, Task def priorityOrUrgency = "" // I use urgency for tasks instead of Priority if (issueTypeName == "Task" ) { // Get Urgency field from issue of type Task CustomField cf_urgency = customFieldManager.getCustomFieldObject(12502) // I use Urgency for task instead of Priority priorityOrUrgency = issue.getCustomFieldValue(cf_urgency) } else { // Get Priority value from issue of type Incident or Request for Change priorityOrUrgency = issue.getPriority().getString( "name" ) } /* CompleteSLAData is only filled when the issue has the SLA clock stopped (passed through 'Solved' or 'Resolved' to 'Closed' ) OngoingSLAData is only filled when the issue has the SLA clock running or paused. */ if (timeToResolution != null ) { // SLA clock stopped - get from CompleteSLAData if (timeToResolution.getCompleteSLAData().size() > 0) { // Get elapsed time from Service Desk plugin libraries after have decompiled the .jar long timeToResolutionMillis = timeToResolution.getCompleteSLAData().get(0).getElapsedTime() // Convert time to minutes double timeToResolutionMinutes = timeToResolutionMillis / (1000*60) return timeToResolutionMinutes.round().toString(); } // SLA clock paused - get from OngoingSLAData else { double elapsedTime = 0; if (timeToResolution.getOngoingSLAData() != null ) { // Get StarTime from OngoingSLAData double remainingTimeMin = (timeToResolution.getOngoingSLAData().getThresholdData().get().getRemainingTime().get()) / (1000*60) long remainingTimeMinLong = remainingTimeMin.round().longValue() if (remainingTimeMin < 0) // RemainingTime is negative { elapsedTime = elapsedTime.sum(goalMinutesPerPriorityOrUrgency(issueTypeName, priorityOrUrgency), remainingTimeMinLong.abs()) } else { elapsedTime = goalMinutesPerPriorityOrUrgency(issueTypeName, priorityOrUrgency).doubleValue() - remainingTimeMin } } return elapsedTime.round().toString() } } Hope it helps! Hector Flores

            Do you really think my bosses want to know a report with remaining times? Not at all. They need the Elapsed time to know real times spent in the issues.
            Thanks you!

            Hector Flores added a comment - Do you really think my bosses want to know a report with remaining times? Not at all. They need the Elapsed time to know real times spent in the issues. Thanks you!

            Hello Everyone,

            We saw that JSD reporting was limited, it was a real pain for a lot of people (including us) and Atlassian wasn't gonna fix it anytime soon. So we developed a custom report for JSD which gives you the ability to define custom datetime intervals, report on elapsed/remaining time and even export to excel. "Service Desk Reporter" is available on the marketplace today.

            You can get it from: https://marketplace.atlassian.com/plugins/tr.com.obss.jira.plugin.service-desk-reporter

            Have a good one...

            Emre Toptancı [OBSS] added a comment - Hello Everyone, We saw that JSD reporting was limited, it was a real pain for a lot of people (including us) and Atlassian wasn't gonna fix it anytime soon. So we developed a custom report for JSD which gives you the ability to define custom datetime intervals, report on elapsed/remaining time and even export to excel. "Service Desk Reporter" is available on the marketplace today. You can get it from: https://marketplace.atlassian.com/plugins/tr.com.obss.jira.plugin.service-desk-reporter Have a good one...

            Guys, please? Customer is asking for this.

            They claim they could do this with VertygoSLA, now they can't.

            Emre TOPTANCI added a comment - Guys, please? Customer is asking for this. They claim they could do this with VertygoSLA, now they can't.

              Unassigned Unassigned
              38754ddc40c7 angel
              Votes:
              118 Vote for this issue
              Watchers:
              67 Start watching this issue

                Created:
                Updated: