Hello,
I am displaying an Issue Matrix on the parent issue and would like to display the Sum total of all subtasks (custom field values for field name 'Total') in a custom field underneath the Issue Matrix on the parent issue in a field named 'Request Total'. Subtask field 'Total' is defined as a Number Field. And the parent Issue field 'Request Total' is defined as a Scripted Field using Template: Number Field.
I think I need to:
1) query the total number of Subtasks
2) get the value for each subtask 'Total' field and store in an array
3) add the values for each subtask 'Total' field (add array)
4) display the SUM of all 'Total' field values (SUM of array) in the 'Request Total' field on the parent Issue
Can anyone please help me get started with coding this. I am pretty new to JIRA and Groovy scripts, yet have experience, albeit dated experience, in C and VB.
I appreciate any help!
Thanks much,
Scott
Use this code for scripted field:
import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.fields.CustomField //return number subtasks issue.getSubTaskObjects().size() CustomField total = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Total") double totalSum = 0; for(Issue subtask: issue.getSubTaskObjects()){ if(subtask.getCustomFieldValue(total) != null) totalSum += subtask.getCustomFieldValue(total) } return totalSum
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Sometimes these warnings are not correct. It is better to use IDE. I use IDEA to write code.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello, how do you deal with the case when fields in subtasks are updated? How do you ask the parent issue to update its total sum?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Kelly, hi!
Try this script:
import com.atlassian.jira.issue.Issue
long totalSum = 0;
for(Issue subtask: issue.getSubTaskObjects()){
if(subtask.getCustomFieldValue(total) != null)
totalSum += subtask.getEstimate()
}
return totalSum / (1000 * 60) //return result in hours
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Thanks for the super fast response and script! I apologize if I'm making a completely amateur mistake, but it's not working in the preview (returning several errors and a "null" when I know it shouldn't be). I've attached a screenshot that shows the errors. Any pointers?
I assume "total" is referring to the field I'm creating, but I've renamed it in various combinations and can't figure it out :(
Thank you for any additional help! This bit of automation will save our team lots of time.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Actually nevermind, I figured out a way to make it work like so, returning minutes:
import com.atlassian.jira.issue.Issue
long totalSum = 0;
for(Issue subtask: issue.getSubTaskObjects()){
if(subtask.getEstimate() != null)
totalSum += subtask.getEstimate()
}
return totalSum / 60
Thank you again for your help!!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
FWIW for future folks: I ended up tweaking the code so it now adds remaining estimates of all the subtasks as well as the remaining estimate on the story level ticket, or returns null if neither story nor subtasks have estimates. Final code below:
import com.atlassian.jira.issue.Issue
long totalSum = 0;
boolean noEstimates = true;
def totalSubTasks = issue.getSubTaskObjects().size()
for(Issue subtask: issue.getSubTaskObjects()){
if(subtask.getEstimate() != null){
totalSum += subtask.getEstimate()
noEstimates = false
}
}
if (issue.getEstimate() != null){
totalSum += issue.getEstimate()
noEstimates = false
}
if (noEstimates == true){
return null
}
else {
return totalSum / 60
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi folks,
I think I'm trying to do a similar thing, but I need the value I'm pulling to be the remaining time estimate. I know JIRA does this automatically on the parent issues but I need that "remaining sum" value in an explicit field so I can export those values to our project management tool.
Basically, I need a scripted field that adds up the remaining time estimates of the subtasks.
I'm not a developer and I can't figure out how to adjust this script to make this work - any help would be very appreciated!
Thanks,
Kelly
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hey Nic,
Thank you so much for your response. I did not pursue your answer as Vasily's answer works. Yet I do thank you!
Scott
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
His code is much better than mine (as usual), but does the same thing in much the same way.
Did you pick up the bit about causing the parent issue to re-index?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I may be wrong but I think that in this case it may not be an issue. The project only has one issue type (IT Sourcing Intake Request Form) and a subtask (IT Sourcing Intake Request Form Subtask). Create only provides the IT Sourcing Intake Request Form as an option. Users will be trained to create subtask to represent orders under the parent issue (requisition). As of now the scripted field is only displayed on the View Issue intake form, as I thought if I placed it there it would force the field to trigger. So far in my testing when I update a subtask, the view issue screen updates the Total. I'll keep pocking at it. Thanks again! -Scott
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Ok, it's a good starting idea, the principles are right, but I would approach it slightly differently
Scripted fields run code and display the result. When we're looking at doing this, let's start with the issue you're going to display it on. Groovy lets you get into the JIRA API, so you can use that directly.
Specifically, let's assume you have the issue object for the issue you're going to display the field on.
You can bypass most of your steps very easily:
def listOfSubtasks = issue.getSubTaskObjects ()
Then grab the values you want:
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def totalField = customFieldManager.getCustomFieldObjectByName(
"Total"
)
listOfSubtasks.each {
if
(it.getCustomFieldValue(totalField))
result
+= (
double
) it.getCustomFieldValue(totalField)
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi @Nic Brough -Adaptavist- , I have the same re-indexing issue.
Can you please help me with re-indexing the parent issue if one custom field is updated on subtask.
I found this code but it seems to be not working in script runner listener.
public class IssueModifiedListener implements InitializingBean, DisposableBean {
private static final Logger log = Logger.getLogger(IssueModifiedListener.class);
private final EventPublisher eventPublisher;
private final IssueIndexManager issueIndexManager;
/**
* Constructor.
* @param eventPublisher injected {@code EventPublisher} implementation.
*/
public IssueModifiedListener(EventPublisher eventPublisher, IssueIndexManager issueIndexManager) {
this.eventPublisher = eventPublisher;
this.issueIndexManager = issueIndexManager;
}
/**
* Called when the plugin has been enabled.
* @throws Exception
*/
@Override
public void afterPropertiesSet() throws Exception {
// register ourselves with the EventPublisher
eventPublisher.register(this);
}
/**
* Called when the plugin is being disabled or removed.
* @throws Exception
*/
@Override
public void destroy() throws Exception {
// unregister ourselves with the EventPublisher
eventPublisher.unregister(this);
}
/**
* Receives any {@code IssueEvent}s sent by JIRA.
* @param issueEvent the IssueEvent passed to us
*/
@EventListener
public void onIssueEvent(IssueEvent issueEvent) {
Long eventTypeId = issueEvent.getEventTypeId();
Issue issue = issueEvent.getIssue();
Issue parent = issue.getParentObject();
if( parent != null ) {
reindexIssue( parent );
}
}
/**
* Called a parent issue is found that needs to be reindexed.
* @param issue The issue to be reindexed
*/
private void reindexIssue(Issue issue) {
try {
boolean origVal = ImportUtils.isIndexIssues();
ImportUtils.setIndexIssues(true);
issueIndexManager.reIndex(issue);
ImportUtils.setIndexIssues(origVal);
} catch (IndexException ie) {
log.error("Unable to reindex issue: " + issue.getString("key")
+ ", [id=" + issue.getLong("id") + "].", ie);
}
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Online forums and learning are now in one easy-to-use experience.
By continuing, you accept the updated Community Terms of Use and acknowledge the Privacy Policy. Your public name, photo, and achievements may be publicly visible and available in search engines.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.