Пользовательская задача
Обзор
Пользовательская задача — это задача, которая назначается пользователю или группе для выполнения вручную в рамках бизнес-процесса. Пользовательские задачи — неотъемлемая часть рабочего процесса: через них люди взаимодействуют с процессом, выполняя конкретные действия, принимая решения или вводя данные.
|
Один исполнитель или группа В BPMN у задачи может быть только один исполнитель. Когда говорят «задача назначена группе», имеют в виду список потенциальных исполнителей, а не объект UserGroup. Один из них должен стать фактическим исполнителем, забрав задачу. |
Пользовательская задача изображается как обычная задача (прямоугольник со скругленными углами) с небольшим значком пользователя в левом верхнем углу.
В XML пользовательская задача определяется так.
Атрибут id обязателен, атрибут name необязателен.
<userTask id="user-task-01" name="User task" />
Свойства
В моделере BPMN можно задать следующие свойства пользовательской задачи:
Свойство |
Описание |
Id |
Идентификатор элемента. Он генерируется автоматически, но его можно заменить на более понятный, чтобы логи было проще читать. |
Name |
Имя задачи, не более 255 символов. Обычно задачи называют по схеме «глагол + объект», например «Согласовать заказ» или «Отправить счет». |
Due date |
Дата, к которой задача должна быть выполнена. См. Срок выполнения. |
Business calendar name |
Бизнес-календарь, по которому рассчитывается срок выполнения. См. Использование бизнес-календаря. |
Assignee |
Исполнитель задачи или потенциальные исполнители (кандидаты). См. Назначение исполнителя. |
Form |
Пользовательский интерфейс задачи. См. Процессные формы пользовательской задачи. |
Multi instance |
|
Task listeners |
Слушатели, которые срабатывают на события жизненного цикла задачи. См. Настройка слушателей задач. |
Notifications |
Уведомления, которые отправляются при событиях задачи. См. Уведомления. |
Execution listeners |
См. Слушатели выполнения. |
Extension properties |
См. Свойства расширения. |
Asynchronous execution |
Начиная с Jmix 3.1 |
Documentation |
См. Документация. |
Срок выполнения
Параметр срок выполнения (due date) пользовательской задачи задает крайний срок, к которому задача должна быть выполнена. Этот параметр важен для управления действиями процесса, зависящими от времени.
| Срок выполнения сам по себе не запускает никаких автоматических действий. Последующие действия нужно настроить вручную. |
Задание срока выполнения
Параметр Due date можно задать двумя способами:
-
Фиксированная дата: дата в будущем, которая означает крайний срок. (Дата в прошлом игнорируется, задача будет показана как просроченная.)
-
Длительность: период времени, отсчитываемый с момента создания задачи.
Фактически срок выполнения — это текстовое поле, которое движок процессов интерпретирует во время выполнения. Доступны следующие варианты:
-
Строка в формате ISO8601, задающая фиксированную дату или длительность.
-
Переменная процесса типа:
-
java.lang.String— должна содержать значение в формате ISO8601. -
java.util.Date— должна содержать дату.
-
-
Выражение, которое во время выполнения вычисляется в один из вариантов выше, например
$/{someDateVariable/}.
|
Примеры ISO 8601
-
Фиксированная дата:
-
2024-02-01T08:40:37
-
2050-01-01
-
-
Длительность:
-
PT20M — через 20 минут
-
PT5H — через 5 часов
-
PT3D — через 3 дня
-
Работа со сроком выполнения из кода
Параметром due date можно управлять с помощью методов класса Task:
Task task = taskService.createTaskQuery()
.taskId("taskId").singleResult(); (1)
task.getDueDate(); (2)
task.setDueDate(null); (3)
taskService.saveTask(task); (4)
| 1 | получение задачи по id |
| 2 | получение текущего срока выполнения |
| 3 | установка нового срока выполнения, равного null |
| 4 | сохранение объекта задачи |
Так можно динамически менять сроки выполнения в зависимости от бизнес-логики. Например, исполнитель может попросить дополнительное время на выполнение задачи.
Использование бизнес-календаря
Если установлено дополнение Business Calendars, в разделе свойств General на экране Web BPM Modeler появляется поле бизнес-календаря:
Здесь можно выбрать один из заранее настроенных бизнес-календарей в выпадающем списке. В этом случае срок выполнения можно задать только как длительность, а прошедшее время рассчитывается с учетом бизнес-календаря.
Например, пользователь получил задачу в 16:00.
В бизнес-календаре стандартное рабочее время — с 10:00 до 18:00,
а срок выполнения задан как 3 часа (PT3H).
Крайний срок будет не в 19:00, через 3 часа, а в 11:00 следующего рабочего дня. С бизнес-календарем учитываются только рабочие часы.
|
С бизнес-календарем длительность можно задать в часах и минутах, но не в днях. |
XML-представление Пользовательская задача со сроком выполнения:
<userTask id="Activity_0gsy9yk" name="User task"
flowable:dueDate="PT3H" (1)
flowable:businessCalendarName="test-calendar"> (2)
. . .
</userTask>
| 1 | срок выполнения в виде длительности |
| 2 | атрибут бизнес-календаря |
Подробнее см. в описании дополнения Business Calendars.
Назначение исполнителя
Чтобы задачу можно было выполнить, ей нужно назначить исполнителя. Исполнителем задачи может быть назначен только один пользователь, его называют assignee.
Атрибут assignee может быть пустым. Это значит, что ни у одного пользователя эта задача не отображается в списке задач.
Обычно такая задача считается групповой: у нее есть список потенциальных исполнителей, или кандидатов.
Кроме того, исполнителя можно назначить во время выполнения — с помощью административных функций или из кода.
Источники исполнителя
В Jmix BPM источник исполнителя (assignee source) — это способ, которым определяется пользователь, назначаемый исполнителем конкретной пользовательской задачи в бизнес-процессе. Есть три варианта:
| Expression |
Выражение, результат которого — строка с именем пользователя. |
| Process variable |
Переменная, которая ссылается на сущность User. |
| User provider |
Java-класс с методом, который возвращает имя пользователя. |
Назначение задачи по выражению
Выражение — источник исполнителя по умолчанию.
Нужно написать выражение, которое вычисляет имя пользователя-исполнителя.
Например, если сущность User хранится в переменной процесса manager, выражение будет таким: ${manager.username}:
XML-представление
<userTask id="user-task-01" name="User task"
flowable:assignee="${manager.username}"
jmix:assigneeSource="expression"
jmix:assigneeValue="${manager.username}" />
Чтобы назначить задачу конкретному пользователю, можно указать имя пользователя напрямую:
Также можно вызвать метод бина Spring, который возвращает имя пользователя:
${smpl_MyBean.evaluateManager(methodParam1, 'methodParam2')}
Назначение задачи по переменной процесса
Если выбрать источник исполнителя Process variable, на панели свойств появляется компонент ComboBox. В нем отображаются поля и переменные процесса типа Entity, класс сущности которых реализует интерфейс UserDetails.
Встроенная переменная initiator
При моделировании процесса для назначения задач доступна встроенная переменная процесса initiator. Она содержит сущность пользователя, который запустил процесс:
XML-представление
Пользовательская задача с исполнителем, назначенным по переменной процесса:
<userTask id="user-task-01" name="User task"
camunda:assignee="${initiator.username}"
jmix:assigneeSource="processVariable"
jmix:assigneeValue="initiator" />
|
Если процесс запущен через API или сообщением либо сигналом, переменная |
Переменную процесса initiator можно отключить с помощью следующего свойства:
jmix.bpm.process-initiator-variable-enabled=false
Также можно изменить имя переменной initiator:
jmix.bpm.process-initiator-variable-name=manager
Назначение задачи через поставщика пользователей
Если для определения исполнителя задачи нужна сложная бизнес-логика, лучше выбрать вариант User provider. В этом случае система предлагает выбрать существующий Java-класс поставщика пользователей:
Класс поставщика пользователей должен реализовать один или несколько методов, возвращающих String.
Метод получает значения параметров, заданные в моделере, и возвращает имя пользователя, который становится исполнителем задачи.
XML-представление
Пользовательская задача с исполнителем, назначенным через поставщика пользователей:
<userTask id="user-task" name="User task" jmix:assigneeSource="userProvider" jmix:assigneeValue="smpl_MyUserProvider">
<extensionElements>
<jmix:springBean beanName="smpl_MyUserProvider" methodName="getUser" />
</extensionElements>
</userTask>
Класс поставщика пользователей — это обычный бин Spring с аннотацией @UserProvider.
Вот пример поставщика пользователей, который читает переменную процесса с адресом электронной почты пользователя и находит пользователя в базе данных.
@UserProvider(value = "smpl_MyUserProvider", description = "Returns a user with the specified email")
public class MyUserProvider {
@Autowired
private DataManager dataManager;
public String getUserByEmail(String parameter) {
return dataManager.load(User.class)
.query("select u from smpl_User u where u.email = :email")
.parameter("email", parameter)
.one()
.getUsername();
}
}
В классе UserProvider можно реализовать любые бизнес-правила.
Например, выбрать наименее загруженного пользователя из роли или отдела, выбрать следующего по очереди или хотя бы случайного пользователя из группы.
Назначение задач по полосе
Пользовательская задача, расположенная на полосе, может получать исполнителя и кандидатов от полосы. Чтобы задать их, выберите полосу:
Свойство |
Описание |
Id |
Идентификатор элемента. Он генерируется автоматически, но его можно заменить на более понятный, чтобы логи было проще читать. |
Name |
Имя элемента. |
Assignee source |
Назначение исполнителя по выражению, переменной процесса или через поставщика пользователей. См. Источники исполнителя. |
Candidate groups |
Группа пользователей, которым разрешено выполнять действия в пределах полосы. |
Candidate users |
Отдельные пользователи, которым разрешено выполнять действия в пределах полосы. |
Documentation |
Описание и дополнительные сведения об элементе. |
При развертывании процесса движок проверяет каждую пользовательскую задачу на полосе. Если у задачи нет ни исполнителя, ни групп-кандидатов, она получает исполнителя, пользователей-кандидатов и группы-кандидатов, заданные полосой. Пользователи-кандидаты полосы заменяют собственных пользователей-кандидатов задачи. Если у задачи есть исполнитель или группы-кандидаты, движок игнорирует полосу.
В XML полосы представлены элементом laneSet и его элементами lane. Каждый элемент lane содержит свойства назначения и список размещенных на полосе элементов.
<process id="pool-and-lanes" name="Pool and lanes" isExecutable="true">
<laneSet id="LaneSet_1lxq2l3">
<lane id="Lane_1" name="User 1">
<extensionElements>
<jmix:assignmentDetails assigneeSource="expression" assigneeValue="user1" assignee="user1" candidateUsersSource="users" candidateGroupsSource="userGroups" />
</extensionElements>
<flowNodeRef>Activity_0n34ol9</flowNodeRef>
<flowNodeRef>Activity_0758bjc</flowNodeRef>
<flowNodeRef>Event_1mkoyrv</flowNodeRef>
</lane>
<lane id="Lane_2" name="User 2">
...
</lane>
</laneSet>
Назначение задачи из кода
Чтобы задать исполнителя задачи из кода, используйте метод setAssignee сервиса TaskService. Пример:
Task task = taskService.createTaskQuery()
.taskId("taskId")
.singleResult(); (1)
taskService.setAssignee(task.getId(), "jane"); (2)
| 1 | получение объекта задачи через Query API |
| 2 | назначение исполнителя по имени пользователя |
Задачи, назначенные определенному пользователю, можно получить через TaskService так:
List<Task> tasks = taskService.createTaskQuery()
.taskAssignee("jane") (1)
.list();
| 1 | имя пользователя |
Пользователи-кандидаты и группы-кандидаты задачи
Кандидаты — это пользователи или группы, которые могут забрать задачу и выполнить ее. Если у задачи несколько кандидатов, задача появляется в списках задач всех кандидатов. Первый кандидат, который забирает задачу, становится исполнителем и может выполнить задачу. После этого задача перестает быть видна другим кандидатам.
|
Под «группами» здесь технически понимается список кодов User group. |
Как забрать групповую задачу
Часто не важно, какой именно пользователь выполнит задачу. Например, менеджеру все равно, кто из двух бухгалтеров примет решение по его заказу.
В этом случае Jmix BPM позволяет назначить задачу списку кандидатов, и исполнителем может стать любой из них. Но сначала он должен забрать задачу. Забрать задачу — значит назначить ее на себя.
Задача с кандидатами появляется на экране My tasks в разделе Group tasks у каждого кандидата.
После того как один из кандидатов забирает задачу, она переходит в список Assigned tasks этого пользователя и исчезает из списка Group tasks остальных кандидатов.
Чтобы забрать задачу, пользователь должен открыть ее и выполнить одно из действий:
-
Claim and resume — пользователь становится исполнителем задачи, форма задачи открывается заново в обычном режиме, и с ней можно продолжить работу.
-
Claim and close — пользователь становится исполнителем задачи, форма задачи закрывается; позже ее можно найти в разделе Assigned tasks списка задач:
Как забрать задачу из кода
Через API задачу можно забрать от имени указанного пользователя:
taskService.claim("taskId", "userId");
Задание кандидатов в моделере
Чтобы задать группы-кандидаты, нажмите кнопку Edit:
Откроется окно Candidate groups editor, где можно выбрать источник групп-кандидатов:
-
User groups — выбор групп пользователей из списка.
-
User groups provider — выбор специального Java-класса, который возвращает список групп пользователей.
-
Expression — получение списка групп пользователей из выражения, например из переменной процесса, определенной ранее в процессе.
Задание кандидатов по группам пользователей
Если в качестве источника выбран вариант User groups, можно выбрать любую из существующих групп пользователей:
Поставщик групп пользователей
Если при задании групп-кандидатов нужна сложная логика, лучше выбрать вариант User groups provider.
Он позволяет выбрать один из ранее созданных бинов Java с аннотацией @UserGroupListProvider.
Этот бин должен реализовать один или несколько методов, которые возвращают List<String> с кодами групп пользователей.
У аннотации @UserGroupListProvider два атрибута:
-
value — имя, которое отображается в моделере.
-
description — необязательное пояснение назначения метода.
Пример:
@UserGroupListProvider(value="allGroups",
description = "Returns a list of all groups")
public class MyGroupListProvider {
@Autowired
private UserGroupService userGroupService;
public List<String> getAllUserGroups() {
List<UserGroup> allUserGroups = userGroupService.getAllUserGroups();
if (!allUserGroups.isEmpty()) {
return allUserGroups.stream().map(UserGroup::getCode).toList();
} else {
return Collections.emptyList();
}
}
}
Подробнее см. в разделе User groups.
Задание групп-кандидатов выражением
Самый общий способ задать параметры BPMN — выражение. Для групп-кандидатов он тоже доступен:
Варианты задания пользователей-кандидатов
Пользователи-кандидаты задаются на экране Web BPM Modeler почти так же, как группы-кандидаты. Доступны следующие источники:
-
User groups — выбор имен пользователей из списка.
-
User groups provider — выбор специального Java-класса, который возвращает список имен пользователей.
-
Expression — получение списка имен пользователей из выражения.
Поставщик списка пользователей
Как и в случае с User Groups Provider, список пользователей-кандидатов можно получить из кода,
вызвав метод бина Spring с аннотацией @UserListProvider:
Пример:
@UserListProvider(value = "smpl_UserListProviderDemo",
description = "Get all users")
public class UserListProviderDemo {
@Autowired
private DataManager dataManager;
@Autowired
private SystemAuthenticator authenticator;
public List<String> getAllUsers() {
authenticator.begin();
try {
List<User> users = dataManager.load(User.class).all().list();
return users.stream().map(User::getUsername).toList();
} finally {
authenticator.end();
}
}
}
Задание пользователей-кандидатов выражением
Также можно использовать самый общий способ задать параметр модели процесса — выражение:
Например, так можно сослаться на имя пользователя из переменной с сущностью User:
${initiator.username}
CandidateUsers и candidateGroups можно задать в одной и той же пользовательской задаче.
Процессные формы пользовательской задачи
Для пользовательской задачи можно настроить процессную форму, чтобы помочь исполнителю ввести данные, необходимые для задачи. Затем собранные данные можно передать дальше в процесс.
Множественный экземпляр
Пользовательские задачи могут выполняться как множественный экземпляр. Подробнее об этом режиме см. в разделе Множественный экземпляр.
Настройка слушателей задач
Пользовательские задачи в Jmix BPM поддерживают слушатели задач, которые выполняют собственную логику в ответ на события задачи. Слушатели задач позволяют задать Java-классы или выражения, которые срабатывают при событиях пользовательской задачи.
Слушатели задач могут реагировать на следующие события пользовательской задачи:
-
create: срабатывает, когда пользовательская задача создана и заданы ее свойства, включая исполнителя.
-
assignment: срабатывает, когда меняется исполнитель пользовательской задачи. Если задача получает исполнителя при создании, assignment срабатывает перед create. Добавление пользователей-кандидатов или групп-кандидатов его не вызывает.
-
complete: срабатывает, когда пользовательская задача выполнена, перед delete.
-
delete: срабатывает перед удалением пользовательской задачи из данных времени выполнения — после complete или когда задача удаляется, например вместе с экземпляром процесса.
Чтобы настроить слушатель задач для пользовательской задачи, используйте элемент расширения flowable:taskListener в BPMN XML
или метод addTaskListener в Java API.
Слушатели задач — мощный механизм, который расширяет поведение пользовательских задач и встраивает в процессы собственную логику. С их помощью можно отправлять уведомления, обновлять внешние системы или выполнять дополнительные проверки в ответ на события жизненного цикла пользовательской задачи.
XML-представление
<userTask id="approve-invoice" name="Approve invoice" jmix:assigneeSource="expression">
<extensionElements>
. . .
<flowable:taskListener class="com.company.demo.listener.ApproverAssignment" (1)
event="assignment" /> (2)
</extensionElements>
. . .
</userTask>
| 1 | Класс слушателя задач |
| 2 | Событие задачи |
Уведомления
Начиная с Jmix 3.1
Пользовательская задача может отправлять уведомления в приложении и по электронной почте через дополнение Notifications, поэтому это дополнение обязательно. Без него моделер не показывает раздел Notifications пользовательских задач, а во время выполнения процесс не отправляет уведомления.
Другие дополнения расширяют эти возможности:
-
Email Sending включает канал Email. См. Канал Email.
-
Message Templates позволяет формировать текст из шаблона. См. Шаблоны сообщений в уведомлениях.
Чтобы выбирать тип уведомления в моделере, зарегистрируйте типы, как описано в разделе Типы уведомлений. Чтобы читать уведомления в приложении, получателям нужна роль, описанная в разделе Роли безопасности.
Каждое уведомление отправляется при событии задачи, выбранном в его свойстве Event: create, assignment, complete или delete. Это события слушателей задач, и Jmix BPM добавляет эти слушатели при развертывании процесса. Движок генерирует delete, когда задача выполнена, сразу после complete, а также когда прерывающее граничное событие отменяет задачу или удаляется экземпляр процесса.
Чтобы отправить уведомление в другой момент, прикрепите к задаче граничное событие и соедините его с задачей отправки уведомления. Например, непрерывающее граничное событие таймера может уведомить инициатора процесса, что задача не выполнена вовремя.
XML-представление
<userTask id="approve-order" name="Approve order">
<extensionElements>
<jmix:notification event="assignment" recipientType="assignee"
channels="in-app" contentType="plain">
<jmix:subject>Task assigned: ${context.taskName}</jmix:subject>
<jmix:body>Hello ${context.recipientUser.username}, please approve order ${order.number}.</jmix:body>
</jmix:notification>
</extensionElements>
</userTask>
В уведомлениях пользовательской задачи у объекта context, описанного в разделе Выражения в уведомлениях, также есть свойства taskId и taskName с id и именем задачи и свойство taskAssigneeUser с ее исполнителем.
Свойства уведомления
Раздел Notifications показывает список уведомлений. Для управления ими используйте кнопки Create, Edit и Remove. У уведомления есть следующие свойства:
Свойство |
Описание |
Subject |
Тема уведомления. Обязательное свойство. Может содержать выражения. |
Type |
Необязательный тип уведомления. Задает значок уведомления в UI. Список показывает зарегистрированные типы; также можно ввести имя типа. |
Event |
Событие задачи, при котором отправляется уведомление. Обязательное свойство. См. Уведомления. |
Recipient |
Кто получает уведомление. Обязательное свойство. См. Получатели уведомлений. |
Recipient expression |
Выражение, которое возвращает получателей. Показывается, если Recipient имеет значение Expression. |
Channels |
In-app, Email или оба. Нужен хотя бы один канал. По умолчанию выбран In-app. Email доступен, если установлено дополнение Email Sending. |
Use message template, Message template |
Шаблон, по которому формируется текст. Доступно, если установлено дополнение Message Templates. См. Шаблоны сообщений в уведомлениях. |
Content type |
Plain text или HTML. Для HTML текст редактируется в редакторе форматированного текста. Если переключиться с HTML на обычный текст, моделер запрашивает подтверждение и очищает текст. Скрыто, если используется шаблон сообщения. |
Body |
Текст уведомления. Может содержать выражения. Скрыто, если используется шаблон сообщения. |
В XML каждое уведомление — это элемент расширения jmix:notification. Его атрибуты: recipientType, recipientExpression, channels, type, contentType и templateCode; дочерние элементы: jmix:subject и jmix:body. Атрибут event хранит событие.
Получатели уведомлений
| Recipient | Значение в XML | Описание |
|---|---|---|
Task assignee |
|
Если у задачи нет исполнителя, уведомление не отправляется. |
Candidate users |
|
|
Candidate groups |
|
Все пользователи групп-кандидатов задачи, в соответствии с типом группы. |
Process initiator |
|
Пользователь, сохраненный в переменной процесса initiator. |
Expression |
|
Результат Recipient expression. Выражение может возвращать имя пользователя, пользователя или их коллекцию, например |
Каждый получатель получает отдельное уведомление, а тема и текст формируются для этого получателя. Пользователь получает одно уведомление, даже если он найден несколько раз, например в двух группах-кандидатах. Имя пользователя, которому не соответствует существующий пользователь, пропускается.
Выражения в уведомлениях
Тема и текст — это выражения Flowable, например ${order.number} или ${context.recipientUser.username}. Значения вставляются с помощью toString(), поэтому для форматирования вызывайте методы, например ${order.date.getYear()}.
У объекта context есть следующие свойства:
| Свойство | Описание |
|---|---|
|
Пользователь, который получает это уведомление. |
|
Id экземпляра процесса. |
|
Id и имя определения процесса. |
|
Id исполнения. |
|
Map переменных процесса, например |
В теме и тексте context всегда означает контекст уведомления, даже если у процесса есть переменная с таким именем.
|
Шаблоны сообщений в уведомлениях
Если уведомление использует шаблон сообщения, шаблон формирует только текст. Тема по-прежнему берется из свойства Subject и использует выражения Flowable, а шаблон использует синтаксис FreeMarker.
Параметры шаблона заполняются из переменных процесса: алиас каждого параметра должен совпадать с именем переменной процесса. Например, если у процесса есть переменная order, добавьте параметр order и используйте ${order.number} в шаблоне. Объект context, описанный в разделе Выражения в уведомлениях, тоже доступен. Значения параметров по умолчанию не используются. Если шаблон ссылается на отсутствующую переменную, уведомление не отправляется, а ошибка записывается в лог.
Ошибки в уведомлениях
Уведомления не прерывают процесс. Если выражение завершается ошибкой или уведомление не удается отправить, ошибка записывается в лог и процесс продолжается. Другие уведомления и другие получатели того же уведомления не затрагиваются.
Уведомления в приложении сохраняются в отдельной транзакции, поэтому остаются, даже если транзакция процесса позже откатывается. Электронные письма отправляются асинхронно дополнением Email Sending. Получатель без адреса электронной почты не получает письмо, а в лог записывается предупреждение.
Документация
Дополнительную информацию для пользователя можно указать в параметре documentation (так он называется в BPMN) или description (так он называется в API). Его длина не может превышать 4000 символов.
Изначально поле documentation было предназначено для документирования модели процесса аналитиками. Но в пользовательской задаче его можно рассматривать как инструкцию для пользователя, объясняющую, что нужно сделать.
Это поле находится в самом конце панели свойств.
| Поле documentation можно обновлять при каждом изменении процесса. Это самый простой и эффективный способ давать пользователям актуальную информацию. |