Вопрос

Добрый день!

При вызове скрипта генерирования печатной формы в бизнес-процессе он падает с ошибкой:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Terrasoft.Configuration.ReportService.ReportService.GetSchemaNameByTemplateId(Guid templateId)

Определили, что это возникает только когда бизнес-процесс вызывается сигналом или событием, т.е. только тогда когда процесс запускается от имени Supervisor. Запускаем вручную - всё работает отлично.

Вопросы: как можно заменить Supervisor на другого пользователя? Или может посоветуете как получить UserConnection другого пользователя для выполнения ReportService? Возможно ли обойтись в ReportService без UserConnection?

Спасибо!

У меня такой же вопрос

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

а как происходит инициализация ReportService в бп?

Ранее тема обсуждалась тут и тут. В ReportService в логике функций GenerateMSWordReport или GenerateDevExpressReport есть фрагменты, которые позволяют его запускать только при работе из браузера, но не в фоновом режиме с сервера, когда UserConnection нет. В комментариях один из участников рассказал, что в итоге переделал этот сервис, чтобы не использовать UserConnection. А другой предложил запускать от имени какого-то пользователя посредством ProcessEngineService, так работает нормально.

Варфоломеев Данила,

Процесс запускается через задание-сценарий вызовом 

GenerateMSWordReport, в который передаются параметры бизнес-процесса и UserConnection

 

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

Спасибо вам за информацию!

Мы заметили, что новый функционал в 7.13.2 "Фоновое выполнение операции" предназначен для запуска фоновых задач, которые требуют UserConnection. Я правильно понимаю, что с помощью этого функционала можно создать UserConnection для передачи в GenerateMSWordReport? (https://academy.terrasoft.ru/documents/technic-sdk/7-13/fonovoe-vypolne…)

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

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

Дело не в том, что это конкретно Supervisor. Если под Supervisor зайти в систему и по действию построить отчёт, всё отработает.

Варианты по ссылкам предлагались ещё до появления 7.13.2, можете проверить и этот механизм.

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

Добрый день.

Процесс -> Задание сценарий содержит некий код:

if (UserConnection.GetIsFeatureEnabled("EmailMessageMultiLanguage"))
{
    некий код...
}
else
{
    некий код...
}

При запуске данного процесса всегда отрабатывает ветка "else".

Не могу понять что за параметр "EmailMessageMultiLanguage". В системных настройках по коду ничего найти не удалось... 
В профиле пользователя так же ничего похожего не обнаружил.

У меня такой же вопрос

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

Это Механизм отключения функциональности Feature Toggle. По ссылке написано, как менять значение пользовательскими средствами и где оно хранится в базе.

Конкретно по EmailMessageMultiLanguage на странице включения параметров нет никаких пояснений. Но, очевидно, если его включить, то тут и в других местах выполнение пойдёт по верхней ветке.

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

Спасибо, действительно пройдя по адресу [Адрес приложения]/0/Nui/ViewModule.aspx#BaseSchemaModuleV2/FeaturesPage

попал на некую страницу добавления функциональности и возможностью вкл/выкл этой функциональности. К большому удивлению запись с кодом "EmailMessageMultiLanguage" я не обнаружил. Теперь понятно, почему отрабатывает ветка else.

У меня на тестовом сайте 7.12 Sales Enterprise она есть, выключена. Возможно, зависит от версии.

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

Коллеги, добрый день!

Ранее в сообществе несколько раз поднимались темы использования элемента "Чтение данных" для получения "результирующей коллекции", чтобы в последствии её использовать в элементе "Задание-сценарий" для различных нужд. В версии 7.8 осталось только режимы: "читать первую запись", "считать количество записей" и "считать функцию".

Каким образом в данной версии можно получить Результирующую коллекцию? И каким образом можно к ней обратиться в элементе "Задание-сценарий"?

Заранее спасибо!

У меня такой же вопрос

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

Добрый день!

Пример обработки коллекции из чтения данных в ScriptTask:

EntityCollection entities = Get<EntityCollection>("ReadDataUserTask1.ResultEntityCollection");

var result = new Collection<string>();

foreach(Entity entity in entities) {
    
    var cityName = entity.GetTypedColumnValue<string>("Name");

    string temp = cityName.ToString();

    result.Add(temp);

    }

string displayValue = result.ConcatIfNotEmpty(",");

Set("MyResult", displayValue);

return true;

* MyResult - параметр процесса с типом Строка неограниченной длины

* ReadDataUserTask1 - название элемента Чтения данных

 

Олег, Спасибо!

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

Всем доброго времени суток.
Хотелось бы узнать если ли возможность в элемент бизнес-процесса "Задание-сценарий" вставить запрос к базе данных и если есть, то можно хоть самый простой пример c Select.

У меня такой же вопрос

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

Сергей, такая возможность есть.
Пример можно посмотреть на академии в этой статье.

Спасибо Наталия. Буду разбираться.

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

Добрый день.

Не могу понять как запустить БП из другого БП через элемент "Задание-сценарий". Подскажите, можно ли это сделать?
Так же в запускаемый процесс мне нужно передать параметр.

У меня такой же вопрос

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

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

Запустить БП из ScriptTask можно. Для передачи параметров необходимо использовать словарь. Пример:
DateTime someDate = Get("dateTimeParam");
IDictionary parameters = new Dictionary();
parameters["ContactNum"] = Get("ContactNum");
parameters["starttime"] = someDate.ToString();
IProcessExecutor processExecutor = userConnection.ProcessEngine.ProcessExecutor;
processExecutor.Execute("UsrSomeProcessName ", parameters);

"Зарицкий Олег" написал:Здравствуйте!

Запустить БП из ScriptTask можно. Для передачи параметров необходимо использовать словарь. Пример:
DateTime someDate = Get("dateTimeParam");
IDictionary parameters = new Dictionary();
parameters["ContactNum"] = Get("ContactNum");
parameters["starttime"] = someDate.ToString();
IProcessExecutor processExecutor = userConnection.ProcessEngine.ProcessExecutor;
processExecutor.Execute("UsrSomeProcessName ", parameters);

Спасибо. Попробовала сделать как вы сказали. В элементе "Задание-сценарий" прописала:

UserConnection userConnection=context.UserConnection;
IDictionary<string, string> parameters = new Dictionary<string, string>();
parameters["param1"] = idSale.ToString();
IProcessExecutor processExecutor = userConnection.ProcessEngine.ProcessExecutor;
processExecutor.Execute("UsrProcess23", parameters);

При сохранении и публикации процесса возникает ошибка (скриншот прикрепляю).
Не подскажите что я делаю не так?

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

Зачем придумывать велосипед? Есть элемент "Подпроцесс" - можно использовать его. Альтернативный вариант был описан в теме:
http://www.community.terrasoft.ru/forum/topic/25071

"Демьяник Алексей" написал:Зачем придумывать велосипед? Есть элемент "Подпроцесс" - можно использовать его.

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

Можете из скриптаска дернуть веб сервис, вот статья:
https://academy.terrasoft.ru/documents/technic-sdk/7-4-0/zapusk-process…

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

Коллеги, приветствую.

Есть некоторый код C# в действии "Задание- сценарий", читающий из базы данных определенную информацию и, если таковая есть - устанавливает параметр процесса, скажем, isNewPayments.

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

var userConnection = Get("UserConnection");
Set("isNewPayments", -1);

var selectNewPayments = (Select)new Select(userConnection)
   .Column("t1", "ContactId")
   .Column("t1", "CreatedOn")
   .Column("t2", "CreatedOn")
   .From("Activity").As("t1")
   .Join(JoinType.Inner, "UsrPayments").As("t2")
   .On("t1", "ContactId").IsEqual("t2", "UsrDebtorId")
   .Where("t1", "CreatedOn").IsLess("t2", "CreatedOn")
   .OrderByAsc("t1", "id") as Select;

using (DBExecutor dbExecutor = userConnection.EnsureDBConnection())
{
    using (IDataReader reader = selectNewPayments.ExecuteReader(dbExecutor))
    {
        if(reader.Read()) {
                Set("isNewPayments", 1);
        } else {
                Set("isNewPayments", -1);
        }
    }
}

return true;

Это работает.

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

Если для метода Get я могу указать тип,

var isNewPayments = Get("isNewPayments");

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

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

У меня такой же вопрос

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

Здравствуйте, Алексей!

Уточните, пожалуйста, Вашу задачу.

Вы хотите в параметр процесса записывать коллекцию объектов, или параметр процесса хранит коллекцию и Вы хотите ее получить в элементе "Задание-сценарий"?

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

// Чтение параметра бизнес- процесса
var paramOne = Get<Decimal>("paramOne"); // Тип данных в дизайнере "Дробное число (0,01)"
 
...
paramOne = decimal.Parse(reader["UsrColumnWithData"].ToString());
...
 
// Запись в параметр бизнес- процесса, тип данных не указываю - работает
Set("paramOne", paramOne);

В случае с коллекцией объектов, как использовать Get и Set?

Добрый день!
В новом движке процессов работать можно только с параметрами процесса, либо напрямую с параметрами элементов, на которые настроен маппинг.
Т.е. если есть результат коллекции, с которым необходимо работать в Задание-сценарий подойдет такой пример:
1. Создать параметр процесса типа Строка - TestParam.
2. В значение параметра указать [#Read data 1.First item of resulting collection#].GetTypedColumnValue("Name")
3. В элементе Задание-сценарий работать с параметром.
var contactFullName = Get("TestParam");

Или в свойствах элемента Задание-сценарий убрать птичку "Для интерпретируемого процесса" и писать код как для старого движка.

Здравствуйте, Олег! Спасибо большое за ответ!

Олег, а как быть если ситуация обратная? Сценарий сформировал коллекцию обьектов и её нужно передать в параметр БП?

"Горовецкий Вячеслав Илларионович" написал:

Олег, а как быть если ситуация обратная? Сценарий сформировал коллекцию обьектов и её нужно передать в параметр БП?

Приведите, пожалуйста, пример, где элемент "Задание-сценарий" формирует коллекцию, которая дальше используется по процессу.

Например, я пишу вебсервис, как у вас описано на академии (кстати тот пример не рабочий в 7.7). Этот сервис вызывает бизнес процесс, состоящий из одного элемента типа скрипт, который по заданным параметрам работает с ESQ и формирует, допустим некий список контрагентов (это коллекция неких объектов). Этот список нужно передать в исходящий параметр для выгрузки в качестве результата работы вебсервиса.

А теперь вопрос. Какой должен быть тип исходящего параметра у процесса (Entity или массив Entity) и как в него передать список объектов, полученных в скрипте?

Пример для интерпретируемого процесса:
Важно! В процессе в Usings необходимо подключить:
Terrasoft.Common.Json

var myUserConnection = context.UserConnection;
var esq = new EntitySchemaQuery(myUserConnection.EntitySchemaManager, "Account");
var nameColumn = esq.AddColumn("Name");
var primaryContactColumn = esq.AddColumn("PrimaryContact.Name");
var gorovetskiyContactId = new Guid("CEDA7503-8EAC-4581-B88F-DB537A27EB2C");
var filter = esq.CreateFilterWithParameters(FilterComparisonType.Equal, "PrimaryContact", gorovetskiyContactId);
esq.Filters.Add(filter);
var entityCollection = esq.GetEntityCollection(myUserConnection);
if (entityCollection.Count == 0) {
Set("AccountList", string.Empty);
return true;
}
var accounts = new List ();
foreach(var entity in entityCollection) {
var account = new {
Name = entity.GetTypedColumnValue(nameColumn.Name),
PrimaryContact = entity.GetTypedColumnValue(primaryContactColumn.Name)
};
accounts.Add(account);
}
string serialized = Json.Serialize(accounts);
Set("AccountList", serialized);
// пример для компилируемого процесса: AccountList = serialized
// параметр процесса AccountList - тип неограниченная строка – параметр процесса
//Json.Deserialize>(source) – пример, как выполнить обратное действие
return true;

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

Коллеги, приветствую.

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

F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B

Я выполняю простой запрос из MS SQL Server Management Studio -

SELECT
        UsrInDebtId
FROM
        UsrDebt
WHERE
        Id='F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B';

Получаю какой- то результат.

Аналогично из кода C#

...
myConnection.Open();
SqlCommand myCommand = new SqlCommand("...", myConnection);
SqlDataReader myReader = myCommand.ExecuteReader();
while (myReader.Read()) {
   ...
}
...    

Уникальный идентификатор я сохраняю в параметре addedRecordId -

Guid addedRecordId = Get("addedRecordId");

Далее я хочу использовать класс Select из пространства имен Terrasoft.Core.DB -

var userConnection = Get("UserConnection");
Select select = (Select)new Select(userConnection)
            .Column("UserInDebtId")
            .From("UsrDebt").As("UD")
            .Where("UD", "Id")
            .IsEqual(addedRecordId); // строка 42

Получаю ошибки компиляции -

Как я могу использовать Guid в условии IsEqual?

Был бы весьма признателен за информацию.

Спасибо.

--
С уважением, Алексей Быков.

У меня такой же вопрос

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

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

Например:

string str = "F6F4725A-C7C6-4AA2-BE50-E4878ACB7D4B";
Guid guid = new Guid(str);

А затем уже:

...
.IsEqual(guid);

Хотя и не совсем ясно, что бы это могло дать...

Алексей,

В этом случае можно решить задачу двумя способами:

Вариант 1.
.IsEqual(addedRecordId.ToString());
Вариант 2.
.IsEqual(Column.Parameter(addedRecordId));

Второй вариант более корректный.

Здравствуйте, Олег! Большое спасибо за ответ, попробую сегодня.

В обоих случаях получаю такую ошибку компиляции:

Cannot implicity convert type 'Terrasoft.Core.DB.Query' to 'Terrasoft.Core.DB.Select'. An explicit
conversion exists (are you missing a cast?)

Нужно видеть всю картину, трудно так определить где зарыт камень.
Напишите в техническую поддержку.

Олег, спасибо.

Помогло использование переменной с неявным типом:

var selectQuery = 
	new Select(userConnection) ...
Войдите или зарегистрируйтесь, чтобы комментировать