Skip to main content

Workflows and Processes

How to Work with the Activiti Tool?

Written by Lenka Haringerová

Note: If you are interested in workflow functionality, you need to contact our integration partner ARIT and discuss the specific configuration and integration options with them.

The foundation of workflows and processes is the Activiti engine. It includes a programming interface called the Activiti REST API. This interface is accessible at the following address:

/c/<identifikátor firmy>/activiti/

The following limitations apply:

  • The /login interface is not supported. ABRA Flexi authorization is used instead.

  • Modification of users, groups, and memberships is not supported. Everything is managed through the ABRA Flexi interface.

  • Uploading a new process must be done via ABRA Flexi (due to workflow validity definitions). Process updates can already be performed via the Activiti API.

API for ABRA Flexi

List of workflow definitions for a given record type:

GET /c/<identifikátor firmy>/<evidence>/workflows.xml

Starting a workflow

PUT /c/<identifikátor firmy>/<evidence>/<id záznamu>/workflows/<processId>/start

When starting a workflow, you can also pass parameters that can be used in decision-making:

PUT /c/<identifikátor firmy>/<evidence>/<id záznamu>/workflows/<processId>/start?parametr1=value1&parametr2=value2

List of events (notes and tasks) for a given object:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalost

Listing events including additional workflow attributes:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalost.xml?includes=udalost/actRuTask

When working with workflows, you typically want tasks of a specific type only:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalost/(typUdalosti = 'druhUdal.workflow')


List of all tasks for a specific workflow:

/c/<identifikátor firmy>/udalost/(typUdalosti = 'druhUdal.workflow' and processDefinitionId = '<processId>')


List of all tasks with a given task key for a specific workflow:

/c/<identifikátor firmy>/udalost/(typUdalosti = 'druhUdal.workflow' and processDefinitionId = '<processId>' and taskDefinitionKey = '<taskKey>')


List of all tasks that the currently logged-in user can resolve:

/c/<identifikátor firmy>/udalost@ukoly-k-realizaci


Sending a signal to all running workflows that can react to it:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/workflow-signal/<signalId>?param1=value


Sending a message to all running workflows that can react to it:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/workflow-message/<messageId>?param1=value


Working with a task:

/c/<identifikátor firmy>/udalost/<ID záznamu>/<operace>

claim.xml

claim the task

unclaim.xml

unclaim the task

complete.xml
complete.xml?param1=value…
1)

complete the task

assign.xml?username=user
1)

assign the task to user

add-comment.xml?comment=text
1)
2)

add a comment to the task

  1. For parameter values containing characters other than allowed URL characters (space, at sign, etc.), URL encoding must be applied.

  2. Text encoding is expected in UTF-8.

Note: events of the task type for a workflow are cancelled once they are resolved. Instead of .xml, you can also use .json or the header Accept.

List of tasks and their related objects

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalost.xml?includes=udalost/doklFak

Objects available for decision-making in ABRA Flexi

flexibee.user(username)

Returns the user with the specified name

flexibee.userQuery(username)

Returns the query object for the user with the specified name (output is identical to the objectQuery method).

flexibee.object(evidenceType)

Returns the object of the given type that is attached to the workflow task

flexibee.objectQuery(evidenceType).relation(relationName).filter(filter).list()

Allows filtering objects in a relation.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).one()

Allows returning the first object in a filtered relation.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).sum()

Allows summing objects in a filtered relation.

flexibee.objectQuery(evidenceType).relationFilter(relationName).filter(filter).firstQuery().relation(relationName2).one()

Allows chaining query processing.

flexibee.objectQuery(evidenceType).relation(relationName).list()

Allows filtering objects in a relation.

flexibee.objectQuery(evidenceType).relation(relationName).one()

Allows returning the first object in a relation.

flexibee.objectQuery(evidenceType).relation(relationName).sum()

Allows summing objects in a relation.

flexibee.wrap(object)

Wraps an object using a query (same result as returned by e.g. objectQuery). You can then use the full set of functions offered by the query.

flexibee.query(evidenceType).filter(filter).one()

Returns a single object of the given type that matches the specified filter.

flexibee.query(evidenceType).filter(filter).firstQuery().signal('signalName')

Triggers a signal on all workflows running on the selected record.

flexibee.query(evidenceType).filter(filter).list()

Returns all objects of the given type that match the specified filter.

flexibee.query(evidenceType).filter(filter).count()

Returns the count of objects of the given type that match the specified filter.

flexibee.query(evidenceType).filter(filter).sum(propertyName)

Returns the sum of the specified column for all objects of the given type that match the specified filter.

flexibee.query(evidenceType).filter(filter).max(propertyName)

Returns the max of the specified column for all objects of the given type that match the specified filter.

flexibee.query(evidenceType).filter(filter).min(propertyName)

Returns the min of the specified column for all objects of the given type that match the specified filter.

flexibee.query(evidenceType).filter(filter).avg(propertyName)

Returns the avg of the specified column for all objects of the given type that match the specified filter.

flexibee.query(evidenceType).asc(propertyName).first()

Enables ascending sorting (more at sorting in API).

flexibee.query(evidenceType).desc(propertyName).first()

Enables descending sorting (more at sorting in API).

flexibee.settings()

Returns the current company settings (record nastaveni). The company name can be retrieved for example via ${flexibee.settings().nazFirmy}

flexibee.settingsForDate(dt)

Returns the company settings (record nastaveni) for the given day (typically the document date). The company name can be retrieved for example via ${flexibee.settingsForDate(dt).nazFirmy}

flexibee.varName(evidenceType)

Returns the internal name of the variable that ABRA Flexi uses to link individual workflows to documents and objects in ABRA Flexi. Typically used when calling a subprocess.

flexibee.isDesktop()

Returns true if the workflow is currently running in the desktop application

flexibee.isServer()

Returns true if the workflow is currently running via REST API or in a browser

flexibee.importXml(string)

Performs an import of an XML string according to the ABRA Flexi REST API. Returns a collection of object identifiers from the XML import.

now

Current date and time.

authenticatedUserId

The name of the currently logged-in user (for more information, use flexibee.user(authenticatedUserId) (more documentation at activiti).

task

The Activiti record representing the task (more documentation at activiti).

execution

Information about the currently running workflow (more documentation at activiti).

Calling a subprocess

If you are calling a subprocess and want the resulting tasks to be linked to documents, you must enable propagation of the binding variable into the workflow. You can do this as follows:

<?xml version="1.0"?>
<callActivity id="callSubProcess" calledElement="checkCreditProcess">
<extensionElements>
<activiti:in source="${flexibee.varName('faktura-prijata')}" target="${flexibee.varName('faktura-prijata')}"/>
<activiti:in source="initiator" target="initiator"/>
</extensionElements>
</callActivity>

Working with users in a workflow

If you want to work with users, there are several options available. Be careful not to use a comma character (,) in user definitions. Activiti has a bug that prevents its use.

Workflow initiator

When starting a workflow, define the variable initiator. You can then use it as the username for task assignment.

<startEvent id="theStart" activiti:initiator="initiator">

Current user

If you want to assign a task to the same user who performed the current operation, use the variable authenticatedUserId.

Specific user

During processing, you can use a specific user. You can also look up a user based on certain criteria (e.g. a label):

<formalExpression>${flexibee.query('uzivatele').relation('stitek = "code:PRACOVNIK"').one().kod}</formalExpression>


Or a user relation:

<formalExpression>${flexibee.userQuery(initiator).relation('uzivatelske-vazby').filter('typVazby = "code:NADRIZENY"').one().kod}</formalExpression>

Modifying documents

Sometimes it is necessary to modify one or more documents during workflow processing. This can be done using flexibee-xml. For the flexibee.object() method to work, the workflow must be linked to that document.

<?xml version="1.0"?>
<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="object" expression="${flexibee.object('faktura-vydana')}"/>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[ <winstrom><faktura-vydana action="storno"></faktura-vydana></winstrom> ]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>

You can also modify multiple objects:

<?xml version="1.0"?>
<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[ <winstrom><faktura-vydana action="storno"><id>code:FAV0001/2013</id></faktura-vydana><faktura-vydana action="storno"><id>code:FAV0002/2013</id></faktura-vydana></winstrom> ]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>

Retrieving identifiers of modified objects

Using the variable idsVar, you can retrieve a collection of identifiers that were modified by the XML import.

<?xml version="1.0"?>
<serviceTask id="import" activiti:class="flexibee-xml"> &#x2026;
<extensionElements>
<activiti:field name="idsVar" stringValue="seznamId"/>
</extensionElements>
</serviceTask>

After a successful XML import, the variable seznamId will contain a collection of identifiers of the modified objects.

Handling errors during XML import

If an error occurs during an XML import in a task of type flexibee-xml, the workflow processing is interrupted by a WSBusinessRTException exception. The exception contains an error description and is displayed in the GUI as an error dialog.

If the workflow should continue even when an import error occurs, you can extend the task definition with the parameters errorVar and errorMessageVar:

<?xml version="1.0"?>
<serviceTask id="storno" activiti:class="flexibee-xml"> &#x2026;
<extensionElements>
<activiti:field name="errorVar" stringValue="wasError"/>
<activiti:field name="errorMessageVar" stringValue="errorMessage"/>
</extensionElements>
</serviceTask>

variable

data type

description

errorVar

Boolean

defines the name of the variable (e.g. wasError) where the flag indicating whether errors occurred during import will be stored

errorMessageVar

String

defines the name of the variable (e.g. errorMessage) where the text describing the import errors will be stored

Conditional branching based on objects

Within a workflow, you can query ABRA Flexi and react based on the response:

${flexibee.object('objednavka-prijata').sumCelkem > 1000}

You can also query more generally, for example how many unpaid invoices exist for the company listed on the current invoice:

${flexibee.query('faktura-vydana').filter('stavUhrK != "stavUhr.uhrazeno" and stavUhrK != "stavUhr.uhrazenoRucne" and firma='.concat(flexibee.object('faktura-vydana').firma.id)).sum('sumCelkem') > 1000}


Transferring workflow status to a document

Sometimes it is necessary to change the document status based on the workflow status. This can be achieved using labels assigned to a group with exclusivity enabled (when a new label from the same group is set, the others are removed). The implementation is again done using flexibee-xml, which you call at each workflow status change:

<?xml version="1.0"?>
<serviceTask id="storno" activiti:class="flexibee-xml">
<extensionElements>
<activiti:field name="object" expression="${flexibee.object('faktura-vydana')}"/>
<activiti:field name="xml">
<activiti:expression>
<![CDATA[ <winstrom><faktura-vydana><stitky>SCHVÁLENO</stitky></faktura-vydana></winstrom> ]]>
</activiti:expression>
</activiti:field>
</extensionElements>
</serviceTask>
Did this answer your question?