Потрібно створити фільтр, який би гарантував пусту вибірку.
Я собі так уявляю, що фільтр має реалізовувати умову типу 0=1.
Але всі методи на створення фільтрів так чи інакше одним з атрибутів мають поле.

Як правильно реалізувати фільтр ?

Нравится

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

Может, такое сработает?

esq.CreateIsNullFilter("Id");

А [Id] ні за яких умов не стане Guid.Empty() ?

Оно же первичный ключ. Кроме того, фильтр проверяет не Guid.Empty (из нулей), а Null.

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

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

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

Нравится

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

В обработчике события Init процесса страницы карточки надо дописать код вроде:

Page.ContactEdit.PrepareLookupFilter += delegate (object sender, LookupEditEventArgs e) {
        if (!Page.AccountEdit.Value.Equals(Guid.Empty)) {
                var filters = e.Filters;
                filters.Add(new Dictionary<string, object> {
           {"comparisonType", FilterComparisonType.Equal},
           {"leftExpressionColumnPath", "Account.Id"},
           {"useDisplayValue", false},
           {"rightExpressionParameterValues", new object[] {(Guid)Page.AccountEdit.Value}}});
 
        }
};

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

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

На разделе «Контрагент» ест 2 детали:
1. «Карьера контакта»
2. «Недавние Звонки»

На детали «Недавние Звонки» есть поле «Сотрудники» привязанный к справочнику «Карьера контакта». Но почему-то при нажатие на данное поле справочник открывается с пустым значением (реестром). Хотя на детали «Карьера контакта» фильтруется контакты связанных с соответствующему Контрагенту. Где я не правильно настроила? Прощу помочь.

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

Нравится

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

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

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

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

Есть ли ограничение в количестве динамических групп?

С уважением,

Нравится

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

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

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

При изменении\добавлении с детали "Персональных дней" мы меняем на уровне обьекта 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 на вставку или удалении в детали срабатывает изменение записи.

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

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

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

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

С уважением,

Нравится

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.

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

Добрый день.
Подскажите каким образом в системе реализовать так, чтобы при нажатии на кнопку один раз, она была зажата. Грубо говоря, чтобы пользователь мог ставить и снимать событие 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 комментария

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

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

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

С уважением,

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