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

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

Например, у меня есть некоторое задание- сценарий, где я пишу -

// Создание экземпляра запроса, добавление в запрос колонок и источника данных.
Select selectQuery = new Select(UserConnection)
                                        .Column("Id")
                                        .Column("Name")
                                        .From("Contact");
// Выполнение запроса к базе данных и получение результирующего набора данных.
using (DBExecutor dbExecutor = UserConnection.EnsureDBConnection())
{
        using (IDataReader reader = selectQuery.ExecuteReader(dbExecutor))
        {
                while (reader.Read())
                {
                        // Обработка результатов запроса.
                }
        }
}
return true;

(Пример - Использование EntitySchemaQuery для построения запросов к базе данных)

Публикую, компилирую сборку и получаю в итоге -

При попытке компиляции возникло: ошибок - 3, предупреждений - 2

В ходе кодогенерации компиляция не удалась и файлов символов, соответственно, нет - точки останова не срабатывают:

The breakpoint will not currently be hit.
No symbols have been loaded for this document.

Сгенерированный код, который я пытаюсь отладить в Visual Studio -

Нужно- ли определять директивы using в действии "Задание- сценарий"?

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data;
using Terrasoft.Common;
using Terrasoft.Core;
using Terrasoft.Core.DB;
using Terrasoft.Core.Entities;
...

Если да, то они тоже попадут в тело метода ScriptTask1Execute.
Как правильно написать серверный код в действии "Задание- сценарий", чтобы его можно было отладить в MS Visual Studio? Особенно, если на вход действия подается некий параметр события, который в IDE определяет как undefined?

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

Спасибо.

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

Нравится

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

В 7.7 есть особенности использования UserConnection в БП.
Подробнее можно ознакомиться в теме:
http://www.community.terrasoft.ru/forum/topic/14645
Директивы using указываются один раз для всего процесса. Делается это структуре процесса (боковая панель).

Александр, большое спасибо за ответ! Сейчас поизучаю.

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

Кстати сказать, попытался получить экземпляр класса UserConnection и некоторый параметр процесса таким образом:

var userConnection = Get("UserConnection");
var temp = Get("addedRecordId");

Ошибки компиляции:

Если использовать context.UserConnection, то все Ок.

Попробуйте явно указать тип для метода Get

var userConnection = Get<UserConnection>("UserConnection");
var temp = Get<Guid>("addedRecordId");

И судя по ошибкам temp у Вас объявляется 2 раза.

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

Александр, спасибо еще раз!

Да, все верно, temp я объявил два раза. Попробую явно указать тип.

Да, если явно указать тип, то все Ок.

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

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

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

В ..\Terrasoft.WebApp\Web.config настроил выгрузку исходных кодов C# в процессе кодогенерации -

    ...
   
   ...

Подключил библиотеки Terrasoft.

Собственно, пытаюсь отладить какой- нибудь простой запрос, вроде такого -

...
var select = new Select(userConnection)
        .Column("Id")
        .Column("Name")
        .From("Contact");
...

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

Спасибо.

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

Нравится

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

Я могу, конечно, использовать такой код -

using System.Data.SqlClient;
 
static void Main(string[] args)
{
 
	SqlConnection myConnection = new SqlConnection("user id=sa; password....");
 
	try
	{
		myConnection.Open();
		SqlDataReader myReader = null;
 
		SqlCommand myCommand = new SqlCommand("select Id, Name from Contact", myConnection);
		myReader = myCommand.ExecuteReader();
		while (myReader.Read())
		{
			Console.WriteLine(myReader["Id"].ToString());
			Console.WriteLine(myReader["Name"].ToString());
		}
	}
	catch (Exception e)
	{
		Console.WriteLine(e.ToString());
	}
}

- но как отладить такой -

var select = new Select(userConnection)
        .Column("Id")
        .Column("Name")
        .From("Contact"); 

Алексей, для отладки есть еще ряд флагов в конфигах. Подробнее на скриншоте:

Для отладки нужно приаттачиться VS к вашему процессу w3wp.exe (если их несколько, то можно различать по имени пользователя, от которого запущен пул приложения)

В студии открываете выгруженный код, ставите точки останова в нужных местах.

Для получения текста запросов:
- для классов Select,Update,Delete есть метод GetSqlText() и свойство BuildParametersAsValue, которое нужно устанавливать в true для явного получения параметров;
- для классов ESQ есть метод GetSelectQuery(UserConnection), который возвращает объект класса Select, а из него уже можно получить текст запроса.

Также для просмотра запросов к БД можно использовать SQL Profiler

Александр, спасибо огромное! То, что нужно.

Очень полезная статья в дополнение к видеокурсам по разработке на платформе 7.6: Отладка серверного кода

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

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

Хотел бы поинтересоваться относительно возможности инициирования бизнес- процессов событиями страницы.

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

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

Существует- ли какое- либо релевантное событие страницы (onchange на выпадающем списке, например), которое могло бы инициировать бизнес- процесс?

Спасибо.

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

Нравится

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

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

Ну, наверное, пересчет через процесс - ресурсоемкое удовольствие.

Не легче сделать агреггирующую колонку в реестре раздела "Контакты"?
Как вариант, Вы можете настроить "Итоги" в разделе "Договоры", и построить динамическую группу, в которой Вы будете изменять контакт.

Данная реализация подойдет?:smile:

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

Отлично, спасибо большое за ответ - да, подойдет.

Относительно ресурсоемкости согласен.

Тем не менее, вот некоторые размышления на эту тему, если у кого- нибудь появится спортивный интерес - в модели представления можно настроить зависимость колонки и добавить метод- обработчик (см. Как добавить вычисляемое поле), из которого запускать бизнес- процесс, как описано, например, здесь - Запуск процесса с параметрами Действием в карточке

Спасибо!

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

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

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

Подскажите, как отловить сигнал завершения БП со страницы раздела. БП запускается с этой же страницы. А после получения сигнала о завершении, выполнить произвольную функцию.

БП со страницы раздела вызываю следующим кодом:

                                       var processArgs = {
                                                sysProcessName: 'CollectionOfStatistics',
                                                parameters: {
                                                        CreatedById: CreatedById,
                                                        CalcForPeriod: forPeriod
                                                }
                                        };
                                        ProcessModuleUtilities.executeProcess(processArgs);

Нравится

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

Здравствуйте, Олег!

Вы можете вызвать следующий web сервис:
http[s]://<адрес_приложения_bpm'online>/0/ServiceModel/ProcessEngineService.svc/CollectionOfStatistics/Execute?ResultParameterName=RESULTPARAMETERNAME&CreatedById=CreatedById&CalcForPeriod=forPeriod

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

Более подробно о сервисе ProcessEngineService.svc Вы можете почитать по ссылке

RESULTPARAMETERNAME - параметр процесса с типом "Строка". В Вашем кейсе достаточно будет ограничить длину строки 50 символами.

Здравствуйте, Алексей. Спасибо за ответ. Возможно я что-то делаю не правильно. Воспользывался вашим советом. Вызываю БП со страницы раздела следующим методом:

var CreatedById = this.Terrasoft.SysValue.CURRENT_USER_CONTACT.value;
 
var Params = "ResultParameterName=ResultProcess&CreatedById=" + CreatedById + "&CalcForPeriod=false";
 
 
Terrasoft.AjaxProvider.request({
		url: "../ServiceModel/ProcessEngineService.svc/CollectionOfStatistics/Execute?" + Params,
		method: "POST",
		scope: this,
		jsonData: {},
		callback: function(request, success, response) {
			if (success) {
 
//Сюда приходит строка с возвращаемым параметром из БП
//Вида : 
//response.responseText =
//"<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">"ProcessEnd"</string>"
//Как ее правильно обработать? string.replace мне кажется не совсем верным решением
 
                      }
		}
	});

Как правильно обработать строку вида:

response.responseText = ""ProcessEnd""?

И второй вопрос: в БП есть преднастроенная страница. Соответственно, если она вызывается, то страница раздела ничего не ждет. Параметр response.responseText приходит со значением null и метод в котором вызывается БП завешается. Что не так?

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

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

Обработка полностью зависит от Вашей задачи. Так как всегда будет приходить один и тот же параметр, то string.replace, как по мне, очень даже корректное решение.

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

Я ножичек.
Подскажите где есть инструкции видео о том "Как передать параметр ID выбранной записи, строчки в БП ? "

Суть такова(CASE).
1. Пользователь выбирает строчку к примеру документа ID_doc.
2. Нажимает запустить процесс. Сформировать шаблон.
3. Запускается БП где идет чтение из БД по ID_doc

Нигде не могу найти как это сделать поэтапно.
Помогите. Всем заранее спасибо.

Нравится

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

Добрый день!

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

Пример обработчика для запуска процесса по выделенной записи:
runProcess: function(tag) {
var activeRow = this.getActiveRow();
if (!activeRow) {
return;
}
var processArgs = {
sysProcessName: "UsrReadTest",
parameters: {
DocParam: activeRow.get("Id") // DocParam - параметр процесса
}
};
Terrasoft.ProcessModuleUtilities.executeProcess(processArgs);
}

Примеры решения подобных задач можно найти в других постах, например:
http://www.community.terrasoft.ru/forum/topic/13314
http://www.community.terrasoft.ru/forum/topic/11626
http://www.community.terrasoft.ru/forum/topic/12414

Уважаемые мы наверное полные дилетанты. Но у нас версия 7,5. Про 7,5 мало что описано.
Будем благодарны если подскажите:

- КАК заместить нужную схему (откуда будет запускаться процесс) в 7,5 ?
- КАК добавить кнопку/действие в 7,5 ?
- КАК добавить обработчик в 7,5 ?

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

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

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

Спасибо.

Нравится

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

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

А как я могу сделать проверку в условном потоке, если я проверяю допустим счет. Я читаю данные счет и по названию фильтрую. Но если такого нет, то Читать данные выдает ошибку и все. Процес останавливается.

Добрый день!

Как вариант:
После чтения данных добавить условный поток.
[#Читать данные. Id#] != Guid.Empty

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

Есть вопрос, кто сталкивался с этой проблемой прошу помочь
Создал параметр в БП LeadID, дал значения новый идентификатор лида, при создании лида в БП присвоил полю Id значение LeadID, потом в другой карточке сделал изменения и записал в поле лид значение LeadID. Но туда ничего не записывается, в чем проблема?

Нравится

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

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

Не могли Вы поподробнее описать момент:

"Радчук Виталий Владимирович" написал:

Создал параметр в БП LeadID, дал значения новый идентификатор лида, при создании лида в БП присвоил полю Id значение LeadID

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

Дело в том что нужно создать 3 разных лида(в зависимости от условий) а потом в независимости какой был создан вести этот лид дальше по процессу.

В таком случае сделайте наоборот:
1) Создайте параметр бизнес процесса (с типом уникальный идентификатор)
2) После каждого элемента "Добавить данные", который создает лид, используйте элемент "Формула", чтобы заполнить созданный параметр значением Id созданной записи.

В результате, у Вас в параметре будет хранится корректное значение Id лида.

что может значить эта ошибка?
process_obrabotki_zvonkov_error.txt

"Радчук Виталий Владимирович" написал:
The INSERT statement conflicted with the FOREIGN KEY constraint "FKkw7kQYErf0GdDIOp9FOjniv8". The conflict occurred in database "BPMOnline", table "dbo.SysProcessData", column 'Id'.

Где-то на ветвлении в процессе используется обычный поток вместо потока по умолчанию/условного потока. В результате две ветки приходят к одному элементу.

Вот скрин процесса

Пришлите, пожалуйста, настройки элемента "А) Добавить лид".

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

еще вопрос...
сделал как сказали:

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

Виталий,

Предлагаю убедится, какое именно значение передается в поле Лид карточки Звонка. Для этого добавьте во второй ветке автогенерируемую страницу. С помощью элемента Формула передавать на автогенерируемую страницу Id созданного лида.
Также после создания лида попробуйте добавить таймер с задержкой в 1 секунду, после чего передавать значение Id в карточку звонка.

"Зарицкий Олег Васильевич" написал:Виталий,

Предлагаю убедится, какое именно значение передается в поле Лид карточки Звонка. Для этого добавьте во второй ветке автогенерируемую страницу. С помощью элемента Формула передавать на автогенерируемую страницу Id созданного лида.
Также после создания лида попробуйте добавить таймер с задержкой в 1 секунду, после чего передавать значение Id в карточку звонка.


Сделал по другому(решил сделать подобно первой ветке), поменял местами запоминание лида со следующими тремя элементами. И о чудо она сработало так как нужно, в чем ошибка я так и не понял(

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

Всем привет.

Используется BPMonline Bank Sales Версия 7.5.0.1275
Возникает проблема с параметром процесса типа Коллекция. Диаграмма процесса приложена.

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

System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values.
Parameter name: Значение индекса находится вне допустимого диапазона значений
   at Terrasoft.Core.Entities.EntityCollection.FindNodeByIndex(Int32 index)
   at Terrasoft.Core.Process.BirthdayQuery.ScriptTask2Execute(ProcessExecutingContext context)
   at Terrasoft.Core.Process.ProcessFlowElement.Execute(ProcessExecutingContext context)

Индекс при этом равен 1. То есть, от коллекции, похоже, осталась только одна запись.

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

Код сценария Выборка данных у кого ДР

        var esqBirthdays = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "Contact");
        contactIdFieldName = esqBirthdays.AddColumn("Id").Name;
        esqBirthdays.AddColumn("GivenName");
        esqBirthdays.AddColumn("MiddleName");
               
        esqBirthdays.IsDistinct = true;
                       
        //Получение сегодняшней даты
         today = DateTime.Today;
       
        var esqMacrosTypeMonth = EntitySchemaQueryMacrosType.Month;
        var esqFilterByMonth = esqBirthdays.CreateFilter(FilterComparisonType.Equal, "BirthDate", esqMacrosTypeMonth, today.Month);
        esqBirthdays.Filters.Add(esqFilterByMonth);
               
        var esqMacrosTypeDay = EntitySchemaQueryMacrosType.DayOfMonth;
        var esqFilterByDayToday = esqBirthdays.CreateFilter(FilterComparisonType.Equal, "BirthDate", esqMacrosTypeDay, today.Day);
        esqBirthdays.Filters.Add(esqFilterByDayToday);
       
        //Есть моб тел?
        var esqFilterWithMobilePhone = esqBirthdays.CreateFilterWithParameters(FilterComparisonType.Equal, "[ContactCommunication:Contact].CommunicationType", new Guid("F039972E-470E-457F-9B77-65054B3534B0"));
        esqBirthdays.Filters.Add(esqFilterWithMobilePhone);
       
        //Выполнение запроса и получение результирующей коллекции
        entitiesBD = esqBirthdays.GetEntityCollection(UserConnection);
    numberOfentitiesBDInCollection = entitiesBD.Count;
        currentIndexBD = 0;
        esqSqlText = esqBirthdays.GetSelectQuery(UserConnection).GetSqlText();
               
        return true;

Код сценария Формирования текста СМС и номера

        Entity element = entitiesBD[currentIndexBD];
        Guid contactID = element.GetTypedColumnValueGuid>(contactIdFieldName);
    string contactName = element.GetTypedColumnValuestring>("GivenName");
        string contactMiddleName = element.GetTypedColumnValuestring>("MiddleName");
        string BirthDateText = DateTime.Today.ToString("dd MMMM");
        string messageText = "Дорогой(ая) "+contactName+"! Росинбанк поздравляет Вас с Днем Рождения "+BirthDateText+"  и желает Вам всех благ! Росинбанк";
        if(contactMiddleName!=null) messageText = "Дорогой(ая) "+contactName+" "+contactMiddleName+"! Росинбанк поздравляет Вас с Днем Рождения "+BirthDateText+"  и желает Вам всех благ! Росинбанк";
        SMSTextBD = messageText;
       
        var contactComm = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "ContactCommunication");
        var contacctNumberFieldName = contactComm.AddColumn("Number").Name;
       
        var esqFilter1 = contactComm.CreateFilterWithParameters(FilterComparisonType.Equal, "Contact", contactID);
        contactComm.Filters.Add(esqFilter1);
       
        var esqFilter2 = contactComm.CreateFilterWithParameters(FilterComparisonType.Equal, "CommunicationType", new Guid("F039972E-470E-457F-9B77-65054B3534B0"));
        contactComm.Filters.Add(esqFilter2);
       
        var mobilePhoneCollection = contactComm.GetEntityCollection(UserConnection);
        if(mobilePhoneCollection.Count>0)
        {
        phoneNumberBD = mobilePhoneCollection[0].GetTypedColumnValuestring>(contacctNumberFieldName);
        } else
        {
        phoneNumberBD = "No number";
        }
       
        //var SMSObject = new SendSMSClass(SMSServiceAddress);
        //SMSObject.SendSMS(phoneNumber, messageText);

return true;   
csharp>

Нравится

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

Добрый день!
Попробуйте выполнять проверку и автоинкремент индекса в элементе “Задание сценарий”. Например,

if(IndexBD < entitiesBD.Count){
...
IndexBD++;
} else {
...
}
return true;

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

Реализовать возможность смены прав доступа для группы записей (по фильтру). Сейчас это работает лишь для одной записи

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

Добрый день!

Права доступа можно раздать нескольким записям одновременно по условию фильтрации. Следует убедится, что объект на который необходимо раздать права – администрируется по записям.
Пользователь 1 создал несколько записей на детали “Адреса” на странице редактирования контакта. Права по умолчанию для всех записей на детали – все создают – у всех есть доступ.
Выполнил процесс, который забирает права доступа у всех сотрудников компании и предоставляет только 1 пользователю.

В результате все записи на детали “Адреса” отображаются только у Supervisor’а. Процесс создавал в версии 7.6

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

Добрый день.
Помогите разобраться.
Были созданы раздел "Расходных материалов" и деталь в Обращении "Расходные материалы в обращении". Общее поле в них это "Модель картриджа". Мне необходимо посчитать количество израсходованных.
Я построила БП, но возможно будет какой то другой совет как это сделать.
Проблема заключается в БП, он отрабатывается, но результата я не получаю.

text
Скрин
Скрин 1
Скрин 2
Скрин 3
Скрин 4
Скрин 5
Скрин 6

Нравится

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

Добрый день!

Трудно определить причину судя по скриншотам. Лучше обратиться в техническую поддержку для детального анализа.
Примечания:
1. “Читать данные расходных материалов в обращении”. В условии следует поставить логическое ИЛИ. Id = Id. Добавленной записи ИЛИ Id = Id. Измененной записи.
2. Следует убедится, что поля “Количество пустых”, “Количество” и параметр “Сумма пустых картриджей” имеют тип Целое.

Кроме того, можно добавить автогенерируемую страницу перед каждым из элементов. И с помощью элемента “Формула” передавать на страницу значения, который мы получаем из чтения данных. Таким образом можно определить на каком из этапов происходит сбой.

Добрый день.
Спасибо, Олег, за помощь.
Я изменила условие на ИЛИ в "Читать данные расходных материалов в обращении", и добавила чтение данных после изменения записи, и все заработало.

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