Если использовать приложенную тут модель процесса - фрагмент не станет активным
Можете проверить.
Странно, все работает, из изменения только фрагмент на верх кинул для удобства.
Конечно, у вас работает, потому что модель процесса другая.
Скачайте то, что вы выложили в эту ветку.
Контроллер 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)
Максим, спасибо. Это решило все проблемы, а то мне пришлось делать в обход переопределяя стартовый экран процесса, и в контейнер подсовывать свои роли при инициализации. Теперь стало хорошо Еще раз спасибо
Максим добрый день. Подскажите пжл, как можно реализовать вот такую бы схему. Сейчас все работает, но необходимо добавить вот такой “ифчик”. Спасибо
Добрый день. При запуске процесса можете передать процессную переменную, boolean с признаком того, что запущено админом, логин пользователя, в общем что угодно. Затем проанализировать её значение в любом месте процесса:
Выражение может выглядеть, например так: ${myVariable == 'myValue'}
Спасибо в очередной раз
Макс, я нашел инфу как передать процессную переменную в новом аддоне - Bproc, а как это сделал в старом bpm…который уже деприкейтед )))
Макс, а я могу там сделать по типу:
${myVariable == ‘myValue’ || myVariable == ‘myValue2’ || myVariable == ‘myValue3’}
Макс, и еще вопрос. Раньше можно было искать юзеров по ролям таким способом:
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();
}
Но после перехода на 7.2.x уже не работает данный метод, точнее он работает для созданных мной ролей ( а на 7.1.0 и с куба ролями работало ), а теперь с куба ролями уже не работает. Есть решение для обновленных ролей ?
Проблему с куба ролями решил таким способом.
private List<User> findAdminsBySecRole(String cubaRoleName) {
return dataManager.load(User.class)
.query("select u from sec$User u join u.userRoles ur where ur.roleName = :roleName")
.parameter("roleName", cubaRoleName)
.list();
}
Пожалуйста, если не трудно, на последующие вопросы создавайте отдельные темы. Не нужно бесконечно растягивать одну тему, одна проблема - одна тема. Так будет удобнее искать информацию другим пользователям.