The Atlassian Community Forums are currently in read-only mode. We will be relaunching on a new platform on September 22 (read more here). We apologize for the extended downtime. For concerns or questions, please email communitymanagers@atlassian.com. See you on the other side, on the new Atlassian Community Forums! :)

×

Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
  • Community
  • Q&A
  • Jira
  • Questions
  • Change custom field based on multiple select fields in ScriptRunner, e.g. calculating the average

Change custom field based on multiple select fields in ScriptRunner, e.g. calculating the average

Cory Strope
May 13, 2021

I am trying to recalculate the average value whenever one of the numbers change. I believe this is possible using behaviors for each value, but there will be hundreds of such fields. As an example, I have attempted to put together this behavior in a Scriptrunner 6.20.0 custom scripted field:

-----

import com.atlassian.jira.component.ComponentAccessor

def customFieldManager = ComponentAccessor.getCustomFieldManager()

def M1_nacc = customFieldManager.getCustomFieldObjectsByName("mon.M1.nacc")
def M1_conf = customFieldManager.getCustomFieldObjectsByName("mon.M1.conf")
def M2_nacc = customFieldManager.getCustomFieldObjectsByName("mon.M2.nacc")
def M2_conf = customFieldManager.getCustomFieldObjectsByName("mon.M2.conf")
def M3_nacc = customFieldManager.getCustomFieldObjectsByName("mon.M3.nacc")
def M3_conf = customFieldManager.getCustomFieldObjectsByName("mon.M3.conf")

static float metric_score (nacc, conf) {
if (nacc == "Unacceptable") { return 4.0 as float }
if (conf == "High") { return 1.0 as float }
if (conf == "Medium") { return 2.0 as float }
return 3.0 as float
}

def conf = 0
def acc = 0
if (M1_nacc != "N/A") { acc += 1; conf += metric_score (M1_nacc, M1_conf) }
if (M2_nacc != "N/A") { acc += 1; conf += metric_score (M2_nacc, M2_conf) }
if (M3_nacc != "N/A") { acc += 1; conf += metric_score (M3_nacc, M3_conf) }

if (acc == 0) return 0
return (conf / acc)

----

Here, the *_nacc field controls whether the *_conf field is calculated. if:
*_nacc = "N/A" --> ignore in calculation of average
*_nacc = "Unacceptable" --> value returned is 4
*_nacc = "Acceptable" --> use conf field value for average value calculation

The above script is simplistic, but it does calculate the appropriate value *the first time*. Any changes that occur later do not affect the returned value. What I would like to do is to capture each change to the nacc and conf values to modify the average value.

In the worst case scenario, this could be done on transition, but I would like to avoid that path.

Thanks!

1 answer

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

1 vote
Answer accepted
PD Sheehan
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Champions.
May 13, 2021

To implement this as a behaviour, you would want to assign the same behaviour script to each field.  That might be tedious, but by using a script file and pointing each field to the same file, at least you would have a central place to maintain the file.

Here is my attempt at reverse engineer your logic a best as I understood in a way that should be relatively easy to expand and adjust

def fieldPrefix = 'mon'
def fieldIdList = ['M1','M2','M3'] //add as many fields as you need
def confScoreMap = [High:1F, Medium: 2F]
def naccScoreMap = ['Unacceptable':4F, 'Acceptable':3F] //used for default values
def scores =[]
fieldIdList.each{
def naccField = getFieldByName("${fieldPrefix}.${it}.nacc")
def confField = getFieldByName("${fieldPrefix}.${it}.conf")
def nacc = naccField.value
def conf = confField.value
switch(nacc){
case 'Unacceptable':
scores << naccScoreMap[nacc]
break
case 'Acceptable':
scores << confScoreMap[conf] ?: naccScoreMap[nacc] //default to 3 if value not found in map
break
}
}
def total = scores.sum() as Float
def average = total/scores.size()
getFieldByName('average result field').setReadOnly(true).setFormValue(average)
Cory Strope
May 14, 2021

This is a great reverse engineer! Though it may be slightly tedious to add the behavior to all .nacc and .conf fields, it us much less tedious than cluttering the behaviors in scriptrunner with > 150 specific behaviors.

Thanks!