Дерево страниц

Сравнение версий

Ключ

  • Эта строка добавлена.
  • Эта строка удалена.
  • Изменено форматирование.
Информация
iconfalse
titleПостановка задачи
Запустить процесс
Подсказка
iconfalse
Инструмент: Палитра XML
Свойства страницы
Статус

Статус
colourGreen
titleГОТОВО

РазделWorkFlow
Комментарий

панель
titleРеализация

Оглавление

панель
titleРезультат

Создать модель процесса

Создать модель процесса example_process (создание описано тут)

Загрузить модель процесса

Загрузка описана тут

Подключить WorkFlow-схемы в основную схему

Блок кода
languagexml
titleСхема
<?xml version='1.0' encoding='UTF-8'?>
<schemas xmlns="http://www.intertrust.ru/schema/palette/tn-schema">
  <schema extends="RkkResource" name="RkkResourceInternal">
	<!--...-->
    <schema-ref name="wf" ref="WorkFlow"/>
    <schema-ref name="wfLifeCycle" ref="WorkFlowLifeCycle" null-empty="true" array="true"/>
	<!--...-->
  </schema>
</schemas>

Подключить жизненный цикл WorkFlow к форме

Блок кода
languagexml
titleФорма
<?xml version='1.0' encoding='UTF-8'?>
<ui xmlns="http://www.intertrust.ru/schema/palette/tn-ui">
    <form schema-ref="RkkResourceInternal" id="RkkResourceInternalForm" name="${ui.form.RkkResourceInternalForm.name:}" projection="default" showtabs="true">
        <properties>
            <hide condition-union="AND">
                <negative-condition-ref ref="edit"/>
                <negative-condition-ref ref="read"/>
            </hide>
        </properties>
        <appearance widget="tabs"/>
        <component>
			 <!--...-->
             <section id="LifeCycle" name="${ui.form.RkkResourceInternalForm.section.LifeCycle.name:Жизненный цикл}">
                <properties>
                    <read-only condition-union="AND">
                        <condition>true</condition>
                    </read-only>
                </properties>
                <component>
                    <field attribute-ref="wfLifeCycle">
                        <properties>
                            <read-only condition-union="AND">
                                <condition>true</condition>
                            </read-only>
                        </properties>
                        <appearance location="table" importance="normal"/>
                    </field>
                </component>
            </section>
		 	<!--...-->
        </component>
    </form>
</ui>

Создать handler (JS-Обработчик операций)

Блок кода
languagexml
titleОбработчик операций
<?xml version='1.0' encoding='UTF-8'?>
<ui xmlns="http://www.intertrust.ru/schema/palette/tn-ui">
    <handler name="WF-кнопка" id="WFCustomHandlerName">
        <meta>
            <documentation></documentation>
        </meta>
        <script lang="JavaScript"><![CDATA[код кнопки]]></script>
	</handler>
</ui>
Блок кода
languagejs
titleШаблон кода кнопки
linenumberstrue
collapsetrue
importClass(Packages.ru.intertrust.cmj.af.core.AFSession);
importClass(Packages.ru.intertrust.cmj.af.exceptions.AFDaoBadParameterException);
importClass(Packages.ru.intertrust.cmj.rest.tunable.object.TunableObjectREST);
importClass(Packages.ru.intertrust.cmj.rest.tunable.object.TunableObjectREST.Resource);
importClass(Packages.ru.intertrust.cmj.rest.tunable.object.action.TunableOperation);
importClass(Packages.ru.intertrust.cmj.tunable.object.AnyTunableObject);
importClass(Packages.ru.intertrust.cmj.tunable.object.TunableObjectApplication);
importClass(Packages.ru.intertrust.cmj.tunable.object.TunableObjectApplication.ClientContextKey);
importClass(Packages.ru.intertrust.cmj.tunable.object.common.TunableObjectHelper);
importClass(Packages.ru.intertrust.cmj.rest.tunable.object.action.OperationJScriptREST);
importClass(Packages.ru.intertrust.cmj.rest.tunable.object.action.OperationJScriptREST.ReturnParamsResource);
importClass(Packages.ru.intertrust.cmj.af.tuning.impl.PropertyImpl);
importClass(Packages.ru.intertrust.cmj.dp.DPApplication);
importClass(Packages.ru.intertrust.cmj.rest.rkk.RkkResource);
importClass(Packages.ru.intertrust.cmj.af.utils.BeansUtils);
importClass(Packages.ru.intertrust.cmj.wf.impl.WorkflowProcessServiceImpl);
importClass(Packages.ru.intertrust.cmj.wf.api.ProcessVariables);
importClass(Packages.ru.intertrust.cmj.wf.api.ProcessUserTask);
importClass(Packages.ru.intertrust.cmj.wf.api.TaskVariables);
importClass(Packages.ru.intertrust.cmj.af.misc.AFDateTime);
importPackage(Packages.ru.intertrust.cmj.af.utils);
importPackage(Packages.ru.intertrust.cmj.af.tuning.impl);
importPackage(Packages.ru.intertrust.cmj.af.tuning);
importPackage(Packages.ru.intertrust.cmj.rest.tuning);
importPackage(Packages.java.util);
importPackage(Packages.java.lang);
importClass(Packages.org.apache.commons.lang3.exception.ExceptionUtils);
importClass(Packages.org.slf4j.LoggerFactory);
importClass(Packages.ru.intertrust.cm.core.business.api.dto.Filter);
importClass(Packages.java.util.Collections);
importClass(Packages.ru.intertrust.cmj.af.so.SOBeard);
importClass(Packages.ru.intertrust.cmj.af.so.SOApplication);
importClass(Packages.ru.intertrust.cmj.af.core.AFCMDomino);
importPackage(Packages.ru.intertrust.cm.core.business.api.dto.ReferenceValue);
importClass(Packages.ru.intertrust.cm.core.business.api.dto.StringValue);

function process(paramsResource, returnResource) {

    if (paramsResource == null) {
        throw new IllegalArgumentException("paramsResource must no be null.");
    }

	var dialogNameList = new ArrayList();
	dialogNameList.add("ClientContextRequest");
    dialogNameList.add("dialogParamWF");
	dialogNameList.add("ExampleDialogInfo");


    paramPackageId = "";
    paramSchemaName = paramsResource.tuning().getSchema().getName();
    if (dialogNameList.contains(paramSchemaName)) {
        paramPackageId = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("counter"));
    } else {
        paramPackageId = "contextWithResource";
    }

    if (paramPackageId.equals("context")) {
        createContextResourceRequest(returnResource);
    } else if (paramPackageId.equals("contextWithResource")) {
        process_dialog(paramsResource, returnResource);
    } else if (paramPackageId.equals("answer")) {
        process_context(paramsResource, returnResource);
    } else if (paramPackageId.equals("exit_update")) {
        process_refresh(paramsResource, returnResource);
    } else if (paramPackageId.equals("exit")) {
        return process_exit(paramsResource, returnResource);
    }

}

/**
 * Обработка первого пакета данных с клиента.
 * @return возвращение контекста открытого документа
 */
function createContextResourceRequest(returnResource) {
  var appTNObject = AFSession.get().getApplication(TunableObjectApplication.class);
  var afObjectContextRequest = appTNObject.createClientContextRequest(TunableObjectApplication.ClientContextKey.resourceid, TunableObjectApplication.ClientContextKey.resource);

  TunableObjectHelper.putAFInstanceValue(afObjectContextRequest, "counter", "contextWithResource");
  returnResource.setResource(TunableObjectREST.Resource.create(afObjectContextRequest));
}

/**
 * Обновление объекта
 * @param paramsResource
 * @return ресурс первого диалога сценария
 */
function process_refresh(paramsResource, returnResource) {
    var ids = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("selectIds"));

	var appdp = AFSession.get().getApplication(DPApplication.class);
	var obj = appdp.getEntityByUNID(ids.get(0));

	var res = RkkResource.valueOf(obj);
	returnResource.setResource(res);
}

/**
 * Завершение обработки в случае ошибки
 * @param paramsResource
 * @return ресурс первого диалога сценария
 */
function process_exit(paramsResource, returnResource) {
	var ids = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("selectIds"));

	var appdp = AFSession.get().getApplication(DPApplication.class);
	var obj = appdp.getEntityByUNID(ids.get(0));

	returnResource.setResource(null);
}

/**
 * Диалог Информации c обновлением документа
 * @ids текущий идентификатор документа
 * @resultMessage сообщение
 * @return ресурс
 */
function process_dlginfo_refresh(ids, resultMessage,returnResource){
    var appTNObject = AFSession.get().getApplication(TunableObjectApplication.class);
    var message = appTNObject.composeDialog("ExampleDialogInfo", null, null, null);
    TunableObjectHelper.putAFInstanceValue(message.tuning(), "message", resultMessage);
	TunableObjectHelper.putAFInstanceValue(message.tuning(), "selectIds", ids);
    TunableObjectHelper.putAFInstanceValue(message, "counter", "exit_update");
    returnResource.resource = TunableObjectREST.Resource.create(message);
    return returnResource.resource;
}

/**
 * Диалог Информации c обновлением документа
 * @ids текущий идентификатор документа
 * @resultMessage сообщение
 * @return ресурс
 */
function process_dlginfo(ids, resultMessage,returnResource){
    var appTNObject = AFSession.get().getApplication(TunableObjectApplication.class);
    var message = appTNObject.composeDialog("ExampleDialogInfo", null, null, null);
    TunableObjectHelper.putAFInstanceValue(message.tuning(), "message", resultMessage);
	TunableObjectHelper.putAFInstanceValue(message.tuning(), "selectIds", ids);
    TunableObjectHelper.putAFInstanceValue(message, "counter", "exit");
    returnResource.resource = TunableObjectREST.Resource.create(message);
    return returnResource.resource;
}

/**
* Обработка первого пакета данных с клиента.
* @param paramsResource
* @return ресурс первого диалога сценария
*/
function process_dialog(paramsResource, returnResource) {
    var appTNObject = AFSession.get().getApplication(TunableObjectApplication.class);
    var id = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("$id"));
    var ids = Utils.newArrayList();
    ids.add(id);

    var appdp = AFSession.get().getApplication(DPApplication.class);
    var obj = appdp.getEntityByUNID(id);

    //Проверка на актуальность документа
    var version = paramsResource.getVersion();
    var versionParts = version.split('$$');
    var versionContext = versionParts[0];

    var versionCurrent = '';
    try {
       versionCurrent = obj.getVersionStamp().toString();
    } catch (e) {
       versionCurrent = versionContext;
    }

    if (versionContext != versionCurrent){
       process_dlginfo(ids,"Данная версия объекта/документа была изменена. Требуется обновить!",returnResource);
       return returnResource.resource;
    }

    var message = appTNObject.composeDialog("dialogParamWF", null, null, null);
    TunableObjectHelper.putAFInstanceValue(message.tuning(), "message", "Запуск WF-процесса");
    TunableObjectHelper.putAFInstanceValue(message.tuning(), "selectIds", ids);
    TunableObjectHelper.putAFInstanceValue(message.tuning(), "versionContext", versionContext);
    TunableObjectHelper.putAFInstanceValue(message, "counter", "answer");

    returnResource.setResource(TunableObjectREST.Resource.create(message));
}

/**
 * Обработка контекста
 * @param paramsResource
 * @return ресурс первого диалога сценария
 */
function process_context(paramsResource, returnResource) {
    var ids = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("selectIds"));
    var wfProcessName = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("wfProcessName"));
    var wfAssignee1 = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("wfAssignee1"));
    var wfAssignee2= TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("wfAssignee2"));
    var wfAssignee3 = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("wfAssignee3"));
    var versionContext = TunableObjectHelper.getAFInstanceValue(paramsResource.tuning().getValues().get("versionContext"));

    var workflowProcessName = wfProcessName;
    var params = new ProcessVariables();
    var currentUser = AFSession.get().currentUser().getBeard();
    params.put("wfInitiator", currentUser.toString(SOBeard.ToStringFormat.CMDOMINO_STD));
    params.put("wfAssignee1", wfAssignee1.toString(SOBeard.ToStringFormat.CMDOMINO_STD));
    params.put("wfAssignee2", wfAssignee2.toString(SOBeard.ToStringFormat.CMDOMINO_STD));
    params.put("wfAssignee3", wfAssignee3.toString(SOBeard.ToStringFormat.CMDOMINO_STD));

    var appdp = AFSession.get().getApplication(DPApplication.class);
	var obj = appdp.getEntityByUNID(ids.get(0));

	var versionCurrent = '';
	try {
	   versionCurrent = obj.getVersionStamp().toString();
	} catch (e) {
	   versionCurrent = versionContext;
	}

	if (versionContext != versionCurrent){
		process_dlginfo_refresh(ids,"Изменена версия объекта.\nОбъект будет переоткрыт в актуальном состоянии.",returnResource);
        return returnResource.resource;
	}

 	// Необходимо выдать исключение, если объект удален или прекращен в WD
    if ("Webdocs2.0".equals(AFSession.get().currentUser().extendedAttributes().get("ClientAlias"))) {
        var isTerminate = obj.tuning().getValues().get("wf") == null ? false : obj.tuning().getValues().get("wf").getValues().get("stage") == null ? false : obj.tuning().getValues().get("wf").getValues().get("stage").getValue().equals("Прекращена") ? true : false;
        if (obj.isDeleted() || isTerminate) {
			 process_dlginfo(ids,"Документ был удален обратитесь к администратору",returnResource);
			 return returnResource.resource;
        }
    }

	var workflowProcessService = BeansUtils.getBean("workflowProcessServiceImpl");

 	//запустить процесс
	var StartProcessResult = workflowProcessService.startProcess(workflowProcessName, ids.get(0), params);
	if (StartProcessResult.hasError()) {
        stackTrace = ExceptionUtils.getStackTrace(StartProcessResult.getException());
		throw new RuntimeException("Не удалось запустить процесс " +workflowProcessName + ". Обратитесь к администратору.\nОшибка: " + stackTrace);
	}

	obj = appdp.getEntityByUNID(ids.get(0));
 	var res = RkkResource.valueOf(obj);
	returnResource.setResource(res);
}

Добавить кастомную кнопку и подключить кастомную операцию

  1. В форме создать секцию RootMenu
  2. В RootMenu создать button и подключить к нему handler


Информация
titleКоды иконок

https://conf.inttrust.ru:8443/pages/viewpage.action?pageId=59704445

Блок кода
languagexml
<section id="RootMenu">
    <component>
        <button name="${<Form Name>.RootMenu.button.<Name>:Новая кнопка}">
            <icon code="37"/>
            <action>
                <custom>
                    <operation>
                        <handler-ref ref="WFCustomHandlerName"/>
                    </operation>
                </custom>
            </action>
        </button>
    </component>
</section>

Подключить скрипт в WF-процесс

Скрипт устанавливает статус и заполняет жизненный цикл.

Блок кода
languagejs
titleСкрипт
linenumberstrue
collapsetrue
load("nashorn:mozilla_compat.js");
importClass(Packages.ru.intertrust.cmj.af.core.AFSession);
importClass(Packages.ru.intertrust.cmj.dp.DPApplication);
importClass(Packages.ru.intertrust.cmj.rest.tuning.TuningHelper);
importClass(Packages.ru.intertrust.cmj.tunable.object.TunableObjectApplication);
importClass(Packages.ru.intertrust.cmj.tunable.object.TunableObjectApplication.ClientContextKey);
importClass(Packages.ru.intertrust.cmj.tunable.object.common.TunableObjectHelper);
importClass(Packages.ru.intertrust.cmj.af.misc.AFDateTime);
importClass(Packages.ru.intertrust.cmj.af.utils.Utils);
importClass(Packages.java.util.Calendar);
importClass(Packages.java.util.ArrayList);
importClass(Packages.ru.intertrust.cmj.af.tuning.impl.AFInstanceObjectImpl);
importClass(Packages.ru.intertrust.cmj.af.tuning.impl.AFInstanceArrayImpl);
importClass(Packages.ru.intertrust.cmj.admin.AdminApplicationImpl);
importClass(Packages.ru.intertrust.cmj.af.so.SOBeard);
importClass(Packages.ru.intertrust.cmj.af.utils.BeansUtils);
importClass(Packages.ru.intertrust.cmj.af.so.SOUnitPost);
importClass(Packages.org.slf4j.LoggerFactory);

var appDp = AFSession.get().getApplication(DPApplication.class);
var document = appDp.getEntityByUNID(contextId);

//Статус
var wf = document.tuning().getValues().get('wf');
var propertyStage = wf.getSchema().getProperty("stage");
var stageValue = TuningHelper.createPropertyValue(stage,propertyStage);
wf.getValues().put("stage", stageValue);

//Заполнение ЖЦ
var currentUser = AFSession.get().currentUser().getBeard();
var assignee = currentUser;
var startDate = new AFDateTime(Calendar.getInstance());
var endDate = new AFDateTime(Calendar.getInstance());
var action = "Запуск WF-процесса";
var result = "Запущен процесс";
var information = "-";

var time = new AFDateTime(Calendar.getInstance());
TunableObjectHelper.putAFInstanceValue(document.tuning(), "wf.actiontime", time);

var propertyLifecycle = document.tuning().getSchema().getProperty("wfLifeCycle");
var lifecycle = null;

if (document.tuning().getValues().containsKey("wfLifeCycle") && document.tuning().getValues().get("wfLifeCycle") != null) {
	lifecycle = document.tuning().getValues().get("wfLifeCycle").getValues();
} else {
	lifecycle = Utils.newArrayList();
}
	
var propertyStartDate = propertyLifecycle.getSchema().getProperty("lifecycle_start_date");
var propertyDate = propertyLifecycle.getSchema().getProperty("lifecycle_date");
var propertyAction = propertyLifecycle.getSchema().getProperty("lifecycle_action");
var propertyAssignee = propertyLifecycle.getSchema().getProperty("lifecycle_assignee");
var propertyCurrentUser = propertyLifecycle.getSchema().getProperty("lifecycle_current_user");
var propertyResult = propertyLifecycle.getSchema().getProperty("lifecycle_result");
var propertyInformation = propertyLifecycle.getSchema().getProperty("lifecycle_information");

var startDateValue = TuningHelper.createPropertyValue(startDate, propertyStartDate);
var endDateValue = TuningHelper.createPropertyValue(endDate, propertyDate);
var actionValue = TuningHelper.createPropertyValue(action, propertyAction);
var currentUserValue = TuningHelper.createPropertyValue(currentUser, propertyCurrentUser);
var assigneeValue = TuningHelper.createPropertyValue(assignee, propertyAssignee);
var resultValue = TuningHelper.createPropertyValue(result, propertyResult);
var informationValue = TuningHelper.createPropertyValue(information, propertyInformation);

var wf_lifecycle = new AFInstanceObjectImpl(propertyLifecycle.getSchema());
wf_lifecycle.getValues().put("lifecycle_start_date", startDateValue);
wf_lifecycle.getValues().put("lifecycle_date", endDateValue);
wf_lifecycle.getValues().put("lifecycle_action", actionValue);
wf_lifecycle.getValues().put("lifecycle_assignee", assigneeValue);
wf_lifecycle.getValues().put("lifecycle_current_user", currentUserValue);
wf_lifecycle.getValues().put("lifecycle_result", resultValue);
wf_lifecycle.getValues().put("lifecycle_information", informationValue);

lifecycle.add(wf_lifecycle);

var lifecycleValue = new AFInstanceArrayImpl(propertyLifecycle.getSchema(), lifecycle);
document.tuning().getValues().put("wfLifeCycle", lifecycleValue);

//Сохранение
document.save();