Универсальный фильтр#

Основные положения#

Операции универсального фильтра объявлены в EntityAvi, что означает, что он доступен в каждой выборке.

Вся фильтрация построена на создании объектов scala-классов, которые хранятся в памяти, сохранение настроек осуществляется в таблицу базы данных в виде json.

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

По умолчанию в фильтре для фильтрации доступны атрибуты выборки, а так же класса, который определяется через Avi-функцию thisApi() .

Сохраненная настройка не обращает внимание на изменившиеся свойства атрибутов и прочее. Она использует те настройки атрибутов, которые были в момент добавления этого атрибута с панели. Что бы изменилось поведение атрибута в настройке, необходимо его удалить, затем снова добавить и сохранить настройку.

Физические атрибуты и выражения фильтрации#

  • Атрибуты в макросе представлены их «физическими атрибутами». По умолчанию физический атрибут равен системному имени атрибута, но существуют атрибуты где это не так.Примером может служить технический атрибут класса «IdObject#», имеющий физическое имя «ID» (или gidRef для Mixin-ов и пр.). В макросе такой атрибут всегда представлен как ID.

  • У атрибутов фильтра есть понятия выражения фильтрации, в котором указывается произвольное sql-выражение, для определения значения этого атрибута. Например, такие выражения используются в объектных характеристиках, хранящихся в json

Активация фильтра в выборке#

Для включения возможности фильтрации через универсальный фильтр в отображении необходимо активировать операцию uniFilter. Так же удостовериться в активности операций onApplyFilter, onFilterFinalize, onFilterInit

Внимание

Фильтр не работает в выборках с объектными запросами

HL-атрибуты#

HL – атрибуты (далее IdAttrHL) считаются ссылочными атрибутами и в фильтрации не участвуют, фильтрация осуществляется по их id-атрибутам (далее IdAttr).

  • Если в выборке присутствует IdAttrHL, но отсутствует IdAttr, то фильтрация по атрибуту IdAttrHL будет недоступна.

  • Все расширенные настройки требуется указывать на атрибуте IdAttr

  • Ссылочность определяется:

    • Через тег <ref>, например: <ref class="Rpl_IntOutSession"/>

    • через одноименный атрибут класса этой выборки

Связь выборки и класса#

Для выборки класс определяется через Avi-функцию thisApi()

Связь атрибута выборки и атрибута класса#

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

Тип редактора атрибута#

Тип редактора атрибута в большинстве случаев такой же, как указан в выборке, исключения:

  • Выпадающие списки открываются через редактор с тремя точками

  • Даты фильтруются через интерфейс «Фильтрации по периоду»

  • Ссылочные атрибуты через редактор с тремя точками

  • Специфичные типы сравнения (множественность) изменяют редактор на редактор с тремя точками .

Для атрибутов класса тип редактора определяется:

  • Если указан в odm, то этот тип редактора.

  • Иначе определяется от типа атрибута и его типа данных.

Коллекции класса#

Для выборок с классами и для классов в перечне доступных для фильтрации атрибутов могут быть позиции с красными иконками, которые позволяют осуществлять фильтрации по коллекциям. Коллекции доступные для фильтрации определяются через odm- файл в теге <collections>.

Так же в карточке класса на закладке «Коллекции универсального фильтра» есть возможность добавить дополнительные коллекции для фильтрации. Например, подключить какой-то класс, который не входит в бизнес-объект, но имеет ссылки на текущий.

На этой же закладке можно переопределить и стандартные коллекции класса:

  • отключить фильтрацию по коллекции, сняв признак «Активность»

  • переименовать коллекцию, изменив поле «Наименование»

Доступные элементы для фильтрации#

Типы доступных элементов#

  • Атрибут класса/выборки – доступен в случае генерации доступных атрибутов по классу или выборке

  • Коллекции - добавляются при генерации по классу

  • Объектные характеристики, хранящиеся в json :

    • Фильтрация:

      • Осуществляется через выражение, которое получает значение атрибута из json

    • Заполнение на панели доступных атрибутов:

      • Все об. Характеристики класса или класса, с которым сопоставлена выборка.

  • Универсальные характеристики :

    • Фильтрация:

      • Для единичных - осуществляется через выражение, которое получает значение атрибута из json

      • Для множественных - формирует выражение через exists или not exists, по аналогии с фильтрацией по коллекциям.

    • Заполнение на панели доступных атрибутов:

      • Все универсальные характеристики, объявленные на:

        • группах класса, если у класса включена Группировка

        • типах объекта класса

  • Постоянные/технические атрибуты класса

    • Заполнение на панели доступных атрибутов:

      • Всегда, при раскрытии узла, ссылочного на класс

      • Всегда, если выборка связана с классом

    • Атрибуты

      • sHeadLine# (Заголовок)

      • sMnemoCode# (Мнемокод)

      • dModifyDate# (Дата изменения)

      • dCreateDate# (Дата создания)

      • sModifyUser# (Изменивший пользователь)

      • sCreateUser# (Создатель)

      • IdGroup# (Группа) – заполняется только для классов, имеющих группировку. Позволяет фильтроваться по группе

      • idObject# (Объект) – специальный атрибут, позволяющий фильтроваться по идентификатору(или gidRef) объекта

Первичная генерация по выборке#

В операции lazyInitFilter происходит заполнение доступных атрибутов по выборке. Ниже рассмотренные варианты.

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

Генерация по классу#

Для класса формируются:

  • Атрибуты класса (кроме idClass), с не отключенным свойством доступности в фильтре

    <attr name="bError">
        <uniFilter isActive="false"/>
    </attr>
    
  • Все объектные характеристики, настроенные пользователями и хранящимися в jObjAttrs_dz

  • Технические атрибуты (заголовок, дата создания, объект и тд)

  • Коллекции, перечисленные в odm и в карточке класса на закладке «Коллекции универсального фильтра»

  • Универсальные характеристики, объявленные:

    • на группах класса, если в классе включен сервис группировки

    • на типах объекта класса, если сервис группировки не включен для класса.

Примечание

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

Подробности в главе Расширенная настройка - Класс

Атрибуты переменной ссылочности или ссылочные на миксин.#

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

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

  • Атрибут, ссылочный на один класс, сразу фильтруется по этому классу

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

    <attr name="gidRefDocument" attribute-type="Varchar" caption="Документ" order="20" type="refAnyObject">
         <uniFilter>
             <refAnyObject>
                 <ref name="Wf_Doc"/>
                 <ref name="Cnt_Contract"/>
             </refAnyObject>
         </uniFilter>
     </attr>
    
  • Атрибут с ненастроенной ссылочностью фильтруется как значимый. Приоритет обработки ссылочности:

  1. Ссылочный на класс в refClass в теге uniFilter

  2. Ссылочный на перечень классов в теге refAnyObject в теге unitFilter

  3. Ссылочный на класс в refClass в настройке самого атрибута.

Формирование макроса#

Макрос формируется в операции onApplyFilter. По умолчанию в фильтре создается главная группа, имеющая признак bisMainGroup = 1 и системное имя MainGroup, по ней и формируются макросы.

Каждая фильтруема коллекция будет представлять Exists в макросе.

Режим onlyWhere#

Стандартный режим работы фильтра, в результате выдается текст одного макроса, который будет представлять собой exists, примером может служить:

Exists (
    select 1 
      from bs_goods t#2 
     where t#2.sName = '1' 
       and t#2.id = t.id
    ) 

Обработка сервером приложений сформированного макроса#

На операции onApplyFilter сформированный макрос передается серверу, чтобы он наложил условие на запрос данных выборки:

selection.filters().server.alias = mainGroupAlias
selection.filters().server.condition = fltMacro.where
selection.filters().server.isEnabled = true

Передача условий фильтра через параметры выборки#

Для формирования условия используется объект класса FltCondition. В качестве имен атрибутов и коллекций можно использовать:

  • Системное имя – в таком случае атрибут или коллекция ищется на первом уровне дерева доступных элементов.

  • Путь – позволяет добавлять условия со вложенных уровней доступных элементов. Например, по атрибуту класса, на который ссылается атрибут верхнего уровня. Путь можно получить через дебаггер (атрибут sPath), стоя на доступном к фильтрации элементе. Пример использования:

val fltCondition = FltCondition()

//условия группы "отбор"
fltCondition.withMainGroup{mainGroup =>
    //добавляем условие по атрибутам выборки
    mainGroup.addAttr("nNumber", 1.nn)
    //условие "Заполнен"
    mainGroup.addIsNotNullAttr("sCaption")
    //добавляем условие по ссылочному атрибуту с раскрытием его на подуровни
    mainGroup.addAttr("attr:idPurchaseDirection/attr:sCaption", "643")

    //добавляем условие по атрибуту класса выборки, который отсутствует в дата-сете
    mainGroup.cl.addAttr("sCreateUser_dz", "admin")

    //добавляем условие по атрибуту даты
    mainGroup.cl.addDateInterval("dCreateDate_dz", "10.02.2020".nd, "10.02.2021".nd)

    //условие "в списке"
    mainGroup.addAttr("idRef", Seq(1.nl, 2.nl, 3.nl))

    //условие "Не в списке"
    mainGroup.addAttr("idRef", Seq(1.nl, 2.nl, 3.nl), FltAttributeCompareKind.notInList)

    //добавляем группу "Или"
    mainGroup.addOrGroup{orGr =>
        orGr.addAttr("sCaption", "123")
        orGr.addAttr("sCaption", "321")
    }

    //добавляем условие по коллекции
    mainGroup.withCollection("Btk_SomeCollection") {col =>
        col.addAttr("sCaption","someValue")
    }
}

//добавляем условие по другой рутовой группе
fltCondition.withRootGroup("groupName"){group =>
  //условия по атрибутам и коллекциям
  //...
}

//передаем условие в выборку
Btk_ClassAvi.defList.newForm().params(Map("uniFilterCondition_dz" -> fltCondition)).open()

Внимание

Если нужно добавить условия по атрибуту класса выборки, который отсутствует в дата-сете, и объединить их в отдельную группу «И»/группу «ИЛИ», необходимо добавить .cl непосредственно перед добавлением соответствующей группы, а не самого атрибута.

Корректный пример добавления группы:

  fltCondition.withMainGroup { mainGroup =>
    mainGroup.cl.addOrGroup { orGr =>
      orGr.addAttr("attr:id/attr:jAttrDataDeb_sCaption", "123")
      orGr.addAttr("attr:id/attr:jAttrDataCr_sCaption", "123")
    }
  }

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

  fltCondition.withMainGroup { mainGroup =>
    mainGroup.addOrGroup { orGr =>
      orGr.cl.addAttr("attr:id/attr:jAttrDataDeb_sCaption", "123")
      orGr.cl.addAttr("attr:id/attr:jAttrDataCr_sCaption", "123")
    }
  }

Примечание

Узнать путь до определенного атрибута универсального фильтра можно при помощи отладчика (Ctrl+Alt+Shift+w). Заметим, что при формировании в коде пути до ссылочного атрибута необходимо указывать строку пути полностью, например, attr:idPurchaseDirection/attr:sCaption. Для обычных атрибутов указывается сокращенный путь, например, строка mainGroup.addAttr(«nNumber», 1.nn) добавляет условие фильтрации по атрибуту attr:nNumber.

Описание scala-классов, используемых фильтром#

Во всех отображениях присутствует переменная менеджер фильтров fltManager, хранящая объект, создающийся в операции onFilterInit.

Менеджер управляет фильтром, загружает/выгружает настройки, формирует макрос. Основные классы фильтра находятся в пакете ru.bitec.app.btk.flt

Avi-методы выборки#

  • onFilterInit – событие инициализации фильтра. Создается фильтр-менеджер fltManager

  • onApplyFilter – первичное применение настройки по умолчанию при отрытии выборки. Формирование макроса, применение макроса.

  • onFilterFinalize – уничтожение фильтра.

  • uniFilter – операция фильтра, если ее активировать, то будет возможность фильтрации.

  • lazyInitFilter – ленивая инициализация. Вызывается при обращении к фильтру. Формирует главную группу фильтра.

Расширенная настройка#

Класс#

Разметка класса (odm.xml)#

Для атрибута доступен тег uniFilter:

  • isActive - по умолчанию включено, определяет наличие этого атрибута в перечне доступных для фильтрации

  • refClass – ссылочный класс, перекрывает настройку ссылочности самого атрибута(указанного в теге attr)

  • тег refAnyObject – позволяет настроить перечень классов, на который ссылается атрибут переменной ссылочности

Пример настройки атрибута класса в odm.xml:

<attr name="bError" attribute-type="Number" caption="С ошибками" order="70" type="basic" editorType="check" defaultValue="0">
    <uniFilter isActive="false" refClass = " Bs_Goods">
        <refAnyObject>
            <ref name="Bs_Goods"/>
        </refAnyObject>
    </uniFilter>
    <booleanColumn/>
</attr>

Управление атрибутами в бизнес-логике#

Для того чтобы управлять атрибутами в бизнес-логике используется точка расширения Btk_Ext.afterBuildFltEntityMeta, которая позволяет изменять атрибуты, которые формируются по умолчанию, а так же добавлять свои собственные.

Для управления атрибутами используются методы пакета ru.bitec.app.btk.flt.meta.Btk_FltMetaAttributePkg.

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

def afterBuildFltEntityMeta(fltMetaEntity: FltMetaEntity, fltManager: FltManager): Unit = {
  //проверка, что переданный класс - класс, для которого нужно добавить логику
  if (fltMetaEntity.name == "Bs_Goods") {
    //определяем, что json-атрибут доступен по умолчанию.
    val typeSizeAttrOpt = fltMetaEntity.attrMap.get("jTypeSizeAttrs".toLowerCase)
    if (typeSizeAttrOpt.isDefined) {
      val typeSizeAttr = typeSizeAttrOpt.get
      //ставим признак, что он может быть раскрыт в дереве
      Btk_FltMetaAttributePkg().setCanExpand(typeSizeAttr, true)

      //формируем атрибуты-потомки
      for (rvx <- new OQuery(Gds_TypeSizeCharacteristicAta.Type) {
      }) {
        //создаем значимые атрибуты, которые хранятся в json-контейнере
        val fltAttr = Btk_FltMetaAttributePkg().buildBasicJObjectAttr(
          systemName = rvx.get(_.sCode),
          caption = rvx.get(_.sCaption),
          dbType = AttributeTypes.Number,
          isBoolean = false,
          jsonColumnName = "jTypeSizeAttrs"
        )

        //устанавливаем созданному атрибуту потомка.
        Btk_FltMetaAttributePkg().setParentTree(fltAttr, typeSizeAttr)

        //добавляем атрибут в общий перечень атрибутов.
        fltMetaEntity.attrMap(fltAttr.systemName.toLowerCase) = fltAttr
      }
    }
  }
}

Коллекции#

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

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

Для коллекций атрибут мастера – id, для v-коллекций – gid.

Для регистрации записей в настройку используется метод ru.bitec.app.btk.class_.flt.Btk_ClassFltCollectionApi#register

Выборка#

В avm выборки для атрибута доступен тег uniFilter, имеющий свойства:

  • isActive – если снят, то такой атрибут не будет отображаться в списке доступных для фильтрации. По умолчанию включено.

  • isSelectionAttr – если снят, то такой атрибут будет фильтроваться как атрибут класса (через join с таблицей класса по id), если у выборки нет класса, то атрибут не доступен для фильтрации. По умолчанию включено.

  • refSelection – позволяет явно указать имя выборки, которая будет открываться при выборе значения в фильтре. Имеет приоритет перед свойством refSelection тега ref

  • refRepresentation – позволяет явно указать имя отображения, которое будет открываться при выборе значения в фильтре. Имеет приоритет перед свойством refRepresentation тега ref

Создание дополнительных групп фильтрации#

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

Для этого требуется:

  1. инициализировать новую группу;

  2. сформировать макрос фильтрации по этой группе;

  3. полученный текст подставить в основной запрос onRefresh

Ниже приведен пример создания дополнительной группы, которая позволяет фильтровать по условиям, наложенным на класс ТМЦ

  1. На операции lazyInitFilter инициализируем дополнительную группу:

    override def lazyInitFilter(): Unit = {
      if (!fltManager.isPopulatedRootGroup) {
        Btk_FltPkg().createRootGroupByClass(fltManager, "Bs_Goods", "Bs_Goods")
      }
      super.lazyInitFilter()
    }
    
  2. На onApplyFiler получаем текст фильтрации по группе:

    override def onApplyFilter(): Unit = {
      super.onApplyFilter()
      //проверяем, что группы инициализированы и фильтр активен в выборке
      if (fltManager.isPopulatedRootGroup && fltManager.isActive) {
        val alias = "tt"
        val macros = Btk_FltPkg().generateMacroByGroup(fltManager, "Bs_Goods", alias)
        //если наложено условие по этой группе, то формируем текст макроса фильтрации, который будет применим к запросу данных нашей выборки
        if (macros.hasFilter) {
          selection.setMacro(
             "GdsMacro", 
             s"""
              exists (
                select 1
                  from bs_goods $alias
                 where $alias.id = t.idGds -- join к атрибуту из дата-сета (t.idGds)
                   and ${macros.where} -- условия по этой группе
              )
             """
         ) 
        } else {
          //иначе делаем макрос без наложения условий
          selection.setMacro("GdsMacro", "1=1")   
        }
      }
    }
    
  3. В операции onRefresh используем установленный в onApplyFiler макрос:

    • Через метод prepareSelectStatement

    override protected def onRefresh: Recs = {
      prepareSelectStatement("&GdsMacro")
    }
    
    • В тексте sql-запроса

    override protected def onRefresh: Recs = {
      """
        select .....
          from .....
         where ....
           and &GdsMacro
      """
    }
    

Связь панели стандартного фильтра с универсальным фильтром#

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

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

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

Существует 3 режима связи атрибута стандартного фильтра и универсального:

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

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

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

Добавление атрибута через панель доступных для фильтрации атрибутов УФ#

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

Фильтрация по атрибутам коллекций также доступа в этом режиме.

Настройка#
  1. Откройте интерфейс универсального фильтра выборки, для которой хотите создать новый атрибут на панели фильтров

  2. Откройте панель доступных атрибутов

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

  4. Выполните контекстную операцию Сформировать текст разметки стандартного фильтра. Операция доступа супер-пользователям или пользователям, обладающих объектной привилегий Формирование текста разметки связей стандартного фильтра пакета Btk_FltPkg

  5. В открывшемся мастере укажите:

    • системное имя атрибута стандартного фильтра
      По умолчанию flt_<Имя атрибута УФ>

    • наименование
      По умолчанию наименование атрибута УФ

    • порядковый номер
      Порядковый номер для атрибута стандартного фильтра.

    • с условием сравнения
      Если признак установлен, то будет сформированы атрибуты стандартного фильтра, позволяющие изменять тип сравнения.

  6. Подтвердите выбор в мастере

  7. Из открывшегося окна скопируйте в avm.xml и Avi сформированный текст

Создание ссылочного атрибута с типом редактора «Выпадающий список»#
  1. Выполните действия описанные в главе Настройка.

  2. Смените тип данных атрибута на Long

  3. Сделайте атрибут не видимым

  4. Добавьте hl-атрибут, в котором настройте выпадающий список.

Описание xml-разметки#

Для атрибута стандартного фильтра добавляется тег uniFilter, в котором указываются следующие xml-атрибуты:

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

  • attribute-type
    Тип данных атрибута

  • conditionAttr
    Имя атрибута стандартного фильтра с типом сравнения. Содержит имя атрибута, который будет отвечать за смену типа сравнения. Если не указан, то тип сравнения для этого атрибута нельзя будет изменить в универсальном фильтре.

  • conditionType
    Тип сравнения по умолчанию. Если не указан, то будет использоваться стандартный алгоритм определения типа сравнения. В качестве значений используется системное имя объекта ru.bitec.app.btk.flt.selected.attribute.FltAttributeCompareKind

  • defaultValue
    Значение по умолчанию

  • defaultValueType
    Тип значения по умолчанию

  • ref.selection
    Имя выборки, которая будет открываться для выбора значений ссылочных атрибутов

  • ref.representation
    Имя отображения выборки, которое будет открываться для выбора значений ссылочных атрибутов

Добавление произвольного атрибута#

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

Настройка#
  1. Добавьте в avm.xml для нужного атрибута тег uniFilter и настройте нужные свойства

  2. Добавьте в Avi сеттеры для атрибутов:

    • атрибут значения:

      @Setter()
      def setflt_someValue(event: SetterEvent): Unit = {
        Btk_FltLib().setStdFilterValue(event)
      }
      
    • атрибут типа сравнения:

      @Setter()
      def setflt_someCondition(event: SetterEvent): Unit = {
        Btk_FltLib().setStdFilterConditionType(event)
      }
      
  3. Добавьте ограничение в запрос выборки
    Для добавления ограничения добавьте в операции onRefresh использование макросов,сформированных по каждому из атрибутов. Имя макроса указывается в свойстве macros тега uniFilter.

    Например:

     override def onRefresh: Recs = {
       prepareSelectStatement(
         s"""&flt_stdMacroName -- условие по атрибуту, имя макроса которого равно flt_stdMacroName  
             """
       )
     }
    

    Пример сложного условия с под-запросами. В этом примере, сначала проверяется есть ли наложенное ограничение по атрибуту, и если оно есть, то добавляется под-запрос

    override def onRefresh: Recs = {
      prepareSelectStatement(
        s"""
          ${if (fltManager.hasStdAttrCondition("flt_someAttrName")) {
            """exists (
                   select 1
                     from Some_class tt
                    where tt.id = t.idSomeAttr -- связь между основной коллекцией и таблицей   подзапроса
                      and &flt_stdMacroName -- макрос с сформированным ограничением по атрибуту
                 )"""
         } else {
           ""
         }}
       """
      )
    }
    
Описание xml-разметки#

Для атрибута стандартного фильтра добавляется тег uniFilter, в котором указываются следующие xml-атрибуты:

  • attribute-type
    Тип данных атрибута

  • type
    Тип ссылочности атрибута. Доступные значения:

    • basic
      Значимый

    • boolean
      Булево

    • refObject
      Ссылочный на объект

    • refState
      Ссылочный на состояние

    • refGroup
      Ссылочный на группу

  • expression
    sql-выражение для получения значения атрибута. Например, tt.idGs. Будет использовано при формировании макроса атрибута

  • macros
    Имя макроса, в который будет установлено сформированное sql-выражение по этому атрибуту Пример выражения: tt.idGds = 42. В качестве правого операнда используется выражение указанное в expression

  • valueMacros
    Имя макроса, в который будет установленно sql-выражение этого атрибута, но содержащее только часть, относящуюся к значению. Например, 42. Если в значении указан интервал, то будет использовано выражение вида (10, 20), где первое значение - начало интервала, второе значение - конец. Если одна из границ не задана, то будет указано null

  • ref.class
    Ссылочный класс. Используется для атрибутов:

    • Ссылочный на объект
      Содержит имя класса, объекты которого будут доступны для выбора

    • Ссылочный на группу или Ссылочный на состояние\ Содержит имя класса, которым будет ограничен выбор групп и состояний

  • conditionAttr
    Имя атрибута стандартного фильтра с типом сравнения. Содержит имя атрибута, который будет отвечать за смену типа сравнения. Если не указан, то тип сравнения для этого атрибута нельзя будет изменить в универсальном фильтре.

  • conditionType
    Тип сравнения по умолчанию. Если не указан, то будет использоваться стандартный алгоритм определения типа сравнения. В качестве значений используется системное имя объекта ru.bitec.app.btk.flt.selected.attribute.FltAttributeCompareKind

  • defaultValue
    Значение по умолчанию

  • defaultValueType
    Тип значения по умолчанию

  • ref.selection
    Имя выборки, которая будет открываться для выбора значений ссылочных атрибутов

  • ref.representation
    Имя отображения выборки, которое будет открываться для выбора значений ссылочных атрибутов

Режим «Только сохранение»#

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

Такой подход позволяет сохранять значения стандартного фильтра в настройках универсального.

Настройка#
  1. Настройте атрибут стандартного фильтра используя базовый подход

  2. Для атрибута добавьте тег uniFilter, установите свойство saveOnly="true"

  3. Добавьте сеттер для фильтра

    @Setter()
    def setflt_someValue(event: SetterEvent): Unit = {
      Btk_FltLib().setStdFilterValue(event)
    }
    

Принудительная отправка значения в универсальный фильтр#

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

Для этого можно воспользоваться методом Btk_FltLib.submitStdFilterValue.

Пример использования:

@Setter()
def setflt_idClassHl(event: SetterEvent): Unit = {
  event.editButton match {
    case EditButton.lookup =>
      Btk_DialogLib().withLookupIdMulti(Btk_ClassAvi.listForChoose()) { ids =>
        val idss = ids.mkString(";")
        val hls = ids.map(id => Btk_ClassApi().getMnemoCode(id)).mkString(";")

        selection.clientSetSelfVar("flt_idClass", idss) // установка значения другого фильтра без вызова сеттера
        Btk_FltLib().submitStdFilterValue("flt_idClass") // отправка значения стандартного фильтра в универсальный
        selection.clientSetSelfVar("flt_idClassHl", hls)
      }
    case _ =>
  }
  Btk_FltLib().setStdFilterValue(event) // значение фильтра, для которого был вызван сеттер, будет отправлено в универсальный в этом вызове
}

Управление возможностью редактирования значения атрибута в универсальном фильтре.#

Если требуется запретить редактировать значение в универсальном фильтре, то можно воспользоваться методом Btk_FltStdLinkLib.setUniFilterReadOnly. Часто это используется в связке вместе с блокирование атрибута и на панели фильтрации.

val bool = true

selection.filters().std.attrs("flt_someAttrName").isReadOnly = bool
Btk_FltStdLinkLib().setUniFilterReadOnly("flt_someAttrName", bool)

Примечание

Не работает для атрибутов, работающих в режиме saveOnly. Для таких атрибутов значение всегда не редактируется.

Значение по умолчанию#

Значение по умолчанию указывается в теге uniFilter в свойстве defaultValue. Кроме самого значения может быть указан и его тип.

Тип значения по умолчанию указывается в свойстве defaultValueType и может принимать значения:

  • Constant
    Константа. Если тип значения по умолчанию не указан, то он считается константой.

  • Jexl
    Jexl-скрипт.

Константное значение#

В свойстве defaultValue указывается константное значение. Например:

  • Для числовых атрибутов 123

  • Для строковых abc

  • Для даты 20.12.2023 10:30:42 Если требуется указать множественное значение, то указывается массив значений, разделенных запятой

  • Для числовых атрибутов [123,321]

  • Для строковых [abc,cde] Если указывается интервальное значение, то значения указывается массив, содержащий 2 значения. Первое значение - начало интервала, второе значение - конец. Если для одной из границ интервала не задано значение, то оставляется пустая строка:

  • [20.12.2023 10:30:42,20.12.2023 10:30:42]

  • [,20.12.2023 10:30:42]

Jexl-скрипт#

В свойстве defaultValue указывается jexl-скрипт, который будет выполнен в контексте выборки для вычисления значения по умолчанию.

Если требуется указать множественное значение, то jexl-скрипт должен вернуть массив значений.

Если требуется указать интервальное значение, то jexl-скрипт должен вернуть массив, содержащий 2 значения. Первое значение - начало интервала, второе значение - конец.

Передача значений фильтра через параметры выборки#

Для передачи значений используется тот же механизм, что и для передачи значений в универсальный фильтр

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

Пример:

val fltCondition = FltCondition().withStdLinkGroup{std =>
  std.addAttr("flt_idClass", Btk_ClassApi().findByMnemoCode("Btk_Class"))
  std.addAttr("flt_bBool", 1.nn)
}

Some_Avi.defList().newForm().params(Map("uniFilterCondition_dz" -> fltCondition)).open()

Получение значения атрибута фильтра#

Если в прикладной логике для какого-то либо атрибута стандартного фильтра требуется получить его значение, особенно это актуально для ссылочных атрибутов, необходимо воспользоваться библиотечным методом ru.bitec.app.btk.flt.Btk_FltStdLinkLib#getAttrValue, в который требуется передать имя атрибута стандартного фильтра

Пример использования:

val fltCond = Btk_FltStdLinkLib().getAttrValue("flt_idBisObj")
//проверяем, что условие активно.
if (fltCond.isActive) {
  //проверяем, что выбран множественный тип сравнения
  if (fltCond.compareKind.isMultiValue) {
    //конвертируем к массиву и обходим значения
    fltCond.value.asNLongArray.foreach{v =>
      println(v)
    }
  } else if (fltCond.compareKind.isInterval) {
    //сравнение "В интервале"
    val interval = fltCond.value.value.asInstanceOf[FltLongInterval]
    println(interval.from)
    println(interval.to)
  } else {
    //единичное значение
    println(fltCond.value.asNLong)
  }
}

Формирование макроса#

Строковый атрибут#

  • Содержит - накладывает условие по регистронезависимому вхождению строки.

Пример макроса:

upper(t.sCaption) like upper('%'||'value'||'%')
  • Начинается с - накладывает условие на регистронезависимое начало строки.

Пример макроса:

upper(t.sCaption) like upper('value'||'%')
  • Заканчивается на - накладывает условие на регистронезависимое окончание строки.

Пример макроса:

upper(t.sCaption) like upper('%'||'value')
  • Равно - накладывает условие на регистронезависимое совпадение строки.

Пример макроса:

upper(t.sCaption) = upper('value')
  • Не равно - накладывает условие на регистронезависимое несовпадение строки.

Пример макроса:

upper(t.sCaption) <> upper('value')
  • В списке - накладывает условие на регистронезависимое вхождение в список.

Пример макроса:

upper(t.sCaption) in (upper('value'))
  • Не в списке - накладывает условие на регистронезависимое отсутствие в списке.

Пример макроса:

upper(t.sCaption) not in (upper('value'))
  • Заполнено - накладывает условие на наличие значения.

Пример макроса:

t.sCaption is not null
  • Не заполнено - накладывает условие на отсутствие значения.

Пример макроса:

t.sCaption is null
  • Не содержит - накладывает условие на регистронезависимое отсутствие подстроки.

Пример макроса:

upper(t.sCaption) not like upper('%'||'value'||'%')
  • В интервале - накладывает условие на вхождение в заданный интервал.

Пример макроса:

upper(t.sCaption) >= upper('value') and upper(t.sCaption) <= upper('value')

Числовой атрибут#

  • Равно - накладывает условие на точное совпадение числового значения.

Пример макроса:

t.nNumber = value
  • Не равно - накладывает условие на несовпадение числового значения.

Пример макроса:

t.nNumber <> value
  • В списке - накладывает условие на вхождение числового значения в список.

Пример макроса:

t.nNumber in (value)
  • Не в списке - накладывает условие на отсутствие числового значения в списке.

Пример макроса:

t.nNumber not in (value)
  • Заполнено - накладывает условие на наличие числового значения.

Пример макроса:

t.nNumber is not null
  • Не заполнено - накладывает условие на отсутствие числового значения.

Пример макроса:

t.nNumber is null
  • В интервале - накладывает условие на вхождение числового значения в заданный интервал.

Пример макроса:

t.nNumber >= value and t.nNumber <= value
  • Меньше - накладывает условие на то, что числовое значение меньше заданного.

Пример макроса:

t.nNumber < 1
  • Меньше или равно - накладывает условие на то, что числовое значение меньше или равно заданному.

Пример макроса:

t.nNumber <= 1
  • Больше - накладывает условие на то, что числовое значение больше заданного.

Пример макроса:

t.nNumber > 1
  • Больше или равно - накладывает условие на то, что числовое значение больше или равно заданному.

Пример макроса:

t.nNumber >= 1

Внимание

Для типа Long виды сравнения: Меньше, Меньше или равно, Больше, Больше или равно - не доступны!

Булевый атрибут#

  • Равно - накладывает условие на точное совпадение булевого значения.

Пример макроса:

and t.bBool = 1
  • Не равно - накладывает условие на несовпадение булевого значения.

Пример макроса:

and t.bBool <> 1
  • Заполнено - накладывает условие на наличие числового значения.

Пример макроса:

t.bBool is not null
  • Не заполнено - накладывает условие на отсутствие булевого значения.

Пример макроса:

t.bBool is null

Дата#

  • Равно - накладывает условие на точное совпадение даты.

Пример макроса:

t.dDate = to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')
  • Не равно - накладывает условие на несовпадение даты.

Пример макроса:

t.dDate <> to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')
  • Заполнено - накладывает условие на наличие даты.

Пример макроса:

t.dDate is not null
  • Не заполнено - накладывает условие на отсутствие даты.

Пример макроса:

t.dDate is null
  • В интервале - накладывает условие на вхождение даты в заданный интервал.

Пример макроса:

t.dDate >= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') and t.dDate <= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS')
  • Меньше - накладывает условие на то, что дата меньше заданной.

Пример макроса:

t.dDate < to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') 
  • Меньше или равно - накладывает условие на то, что дата меньше или равна заданной.

Пример макроса:

t.dDate <= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') 
  • Больше - накладывает условие на то, что дата больше заданной.

Пример макроса:

t.dDate > to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') 
  • Больше или равно - накладывает условие на то, что дата больше или равна заданной.

Пример макроса:

t.dDate >= to_timestamp('31.12.2000 00:00:00','DD.MM.YYYY HH24:MI:SS') 

Json атрибут#

  • Заполнено - накладывает условие на наличие json значения.

Пример макроса:

t.jJson is not null
  • Не заполнено - накладывает условие на отсутствие json значения.

Пример макроса:

t.jJson is null

Blob атрибут#

  • Заполнено - накладывает условие на наличие числового значения.

Пример макроса:

t.lBlob is not null
  • Не заполнено - накладывает условие на отсутствие булевого значения.

Пример макроса:

t.lBlob is null

Сlob атрибут#

  • По аналогий, как с Строковым атрибутом

Ссылочный атрибут#

  • По аналогий, как с Числовым атрибутом