CheckBox
Технические вопросы
5.x

Нужно кодом проставить "галочку" в CheckBoxEdit, при этом необходимо избежать срабатывания обработчика, назначенного на IsMyEditCheck.
Такой вариант не помогает, обработчик все равно срабатывает:sad:

Page.MyEdit.SuspendAjaxEvents();
...
Page.MyEdit.ResumeAjaxEvents();

Подскажите, как бы добиться отключения событий?

Нравится

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

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

Уточните, вы точно вызываете эти два метода для контрола CheckBox, а не Edit?

Page.PeriodCheckBox.SuspendAjaxEvents();
Page.PeriodCheckBox.ResumeAjaxEvents();

Попробуйте следующим способом:

Page.MyEdit.SuspendAjaxEvents();
Page.AddScript(Page.MyEdit.ClientID + “.setChecked(1)”);
Page.MyEdit.ResumeAjaxEvents();

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

Page.FieldAEdit.SuspendAjaxEvents();
Page.FieldBEdit.SuspendAjaxEvents();
Page.FieldCEdit.SuspendAjaxEvents();
// много много раз

А может есть какой способ для Page и всего ее содержимого события отключить? Чтобы не писать для каждого контрола индивидуально...

Для всей станицы, насколько я знаю нет, я вот для фрейма (который включает в себе n-контролов) - да.

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

"Олейник Дмитрий" написал:

Для всей станицы, насколько я знаю нет, я вот для фрейма (который включает в себе n-контролов) - да.


Спасибо, попробую!
"Зверев Александр" написал:

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


Тоже вариант решения, но интересна была возможность массовых операций:smile:

Показать все комментарии
Получить название Группы и данные
Технические вопросы
5.x

Добрый день,
Как можно получить название активной группы в разделе "Активности"
Например,

В группе "Все активности" есть динамическая группа "Папка Б". Когда нажимаем на эту группу в реестре формируются данные.
И над реестром есть кнопка "Установить Группу".
Задача: После нажатия я должен получить Ид и Название Группы и Все Данные по этой группе
Спасибо

Нравится

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

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

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

Показать все комментарии
Технические вопросы
5.x

Доброго времени суток!

Вопрос: есть ли в BPM возможность отображать какое-нибудь окно выполнения скрипта? Например какая-нибудь полоса, отражающая выполнение функции в скрипте (как в интеграции с 1С в 3.4, например).

Если есть, дайте пример пожалуйста, как это можно сделать для своего кода.

Версия BPM 5.4.0.317

Нравится

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

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

Добрый день!

Подскажите ShowLoadMask - это свойство окна?
Как правильно регулировать это свойство в скрипте?

Например так, если у вас выполняется длительная операция по нажатию на кнопку:

SearchButton.AjaxEvents.Click.ShowLoadMask = true;

Добрый день.

Где именно это должно быть прописано?
Сейчас на событие нажатие на кнопку стоит скрипт, в начале которого прописано:
Page.SendToQMS.AjaxEvents.Click.ShowLoadMask = true;
Но ничего не происходит, окна загрузки нет.

Попробуйте на PageLoadComplete

Показать все комментарии
null
update
Технические вопросы
5.x

Пытаюсь решить простую задачу - нужно в скрипте "обнулить" значение поля справочника. Поле не обязательное для заполнения, значение отличное от null в него записать удается, а вот как стереть из него все?

update = new Update(Page.UserConnection, "ConsignmentCargo")
        .Set("CurrentRoutePointId", Column.Parameter(DBNull.Value))
        .Where("IsLast").IsNotEqual(Column.Parameter(1))
        .And("ConsignmentId").IsEqual(Column.Parameter(CurrentConsignmentId));
update.Execute();

В примере это поле CurrentRoutePointId.

Через entity также установить null не удается

var entitySchemaManager = Page.Schema.SchemaManagerProvider.GetManager("EntitySchemaManager") as Terrasoft.Core.Entities.EntitySchemaManager;
        var entitySchemaQuery = new EntitySchemaQuery(entitySchemaManager, "ConsignmentCargo");
        entitySchemaQuery.AddColumn("CurrentRoutePoint");
        entitySchemaQuery.Filters.Add(entitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Consignment", CurrentConsignmentId));
        entitySchemaQuery.Filters.Add(entitySchemaQuery.CreateFilterWithParameters(FilterComparisonType.NotEqual, "IsLast", 1));       
        var entities = entitySchemaQuery.GetEntityCollection(UserConnection);  
               
        foreach (var entity in entities) {
                entity.SetColumnValue("CurrentRoutePointId", Column.Parameter(Guid.Empty));
                entity.Save();
        }

Нравится

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

Александр, попробуйте так

Column.Parameter(null, "Guid")

Думаю, такие примеры тоже пригодятся

			var dbNull = DataTypeUtilities.ValueAsType<Guid>(DBNull.Value);
			Assert.AreEqual(Guid.Empty, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<Guid>(null);
			Assert.AreEqual(Guid.Empty, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<DateTime>(DBNull.Value);
			Assert.AreEqual(DateTime.MinValue, dbNull);
 
			var dbNull = DataTypeUtilities.ValueAsType<DateTime>(null);
			Assert.AreEqual(DateTime.MinValue, dbNull);

"Раловец Ольга" написал:

Александр, попробуйте так

Column.Parameter(null, "Guid")


Сработало, спасибо!

"Александр Кудряшов" написал:

.Where("IsLast").IsNotEqual(Column.Parameter(1))


Александр, такой код не переносим на Oracle. К сожалению, или к с частью :), mssql очень много "додумывает" за разработчика и неявно приводит типы данных. Но Oracle не сможет интерпретировать 1 как true. Поэтому лучше написать:

.Where("IsLast").IsNotEqual(Column.Parameter(true, "Boolean"))
Показать все комментарии

Добрый день,
есть BPMOnline SD + CRM on-site.
Хочу добавить вот такйю штуку:
в разделах "Инциденты" и "запросы на обслуживание" сделать так, чтобы при нажатии правной кнопки мыши на запись, можно было поменять статус инцидента, "закрыт" или "в работе", например. Т.е. чтобы не открывать карточку инцидента, только для того, чтобы поменять статус.
Куда копать?
Спасибо.

Нравится

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

Здравствуйте, Кирилл.

Вам нужно на событии нажатия на это меню выполнить Update запрос^

var myUpdate =  new Update(userConnection, "MyTable")
        .Set("Number", new QueryParameter("Number", T1.Number + 1, "Int")
.Where("Id").IsEqual(Column.Parameter(new Guid(Page.DataSource.ActiveRow.GetColumnuValue("ID").ToString())));
myUpdate.Execute();

Добавить само меню можно с помощью этих методов:

Terrasoft.Configuration.DynamicMenuConstructor.ClientAppendMenuItem()
Terrasoft.Configuration.DynamicMenuConstructor.SetComponentMenuItemClickSignal()

Телефонические компоненты их используют, например.

Вот кусочек кода, динамически строящий менюшку системных переменных, и привязывающий на OnClick сигнал "SysVariableMenuItemClick":

foreach(var systemValueItem in UserConnection.SystemValueManager.GetItems()) {
	var systemValue = UserConnection.SystemValueManager.GetInstanceByUId(systemValueItem.UId);
	Terrasoft.Configuration.DynamicMenuConstructor.ClientAppendMenuItem(
		Page, Page.AddSysVariableButton.ClientID,
		systemValue.Name, systemValue.Caption.ToString(),
		new ControlImage(), systemValue.Name, "SysVariableMenuItemClick");
}
Terrasoft.Configuration.DynamicMenuConstructor.SetComponentMenuItemClickSignal(Page, Page.AddSysVariableButton.ClientID, "SysVariableMenuItemClick");

Дмитрий, спасибо за ответ.
Мне нужно искать OnClick в БП на "странице раздела Запросы на обслуживание"? Там нет.

Кирилл, добавляете в БП страницы сигнал "MySignal" (к примеру), после него элемент скрипт, где получаете ID записи и выполняете UPDATE. Как привязать сигнал MySignal к событию OnClick вашей кнопки контекстного меню - описано выше.

Дмитрий, спасибо.
Мне это не совсем просто дается. В какое место БП добавить сигнал? У меня в БП этой страницы куча
И сигнал какого события: начальное, промежуточное генер., промежуточное обрабатывающее, завершающее?

Здравствуйте, Кирилл!

Начиная с версии 5.4 есть возможность запускать БП по определенному событию. Дл яэтого используется элемент Сигнал (см приложение)

Здраввствуйте, Анна.
Вообще у меня 5.2 on-site и такой элемент у меня есть. Только я не пойму куда его вставить.
Кстати, а когда будет 5.4 доступна для клиентов, у которых on-site версия? И если 5.4 уже есть, есть какой-нибудь release notes?

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

Тогда как начиная с версии 5.4 БП может стартовать по событию, например, добавление или изменение объекта. Кроме того, стартовый элемент Сигнал в 5.4 имеет отдельное окно найтройки, и может быть запущен с неким фильтром. Детальнее в документации.

Показать все комментарии
и из базы данные по динамическим группам
программно
Технические вопросы
5.x

Добрый день, Как можно получить данные которые попадают в определенную динамическую группу из базы и в самом CRM-е( по скрипту, если сам этот раздел не был открыт) ?

Спасибо

Нравится

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

Что касается выборке на уровне базы данных, то это не возможно, так как реализация фильтра описана в скриптах, в саму базу данных передается информация в таком примерно виде :

0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C46696C746572734275696C646572526F6F744E6F646520547970653D2246696C746572734275696C6465724974656D73223E0A20203C4974656D20547970653D224C6F6F6B757046696C746572734275696C6465724974656D2220446174614669656C644E616D653D22436F6E74616374547970654944223E0A202020203C4974656D2056616C75653D227B34374342433642422D443734452D343837322D413438382D3735434330313132323133367D222F3E0A202020203C446973706C617946696C656456616C7565733E0A2020202020203C4974656D2056616C75653D22D0A1D0BED182D180D183D0B4D0BDD0B8D0BA20D092D0B0D188D0B5D0B920D0BAD0BED0BCD0BFD0B0D0BDD0B8D0B822205549443D224533414645443245313346393439423342333737443836424332333530443443222F3E0A202020203C2F446973706C617946696C656456616C7565733E0A20203C2F4974656D3E0A3C2F46696C746572734275696C646572526F6F744E6F64653E0A

Как Вы сами понимаете, оперировать этими данными нет возможности, единственным вариантом , используя запросы, есть вариант используя стандартную конструкцию select ......join... where....

Если использовать конфигурацию самой CRM системы, то это может иметь примерно вот такой вид:

string serializedString = string.Empty;
var FolderId = " Folder Guid";
var schemaName  = "Activity";
// Получаем строку из базы по идентификатору группы
var manager = UserConnection.GetSchemaManager("EntitySchemaManager") as Terrasoft.Core.Entities.EntitySchemaManager;
var entitySchema = manager.GetInstanceByName(schemaName);
Entity entity = entitySchema.CreateEntity(UserConnection);
var valueColumn = entitySchema.Columns.GetByColumnValueName ("SearchData");
if (entity.FetchFromDB(entitySchema.GetPrimaryColumnName(), FolderId)) {
                using (MemoryStream stream = entity.GetStreamValue(valueColumn.ColumnValueName)){
                               if (stream != null) {
                                               stream.Position = 0;
                                               serializedString = Terrasoft.Common.StreamUtilities.GetStreamContent(stream);
                               } else {
                                               serializedString = String.Empty;
                               }
                stream.Flush();
                }
}
//Если ничего не нашел очищаем текущие фильтры
if (string.IsNullOrEmpty(serializedString)) {
                if (string.IsNullOrEmpty(FilterName)) {
                               FilterName = "FilterEdit";
                }
                var oldFilters = dataSource.CurrentStructure.Filters.FindByName(FilterName) as DataSourceFilterCollection;
                if (oldFilters != null) {
                               oldFilters.Clear();
                }
                return;
}
//Конвертируем строку в фильтры
var jsonConverter = new DataSourceFiltersJsonConverter(UserConnection, dataSource){
                                                                                                              PreventRegisteringClientScript = true
                                                                                              };
var filters = JsonConvert.DeserializeObject<DataSourceFilterCollection>(
                                                                                              serializedString, jsonConverter);
 
//Загружаем фильтры для текущего датасорса, можно использовать и в запросе
if (filters != null) {
                var existingFilterCollection = dataSource.CurrentStructure.Filters.FindByName(filters.Name) as DataSourceFilterCollection;
                if (existingFilterCollection != null){
                               existingFilterCollection.Clear();
                               var filtersCollection = filters as DataSourceFilterCollection;
                               foreach (var filterItem in filtersCollection) {
                                               existingFilterCollection.Add(filterItem);
                               }
                               existingFilterCollection.LogicalOperation = filters.LogicalOperation;
                               existingFilterCollection.IsEnabled = filters.IsEnabled;
                               existingFilterCollection.IsNot = filters.IsNot;
                }
                else {
                               dataSource.CurrentStructure.Filters.Add(filters);
                }
}

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

С уважением Сергей :)

Теоретически решить задачу можно.
Самый простой вариант:
Доработать конфигурацию и БД. В таблице рядом с полем, где храниться фильтр, добавить текстовую колонку и писать sql текст фильтра. Его можно будет получить методами на уровне приложения. Для этого у запросов есть методы для получения текста запроса сразу со значением параметров. Но тут есть нюанс с системными переменными - такими как текущий пользователь и т.п. На уровне приложения их можно узнать из текущей сессии, но на уровне sql сервера - нет такой информации.
Смотрите из SDK:
BuildParametersAsValue
GetSqlText

Вариант сложный:
Написать CLR хранимую процедуру, которая используя наши .net сборки, сможет получить текст фильтра на уровне sql севера. В таком случае необходимо будет постоянно обновлять сборки на sql сервере в случае их обновлений для приложения (сайта). Так же станет вопрос с параметрами и системными переменными.

Добрый день.
Скажите на одном примере запроса: как получить все-таки это поле searchdata?
Либо где посмотреть в коде?
Спасибо!

Кирилл, Выше же есть пример, где получаем SerachData, и на основании его пытаемся воссоздать фильтр EntitySchemaQuery:

var valueColumn = entitySchema.Columns.GetByColumnValueName ("SearchData");

Дмитрий, я имел в виду запрос SQL.

"Sergey Karpenko" написал:Что касается выборке на уровне базы данных, то это не возможно, так как реализация фильтра описана в скриптах, в саму базу данных передается информация в таком примерно виде :

0x3C3F786D6C2076657273696F6E3D22312E302220656E636F64696E673D225554462D38223F3E0A3C46696C746572734275696C646572526F6F744E6F646520547970653D2246696C746572734275696C6465724974656D73223E0A20203C4974656D20547970653D224C6F6F6B757046696C746572734275696C6465724974656D2220446174614669656C644E616D653D22436F6E74616374547970654944223E0A202020203C4974656D2056616C75653D227B34374342433642422D443734452D343837322D413438382D3735434330313132323133367D222F3E0A202020203C446973706C617946696C656456616C7565733E0A2020202020203C4974656D2056616C75653D22D0A1D0BED182D180D183D0B4D0BDD0B8D0BA20D092D0B0D188D0B5D0B920D0BAD0BED0BCD0BFD0B0D0BDD0B8D0B822205549443D224533414645443245313346393439423342333737443836424332333530443443222F3E0A202020203C2F446973706C617946696C656456616C7565733E0A20203C2F4974656D3E0A3C2F46696C746572734275696C646572526F6F744E6F64653E0A

Как Вы сами понимаете, оперировать этими данными нет возможности, единственным вариантом , используя запросы, есть вариант используя стандартную конструкцию select ......join... where....

Показать все комментарии
RADMIN
Технические вопросы
5.x

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

Можна ли связать RADMIN (безопасного удалённого управления компьютерами) с полей (колонкой) контрагента на карточки инцидент?

Заранее Спосиба,
С уважением Гюнель

Нравится

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

Здравствуйте, Гюнель.

Не совсем понял Вашу задачу. Да, есть программа Radmin, которая позволяет удаленно подключатся к рабочему столу другого ПК. Есть карточка "Контрагент" в системе.
Что вы хотите связать?

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

Извините я перепутала продукт.
Хочу создат кнопку "RADMIN" на карточке "ContactEditPage" (TerraSoft BPMOnline). Как сделать что бы при нажатии на эту кнопку открывался "Radmin Viewer"? (Влож. файл "RADMIN.pptx")

radmin.pptx

Заранее Спосиба,
С уважением Гюнель

Можно зарегистрировать Radmin так, чтобы он открывался по определённому виду ссылок в браузере, см. тут:
[quote]
Ну не так уж и нельзя...

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

Пример файла для создания протокола — radmin_protocol.reg
Исправьте путь к радмину и лаунчеру.
Обратите внимание — тут должны быть двойные слэши!
Запустите с админскими правами.

Код

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\radmin]
@="URL: Radmin Protocol"
"URL Protocol"=""

[HKEY_CLASSES_ROOT\radmin\DefaultIcon]
@="C:\\Program Files\\Radmin Viewer 3\\Radmin.exe"

[HKEY_CLASSES_ROOT\radmin\shell]

[HKEY_CLASSES_ROOT\radmin\shell\open]

[HKEY_CLASSES_ROOT\radmin\shell\open\command]
@="\"C:\\Program Files\\Radmin Viewer 3\\Radmin_launcher.cmd\"" \""%1\""""

А как написать логику, чтобы кнопка формировала ссылку, вида radmin://<Значение из поля> ? Я так понимаю, что надо создать кнопку, а для нее уже в БП создать событие? Если можно, то подробнее. Спасибо.

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

Можно воспользоваться

Response.Redirect("URL");

на событии нажатия на кнопку.
Значение поля можно получить из Page.DataSource.

Немного не понял. У меня есть поле, например IP. Как мне написать? Спасибо.

Кирилл, примерно так:

string IP = Page.DataSource.ActiveRow.GetColumnValue("IP").ToString();
string URL = "radmin://" + IP;
Response.Redirect(URL);
Показать все комментарии
Ключевые показатели эффективности (KPI)
Технические вопросы
5.x

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

Как можно создать (настроит) новое ключевые показатели эффективности KPI (например, показатель качества и метрика для SLM или же IM)?

Заранее Спосиба.
С уважением,
Гюнель

Нравится

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

Уважаемая Гюнель!

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

Стандартными являются следующие отчеты\графики:
- общее количество инцидентов;
- среднее время разрешения инцидентов;
- среднее время разрешения инцидентов по приоритетам;
- среднее число инцидентов, разрешенных в рамках соглашений (SLA);
- процент инцидентов, разрешенных первой линией поддержки (без направления в другие группы);
- средняя стоимость поддержки на инцидент;
- число решенных инцидентов на одно рабочее место или на одного сотрудника службы Service Desk;
- инциденты, решенные без посещения пользователя (удаленно);
- число (или процент) инцидентов с первоначально некорректной классификацией;
- число (или процент) инцидентов, неправильно распределенных в группы поддержки.

Показать все комментарии
в зависимости от родительского элемента
Фильтрация реестра в деталях «Активность» с типом звонок
Технические вопросы
5.x

Добрый день, задача по BPMOnlineCRM
Как сделать так, чтобы при выделении в реестре любой задолженности в деталях "Активности" отражались только задачи с типом "Звонок" этой задолженности
Спасибо

Нравится

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

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

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

Последовательность действий такая:

1. Создается реестр, унаследованный от реестра детали;

2. В рабочих местах переопределяется реестр;

3. Создаете обработчик события PageLoadComplete и в скрипте обработчика добавляете фильтрацию:

var dataSource = Page.DataSource;
var ActivityType
var currentStructure =  dataSource.CurrentStructure;
var FullFilter = currentStructure.CreateFiltersGroup("FullFilter",LogicalOperationStrict.And);
var filterCall = currentStructure.CreateFilterWithParameters(dataSource.Schema, FilterComparisonType.Equal, "Type.Code", "Call"));
FullFilter.Add(filterCall);
DataSourceFilter = FullFilter;
Page.ThrowEvent("LoadRowsByFilter");
dataSource.CurrentStructure.Filters.Add(FullFilter);
dataSource.LoadRows();

Спасибо, получилось
Появилась схожая задача

Как вы знаете есть раздел "Активности", где есть реестр активностей("Активность") и группы активностей("Активность в группе").

Задача: Необходимо создать отдельный раздел "Активности с типом Звонок" и с отдельной группой, чтобы группы "Активность в группе" не было
Как это можно реализовать?

Спасибо

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

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

Показать все комментарии
5.x
справочник сотрудников
Технические вопросы

BPM 5.2
Как на странице вывести не справочник всех контактов, а только справочник сотрудников своей компании?

Нравится

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

Здравствуйте, Илья!

Для этого контакты следует отфильтровать по типу "Содтрудник". При необходимости можно создать динамичекую группу.

Я про элемент страницы "справочник". Там можно фильтровать? Как?

Примерно так.

Спасибо, вроде то, что надо !

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