Hello,
I am developing a piece of code to take three inputs. This is then applied to a listener that looks at "Issue Created" or "Issue Updated" events.
The inputs are as follows:
Original Estimate (from the time tracking field)
Impact (Dropdown list with options "Low" and "High")
Severity (Dropdown list with three options "Minor", "Major" and "Critical")
The output is as follows:
Revised Estimate (Text (Single Line)).
What I want it to do:
Takes original estimate
Depending on value of Impact and Severity - Apply a frig factor
Output Estimate + impact and Severity hours to a field called "Revised Estimate"
What I've got working:
Original estimate is captured and then converted to a string (By changing the seconds value of Original estimate into h,m,d,m,y format). This works on its own. Yes I probably did this quite inefficently... But its the only way I could work out how to get this to work on one coffee
.
What I can't get to work:
Impact and Severity fields applying the frig factor and add them to "Revised Estimate"
I have pasted my code below. Please bear in mind, I am relatively inexperienced with Scriptrunner.
import com.atlassian.jira.component.ComponentAccessor
import org.apache.log4j.Logger
def log = Logger.getLogger("com.onresolve.scriptrunner.canned.jira.workflow.listeners.CustomListener")
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def originalEstimateField = customFieldManager.getCustomFieldObjectByName('Original Estimate')
def revisedEstimateField = customFieldManager.getCustomFieldObjectByName('Revised Estimate')
def impactField = customFieldManager.getCustomFieldObjectByName('Impact')
def severityField = customFieldManager.getCustomFieldObjectByName('Severity')
def originalEstimate = event.issue.getOriginalEstimate() // Original Estimate in seconds
def revisedEstimateStr = event.issue.getCustomFieldValue(revisedEstimateField) as String
def impactOption = event.issue.getCustomFieldValue(impactField)
def severityOption = event.issue.getCustomFieldValue(severityField)
log.info("Original Estimate: ${originalEstimate}")
log.info("Revised Estimate (String): ${revisedEstimateStr}")
log.info("Impact Option: ${impactOption}")
log.info("Severity Option: ${severityOption}")
// Extract the actual values from the options
def impact = impactOption ? impactOption.getValue() : null
def severity = severityOption ? severityOption.getValue() : null
log.info("Impact: ${impact}")
log.info("Severity: ${severity}")
// Convert revised estimate string to numeric value (seconds)
def revisedEstimate = revisedEstimateStr ? revisedEstimateStr.toDouble() : 0
log.info("Revised Estimate (Numeric): ${revisedEstimate}")
// Ensure original estimate is not null
if (originalEstimate != null && impact != null && severity != null) {
def impactCoefficient = 1.6
def severityCoefficient = 2.4
def additionalEstimate = (impactCoefficient * impact.toInteger() + severityCoefficient * severity.toInteger()) * 3600 // Convert hours to seconds
def newRevisedEstimate = originalEstimate + additionalEstimate
log.info("New Revised Estimate: ${newRevisedEstimate}")
def issueManager = ComponentAccessor.getIssueManager()
def mutableIssue = issueManager.getIssueObject(event.issue.id)
mutableIssue.setCustomFieldValue(revisedEstimateField, formatTime(newRevisedEstimate))
issueManager.updateIssue(event.user, mutableIssue, com.atlassian.jira.event.type.EventDispatchOption.DO_NOT_DISPATCH, false)
// Log the updated value
def updatedRevisedEstimateStr = mutableIssue.getCustomFieldValue(revisedEstimateField) as String
log.info("Updated Revised Estimate (String): ${updatedRevisedEstimateStr}")
} else {
log.warn("Original Estimate is null: ${originalEstimate == null}")
log.warn("Impact is null: ${impact == null}")
log.warn("Severity is null: ${severity == null}")
}
// Helper function to format time in seconds to human-readable format
def formatTime(seconds) {
def units = [
[unit: 'y', value: 60 * 60 * 24 * 365],
[unit: 'm', value: 60 * 60 * 24 * 30],
[unit: 'd', value: 60 * 60 * 24],
[unit: 'h', value: 60 * 60],
[unit: 'm', value: 60]
]
def result = []
def remainingSeconds = seconds
units.each { unit ->
def unitValue = (remainingSeconds / unit.value).intValue()
if (unitValue > 0) {
result << "${unitValue}${unit.unit}"
remainingSeconds -= unitValue * unit.value
}
}
if (remainingSeconds > 0) {
result << "${remainingSeconds}s"
}
return result.join(' ')
}Test Case:
Ticket created and Original Estimate is added (2hrs).
Ticket then processed through the workflow until "Impact" and "Severity" fields need to be set.
Result:
Remaining Estimate remains at "none"
What to the logs say:
2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Original Estimate is null: false
2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Impact is null: true
2025-03-26T17:39:46,348 WARN [listeners.CustomListener]: Severity is null: true
The script is clearly ignoring the "Impact" and "Severity" fields.
Any help would be appreciated.
Thanks