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

 

Для того что бы перенести признак деактивации процесса на другую среду необходимо к пакету привязать 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;
}

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

 

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

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

Привет коллеги!

 

Иногда требуется отловить плавающий кейс в работе процесса или "отладить" процесс без использования VisualStudio. Большинство проблем можно решить с помощью трассировки процесса. Но если проблема в коде написанном в скриптаске или методах процесса, то самый простой способ - это добавить логирование.

Для этого необходимо:

1) в Using добавить

global::Common.Logging

2) в коде использовать

var _log = LogManager.GetLogger("BusinessProcess");
var processName = "MyProcess"; //Название процесса для простого поиска логов
_log.DebugFormat(@"{0}: Process was started", processName); //Уровень логирования Debug
_log.InfoFormat(@"{0}: Process was started", processName); //Уровень логирования Info
_log.WarnFormat(@"{0}: Process was started", processName); //Уровень логирования Warn
_log.ErrorFormat(@"{0}: Process was started", processName); //Уровень логирования Error

Если сайт развернут в облаке (cloud), то логи можно получить обратившись в техническую поддержку.

Если же сайт размещен на своих серверах (on-site), то логи необходимо искать по пути C:\Windows\TEMP\Creatio\SiteName\0\Log (этот путь может быть изменен в файле nlog.targets.config, параметр LogDir).

Для уровня логирования Debug и Info логи запишутся в файл Common.log, а для уровня Error - в файл Error.log

По умолчанию минимальный уровень логирования в on-site для логера "Common" указан Info. Изменить его можно в файле ..\Terrasoft.WebApp\nlog.config

<logger name="*" writeTo="commonAppender" minlevel="Info" maxlevel="Warn" />

 

Нравится

Поделиться

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

Добрый день!

Подскажите, есть ли порядок в котором стартуют Бизнес-процессы в следующей ситуации (пример): 

Есть два БП. Один стартует по Сигналу от Объекта. Второй БП без стартового сигнала, но указан на одной из стадий динамического кейса объекта.

Допустим, что по условиям, оба БП должны отработать при переходе на стадию.

Оба запустятся одновременно или сначала отрабатывают БП на кейсе?

Нравится

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

Коллеги, такой вопрос. При запуске кейса в Лидах он стартует со второй стадии, хотя на среде разработки работает корректно, значения по умоланию для стадии в объекте верное, другие процессы не запускаются.

В чем может быть проблема?

Нравится

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

Может на проде в пакете Custom есть замещенный объект Лид и там стоит другое значение по умолчанию для стадии лида? Либо какой-то процесс, который меняет стадию. 

А как создаются данные лиды? Если приходят из Landing page, то ещё в конфигурации Landing page могут указываться значения по умолчанию, в том числе для стадий

Alex Zaslavsky,

Нет, замещенного процесса нет. Процессы посторонние не запускаются, даже все базовые не активны (по лид-менеджменту)

Владимир Соколов,

Нет, создаются по процессу

Вообще, кейс не «стартует», на полосе просто отображается текущее значение справочного поля «стадия», плюс логика при изменении и условия допустимости переходов. Следовательно, нужно понять, кто и когда задаёт значение в поле.

Это может быть значение поля по умолчанию в дизайнере объекта «Лид» в одном из пакетов, в них же логика во встроенных БП на объекте «Лид», отдельные БП на событии создания или изменения лида, логика в событийном слое, триггер или значение по умолчанию в БД или, наконец, JS-логика на стороне карточки. Если создать тестовую запись на уровне ESQ (не сработает логика карточки) и на уровне Insert-запроса (сработает только логика БД), можно подтвердить или отсеять два последних варианта. Остальные нужно проверять, изучая все места вручную.

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

Было бы очень прекрасно (и в том числе с т.з. производительности БП) дать возможность выбирать поля связанных объектов в выборку стандартного элемента БП "Читать данные".



Например, при чтении первого элемента выборки объекта Заказ добавить поле Основной контакт Контрагента в заказе.

Или при чтении счета получать общую сумму связанного заказа

 

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

Здравствуйте, Игорь!

Передали данное пожелание команде разработки для анализа возможности внедрения такой возможности в будущих версиях продукта.

Пока есть обходной вариант получения информации двумя чтениями.

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

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

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

Прихожу к выводу, что при изменении группы ответственных надо знать еще и предыдущее значение группу. Если оно было пустое, то процесс не вызывать. Только вот как реализовать?

Изображение удалено.

Нравится

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

Добрый день.

Если хотите сравнивать значения до и после, то есть 2 варианта.

1. Запускать процесс не по сигналу, а из клиентских скриптов, например, из карточки редактирования обращения.

2. Реализовать данную логику через событийные процессы схемы таблицы на серверной стороне.

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

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

Добрый день.

Если хотите сравнивать значения до и после, то есть 2 варианта.

1. Запускать процесс не по сигналу, а из клиентских скриптов, например, из карточки редактирования обращения.

2. Реализовать данную логику через событийные процессы схемы таблицы на серверной стороне.

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

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

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