Workflow
The original
workflow
notes are in the app documentation: https://gitlab.com/kb/workflow/blob/master/docs/source/index.rst
Development
Kubernetes
(November 2019) We are trying to use Kubernetes for Development - Install for local development with Flowable on our workstations.
Here are a couple of links to .env
and settings files:
User Manual
Start Event (startEvent
)
Note
13/01/2022, We are adding a user to the process on creation
(process_identity_add_participant
), so perhaps we won’t need the
userPk
in future?
For details, see commit 8361c1103cf09021a795c648cc867ee2549736a6
We need to search for workflow processes started by a user (#5553):
The Flowable
startedBy
filter looks for the owner of the workflow, but we don’t set an owner.As a workaround, we set the
user_pk
in the start event when we create a workflow.
The started_by
filter searches for the userPk
variable in the
_historic_process
and _process_instances
methods (workflow/activiti.py
)
All workflows require a userPk
in the startEvent
e.g:
<startEvent id="startEvent1" flowable:formFieldValidation="true">
<extensionElements>
<flowable:formProperty id="userPk" type="long" required="true"></flowable:formProperty>
</extensionElements>
</startEvent>
Note
If the start event doesn’t include the userPk
, then we throw an
ActivitiError
exception.
Form Fields
Check Box

To create a series of tick boxes, the type
must be boolean
:
<activiti:formProperty id="monday" name="Monday" type="boolean" expression="True"></activiti:formProperty>
<activiti:formProperty id="tuesday" name="Tuesday" type="boolean" expression="True"></activiti:formProperty>
<activiti:formProperty id="wednesday" name="Wednesday" type="boolean" expression="True"></activiti:formProperty>
Form Headings

To create a form heading, add a formProperty
with _heading
appended to
the id
e.g:
<activiti:formProperty id="invoice_heading" name="Invoice Heading" type="string" required="true" writable="false">
The name
will display as the heading.
You can add help text in Settings, Mapping, Mapping, <field name>
,
Help Text.
Note:
writable
must befalse
The property must not have a
value
(not sure where this comes from)If the
name
is empty, you must add help text.
HTTP Task
Add the apiUrl
to the start event.
The requestUrl
will use this variable as follows:
${apiUrl}/refresh-variables/${execution.getProcessInstanceId()}/
See this ticket for an example API and a test workflow: https://www.kbsoftware.co.uk/crm/ticket/4974/
Tip
If you are running Flowable inside Kubernetes, then make sure your
apiUrl
is accessible from there.
Tip
This is a very useful forum post to help with variables in the HTTP task: How should I use PUT/POST in Http task when I am limited to only strings
Mapping
Imported User, import-user
If your workflow includes a user ID in the start event, then select
import-user
to have the full name and email address automatically generated when the workflow is started.The
work
API also regenerates the variables when a task is completed (source code inwork.api._variables_to_save
).
Options
|
Attach a simple PDF document with a table containing the form variables. To get it working, add a form variable with an id of |
|
Copy attachments to Alfresco:
|
|
Will add a Delete Workflow button to the task. This is useful when the workflow is in development as the process can be deleted quickly and easily. |
Permissions
Process
The Workflow
model has two security related fields:
security_history
(can view workflow history for any user)security_history_my
(can view workflow history where they have been involved)
Tip
The code below is for checking the permissions for a single process.
To get a list of workflows where the user has permission, the
WorkflowManager
has security_history
and
security_history_my
methods which can be used.
Start by checking the security_history
. If the user doesn’t have
security_history
permission, check security_history_my
:
def user_has_security_history_for_process(user, process):
"""Does the user have permission to view the history for this process?"""
result = False
workflow = get_workflow(process.process_key)
if workflow.has_security_history(user):
result = True
else:
# permission to view workflows where they have been involved
if workflow.has_security_history_my(user):
# has the user been involved with this process?
activiti = Activiti()
identity_list = activiti.process_identity_list(process.process_id)
if user.pk in set([x.user for x in identity_list]):
result = True
return result
Note
Code from work/service.py
.
Here is an example configuration:
Created two Global Groups where needed i.e. adding the word Delete and then configuring the mapping as shown below.


Hopefully a sensible way to approach this.
Prerequisite
Every task must have the following form variable:
|
The text in the |
Script Task
From JSON process variables - any gotchas?, to save data in json
format:
<scriptTask id="sid-780D1BD8-9E03-4802-8EC3-C944F5B00A67" scriptFormat="javascript" flowable:autoStoreVariables="false">
<script>
<![CDATA[var ObjectMapper = com.fasterxml.jackson.databind.ObjectMapper;
var data = {};
data.name = "Andrea";
var httpTaskData = JSON.stringify(data);
var json = new ObjectMapper().readTree(httpTaskData);
execution.setVariable("httpTaskData", json);]]>
</script>
</scriptTask>
Tip
Make sure the scriptFormat
is set to javascript
.
Management Commands
6699-mapping-export
To export the mapping for a workflow:
django-admin 6699-mapping-export myTempWorkflow
Tip
The management command will create an export file e.g.
myTempWorkflow-mapping-export.json
To import the mapping for the workflow:
django-admin 6699-mapping-import ~/temp/myTempWorkflow-mapping-export.json
create_pending_workflows
Will use ScheduledWorkflowUser.objects.pending_with_options
to check the
database for pending workflows
(created since the first minute of the day) and start them in Activiti.
It takes an optional argument - the name of the process definition e.g:
django-admin.py create_pending_workflows timeOff
history-process
Call the history_process
API and output some information to a CSV file:
# source ('workflow')
workflow/management/commands/history-process.py
# e.g.
django-admin history-process periodicReview finished 2021-03-12 2021-03-14 document_code
django-admin history-process periodicReview started 2021-03-12 2021-03-14 document_code
Tip
Use started
for workflows started within the two dates.
Use finished
for workflows finishing within the two dates.
Tip
The document_code
in the example above is a variable name to add
to the CSV file.
rest_task
, rest_process
and rest_variable
Tip
Source code for these management commands is in
workflow/management/commands/
Display task data (and find the process ID) e.g:
django-admin rest-task fe485d7c-ce6b-11eb-b755-000d3a7f022c
Display process data e.g:
django-admin rest-process ba224c9a-7db3-11eb-ad2b-000d3a7f022c
# to display the data for one of the variables
django-admin rest-process ba224c9a-7db3-11eb-ad2b-000d3a7f022c documentTitle
Display (and update) a variable e.g:
django-admin rest-variable ba224c9a-7db3-11eb-ad2b-000d3a7f022c documentTitle
# to update the variable
django-admin rest-variable ba224c9a-7db3-11eb-ad2b-000d3a7f022c documentTitle "Management Systems"
Note
rest-variable
can only update string
variables at present.
Feel free to update and improve!
Settings
Activiti
A standard install will have Flowable running on localhost
. To configure
this, add the following settings:
# 'settings/base.py'
ACTIVITI_HOST = 'localhost'
ACTIVITI_PORT = 8080
# 'settings/local.py'
ACTIVITI_PATH = 'activiti-rest'
# 'settings/production.py'
ACTIVITI_PATH = 'activiti-rest-{}'.format(DOMAIN.replace('.', '-').replace('-', '_'))
If Flowable is running on a different server, you can configure the settings differently e.g:
# 'settings/base.py'
ACTIVITI_PORT = 8080
# 'settings/local.py'
ACTIVITI_HOST = 'localhost'
ACTIVITI_PATH = 'activiti-rest'
# 'settings/production.py'
ACTIVITI_HOST = get_env_variable("ACTIVITI_HOST")
ACTIVITI_PATH = 'activiti-rest-{}'.format(DOMAIN.replace('.', '-').replace('-', '_'))
workflow
app
The URL for an API should be added to WORKFLOW_API_URL
.
We also have a WORKFLOW_PLUGIN
system which can be used to add extra
variables to a workflow e.g:
WORKFLOW_API_URL = get_env_variable("WORKFLOW_API_URL")
WORKFLOW_PLUGIN = ("example_workflow.models.WorkflowContact",)
Add the WORKFLOW_API_URL
to the pillar
file for your project.
Warning
Do not append a /
to the end of the WORKFLOW_API_URL
e.g.
http://127.0.0.1:3042/api/0.1
Settings (Dashboard)
History
Settings, Workflow, Tasks has a new History menu option which allows you to filter by workflow type e.g.

Task History
Settings, Workflow, Tasks and clicking on a process, gives you access to Task History:

Task
Delete by ID
from workflow.activiti import Activiti
activiti = Activiti()
# replace `17077`` with your task ID
task = activiti.task_status(17077)
task.process_key
activiti.process_delete(task.process_id)
Owner
To see if a user owns a task, we need to check:
Are they an
assignee
on the task (task.assignee == user.pk
)?Are they a member of the group…