Понял, большое спасибо. Думал listener вешать, но через сервисный шаг даже читабельнее …
Максим, добрый день.
.view("procInstance-listener-view")
Не пойму где взять/создать эту вьюшку
В сообщении выше есть ссылка на демо-проект. Там вы можете поиском воспользоваться и найдете места объявления и использования вьюшки.
Тестовый проект падает на этой строчке ((
Может гляните что не так у меня то.
bpmdemo-roles.zip (78.4 КБ)
Кто бы еще писал ошибку с которой “падает” и путь воспроизведения проблемы на демо-проекте…
Попытался угадать…
Я под admin создал экземпляр Contract, создал ручками экз. приложенного процесса (BPM/Экземпляры процесса), связал с созданным экз. Contract, запустил процесс, принял процессную задачу, выполнил для нее процессное действие “Удалить”.
Все отработало без ошибок.
Могу предположить, что у вас dataManager.load(..).id(...).one()
кидает
IllegalStateException, а такое случается, если по данному ID сущности в БД не обнаружено.
О чем сказано в Javdoc
Добрый день, Андрей. Спасибо что помогаете ))
Если создавать ручками то все действительно отработало без ошибок, и процесс роль связывает задачу с ролью куба.
Но если это делать с экрана контракта, то падает ошибка:
И теперь еще больше не понятна причина, почему ручками отрабатывает, а при “автоматизации” нет.
Спасибо
Но если это делать с экрана контракта, то падает ошибка
Как говорится “не могу не подтвердить, ни опровергнуть”.
В приведено демо-проекте нет возможности запустить процесс с контракта.
Собственно, в контроллере ContractBrowse
нет рабочего кода который позволил бы запустить процесс с размещенного внизу procActionsFragment
при выделенным Contract. А на экране ContractEdit
вообще нет procActionsFragment
.
Но судя по ошибке - проблема с чтением конкретного экземпляра procInstance
по id.
Как вариант - есть ограничения для этой сущности, которые скрывают этот или все экземпляры procInstance
от пользователя, выполняющего действие.
Андрей ещё раз спасибо за помощь, нужно выделить сущность, нажать кнопку обновить процесс, и внизу будет активным окно запуска( фрагмент).
Если использовать приложенную тут модель процесса - фрагмент не станет активным
Можете проверить.
Странно, все работает, из изменения только фрагмент на верх кинул для удобства.
Конечно, у вас работает, потому что модель процесса другая.
Скачайте то, что вы выложили в эту ветку.
Контроллер ContractBrowse
private static final String PROCESS_CODE = "delete";
....
...
procActionsFragment.initializer()
.standard()
.init(PROCESS_CODE, contractsTable.getSingleSelected());
Открываем вашу модель процесса
Ладно, “обработал напильником” тестовый проект и смог под отладчиком вашу ошибку поймать.
Пробовали вот тут ставить точку останова и заглянуть в БД на тему того, есть ли в БД ProcInstance с данным ID?
На момент выполнения этого кода, ProcInstance таким ID еще не успел сохраниться в БД.
У вас в модели сразу идет вызов bpmdemo_ProcRolesHelper.fillProcRoles('boss', 'Administrators', bpmProcInstanceId)
.
В процессной переменной bpmProcInstanceId
ID экземпляра уже есть, он СУБД еще не успела сохранить экземпляр.
Попробуйте перенести действия с только что стартовавшим процессом из модели процесса в ProcActionsFragment
в слушатель setAfterStartProcessListener()
.
Спасибо, но не прокатило ))
bpmdemo-test.zip (79.6 КБ) Удаление заявки.json (10.7 КБ)
Ребят, вот итоговая демка и модель. Так и не могу решить как исправить этот эксепшен:
Как советовал Андрей выше, я пробывал через слушатель setAfterStartProcessListener()
, результат такой: роли подставляются, но не назначаются, я думаю это связано с тем, что процесс уже запущен на момент назначения роли, а потом просто подставляет роль. Хотелось бы решить эту проблему. Так же пробывал сделать этот сервисом, результат такой же как вызывать эти методы таском через модель из бина - экспешен такой же как на скрине.
Спасибо.
В вашем случае проблема следующая: вы стартуете новый процесс - в этот момент открывается новая транзакция БД. В этой транзакции создаётся экземпляр ProcInstance. Затем в этой же транзакции управление переходит к первому элементу процесса (вызов ProcRolesHelper)
Внутри ProcRolesHelper вы используете DataManager для поиска экземпляра ProcInstance, но DataManager создаёт новую транзакцию, а предыдущая транзакция ещё не закоммичена. Поэтому метод load ничего и не возвращает.
Вариант1 - можете попробовать использовать TransactionalDataManager - он не создаёт новую транзакцию, а присоединяется к текущей.
Вариант 2 - если участники процесса у вас заполняются при старте процесса, а не где-то в середине его выполнения, то использовать подход с сервисом, заполняющим роли, смысла не имеет. Вот пример как задать участников процесса программно из контроллера экрана.
Спасибо, Максим, буду пробывать первый вариант. Второй вариант теряют всю суть - для измениния согласующего нужен разработчик, а не человек с учеткой админа. Еще раз спасибо
Максим, спасибо. Первый вариант сработал отлично. Почти все заработало
Я так понимаю менеджер тразакция не может сейвить контекст, только ентити. Может есть вариант делать коммит после “получения” id процесса, что бы было что грузить из БД.
package com.company.bpmdemo.core;
import com.haulmont.bpm.entity.ProcActor;
import com.haulmont.bpm.entity.ProcInstance;
import com.haulmont.bpm.entity.ProcRole;
import com.haulmont.cuba.core.TransactionalDataManager;
import com.haulmont.cuba.core.global.DataManager;
import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.security.entity.User;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
@Component(ProcRolesHelper.NAME)
public class ProcRolesHelper {
public static final String NAME = "bpmdemo_ProcRolesHelper";
@Inject
private Logger log;
@Inject
private DataManager dataManager;
@Inject
private Metadata metadata;
@Inject
private TransactionalDataManager transactionalDataManager;
public void fillProcRoles(String procRoleCode, String secRoleName, UUID bpmProcInstanceId) {
ProcInstance procInstance = transactionalDataManager.load(ProcInstance.class)
.id(bpmProcInstanceId)
.view("procInstance-listener-view")
.one();
Optional<ProcRole> procRoleOpt = procInstance.getProcDefinition().getProcRoles().stream()
.filter(procRole -> procRole.getCode().equals(procRoleCode))
.findAny();
if (!procRoleOpt.isPresent()) {
log.error("ProcRole {} not found", procRoleCode);
return;
}
List<User> usersWithSecRole = findUsersBySecRole(secRoleName);
List<ProcActor> procActorsToCreate = new ArrayList<>();
for (User user : usersWithSecRole) {
ProcActor procActor = metadata.create(ProcActor.class);
procActor.setUser(user);
procActor.setProcInstance(procInstance);
procActor.setProcRole(procRoleOpt.get());
procActorsToCreate.add(procActor);
transactionalDataManager.save(procActor);
}
}
private List<User> findUsersBySecRole(String secRoleName) {
return dataManager.load(User.class)
.query("select u from sec$User u join u.userRoles ur join ur.role r where r.name = :secRoleName")
.parameter("secRoleName", secRoleName)
.list();
}
}
Максим, если заменяем DataManager на TransactionalDataManager, то в итоге не можем закоммитить вот эту штуку : procActorsToCreate.add(procActor);
, раньше это было реализовано через dataManager.commit(new CommitContext(procActorsToCreate));
, как можно выкрутиться из этой ситуации ? Без нее роли конечно назначаются, но только роли и сохраняются, комменты, статус заявки, ничего не меняется, можно бесконечно создавать заявки, фрагмент инициализируется постоянно.
Можете попробовать пойти другим путём.
Можно оставить предыдущий вариант (с обычным DataManager), но отметить в модели элемент Fill approver role как asynchronous
Чтобы флаг заработал, не забудьте в app.properties проставить свойство bpm.activiti.asyncExecutorEnabled в true
Данный флаг укажет на то, что транзакцию надо будет закоммитить перед передачей управления элементу, который назначает роли (см. документацию Activiti)
Максим, спасибо. Это решило все проблемы, а то мне пришлось делать в обход переопределяя стартовый экран процесса, и в контейнер подсовывать свои роли при инициализации. Теперь стало хорошо Еще раз спасибо
Максим добрый день. Подскажите пжл, как можно реализовать вот такую бы схему. Сейчас все работает, но необходимо добавить вот такой “ифчик”. Спасибо