Добрый день. Прошу помощи - третий день мучаюсь с этой задачкой. Есть страница редактирования. В ней есть деталь, отображающая (только чтение) записи из того же реестра. Отбор записей в деталь должен проводиться по ряду условий, связанных с полями основной записи на странице редактирования. Мысль в том, чтобы по этим условиям отобрать через EntitySchemaQuery несколько Id и назначить их в фильтр детали через createColumnInFilterWithParameters.

Проблема в том, что результаты EntitySchemaQuery.getEntityCollection отрабатываются в callback-функции, и происходит это в большинстве случаев позже, чем завершается работа функции filterMethod детали, в которой делается вызов getEntityCollection. Фильтр получается пустым.

Ниже проблемный код:

// функция назначена как "filterMethod" детали
applyFilter: function() {
    //
    var vFGroup = Terrasoft.createFilterGroup();
    vFGroup.logicalOperation = Terrasoft.LogicalOperatorType.AND;

    //

    var esq = Ext.create("Terrasoft.EntitySchemaQuery", {
        rootSchemaName: "Tenants"
    });

    esq.addColumn("Id");
    esq.addColumn("ReportMonth");
    esq.addColumn("Area");

    var vArea = this.get("Area");

    // фильтры запроса - должна совпадать дата, и площадь быть в +-20%                    
    esq.filters.add("ReportMonthFilter", 
        esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, 
            "ReportMonth", this.get("ReportMonth")));
    esq.filters.add("AreaFilter", 
        esq.createColumnBetweenFilterWithParameters("Area", 
            vArea * 0.8, vArea * 1.2));

    // до этого места все работает корректно 
    // теперь запускаем запрос и получаем данные
     // насколько я понимаю, архитектурно система распараллеливает задачи,
    // т.е. function(result) и следующая инструкция после getEntityCollection()
    // начинают отрабатываться одновременно
    esq.getEntityCollection(function (result) {
        if (result.success) {

            // добавляем фильтр как UID по списку
            // здесь так можно, больших выборок не предполагается
            var vSelected = [];                        
            result.collection.each(function (item) {
                vSelected.push(item.get("Id"));
            });

            var vIdF = Terrasoft.createColumnInFilterWithParameters("Id", vSelected);

            // нужно как-то гарантировать, чтобы эта операция всегда выполнялась раньше, чем 
            // return vFGroup; в конце функции. Иначе в фильтры попадает пустой список, и фильтр
            // не работает. 
            vFGroup.add("vIdF", vIdF);
        }
    }, this);

    // Интересно, что при первом открытии детали после обновления 
    // страницы операция return vFGroup; 
    // выполняется корректно, т.е. после vFGroup.add("vIdF", vIdF);. 
    //Если дальше закрыть страницу и через реестр
    // открыть другую запись - уже не работает.

    // Также интересно, что если вбить вот сюда:
    // window.alert("!");
    // то пауза будет достаточна для формирования vFGroup 
    // независимо от того, в первый раз я открываю
    // запись или нет

    return vFGroup;
},

 

Нравится

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

Сорри, уже сам разобрался. Надо было всего-то создать property для списка UID и перенести его подгрузку в onEntityInitialized, оставив в applyFilter только сортировку и создание итогового фильтра для детали. 

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

Юрий, вообще, такая постановка намекает, что можно в БД сделать view с нужными данными: каждому Id записи в основном разделе будет соответствовать несколько строк для отображения на детали по нужному условию.

 

Создать объект с такими же колонками, привязать к этой view и далее в разделе настроить деталь стандартными средствами без всякого кода.

Согласен с Александр Зверев
Недавно сам мучался с подобным, гораздо приятнее когда вся логика связок таблиц завернута во фьюху.
Главное не забыть что во фьюхе должны быть также служебные поля:

DROP VIEW IF EXISTS dbo.VwCaseGroup
GO

CREATE VIEW dbo.VwCaseGroup
AS SELECT
  SAU.ContactId AS Id,
  SUR.SysRoleId,
  SUR.CreatedById,---------<
  SUR.ModifiedById,---------<
  SUR.CreatedOn,---------<
  SUR.ModifiedOn,---------<
  SUR.ProcessListeners---------<
FROM dbo.SysAdminUnit SAU
JOIN dbo.SysUserInRole SUR ON SAU.Id = SUR.SysUserId
GO

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

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

Нравится

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

Добрый день.

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

Ниже привожу пример подобной фильтрации:

if (project && project.value) {
	var filterGroup = this.Terrasoft.createFilterGroup();
	var subFilters = Terrasoft.createFilterGroup();
    subFilters.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "EWBProject", project.value));
	filterGroup.addItem(this.Terrasoft.createExistsFilter("[BTProjectDisease:BTDiseaseType:Id].Id",
		subFilters));
	var subFilters1 = Terrasoft.createFilterGroup();
	subFilters1.addItem(Terrasoft.createColumnFilterWithParameter(
		Terrasoft.ComparisonType.EQUAL, "ProjectSpecification", this.get("MasterRecordId")));
	filterGroup.addItem(this.Terrasoft.createNotExistsFilter(" 
       [SpecificationByDiseaseType:DiseaseType:Id].Id",	subFilters1));
}

 

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

Добрый день!Ф
такая задача:
есть фильтр по дате в формате с-по. Как сделать быстрый фильтр где из календаря можно выбрать 1 конкретную дату в 1 поле, не выбирая с и по?

Нравится

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

По идее, нужно примерно так, как с добавлением целочисленного или логического фильтра по полю, но там, где делают  filterCollection.add, вставлять два условия фильтрации, связанные and, по дате больше или равно начала тех суток, которые выбраны в календаре, и дате меньше начала следующих суток.

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

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

Устал искать, инфоромации нигде не нашел.

Есть ли способ почистить этот фильтр от лишних полей, не использующихся в системе в целом, чтобы было удобнее пользоваться быстрым фильтром? 

Нашел в QuickFilterModuleV2 метод initCustomFilterConfig, в котором существует свойство allowedColumns, но если я туда что либо пишу, пропадают вообще все поля без исключения (пробовал писать как-то так:
this.filtersConfig.customFilterConfig.allowedColumns = ["Name", "Owner"];

Нигде использований не нашел. Может кто нибудь пользовался\знает?

Нравится

1 комментарий
Лучший ответ

Ответ оказался прост

Ответ оказался прост

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

Добрый день.

 

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

Пример: Есть контакты, у них есть некий тип. И есть объект, скажем, "Разрешенные типы контактов". Нужно сделать выбор контактов по следующему условию: тип контакта присутствует в разрешенных (это легко), если разрешенные типы заполнены. Если не заполнены, то разрешен любой тип (вот это не понимаю как добавить в условие) 

Технически мне нужен фильтр на сущность Contact вида

Contact.Type in (AllowedTypes.Id) OR (NOT EXISTS (select * from AllowedTypes))

Проблема в том, что в куске после OR требуется фильтр, никак не связанный с Contact, а построитель путей к колонкам автоматически привязывает всё к корневой схеме.

Нравится

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

Добрый день.

 

Вы можете реализовать проверку на заполненность таблицы "Разрешенные типы контактов" простым селектом к этой таблице.

 

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

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

 

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

Если одно или несколько значений справочника устарели и больше не используются, то такие значения можно деактивировать. Деактивированное значение не будет отображаться при выборе значений в справочных полях. При этом пользователи продолжат видеть это значение в тех записях, где оно было указано ранее, и смогут использовать его для фильтрации. По умолчанию возможность деактивировать значения справочника выключена. Разрешить деактивацию записей для нужного справочника можно в разделе [Конфигурация]. Подробнее о настройке читайте в статье “Деактивация записей объектов”.

 

Деактивированное значение справочника [Типы статей базы знаний]

section_lookups_deactivated_record_example.png

 

Коллеги, спасибо за ответы.

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

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

Все настройки фильтров в клиентском коде в итоге всё равно превращаются в запросы к DataService. О фильтрах в ней есть тут и не уверен, что получится такое, как Вы хотите. Сложный exists делают тут, но всё равно со связью с основной таблицей.

 

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

 

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

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

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

 

Уверенна, дорогу осилит идущий...

О, в этой теме ещё через view не предлагали.

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

Кстати, да, как вариант laugh

Итак, я всё-таки решил эту интересную головоломку, оставлю ответ тут на случай если кто-то ещё столкнется с подобным.
Подсказку для начала решения нашел вот здесь - это помогло вспомнить, что для subfilter путь к колонке указывается относительно подсхемы вышестоящего фильтра, а не root-схемы всего запроса, то что нужно.
Однако, получается, что всё равно невозможно составить запрос именно в том виде, что я описал изначально, т.к. вышестоящий фильтр всё же должен быть как-то связан с root-схемой. Поэтому здесь мне пришлось немножко одурачить esq и подсунуть связь там, где её на самом деле нет. Это можно сделать с помощью двух вложенных  фильтров - notexists внутри exists, причем внешний exists должен иметь связь с root схемой и быть true всегда. Например, exists (наш статус в справочнике статусов)
Таким образом, изначальный запрос 

select * from Contact where Contact.StateId = @someState
or not exists (select Id from AllowedStates) /* вот эту часть в чистом виде записать на esq нельзя, нет связи с Contact*/

превращается в

select * from Contact where Contact.StateId = @someState 
or exists (select Id from State where State.Id = Contact.StateId /*вот она нужная связь*/ and not exists (select StateId from AllowedStates)) /* true только тогда, когда true нужный нам notexists.*/

или на js это выглядит примерно так (root-схема Contact, код не проверял, т.к. в оригинале объекты совсем другие и связи запутаннее)

var allowedStateFilterGroup = Ext.create("Terrasoft.FilterGroup");
allowedStateFilterGroup.logicalOperation = this.Terrasoft.LogicalOperatorType.OR;
var stateFilter = Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL,
	"State", someState);	
var notExistsStateFilter = Terrasoft.createExistsFilter("[State:Id:State].Id");
notExistsStateFilter.subFilters.addItem(Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.EQUAL, "Id", someState));
notExistsStateFilter.subFilters.addItem(Terrasoft.createNotExistsFilter("[AllowedStates:State].Id"));
allowedStateFilterGroup.add("StateFilter", stateFilter);
allowedStateFilterGroup.add("NotExistsStateFilter", notExistsStateFilter);

Esq вообще удивительно гибкая штука, стоит только заглянуть чуть глубже привычного createColumnFilterWithParameter.
Как я предполагал, всё что нужно делается прямо внутри функции filters, не нужны тут никакие view, ужас какой, не путайте людей.

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

Может кто сталкивался с таким.

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

Можно зафильтровать добавив в замещаемом модуле код для атрибута

"Owner": {
	"dataValueType": Terrasoft.DataValueType.LOOKUP,
	"lookupListConfig": {
		filter: function() {
			var filterGroup = Ext.create("Terrasoft.FilterGroup");
			filterGroup.add("IsUser",
				Terrasoft.createColumnIsNotNullFilter("[SysAdminUnit:Contact].Id"));
			filterGroup.add("IsActive",
				Terrasoft.createColumnFilterWithParameter(
					Terrasoft.ComparisonType.EQUAL,
					"[SysAdminUnit:Contact].Active",
					true));
			return filterGroup;
		}
}

В продаже это нормально сработало, но в активностях не как не хочет работать фильтр.

Может кто в курсе почему?

Но вообще было бы не плохо сделать это глобально конечно, что бы ответственных можно было добавить только активных пользователей, но я такого не нашел

Нравится

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

Александр, может, в карточке активности в одном из пакетов есть своя логика на этом поле и она мешает Вашей?

Попробуйте посмотреть, какой запрос идёт в одном и другом случае. Сначала — запрос от браузера к веб-сервису, его можно увидеть в «Инструментах разработчика». Если не поможет понять и сайт развёрнут локально, можно запустить SQL-профайлер и посмотреть запросы уже на уровне базы.

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

Проверил все наследования - только в ActivityPageV2 в NUI rfgtnt есть логика через атрибут

"Owner": {
	dataValueType: Terrasoft.DataValueType.LOOKUP,
	lookupListConfig: {filter: BaseFiltersGenerateModule.OwnerFilter}
}

и наследование идет от модуля что наследовался от выше указанного в NUI пакете. У себя в замещенном модуле его и заместил

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

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

Добрый день!

Есть реестр объектов O, на странице используется деталь D, в ней несколько записей, связь детали D с объектом O через атрибут A.

Нужно создать сложный фильтр, по которому в реестре объектов X буду выводиться только те записи, в которых в связанной детали нет записи со значением атрибута Z=1. 

Просто вывести фильтр объектов O, где в записях детали D атрибут Z не равен 1, не поможет. Потому что в детали D могут быть и другие строчки, где атрибут Z = 1. Нам такие записи объекта не нужны.

Можно ли это сделать или такой фильтр настроить нереально?
Конкретно на примере.

Нужно вывести договоры, в которых в детали Визы нет строчки со значением визирующего = Петров Петр Петрович.

Спасибо!

Нравится

2 комментария
Лучший ответ

Боже, как просто, совсем глаз замылился, спасибо))))))))

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

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

Задача:

На странице продуктового каталога (ProductSelectionSchema) необходимо для справочного поля [Прайс-лист] (PriceList) добавить логику фильтрации значений.

https://www.screencast.com/t/KGWpnt5Ab

 

Что попробовал:

"Классический" вариант, объявленный на замещённой странице ProductSelectionSchema. Попробовал просто скрыть "Базовый" прайс-лист.

https://academy.terrasoft.ru/documents/technic-sdk/7-15/primenenie-filtracii-k-spravochnym-polyam

Не помогло.

 

Подскажите, пожалуйста, как именно можно реализовать дополнительную логику фильтрации?

Возможно свойство filters для атрибута нужно объявить в другой схеме/модуле?

Или подскажите на какие методы обратить внимание?

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

 

Нравится

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

Добрый день!
В указанное вами поле попадают записи с детали "Цены" объекта "Продукт" (вкладка "Цены и остатки").
Логика отбора записей реализована в ProductSelectionQueryUtilitiesMixin (метод getProductInBasePriceListEsq), который скорее всего переопределить не получится (модули переопределять нельзя в системе).
Как вариант, удалять записи "Основной" из детали "Цены" продукта. Но это крайне не рекомендуется делать, даже запрещено на уровне системы.

Спасибо за "Наводку", Александр! Думаю можно поработать с методом initCurrencies в ProductSelectionSchema. Хотя тоже не лучший вариант. Попробую всё же разобраться, как именно можно навесить обработчик с фильтром на справочную колонку, так как отключение логики пересчёта, при наличии пункта меню справочника, как вы отметили, не лучшая идея..

Титаев Александр Николаевич,

Покопался еще в коде. Именно получение запроса на выборку списка прайс-листов осуществляется в методе applyProductPriceItemsEsq (ProductSelectionQueryUtilitiesMixin).
Этот метод глобально вызывается в методе getLookupQuery (модуль

ProductSelectionSchema) по клику по лукапному полю (берется обработчик заполнения списка лукапного поля в методе getLookupColumnHandlers).
Что можно сделать:
1) Реализовать свой метод applyProductPriceItemsEsq с нужной вам фильтрацией в ProductSelectionSchema
2) Указать новый метод в getLookupColumnHandlers
3) Указать новый метод в getGridRecordByItemValues

 

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

Задача такая.

Есть деталь с редактир.реестром. На ней поле Продукт. Продукты в справочнике с разными категориями.

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

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

 

 

Нравится

1 комментарий
Лучший ответ

Посмотрите это обсуждение. По фильтрации записей в реестре на форуме очень много обсуждений!

Посмотрите это обсуждение. По фильтрации записей в реестре на форуме очень много обсуждений!

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

Добрый день. Подскажите как можно отфильтровать справочник контактов по группе? Смысл в том что при выборе из справочника в списке должны быть сотрудники только определенной группы (у нас тебе группа "телефермеры")

Нравится

14 комментариев
Лучший ответ

Александр Тыра,

1. Можно сделать эту группу не функциональной, а организационной ролью.

2. Можно попробовать написать свое представление и для фильтрации нужных контактов завязаться на это представление.

Доброе утро.

Ваша группа 'Телефермеры' - это группа администрирования или какая-то другая?

Телефермеры — это как телепузики?smiley

Если это группа администрировования, см. тут. Если группа контактов, то условие фильтра будет даже проще, только по полю FolderId в таблице ContactInFolder. 

Алла Савельева,

"Организационные роли"

Александр Тыра,

Посмотрите решение по ссылке выше, которое привел Александр Зверев.

Алла Савельева,

"Организационные роли" работают, а вот "Функциональные роли" нет

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

Спасибо, решение отличное, но только работают так только 

"Организационные роли", а вот "Функциональные роли" нет

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

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

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

Если есть доступ к базе, напишите SQL-запрос, обращающийся к Contact, SysAdminUnit, SysUserInRole и SysAdminUnitInRole и получающий нужную Вам выборку контактов, а затем адаптируйте его под синтаксис с квадратными скобками.

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

спасибо за совет, попробую

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

Select * from "Contact" INNER JOIN "SysAdminUnit" ON "Contact"."Id" = "SysAdminUnit"."ContactId"
where "SysAdminUnit"."Id" IN (Select "SysAdminUnitId" from "SysAdminUnitInRole" where "SysAdminUnitRoleId" = '{C7C2A8E0-C54A-485B-A7A7-6FE3590E769B}')

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

 

filterGroup.add("IsGroupAccess",
    Terrasoft.createColumnFilterWithParameter(
    Terrasoft.ComparisonType.EQUAL,
    "[SysAdminUnit:Contact].[SysAdminUnitInRole:SysAdminUnit].SysAdminUnitRole.Id",
    "{C7C2A8E0-C54A-485B-A7A7-6FE3590E769B}"));

так пробую - не работает

Александр Тыра,

1. Посмотрите sql-профайлером, какой запрос формируется в базу данных при вызове Ввшего кода.

2. Также посмотрите статьи по принципам построения путей к колонкам вот эту и эту.

 

Алла Савельева,

тут как раз пишут что к таблице этой не добраться такими запросами

https://community.terrasoft.ua/questions/esq-sintaksis-zaprosa-pri-cepo…

Александр Тыра,

1. Можно сделать эту группу не функциональной, а организационной ролью.

2. Можно попробовать написать свое представление и для фильтрации нужных контактов завязаться на это представление.

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