Обзор
Данный модуль для CUBA приложений предоставляет дополнительный функционал по реализации сложных рабочих процессов декларативным путем любых сущностей в системе (заявки, задачи и др.) для которых необходимо как последовательное выполнение определенных действий так и глубокое взаимодействие с пользователями на различных этапах.
Начало работы
Установка Workflow-STP Add-on
Для того, чтобы у пользователя появилась возможность использовать add-on в CUBA.platform приложении необходимо произвести установку add-on в локальный репозиторий пользователя. Рекомендуется делать эту процедуру в Cuba Studio, для этого импортируйте add-on в Cuba Studio и выполните Run -> Install app component.
Подключение Workflow-STP Add-on в CUBA.platform App
Данную операцию рекомендуется выполнять в Cuba Studio. Откройте проект в Cuba Studio и перейдите к редактированию его своств (Project properties -> Edit). Нажмите на + расположенный рядом с надписью Custom components. В выподающем спике (второе поле) должен быть доступен компонент с именем workflow-stp (в случае если вы выполнили его установку ранее). Выберите компонент, нажмите ok, сохраните настройки проекта. Workflow-STP Add-on подключен.
Так же необходимо указать настройку в файле app.properties в core модуле
wfstp.heartbeatMs = 300000
Означающую частоту обновления рабочих процессов (для поддержки таймаутов, своего рода некая допустимая задержка).
В случае если нет необходимости в этом функционале, в аддоне есть специальная надстройка:
workflow.heartbeatEnable = false
Так же модуль предусматривает отложенное обновление для облегчения и быстрого старта приложения. Настройка указывает какое количество "тиков" запланированной задачи система должна пропустить:
workflow.delayCallCount = 2
Описание предметной модели
Описание рабочего процесса состоит из нескольких основных и простых частей. Опишем каждую из них.
Обрабатываемая сущность (WorkflowEntity)
Под обрабатываемой сущностью подразумевается любая сущность в системе для которой необходимо реализовать рабочий процесс обработки. Сущность должна наследоваться от специального интерфейса:
com.groupstp.workflowstp.entity.WorkflowEntity
Которая предоставляет возможность сохранять связь с процессами, помечать текущий статус, а так же прослеживать прогресс обработки.
Рабочий процесс (Workflow)
Под рабочим процессом понимается совокупность заранее определенных шагов и направлений обработки. Иными словами рабочий процесс - это шаблон, описание, по тому как необходимо производить обработку.
- Название(name): Название для быстрой идентификации пользователями.
- Код (code): Машинный шифр для идентификации рабочего процесса системой.
- Активен (active): Флажок означающий что рабочий процесс готов и может быть применен в работу.
- Название применяемой сущности (entityName): Именование сущности для которой описан данный рабочий процесс.
- Шаги (steps): Список определенных в рабочем процессе шагов.
- Порядок (order): Общий порядок рабочего процесса в списке всех рабочих процессов.
Этап (Stage)
Под этапом подразумевается некое абстрактное атомарное состояние процесса обработки. Каждый этап можно разделить на определенный тип, определить действия, поведение и т.д.
- Название(name): Название для быстрой идентификации пользователями.
- Название применяемой сущности (entityName): Именование сущности для которой описан данный этап.
- Тип этапа (type): Тип этапа. Возможные значения: ** Взаимодействие с пользователями (USERS_INTERACTION) - когда ожидается некоторые действия от пользователей в системе ** Архив(ARCHIVE) - состояние, которое не требует непосредственного взаимодействия от пользователей, однако помечает рабочий процесс как завершенный предоставляет возможность постоянного просмотра ** Выполнение алгоритма(ALGORITHM_EXECUTION) - этап подразумевает выполнение системы некоторой последовательности команд.
- Участники (actors): В случае с типом USERS_INTERACTION можно указать конкретных пользователей, от которых ожидается действие.
- Участники по ролям (actorsRoles): В случае с типом USERS_INTERACTION можно указать конкретные роли пользователей, от которых ожидается действие. И если пользователь обладает хоть одной ролью из перечисленных, он является полноправным участником данного этапа.
- Наблюдатели (viewers): В случае с типом USERS_INTERACTION можно указать конкретных пользователей, которые имеют возможность взаимодействовать с этапом, но только в режиме просмотра (viewOnly).
- Наблюдатели по ролям (viewersRoles): В случае с типом USERS_INTERACTION можно указать конкретныt роли пользователей, которые имеют возможность взаимодействовать с этапом, но только в режиме просмотра (viewOnly). И если пользователь обладает хоть одной ролью из перечисленных, он является полноправным наблюдателем данного этапа. В случае если пользователь и наблюдатель и участник - система воспримет его как участника.
- Набор команд для выполнения (executionGroovyScript): В случае с типом ALGORITHM_EXECUTION необходимо предоставить набор команд, которые необходимо выполнить системе.
- Системный сервис выполнения (executionBeanName): В случае с типом ALGORITHM_EXECUTION можно так же просто указать системный сервис для выполнения. Он должен имплементировать интерфейс com.groupstp.workflowstp.service.WorkflowExecutionDelegate. В системе так же предусмотрен базовый класс для com.groupstp.workflowstp.service.AbstractWorkflowExecutionDelegate.
- Описание расширения экрана списков (browserScreenConstructor): В случае с типом USERS_INTERACTION или ARCHIVE можно декларативно задать главные элементы экрана для страницы со списоком.
- Описание расширения экрана редактора (editorScreenConstructor): В случае с типом USERS_INTERACTION или ARCHIVE можно декларативно задать главные элементы экрана для страницы с редактором.
- Общее расширение экрана (screenConstructor): В случае с типом USERS_INTERACTION или ARCHIVE можно декларативно задать общие элементы экранов как для списков так и для редактора.
- Переменные направлений (directionVariables): Перечисление возможных переменных из этапа, которые будут подчищены при движении по одному из направлений.
Шаг (Step)
Сам рабочий процесс представляет собой совокупность допустимых шагов и связей между ними в зависимости от состояния обрабатываемой сущности. Шаг является отсылкой к этапу, имея при этом связи между другими шагами в рабочем процессе.
- Порядок(order): Порядок шага для отображения в пользовательском интерфейсе.
- Начальный(start): Является ли данный шаг начальным для рабочего процесса. Рабочий процесс может иметь только один начальный шаг.
- Этап(stage): Связь шага с этапом. Шаг может иметь только один этап. Этап же может иметь несколько шагов.
- Срок выполнения(timeoutSec): Можно задать максимальное время (в секуднах) при котором если данный шаг не будет выполнен, задача пометится как просроченная и рабочий процесс двинется дальше. При возникновении таймаута, в контекст экземпляра рабочего процесса будет помещена пометка 'wf_timeout' которая может быть легко обработана клиентским кодом.
- Время повторения(repeatSec): Должен ли текущий шаг быть повторен через определенный промежуток времени (в секундах). В данном случае если скрипт шаг вернет отрицательный результат, процесс выполнения данного шага повторится.
- Направления(directions): Возможные направления рабочего процесса на другие шаги от текущего.
- Рабочий процесс(workflow): Связь шага с рабочим процессом.
Направления (StepDirection)
Данная сущность представляет собой условное направление рабочего процесса из одного шага в другой в пределах одного рабочего процесса.
- Порядок(order): Порядок перебора направлений при определении следующего шага в рабочем процессе.
- Откуда(from): Связь с шагом откуда происходит перемещение состояния рабочего процесса.
- Куда(to): Связь с шагом куда происходит перемещение состояния рабочего процесса.
- SQL условие(conditionSqlScript): SQL условие перехода. В данном условии можно описать SQL выражение применимое для обрабатываемой сущности.
- Groovy условие(conditionGroovyScript): Groovy условие перехода. Здесь можно описать условие на высокоуровневом языке Groovy с Java-подобным синтаксисом.
Определение процесса (WorkflowDefinition)
Так как для одной сущности в системе могут существовать одновременно несколько различных рабочих процессов, можно динамически задать условия определения выбора того или иного рабочего процесса в зависимости от обрабатываемой сущности и др.
- Наименование сущности(entityName): Уникальное именование сущности в системе для которой применим данный определитель.
- Рабочий процесс(workflow): Связь с активным рабочим процессом который будет использован в случае удачного применения определителя.
- Приоритет(priority): Приоритет определения. Чем выше приоритет, тем более первым он будет использован для вычисления.
- SQL условие(conditionSqlScript): SQL условие для успешного применения определения.
- Groovy условие(conditionGroovyScript): Groovy условие для успешного применения определения.
Экземпляр рабочего процесса (WorkflowInstance)
При запуске рабочего процесса создается новая отдельная сущность - экземпляр рабочего процесса, которая характеризует и хранит все необходимые данные для обработки.
- Рабочий процесс(workflow): Связь экземпляра рабочего процесса с самим рабочим процессом (шаблоном).
- Наименование сущности(entityName): Уникальное имя сущности в системе.
- Идентификатор сущности(entityId): Уникальный идентификатор конкретной обрабатываемой сущности.
- Контекст переменных исполнения(context): Контекст исполнения экземпляра рабочего процесса содержащий в себе все требуемые переменные и данные которые могут быть сохранены в пределах всего времени выполнения экземпляра рабочего процесса.
- Комментарии(comments): Список возникших комментариев при выполнении экземпляра рабочего процесса.
- Задачи(tasks): Список задач возникших при выполнении экзепляра рабочего процесса, как активных так и завершенных.
- Время начала(startDate): Время запуска рабочего процесса.
- Время завершения(endDate): Время полного завершения текущего рабочего процесса.
- Сообщение об ошибке(error): Сообщение об ошибке в случае неудачного завершения экземпляра рабочего процесса.
- Ошибка получена при выполнении задачи(errorInTask): Возникла ли ошибка при выполнении задачи, или ошибка связана с иными случаями (например обрабатываемая сущность была удалена).
Комментарий (WorkflowInstanceComment)
При выполнении экземпляра рабочего процесса может понадобится возможность оставлять комментарии пользователями при тех или иных обстоятельствах.
- Экземпляр рабочего процесс(instance): Связь комментария и выполняемого экземпляра рабочего процесса.
- Задача (task): Связь комментария с выполняемой задачей рабочего процесса, при котором был создан комментарий.
- Автор(author): Автор комментарий
- Сообщение(comment): Само сообщение комментария
- Вложение(attachment): При создании комментария есть возможность прикрепить любой файл или архив как вложение.
Задача (WorkflowInstanceTask)
При выполнении экземпляра рабочего процесса на каждый шаг описанный в рабочем процесса создается новая задача, которая позволяет управлять и контролировать ход обработки.
- Экземпляр рабочего процесс(instance): Связь задачи и выполняемого экземпляра рабочего процесса.
- Задача (step): Связь задачи с выполняемым шагом описанным в рабочем процесса.
- Время начала(startDate): Время начала задачи, когда экземпляр рабочего процесса изменил текущий шаг.
- Время завершения(endDate): Время завершения задачи, когда экземпляр рабочего процесса выполнил описанный шаг и изменяет свое состояние.
- Исполнитель(performer): Связь на пользователя исполнителя, который завершил текущую задачи и изменил состояние экземпляра рабочего процесса.
Расширение пользовательских экранов
Workflow-STP Add-on предоставляет возможность видоизменять динамически пользовательский интерфейс в зависимости от обрабатываемого шага. Пользователь может при описании рабочего процесса определить какие поля могут быть редактируемые, задать перечень отображаемых колонок, задать их редактируемость. А так же расширить представление экрана путем описания дополнительного Groovy кода.
Модуль так же предоставляет функциональность по определению заранее расширенных и заданных действий, а так же генерализированный экспорт/импорт между системами, что позволяет почти без программирования задать и выдоизменять пользовательский интерфейс.
По умолчанию расширяются стандартные экраны browse и edit обрабатываемых сущностей. Можно переопределить какие экраны необходимо расширять, достаточно поставить аннотацию над требуемой сущностью и определить экраны
com.groupstp.workflowstp.annotation.WorkflowDetails
Например:
@WorkflowDetails(browseId = "my-browse", editorId = "my-edit")
@Entity(name = "wfstpdemo$Ticket")
public class Ticket extends StandardEntity implements WorkflowEntity<UUID> {
...
}
Опишем основные моменты.
ScreenActionTemplate (Действия)
Здесь можно задать некий шаблон действия (кнопку) в случае которого выполнится заранее определенная логика. Рассмотрим на примере создания общей кнопки экспорта в Excel.
- Наименование действия(name): Название действия для быстрой идентификации. Например "Экспорт в Excel".
- Действие всегда доступно(alwaysEnabled): Доступна ли всегда данное действие даже если оно открыто только для просмотра. Например "да".
- Заголовок(caption): Заголовок действия который будет отображен на экране. Например "Excel".
- Иконка(icon): Связь задачи и выполняемого экземпляра рабочего процесса. Например "⇪"
- Стиль(style): Стиль отображения кнопки. При отсутствии будет использован стить по-умолчанию.
- Код выпонения(script): Код на языке Groovy который необходимо выполнить системе для выполнения действия. Например
new com.haulmont.cuba.gui.components.actions.ExcelAction(target).actionPerform(target)
ScreenTableColumnTemplate (Колонки)
При расширении экрана с таблицами можно задать какие колонки будут отображены и в каком виде.
- Наименование колонки(name): Название действия для быстрой идентификации. Например "Колонка аэропортов".
- Заголовок(caption): Заголовок колонки который будет отображен. Например "Аэропорты".
- Идентификатор колонки(columnId): Все колонки в таблице должны имень уникльный идентификатор. Например можно задать "Airport_column" или указать непосредственную связь "invoice.airport"
- Скрипт генерации(generatorScript): Код генерации колонки на языке Groovy который должен вернуть класс:
com.groupstp.workflowstp.web.util.data.ColumnGenerator или com.haulmont.cuba.gui.components.Table.ColumnGenerator
ScreenExtensionTemplate (Экраны)
Модуль так же предоставляет возможность заранее полностью динамически определить отображение целого экрана.
- Наименование экрана(name): Название экрана для быстрой идентификации. Например "Каталог телефонов".
- Ключ экрана(key): Заранее определенный уникальный ключ расширение экрана, который используется для вызова построения. Например "phone-catalog".
- Имя сущности(entityName): Идентификатор-имя обрабатываемой сущности.
- Идентификатор экрана(screenId): Идентификатор экрана системы который может быть расширен.
- Конструктор экрана(screenConstructor): Содержание расширения экрана
Подготовка проекта для интеграции обработки процессами.
Прежде чем приступить непосредственно к реализации рабочих процессов необходимо сначало определить обрабатываемые сущности, определить для них по крайней мере один экран, чуть видоизменив и подготовив его для расширения.
1. Подготовка обрабатываемой сущности.
Прежде всего необходимо расширить специальный интерфейс помечающий указанную сущность в системе как обрабатываемая.
...
import com.groupstp.workflowstp.entity.Workflow;
import com.groupstp.workflowstp.entity.WorkflowEntity;
import com.groupstp.workflowstp.entity.WorkflowEntityStatus;
...
@Entity(name = "wfstpdemo$Ticket")
public class Ticket extends StandardEntity implements WorkflowEntity<UUID> {
private static final long serialVersionUID = 7337017127753361381L;
@Column(name = "STEP_NAME")
private String stepName;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "WORKFLOW_ID")
private Workflow workflow;
@Column(name = "STATUS")
private Integer status;
...
}
2. Подготовка экранов с обрабатываемой сущностью (для рабочих процессов с пользовательским взаимодействием)
Следующий шаг будет подготовка экрана с обрабатываемой сущностью. Необходимо определить позицию для расширяемых действий, а так же определить поля которые будут редактироваться.
Для указания позиции для действий достаточно подключить xsd схему к экрану и указать в корневом элементе XML экрана идентификатор контейнера действий.
<window xmlns="http://schemas.haulmont.com/cuba/window.xsd"
xmlns:wf="http://schemas.groupstp.com/wf/0.1/wf-schema.xsd"
wf:actions="bottomPanel">
<hbox id="bottomPanel" spacing="true"/>
</window>
Для возможности задания редактирования свойств пожалуйста укажите у каждого идентификатор (id)
<fieldGroup id="fieldGroup"
datasource="ds">
<column width="250px">
<field property="urgent" id="urgent"/>
</column>
</fieldGroup>
<richTextArea datasource="ds" property="description" id="description" width="100%" required="true"/>
3. Интеграция с внешними системами
Управление рабочими процессами (отображение колонок, выполнение действий) может быть интегрированно с внешними системами через технологию REST. Сервис который предоставляет данный функционал описан в классе com.groupstp.workflowstp.rest.controller.WorkflowRestAPI В проекте есть дескриптор этого сервиса в формате raml:
#%RAML 0.8
title: REST сервис рабочих процессов
version: v1
baseUri: url_сервера:порт/app/rest/wf/workflow
/all:
get:
description: |
Получить все доступные рабочие процессы с их настройками (действиями, отображаемыми колонками-свойствами, редактируемые поля и т.д.)
responses:
200:
body:
application/json:
example: |
[
{
"id": "920a5902-061e-76b5-882e-91ccca1bccc7",
"name": "Обработка задач",
"code": "A1",
"entity_name": "test$Task",
"steps": [
{
"id": "b55f895e-4bfa-c6df-ceb6-3806261979d0",
"name": "Финансовый контроль",
"entity_name": "test$Task",
"permission": "FULL", //Может быть FULL (полный доступ к шагу), READ_ONLY (шаг доступен только на чтение)
"actions": [//список действий
{
"id": "60131a32-4d64-1b1f-48df-a118049c7163",
"caption": "Согласование",
"icon": "fa-check",
"always_enabled": false,
"style": "primary",
"order": 1
},
{
"id": "f8fc2022-5434-4572-6c5d-757d39a8778b",
"caption": "Excel",
"icon": "fa-file-excel-o",
"always_enabled": true,
"order": 4
},
],
"browser_columns": [//список отображаемых колонок
{
"id": "number",
"caption": "Номер",
"order": 1
},
{
"id": "amount",
"caption": "Сумма",
"order": 2
}
],
"editor_fields": [//список редактируемых свойств
{
"id": "images",
"caption": "Вложения"
},
{
"id": "taxNumber",
"caption": "ИНН"
},
{
"id": "company",
"caption": "Компания"
}
],
"order": 1
},
{
"id": "565ce6a3-fb01-44a0-9ed7-9f3761dcc909",
"name": "Согласование с директором",
"entity_name": "test$Task",
"permission": "READ_ONLY",
"actions": [
{
"id": "0acfa67a-f0dc-53c1-1879-4e53dab154ca",
"caption": "Согласование",
"icon": "fa-check",
"always_enabled": false,
"style": "primary",
"order": 1
},
{
"id": "71399dbc-59a8-036f-744f-eb20db015e72",
"caption": "Excel",
"icon": "fa-file-excel-o",
"always_enabled": true,
"order": 2
}
],
"browser_columns": [
{
"id": "number",
"caption": "Номер",
"order": 1
},
{
"id": "amount",
"caption": "Сумма",
"order": 2
}
],
"editor_fields": [
{
"id": "urgent",
"caption": "Срочность"
}
],
"order": 2
}
],
"order": 1
},
{
"id": "e49e98c9-de58-ecaf-0289-62cf2c4309d2",
"name": "Двойное согласование",
"code": "A2",
"entity_name": "test$Task",
"steps": [],
"order": 2
}
]
/start:
post:
description: |
Запустить рабочий процесс для указанной сущности и получить идентификатор запущенного процесса
queryParameters:
entityId:
type: текст
description: идентификатор сущности
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
entityName:
type: текст
description: имя сущности
example: 'test$Task'
required: true
responses:
200:
body:
application/json:
example: |
{
"result": "b34c8ad4-1e05-4119-ee14-1fb30e86fc8c"
}
/processing:
get:
description: |
Получить информацию запущена ли сущность в рабочий процесс, и если да, система вернет идентификатор запущенного процесса
queryParameters:
entityId:
type: текст
description: идентификатор сущности
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
entityName:
type: текст
description: имя сущности
example: 'test$Task'
required: true
responses:
200:
body:
application/json:
example: |
{
"result": "b34c8ad4-1e05-4119-ee14-1fb30e86fc8c"
}
/performable:
get:
description: |
Получить информацию о том возможно ли выполнить указанное действие для указанных сущностей в текущий момент или нет
queryParameters:
entityId:
type: список
description: идентификаторы сущностей
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
workflowId:
type: текст
description: идентификатор рабочего процесса
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
stepId:
type: текст
description: идентификаторы выполняемого шага
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
actionId:
type: список
description: идентификаторы проверяемых действий
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
responses:
200:
body:
application/json:
example: |
{
"result": {
"cb6ee232-d82d-43b2-6775-ad4e91613523": true,
"c5896b1d-bb27-7c50-2bd7-debc0bab0ec2": true
}
}
/perform:
post:
description: |
Произвести выполнение указанного действия текущим пользователем для указанных сущностей
queryParameters:
entityId:
type: список
description: идентификаторы сущностей
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
workflowId:
type: текст
description: идентификатор рабочего процесса
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
stepId:
type: текст
description: идентификаторы выполняемого шага
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
actionId:
type: текст
description: идентификатор действия
example: e49e98c9-de58-ecaf-0289-62cf2c4309d2
required: true
body: |
Любая полезная нагрузка
responses:
200:
body:
application/json:
example: |
{
"result": "Success"
}
Дополнение A: Свойства модуля.
Основные свойства
workflow.showSelection
- Description: Показывать ли дополнительную колонку выбора при расширении таблиц экрана.
- Default value: true
- Type: Используется на web уровне
- Interface: WorkflowWebConfig
workflow.printScreenExtensionScripts
- Description: Выводить ли в лог файл сгенерированные Groovy коды экранов расширений.
- Default value: false
- Type: Используется на web уровне
- Interface: WorkflowWebConfig
Дополнение Б: Основная логика.
Вся основная логика рабочих процессов обрабатывается в Spring контекстах в двух модулях. Рекомендуется ознакомится с ними.
На core модуле сервис отвечающий за работоспособность рабочих процессов:
com.groupstp.workflowstp.service.WorkflowService
На web модуле сервис отвечающий за расширение экранов и действий:
com.groupstp.workflowstp.web.bean.WorkflowWebBean
Дополнение В: Вспомогательные классы-помощники.
Workflow-STP Add-on поставляется с заранее определенным набором вспомогательных классов для быстрого описания рабочих процессов. При написании кода выполнения рабочих процессов рекомендуется с ними ознакомиться и, в случае необходимости, расширить.
com.groupstp.workflowstp.web.util.MapHelper
Класс для быстрого создания структур типа Ключ-Значение
com.groupstp.workflowstp.web.util.WebUiHelper
Класс для выполнения и обработки рабочих процессов на web модуле приложения.
com.groupstp.workflowstp.web.util.WorkflowInstanceHelper
Класс для работы с экземплярами рабочих процессов.
com.groupstp.workflowstp.rest.util.RestUiHelper
Класс для выполнения и обработки рабочих процессов на rest модуле приложения.
Дополнение Г: Тестовый проект
Самый простой проект использующий данный модуль.
- https://github.com/gecrepo/wfstp-demo