Workflow ******** .. highlight:: python - 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 :doc:`dev-kubernetes-install` for local development with *Flowable* on our workstations. Here are a couple of links to ``.env`` and settings files: - https://gitlab.com/kb/workflow/blob/4645-ember-workflow/.env.fish - https://gitlab.com/kb/workflow/blob/4645-ember-workflow/example_workflow/dev_patrick.py 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:: .. note:: If the start event doesn't include the ``userPk``, then we throw an ``ActivitiError`` exception. Form Fields ----------- Check Box .. image:: ./misc/workflow-form-field-check-box.png To create a series of tick boxes, the ``type`` must be ``boolean``:: Form Headings ------------- .. image:: ./misc/workflow-form-headings.png To create a form heading, add a ``formProperty`` with ``_heading`` appended to the ``id`` e.g:: The ``name`` will display as the heading. You can add help text in *Settings*, *Mapping*, *Mapping*, ````, *Help Text*. Note: - ``writable`` must be ``false`` - 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: .. code-block:: javascript ${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 in ``work.api._variables_to_save``). Options ------- +------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+ | ``dataDocument`` | Attach a simple PDF document with a table containing the form variables. | | | | | | To get it working, add a form variable with an id of ``dataDocument``. | | | The ``name`` will be used as the title e.g: | | | ```` | +------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+ | ``copyToDocumentManagement`` | Copy attachments to Alfresco: | | | | | | ```` | +------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------+ | ``deleteWorkflow`` | 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. .. image:: ./misc/2023-11-15-app-workflow-global-groups.png .. image:: ./misc/2023-11-15-app-workflow-security.png Hopefully a sensible way to approach this. Prerequisite ------------ Every task must have the following form variable: +------------------------------+-----------------------------------------------------------------------------+ | ``auditDescription`` | The text in the ``Expression`` will be added to the audit for this process. | +------------------------------+-----------------------------------------------------------------------------+ Script Task ----------- From `JSON process variables - any gotchas?`_, to save data in ``json`` format: .. code-block:: xml .. 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! Find all workflows for a process key and list a variable:: # source ('workflow') workflow/management/commands/workflow-variable-to-csv.py # e.g. django-admin workflow-variable-to-csv timeOff document_code # Sample output process status created value af3cece6-afb9 Current 10/01/2024 13:10 DOC-1991 9d3bb3e3-afb9 Current 10/01/2024 13:10 DOC-1992 a4176087-afb9 Current 10/01/2024 13:10 DOC-1993 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. .. image:: ./misc/app-workflow-settings-history.png Task History ------------ *Settings*, *Workflow*, *Tasks* and clicking on a process, gives you access to *Task History*: .. image:: ./misc/app-workflow-settings-task-history.png 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: 1. Are they an ``assignee`` on the task (``task.assignee == user.pk``)? 2. Are they a member of the group... .. _`#5553`: https://www.kbsoftware.co.uk/crm/ticket/5553/ .. _`commit 8361c1103cf09021a795c648cc867ee2549736a6`: https://gitlab.com/kb/workflow/-/commit/8361c1103cf09021a795c648cc867ee2549736a6 .. _`How should I use PUT/POST in Http task when I am limited to only strings`: https://forum.flowable.org/t/how-exactly-should-i-use-put-post-in-http-task-when-i-am-limited-to-only-strings-for-request-body/2243/2 .. _`JSON process variables - any gotchas?`: https://forum.flowable.org/t/json-proces-variables-any-gotchas/1798/2