Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Celebration

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,501,434
Community Members
 
Community Events
180
Community Groups

Scriptrunner post function: Search for highest number in custom fields and set the next higher number on current issue

Dear atlassian community,


I got a custom field (text) named "Invoice Number" containing a number. The field should be filled on a certain workflow transition (post function). I need to get the highest previously used number so far in other issues of the same JIRA project and increase the invoice number of the current issue by 1.

Background: The idea is to generate some sort of sequential invoice number.

That's what I came up with so far. The first part that searches for the highest used invoice number works fine in script console, but when I add this script as a post function I get the following error:

Property 'results' not found
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.ComponentManager
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.CustomFieldManager
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.ModifiedValue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.issue.util.DefaultIssueChangeHolder;


def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchProvider = ComponentAccessor.getComponent(SearchProvider)
def issueManager = ComponentAccessor.getIssueManager()
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()

// get all the used invoice numbers so far
def query = jqlQueryParser.parseQuery("project = SJ AND 'Invoice Number' is not EMPTY ORDER BY 'Invoice Number' DESC")
def results = searchProvider.search(query, user, PagerFilter.getUnlimitedFilter())
def i = 0
int newInvoiceNumber = 0

// get the highest used invoice number
results.getIssues().each {
    documentIssue ->
    if (i == 0){
        def issue = issueManager.getIssueObject(documentIssue.id)
        def customFieldManager = ComponentAccessor.getCustomFieldManager()
        CustomField cField = customFieldManager.getCustomFieldObjectByName("Invoice Number")
        int oldInvoiceNumber = issue.getCustomFieldValue(cField) as Integer
        // get the new invoice number
        newInvoiceNumber = ++oldInvoiceNumber
    }
    i++
}


// set the new invoice number
def customFieldManager = ComponentAccessor.getCustomFieldManager()
def tgtField = customFieldManager.getCustomFieldObjects(issue).find {it.name == "Invoice Number"}
DefaultIssueChangeHolder issueChangeHolder = new DefaultIssueChangeHolder();
tgtField.updateValue(null, issue, new ModifiedValue(issue.getCustomFieldValue(tgtField), newInvoiceNumber),issueChangeHolder)

Do you guys have any ideas?
Thank you in advance, and kind regards!



2 answers

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

2 votes
JamieA Rising Star Mar 28, 2017

I've refactored as well, below. I think the above scripts are confusing the issues coming from the query with the issue involved in the transition.

Also you don't need an unlimited pager, if you are sorting by invoice number desc, then you only need the top one.

Note this will only work in a workflow function, not script console, as in script console there is no bound variable "issue".

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider
import org.apache.log4j.Logger

MutableIssue issue //predifined variable into a script postfunction

def log = Logger.getLogger("com.springtime.CustomScripts")

// get all the used invoice numbers so far
def query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery("project = SJ AND 'Invoice Number' is not EMPTY ORDER BY 'Invoice Number' DESC")
def results = ComponentAccessor.getComponent(SearchProvider).search(
    query,
    ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(),
    new PagerFilter(1))

int maxInvoiceNumber = 0
CustomField cField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Invoice Number")

// get the highest used invoice number
for(Issue documentIssue: results.getIssues()) {
    maxInvoiceNumber = documentIssue.getCustomFieldValue(cField) as Integer
}
// set the new invoice number
issue.setCustomFieldValue(cField, maxInvoiceNumber + 1)

Hi Jamie,

thanks for your input. Just the last part "setCustomFieldValue" doesn't work yet. Seems like the issue is null:

java.lang.NullPointerException: Cannot invoke method setCustomFieldValue() on null object
JamieA Rising Star Mar 28, 2017

You need to remove this line:

MutableIssue issue //predifined variable into a script postfunction


It's masking the actual variable passed to the script, or you can look at it as if it's redefinining it to null.

Hi Jamie, thanks I had to make one final addition. This is the working code now:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider


// get all the used invoice numbers so far
def query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery("project = SJ AND 'Invoice Number' is not EMPTY ORDER BY 'Invoice Number' DESC")
def results = ComponentAccessor.getComponent(SearchProvider).search(query,ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(),new PagerFilter(1))
int maxInvoiceNumber = 0
CustomField cField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Invoice Number")


// get the highest used invoice number
for(Issue documentIssue: results.getIssues()) {
    maxInvoiceNumber = documentIssue.getCustomFieldValue(cField) as Integer
}


// set the new invoice number
def newInvoiceNumber = ++maxInvoiceNumber as String
issue.setCustomFieldValue(cField, newInvoiceNumber)

I believe it's possible for this solution to assign duplicate invoice numbers if for some reason the JIRA indexer is running slowly. JQL queries use the indexed field values to perform the search. If a new invoice issue hasn't been indexed, it will not be returned by the query, allowing a duplicate to be assigned.

Even if the indexer is running normally, it could assign a duplicate invoice numbers if two invoices are needed within milliseconds of each other.

JamieA Rising Star Mar 30, 2017

Have you seen that happen? If so you could use a PropertySet on the current project, that retrieves and updates the counter more or less atomically.

Tarun Sapra Community Leader Mar 31, 2017

I also think that this approach doesn't guarantee thread safety, as in there can be race condition. I didn't know about "PropertySet" , would look into it.

Jamie,

I have seen the indexer be behind enough to causes problems for a plugin using JQL for similar purposes. It doesn't happen often, but should be allowed for. Changing the script to use a PropertySet is safer.

JamieA Rising Star Mar 31, 2017

If you just want a monotonically increasing number, how about just using the issue's id (issue.id) ? Or do you want a number that represents the actual number of invoices?

0 votes

I refactored your script

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider

MutableIssue issue //predifined variable into a script postfunction

def log = Logger.getLogger("com.springtime.CustomScripts")

// get all the used invoice numbers so far
def query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery("project = SJ AND 'Invoice Number' is not EMPTY ORDER BY 'Invoice Number' DESC")
def results = ComponentAccessor.getComponent(SearchProvider).search(
        query,
        ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(), 
        PagerFilter.getUnlimitedFilter())

int maxInvoiceNumber = 0
int curInvoiceNumber;
CustomField cField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Invoice Number")

// get the highest used invoice number
for(Issue documentIssue: results.getIssues()) {
    curInvoiceNumber = issue.getCustomFieldValue(cField)
    if(curInvoiceNumber > maxInvoiceNumber)
        maxInvoiceNumber = curInvoiceNumber
}
// set the new invoice number
issue.setCustomFieldValue(cField, maxInvoiceNumber + 1)

Hello, thank you for your effort.

The mentioned error is now gone, but another error occurs:

java.lang.NullPointerException: Cannot invoke method getCustomFieldValue() on null object

Further the new number is not added to the custom field.

Here you are

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.issue.fields.CustomField
import com.atlassian.jira.issue.Issue
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.issue.search.SearchProvider
 
MutableIssue issue //predifined variable into a script postfunction
 
def log = Logger.getLogger("com.springtime.CustomScripts")
 
// get all the used invoice numbers so far
def query = ComponentAccessor.getComponent(JqlQueryParser).parseQuery("project = SJ AND 'Invoice Number' is not EMPTY ORDER BY 'Invoice Number' DESC")
def results = ComponentAccessor.getComponent(SearchProvider).search(
                query,
                ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser(),
                PagerFilter.getUnlimitedFilter())
 
int maxInvoiceNumber = 0
int curInvoiceNumber;
CustomField cField = ComponentAccessor.getCustomFieldManager().getCustomFieldObjectByName("Invoice Number")
 
// get the highest used invoice number
for(Issue documentIssue: results.getIssues()) {
        curInvoiceNumber = documentIssue.getCustomFieldValue(cField)
        if(curInvoiceNumber > maxInvoiceNumber)
            maxInvoiceNumber = curInvoiceNumber
}
// set the new invoice number
issue.setCustomFieldValue(cField, maxInvoiceNumber + 1)
Like Florian Reichl likes this
TAGS
AUG Leaders

Atlassian Community Events