Skip to Content
Flower 3.2.3 is released 🎉
DocsConceptsDecision Handling in Gateways
Image

BPMN Gateways & Decision Handling

BPMN Gateways & Decision Handling

Automating decisions in Jira workflows can drastically improve efficiency and eliminate bottlenecks.
With BPMN Gateways, you can define clear decision logic and let Flower BPM handle the rest.

This guide will show you how to craft decision expressions using Jira Smart Values, ensuring smooth and automated process execution.


Expressions with Jira Smart Values

When a process reaches a BPMN Gateway, a decision needs to be made.
The Flower BPM Engine evaluates this decision based on predefined expressions.

Expressions use Jira Smart Values  and are stored directly on the outgoing transitions from the gateway.

Jira Smart Value Expressions used in XOR gateway

The process follows the first transition where the expression evaluates to true.

ℹ️

If a transition loops back to a previously completed activity, it will be reopened,
as long as your Jira workflow configuration allows it.


Using Jira Smart Values in BPMN Expressions

Jira Smart Values  allow you to access issue fields and properties dynamically.
They are also widely used in Jira Automations .

For example:

pi.fields.summary

This returns the summary of the current process instance.

Example Expressions:

#Expression
1pi.fields.summary == 'New Issue'
2cur.fields.status.name == 'Rejected'
3cur.fields.priority.name == 'Low'
4cur.fields.assignee.accountId == '557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914'
5cur.fields.customfield_10113 >= 5000
6cur.fields.customfield_10115.value == 'yes'
7pi.properties.flowerVariables.external.data.value >= 1000
8pi.fields.comment.comments[0].accountId == '557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914'
9pi.fields.customfield_10023.requestType.name == 'Technical support'

These conditions ensure that only relevant transitions are activated, reducing manual input and automating decision-making.

Select the Right Jira Ticket for Your Expression

An expression evaluates whether a field in a Jira ticket matches a specific condition and returns either true or false. The process will always take the transition whose expression evaluates to true.

There are two Jira tickets to consider:

  • The process instance ticket (pi)
  • The current ticket (cur), which is always the ticket created by the last activity before the decision gateway.

Typically, you use cur to evaluate the status of the last ticket, such as checking if it was resolved or rejected in approval steps. In contrast, fields on pi are commonly used to reference data that was set at the start of the process and remains consistent throughout.

Additionally, you can reference external data sources through flowerVariables.

How to Address Complex Objects in Your Expression

Not all fields are as simple as the summary field.
Sometimes, you need to access complex fields like the requestType of a JSM issue (see example 9 in the table).

Jira custom fields in general

Custom fields in Jira always have a specific type, and most of these types are not simple primitive values. Instead, they are complex objects. Many custom field types do have a simple string value and can be accessed like this:

pi.fields.customfield_1234.value == 'yes'

However, some fields are more complex and require a deeper understanding of their structure to reference them correctly.

Identify the Custom Field for Request Type

Unlike standard fields, Request Type is stored in a Jira custom field, which may vary between Jira instances.
To find out the correct field ID for your instance, use the Jira REST API:

curl --request GET \ --url 'https://your-domain.atlassian.net/rest/api/3/issue/FLOWER-123' \ --user '[email protected]:<api_token>' \ --header 'Accept: application/json' \ ## or simply put the url in your browser: https://your-domain.atlassian.net/rest/api/3/issue/FLOWER-123

Look for an entry like:

{ "customfield_10023": { "requestType": { "name": "Technical Task" } } }

This confirms that customfield_10023 is the Request Type field in this instance.

To reference requestType in an expression, you need the correct path. Since requestType.name might change, it’s often safer to use the Request Type ID instead:

pi.fields.customfield_10023.requestType.name pi.fields.customfield_10023.requestType.id

The same approach works for other complex fields like:

  • Priority (pi.fields.priority.name)
  • Status (pi.fields.status.name)
  • User fields (pi.fields.assignee.displayName)
  • Any other custom field (pi.fields.customfield_xxxxxx)

Check the JSON response of your Jira issue to determine the correct field structure

{ "expand": "renderedFields,names,schema,operations,editmeta,changelog,versionedRepresentations,customfield_10023.requestTypePractice", "id": "28406", "self": "https://your-jira-instance.atlassian.net/rest/api/latest/issue/28406", "key": "FLOWER-123", "fields": { "statuscategorychangedate": "2025-02-23T18:42:28.260+0100", "lastViewed": "2025-02-24T16:17:03.503+0100", "customfield_10100": [], "priority": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/priority/5", "iconUrl": "https://your-jira-instance.atlassian.net/images/icons/priorities/trivial.svg", "name": "Trivial", "id": "5" }, "assignee": "user object", "status": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/status/10000", "description": "This was auto-generated by JIRA Service Desk during workflow import", "iconUrl": "https://your-jira-instance.atlassian.net/images/icons/status_generic.gif", "name": "Waiting for support", "id": "10000", "statusCategory": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/statuscategory/1", "id": 1, "key": "undefined", "colorName": "medium-gray", "name": "No Category" } }, "creator": "user object", "reporter": "user object", "customfield_11011": { "id": "13", "name": "Time to first response", "_links": { "self": "https://your-jira-instance.atlassian.net/rest/servicedeskapi/request/28406/sla/13" }, "completedCycles": [], "ongoingCycle": { "startTime": { "iso8601": "2025-02-23T19:42:27+0200", "jira": "2025-02-23T18:42:27.531+0100", "friendly": "Yesterday 7:42 PM", "epochMillis": 1740332547531 }, "breachTime": { "iso8601": "2025-02-24T18:00:00+0200", "jira": "2025-02-24T17:00:00.000+0100", "friendly": "Today 6:00 PM", "epochMillis": 1740412800000 }, "breached": false, "paused": false, "withinCalendarHours": true, "goalDuration": { "millis": 28800000, "friendly": "8h" }, "elapsedTime": { "millis": 27632453, "friendly": "7h 40m" }, "remainingTime": { "millis": 1167547, "friendly": "19m" } } }, "aggregateprogress": { "progress": 0, "total": 0 }, "progress": { "progress": 0, "total": 0 }, "votes": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/issue/PC-3/votes", "votes": 0, "hasVoted": false }, "worklog": { "startAt": 0, "maxResults": 20, "total": 0, "worklogs": [] }, "issuetype": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/issuetype/10126", "id": "10126", "description": "For customer support issues. Created by Jira Service Desk.", "iconUrl": "https://your-jira-instance.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/11228?size=medium", "name": "Support", "subtask": false, "avatarId": 11228, "hierarchyLevel": 0 }, "project": { "self": "https://your-jira-instance.atlassian.net/rest/api/2/project/10915", "id": "10915", "key": "PC", "name": "ProcessCreators", "projectTypeKey": "service_desk", "simplified": false }, "created": "2025-02-23T18:42:27.531+0100", "customfield_10023": { "_links": { "jiraRest": "https://your-jira-instance.atlassian.net/rest/api/2/issue/28406", "web": "https://your-jira-instance.atlassian.net/servicedesk/customer/portal/8/PC-3", "agent": "https://your-jira-instance.atlassian.net/browse/PC-3", "self": "https://your-jira-instance.atlassian.net/rest/servicedeskapi/request/28406" }, "requestType": { "_expands": [ "field" ], "id": "48", "_links": { "self": "https://your-jira-instance.atlassian.net/rest/servicedeskapi/servicedesk/8/requesttype/48?expand=requestTypePractice" }, "name": "Technical support", "description": "Need help installing, configuring, or troubleshooting? Select this to request assistance.", "helpText": "", "issueTypeId": "10126", "serviceDeskId": "8", "portalId": "8", "groupIds": [ "12" ], "icon": { "id": "11196", "_links": { "iconUrls": { "48x48": "https://your-jira-instance.atlassian.net/rest/api/2/universal_avatar/view/type/SD_REQTYPE/avatar/11196?size=large", "24x24": "https://your-jira-instance.atlassian.net/rest/api/2/universal_avatar/view/type/SD_REQTYPE/avatar/11196?size=small", "16x16": "https://your-jira-instance.atlassian.net/rest/api/2/universal_avatar/view/type/SD_REQTYPE/avatar/11196?size=xsmall", "32x32": "https://your-jira-instance.atlassian.net/rest/api/2/universal_avatar/view/type/SD_REQTYPE/avatar/11196?size=medium" } } } }, "currentStatus": { "status": "Waiting for support", "statusCategory": "UNDEFINED", "statusDate": { "iso8601": "2025-02-23T19:42:27+0200", "jira": "2025-02-23T18:42:27.531+0100", "friendly": "Yesterday 7:42 PM", "epochMillis": 1740332547531 } } }, "customfield_10024": { "id": "12", "name": "Time to resolution", "_links": { "self": "https://your-jira-instance.atlassian.net/rest/servicedeskapi/request/28406/sla/12" }, "completedCycles": [], "ongoingCycle": { "startTime": { "iso8601": "2025-02-23T19:42:27+0200", "jira": "2025-02-23T18:42:27.531+0100", "friendly": "Yesterday 7:42 PM", "epochMillis": 1740332547531 }, "breachTime": { "iso8601": "2025-02-25T18:00:00+0200", "jira": "2025-02-25T17:00:00.000+0100", "friendly": "25/Feb/25 6:00 PM", "epochMillis": 1740499200000 }, "breached": false, "paused": false, "withinCalendarHours": true, "goalDuration": { "millis": 57600000, "friendly": "16h" }, "elapsedTime": { "millis": 27632545, "friendly": "7h 40m" }, "remainingTime": { "millis": 29967455, "friendly": "8h 19m" } } }, "updated": "2025-02-23T18:42:33.013+0100", "description": "Your issue description", "summary": "Your issue summary" } }

User Object

The user object is used e.g. for the fields assignee, creator, reporter etc..

Expand to see the JSON response

{ "self": "https://your-jira-instance.atlassian.net/rest/api/2/user?accountId=557058%3Afc60faa5-f40d-4344-ae2b-4becd42a7914", "accountId": "557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914", "avatarUrls": { "48x48": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914/a3075f1a-94e7-4ea6-91bd-a0165342fcfd/48", "24x24": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914/a3075f1a-94e7-4ea6-91bd-a0165342fcfd/24", "16x16": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914/a3075f1a-94e7-4ea6-91bd-a0165342fcfd/16", "32x32": "https://avatar-management--avatars.us-west-2.prod.public.atl-paas.net/557058:fp60faa5-xxxx-4344-yyyy-4becd42z7914/a3075f1a-94e7-4ea6-91bd-a0165342fcfd/32" }, "displayName": "Power User", "active": true, "timeZone": "Europe/Athens", "accountType": "atlassian" }
ℹ️

The JSON structure in Jira Cloud and Jira Data Center is almost identical but may vary in some details.
Always check the data structure in your specific Jira instance to ensure compatibility.

Integrating External Data into Gateway Decisions

Sometimes, decisions depend on external data not stored in Jira. Flower BPM allows external data to be stored as JSON in the process instance, which can then be referenced in expressions.

Storing External Data via the Jira REST API

Jira provides a REST endpoint for Issue Properties  to store JSON data on a Jira issue.

curl --request PUT \ --url 'https://your-domain.atlassian.net/rest/api/3/issue/FLOWER-2/properties/flowerVariables' \ --user '[email protected]:<api_token>' \ --header 'Accept: application/json' \ --header 'Content-Type: application/json' \ --data '{"some":"value"}'

The JSON data can be as complex as needed but must not exceed 32,768 bytes. It can then be accessed in BPMN transitions:

pi.properties.flowerVariables.some=='value' //returns true

Default Transitions: Ensuring the Process Keeps Moving

In BPMN, Default Transitions ensure that if no conditions are met, the process follows a predefined path instead of getting stuck. This is particularly useful when working with decision gateways based on dynamic expressions, such as a Jira custom field.

Default Transitions

In our Capital Investment Approval Process, the approval decision is determined based on the Jira custom field “approval” at an exclusive gateway (XOR Gateway). The possible outcomes:

  • YES → CFO/Board Approval → Investment Execution
  • NO (Default) → Rework Request → Resubmit Investment Request
  • REJECT → Investment Rejected → End Process

Why Use a Default Path?

If an error occurs in the condition (e.g., missing or incorrect field values), the process does not break but follows the default path instead. This allows the requester to review, refine, and resubmit the investment request.

This approach ensures process robustness and smooth execution, even when data inconsistencies or missing values exist in Jira.


Learn More

Last updated on