Skip to main content

Workflows and Processes

How to Work with the Activiti Tool?

Written by Lenka Haringerová

💡 If you're interested in workflow functionality, you need to contact our integration partner ARIT to discuss specific configuration and integration options.

Workflow and processes are based on the Activiti tool. It includes the Activiti REST API programming interface, which is accessible at this address:

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

Limitations compared to standard Activiti

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

  • Modification of users, groups, and memberships is not supported. All of this must be done via the ABRA Flexi interface.

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


API for ABRA Flexi

Listing 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, you can also pass parameters for the workflow that can be used in decision-making:

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

Events and tasks

List of events (notes and tasks) for a given object — this is the udalosti relation on a specific record:

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

Listing events including additional workflow attributes:

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

⚠️ The relation on a record is called udalosti (plural) — the path …/<ID>/udalost returns 404. Conversely, the standalone record type being filtered is udalost in singular form. Both forms are valid, but each applies in a different part of the URL.

When working with workflows, you usually want tasks of only a certain type. The event type carries the property typAkt, which is a link to the typ-aktivity record type; workflow tasks have the code ÚKOL WORKFLOW in this record type:

/c/<identifikátor firmy>/<evidence>/<ID záznamu>/udalosti/(typAkt = 'code:ÚKOL WORKFLOW')

🚨 Neither the property typUdalosti nor the value druhUdal.workflow exist in this API — such a filter will result in a 400 error with the message "Property 'typUdalosti' does not exist". Use typAkt instead. Alternatively, workflow tasks can be selected by processDefinitionId is not null.

Listing all tasks for a specific workflow:

/c/<identifikátor firmy>/udalost/(typAkt = 'code:ÚKOL WORKFLOW' and processDefinitionId = '<processId>')

Listing all tasks with a given task key for a specific workflow:

/c/<identifikátor firmy>/udalost/(typAkt = 'code:ÚKOL WORKFLOW' and processDefinitionId = '<processId>' and taskDefinitionKey = '<taskKey>')

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

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

List of tasks and their related objects:

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

Signals and messages

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

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

Sending a message to all running workflows that can respond 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>

Operation

Meaning

claim.xml

claim the task

unclaim.xml

unclaim the task

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

resolve the task

assign.xml?username=user 1)

hand over the task to user user

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

add a comment to the task

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

  • 2) Text encoding is expected to be in UTF-8.

ℹ️ Events that are of the task type for workflows are removed once they are resolved. Instead of .xml, you can also use .json or the Accept header.


Objects usable in ABRA Flexi decision-making

Expression

Description

flexibee.user(username)

Returns the user with the specified name

flexibee.userQuery(username)

Returns a query object for the user with the specified name (the 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 you to filter objects in a relation.

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

Allows you to return the first object in a filtered relation.

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

Allows you to sum objects in a filtered relation.

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

Allows you to chain query processing.

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

Allows you to filter objects in a relation.

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

Allows you to return the first object in a relation.

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

Allows you to sum objects in a relation.

flexibee.wrap(object)

Wraps an object using a query (the same result as, e.g., objectQuery returns). 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 given column for all objects matching the filter.

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

Returns the maximum of the given column for all objects matching the filter.

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

Returns the minimum of the given column for all objects matching the filter.

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

Returns the average of the given column for all objects matching the filter.

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

Enables ascending sorting.

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

Enables descending sorting.

flexibee.settings()

Returns the current company settings (nastaveni record type). The company name can therefore be obtained, e.g., via ${flexibee.settings().nazFirmy}

flexibee.settingsForDate(dt)

Returns the company settings for a given day (usually the document date), e.g., ${flexibee.settingsForDate(dt).nazFirmy}

flexibee.varName(evidenceType)

Returns the internal variable name that ABRA Flexi uses to link individual workflows to documents and objects. This is 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 running via the 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.

Variables

Variable

Description

now

Current date and time.

authenticatedUserId

The name of the currently logged-in user. For more information, use flexibee.user(authenticatedUserId) — see the Activiti documentation.

task

The Activiti record representing the task (see the Activiti documentation).

execution

Information about the currently running workflow (see the Activiti documentation).


Calling a subprocess

If you're calling a subprocess and want the resulting tasks to be linked to documents, you need to activate propagation of the linking variable into the workflow. You do this as follows:

<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 workflows

If you want to work with users, there are several options available.

⚠️ Be careful not to use a comma character (,) when defining users. Activiti has a bug that prevents its use.

Workflow initiator

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

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

Current user

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

Specific user

During processing, you can use a specific user. You can also search for a user based on certain criteria (e.g., a tag):

<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 you need to modify one or more documents while processing a workflow. This can be done using flexibee-xml. For the flexibee.object() method to work, the workflow must be linked to this document.

<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>

Multiple objects can also be modified:

<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>

Getting identifiers of modified objects

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

<serviceTask id="import" activiti:class="flexibee-xml">
…
<extensionElements>
<activiti:field name="idsVar" stringValue="seznamId" />
</extensionElements>
</serviceTask>

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

Handling errors during XML import

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

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

<serviceTask id="storno" activiti:class="flexibee-xml">
…
<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 error occurrence flag 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

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

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

You can also ask general questions, e.g., 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 state to a document

Sometimes it's necessary to change a document's state based on the workflow state. This can be achieved using tags assigned to a single group with exclusivity enabled (in that case, setting a new tag from the same group cancels the others). Implementation is again done via flexibee-xml, which you call whenever the workflow state changes:

<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>


Related

Did this answer your question?