Перейдите на вкладку Controller и замените ее содержимое на следующий код:
ContractEdit.java.
package com.company.demo.gui.contract; import com.haulmont.bpm.entity.ProcDefinition; import com.haulmont.bpm.entity.ProcInstance; import com.haulmont.bpm.gui.action.ProcAction; import com.haulmont.bpm.gui.procactions.ProcActionsFrame; import com.haulmont.cuba.core.global.*; import com.haulmont.cuba.gui.WindowManager; import com.haulmont.cuba.gui.app.core.file.FileDownloadHelper; import com.haulmont.cuba.gui.components.*; import com.company.demo.entity.Contract; import com.haulmont.cuba.gui.components.actions.BaseAction; import com.haulmont.cuba.gui.data.DsContext; import com.haulmont.cuba.gui.xml.layout.ComponentsFactory; import javax.annotation.Nullable; import javax.inject.Inject; import java.util.Map; public class ContractEdit extends AbstractEditor<Contract> { private static final String PROCESS_CODE = "contractApproval"; @Inject private DataManager dataManager; private ProcDefinition procDefinition; private ProcInstance procInstance; @Inject private ProcActionsFrame procActionsFrame; @Inject private GroupBoxLayout procActionsBox; @Inject private ComponentsFactory componentsFactory; @Inject private Table attachmentsTable; @Inject private Metadata metadata; @Override protected void postInit() { super.postInit(); procDefinition = findProcDefinition(); if (procDefinition != null) { procInstance = findProcInstance(); if (procInstance == null) { procInstance = metadata.create(ProcInstance.class); procInstance.setProcDefinition(procDefinition); procInstance.setEntityName("demo$Contract"); procInstance.setEntityId(getItem().getId()); } initProcActionsFrame(); } getDsContext().addListener(new DsContext.CommitListenerAdapter() { @Override public void beforeCommit(CommitContext context) { if (procInstance != null && PersistenceHelper.isNew(procInstance)) { context.getCommitInstances().add(procInstance); } } }); FileDownloadHelper.initGeneratedColumn(attachmentsTable, "file"); } private void initProcActionsFrame() { procActionsFrame.setBeforeStartProcessPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { if (PersistenceHelper.isNew(getItem())) { showNotification(getMessage("saveContract"), NotificationType.WARNING); return false; } return true; } }); procActionsFrame.setAfterStartProcessListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("processStarted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setBeforeCompleteTaskPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { return commit(); } }); procActionsFrame.setAfterCompleteTaskListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("taskCompleted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setCancelProcessEnabled(false); procActionsFrame.init(procInstance); } @Nullable private ProcDefinition findProcDefinition() { LoadContext ctx = new LoadContext(ProcDefinition.class); ctx.setQueryString("select pd from bpm$ProcDefinition pd where pd.code = :code") .setParameter("code", PROCESS_CODE); return dataManager.load(ctx); } @Nullable private ProcInstance findProcInstance() { LoadContext ctx = new LoadContext(ProcInstance.class).setView("procInstance-start"); ctx.setQueryString("select pi from bpm$ProcInstance pi where pi.procDefinition.id = :procDefinition and pi.entityId = :entityId") .setParameter("procDefinition", procDefinition) .setParameter("entityId", getItem()); return dataManager.load(ctx); } }
Сохраните изменения, нажав кнопку OK.
Рассмотрим код контроллера более подробно.
Чтобы запустить процесс, мы должны создать экземпляр процесса - объект ProcInsntance
, связать его с описанием процесса (ProcDefinition
) и выполнить запуск. Экземпляр процесса (ProcInstance
) может быть запущен как самостоятельно, так и с привязкой к какой-либо сущности проекта. В нашем случае нужна привязка к
договору.
В начале метода postInit()
производится поиск экземпляра процесса согласования договора. Метод findProcDefinition()
по коду contractApproval
ищет описание процесса.
Далее проверяется нет ли в базе объекта ProcInstance
, связанного с текущим договором (метод findProcInstance()
). Если экземпляр процесса для данного договора еще не создан, то создаем его, заполняя ссылку на описание процесса, устанавливая
имя связанной сущности и ее идентификатор.
if (procInstance == null) { procInstance = metadata.create(ProcInstance.class); procInstance.setProcDefinition(procDefinition); procInstance.setEntityName("demo$Contract"); procInstance.setEntityId(getItem().getId()); }
CommitListener
добавляет в список сущностей, отправляемых на средний слой для коммита, созданный объект ProcInstance
.
getDsContext().addListener(new DsContext.CommitListenerAdapter() { @Override public void beforeCommit(CommitContext context) { if (procInstance != null && PersistenceHelper.isNew(procInstance)) { context.getCommitInstances().add(procInstance); } } });
Далее переходим к методу initProcActionsFrame()
.
ProcActionsFrame
- это стандартный фрейм для отображения кнопок доступных в данный момент процессных действий. ProcActiosnFrame
связан с экземпляром ProcInstance
. Если процесс не запущен, то фрейм отобразит кнопку запуска процесса, если процесс запущен и для текущего пользователя имеются
активные задачи, то он отобразит кнопки завершения текущей задачи в соответствии с определенными в модели процесса выходами
из задачи (Task outcomes). Подробнее о ProcActionsFrame см. Раздел 6.1, «ProcActionsFrame».
private void initProcActionsFrame() { procActionsFrame.setBeforeStartProcessPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { if (PersistenceHelper.isNew(getItem())) { showNotification(getMessage("saveContract"), NotificationType.WARNING); return false; } return true; } }); procActionsFrame.setAfterStartProcessListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("processStarted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setBeforeCompleteTaskPredicate(new ProcAction.BeforeActionPredicate() { @Override public boolean evaluate() { return commit(); } }); procActionsFrame.setAfterCompleteTaskListener(new ProcAction.AfterActionListener() { @Override public void actionCompleted() { showNotification(getMessage("taskCompleted"), NotificationType.HUMANIZED); close(COMMIT_ACTION_ID); } }); procActionsFrame.setCancelProcessEnabled(false); procActionsFrame.init(procInstance); }
Метод procActionsFrame.setBeforeStartProcessPredicate()
добавляет проверку, выполняемую перед запуском процесса. Если объект с договором еще не сохранен, то процесс не запустится
и будет выведено соответствующее предупреждение.
Метод procActionsFrame.setBeforeCompleteTaskPredicate()
вызывает коммит редактора и позволяет завершить процессное действие только если коммит редактора прошел успешно.
Методы setAfterProcessStartListener
и setAfterCompleteTaskListener
будут вызваны после соответствующего события. Они отобразят уведомление и закроют редактор договора.
После того, как необходимые слушатели и предикаты для procActionsFrame
заданы, вызывается инициализация фрейма.
procActionsFrame.init(procInstance);
Во время инициализации и происходит создание необходимых элементов управления внутри фрейма.