Здравствуйте!
Такой вопрос:

Есть карточка редактирования раздела "Заявление на перс. дни", у неё есть деталь "Персональный день в заявлении", при добавлении или изменении значения в которой - требуется изменить значение числового поля Кол-во(дней) указать количество выбранных дней добавленных на деталь. (в атаче наглядно)

При изменении\добавлении с детали "Персональных дней" мы меняем на уровне обьекта Entity значение У заявления (тоесть у записи открытой карточки), и само собой разумеется - нужно установить соответствующее на текущей открытой карточке Заявления.

Для этого в карточке редактирования "Заявления на перс. день" после PageOnLoadCompleete я сохраняю в сессии Uid процесса так

var session = System.Web.HttpContext.Current.Session;
if (session["FreeDayStatementPageProcessUid"] == null) {
        session.Add("FreeDayStatementPageProcessUid", Page.Process.InstanceUId);
}

В карточке редактирования детали "Персональные дни" на нажатие кнопки Ok я вытаскиваю из сессии id процесса и высылаю ему сообщение, и сообщение то приходит. Код:

var session = System.Web.HttpContext.Current.Session;
string freeDayStatementPageProcessUId = (string) session["FreeDayStatementPageProcessUid"];           
if (!string.IsNullOrEmpty(freeDayStatementPageProcessUId ))
{
        var process = UserConnection.ProcessEngine.FindProcessByUId(freeDayStatementPageProcessUId );
        if (process != null)
        {
                process.ThrowEvent(process.InternalContext, "FreeDayInFreeDayStatementMessage");
        }
}
return true;
;

И вот тут начинается самое интересное:
В процессе родительского окна (то есть Заявления) я пытаюсь установить значение полю. А поля нет т.к Page = null (в атаче картинка). При этом context и this это тот нужный процесс. Пробовал сохранять Page в параметр отдельно, и тоже Null. Также пытался передавать в ThrowEvent ранее сохраненный контекст Заявления - всё безрезультатно. До контролов не добраться.
Подскажите что я делаю не так?

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

Нравится

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

Похожее делали с помощью клиентской логики.

На PageLoadComplete детали (у нас DiscountGridPage):

AddPageRefreshFunctionality(Page);

функция:

        public static void AddPageRefreshFunctionality(DiscountGridPageSchemaUserControl Page) {
const string methodName = "setNewColumnValues";
            var script = "";
script += @"window."+methodName+ @" = function (newValues){
    var ds = " + Page.OpportunityDataSource.ClientID + @";
    ds.suspendAjaxEvents();
	for(var columnName in newValues){
		var column = ds.getColumnByName(columnName);
		if (column) {
			ds.setColumnValue(columnName, newValues[columnName]);
		}
	}
    ds.resumeAjaxEvents();
};
window.ReloadOpportunityInfo = function () {
    var layout = " + Page.CustomerDiscountControlLayout.ClientID + @";
    layout.callPageMethod('ThrowEvent',{signalName:'RefreshData'});
};";
            script = ";(function(){" + script + "})();";
            Page.AddScript(script);
        }

На детали на событии RefreshData вызываем функцию с параметрами Page и SelectedNodePrimaryColumnValue.
Она создаёт Entity основного раздела с новыми значениями полей:

 public static void OnDiscountFieldsChanged(DiscountGridPageSchemaUserControl Page, Guid opportunityId) {
            var row = FetchCurrentOpportunity(Page.UserConnection, opportunityId, true);
            var isChangesOnCardFlag = false;
            if (row.CDStockDiscountUse != (bool) Page.CDStockDiscountUseCheckBox.Value) {
                row.CDStockDiscountUse = (bool)Page.CDStockDiscountUseCheckBox.Value;
                isChangesOnCardFlag = true;
            }
            if (row.CDConsideredKS != (bool)Page.CDConsideredKSCheckBox.Value) {
                row.CDConsideredKS = (bool)Page.CDConsideredKSCheckBox.Value;
                isChangesOnCardFlag = true;
            }
            if (row.CDConsideredSK != (bool)Page.CDConsideredSKCheckBox.Value) {
                row.CDConsideredSK = (bool)Page.CDConsideredSKCheckBox.Value;
                isChangesOnCardFlag = true;
            }
            if (isChangesOnCardFlag) {
                OpportunityLogicHelper.UpdateFinalDiscount(row);
            }
            UpdateOpportunityFields(Page, row);
        }

Тут в предпоследней строке вызывается функция, которая делает Update в базе для полей в записи в разделе (не показана). Именно Update — чтобы не сработали события на объекте.
А в последней — обновление в карточке, о котором Вы спрашивали:

        private static void UpdateOpportunityFields(DiscountGridPageSchemaUserControl Page, Opportunity opportunity) {
            if (opportunity != null) {
                var info = AmountColumnns.ToDictionary(s => s, opportunity.GetColumnValue);
                var script = "if (window.setNewColumnValues) { window.setNewColumnValues(" + JsonConvert.SerializeObject(info) + "); }";
                script = ";(function(){" + script + "})();";
                Page.AddScript(script);
            }
        }

Там ещё много другой логики, что-то мог и пропустить.

Решение в лоб повесил на события детали DataSourceRemoved, DataSourceLoadRowsResponseRegistered:

var durationEditControl= ControlUtilities.FindControl(Page.AspPage.Controls[0], "DurationEdit", true) as Terrasoft.UI.WebControls.Controls.FloatEdit;
 
if (durationEditControl != null && SelectedNodePrimaryColumnValue != null) {
	var freeDayStatementEntity = new Terrasoft.Configuration.FreeDayStatement(UserConnection); 
	Guid freeDayStatementId = Guid.Empty;
        freeDayStatementId = new Guid(SelectedNodePrimaryColumnValue.ToString());		
	if (freeDayStatementEntity.FetchFromDB(freeDayStatementId)) {
		durationEditControl.SetValue(freeDayStatementEntity.GetTypedColumnValue<decimal>("Duration"));
	} 
}
return true;

В объекте Заяление на перс дни, при добавлении на деталь персональных дней отрабатывает логика в entity которая меняет значение той записи для которой добавили дни.

Можно и так. Возможно, стоит одновременно менять значение поля и в БД (с использованием Entity или Update), чтобы не возникло расхождение, если пользователь поменяет на детали и нажмёт в карточке отмену. Лучше даже Update, чтобы возможный БП по таблице раздела сработал только раз, при нажатии ОК.

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

Можно и так. Возможно, стоит одновременно менять значение поля и в БД (с использованием Entity или Update), чтобы не возникло рахождение, если пользователь поменяет на детали и нажмёт в карточке отмену. Лучше даже Update, чтобы возможный БП по таблице раздела сработал только раз, при нажатии ОК.

Да именно так и делаю через entity на вставку или удалении в детали срабатывает изменение записи.

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

Скажем, есть такая хранимая процедура:

ALTER PROCEDURE [dbo].[spBuildingAddress]
        @AOGUID uniqueidentifier
AS
BEGIN
        SELECT * FROM fias_ADDROBJ WHERE AOGUID = @AOGUID
        SELECT AOGUID FROM fias_ADDROBJ WHERE AOGUID = @AOGUID
END

она возвращает два набора данных (см. прикрепленный файл), можно ли в Террасофте получить доступ к обоим этим наборам? если можно, то как?

версия 3.0.2.244

Нравится

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

Скажите, а зачем? Почему нельзя использовать обычную процедуру, а лучше функцию?

А Вы с какой целью интересуетесь?

А Вы?:wink:

В Terrasoft есть возможность получать в SelectQuery в качестве источника данных результаты, возвращаемые функцией. Для хранимых процедур можно получать значения выходных параметров.

"Зверев Александр" написал:есть возможность получать в SelectQuery в качестве источника данных результаты, возвращаемые функцией

версия 3.0.2 ? там оно уже работало?

И кстати действительно непонятно, почему бы результаты работы данной процедуры не получать без процедуры :) простым сервисом sq_ в Terrasoft

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

версия 3.0.2 ? там оно уже работало?


Можно проверить, тут написано, как такое делается.

И кстати действительно непонятно, почему бы результаты работы данной процедуры не получать без процедуры :) простым сервисом sq_ в Terrasoft


Можно написать view с логикой и привязать сервис tbl к нему.

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

Нет, нельзя. А если узнаете, что как-то можно, напишите.

спасибо...

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

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

BPM 7.5 off-site. Нужно делать поля обязательными / отменять признак обязательности по условию. Поле лукапное, не эксперементировал с другими типами. Поле НЕ помечено как обязательнтое в базе. Вычитал на форуме, что это делается посредством атрибутов:

 

"UsrCustomer":
{
        "isRequired":
        {
                "bindTo": "getUsrCustomerIsRequired"
        }
},

 

Код функции:

 

getUsrCustomerIsRequired: function()
{
        var department = this.get("UsrDepartmentUsr");
        var departmentEngineering = 'c7f45266-747b-47d3-9af1-63978f63f321';
        var result = department && department.value === departmentEngineering;
        return result;
},

 

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

Вопросы:
1. Это баг?
2. Какие есть обходные решения, желательно, работающие? Правила?

UPDATE: Правила работают корректно. Однако, хотелось бы услышать и про биндинг на isRequired атрибута. Ведь если нужно будет более сложное условие, то атрибута будет мало...

Спасибо
-----
Lohika

Нравится

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

Добрый день!

Вы пытаетесь биндиться на поле, а необходимо на колонку в diff.
Нужно установить атрибут isRequired колонке в diff и забиндить на Ваше свойство.

"Вильшанский Дмитрий" написал:

Добрый день!

Вы пытаетесь биндиться на поле, а необходимо на колонку в diff.

Нужно установить атрибут isRequired колонке в diff и забиндить на Ваше свойство.


Помнится, я уже делал так ранее, однако, всё что происходило - появлялся красненький текст и астерикс (валидация), однако поле НЕ становилось required, всмысле, можно было сохранить, даже тогда, когда всё красненькое и поле ПУСТОЕ )) Т.е. тут баг наоборот..

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

Проверил, увы, я был прав :)

Вообщем, саммари:
1. С помощью правил работает (красный текст и нельзя сохранить пустое поле), однако, он не поможет, если сложная логика, нужна функция.
2. С помощью атрибута - пустое поле ВСЕГДА НЕЛЬЗЯ сохранить, даже если текст перестал быть красным.
3. С помощью биндинга на isRequired в diff - пустое поле ВСЕГДА МОЖНО сохранить, даже когда текст становится красный.
Вот такие пироги..

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

{
  "operation": "insert",
    "name": "UsrCustomer",
      "values":
      {
        "layout":
        {
          "column": 0,
            "row": 5,
              "colSpan": 12,
                "rowSpan": 1
        },
          "bindTo": "UsrCustomer",
            "caption":
            {
              "bindTo": "Resources.Strings.UsrCustomerCaption"
            },
              "textSize": 0,
                "contentType": 5,
                  "labelConfig":
                  {
                    "visible": true
                    /*,
									"isRequired": { "bindTo": "getUsrCustomerIsRequired" }*/
            },
              "enabled":
              {
                "bindTo": "getUsrCustomerEnabled"
              },
                "isRequired":
                {
                  "bindTo": "getUsrCustomerIsRequired"
                }
        },
          "parentName": "Header",
            "propertyName": "items",
              "index": 11
    },

Здравствуйте снова.
Вы не могли бы как то откомментировать предыдущий пост с анализом?
Например:
1. Здравствуйте, ведётся анализ разработчиками
2. Здравствуйте, я еще не читал ваше сообщение
3. Здравствуйте, у нас всё работает (но я не проверял)
4. Здравствуйте, я проверил, и у нас всё работает
5. Здр, вы правы, во всём, всегда :)
6. Здр. вы правы насчёт вариантов X и Y, но с Z мы вы неправильно сделали, нужно так..
7. Здравствуйте, есть 4й способ..
8. Ну и так далее

Просто холдер на холдере, бесплатные тестировщики :)

Спасибо!

Еще одна проблема. Я не только должен добавить / убрать признак обязательности, но еще и стереть значение (оно нерелеватно в данном случае). Добавляю / убираю признак isRequired я с помощью правила. Стираю значение я в функции вызываемой из attributes > dependencies, используя this.setColumnValue("ColumnName", null). Что происходит (подозреваю)? Я не могу контролировать порядок вызова методов. Сначала вызвается метод, стирающий значение, пр этом поле еще required, появляется индикация "Specify the value". После этого поле становится required, однако, индикация не пропадает. Сущность сохранить МОЖНО, однако, индикация сбивает пользователя с толку. Он может захотеть попытаться заполнить поле (хотя оно у меня еще и disabled делается).

Пришлите, пожалуйста, полный листинг кода.

Спасибо!

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

"Вильшанский Дмитрий" написал:Пришлите, пожалуйста, полный листинг кода.

Просьба странная, я вам описал 4 проблемы. Две из них различные НЕРАБОТАЮЩИЕ варианты сделать одно и тоже (required по условию). Было бы глупо в коде исползовать то, что не работает. 3-е решение (проблема) работает, именно его я и использовал в коде (используя правила). Проблема этого решения - раздутый синтаксис правил, слишком много кода, чтобы решить такую мелкую проблему, учитывая, что полей может быть много, и вся логика будет разбросана по rules, diff, attributes. 4-я проблема связана с использованием 3-его работающего решения + стиранием значения поля использую attributes > dependencies > this.setColumnValue("FieldName", null) - если поле, будучи required по условию, содержало значение, условие поменялось, и на false условия мы хотим сбросить значение используя attributes > dependencies > this.setColumnValue("FieldName", null), то остаётся надпись "Specify the value", при этом сущность можно сохранить, однако, эта надпись может озадачить пользователя, и он может совершить ненужные действия.
------
Я записал 4 видео, где воспроизвёл все 4 проблемы, показал также клиентский код из инспектора. Надеюсь, Вам это заменит "полный листинг кода".

1. Сценарий 1 - биндинг функции на diff > isRequied (ВСЕГДА МОЖНО сохранить пустое поле)
https://dl.dropboxusercontent.com/u/54624048/ShareX/2015/07/2015-07-11_…
2. Сценарий 2 - биндинг функции на attributes > isRequired (ВСЕГДА НЕЛЬЗЯ сохранить пустое поле)
https://dl.dropboxusercontent.com/u/54624048/ShareX/2015/07/2015-07-11_…
3. Сценарий 3 - использования rules - единственное рабочее решение. Кроме как в сочетании с
https://dl.dropboxusercontent.com/u/54624048/ShareX/2015/07/2015-07-11_…
4. Сценарий 4 - сценарий 3 + сброс значения поля - остаётся нерелватный validation message - "Specify the value"
https://dl.dropboxusercontent.com/u/54624048/ShareX/2015/07/2015-07-11_…
-----
Разбор полётов. Если я очень глупо где-то ошибся - очень сильно прощу прощения, и беру все свои слова обратно.
Я (разработчик, представляю компанию, ваших потенциальных Customers) создал тему на форуме, где указал, что определённый способ решения задачи не работает. Параллельно создал тикет на портале самообслуживания. Тикет быстро закрыли как дубликат на тему на форуме (???). Мне предложили другой вариант. Я ответил, что я уже пробовал тот другой, и он не работал, но так и быть, я перепроверю. Я перепроверил, и сказал, что я был прав, это способ нерабочий. Итого - поддержка дала мне неработающее решение. Возможно, я сделал что-то не так, однако мне не предоставили "правильный" листинг кода. Более того, я провёл анализ известным мне способов достичь желаемого, и достаточно подробно для человека "в теме" описал, что 2 из них откровенно НЕ РАБОТАЮТ, 1 работает (УРА!), однако, он очень громоздкий, особенное, если нужна проверка не НЕСКОЛЬКО условий одновременно.
Я ждал ответа, как соловей лета (в ловушке, как мотылёк в ванной). Ответа ждал почти 2 дня. Написал еще одно сообщение, где попросил поддержку сообщить о статусе. Тишина. Потом, начальство узнало об этом всём, возмутилось, почему закрыли тикет как дубликат на эту тему, и настоятельно попросило ПЕРЕОТКРЫТЬ тикет, что я и сделал. Возможно, еще какие-то рычаги применились. Тут же запустилась формальная процедура (подозреваю), на тикет ответили, и на форуме ответили - предоставьте полный листинг кода.
------------
Мои (наши, компании) ожидания были немного другими:
1. Информацию, которую мы предоставили, проанализируют. Даже в целях улучшения качества продукта, за что нам нужно сказать спасибо. Уже несколько серьёзных проблем было добавлено в Ваш бэклог, что должно Вас радовать, а вот ваших QA нет.
2. Ответственный QA попытается воспроизвести сценарии, отпишется по результатах, и по цепочке это приведёт к ответу.
3. В случае некомпетенции QA, вопрос будет передан разработчику, который сделает то же.
4. Не нужно будет "давить" переоткрытием тикета для реакции.
5. Поддержка даёт только те советы, в которых уверена. А не то, что она "думает", что работает, или работало раньше, или что "наверное работает.". Проверять свои заготовленные "copy-paste" шаблоны на актуальность и соответствие версии продукта.
-------
Ничего личного, отношусь ко всему с юмором, в рестроспективе :)

Спасибо

Используя бизнес правила и dependency на поле изменить поведение системы не получится, чтобы не отображать сообщение о валидации.

В карточке счета реализована асинхронная валидация полей "Контакт" и "Контрагент". Это может помочь.
В схеме InvoicePage2, в методах validateAccountOrContactFilling и asyncValidate реализована обязательность заполнения одного из полей - "Контакт", "Контрагент".

Физически поля не являются required, но они валидируются.

Прилагаю схему InvoicePage2

invoicepagev2.txt

Уже 7.8.1, а установки обязательности через атрибуты до сих пор нет.

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

Данную информацию передали в департамент разработки для рассмотрения возможной реализации в будущих версиях

"Коновалов Игорь" написал:Уже 7.8.1, а установки обязательности через атрибуты до сих пор нет.

Похоже, что в 7.10 тоже :cry:

С помощью валидатора можно выйти из положения в 7.11, если мастер бизнес-правил не подходит (потому, что при некоторых комбинациях условий на одно поле правило может не работать), но вообще печально :сry:  https://academy.terrasoft.ru/documents/technic-sdk/7-11/dobavlenie-vali…

7.14.2 Всё ещё нет, Держу в курсе 

Также см. соседнее обсуждение.

А вообще, есть такая информация:

Это не ошибка. 

Diff – отвечает за представление. И только. Никакой валидации View не делает. 

Этим занимается модель. Если атрибуту модели дописать свойство isRequired – тогда сработает валидация модели при сохранении. 

 

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

Коллеги, а поделитесь, пожалуйста своими наблюдениями и приемами ускорения работы платформы?

Сейчас используется sales commerce 7.5.0.1544 on-demand.

Контрагентов около 100
Лидов около 500
Контактов тоже около 600
То есть немного.

Реально очень часть подолгу загружаются реестры.
Понятно еще, например, когда это в первые раз после обновлений конфигурации, перекешируется наверно вот это всё. Но потом-то?
Причем часто очень неожиданно, например ни с того ни с сего может очень долго загружаться реестр справочников.

Может быть есть рекомендации и best practice по использованию конкретных браузеров, их настроек, определенных системных настроек?

Нравится

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

Я бы начал не с браузеров, а со скорости канала и его качества. Как вариант посмотреть как пинг идет от вас до серверов on-demand где узкие места.
Потом смотрел бы на процесс открытия страницы с точки зрения потребления ресурсов браузером на конкретной клиентской машине - сколько памяти доступно, сколько "ест", сколько ресурсов процессора доступно и используется в процессе.

Пинг и канал нареканий не вызывают, это я смотрел в первую очередь.
Ответ от 195.189.123.118: число байт=32 время=2мс TTL=117
Ответ от 195.189.123.118: число байт=32 время=2мс TTL=117
Ответ от 195.189.123.118: число байт=32 время=2мс TTL=117
Ответ от 195.189.123.118: число байт=32 время=2мс TTL=117

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

Для браузера Google Chrome для увеличения быстродействия можно отключить аппаратную часть. Инструкция следующая:
1) Откройте страницу настроек:

2) Нажмите ссылку отображения расширенных настроек:

3) Отключите флаг "Use hardware acceleration when available" в блоке "System":

Так как у вас on-demand дам радикальный совет - озадачьте производительностью не себя, а команду поддержки on-demand, если проблема на их стороне они ее будут решать, а нет - так в процессе выяснения укажут на "узкие" места в канале, браузере :) как я понимаю, именно в этом смысл облака и платной поддержки

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

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

Как можно настроит так что бы, при выборе ответственного (поле "Ответсвенный" = раздел "Контакт") фильтровалось поле группа (поле "Группа" = справочник "Объект Администрирование") с помощью значка молния на карточке активности (тип "Задача")? (прик. файл)

Заранее большое спосиба.

С уважением,

Нравится

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

Такую реализацию можно посмотреть в BPMonline Sevice Desk 5.X, карточка инцидента BaseServiceRequestInBPMonlineEditPage, сервис фильтруется по сервисному договору.

Там, в частности используются функции.

Первая — получает список отфильтрованных по сервисному договору сервисов:

RecordData[] GetAvailableServicesNew(Guid serviceAgreementId){
if (serviceAgreementId == Guid.Empty) {
	return null;
}
var resultList = new List<RecordData>();
var serviceIdsList = new List<Guid>();
 
var entitySchemaManager = UserConnection.GetSchemaManager("EntitySchemaManager") as EntitySchemaManager;
//in packages
var serviceInServiceAgreementSchemaQuery = new EntitySchemaQuery(entitySchemaManager, "ServiceInServiceAgreement");
var serviceIdQueryColumnName = serviceInServiceAgreementSchemaQuery.AddColumn("Service.Id").Name;
var serviceNameQueryColumnName = serviceInServiceAgreementSchemaQuery.AddColumn("Service.ServiceName").Name;
var packageNameQueryColumnName = serviceInServiceAgreementSchemaQuery.AddColumn("ServicePackage.Name").Name;
var serviceAgreementFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "ServiceAgreement.Id", serviceAgreementId);
var typeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Type.Id", new Guid("f3b90f08-f46b-1410-809e-00155d852b12"));
var packageNotNullFilter = serviceInServiceAgreementSchemaQuery.CreateIsNotNullFilter("ServicePackage");
var activeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Status.Active", true);
IEntitySchemaQueryFilterItem filter = null; 
object[] serviceRequestTypeServiceIds = null;
if (string.IsNullOrEmpty(VirtualEntitySchemaName)) {
	filter = new EntitySchemaQueryFilterCollection(serviceInServiceAgreementSchemaQuery, LogicalOperationStrict.And, serviceAgreementFilter, typeFilter, packageNotNullFilter, activeFilter);	
}
else {
	serviceRequestTypeServiceIds = GetServicesForServiceRequestTypeByServiceAgreement(serviceAgreementId);
	IEntitySchemaQueryFilterItem serviceRequestTypeFilter;
	if (serviceRequestTypeServiceIds.Length == 0 ) {
		//HACK
		serviceRequestTypeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Id", Guid.NewGuid());
	}
	else {
		serviceRequestTypeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Id", serviceRequestTypeServiceIds);
	}	 
	filter = new EntitySchemaQueryFilterCollection(serviceInServiceAgreementSchemaQuery, LogicalOperationStrict.And, serviceAgreementFilter, typeFilter, packageNotNullFilter, activeFilter, serviceRequestTypeFilter);	
}
serviceInServiceAgreementSchemaQuery.Filters.Add(filter);
var servicesInServiceAgreement = serviceInServiceAgreementSchemaQuery.GetEntityCollection(UserConnection);
foreach (var serviceInServiceAgreement in servicesInServiceAgreement) {
	var serviceId = serviceInServiceAgreement.GetTypedColumnValue<Guid>(serviceIdQueryColumnName);
	if (!serviceIdsList.Contains(serviceId)) {
		var serviceName = serviceInServiceAgreement.GetTypedColumnValue<string>(serviceNameQueryColumnName);
		var packageName = serviceInServiceAgreement.GetTypedColumnValue<string>(packageNameQueryColumnName);
		var recordData = new RecordData();
		recordData.Id = serviceId;
		recordData.Name = string.Concat(serviceName, " (", packageName, ")");
		resultList.Add(recordData);
		serviceIdsList.Add(serviceId);
	}
}
//just services
serviceInServiceAgreementSchemaQuery = new EntitySchemaQuery(entitySchemaManager, "ServiceInServiceAgreement");
serviceIdQueryColumnName = serviceInServiceAgreementSchemaQuery.AddColumn("Service.Id").Name;
serviceNameQueryColumnName = serviceInServiceAgreementSchemaQuery.AddColumn("Service.ServiceName").Name;
serviceAgreementFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "ServiceAgreement.Id", serviceAgreementId);
typeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Type.Id", new Guid("f3b90f08-f46b-1410-809e-00155d852b12"));
var packageNullFilter = serviceInServiceAgreementSchemaQuery.CreateIsNullFilter("ServicePackage");
activeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Status.Active", true);
filter = new EntitySchemaQueryFilterCollection(serviceInServiceAgreementSchemaQuery, LogicalOperationStrict.And, serviceAgreementFilter, typeFilter, packageNullFilter, activeFilter);	
if (!string.IsNullOrEmpty(VirtualEntitySchemaName)) {
	serviceRequestTypeServiceIds = GetServicesForServiceRequestTypeByServiceAgreement(serviceAgreementId);
	IEntitySchemaQueryFilterItem serviceRequestTypeFilter;
	if (serviceRequestTypeServiceIds.Length == 0) {
		//HACK
		serviceRequestTypeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Id", Guid.NewGuid());
	}
	else {
		serviceRequestTypeFilter = serviceInServiceAgreementSchemaQuery.CreateFilterWithParameters(FilterComparisonType.Equal, "Service.Id", serviceRequestTypeServiceIds);
	}
	filter = new EntitySchemaQueryFilterCollection(serviceInServiceAgreementSchemaQuery, LogicalOperationStrict.And, filter, serviceRequestTypeFilter);
}
serviceInServiceAgreementSchemaQuery.Filters.Add(filter);
servicesInServiceAgreement = serviceInServiceAgreementSchemaQuery.GetEntityCollection(UserConnection);
foreach (var serviceInServiceAgreement in servicesInServiceAgreement) {
	var serviceId = serviceInServiceAgreement.GetTypedColumnValue<Guid>(serviceIdQueryColumnName);
	if (!serviceIdsList.Contains(serviceId)) {		
		var recordData = new RecordData();
		recordData.Id = serviceId;
		recordData.Name = serviceInServiceAgreement.GetTypedColumnValue<string>(serviceNameQueryColumnName);
		resultList.Add(recordData);
		serviceIdsList.Add(serviceId);
	}
}
return resultList.ToArray();
}

Вторая — строит меню у кнопки:

void SetServiceToolButtonStateNew(LookupEdit serviceLookupEdit, ToolButton serviceLookupToolButton, RecordData[] availableServices){
CreateToolButtonMenuNew(serviceLookupEdit, serviceLookupToolButton, availableServices, "ShowAllServices", AllServicesInAgreementCaption.ToString(), false);
}
 
 
void CreateToolButtonMenuNew(LookupEdit lookupEdit, ToolButton toolButton, RecordData[] availableItems, string allItemsMessage, string allItemsCaption, bool showIfOneRecord) {
toolButton.Menu.Clear();
Page.AddScript(string.Format("{0}.getMenu().removeAll();", toolButton.ClientID));
if (availableItems == null) {
	toolButton.Hidden = true;
	return;
}
var n = availableItems.Length;
var minN = showIfOneRecord ? 1 : 2;
if (n >= minN) {
	toolButton.Hidden = false;	
	var m = Math.Min(n, 10);
	if (n > 10) {
		m = 9;
	}
	for (var i = 0; i < m; i++) {
		var recordData = availableItems[i];				
		var menuItem = new Terrasoft.UI.WebControls.Controls.MenuItem();
		menuItem.Caption = recordData.Name;
		menuItem.CreatedByAjax = true;
		menuItem.EnableViewState = false;
		menuItem.Name = string.Concat(allItemsMessage, "MenuItem", i.ToString());
		menuItem.UId = Guid.NewGuid();
		menuItem.Image = GetServiceObjectIconNew(recordData);
    	toolButton.Menu.Add(menuItem);
		//HACK
		//Page.AddScript(string.Format("{0} = {{}};{0}.setImage=Ext.emptyFn;", menuItem.ClientID));
		menuItem.AllowCallbackScriptMonitoring = false;
		var script = string.Format("window.{0} = {1};\n", menuItem.ClientID, menuItem.GenerateControlScript(true, null));
    	script += string.Format("{0}.getMenu().addItem(window.{1});\n", toolButton.ClientID, menuItem.ClientID);
		script += string.Format("{0}.on('click', function() {{ {1}.setValueAndText('{2}', '{3}'); }}, this);\n", menuItem.ClientID, lookupEdit.ClientID, recordData.Id.ToString(), recordData.Name.Replace("'", @"\'").Replace("\""

А можно ли если не трудно прописать скрипт более детально? А то я что-то не поняла...

С уважением,

Лучше посмотрите целиком в карточке, если есть возможность посмотреть на Service Desk.

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

Добрый день.
Возникла необходимость добавить в деталь блок быстрой фильтрации, как в модуле активности (даты, ответственный). Если с добавлением такого блока в другой раздел проблем нет, то с деталью все сложнее. Буду признателен за помощь в решении этой задачи.
BPM 7.5

Нравится

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

В 7.6 сделали функциональность такую, но крайне урезанную

Иван, добрый день!

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

Как вариант можете обновить приложение до версии 7.6.

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

Добрый день.
Подскажите каким образом в системе реализовать так, чтобы при нажатии на кнопку один раз, она была зажата. Грубо говоря, чтобы пользователь мог ставить и снимать событие Pressed кнопки?

Нравится

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

Может быть проще реализовать чекбоксом? Разница будет только визуальная

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

Антонина, у кнопки надо что-то ввести в поле «Название группы» (группа свойств «Поведение в группе», по умолчанию скрыта) и поставить галку «Независимая кнопка».

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

Добрый день.
Подскажите, как сделать правильно фильтрацию?
В объекте существует атрибут с типом int - Количество комнат.

Я сделала на странице фильтрации несколько CheckBox-кнопок(Количество комнат 1, Количество комнат 2 и т.д.). Необходимо, чтобы когда пользователь ставил например галочку у поля "Количество комнат 1", а также у поля "Количество комнат2", фильтр подбирал по принципу и то или другое.....
Ниже прилагаю свой код, что нужно дописать и как поправить логику работы?

bool NumberOfRoomsCheckBox1 = Page.NumberOfRoomsCheckBox1.Checked;
bool NumberOfRoomsCheckBox2 = Page.NumberOfRoomsCheckBox2.Checked;
bool NumberOfRoomsCheckBox3 = Page.NumberOfRoomsCheckBox3.Checked;
bool NumberOfRoomsCheckBox4 = Page.NumberOfRoomsCheckBox4.Checked;
bool NumberOfRoomsCheckBox5 = Page.NumberOfRoomsCheckBox5.Checked;
if ((NumberOfRoomsCheckBox5)||(NumberOfRoomsCheckBox1)||(NumberOfRoomsCheckBox2)||(NumberOfRoomsCheckBox3)||(NumberOfRoomsCheckBox4)) {
        DataSourceFilter NumberOfRoomsCheckBox1Filter = dataSource.CreateFilterWithParameters(FilterComparisonType.Equal, "NumberOfRooms", "1");
        DataSourceFilter NumberOfRoomsCheckBox2Filter = dataSource.CreateFilterWithParameters(FilterComparisonType.Equal, "NumberOfRooms", "2");
        DataSourceFilter NumberOfRoomsCheckBox3Filter = dataSource.CreateFilterWithParameters(FilterComparisonType.Equal, "NumberOfRooms", "3");
        DataSourceFilter NumberOfRoomsCheckBox4Filter = dataSource.CreateFilterWithParameters(FilterComparisonType.Equal, "NumberOfRooms", "4");
        DataSourceFilter NumberOfRoomsCheckBox5Filter = dataSource.CreateFilterWithParameters(FilterComparisonType.GreaterOrEqual, "NumberOfRooms", "5");

moduleFilters.Add(NumberOfRoomsCheckBox1Filter);
}

Нравится

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

Пример накладывания фильтра на реестр
http://www.community.terrasoft.ru/forum/topic/10764

"Чех Григорий Владимирович" написал:

Пример накладывания фильтра на реестр

http://www.community.terrasoft.ru/forum/topic/10764


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

Антонина, нужно создать группу фильтров, связанных условием «ИЛИ» и добавить фильтры туда.

Спасибо.
Удалось.

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

Добрый день!

Подскажите, пожалуйста, правильно ли работает функциональность наследования при использовании мастера раздела? Добавил пару колонок в контакт с помощью мастера раздела. У видел, что объект Contact в пакете Custom унаследовался не от "последнего" пакета Omnichannel, а от базового контакта.

Нравится

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

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

Наследование объектов при использовании мастера раздела работает корректно. Обратите внимание, в разделе Конфигурация - деталь Зависимости пакетов указана иерархия наследования. Пакет Custom находится внизу цепочки наследования. В целях безопасности и надежности системы базовые пакеты недоступны для изменения/добавления. Таким образов пользовательских доработки попадают в пакет Custom, который наследуется от пакетов с базовой функциональностью.

"Зарицкий Олег Васильевич" написал:Таким образов пользовательских доработки попадают в пакет Custom, который наследуется от пакетов с базовой функциональностью.

Олег, спасибо, но не очень понял:
то есть все изменения, которые компания Terrasoft разработает (в процессе перехода на 7.7, 7.8 и т.п.) в пакете Omnichannel (или любых других промежуточных) будут игнорироваться?

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

В свойствах пакета есть детали: Зависит от пакетов и Зависимые пакеты. Для пользовательского пакета Custom устанавливается иерархия таким образом, что он наследуется от базовых пакетов. Изменения/обновления базовой функциональности/пакетов вступает в силу после применения, т.е. игнорироваться не будут. Конфликты могут возникать при обновлении и только в том случае, если в пользовательском пакете есть доработки, которые изменяют/замещают базовую функциональность.

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

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

У одного пользователя не отображается раздел "Активности". (прик. файл)
У всех других пользователей данной проблемы не существует.
С чем это может быть связанно?

С уважением,

Нравится

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

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

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

Заработала) Большое спасибо.

С уважением,

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