Сделать в конструкторе бизнес процессов возможность элемент который позволить запускать процесс не только при создании изменении  записи, но и при нажатии на элемент страницы например сохранить запись или обновить или когда разворачиваешь деталь.

1 комментарий

Александр, зарегистрировал пожелание, но не совсем понимаю, как такое могло бы выглядеть. Есть веб-сервис запуска процессов с нужными значениями параметров, его можно запустить из клиентской логики при выполнении нужного события. Как это делается, можно увидеть в ProcessModuleUtilities:

PROCESS_ENGINE_SERVICE_NAME: "ServiceModel/ProcessEngineService.svc",
...
		_runProcessOld: function(processName, parameters, callback, scope) {
			let queryString = "";
			if (parameters) {
				const queryItems = _.map(parameters, function(value, name) {
					return name + "=" + value;
				}, this);
				queryString = "?" + queryItems.join("&");
			}
			this.callService({
				serviceName: this.PROCESS_ENGINE_SERVICE_NAME,
				methodName: processName + "/RunProcess" + queryString
			}, callback, scope);
		},

Возможно, по Вашему предложению есть смысл дополнить не дизайнер бизнес-процессов, но мастер раздела, добавив там возможность автоматически формировать подобный код, привязанный к событиям и элементам в разделе или на странице.

Показать все комментарии

Добрый день!

Довольно часто требуется выводить пользователю какое-либо модальное окно. Для реализации приходится привлекать разработчиков. Было бы здорово, если бы в элементах бизнес-процесса появился элемент "Модальное окно", который выглядел бы примерно так:

То есть аналитик смог бы настраивать текст и варианты ответов. И после этого элемента использовать условные потоки.

3 комментария

Елизавета, уже зафиксирована идея «Возможность открывать страницы по процессу/показывать сообщения как всплывающее/модальное окно / уведомление (не путать с панелью уведомлений)». 

 

Если же первично для Вас не отображение в виде модального окна, а получение от пользователя ответа на один из нескольких вариантов, можно использовать стандартный элемент БП «Автогенерируемая страница», где добавить две кнопки, привязав к ним условные потоки.

Отличие от модального будет в том, что такое окно будет в верхней части экрана и его можно будет по кнопке «Закрыть» свернуть в правую панель, чтобы дать ответ и продолжить выполнение позже.

Зверев Александр

Александр, да, с автогенерируемой страницей понятно, "Вопрос пользователю"  тоже подойдет для этой цели. Но идея именно в том, чтобы не открывать новую страницу, а выводить маленькое одно модальное окно)  Для глаз пользователя есть разница: открывается новая страница или же на старой появляется модальное окно.

Здорово, что идея уже зафиксирована, будем очень ждать реализации.

Елизавета, такого на уровне элементов БП, а не написанием кода на странице, пока нет, идея заведена.

Показать все комментарии

Добрый день!

Есть задача - добавлять в аудиторию письма (элемент "отправка письма" в процессе) коллекцию получателей (контакты, или их email'ы)

 

Список контактов каждый раз может быть разный и зависит от того, в какую орг.роль они входят. 

Другими словами - пользователь выбирает орг.роль, и в получатели письма вставляются контакты, которые входят в эту роль. 

В коробке системы это уже реализовано в процессе, который уведомляет группы ответственных о получении обращения. Но там это реализовано кодом. 

Вопрос - каким образом задачу можно решить средствами low-code платформы? :)

Нравится

1 комментарий
Лучший ответ

Доброе утро.

 

Средствами low-code можно попробовать реализовать с помощью обработки коллекций данных в бизнес-процессах через многоэкземплярное выполнение элемента [ Подпроцесс ].

Доброе утро.

 

Средствами low-code можно попробовать реализовать с помощью обработки коллекций данных в бизнес-процессах через многоэкземплярное выполнение элемента [ Подпроцесс ].

Показать все комментарии

Баг/фича не пойму, но по мне это серьезная недоработка. В элементе БП Подпроцесс(действие вызов) система предлагает выбрать не активные БП.

А теперь заходим в библиотеку процессов и видим что часть процессов не активны:

Предлагаю либо убрать не активные процессы, либо помечать в выборе что процесс не активен.

1 комментарий

Алексей, не уверен, что это именно бага.

 

Более того, если процесс деактивирован, но его задать из другого активного процесса как подпроцесс, то он запустится.

 

Такое поведение является штатным, оно закладывалось в архитектуру. Активация-деактивация влияет только но запуск ОСНОВНОГО бизнес-процесса. Если он является подпроцессом другого основного процесса, то ничем не отличается по поведению от любого другого элемента БП. Потому что подпроцесс выполняется В КОНТЕКСТЕ ОСНОВНОГО БП. При выполнении подпроцесса учитывается только признак актуальной версии подпроцесса.

 

Если нужно добавить в выпадающий список фильтрацию по активности, заместите схему SubProcessPropertiesPage и там измените функцию getSchemaListFilter, значение свойства EnabledOnly:

/**
 * Returns schema list filter.
 * @protected
 * @param {Function} callback The callback function.
 * @param {Object} callback.filter Schemas filter.
 */
getSchemaListFilter: function(callback) {
	const element = this.get("ProcessElement");
	const schema = this.get("Schema") || {};
	const parentSchema = element.parentSchema;
	const excludedSchemaUId = schema.value;
	let filter = {
		PackageUId: Terrasoft.formatGUID(parentSchema.packageUId, "B"),
		EnabledOnly: true,//false,
		ExcludedSchemas: [Terrasoft.formatGUID(parentSchema.uId, "B")]
	};
	filter = Ext.apply(filter, element.schemaFilter);
	if (excludedSchemaUId) {
		filter.ExcludedSchemas.push(Terrasoft.formatGUID(excludedSchemaUId, "B"));
	}
	callback(filter);
},

Идею стандартно включить такой фильтр зафиксирую.

Показать все комментарии

С версии 7.16 появилась возможность множественного запуска бизнес-процессов через элемент подпроцесс. 

 

К примеру необходимо создать бизнес-процесс который будет отправлять письмо-поздравление всем контактам у которых сегодня день рождения. 

 

Для этого необходимо создать процесс с двумя элементами: 

1. Элемент [Читать коллекцию] контактов у которых сегодня день рождения

2. Элемент [Подпроцесс] в который передать коллекцию контактов которых нужно поздравить.

 

В самом же подпроцессе необходимо создать параметр процесса который соответствует отдельному элементу коллекции, в нашем случае это контакт: 

 

В результате запуска такого процесса получим последовательное выполнение подпроцесса для каждого элемента коллекции. Также процесс можно модифицировать добавив исходящие параметры.

Нравится

Поделиться

0 комментариев
Показать все комментарии

Как пенести на другую среду признак деактивации процесса в пакете?

 

Для того что бы перенести признак деактивации процесса на другую среду необходимо к пакету привязать sql-скрипт.

В элементе sql-скрипт необходимо добавить следующий запрос. Запрос должен соответствовать СУБД, с которой работает система, ниже пример запроса подходящего для MSSQL и PostgreSQL : 

INSERT INTO "SysProcessDisabled" ("Name", "SysSchemaId")
SELECT "Name","Id"
FROM "SysSchema"
WHERE "Name" IN ('Название процесса (важно! не заголовок)')

Пример скрипта деактивации процесса "Квалификация продажи v7.8.0"

 

Название процесса можно найти в дизайнере процесса.

 

Также в дизайнере бизнес-процесса после применения скрипта признак [Активен] будет проставлен до перезагрузки пула приложения, так как эта галочка остается закешированной, хотя процесс по факту больше не активен. 

Нравится

Поделиться

3 комментария

А у меня всё равно такие процессы исполняются... 

Процессы могут исполняться, если запускаются не вручную, а, например, как подпроцесс из другого.

Зверев Александр пишет:

Процессы могут исполняться, если запускаются не вручную, а, например, как подпроцесс из другого.

 И, к сожалению, стартуют по сигналу. А надо совсем отключить

Показать все комментарии

Добрый день, коллеги. 

Так вышло, что бизнес-процессы игнорирует сигнал по добавлению пользователя (или вообще любой записи в таблицу SysAdminUnit). 

Пользователь создается вручную. 

У кого есть идеи, как все-таки запускать процесс при создании пользователя?

Нравится

2 комментария
Лучший ответ

Здравствуйте! Разве что через событийный слой

[EntityEventListener(SchemaName = "SysAdminUnit")]
    public class SysAdminUnitEntityEventListener : BaseEntityEventListener
{
  public override void OnSaving(object sender, EntityBeforeEventArgs e) {
    base.OnSaving(sender, e)
  }
  public override void OnInserting(object sender, EntityBeforeEventArgs e) {
    base.OnInserting(sender, e);
  }
 public override void OnUpdating(object sender, EntityBeforeEventArgs e) {
   base.OnUpdating(sender, e);
}
public override void OnUpdated(object sender, EntityAfterEventArgs e) {
 base.OnUpdated(sender, e);
}
public override void OnInserted(object sender, EntityAfterEventArgs e) {
 base.OnInserted(sender, e);
}
}

Ну а там уже выбирайте при каких событиях Вам нужно обрабатывать про событийный слой прочтите данную статью

 

Так же БП можно запускать из серверного кода примерно следующее:
 

using Terrasoft.Core;
using Terrasoft.Core.Process;
using Terrasoft.Core.Process.Configuration;
 
ProcessSchema schema = UserConnection.ProcessSchemaManager.GetInstanceByName("LeadManagement");
//schema = UserConnection.ProcessSchemaManager.GetInstanceByUId(leadManagementProcessUId);
 
//Разные движки для интерпритируемых и компилироуемых БП
bool canUseFlowEngine = ProcessSchemaManager.GetCanUseFlowEngine(UserConnection, schema);
if(canUseFlowEngine) {
	var flowEngine = new FlowEngine(UserConnection);
	var param = new Dictionary<string, string>();
	param["LeadId"] = Entity.Id.ToString();
	flowEngine.RunProcess(schema, param);
} else {
	Process process = schema.CreateProcess(UserConnection);
	process.SetPropertyValue("LeadId", Entity.Id);
	process.Execute(UserConnection);
}		

 

Здравствуйте! Разве что через событийный слой

[EntityEventListener(SchemaName = "SysAdminUnit")]
    public class SysAdminUnitEntityEventListener : BaseEntityEventListener
{
  public override void OnSaving(object sender, EntityBeforeEventArgs e) {
    base.OnSaving(sender, e)
  }
  public override void OnInserting(object sender, EntityBeforeEventArgs e) {
    base.OnInserting(sender, e);
  }
 public override void OnUpdating(object sender, EntityBeforeEventArgs e) {
   base.OnUpdating(sender, e);
}
public override void OnUpdated(object sender, EntityAfterEventArgs e) {
 base.OnUpdated(sender, e);
}
public override void OnInserted(object sender, EntityAfterEventArgs e) {
 base.OnInserted(sender, e);
}
}

Ну а там уже выбирайте при каких событиях Вам нужно обрабатывать про событийный слой прочтите данную статью

 

Так же БП можно запускать из серверного кода примерно следующее:
 

using Terrasoft.Core;
using Terrasoft.Core.Process;
using Terrasoft.Core.Process.Configuration;
 
ProcessSchema schema = UserConnection.ProcessSchemaManager.GetInstanceByName("LeadManagement");
//schema = UserConnection.ProcessSchemaManager.GetInstanceByUId(leadManagementProcessUId);
 
//Разные движки для интерпритируемых и компилироуемых БП
bool canUseFlowEngine = ProcessSchemaManager.GetCanUseFlowEngine(UserConnection, schema);
if(canUseFlowEngine) {
	var flowEngine = new FlowEngine(UserConnection);
	var param = new Dictionary<string, string>();
	param["LeadId"] = Entity.Id.ToString();
	flowEngine.RunProcess(schema, param);
} else {
	Process process = schema.CreateProcess(UserConnection);
	process.SetPropertyValue("LeadId", Entity.Id);
	process.Execute(UserConnection);
}		

 

Мне кажется, вопрос в другом.

При добавлении пользователя через интерфейс идёт обращение к веб-сервису AdministrationService и его методу UpdateOrCreateUser. В схеме AdministrationServiceUsers виден его код:

protected void SaveUser(object roleId) {
	bool isNew = false;
	object primaryColumnValue;
	changedValues.TryGetValue("Id", out primaryColumnValue);
	EntitySchema entitySchema = UserConnection.EntitySchemaManager.GetInstanceByName("VwSysAdminUnit");
	Entity entity = entitySchema.CreateEntity(UserConnection);
	isNew = !entity.FetchFromDB(primaryColumnValue);
	if (isNew) {
		entity.SetDefColumnValues();
	}
	foreach (KeyValuePair<string, object> item in changedValues) {
		EntitySchemaColumn column = entitySchema.Columns.GetByName(item.Key);
		object columnValue = item.Value;
		if ((column.DataValueType is DateTimeDataValueType) && (item.Value != null)) {
			columnValue = DataTypeUtilities.ValueAsType<DateTime>(item.Value);
		}
		entity.SetColumnValue(column.ColumnValueName, columnValue);
	}
	entity.Save();
	if (isNew) {
		AddUserInRole(entity.PrimaryColumnValue, roleId);
	}
}

То есть видно, что вставка идёт через механизмы ESQ (значит, события отработают), но в объект VwSysAdminUnit, а не SysAdminUnit. Если посмотреть в коде встроенного БП на VwSysAdminUnit в пакетах Base, Translation и WebitelCollaborations, там как раз успешно добавляют свои обработчики на вставку, сохранение и другие события:

То есть нужно будет либо в Custom сделать своё переопределение схемы со встроенным БП, либо сделать отдельный БП, запускающийся по сигналу вставки туда:

В любом случае нужно учитывать, что в этой view видны и пользователи, и роли.

Показать все комментарии

Добрый день . 

Я создал раздел для портальных пользователей.

Есть два поля , Заказчик и Орг.ДИИС.

Два поля основаны на встроенных справочниках в система  : Контакты и Контрагент.

Как через БП сделать так , что при выборе Заказчика , заполнялось поле Орг.ДИИС в соответствии с контрагентом к которому принадлежит  Заказчик ? 

Есть я так понимаю второй еще вариант это прибегнуть к разработке  но в ней я вообще не силен , да и в построении БП бывают трудности ) . 

Есть идеи  ? 

Нравится

1 комментарий

Марк, с версии 7.16.2 это можно настроить на уровне бизнес-правил фильтрации:

Появилась возможность с помощью бизнес-правил настроить автоматическое заполнение и очистку значения в поле. Например, при создании бизнес-правила для фильтрации города по стране можно настроить, чтобы страна автоматически указывалась при выборе города, а поле [Город] очищалось при изменении страны.

business_rule.png

Показать все комментарии

Здравствуйте,

у меня есть бизнес процесс который запускаеться после внесения строки в справочник, но его результатом может быть удаление этой же строки,

из-за чего есть необходимость обновить страницу справочника с Бизнес процесса.

Подскажите как это можно реализовать.

Спасибо.

Нравится

13 комментариев

Добрый вечер.

 

Для передачи сообщений из серверной логики на клиент используется механизм ClientMessageBridge.

 

Также посмотрите обсуждение в этом посте.

Вообще, использовать такие сложные механизмы, как мне кажется, не всегда уместно. Справочники обычно меняют только админы, по умолчанию у пользователей и прав таких нет. Если есть необходимость добавлять значение, может, лучше будет создать процесс с преднастроенной или автогенерируемой страницей, который принимает от пользователя строку, выполняет проверки и в случае выполнения условий добавляет строку в справочник, можно даже в обход проверки прав. И пользователю дать возможность его запускать, а доступ на редактирование справочника напрямую убрать.

Зверев Александр,

спасибо за вариант, но уже все реализовано по другому, осталось проблему с рефрешем страницы решить.

попытался реализовать через ClientMessageBridge, хочу повторить пример со статьи, но опять есть вопрос, с Процесса сообщение уходит, в ClientMessageBridge попадает, но потом хочу получить сообщение в нужной мне схеме, 

я беру (BaseLookupConfigurationSection) так как этот функционал мне нужен при добавлении строки, но туда сообщение NewUserSet не доходит, как понять в чем ошибка?

Так же появляется ошибка:

Приведите Ваш код, который Вы разработали для этой функциональности.

1. В процессе добавил в Задание-сценарий:

string messageText = "{\"name\": \"" + "TestName" + "\"}";
string sender = "NewUserSet";
MsgChannelUtilities.PostMessageToAll(sender, messageText);

return true;

 

2. вот код замещающей схемы ClientMessageBridge :

 /**
 * @class ClientMessageBridge.ELBase
 * @extends ClientMessageBridge.NUI
 */
define(
    "ClientMessageBridge",
    ["ConfigurationConstants"],
    function(ConfigurationConstants) {
        return {
            messages: {
                "NewUserSet": {
                    "mode": Terrasoft.MessageMode.BROADCAST,
                    "direction": Terrasoft.MessageDirectionType.PUBLISH
                }
            },
            methods: {
                /**
                 * @inheritDoc ClientMessageBridge.UIv2#init
                 * @override
                 */
                init: function() {
                    this.callParent(arguments);
                    this.addCustomMessages();
                },
                
                addCustomMessages: function() {
                    this.addMessageConfig({
                        sender: "NewUserSet",
                        messageName: "NewUserSet"
                    });
                },
                afterPublishMessage: function(
                    sandboxMessageName,
                    webSocketBody,
                    result,
                    publishConfig) {
                    if (sandboxMessageName === "NewUserSet") {
                        var name = webSocketBody.name;
                        window.console.info("Опубликовано сообщение: " + sandboxMessageName +". Данные: name: " + name);
                    }
                }
            }
        };
    }
);

 

3. и код замещающей схемы BaseLookupConfigurationSection:

/**
 * @class BaseLookupConfigurationSection.ELBase
 * @extends BaseLookupConfigurationSection.UIv2
 */
define(
    "BaseLookupConfigurationSection",
    [],
    function(BusinessRuleModule, ConfigurationConstants) {
        return {
             messages: {
                "NewUserSet": {
                    "mode": Terrasoft.MessageMode.BROADCAST,
                    "direction": Terrasoft.MessageDirectionType.PUBLISH
                }
            },
            methods: {
                /**
                 * @inheritDoc GridUtilitiesV2.NUI#checkCanDelete
                 * @override
                 */
                checkCanDelete: function(items, callback, scope) {
                    this.callGetLookupDisabledActionsService(this.getParentMethod(this, arguments));
                },
                
                callGetLookupDisabledActionsService: function(callback) {
                    this.showBodyMask();
                    this.callService(
                        this.getGetLookupDisabledActionsServiceConfig(),
                        this.handleGetLookupDisabledActionsServiceResponse.bind(this, callback),
                        this
                    );
                },
                
                getGetLookupDisabledActionsServiceConfig: function() {
                    return {
                        serviceName: "GetUserRolesService",
                        methodName: "GetLookupDisabledActions",
                        data: {
                            lookupEntitySchemaUId: (this.getGridEntitySchema() || {}).uId
                        }
                    };
                },
                
                handleGetLookupDisabledActionsServiceResponse: function(callback, response) {
                    this.hideBodyMask();
                    if (response &&
                        response.success &&
                        !(response.data || []).includes(EL.const.db.EL_RECORD_ACTION.DELETE)) {
                        callback();
                    } else {
                        this.showInformationDialog(this.get("Resources.Strings.ForbiddenToEditLookupMessage"));
                    }
                },

// Инициализация схемы.
                init: function() {
                    this.callParent(arguments);
                    this.sandbox.subscribe("NewUserSet", this.onNewUserSet, this);
                },
// Обработчик события получения сообщения NewUserSet.
                onNewUserSet: function(args) {
                    var name = args.name;
                    window.console.info("Получено сообщение: NewUserSet. Данные: name: " + name);
                }
            }
        };
    }
);

 

А почему у Вас на странице, где будет ловиться сообщение, указано «"direction": Terrasoft.MessageDirectionType.PUBLISH», а не «"direction": Terrasoft.MessageDirectionType.SUBSCRIBE», как в примере? Не в этом ли дело?

Зверев Александр,

вы правы, получилось, с этим спасибо, сообщение я получил.

но изначально я же хотел обновить страницу, и для этого я заменил вывод на this.reloadEntity();

получилось так:

// Инициализация схемы.
                init: function() {
                    this.callParent(arguments);
                    this.sandbox.subscribe("NewUserSet", this.onNewUserSet, this);
                },

                onNewUserSet: function(args) {
/*                   var name = args.name;
                   window.console.info("Получено сообщение: NewUserSet. Данные: name: " + name);*/
                    
                    this.reloadEntity();
                }

 

Но теперь я вижу что reloadEntity - undefined,

и получаю такую ошибку:

Функция reloadEntity задана в BasePageV2. Видимо, BaseLookupConfigurationSection, куда Вы добавляете обработчик, не наследуется от неё.

спасибо за ответ!

а возможно есть еще какие то варианты как обновить страницу?

Видимо, разобраться в логике этой функции и реализовать аналогичное для этой страницы? Она такая:

reloadEntity: function(callback, scope) {
	Terrasoft.chain(
		this.initEntity,
		function(next) {
			this.onEntityInitialized();
			this.actualizeDcmActionsDashboard(next, this);
		},
		function() {
			this.updateDetails();
			this.sandbox.publish("CardRendered", null, [this.sandbox.id]);
			this.hideBodyMask();
			Ext.callback(callback, scope);
		},
		this
	);
},

 

ок, спасибо, буду что то думать.

Показать все комментарии

Интересует такой вопрос, можно ли программно создать подчинённый процесс (который будет привязан к родительскому), аналогично элементу "Подпроцесс". У меня количество подпроцессов не является предопределённым заранее. Поэтому использовать несколько элементов не получится.

Нравится

3 комментария

С привязкой не получалось сделать, а вот как просто запустить процесс из кода можно в этой теме глянуть https://community.terrasoft.ru/questions/mnogokratnyi-zapusk-bp-s-razny…

 

Пример, где SxRecalcPotentialInOppNeed название запускаемого процесса, в Dictionary параметры передаваемые процессы :

UserConnection.ProcessEngine.ProcessExecutor.Execute("SxRecalcPotentialInOppNeed", 
new Dictionary<string, string> {
 
	{ "OpportunityId", opportunityId.ToString() }
 
});

 

Трефилов Павел Сергеевич,

Это я знаю. Мне нужно именно с привязкой к основному это сделать. 

Можно открыть код какого-нибудь компилируемого БП, где есть элемент ProcessSchemaSubProcess и посмотреть, как с ним работают в автогенерируемом коде. Например, в ContactAgeActualizationRunnerProcess подпроцесс определяется так:

ProcessSchemaSubProcess actualizecontactagesubprocess = CreateActualizeContactAgeSubprocessSubProcess();
FlowElements.Add(actualizecontactagesubprocess);
...
protected virtual ProcessSchemaSubProcess CreateActualizeContactAgeSubprocessSubProcess() {
	ProcessSchemaSubProcess schemaActualizeContactAgeSubprocess = new ProcessSchemaSubProcess(this) {
		UId = new Guid("845629d7-6a9f-47ae-8c06-0703688e57ce"),
		ContainerItemIndex = 0,
		ContainerUId = new Guid("d0f0790b-45ea-4f02-b60d-7200272e0e16"),
		CreatedInOwnerSchemaUId = new Guid("bb4d6607-026b-4b27-b640-8f5c77c1e89d"),
		CreatedInPackageId = new Guid("524f976c-dc16-4613-afcd-8360daff9aa0"),
		CreatedInSchemaUId = new Guid("db59d752-4f9e-4fcf-b854-d2eaa0b1f259"),
		EntitySchemaUId = Guid.Empty,
		IsForCompensation = false,
		IsLogging = true,
		ManagerItemUId = new Guid("49eafdbb-a89e-4bdf-a29d-7f17b1670a45"),
		ModifiedInSchemaUId = new Guid("db59d752-4f9e-4fcf-b854-d2eaa0b1f259"),
		Name = @"ActualizeContactAgeSubprocess",
		Position = new Point(505, 166),
		SchemaUId = new Guid("51734939-e406-46f0-b832-0b87c66b860b"),
		SerializeToDB = true,
		Size = new Size(69, 55),
		TriggeredByEvent = false,
		UseBackgroundMode = false,
		UseLastSchemaVersion = false
	};
	InitializeActualizeContactAgeSubprocessParameters(schemaActualizeContactAgeSubprocess);
	return schemaActualizeContactAgeSubprocess;
}

Там же есть функция создания его параметров. Но с использованием этого всего вручную нужно быть осторожным, ничего не пропустить.

 

Может, проще, если подпроцессы запускаются последовательно и их не сильно много, сделать БП с циклом.

Показать все комментарии