Добрый день!
Версия BPMOnline 7.2.0.942
Есть необходимость добавить деталь "продукты в счете" в раздел контрагенты, чтобы видеть все продукты клиента в его счетах.
При добавлении детали проблем не возникло, а с фильтрацией сложности.
Пробовал так:

{
   name: 'product',
   schemaName: 'ProductDetail',
   type: Terrasoft.ViewModelSchemaItem.DETAIL,
   filterPath: 'Invoice',
   filterValuePath: '[Invoice:Account].Id',
   caption: resources.localizableStrings.ProductDetailCaption,
   visible: true,
   collapsed: false,
   leftWidth: '60%',
   rightWidth: '40%',
  wrapContainerClass: 'control-group-container'
}

Выводятся все продукты без какой-либо фильтрации.
Буду благодарен за помощь..

Нравится

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

Здравствуйте, Иван!
Таким образом не получится сложную фильтрацию сделать, так как генератор модели представления детали позволяет накладывать фильтры только для колонок, которые доступны по прямому ключу в модели детали.
Лучше сделать отдельную деталь (или заместить существующую), в которой определить метод "applyFilter", и в нем накладывать фильтрацию.
Аналогичный пример в "ActivityDetail":

var parentApplyFilter = this.methods.applyFilter;
			this.methods.applyFilter = function(select, args) {
				var filterPath = this.filterPath;
				var filterValue = this.filterValue;
				if (args) {
					filterPath = this.filterPath = args.filterPath;
					filterValue = this.filterValue = args.filterValue;
				}
				if (args.filterPath === 'Participant') {
					select.filters.add('participiantdetailFilter', Terrasoft.createColumnFilterWithParameter(
						Terrasoft.ComparisonType.EQUAL,
						'[ActivityParticipant:Activity].Participant.Id', args.filterValue));
					return false;
				}
				else {
					parentApplyFilter.apply(this, arguments);
					return true;
				}
			};

Спасибо Андрей, получилось сделать описанным вами способом!

Добрый вечер,
Подскажите как данный код приспособить к 7.4? Необходимо добавить деталь Продукт в продаже в карточку Контакта, чтобы вывести все продукты которые привязаны к продажам связанным с контактом. С добавлением проблем нет, а вот с фильтрацией ничего не получается, пробовал так

"OpportunityProduct": {
	"schemaName": "OpportunityProductDetailV2",
	"entitySchemaName": "OpportunityProductInterest",
	"filter": {
		"masterColumn": "Id",
		"detailColumn": "Opportunity.UsrContact"
	}
}

выводит ошибку:

Uncaught Terrasoft.UnsupportedTypeException: null is unsupported type

Здравствуйте, Олег!
Попробуйте настроить колонки для детали. Скорее всего, ни одна колонка не добавлена.

Андрей, спасибо огромное, действительно колонки всего лишь надо было настроить

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

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

Версия 7.8.0.1681. Тройной бандл.

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

Добрый день!
В модуле на js требуется запрограммировать такой запрос:

SELECT a.id
FROM Contact a
WHERE a.id > :contactId
AND EXISTS (SELECT id FROM Contact b
        WHERE
        b.id = :contactId AND
        ( (b.DebtorLastName > '' AND a.DebtorLastName = b.DebtorLastName)
        OR (b.BirthDate IS NOT NULL AND a.BirthDate = b.BirthDate)
        OR (b.Phone > '' AND a.Phone = b.Phone)
        OR (b.MobilePhone > '' AND a.MobilePhone = b.MobilePhone)
        OR (b.MobilePhone2 > '' AND a.MobilePhone2 = b.MobilePhone2))
)

часть до exists понятна, а далее не получается...

var select = Ext.create('Terrasoft.EntitySchemaQuery', { rootSchemaName: 'Contact' });
select.addColumn('Id');
select.filters.add('IdFilter', Terrasoft.createColumnFilterWithParameter(Terrasoft.ComparisonType.NOT_EQUAL, 'Id', contactId));

версия BPM 7.2.0.1223

Нравится

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

Спасибо за Ваше обращение. Мы зарегистрировали его в Службе технической поддержки и назначили специалиста, который сможет Вас компетентно проконсультировать по данному вопросу

Здравствуйте, Лариса!
Вот небольшой пример:

var esq = Ext.create('Terrasoft.EntitySchemaQuery', {
                    rootSchemaName: "Contact"
                });
				esq.addColumn('Id');
                esq.addColumn('Name');
                esq.addColumn('Account');
				var f = esq.createExistsFilter('[Activity:Contact].Id');
				var subf = esq.createColumnFilterWithParameter(Terrasoft.ComparisonType.NOT_EQUAL, 'Title', 'Test');
				f.subFilters.add('subtitleFilter', subf);
				esq.filters.add('existActivityFilter',f);

В результате формируется следующий запрос:

SELECT
	[Contact].[Id] [Id],
	[Contact].[Name] [Name],
	[Contact].[AccountId] [AccountId],
	[Account].[Name] [Account.Name],
	[Contact].[PhotoId] [PhotoId],
	[Photo].[Name] [Photo.Name]
FROM
	[dbo].[Contact] [Contact]
	LEFT OUTER JOIN [dbo].[Account] [Account] ON ([Account].[Id] = [Contact].[AccountId])
	LEFT OUTER JOIN [dbo].[SysImage] [Photo] ON ([Photo].[Id] = [Contact].[PhotoId])
WHERE
	EXISTS (
SELECT
	[SubActivity].[Id] [Id]
FROM
	[dbo].[Activity] [SubActivity]
WHERE
	[SubActivity].[ContactId] = [Contact].[Id]
	AND [SubActivity].[Title] <> 'Test')

Андрей у Вас в примере условие exists строится так (такой пример я находила):

WHERE
        [SubActivity].[ContactId] = [Contact].[Id]

а мне связывать напрямую главную таблицу и таблицу подзапроса не нужно

        WHERE 
        b.id = :contactId --тут у меня параметр

также мне не понятно как стоить остальные условия

        ( (b.DebtorLastName <> '' AND a.DebtorLastName = b.DebtorLastName)
        OR (b.BirthDate IS NOT NULL AND a.BirthDate = b.BirthDate)
        OR (b.Phone <> '' AND a.Phone = b.Phone)
        OR (b.MobilePhone <> '' AND a.MobilePhone = b.MobilePhone)
        OR (b.MobilePhone2 <> '' AND a.MobilePhone2 = b.MobilePhone2))

сам запрос можно переписать, например, так:

select a.* from Contact a 
	inner join Contact b on a.Id <> b.Id
where b.id = 'BF66B334-91DC-4E44-8587-4A0620BBC536'
and (
	(a.DebtorLastName <> '' and a.DebtorLastName = b.DebtorLastName)
	or (a.BirthDate is not null and a.BirthDate = b.BirthDate)
	or (a.Phone <> '' and a.Phone = b.Phone)
	or (a.MobilePhone <> '' and a.MobilePhone = b.MobilePhone)
	or (a.MobilePhone2 <> '' and a.MobilePhone2 = b.MobilePhone2)
)

но с точки зрения bpm мне предоставленный вариант показался самым простым...

Лариса, в таком случае можно с помощью отдельных запросов. Так будет проще, думаю.
В запросе ж сравниваются данные по одной записи по сути. Можно сначала получить запись по параметру:

esq.getEntity(contactId, function(result) {...

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

Андрей, запрос выбирает дубли контакта по определенным условиям.
Насчет двух запросов идея понятна, но Вы не ответили по поводу того как сделать такой блок условий:

        WHERE 
        b.id = :contactId AND
        ( (b.DebtorLastName <> '' AND a.DebtorLastName = b.DebtorLastName)
        OR (b.BirthDate IS NOT NULL AND a.BirthDate = b.BirthDate)
        OR (b.Phone <> '' AND a.Phone = b.Phone)
        OR (b.MobilePhone <> '' AND a.MobilePhone = b.MobilePhone)
        OR (b.MobilePhone2 <> '' AND a.MobilePhone2 = b.MobilePhone2) )

Лариса, значит не до конца идею поняли) Или я Вашу. После получения записи по параметру, то есть контакта b в Вашем запросе должно быть что-то вроде:

//...
esq.getEntity(contactId, function (response) {
    if (response.success) {
        var entity = response.entity;
        if (entity) {
            var filterGroup = Terrasoft.createFilterGroup();
            filtersGroup.logicalOperation = Terrasoft.LogicalOperatorType.OR;
            var mobilePhone = entity.get('MobilePhone');
            if (mobilePhone) {
                var mobileFilter = Terrasoft.createColumnFilterWithParameter(
                    Terrasoft.ComparisonType.EQUAL, 'MobilePhone', mobilePhone);
                filtersGroup.add('mobileFilter', mobileFilter);
            }
            //...добавление других фильтров в группу по такому же принципу
            var esqConnectedContact = Ext.create('Terrasoft.EntitySchemaQuery', {
                rootSchemaName: "Contact"
            });
            esqConnectedContact.addColumn('Id');
            esqConnectedContact.filters.add(filtersGroup);
            esqConnectedContact.getEntityCollection(function (result) {
                //callback
            }, this);
        }
    }
}, this);
//...
Показать все комментарии

Предыстория: 5 лет назад, когда мы выбирали CRM-систему под себя, основное, чем поразил Террасофт - это возможность работы с фильтрами и динамическими группами на лету. То есть, чтобы получить оперативную аналитику, не надо звать программиста или строить отчеты в конструкторе. И это реально очень круто!История: за 5 лет 3ка превратилась в 5ку, 5ка в 7ку... О грустном: но за 5 лет я так и не дождался развития самого главного (с моей субъективной точки зрения) инструмента системы, а именно фильтров... Идеи: Очень хочется, чтобы фильтры развивались в 7ке!!! А именно: Сделать возможность фильтрации по вхождению (aka 'like') в расширенном фильтре. Это есть в быстром фильтре, но из быстрого фильтра нельзя сделать динамическую группу!!! Не понимаю, почему то, что есть в быстром фильтре, отсутствует в расширенном: Сделать возможность сравнения 2х полей в фильтре (естественно с проверкой типов). Это будет прорыв! Учитывая предыдущий пункт и великолепные возможности 7ки по фильтации через связанные объекты, можно будет построить фильтр (и динамическую группу по нему), о котором я мечтаю: То есть я смогу смотреть сделки, по которым реальная сумма оплаты по счетам меньше суммы всей сделки. Очень-очень хочется такую возможность!

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

Голосую и поддерживаю идею и пожелания Александра. От себя бы еще хотел добавить уважаемая компания Террасофт пусть в развитие BPMOnline 7.х версии появятся не только фильтры что пожелал Александр, но и возможность создания Пользовательских фильтров с Пользовательскими различными полями, как это было реализовано в Платформе Terrasoft 3.X в сервисах SQL-запросы. Спасибо!!!

Ради справедливости нужно отметить, что по like фильтр можно сделать уже сейчас (через связь+ поле):

но хочется именно простоты. Ведь это работает в быстром фильтре! Видимо смотрится по этой колонке:

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

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

Добрый день. Суть вопроса в теме.
Заранее извиняюсь, если проблема уже обсуждалась, но я не нашла.

P.S. и аналогичный фильтр "Дата создания не равно предыдущая неделя" ?

Нравится

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

Здравствуйте, Виктория!

Уточните, пожалуйста, о какой версии бинарных файлов идет речь?

Дело в том, что подобные фильтры по дате - ядровые, и описанный Вами фильтр был добавлен с определенной сборки 3.3.2. То есть, возможность выбора условия Предыдущий месяц в фильтре по дате создания можно включить, обновив бинарные файлы до последней сборки.

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

У нас 3.3.2.287 версия

Здравствуйте, Виктория!

Для данной версии есть предустановленный фильтр по функции Предыдущий месяц:

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

Обратите внимание, Предыдущий месяц - это с 1-го по 31-е число того месяца, который был до текущего, тогда как Прошлый месяц - это диапазон 30 дней до текущей даты. текущее время при этом не учитывается.

Анна - я виделафильтр "равно предыдущий месяц". Я им прекрасно пользуюсь уже пару лет. Мне нужен фильтр "НЕ РАВНО предыдущий месяц".

Виктория, для "не предыдущего" можно попробовать сделать пользовательский SQL-фильтр с нужным условием вроде такого (месяц):

not (
 [CreatedOn]>=DATEADD(MONTH, DATEDIFF(MONTH,0, CURRENT_TIMESTAMP)-1,0)
  AND [CreatedOn]< DATEADD(MONTH, DATEDIFF(MONTH,0, CURRENT_TIMESTAMP)  ,0))

И подключать его программно, если в блоке фильтрации стоит нужная галка.

Александр , подскажите пожалуйста чуть более подробно. Мне надо добавить пользовательский SQL-фильтр прямо в блок Where (для того sq , в котором это необходимо). Или создать еще какое-то условие - например, фильтр пользователя типа Дата или Exist или какой-то другой?

Виктория, если хотите конкретное решение, опишите конкретную задачу
фильтр пользователя - это те, что используются для фильтрации пользователем в разделах (как у Анны на скриншоте). Если добавлять блок в where, фильтр надо будет включать программно где-то в скриптах на каком-то событии или кнопке.
В общем, опишите более подробно

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

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

1. создать exist фильтр. установить ему галочку НЕ
2. внутри него таблицу установить tbl_ТаКотораяВамНужна задать для нее алиас, чтобы не запутаться
3. в селекте выбрать что-нибудь (ID)
4. в where создать фильтр сравнения, где выставить tbl_ТаКотораяВамНужна.ID = ВашАлиас.ID (основная таблица запроса - первая в списке после параметров) и создать пользовательский фильтр для даты

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

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

На уровне идеи хотелось обсудить сохранение (для последующего использования) и восстановление (раннее сохраненных) фильтров в стандарном окне построения фильтров отчета (wnd_ReportFilters).
В частности интересует что сохранять и где хранить?

Нравится

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

Реализовать сохранение и восстановление фильтров в окне фильтров можно таким образом:
- задать сохранение профиля у окна (свойство UseProfile установить равным True);
- для окна создать обработчики событий OnProfileSerialize и OnProfileDeserialize.
В OnProfileSerialize записывать идентификатор отчета и сохраненные фильтры, в OnProfileDeserialize - считывать данные.
Примеры записи и получения данных в OnProfileSerialize/OnProfileDeserialize Вы можете посмотреть в базовой конфигурации.

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

Добрый день всем.

Помогите понять как правильно настроить отображение записей в разделе Процессы.

Я администратор системы, у меня в этом разделе отражаются списком запущенные всеми пользователями элементы процессов.
У всех остальных пользователей такой роскоши нет. Обычные пользователи в этом разделе видят (ВНИМАНИЕ !) те элементы которые были ими созданы для следующих в процессе исполнителей, те элементы, за которые ответственны другие! А свои элементы они увидеть списком в этом разделе не могут, исключение если пользователь сам выполняет и следующую задачу. В любому случае для таких пользователей раздел по сути бесполезный.

Вопрос возможно в раздаче прав доступа:
1) фильтра по создателю элемента процесса я так и не нашла, а раздел все же фильтруется
2) в разделе Настройка прав доступа в закладке права доступа по умолчанию раздела Процессы нет.
3) таблица tbl_Workflow не администрируется по записям (видимо из-за этого пункт 2)
4) если поставить таблицу tbl_Workflow администрироваться по записям, то у всех пользователей вообще появляется ошибка при попытке открыть свои задачи созданные по процессу, из-за ошибки прав доступа к ним.

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

Версия ТС 3.3.2.287
Заранее спасибо.

Нравится

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

Доюрый день.
Попробуйте изменить фильтр OwnerID в сервисе Workflow\General\Main Grid\sq_Workflow

Старый вариант я переименовал в OwnerID___
Новый - вместо Фильтра сравнения, добавлен "Набор фильтров" : OwnerIDFilter, AuthorIDFilter.

Сделать надо было так , да не совсем так.

В указанных двух CompareFilter надо фильтровать не tbl_Workflow, а tbl_WorkflowItem.
И во втором фильтре конечно по полю CreatedByID.

Спасибо за указание направления , где искать.

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

Здравствуйте,
Есть карточка звонка, в которой нужно вывести грид Проблем, отфильтровав его по HouseID (кастомный раздел), который нужно получить по ContactID (который есть в карточке звонка), по дате начала/дате завершения.

Т.е. нужно получить HouseID по ContactID , по HouseID получить ProblemID.
Как это можно реализовать?
Спасибо.

Нравится

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

Добрый день, Ринат!
Я сделал так (на примере грида контактов в карточке контрагента. Контакты, у которых в поле контрагент указан текущий):
1) Добавил страницу и контейнер окна в карточку Контрагента:

2) В Accounts\General\Main Grid\scr_AccountEdit добавил функцию иницииализации грида контактов:

function InitializeContacts() { 
 
	AccountEdit.ContactsWindow = wndContacts.Window;
	var ContactsDataset = AccountEdit.ContactsWindow.ComponentsByName('dlData').Dataset;
 
 
	SetAttribute(AccountEdit.ContactsWindow, 'ParentItemID', dlData.Dataset.ValAsGuid('ID'));
	SetAttribute(AccountEdit.ContactsWindow, 'EditWindowUSI', 'wnd_ContactEdit');
	SetAttribute(AccountEdit.ContactsWindow, 'WorkspaceDataset', dlData.Dataset);
 
	AccountEdit.ContactsWindow.Prepare();
 
    SetAttribute(AccountEdit.ContactsWindow, 'ParentTypeFieldValue', dlData.Dataset.Values('AccountTypeID'));
    RefreshDetailData(dlData.Dataset, 'ID', ContactsDataset, 'AccountID');
}

3) Добавил вызов InitializeContacts(); в function wnd_AccountEditOnPrepare(Window);

В п.2 к датасету ContactsDataset можно применить дополнительные фильтрации по требующимся параметром
(по аналогии с HouseID (кастомный раздел), который нужно получить по ContactID).

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

Добрый день!

Подскажите, как с помощью стандартных фильтров раздела "Контакты" можно описать следующее условие:

(Контрагент = "Мой контрагент" и Департамент не пусто) ИЛИ (Контрагент > "Мой контрагент" и Департамент пусто)

не могу сообразить :(

Нравится

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

Добрый день!
Возможно вам поможет возможность группировки фильтров в блоки. Для этого надо нажать правой кнопкой на фильтр и выбрать пункт "Группировать". А внутри сгруппированных фильтров связки можно устанавливать любые (И, Или, Или не и т.д.)

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

Здравствуйте!
Задача: Организовать фильтрацию по вложенным записям в древовидном реестре.
Есть грид, который служит только для отображения записей и дерево с одной степенью вложенности.
Записи вида 00001 - корневые
000001-1, 000001-2, 000001-3 - подчиненные
Также в таблице есть поля с идентификаторами ID, ParentID. Для корневых записей ID = ParentID
В общем, все организовано по примеру раздела [Проекты], но в проектах реализован хитрый механизм фильтрации, который позволяет фильтровать по подчиненным записям, с любой вложенности. Вы можете проверить это профильтровав раздел Проекты, по названию подчиненной стадии, предварительно ее создав.
Я подозреваю, что получилось организовать такую хитрую фильтрацию с помощью следующих механизмов:

function InitializeFiltersSchemes() {
        ProjectWorkspace.IsChangeFilterScheme = false;
        ProjectWorkspace.GridFiltersScheme = new Object();
        ProjectWorkspace.GridFiltersScheme.XMLStorage = GetNewXMLStorage();
        ProjectWorkspace.GridFiltersScheme.CustomFilters = GetNewXMLStorage();
        var GridCustomFilters = ProjectWorkspace.GridFiltersScheme.CustomFilters;
        GridCustomFilters.InitRootNode('CustomFilters');
        GridCustomFilters.RootNode.AddChildNode('FiltersData');
        SaveFiltersToScheme(ProjectWorkspace.GridFiltersScheme);
        ProjectWorkspace.GanttFiltersScheme = new Object();
        ProjectWorkspace.GanttFiltersScheme.XMLStorage = GetNewXMLStorage();
        ProjectWorkspace.GanttFiltersScheme.CustomFilters = GetNewXMLStorage();
        var GanttCustomFilters = ProjectWorkspace.GanttFiltersScheme.CustomFilters;
        GanttCustomFilters.InitRootNode('CustomFilters');
        GanttCustomFilters.RootNode.AddChildNode('FiltersData');
        SaveFiltersToScheme(ProjectWorkspace.GanttFiltersScheme);
}

function SaveFiltersToScheme(Scheme) {
        var CustomFiltersNode = Scheme.CustomFilters.RootNode.Items(0);
        CustomFiltersNode.SetAttributeAsBool('ShowForPeriod', chbShowForPeriod.IsChecked, false);
        SetStrAttributeToXMLNode(CustomFiltersNode, 'PeriodType', cbPeriodType.DataField.Value);
        SetStrAttributeToXMLNode(CustomFiltersNode, 'FromDate', dtcFromDate.DataField.Value);
        SetStrAttributeToXMLNode(CustomFiltersNode, 'ToDate', dtcToDate.DataField.Value);
        CustomFiltersNode.SetAttributeAsBool('ShowForOpportunity', chbShowForOpportunity.IsChecked, false);
        SetStrAttributeToXMLNode(CustomFiltersNode, 'Project', edtProject.Value);
        CustomFiltersNode.SetAttributeAsBool('ShowForContact', chbShowForContact.IsChecked, false);
        SetStrAttributeToXMLNode(CustomFiltersNode, 'Contact', edtContact.Value);
        CustomFiltersNode.SetAttributeAsBool('ShowChildren', chbShowChildren.IsChecked, false);
        Scheme.FilterBuilder = GetFilterBuilderXMLDataEx(fbcFilters, Scheme.XMLStorage);
}

function LoadFiltersFromScheme(Scheme) {
        var CustomFiltersNode = Scheme.CustomFilters.RootNode.Items(0);
        chbShowForPeriod.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForPeriod', false);
        var DateEnumID = GetStrAttributeFromXMLNode(CustomFiltersNode, 'PeriodType');
        if (IsEmptyValue(DateEnumID)) {
                dtcFromDate.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'FromDate');
                dtcToDate.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'ToDate');
        } else {
                cbPeriodType.DataField.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'PeriodType');
        }
        chbShowForOpportunity.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForOpportunity', false);
        edtProject.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'Project');
        chbShowForContact.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowForContact', false);
        edtContact.Value = GetStrAttributeFromXMLNode(CustomFiltersNode, 'Contact');
        chbShowChildren.IsChecked = CustomFiltersNode.GetAttributeAsBool('ShowChildren', false);
        fbcFilters.ClearFilter();
        fbcFilters.FiltersBuilder.Deserialize(Scheme.FilterBuilder);
        fbcFilters.Refresh();
        fbcFilters.ApplyFilter();
}

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

Конфигурация Terrasoft 3.3.2.157
Бинарные файлы Terrasoft 3.3.2.268

Нравится

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

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

Уточните, пожалуйста, при фильтрации Вам необходимо чтобы отображалась только(!) подчиненная запись и её родитель, или же родитель этой записи и все подчиненные этому родителю записи?

Здравствуйте Дмитрий,
Необходимо отображать:

"Олейник Дмитрий" написал:родитель этой записи и все подчиненные этому родителю записи

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

Предлагаю базовый механизм быстрого фильтра не трогать, а добавить какую либо кнопку "Фильтр" в окно древовидного реестра.
На OnClick пропишем примерно следующее:

var Dataset = dlData.Dataset;
Dataset.DisableEvents();
vat FilterText = edtFilterText.Value;
ApplyDatasetFilter(Dataset, 'Text', FilterText, true);
Dataset.Open();
var ParentID = Dataset('ParentID');
if(ParentID != null)
{
Dataset.Close();
EnableAllFilters(Dataset.SelectQuery.Items(0).Filters, false);
ApplyDatasetFilter(Dataset, 'ID', ParentID, true);
Dataset.Open();
}
RefreshDataset(Dataset);
Dataset.EnableEvents();

Здравствуйте Дмитрий,
Спасибо за идею с обходным решением, не проверял его еще на практике.
Но так как есть требование иметь полную функциональность работы с фильтрами (как в разделе проекты) у меня есть более "красивая" идея как реализовать задачу.
По сути когда мы ставим Like фильтр по какому либо из полей (допустим текстовом) в древовидном реестре, Террасофт посылает запрос

...
WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%''))
...

где @P1 значение введенное в клиенте
И данные запрос нам вернет ID подчинённых записей, но не корневых. Так как корневых записей нет, в гриде мы ничего не увидим.
Обыграть это можно построив запрос вида:

select tbl_ControlPaySection.OffshNumber from  tbl_ControlPaySection  
where tbl_ControlPaySection.name like '% текст %'
or ID in (select ParentID from tbl_ControlPaySection  a
where a.name like '% текст %'
)
order by tbl_ControlPaySection.OffshNumber

Для того что бы в TSAdmin'е делать подобные фильтры, есть функциональность Пользовательских фильтров (User Filter). Построить подобный запрос можно следующим образом (В данном случае у нас будет String User Filter):
1

2

Проблема в том, что когда вызвать этот Пользовательский фильтр в клиенте, Террасофт сформирует запрос:

...
WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%''))
ORDER BY
	5 ASC',N'@P1 nvarchar(4000)',N'текст с клиента'

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

Конфигурация Terrasoft 3.3.2.157
Бинарные файлы Terrasoft 3.3.2.268

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

А если включить корневой блок WHERE?

Для полноценной фильтрации (по аналогии с разделом "Проэкты"), после ApplyDatasetFilter по искомому поисковому запросу, Вам необходимо проверить, корневой это узел или нет. В случае если ParentID <> null, необходимо фильтровать датасет по этому ParentID, в ином случае (ParentID = null) фильтрация пройдет корректно.

"Олейник Дмитрий" написал:А если включить корневой блок WHERE?

Ситуация не поменялась

"Олейник Дмитрий" написал:Для полноценной фильтрации (по аналогии с разделом "Проэкты"), после ApplyDatasetFilter по искомому поисковому запросу, Вам необходимо проверить, корневой это узел или нет. В случае если ParentID <> null, необходимо фильтровать датасет по этому ParentID, в ином случае (ParentID = null) фильтрация пройдет корректно.

Данный комментарий к коду

"Олейник Дмитрий" написал:var Dataset = dlData.Dataset;
Dataset.DisableEvents();
vat FilterText = edtFilterText.Value;
ApplyDatasetFilter(Dataset, 'Text', FilterText, true);
Dataset.Open();
var ParentID = Dataset('ParentID');
if(ParentID != null)
{
Dataset.Close();
EnableAllFilters(Dataset.SelectQuery.Items(0).Filters, false);
ApplyDatasetFilter(Dataset, 'ID', ParentID, true);
Dataset.Open();
}
RefreshDataset(Dataset);
Dataset.EnableEvents();

понятен, но как сделать что бы можно было пользоваться FilterBuilder'ом?
Просьба уточнить, как работают пользовательские фильтры (User Filter), в случае строкового фильтра (String User Filter).
Что я делаю не так в пользовательском запросе что он формирует запрос к БД

LEFT OUTER JOIN
	[dbo].[tbl_OffshClients] AS [tbl_OffshClients] ON [tbl_OffshClients].[ID] = [tbl_OffshCompanys].[Clients]
WHERE(([tbl_ControlPaySection].[Name] LIKE ''%'' + @P1 + ''%''))
ORDER BY
	4 DESC',N'@P1 nvarchar(4000)',N'Годовой'

и не учитывает всю логику подзапросов.

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

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

"АльфаКрыса" написал: но как сделать что бы можно было пользоваться FilterBuilder'ом?

Для того чтобы пользоваться Filter Build'ером, необходимо в sq добавить Union таблицы саму на себя, после чего добавить фильтр NotExistInChild, ExistsInPath по аналогии c sq_Project.

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

Здравствуйте.
Есть такой вопрос: При создании отчета fast report используется стандартное окно фильтрации, в котором отображаются фильтры Старт. Дата, Кон.Дата, Документ, Тип Документа. Тип Документа выставлен по умолчанию в fr_ReportSheduleOfWork.
Требуется автоматически подставлять в фильтр Документ текущий документ из грида. Делать отчет по выделенным записям нельзя, т.к. необходимо выбирать даты, а так окно фильтрации не появляется.
Вопрос в том, можно ли сделать это без собственного окна фильтрации?
Заранее благодарен.

Нравится

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

Здравствуйте, Иван Александрович.
Для того, чтобы реализовать возможность автоматически подставлять в фильтр "Документ" базового окна фильтрации отчета FastReport текущий документ из реестра записей, необходимо внести следующие дополнения в базовые скрипты:
1. Скрипт scr_ReportUtils. В функцию function ReportMenuItemExecute(ActionMenuItem, GridDataset, DataGrid, WorkspaceName) добавить строки кода (выделено жирным):

function ReportMenuItemExecute(ActionMenuItem, GridDataset, DataGrid, WorkspaceName) {
...................
} else {
var Report = Services.GetNewItemByUSI(ReportCode);
var FilterFormCode = Dataset.ValAsStr('FilterFormCode');
if (FilterFormCode) {
var FilterForm = Services.GetNewItemByUSI(FilterFormCode);
SetAttribute(FilterForm, 'ReportDatasetUSI',
FilteredDatasetCode);
SetAttribute(FilterForm, 'SelectedIDs', SelectedIDs);
}
//For Document//
var SelectedName = GetDatasetFieldValueByID(GridDataset.USI, SelectedIDs[0], 'Title');
SetAttribute(Report, 'SelectedID', SelectedIDs[0]);
SetAttribute(Report, 'SelectedName', SelectedName);
//For Document//

ShowReport(Report, FilterForm);
}
break;
}
} finally {
Dataset.Close();
}
}

2. Скрипт wnd_ReportFiltersScript. В конец функции function LoadFilters(Window), как отображено ниже, добавить код, реализующий установку значения фильтра в окне фильтрации:

function LoadFilters(Window) {
................
XMLStorage.LoadFromText(FiltersXML, ForceEncoding);
fbcMain.DataFieldsList.Deserialize(XMLStorage.RootNode);
}
//For Document//
var ReportCode = System.ExtractUSICode(ReportFilters.FastReport.USI);
if (ReportCode == 'fr_ReportName') {
var FieldName = GetAttribute(ReportFilters.FastReport, 'SelectedName');
var FieldID = GetAttribute(ReportFilters.FastReport, 'SelectedID');
fbcMain.DataFieldsList.Items(0).DisplayValue = FieldName;
fbcMain.DataFieldsList.Items(0).Value = FieldID;
fbcMain.DataFieldsList.Items(0).DisplayFieldValues.Clear();
fbcMain.DataFieldsList.Items(0).DisplayFieldValues.Add(FieldName);
fbcMain.DataFieldsList.Items(0).Values.Clear();
fbcMain.DataFieldsList.Items(0).Values.Add(FieldID);
fbcMain.DataFieldsList.Items(0).ValueNotSet = false;
}
//For Document//

}

Где в fbcMain.DataFieldsList.Items(0) содержится первый по порядку элемент в форме фильтрации, в fbcMain.DataFieldsList.Items(1) - второй и т.д

Получилось! Огромное вам спасибо, Наталия!

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