Child pages
  • JIRA Misc Custom Fields
Skip to end of metadata
Go to start of metadata



Getting help

Please visit our Support Page for more information.

Overview

The JIRA Misc Custom Fields plugin's objective is to provide several new types of custom fields for use in custom JIRA workflows as well as useful JQL functions.

Included custom fields:

  • Calculated Number Field : a calculated custom field returning a number (integer or float). It is a read-only field that returns the result of the evaluation of a formula, such as the addition of two other fields.
  • Calculated Text Field (new in 1.5.5): a calculated custom field returning a String. It is a read-only field that returns the result of the evaluation of a formula, such as the concatenation of two other fields.
    • Exact Text Searcher (Statistics-compatible) (new in 1.5.6): a custom searcher that allows calculated text fields to be used in statistics gadgets
  • Calculated Date/Time Field (new in 1.5.5): a calculated custom field returning a java.util.Date (which represents a date+time). It is a read-only field that returns the result of the evaluation of a formula.
  • Transition Date/Time Field (new in 1.2): a calculated custom field returning the date and time of the last execution of a specified workflow transition.
  • Transition Caller Field (new in 1.2): a calculated custom field returning the caller of the last execution of a specified workflow transition.
  • Transition Count Field (new in 1.5.11): a calculated custom field returning the number of times a specified workflow transition was executed.
  • Last Field Value Change Date/Time Field (new in 1.6): a calculated custom field returning the date and time a field was last modified.
  • Last Field Value Change Author Field (new in 1.6.5/1.7.2): a calculated custom field returning the author of the last modification made to a field.
  • Parent Status Field (new in 1.2.2): a calculated custom field returning the Status of the issue's parent issue.

Included JQL function:

  • currentUserPropertyAsList (new in 1.1): a JQL function that returns the value of a property of the current user, transforming comma-separated values into a list of values.

Installation

The plugin is a "type TWO" plugin, which means that the plugin can be installed by copying it to jira-home/plugins/installed-plugins or, better yet, using the excellent Atlassian Universal Plugin Manager.


Usage


Using calculated fields on large servers

If you are using complicated (like recursive) formulas in calculate custom fields, and you are running on a large server, you might need to tune JMCF's thread pool as documented in JMCF-173.

Calculated Number Field

  1. Create a new custom field, choosing "Calculated Number Field" for its type.
  2. During step 2, in the Description field, include the calculation formula using the syntax described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Formula syntax

The formula is written using the BeanShell language, and should be included in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @@Formula: (note the colon at the end). For example:

<!-- @@Formula: formula goes here -->

You can naturally include the real description of the custom field as well. For example:

This field represents the number of Affected Versions.
<!-- @@Formula: issue.get("versions").size() -->

The formula itself is a Java-style expression that can reference any issue field value, include arithmetic operators as well as any other Java operator, and Java method calls (such as the .size() example above). Access to issue field values is achieved by the following syntax:

issue.get("<field_ID_or_Name>")

where <field_ID_or_Name> is either a built-in JIRA or custom field ID (the latter in the form customfield_nnnnn), or a field name. See this page for details.

You can also access the JIRA Issue object using the issueObject variable.

To identify the custom field ID:

  1. go to Administration/Custom Fields
  2. click on the "Configure" link for the custom field you're interested in
  3. in the URL of the Configure Custom Field page, note the number after "customFieldId=" and append it to "customfield_" to build the custom field ID

Note that you must make sure the formula returns a number, or null.

Debugging the script

If the calculated field does not show up on the view issue screen, you must make sure the formula isn't raising an error. For that, you must look at the end of the JIRA log file (atliassian-jira.log) right after displaying the issue (displaying an issue will always force calculated fields to be re-calculated).

You can also include logging code into your script using the "log" object. For example:

<!-- @@Formula: 
log.error("Value of field 10114 is: "+issue.get("customfield_10114"));
log.error("Value of field 10150 is: "+issue.get("customfield_10150"));

if (issue.get("customfield_10114") == null || issue.get("customfield_10150") == null)
    return null;
 
return issue.get("customfield_10114") + issue.get("customfield_10150");   //we already made sure neither field is empty (==null) 
-->

We recommend you write to the logs using the "log.error()" method because ERROR-level logs are always written out to atlassian-jira.log (whereas DEBUG-level logs are filtered out by default).

Example
Adding two fields

To add two custom fields, such as "Business Value" and "Technical Value" to get an "Overall Value":

<!-- @@Formula: (issue.get("customfield_10114") != null ? issue.get("customfield_10114") : 0) + (issue.get("customfield_10150") != null ? issue.get("customfield_10150") : 0) -->
Custom formatting

You can also specify custom formatting for the value of the Calculated Number field. In the Description field, add your formatting formula using the following syntax:

<!-- @@Format: formula goes here -->

The formula itself is a Java-style expression that can reference the value returned by the formula using the value variable. You can also use the numberTool object to format the number value:

numberTool.format(value)
Example

To display an icon to the left of the field value depending on the field value:

<!-- @@Format:
if (value > 21)
  return "<img src='/images/icons/priority_trivial.gif'> "+numberTool.format(value);
else if (value >= 10)
  return "<img src='/images/icons/priority_major.gif'> "+numberTool.format(value);
else
  return "<img src='/images/icons/priority_blocker.gif'> "+numberTool.format(value);
 -->

Calculated Text Field (new in 1.5.5)

  1. Create a new custom field, choosing "Calculated Text Field" for its type.
  2. During step 2, in the Description field, include the calculation formula using the syntax described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Formula syntax

The formula is written using the BeanShell language, and should be included in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @@Formula: (note the colon at the end). See Calculated Number Field above for details.

Note that you must make sure the formula returns a String, or null.

Exact Text Searcher (Statistics-compatible) (new in 1.5.6)

When creating a Calculated Text Field, you can choose between the standard Free Text Searcher and the new Exact Text Searcher (Statistics-compatible). The latter should be used if you need either of the following:

  • Be able to search issues based on the exact value of the custom field (i.e. use the "=" operator instead of the "~" operator)
  • Be able to use the field in one of the statistics reports or dashboard gadgets


Calculated Date/Time Field (new in 1.5.5)

  1. Create a new custom field, choosing "Calculated Date/Time Field" for its type.
  2. During step 2, in the Description field, include the calculation formula using the syntax described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Formula syntax

The formula is written using the BeanShell language, and should be included in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @@Formula: (note the colon at the end). See Calculated Number Field above for details.

Note that you must make sure the formula returns a java.util.Date, or null.

Custom formatting

You can also specify a date/time format for the value of the Calculated Date/Time field. In the Description field, add the name of the date/time format using the following syntax:

<!-- @@Format: <format_name> -->

where <format_name> is one of the constants found here: https://developer.atlassian.com/static/javadoc/jira/reference/com/atlassian/jira/datetime/DateTimeStyle.html

Transition Date/Time Field

  1. Create a new custom field, choosing "Transition Date/Time Field" for its type.
  2. During step 2, in the Description field, include the transition ID(s) (recommended) or name as described below.
  3. Optionally, specify whether you want the first or last execution of the transition(s) (new in 1.2.5 and 1.5.2)
  4. Re-index your data, as JIRA will kindly suggest you to.
Indicating the transition

The transition(s) should be indicated in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @TransitionId: or @TransitionName: (note the colon at the end). For example:

<!-- @TransitionId: transition ID -->

or

<!-- @TransitionName: transition name -->

If you use @TransitionId, you can specify a list of transition IDs, separated by commas (new in 1.2.5 and 1.5.2):

<!-- @TransitionId: transition_ID_1,transition_ID_2 -->

You can naturally include the real description of the custom field as well. For example:

This field represents the date and time of the Resolution of this issue.
<!-- @TransitionId: 5 -->
<!-- @Execution: last -->
Specifying whether to capture the first or last transition execution

You can also specify whether to capture the first or last transition execution, using the @Execution: keyword followed by first or last. For example:

<!-- @Execution: first -->

If you don't specify anything, the last execution will be captured.

Transition Caller Field

  1. Create a new custom field, choosing "Transition Caller Field" for its type.
  2. During step 2, in the Description field, include the transition ID (recommended) or name as described below.
  3. Optionally, specify whether you want the first or last execution of the transition(s) (new in 1.2.5 and 1.5.2)
  4. Re-index your data, as JIRA will kindly suggest you to.
Indicating the transition

The transition(s) should be indicated in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @TransitionId: or @TransitionName: (note the colon at the end). For example:

<!-- @TransitionId: transition ID -->

or

<!-- @TransitionName: transition name -->

If you use @TransitionId, you can specify a list of transition IDs, separated by commas (new in 1.2.5 and 1.5.2):

<!-- @TransitionId: transition_ID_1,transition_ID_2 -->

You can naturally include the real description of the custom field as well. For example:

This field represents the Resolver of this issue.
<!-- @TransitionId: 5 -->
<!-- @Execution: last -->
Specifying whether to capture the first or last transition execution

You can also specify whether to capture the first or last transition execution, using the @Execution: keyword followed by first or last. For example:

<!-- @Execution: first -->

If you don't specify anything, the last execution will be captured.

Transition Count Field

  1. Create a new custom field, choosing "Transition Count Field" for its type.
  2. During step 2, in the Description field, include the transition ID (recommended) or name as described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Indicating the transition

The transition(s) should be indicated in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @TransitionId: or @TransitionName: (note the colon at the end). For example:

<!-- @TransitionId: transition ID -->

or

<!-- @TransitionName: transition name -->

If you use @TransitionId, you can specify a list of transition IDs, separated by commas (new in 1.2.5 and 1.5.2):

<!-- @TransitionId: transition_ID_1,transition_ID_2 -->

You can naturally include the real description of the custom field as well. For example:

This field represents the Resolver of this issue.
<!-- @TransitionId: 5 -->
<!-- @Execution: last -->

Last Field Value Change Date/Time Field (new in 1.6)

A date/time field that returns the last time a field's value was changed.

  1. Create a new custom field, choosing "Last Field Value Change Date/Time Field" for its type.
  2. During step 2, in the Description field, include the field name as described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Indicating the field

The field whose last modification date should be returned must be indicated in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @@Field:  (note the colon at the end). For example:

<!-- @@Field: <field-name> -->

The field name (indicated as <field-name> above) should be specified as it appears in the "history" tab, except for system fields for which the name should be as listed here.

You can naturally include the real description of the custom field as well. For example:

This field represents the date and time of the Resolution of this issue.
<!-- @@Field: summary -->
Custom formatting

You can also specify a date/time format for the value of the Calculated Date/Time field. In the Description field, add the name of the date/time format using the following syntax:

<!-- @@Format: <format_name> -->

where <format_name> is one of the constants found here: https://developer.atlassian.com/static/javadoc/jira/reference/com/atlassian/jira/datetime/DateTimeStyle.html

Last Field Value Change Author Field (new in 1.6.5/1.7.2)

A user field that returns the author of the last change made on a field.

  1. Create a new custom field, choosing "Last Field Value Change Author Field" for its type.
  2. During step 2, in the Description field, include the field name as described below.
  3. Re-index your data, as JIRA will kindly suggest you to.
Indicating the field

The field whose last modification author should be returned must be indicated in the field description inside an html comment (so that it remains invisible when showing the field description), preceded by the following keyword: @@Field:  (note the colon at the end). For example:

<!-- @@Field: <field-name> -->

The field name (indicated as <field-name> above) should be specified as it appears in the "history" tab, except for system fields for which the name should be as listed here.

You can naturally include the real description of the custom field as well. For example:

This field represents the date and time of the Resolution of this issue.
<!-- @@Field: summary -->

Parent Status Field

  1. Create a new custom field, choosing "Parent Status Field" for its type.
  2. Re-index your data, as JIRA will kindly suggest you to.

currentUserPropertyAsList JQL function

The currentUserPropertyAsList function can be used in a JQL query in an "in" or "not in" condition. It takes one parameter: the name of a user property.
When running the search query, the function will grab the value of the user property and treat it as a comma-separated list of values.

What use is it anyway?

This function is especially useful for building shared filters (and dashboards). You can, for example, create a standard filter that lists open issues for the current user's preferred projects, which you'll store in a user property:

resolution = Unresolved AND project in currentUserPropertyAsList("myProjects")



  • No labels

132 Comments

  1. Hello,

    Sound like a very interesting option.

    Unfortunately I could not get the Calculated Number FieldJIRA Misc Custom Fields(s) being shown in any screen.

    It's visible in Screen-configuration dialogs but not inside the issue (not in view mode nor in edit mode)

    Adding other customer fields immediately works. I'm running Jira 4.2, Plugin v1.1.1.

    Any ideas?

    Thanks a lot!

    BR, Markus

  2. Not any comment? Please!

    Regards,

    Markus

  3. Hello innovalog,

    I really do not want to bother you, but could you please check this issue.

    As I need to create this kind of functionality I would need to check other options; although your approach looks much smarter.

    BR, Markus

  4. Unfortunately not any reply.

    => OK. I'll check other options or implement this functionality myself.

    Regards, Markus

    PS: BTW the first gray box contains an error:

    <!-- @@Formula: formula goes here ->

    shall be

    <!-- @@Formula: formula goes here -->

    1. Unknown User (acox@webassign.net)

      MarkusL,

      Did you ever get this to work? I'm having the same problem.

      Thanks,

      Alan

  5. Hello Alan,

    unfortunately not.

    I'm not trying to use this plugin anymore...without any reaction from developers I just waste my time.

    That's really a pity as the functionality from paer-point-of-view really looks useful!

    BR,

     Markus

    1. Unknown User (matti.jurvanen@ambientia.fi)

      Hello everyone! I think you should go to https://studio.plugins.atlassian.com/browse/JMCF for issues with this plugin.

      I had the same problems and started wondering if the reason might be the same what I found from JMCF-5:

      "unfortunately, calculated fields are only shown on "view" screens, not "edit" or "transition" screens (because they are not editable).

  6. To Marcus and Alan: sorry I never reacted to you posts here, but because of a misconfiguration of the JMCF project in studio.plugins.atlassian.com, I did not receive any notification for your posts.

    In any case, please create issues instead of posting here, as indicated by Matti.

    David.

  7. David,

    I need to make the switch from the old plugin transition search plugin to this plugin:
    Is it correct to do these changes to change the existing fields ?
    (I cannot see the fields anymore in the new jira, since the fieldtype does not exist anymore)
    Also, is it correct that the field will not be used until you re-index ?
    The old plugin did work for new transitions, just not for the old ones.

    select 'com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetime','com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetimesearcher',
    ' <-\- @TransitionName: '\|\| description \|\| '-->'
    from jira.customfield
    where customfieldtypekey = 'de.phil.jira.plugin.searchhistory:searchtransitiondate'
    order by id desc
    
    select 'com.innovalog.jmcf.jira-misc-custom-fields:transitioncaller','com.innovalog.jmcf.jira-misc-custom-fields:transitioncallersearcher',
    ' <-\- @TransitionName: '\|\| description \|\| '-->'
    from jira.customfield
    where customfieldtypekey = 'de.phil.jira.plugin.searchhistory:searchtransitioncaller'
    order by id desc
    

    As this is not a bug, I did not make a ticket for it.

    1. This seems ok, although using transition names is not really recommended as it can be ambiguous.

      Also, pay attention to potential carriage returns at the end of the existing descriptions.

      And yes, you will need to reindex.

      David.

  8. I hope it can handle ambiguous transitions, since in the workflows we have multiple startingpoints that can lead to the same endpoint.

    For example:

    rejected --> closed
    handled --> closed

    In both case the transition-ids will be different, but since I'm interested when the issues was closed I call it by name, so it handles both transitions.
    This is what the old plugin could handle, can this one as well ?

    1. I don't believe the old plugin could handle this (I've checked the code), and neither can my plugin. If you have two transitions that have the same name, only the "first" one will be taken into account (whichever one is considered the first is beyond my control).

      You can create an enhancement request if you need to be able to recognize more than one transition in the same field (by ID or by name for that matter)

      David.

      1. In that case it'd be more accurate to request a change that the transition towards a specific status is logged, so not the transition is taken as input, but the targetstatus.

        Created JMCF-20

  9. Unknown User (charland)

    I'd like to use the calculated field to include the Time Spent on the issue in a calculation. what issue.get("???????") can I use to access the time spent on the issue?

    Thanks

    1. Did you try "timespent"?

  10. Hi,

    I had a question. Could this plugin handle calculating the age of a ticket? I'm looking for something that will look at the created date and today's date, and get the difference?  I know those aren't custom fields per se, but I was curious.

    1. Absolutely! You can use a formula such as:

      <!-- @@Formula: issue.get("created")==null ? null : ((new Date().getTime()) - issue.get("created").getTime()) / 1000 / 3600 / 24 -->

      You can even apply a custom format to display a warning icon next to "old" issues:

      <!-- @@Format:
      if (value > 21)
        return "<img src='/images/icons/priority_trivial.gif'> "+numberTool.format(value);
      else if (value >= 10)
      //  return "<span style='background-color:red;'><img src='/images/border/spacer.gif' border='0' width='16' height='16' alt=''></span>";
        return "<img src='/images/icons/priority_major.gif'> "+numberTool.format(value);
      else
        return "<img src='/images/icons/priority_blocker.gif'> "+numberTool.format(value);
       -->
      1. Thanks for the info. I'm guessing this might be user error on my part, but I am getting the following error thrown:

        Issue field "created" is not supported.?

        1. What version of JMCF are you using? 

          Can you try with JMCF version 1.2.3 (just released)?

          1. Thanks for the quick reply. Sadly, I am stuck with Jira 4.1.1 for the moment, which means I am using JMCF 1.12

  11. Unknown User (jhartwig)

    Hi,

    thanks for your great plugin. It helped me a couple of times.

    Unfortunatly I got stuck this time.

    I would like to retrieve a list of linked issues and sum up a custom field in them. Is this possible with your plugin?

    My first approach:

    <!-- @@Formula:
    
    int sumField( linkedIssues ) {
       int sum = 0;
    
       for(<ISSUE_TYPE> linkedIssue : linkedIssues)
          sum += linkedIssue.get("customfield_xxxxxx");
    
       return sum;
    }
    
    sumStoryPoints(issue.get("<LINKED_ISSUE_KEY>"));
    
    -->  
    

    I really dont know which values these two placeholder should have: <LINKED_ISSUE_KEY>, <ISSUE_TYPE> 

    EDIT:

    issue.get("issuelinks") returnr 0 even if the issue has 2 linked issues.

    "linkedIssues" and "outwardlinks" do not work as well.

    Thanks,

    Jens

    1. Well, I'm not sure this is feasible. Normally, issue.get("issuelinks") should return a collection of IssueLink objects, on each of which you can call getDestinationObject() to get the destination field.

      And issue.get("issuelinks").size() should return the number of links.

      But there is currently a bug preventing issue.get("issuelinks") from working. I've created an issue for that (JMCF-24) and will try to fix it today. Look for a tentative fix in a build I will reference in the issue.

      David

      1. I've checked, and you won't be able to do what you'd like to because you won't be able to access custom fields of the linked issues (because there is no "get" method on real Issue objects - issue.get() works only because "issue" is a wrapper around the real issue object).

        1. Unknown User (jhartwig)

          Hi David,

          thanks for your fast response. Your fix works very well!

          In fact with your help I solved my problem:

          <!-- @@Formula:
          
          import com.atlassian.jira.ComponentManager;
          import com.atlassian.jira.issue.fields.CustomField;
          import com.atlassian.jira.issue.CustomFieldManager;
          import com.atlassian.jira.issue.link.IssueLink;
          
          double sumCustomFieldValues( linkedIssues, customFieldId, linkTypeId ) {
           double sum = 0;
          
           CustomFieldManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager();
           CustomField customField = customFieldManager.getCustomFieldObject(customFieldId);
          
           for( int i = 0; i < linkedIssues.size(); i++ ){
          
              IssueLink link =  linkedIssues.get(i);
          
              if( link.getIssueLinkType().getId() == linkTypeId ){
                 Double customFieldValue = link.getDestinationObject().getCustomFieldValue(customField);
                 sum += (customFieldValue == null) ? 0 : customFieldValue;
              }
          
           }
          
          
           return sum;
          }
          
          sumCustomFieldValues(issue.get("issuelinks"), 10003, 10200);
          
          -->
          


          What it does: It sums up the specified custom field of the linked issues with a specified link type.

          Example:

            
          What you need to do is: Define the Story Points in the User Stories and add a Calculated Number Field in the Epic. Now link them (from Epic to Story). Add the above code in the custom fields description and replace the 2nd and 3rd parameters of the function call with the custom field id and the link type id.
          Jens

          1. Wow! Well done.

            I didn't realize you were a Java developer, in which case I would have added that you could indeed make it work - with some effort!

            Be careful though: Atlassian is deprecating the static "getInstance()" methods in favor of dependency injection (in the constructors for example), so I'm not sure your approach will continue to work in Jira 5.

            If it doesn't, please create an issue and I will inject the typical managers in the script context instead.

            In any case, thanks for sharing your implementation!

            David.

            1. Unknown User (benwfriedman)

              Jens & David - 

              This is terrific - exactly what I need!  I'm trying to implement this in JIRA 5 and having trouble. 

              It seems that issue.get("issuelinks") isn't returning anything even though there are items linked. Do you know if something has changed? 

              [ I'd actually rather just sum up all subtasks if that's easier? ]

              Thanks for any help!

              -Ben 

          2. Just want to thank you for this Jens, it was exactly what I needed (You too David...)  Took me a while to find the link type ID, but viewing the source of the issue page helped.

            1. Hello,

              The discussion thread is extremelly interesting as I also looking at a wait to aggregate the UserStory StoryPoints into their parent Epic.

              I have been using the code example, but still I cannot find the linktype id (I would like to use a "relates to" link).

              Any idea about the way to find this linktype id ?

              Thanks in advance for your support.

              JMi

              1. I found them by opening an issue that has links, viewing the source of the page, and searching for linkType  - you should see one for each link that is in the issue.  For example linkType=10001

                1. Thanks for the advice, I did not yet succedeed to make it work....I will continue to investigate. Now I have some iteration issues...:-) maybe because I am using Jira 5.0

                  1. Unknown User (benwfriedman)

                    Sounds like you may be having the same problem I'm having -- with JIRA 5.x and the exact code above, I cannot succesfully get the list of linked JIRAs to return.

                    Has anybody actually gotten this to work with JIRA 5.x, and, if so, did you have to change anything in the code example above?

                    Alternatively, if there was a way to return the list of all sub-tasks, that would work (for my purposes)

                    Thanks for any help at all!

                    -Ben

                    1. Unknown User (jhartwig)

                      Since my code seems to be deprecated I'll have look at it on friday or saturday. 

                      I'll keep you posted. 

                      Jens

                      1. Unknown User (benwfriedman)

                        Much appreciated - thank you!!

                        -Ben

                      2. Hello Jens,

                        I was looking for the progress you did about the update of the example proposed above.

                        Did you find a way to get rid of the getInstance() call and adpat your code to the latest Jira version ?

                        Thanks to also keep me posted.

                        JMi

                      3. Unknown User (benwfriedman)

                        Jens -

                        Any updates?

                        Thanks,

                        Ben

                        1. Unknown User (jhartwig)

                          Sorry, I got delayed by exams but I expect progress in the next days..

                          Jens

                          1. Unknown User (jbrody@messagebus.com)

                            Has any one been able to walk the issue link tree from an epic down.   We use the structure plugin to create our links epic -> feature -> task.   But as others have reported walking the links as described above does not seem to work in jira 5.x.    

                            1. Unknown User (benwfriedman)

                              I have not been able to make this work --

                              I simply cannot successfully get the list of linked (or child) JIRAs to return -- at all. 

                              Jens was going to look into it, but either hasn't had time or has had no success.

                              If anyone has gotten this to work in any way, would you please post you code?

                              -Ben

                              1. I've just been reading through this thread, and it is exactly what I need, however I am using JIRA 5.x too. =(

                                Did you ever manage to get this resolved / is there an update?

                                1. I will look into it. 

                                  But in any case you must realize that any calculated field that computes its value based on the values of other issues will not be kept up-to-date in the JIRA index. Therefore, while the value will be accurate in the "View Issue" screen, it will be inaccurate in the Issue Navigator and in search conditions (which both use the indexed value instead of re-computing the value on-the-fly).

                                  The reason is simple: the issue index is rebuilt every time the issue is modified, but not when linked issues are modified. Therefore, if, for example, you compute a sum of the Story Points of the issues linked to a "primary" issue (the one that has the calculated field), if the Story Points for one of these linked issues changes, it will not trigger a recompute of the primary issue's indexed values.

                                  David.

                                2. Have you tried something like:

                                  import com.atlassian.jira.component.ComponentAccessor
                                  import com.atlassian.jira.issue.Issue
                                  import com.atlassian.jira.issue.fields.CustomField;
                                  import com.atlassian.jira.issue.CustomFieldManager;
                                  import com.atlassian.jira.issue.link.IssueLink
                                  import com.atlassian.jira.issue.link.IssueLinkManager
                                  double sumCustomFieldValues( Issue issue, customFieldId, linkTypeId ) {
                                   double sum = 0;
                                   
                                   CustomFieldManager customFieldManager = ComponentAccessor.getCustomFieldManager();
                                   CustomField customField = customFieldManager.getCustomFieldObject(customFieldId);
                                    IssueLinkManager issueLinkManager = ComponentAccessor.getIssueLinkManager();
                                    for (IssueLink issueLink : issueLinkManager.getOutwardLinks(issue.getId())) {
                                      if( issueLink.getIssueLinkType().getId() == linkTypeId ){
                                         Double customFieldValue = link.getDestinationObject().getCustomFieldValue(customField);
                                         sum += (customFieldValue == null) ? 0 : customFieldValue;
                                      }
                                        
                                    }
                                   
                                   return sum;
                                  }
                                   
                                  sumCustomFieldValues(issueObject, 10003, 10200);
                                  
                                  

                                  Of course, you'll need to adapt it to your own use (especially the customFieldId and linkTypeId, as well as possibly replace getOutwardLinks with getInwardLinks).

                                  Also note that I have not tested it, so it might not compile, but you'll get the idea.

                                  1. Hi David Fischer

                                    Thanks for the code, please bare with me as I am not a developer.  I have used the code snippet above within a custom field for a Story, so that it sums up a custom field called TotalTests within the Story's sub tasks (which I've called Acceptance Criteria).  I believe the value for the TotalTests field is 10105 and the Type Id (for Acceptance Test?) is 9, therefore I have added those values to the sumCustomFieldValues call.

                                    Am I doing this correctly?  If so, nothing seems to happen - is there a way I can get hold of some compilation errors or something similar?

                                    Many thanks for your help 

                                    1. Hi David Fischer

                                      Have carried out a bit more research and we are almost there, the final issue we have came across is that the method .getIssueLinkType().getId() is returning the id of the project (i.e. 10100) and not the id of the issue type (the value in the <type /> field).

                                      How do we compare the issue type to filter only "Acceptance Criteria"?

                                      1. Unfortunately you've got it wrong. Sub-tasks are not linked issues. they are not accessible through the IssueLinkManager. And FYI getIssueLinkType().getId() returns the IssueLink type ID, which is totally unrelated to the Issue type.

                                        To get the list of sub-tasks, simply use issueObject.getSubTaskObjects()

  12. Unknown User (prophetshsu)

    Quick question, your documentation says to refer to 'http://docs.atlassian.com/jira/4.0/constant-values.html#com.atlassian.jira.jelly.tag.issue.AbstractCreateIssue.KEY_FIX_VERSIONS' to see what all issue.get() will return.  I can't get it to return most of the fields referenced in that document.  (or at the very least they're returning objects of a type I am not aware, it's certainly not an int or string)

    How can I get access to the "aggregatetimeoriginalestimate" or "timeoriginalestimate" field?

    I'm trying to create a field that will take the estimated hours and divide it by 6...  It seems like I'm close here.

    1. I'm afraid the short answer is: you can't. Indeed, some fields are not (yet) accessible using issue.get(). I try to add some fields from time to time, so they might be supported eventually, but not in the near future.

  13. Unknown User (d.zavernyaev)

    Your plugin is great!

    But I have one question. We need to count time that issue spend in Open status, before the Start Progress button was pressed for the first time.

    If I use <!- @TransitionId: 4 -> , it records the last time progress was started. But we need to count only the time before the first press. 

    Can you suggest something? 

    1. The simplest is to use a custom function in you Start Progress transition, and set your custom field value to now() if and only if it is empty. You can implement this using the Jira Scripting plugin.

      Otherwise, you could also create an Improvement request in our Jira, but I'm not sure when I'll be able to implement it.

      David

      1. Unknown User (d.zavernyaev)

        Thanks for your respond! 

  14. Hi ,

    I am looking for the implementation of calculation field using the select list field type.
    Ex: if two select lists with the values Low, Medium, High are present (string), We want to compare both the values and display the calculated result(numeric) in the Calculated custom field.

    Please provide an appropriate solution.

  15. Unknown User (steinja)

    Hi David.

    I think this plugin may help us solve our problem.  We need to have certain custom fields which are calculations based on transition dates.  I read your documentation, and I think I understand it.  First, I was hoping to add two transition date custom fields, and then add a calculated field which subtracted one from the other.

    So, in order to do that, I followed your instructions to add a custom field.  This is the result of my query of     select * from customfield where CUSTOMFIELDTYPEKEY="com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetime";

    '10531', 'com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetime', 'com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetimesearcher', 'Screening-Complete ', '<!- @TransitionId: 111 ->', NULL, NULL, NULL, NULL

    '10532', 'com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetime', 'com.innovalog.jmcf.jira-misc-custom-fields:transitiondatetimesearcher', 'Screening-Complete2', '<!- @TransitionId:-111>', NULL, NULL, NULL, NULL

    As you can see I've created two different custom fields, both pointing to the same TransitionID --> 111 - which is the "ID" of the step on the screen in parenthesis when you look at the Administration-Workflow View-View Workflow Steps.

    I'm not sure exactly how to put this comment into the description.  I was hoping that one of these would work.  Neither seem to be.  When I run the following query,   select * from OS_HISTORYSTEP where ACTION_ID="111" AND CALLER="Jason";

    '122123', '58948', '12', '111', '', '2012-03-28 16:57:22', NULL, '2012-03-28 16:57:48', 'Not Done', 'jason'
    '122130', '58949', '12', '111', '', '2012-03-28 17:33:26', NULL, '2012-03-28 17:33:41', 'Not Done', 'jason'
    '122135', '58950', '12', '111', '', '2012-03-28 17:39:31', NULL, '2012-03-28 17:39:45', 'Not Done', 'jason'
    '122139', '58951', '12', '111', '', '2012-03-28 17:52:26', NULL, '2012-03-28 17:52:43', 'Not Done', 'jason'
    '122144', '58952', '12', '111', '', '2012-03-28 17:56:42', NULL, '2012-03-28 17:56:57', 'Not Done', 'jason'
    '122149', '58953', '12', '111', '', '2012-03-28 18:49:44', NULL, '2012-03-28 18:49:50', 'Not Done', 'jason'
    '122154', '58954', '12', '111', '', '2012-03-28 18:54:11', NULL, '2012-03-28 18:54:21', 'Not Done', 'jason'

    I did try this test 7 times, so I know that I'm testing this correctly, but when I run the query,    select * from customfieldvalue where CUSTOMFIELD="10531";

    I get nothing.  (When I change that to CUSTOMFIELD="10532", I also get nothing.)

    What am I doing wrong?  Oh, and by the way, I've re-indexed probably 20 times at this point.

    1. Unknown User (steinja)

      I see that this comment which is probably the most important part of my post - is automatically being "struck-through".  Therefore, I'm writing it differently. 

      The first line reads, '<!- @TransitionId: 111 ->'    Less than Exclamation dash dash space @TransitionId: space 111 space dash dash Greater than

      The second line reads, '<!- @TransitionId:-111>'   Less than Exclamation dash dash space @TransitionId:dash 111 dash Greater than

      1. Well, this custom field is what Jira calls a "CalculatedCFType", i.e. a calculated custom field. This means that its value is not stored but computed every time it is accessed (because its value can change arbitrarily without explicitly setting it).

        Therefore, you will never see its value in the customfieldvalue table.

        1. Unknown User (steinja)

          David, thank you for your quick reply.  I have a few follow up questions:

          1.  Which one of my descriptions/comments for this formula was correct?  or were they both correct?

          2. If it's not stored but computed every time, how do I know that the correct value is in it?  Can I view it on a screen?

          Thanks.

          1. The correct syntax is:

            <!-- @TransitionId: 111 -->

            And of course the way you can check its value is by displaying it on a screen.

            1. Unknown User (steinja)

              Thank you very much, David.  I'll let you know when I'm successful.

  16. Unknown User (brian)

    I'm a bit confused... with the calculated number field, do you only support addition, and not multiplication?

    1. Unknown User (brian)

      Specifically, this is not working:
      <!-- @@Formula:
      ( issue.get("customfield_10000") != null ? issue.get("customfield_10000") : 1 ) *
      ( issue.get("customfield_10001") != null ? issue.get("customfield_10001") : 1 )
      -->
      Changing the '*' to a '+' causes addition to work fine, but the field doesn't show up if the multiplication (star) is used.

      1. No, all operators should work fine. I know for a fact that division works fine, but I haven't tried multiplication yet. If it doesn't work, I'm afraid there isn't much I can do. But you can create a Jira issue and I'll look into it.

        David.

        1. Unknown User (brian)

          Hi David, thank you for the swift reply!

          I tried operators +, -, /, *, and only + seemed to work.  The custom fields themselves are select lists, but the values are purely numeric (3, 5).  None of the operators besides + seemed to work however.  Even with the + operator, the calculated field concatenated the values, and didn't add them. 

          After checking into the log, it appeared the items were being treated as objects, and not numeric Integers/Floats/Doubles.  Here's a copy of the error received in the log file:

          \[innovalog.jmcf.fields.CalculatedNumberField\] CalculatedNumberField: error evaluating formula: Sourced file: <Inline eval of:&nbsp; &nbsp;
          ( issue.get("customfield_10000") \!= null ? issue.get("customfield_10000") : 1 ) -
          ( issue.get("customfield_10001") \!= null ? issue.get("customfield_10001") : 1 ) &nbsp;
          ; > : Operator: '"-"' inappropriate for objects
          
          

          Not sure what was special, but was able to fix with this:

          <!-- @@Formula:  
          (issue.get("customfield_10000") != null ? Integer.parseInt(issue.get("customfield_10000").toString()) : 1 ) *
          (issue.get("customfield_10001") != null ? Integer.parseInt(issue.get("customfield_10001").toString()) : 1 )
          -->

          1. Well, the reason is simple: the value of a custom field of type Select list is not a String or an Integer but an Object of type Option (if I remember correctly), on which you can call getValue() or toString() to get the value.

            David.

  17. Unknown User (mlehky)

    First I am not a java developer, but i understand the general concepts.  I am trying to create a fairly simply calculated field field that is based on the Priority Field and a Multi Check Box custom field.

    As a first step i am trying to do the points based on the priority using;

    <!-- @@Formula: (issue.get("priority") = "Level 1" ? 100 : 0) + (issue.get("priority") = "Level 3" ? 90 : 0) + (issue.get("priority") = "Level 3" ? 30 : 0) + (issue.get("priority") = "Level 4" ? 10 : 0) + (issue.get("priority") = "Level 5" ? 0 : 0) -->
    

    I'm unclear if the results of issue.get("priority") are the pname or the id (i have tried both and neither approach seem to work.

    I'd would also like to add points based on which items in the my Multi Check Box field have been selected. For example item one checked add 100 points, item three checked adds 40 points.

    Would appropriate any pointers and advise.

    Thanks

  18. Hi,

    We are using the Misc Custom Field Plugin 1.2.3 for JIRA 4.4. But earlier we were using JIRA 4.3 and below calculated number field was working correctly and showing the correct value but not in the JIRA 4.4 upgrade but we are not getting any value.

    <!-- @@Formula:(((issue.get("customfield_10167")  != null ? Integer.parseInt(issue.get("customfield_10167")) : 0 ) +
    (issue.get("customfield_10168")  != null ? Integer.parseInt(issue.get("customfield_10168")) : 0 ) +
    (issue.get("customfield_10169")  != null ? Integer.parseInt(issue.get("customfield_10169")) : 0 ) +
    (issue.get("customfield_10170")  != null ? Integer.parseInt(issue.get("customfield_10170")) : 0 ))/4.0) *
    (issue.get("customfield_10171")  != null ? Float.parseFloat(issue.get("customfield_10171")) : 0 ) -->

  19. Unknown User (david.zhang@equifax.com)

    Is it possible to get the calculated field from child options of cascading list? if so, how?

  20. Unknown User (agrzes)

    Could some update examples on Transition Date/Time Field and Transition Caller Field, as is it is a trap.

     
    <!-- @TransitionId:- transition ID ->
    

    I copied this without noticing unclosed comment and commented out significant portion or admin UI.

    1. Sorry about that. I've updated all code samples.

  21. Unknown User (benwfriedman)

    Hi All -

    I'm trying to create a calculation field that sums a custom field over all of its subtasks or linked tasks (whichever works) -- but not able to get the example above to work. I can't seem to pull a list of linkedissues (always comes back zero) or subtasks.

    Has anyone been able to do this in JIRA 5.x?

    Thanks for any help/pointers!

    -Ben

  22. Unknown User (benwfriedman)

    Hoping someone can help me! :-) Seems like I should be able to get this to work - as in Jen's post above - but can't figure it out.

    I'm trying to create a calculation field that sums a custom field over all of its subtasks or linked tasks (whichever works) -- but not able to get the example above to work. I can't seem to pull a list of linkedissues (always comes back zero) or subtasks.

    Has anyone been able to do this in JIRA 5.x?

    Thanks!

    -Ben

    1. Hi Ben,

      I assume you tried Jens' approach above. Did you get any error in the logs?

      Can you post the code of the formula you used?

      David

      1. Unknown User (benwfriedman)

        David -

        I'm using Jens' code *exactly* except for substituting my fields where needed.

        The structure is working -- but the code as written does not return any linked issues where they do exist. (therefore, I obviously cannot test pulling and summing the specific field from the linked tasks).

        in the above code,   linkedIssues.size()  is always 0.

        Does the code exactly as written actually return a list of linked issues for you?

        Thanks,

        Ben

  23. Unknown User (benwfriedman)

    Hoping someone can help me! :-) Seems like I should be able to get this to work - as in Jen's post above - but can't figure it out.

    I'm trying to create a calculation field that sums a custom field over all of its subtasks or linked tasks (whichever works) -- but not able to get the example above to work. I can't seem to pull a list of linkedissues (always comes back zero) or subtasks.

    Has anyone been able to do this in JIRA 5.x?

    Thanks!

    -Ben

  24. Hello David,

    why is the IssueProxy class not returning the issue itself? I'm currently searching for a way to get the information which com.atlassian.jira.issue.Issue.getResolutionDate() would return. I cannot get this information with the get method provided by the issue proxy because the resolution date is no field. However the IssueProxy knows the issue so it would be easy to implement a getIssue() method.

    Greetings,

    Lars

    1. Hi Lars,

      the reason why I'm returning an IssueProxy object instead of the issue object itself is because there is no method on the issue object to access custom fields. Also, it is easier for some people to use get(<fieldname>) rather than looking up the Jira API documentation for the name of the accessor method.

      However, I should have exposed the Issue object as a separate context variable (which would be simpler than using issue.getIssue()). Can you create an entrancement request?

      David.

      1. Hi David,

        I've just created an improvement request. For now I could workaround by accessing the private field.

        https://studio.plugins.atlassian.com/browse/JMCF-39

        Thanks,

        Lars

  25. Unknown User (freewizard)

    Hi,

    any possibility to support parent fix version?

    1. if you can access an the the com.atlassian.jira.Issue instance it should be possible by calling

      
      issueObject.getParentObject().getFixVersions()
      
      
      

      to get the issue object use the new context variable see JMCF-39 or try this workaround (works with 1.5.1 since 1.5.2 you should utilze the issueObject)

      
      java.lang.reflect.Field field = issue.getClass().getDeclaredField("issue");
      field.setAccessible(true);
      com.atlassian.jira.issue.Issue issueObject = (com.atlassian.jira.issue.Issue) field.get(issue);
      
      
      1. Unknown User (freewizard)

        if evaluating fields in this way, would it be possible to use it in JQL e.g. "myfield IN unreleasedVersions()"?

  26. Unknown User (marcel.dietze)

    Hello,

    first i'm not a java developer. With the Calculated Numer Field i count all linkes issues from one parent issue. This works fine!

    Code I'm using:

    <!-- @@Formula: issue.get("issuelinks").size() -->

    Is it possible to count all linked Issues with a specific status, like "Open" or "Resolved"?

    Marcel

    1. Unknown User (marcel.dietze)

      Hello,

      Is it possible to count all linked Issues with a specific status, like "Open" or "Resolved"?

      Marcel

      1. While it is possible to write a formula that will count such issues, the problem is that the resulting value will not be synchronized with the changing status of linked issues.

        The reason is that Jira indexes field values, and updates the indexes only when the issue is updated. So if a linked issue is updated, only that issue's indexed values will be updated, not the source issue.

        The symptom is simple: while the "view issue" screen will display the correct field value (because it is always recomputed), search results (the "issue navigator") will display incorrect values (from the index) if one of the linked issues has changed.

        There are ways around this, such as creating a post-function that will trigger a re-indexing of all linked issues (so that any reference back to the modified issue is updated), but this is rather complex and error-prone. And it won't work for modifications done through the "Edit" action, since it has no associated transition and therefore no post-function.

        David.

  27. Disclaimer:  I'm not a Java developer

    I saw a discussion above, and have read https://studio.plugins.atlassian.com/browse/JMCF-27 and https://studio.plugins.atlassian.com/browse/JMCF-29 about the unavailability of aggregatetimeoriginalestimate and aggregatetimespent.

    These have discouraged me, but I want to be sure I read this properly, so here is what I'm trying to do:

    We are using the Structure plugin to track projects.

    We have a nested tree, with Deliverables out-dented above Tasks.  This way, the sum of the estimates and time spent for the Tasks roll up to the Deliverables.

    I would like to calculate the percentage of time spent vs. the original estimate.

    I would like to use "aggregatetimespent" / "aggregatetimeoriginalestimate", and display the result as a percentage in the Structure view as a column.

    For example, a Deliverable has 10 Tasks beneath it in the tree, each with an original estimate of 1 hour.

    This makes the Sum Original Estimate for the Deliverable = 10 hours

    Our staff records their time against each task using Tempo.  If each employee records 2 hours of actual time spent on each of the 10 tasks, then the Deliverable above will show Sum Time Spent = 20 hours.

    I want a column that shows Actual Time vs. Estimated Time = 200%

    Can this be done?

    Are these fields available in the calculated custom field?

    If not, do you have a suggestion of how I can display this information?

    Thanks,

    Bryant

  28. Unknown User (ahordes)

    We have workflow transition that is executed when testing fails.  My dev team wants to set up a counter to count how many times the enhancement failed testing.  I'd like to use the calculated field and increment upon this transition. How can I update the value during transition?

    1. A calculated field does not store any value. Therefore, you cannot use it as a counter.

      You should use a regular integer field and use a post-function to increment it. You can write your own post-function using Script Runner.

  29. Unknown User (jreinink@calago.nl)

    Hi All,

    I cant get to get this working to get the resolution time. => Date resolved - Date created.

    Please help!

    Thanks!

    Jeroen

    1. I gues that is what you want to do:

      Timestamp created = issueObject.getCreated()
      Timestamp resolved = issueObject.getResolutionDate();
      long resolvedTime = resolved.getTime() - created.getTime()
      
      1. Unknown User (jreinink@calago.nl)

        Yes, thanks for the quick reply!

        Only how to put this into the Description of the custom field? in the @@Formula: form?

        Thanks!!

        1. Hi,

          you want something like:

          <!-- @@Formula: issue.get("resolved")==null ? null : (issue.get("resolved").getTime() - issue.get("created").getTime()) / 1000 / 3600 / 24 -->

          (the trailing divisions are converting from milliseconds to days - you will adapt them to your own requirements)

          David.

          1. Unknown User (jreinink@calago.nl)

            Yes, I have also tried this, but keeps getting no results.

            Does issue.get("resolved") work in 4.4.3 version of JIRA?

            When I use examples above of documentation, i get output, so the plugin is working.

            Thanks!

            1. Sorry, the name is "resolutiondate", not "resolved".

              <!-- @@Formula: issue.get("resolutiondate")==null ? null : (issue.get("resolutiondate").getTime() - issue.get("created").getTime()) / 1000 / 3600 / 24 -->
              1. Unknown User (jreinink@calago.nl)

                Thanks working!

  30. Unknown User (jreinink@calago.nl)

    This really is a nice plugin. Im checking out the options to add some our SLA fields in JIRA. So I now have the amount of hours it takes to resolve an issue, based on the creation date en resolvement data.

    But can something be created so that the amount of hours to resolve an issue during business hours (09:00 - 17:00) can be used?

    1. I don't really see how. It depends on what you mean by "amount of hours to resolve an issue during business hours". If you just mean that you want to count the business hours between the open date and the resolution date, then it can be done (you just need to develop a function that will compute this and use it in the formula - you can define functions inside the formula). Otherwise, it's really a full-fledged time tracking feature you need and I encourage you to look at the various commercial Jira plugins that address this need.

      1. Unknown User (jreinink@calago.nl)

        Hi,

        I found the following java code for getting the business hours between 2 dates. I tried to implement this in the calc. fields, but no success.
        What am i doing wrong here?

        <!-- @@Formula:
        
        public static double CalculateBusinessHours(DateTime dtStart, DateTime dtEnd)
            {
                int StartingHour = 9;
                int EndingHour = 17;
        
                // initialze our return value
                double OverAllMinutes = 0.0;
        
                // start time must be less than end time
                if (dtStart > dtEnd)
                {
                    return OverAllMinutes;
                }
                DateTime ctTempEnd = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 0, 0, 0);
                DateTime ctTempStart = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 0, 0, 0);
        
                // check if startdate and enddate are the same day
                bool bSameDay = (ctTempStart == ctTempEnd);
        
                // calculate the business days between the dates
                int iBusinessDays = GetBusinessDays(ctTempStart, ctTempEnd);
        
                // now add the time values to our temp times
                TimeSpan CTimeSpan = new TimeSpan(0, dtStart.Hour, dtStart.Minute, 0);
                ctTempStart += CTimeSpan;
                CTimeSpan = new TimeSpan(0, dtEnd.Hour, dtEnd.Minute, 0);
                ctTempEnd += CTimeSpan;
        
                // set our workingday time range and correct the first day
                DateTime ctMaxTime = new DateTime(ctTempStart.Year, ctTempStart.Month, ctTempStart.Day, EndingHour, 0, 0);
                DateTime ctMinTime = new DateTime(ctTempStart.Year, ctTempStart.Month, ctTempStart.Day, StartingHour, 0, 0);
                Int32 FirstDaySec = CorrectFirstDayTime(ctTempStart, ctMaxTime, ctMinTime);
        
                // set our workingday time range and correct the last day
                DateTime ctMaxTime1 = new DateTime(ctTempEnd.Year, ctTempEnd.Month, ctTempEnd.Day, EndingHour, 0, 0);
                DateTime ctMinTime1 = new DateTime(ctTempEnd.Year, ctTempEnd.Month, ctTempEnd.Day, StartingHour, 0, 0);
                Int32 LastDaySec = CorrectLastDayTime(ctTempEnd, ctMaxTime1, ctMinTime1);
                Int32 OverAllSec = 0;
        
                // now sum-up all values
                if (bSameDay)
                {
                    if (iBusinessDays != 0)
                    {
                        TimeSpan cts = ctMaxTime - ctMinTime;
                        Int32 dwBusinessDaySeconds = (cts.Days * 24 * 60 * 60) + (cts.Hours * 60 * 60) + (cts.Minutes * 60) + cts.Seconds;
                        OverAllSec = FirstDaySec + LastDaySec - dwBusinessDaySeconds;
                    }
                }
                else
                {
                    if (iBusinessDays > 1)
                        OverAllSec =
                        ((iBusinessDays - 2) * 9 * 60 * 60) + FirstDaySec + LastDaySec;
                }
                OverAllMinutes = OverAllSec / 60;
        
                return OverAllMinutes / 60;
        
            }
        
        public static DateTime AddBusinessDays(DateTime dt, int nDays)
            {
                int weeks = nDays / 5;
                nDays %= 5;
                while (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
                    dt = dt.AddDays(1);
        
                while (nDays-- > 0)
                {
                    dt = dt.AddDays(1);
                    if (dt.DayOfWeek == DayOfWeek.Saturday)
                    {
                        dt = dt.AddDays(2);
                    }
                }
                return dt.AddDays(weeks * 7);
            }
        
            private static int GetBusinessDays(DateTime ctStart, DateTime ctEnd)
            {
                TimeSpan ctp = ctEnd - ctStart;
                int iDays = ctp.Days + 1;
                int iWeeks = iDays / 7;
                int iBusDays = iWeeks * 5;
                int iRem = iDays % 7;
                while (iRem > 0)
                {
                    // no sunday, no saturday
                    int iStartDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctStart.DayOfWeek.ToString());
                    if (iStartDay != 1 && iStartDay != 7)
                    {
                        iBusDays++;
                    }
                    TimeSpan time1 = new TimeSpan(1, 0, 0, 0);
                    ctStart += time1;
        
                    iRem--;
                }
                return iBusDays;
            }
        
            private static Int32 CorrectFirstDayTime(DateTime ctStart, DateTime ctMaxTime, DateTime ctMinTime)
            {
                Int32 daysec = 0;
        
                if (ctMaxTime < ctStart) // start time is after max time
                {
                    return 0; // zero seconds for the first day
                }
                int iStartDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctStart.DayOfWeek.ToString());
                if (iStartDay == 1 && iStartDay == 7)
                {
                    return 0;
                }
                if (ctStart < ctMinTime) // start time is befor min time
                {
                    ctStart = ctMinTime; // set start time to min time
                }
                TimeSpan ctSpan = ctMaxTime - ctStart;
                daysec = (ctSpan.Days * 24 * 60 * 60) + (ctSpan.Hours * 60 * 60) + (ctSpan.Minutes * 60) + ctSpan.Seconds;
                return daysec;
            }
            private static Int32 CorrectLastDayTime(DateTime ctEnd, DateTime ctMaxTime, DateTime ctMinTime)
            {
                Int32 daysec = 0;
        
                if (ctMinTime > ctEnd) // start time is after max time
                {
                    return 0; // zero seconds for the first day
                }
                int iEndDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctEnd.DayOfWeek.ToString());
                if (iEndDay == 1 && iEndDay == 7)
                {
                    return 0;
                }
                if (ctEnd > ctMaxTime) // start time is befor min time
                {
                    ctEnd = ctMaxTime; // set start time to min time
                }
                TimeSpan ctSpan = ctEnd - ctMinTime;
                daysec = (ctSpan.Days * 24 * 60 * 60) + (ctSpan.Hours * 60 * 60) + (ctSpan.Minutes * 60) + ctSpan.Seconds;
                return daysec;
            }
        
        issue.get("resolutiondate")==null ? null :  CalculateBusinessHours(issue.get("created"), issue.get("resolutiondate"))
         -->
        1. What kind of error are you getting?

          Also, you should try with the latest SNAPSHOT build of JMCF, as a bug prevented errors from showing up in logs in the latest release version.

          1. Unknown User (jreinink@calago.nl)

            We are using JIRA 4.3.3, but I do not get an error, it just does not display the value.
            Where can I find logs or errormessages if they occur from this module?

            Thanks!

            1. Unknown User (jreinink@calago.nl)

              2012-12-19 16:18:55,827 ajp-8010-7 ERROR anonymous 978x2632536x2 - 81.204.104.233 /rpc/soap/jirasoapservice-v2 [innovalog.jmcf.fields.CalculatedNumberField] CalculatedNumberField: error evaluating formula: In file: <Inline eval of:
              
              public static double CalculateBusinessHours(DateTime dtStart, DateTime dtEnd)
                  {
                      int StartingHour = 9;
                      int EndingHour = 17;
              
                      // initialze our return value
                      double OverAllMinutes = 0.0;
              
                      // start time must be less than end time
                      if (dtStart > dtEnd)
                      {
                          return OverAllMinutes;
                      }
                      DateTime ctTempEnd = new DateTime(dtEnd.Year, dtEnd.Month, dtEnd.Day, 0, 0, 0);
                      DateTime ctTempStart = new DateTime(dtStart.Year, dtStart.Month, dtStart.Day, 0, 0, 0);
              
                      // check if startdate and enddate are the same day
                      bool bSameDay = (ctTempStart == ctTempEnd);
              
                      // calculate the business days between the dates
                      int iBusinessDays = GetBusinessDays(ctTempStart, ctTempEnd);
              
                      // now add the time values to our temp times
                      TimeSpan CTimeSpan = new TimeSpan(0, dtStart.Hour, dtStart.Minute, 0);
                      ctTempStart += CTimeSpan;
                      CTimeSpan = new TimeSpan(0, dtEnd.Hour, dtEnd.Minute, 0);
                      ctTempEnd += CTimeSpan;
              
                      // set our workingday time range and correct the first day
                      DateTime ctMaxTime = new DateTime(ctTempStart.Year, ctTempStart.Month, ctTempStart.Day, EndingHour, 0, 0);
                      DateTime ctMinTime = new DateTime(ctTempStart.Year, ctTempStart.Month, ctTempStart.Day, StartingHour, 0, 0);
                      Int32 FirstDaySec = CorrectFirstDayTime(ctTempStart, ctMaxTime, ctMinTime);
              
                      // set our workingday time range and correct the last day
                      DateTime ctMaxTime1 = new DateTime(ctTempEnd.Year, ctTempEnd.Month, ctTempEnd.Day, EndingHour, 0, 0);
                      DateTime ctMinTime1 = new DateTime(ctTempEnd.Year, ctTempEnd.Month, ctTempEnd.Day, StartingHour, 0, 0);
                      Int32 LastDaySec = CorrectLastDayTime(ctTempEnd, ctMaxTime1, ctMinTime1);
                      Int32 OverAllSec = 0;
              
                      // now sum-up all values
                      if (bSameDay)
                      {
                          if (iBusinessDays != 0)
                          {
                              TimeSpan cts = ctMaxTime - ctMinTime;
                              Int32 dwBusinessDaySeconds = (cts.Days * 24 * 60 * 60) + (cts.Hours * 60 * 60) + (cts.Minutes * 60) + cts.Seconds;
                              OverAllSec = FirstDaySec + LastDaySec - dwBusinessDaySeconds;
                          }
                      }
                      else
                      {
                          if (iBusinessDays > 1)
                              OverAllSec =
                              ((iBusinessDays - 2) * 9 * 60 * 60) + FirstDaySec + LastDaySec;
                      }
                      OverAllMinutes = OverAllSec / 60;
              
                      return OverAllMinutes / 60;
              
                  }
              
              public static DateTime AddBusinessDays(DateTime dt, int nDays)
                  {
                      int weeks = nDays / 5;
                      nDays %= 5;
                      while (dt.DayOfWeek == DayOfWeek.Saturday || dt.DayOfWeek == DayOfWeek.Sunday)
                          dt = dt.AddDays(1);
              
                      while (nDays-- > 0)
                      {
                          dt = dt.AddDays(1);
                          if (dt.DayOfWeek == DayOfWeek.Saturday)
                          {
                              dt = dt.AddDays(2);
                          }
                      }
                      return dt.AddDays(weeks * 7);
                  }
              
                  private static int GetBusinessDays(DateTime ctStart, DateTime ctEnd)
                  {
                      TimeSpan ctp = ctEnd - ctStart;
                      int iDays = ctp.Days + 1;
                      int iWeeks = iDays / 7;
                      int iBusDays = iWeeks * 5;
                      int iRem = iDays % 7;
                      while (iRem > 0)
                      {
                          // no sunday, no saturday
                          int iStartDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctStart.DayOfWeek.ToString());
                          if (iStartDay != 1 && iStartDay != 7)
                          {
                              iBusDays++;
                          }
                          TimeSpan time1 = new TimeSpan(1, 0, 0, 0);
                          ctStart += time1;
              
                          iRem--;
                      }
                      return iBusDays;
                  }
              
                  private static Int32 CorrectFirstDayTime(DateTime ctStart, DateTime ctMaxTime, DateTime ctMinTime)
                  {
                      Int32 daysec = 0;
              
                      if (ctMaxTime < ctStart) // start time is after max time
                      {
                          return 0; // zero seconds for the first day
                      }
                      int iStartDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctStart.DayOfWeek.ToString());
                      if (iStartDay == 1 && iStartDay == 7)
                      {
                          return 0;
                      }
                      if (ctStart < ctMinTime) // start time is befor min time
                      {
                          ctStart = ctMinTime; // set start time to min time
                      }
                      TimeSpan ctSpan = ctMaxTime - ctStart;
                      daysec = (ctSpan.Days * 24 * 60 * 60) + (ctSpan.Hours * 60 * 60) + (ctSpan.Minutes * 60) + ctSpan.Seconds;
                      return daysec;
                  }
                  private static Int32 CorrectLastDayTime(DateTime ctEnd, DateTime ctMaxTime, DateTime ctMinTime)
                  {
                      Int32 daysec = 0;
              
                      if (ctMinTime > ctEnd) // start time is after max time
                      {
                          return 0; // zero seconds for the first day
                      }
                      int iEndDay = (Int32)Enum.Parse(typeof(DayOfWeek), ctEnd.DayOfWeek.ToString());
                      if (iEndDay == 1 && iEndDay == 7)
                      {
                          return 0;
                      }
                      if (ctEnd > ctMaxTime) // start time is befor min time
                      {
                          ctEnd = ctMaxTime; // set start time to min time
                      }
                      TimeSpan ctSpan = ctEnd - ctMinTime;
                      daysec = (ctSpan.Days * 24 * 60 * 60) + (ctSpan.Hours * 60 * 60) + (ctSpan.Minutes * 60) + ctSpan.Seconds;
                      return daysec;
                  }
              
              issue.get("resolutiondate")==null ? null :  CalculateBusinessHours(issue.get("created"), issue.get("resolutiondate"))
               ; > Encountered "public" at line 3, column 1.
              
              2012-12-19 16:18:55,829 ajp-8010-7 WARN anonymous 978x2632536x2 - 81.204.104.233 /rpc/soap/jirasoapservice-v2 [innovalog.jmcf.fields.AbstractTransitionSearchField] com.innovalog.jmcf.fields.ActionExecutionCallerField: invalid transition ID in custom field description
              2012-12-19 16:18:55,830 ajp-8010-7 ERROR anonymous 978x2632536x2 - 81.204.104.233 /rpc/soap/jirasoapservice-v2 [innovalog.jmcf.fields.WorkflowHistoryDAO] java.lang.NullPointerException
              java.lang.NullPointerException
              1. The formula syntax doesn't support the full Java language but only a subset. You can refer to http://www.beanshell.org/manual/syntax.html#Basic_Syntax for details.

  31. Unknown User (pamela.guo)

    <!-- @@Formula:import com.atlassian.jira.ComponentManager;import com.atlassian.jira.issue.fields.CustomField;import com.atlassian.jira.issue.CustomFieldManager;int sumCustomFieldValues( string customFieldId) {int sum = 0;CustomFieldManager customFieldManager = ComponentManager.getInstance().getCustomFieldManager();CustomField customField = customFieldManager.getCustomFieldObject(customFieldId);if(issue.getCustomFieldValue(customField)!=null){sum = 1;}return sum;}sumCustomFieldValues("customfield_10003");
    -->

    I tried this code, but it doesn't work at all. Please help.

    1. You need to update to the latest SNAPSHOT version (available in the "Builds" tab) so that logging works again. Then you'll see what the problem is in the Jira logs.

      1. Unknown User (pamela.guo)

        Hi David,

        I updated it to the SNAPSHOT version; however, it still not work and not error message. Any suggestion?

        1. To get the value of field customfield_10003, you can simply use:

          issue.get("customfield_10003")

          But I don't understand what you're trying to achieve. Your function is named "sumCustomFieldValues" but I don't see any sum... You function simply returns 1 if the field value is not null, and 0 otherwise...

  32. I'm trying to add together the values of two custom fields that are select lists.  But it seems that the calculated field doesn't view the select lists as numbers.

    We have a custom field called "Star Chamber Rating", whose custom field ID is: 10503 - it is a select list of 1 through 5

    We have a custom field called "Proposed SC Rating", whose custom field ID is: 10900 - it is a select list of 1 through 5

    I want to know the delta between these two numbers.

    I tried building an equation using subtraction but got no values.

    Just to test it, I changed it to addition.  I finally got values, but it is not actually summing the values, rather concatenating them together.

    Below is the equation:

    <!- @@Formula: (issue.get("customfield_10503") != null ? issue.get("customfield_10503") : 0) + (issue.get("customfield_10900") != null ? issue.get("customfield_10900") : 0)->

    If the selected value for custom field 10503 is 2, and the selected value for custom field 10900 is 1, then the product of the above formula should be 3.

    However, it is returning the value of 21.

    When I change the formula to subtraction, I get no answer at all.

    What's going on?  Is there a way to designate the select list values as numbers instead of strings?

    Thanks,

    Bryant

    1. In Jira 5+; select list fields have values of type "Option". In Jira < 5, they have values of type String. In both cases, you need to convert these values to an Integer type before you can use numerical operators on them. This is discussed numerous times above (e.g. comment-68453064).

      In Jira 5+, it'll be something like Integer.parseInt(issue.get("customfield_12345").getValue())

      In Jira 4, it'll be something like Integer.parseInt(issue.get("customfield_12345"))

  33. I can see that aggregatetimeoriginalestimate and timeoriginalestimate are now supported as I am successfully using them.  Is there support for aggregatetimeremainingestimate as I can't seem to get this to work?

    Also if I have some custom numeric fields within subtasks, how would I go about summing them within the parent user story?

    1. The field you're looking for seems to be actually called "aggregatetimeestimate".

      As for summing numeric fields within subtasks, I believe there are examples within comments above and/or within some of the issues for JMCF.

      1. Hi David Fischer

        Thanks for that - works perfectly now.  (smile)

        As for summing a field for all subtasks within a story, you have mentioned that you will try to fix the code (posted somewhere on this page in the comments, re: story points) to work for JIRA 5.x, although you have mentioned that as a re-index is required that viewing the results in the Issue Navigator, or viewing within Confluence via the JIRA Issues macro will display incorrect results.  Is there a way to force a refresh?  Also am I correct in assuming (can't remember where I read this) that a refresh occurs every midnight by default?

        1. The fix was for summing linked issues, not subtasks, I believe. Iterating over sub-tasks is easy.

          As for re-indexing, it can be done manually within the Administration section. I believe it can also be scheduled using the built-in scheduler. But note that it can take some time (several minutes or more) on large JIRA instances.

  34. Hi, I have been trying to get the JIRA ID successfully and have not been able to.  I create a new custom field called Name and then in the description I wrote <!-- @@Formula: issue.get("<FIELD_PROJECT_ID>") -->

    I also assigned it to all the screen so I can see it if worked correctly but do not see it anywhere is there something I am doing wrong?

    1. I'm not sure I understand what you're trying to do. What field are you trying to read using issue.get?

      1. I am trying to read the JIRA ID like for a project abc-1234 or dcd-123 and when the issue is created it applies that.  Or if I can get a formatted time with day together like 2-2-2013 12:14pm seconds 12.  If that does make any sense?

        1. I believe the field ID for the Issue ID is "issueid". As for formatting date, yes, you can, but you should get help from a Java developer to write your custom formula.

          1. <!-- @@Formula: issue.get("issueid").getValue–> or <!-- @@Formula: issue.get("issueid").getissueid–>

             

            would I write it like that or some other way?

            1. Just 

              <!-- @@Formula: issue.get("issueid") -->
  35. Hi,

    I'm trying to use this formula...but it's not working. Does anyone have any clue of what's wrong?

     

    <!-- @@Formula:

    int qtdPFs = issue.get("customfield_12042");

    int prazo = -1;

    if (qtdPFs <= 10) {

                prazo = 12;

            } else if (qtdPFs > 10 && qtdPFs <= 20) {

                prazo = 25;

            } else if (qtdPFs > 20 && qtdPFs <= 30) {

                prazo = 40;

            } else if (qtdPFs > 30 && qtdPFs <= 40) {

                prazo = 50;

            } else {

                prazo = new Double(Math.pow(value,0,36) *30).intValue();                

            }    

           org.apache.commons.lang.time.DateUtils.addDays(issue.get("customfield_10160"), prazo);

    -->

     

    Best regards,

    Raiza

    1. Hi,

      as mentioned at the top of the page, it's best if you post your usage questions on Atlassian Answers. You're much more likely to get answers there from the community.

      But off the top of my head, I can see at least one reason why your code is not working: Apache Commons Lang might be unavailable (I've heard similar reports before). I will try to enforce its availability to calculated fields in the next release, but for now it is not safe. You can check whether that's your problem in the JIRA logs.

      Cheers,

      David

  36. If I have a custom field of a format JIRA Interval, is there a way to apply that to a date in a calculated date/time field to generate the value.

    IE, I have a field called "Estimated time" of type JIRA interval. If I set that value to 3m. I want to create a calculated date field called "ETA" with a value of "Create time" + "estimated time"

     

     

    1. I'm not sure what you mean by "JIRA Interval" custom field. There is no such field type in the standard JIRA. Are you using the Kepler Custom Fields plugin?

      In any case, as long as you can get the value of your field using issue.get(), you should be able to use it in a calculated date field. It will just require some simple programming.

      I suggest you ask a question on Atlassian Answers as suggested at the top of the page.

  37. I got the information that the Transaction Caller or Date fields do not save the values in the custom fields, but are rather calculated on display need. 

    can you highlight how the link works to find the proper value for a ticket. I need to build an SQL reporting using these fields and cannot find a way to query the proper field values.. 

     

    thanks in advance!! 

      1. David,

        thanks for that this was very useful..

        I still have one issue to understand.. in one of the tickets the field I am trying to query shows a value .. but looking into the OS_HISTORYSTEP table it does not show me any for that particular entry when using inner join OS_HISTORYSTEP workflow on i.workflow_id = workflow.entry_id

        to explain this a bit more.. I have four fields (2 Transaction Caller Fields / 2 Transaction Date Fields)

        FIRST FIELDS: 1 Caller and 1 Date field have the following configuration

        <!-- @TransitionId: 4,5,2 -->

        <!-- @Execution: first -->

        LAST FIELDS: 1 Caller and 1 Date field have the following configuration

        <!-- @TransitionId: 2,5 -->

        <!-- @Execution: last -->

         

        I found in the OS_CURRENTSTEP the information fo the one LAST FIELD .. (caller was empty for some reasons in this table, but shown in ticket)
        I have not found the FIRST FIELDS info for that particular ticket..

         

        I have to say that I am adjusting Workflows as well; and it might be that I have changed project workflow for that ticket while the ticket was open..

        can you explain a bit in more details how this functions..

        many thanks in advance .. I am building a SLA tracking mechanism and can share the use case once functional..

        Reg. Goran

         

        1. It might be because the workflow id changed over time. Look at my code to find out how I look into past workflows.

          1. thanks you were right! 

            all functional and excellent plugin!! 

  38. I have an issue to simply format my result .. I want to make the misc number field red and bold depanding on the value.. 

    here an example which does not work..

    <!-- @@Format:

    if (value > 2)
      value.setForeground(Color.blue);
      return numberTool.format(value) ;
    else if (value <= 2)
      value.setForeground(Color.yellow);
      return numberTool.format(value) ;
    else if (value <=0)
      value.setForeground(Color.red);
      return numberTool.format(value) ;
    else
      numberTool.format(value);

    -->

     

    1. I'm not sure where you got the impression that you could call setForeground(Color.blue) on the value variable. The value variable is a scalar object (a java.lang.Double).

      The format script must return HTML code. So if you want to put the number in italics, you should return "<i>"+numberTool.format(value)+"</i>".

  39. hi David Fischer i need a help to configure the calculated custom field please find the below requirements

     

    JIRA version:6.0.1

    JMCF:1.5.7

    If my caluclated number field value is 0 then my caluculated text field value need to be low

    IF caluclated number field value =2 or 3 then caluculated text field value need to be medium

    IF caluclated number field value =4 then caluculated text field value need to be high

    how to achive this. Please help me out ASAP.

     

    1. Quick reply, before you post your question on Answers: 

      I assume you already have a calculated number field. Let's say its ID is 12345, hence its name is "customfield_12345".

      In your Calculated Text Field, you would do something like:

      <!-- @@Formula: 
      Integer i = issue.get("customfield_12345");
      if (i==null) return null;
      if (i==0) return "low";
      if (i==2 || i==3) return "medium";
      return "high";
      -->
  40. hi David Fischer i am not able get the value of my calculated field value when using issue.get("customfield_12345") but if i do as integer 1 = 2 the i get the output Please help me out

    1. As mentioned earlier, please post your question to Answers.