Скрипт фильтрации значений атрибута при редактировании

Описание скрипта

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

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

Место настройки скрипта

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

Скрипт настраивается для атрибутов с параметром "Фильтрация значений при редактировании"=да, см. Типы атрибутов и их параметры.

Структура скрипта

Формально скрипт состоит из двух частей:

Часть 1, вычисляемая в интерфейсе администратора (subject == null). Возвращается список кодов атрибута, от которых зависит данный атрибут.

Copy
def ATTRS_FOR_UPDATE_ON_FORMS = ['attrCode1', 'attrCode2', ...]
// Обязательная проверка! Даже если фильтрующих атрибутов нет.
if (subject == null)
{
    return ATTRS_FOR_UPDATE_ON_FORMS
}

Часть 2, вычисляемая в интерфейсе оператора (в момент открытия формы). Возвращается список объектов, которые будут отображаться в списке.

return utils.find('class$type',['attrCode1':'value1']...)

Если скрипт фильтрации должен вернуть все объекты (более 500), то вместо конструкции типа:

return utils.find('class$type',[:])

рекомендуется использовать конструкцию, которая значительно сократит время формирования списка объектов:

return api.filtration.disableFiltration()

Если есть зависимость атрибута комментария от атрибута объекта, то указывается fqn класса в виде: fqn@attrCode.

Когда выполняется скрипт

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

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

Если включены параметры оптимизации получения данных, то скрипт выполняется только для видимых на форме атрибутов, см. dbaccess.properties.

Результат выполнения скрипта

В интерфейсе администратора: скрипт возвращает коллекцию (список) кодов атрибутов, от которых зависят возможные значения фильтруемого атрибута. Условие выполнения скрипта subject==null. Если значение фильтруемого атрибута не зависит ни от одного из атрибутов объекта, то возвращается пустой список [].

В интерфейсе оператора:

  • Скрипт возвращает коллекцию (список) объектов, доступных для выбора.

    Для атрибута типа "Ссылка на бизнес-объект": скрипт возвращает один объект, если скрипт используется для фильтрации значений атрибута типа "Ссылка на бизнес-объект".

    Для атрибута типа "Набор типов класса": скрипт должен возвращать коллекцию ClassFqn, или коллекцию строк, представляющих собой ClassFqn, или список объектов.

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

Переменные и их значения

Глобальные переменные:

  • user — пользователь, инициализировавший событие. Является объектом класса "Сотрудник" (employee).

    Если событие инициализировал суперпользователь, то user=null.

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

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

  • ip — ip-адрес рабочего места пользователя user. Если действие выполняется автоматически системой (а не пользователем), то переменная не определяется.
  • appVersion — версия приложения.
  • api — используется для обращения к методам api, например api.utils, api.ldap, api.timing, см. Методы API;
  • modules — используется для обращения к скриптовому модулю и конкретному методу, определенному в нем, с помощью конструкции: modules.{код модуля}.{имя метода}({параметры метода}...), см. Скрипт текста модуля;
  • logger — используется для отладки скриптов и позволяет вывести в лог на указанный уровень переданную строку, см. Отладочные сообщения.
  • utils — синоним api.utils.

Переменные контекста:

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

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

      • при работе с атрибутами объекта в переменной subject будет содержаться объект, у которого меняем статус или ответственного;
      • при работе с атрибутами комментария (в блоке "Комментарий") в переменной subject будет содержаться комментарий, для получения объекта необходимо использовать subject.source.
    • Если скрипт используется на форме добавления комментария (по кнопке добавления комментария), то в переменной subject будет содержаться комментарий. Для получения объекта необходимо использовать subject.source.
  • permittedFqns — список разрешенных типов объектов.

    В атрибутах типа "Ссылка на бизнес-объект" и "Набор ссылок на бизнес-объекты" можно ограничить список возможных значений по типам (с помощью параметра "Типы объектов". В этом случае целесообразно использование переменной permittedFqns.

    Переменная хранит "ClassFqn" для типов, выбранных в параметре "Типы объектов", и позволяет фильтровать объекты только указанных типов, что повышает производительность системы.

    Если выбран класс, то переменная хранит пустую коллекцию. Если переменная не используется, то ограничения по типам не нарушаются.

  • sourceForm — если скрипт выполняется при открытии формы быстрого добавления и редактирования, то переменная содержит значения полей формы, с которой была открыта текущая форма. В остальных случаях переменная имеет значение null.

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

    На форме быстрого добавления предпочтительно использовать прямое сравнение вместо использования sourceForm как условие сравнения (в конструкциях проверки true/false, null/ not null ).

    Пример 1. Вместо

    return sourceForm ? sourceForm?.printFormRule?.UUID

    рекомендуется использовать

    return sourceForm != null ? sourceForm?.printFormRule?.UUID

    Пример 2. Вместо

    if (sourceForm)

    рекомендуется использовать

    if (sourceForm == true)

  • cardObject — объект, из карточки которого было инициировано действие. Если действие инициировано НЕ из карточки объекта, то cardObject = null.

    Переменная не поддерживается в мобильном приложении.

    Переменную cardObject использовать не рекомендуется.

  • origin — тип месторасположения.

    Переменная не поддерживается в мобильном приложении.

    Возможные значения:

    • readForm (форма для чтения) — скрипт вычисляется на карточке объекта, на сложной форме добавления и редактирования связей (расширенная форма редактирования), в списке по ссылке на отдельной странице, в списке на странице результатов поиска, при нажатии на кнопку вызова действий в строке списка;
    • addForm — скрипт вычисляется на форме добавления, на быстрой форме добавления;
    • editForm — скрипт вычисляется на форме редактирования объекта, на форме редактирования атрибутов, вызванной из контента "Параметры объекта", на форме редактирования в ячейке списка, на форме быстрого редактирования, на форме массового редактирования, на форме смены типа; на форме смены ответственного, на форме смены привязки (переклассификации), на форме работы с массовостью (управление массовостью запроса), на форме смены статуса, на форме перемещения (смены родителя);
    • addFormComment/editFormComment — скрипт вычисляется на форме добавления/редактирования комментария;
    • addFormFile/editFormFile — скрипт вычисляется на форме добавления/редактирования файла.

Особенности

  • Если скрипт фильтрации применяется для объектов класса "Отдел" (ou), то для отделов, вложенных в компанию, обращение subject.parent возвращает объект "Компания" (root).
  • Для получения значения атрибута "metaClass" следует использовать конструкцию subject.metaClass.case вместо subject.metaClass.

    Пример: получение metaClass для типа объекта 'employee$serv'.

    При использовании синтаксической конструкции subject.metaClass.toString() не удастся получить ожидаемую строку 'employee$serv'. Вместо этого будет выведена строка 'serv', содержащая только тип объекта (без его класса и знака $).

    return utils.find ('template$template', ['typeEquipment' : op.in (subject.metaClass.toString())])

    Для получения значения атрибута metaClass следует использовать subject.getMetainfo().toString() или subject.getMetaClass().toString().

    return utils.find ('template$template', ['typeEquipment' : op.in(subject.getMetainfo().toString())])

    или

    return utils.find ('template$template', ['typeEquipment' : op.in(subject.getMetaClass().toString())])

Рекомендации

  • Для получения FQN класса (типа) объекта рекомендуется использовать метод .getMetainfo(). Для сравнения FQN класса (типа) со строкой необходимо выполнить явное преобразование с помощью метода .toString().
  • Элемент списка отфильтрованных значений может быть объявлен в виде объекта или UUID объекта. Для корректного выполнения скрипта рекомендуется объявлять все элементы списка либо в виде объектов, либо в виде UUID объектов, чтобы избежать возможного дублирования значений в результатах выполнения скрипта.

Примеры скрипта

  1. Скрипт фильтрации простого раскрывающегося списка объектов (не дерева):

    Copy
    //ПАРАМЕТРЫ------------------------------------------------------------
    // список кодов атрибутов объекта, от которых зависит фильтрация,
    //необходимо для обновления фильтруемого раскрывающегося списка на форме при изменении этих атрибутов.
    def ATTRS_FOR_UPDATE_ON_FORMS = ['metaClass'];
    //ОСНОВНОЙ БЛОК--------------------------------------------------------
    // Если subject = null, нужно вернуть список кодов атрибутов, от которых зависит фильтруемый атрибут
    if(null == subject)
    {
        return ATTRS_FOR_UPDATE_ON_FORMS
    }
    // возвращаем без фильтрации список отделов
    objects = api.utils.find('ou', [:])
    return objects
  2. Скрипт фильтрации раскрывающегося списка объектов в виде дерева. Скрипт возвращает все вложенные в ou$1234 отделы:

    Copy
    //ПАРАМЕТРЫ------------------------------------------------------------
    def ATTRS_FOR_UPDATE_ON_FORMS = [];//список кодов атрибутов объекта, от которых зависит фильтрация, 
    необходимо для обновления фильтруемого селекта на форме при изменении этих атрибутов.
    def PARENT_OU_UUID = 'ou$1234'; //UUID отдела, вложенные отделы в который, необходимо получить
    //ОСНОВНОЙ БЛОК--------------------------------------------------------
    if(null == subject)
    {
        return ATTRS_FOR_UPDATE_ON_FORMS;
    }
    def objects = [];
    objects = api.ou.listNestedOUs(PARENT_OU_UUID);
    return objects;
  3. Скрипт фильтрации агрегирующих атрибутов:

  4. Скрипт фильтрации, с указанием UUID родительского элемента справочника/ папки в параметрах поиска

    return utils.find('cOCSclassific', ['parent' : op.orEq('cOCSclassific$2395602', 'cOCSclassific$2395603')])

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

Примеры скрипта фильтрации для агрегирующих атрибутов

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

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

    Пример скрипта:

    // получить список участников команд, в которых состоит текущий пользователь
    return user?.teams?.members

    Список команд в виде списка объектов или списка UUID. В интерфейсе оператора для выбора доступны только команды.

    Пример скрипта:

    // получить список всех команд, в которых состоит текущий пользователь
    def groups = user?.teams
    return groups

    Список сотрудников - участников определенных команд в виде списка карт "команда:сотрудники" ([{team$1=[employee$1, employee$2]}, {team$2=[employee$3, employee$4]}...]).

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

    Пример скрипта:

    Copy
    // получить список всех сотрудников - участников команд, в которых состоит пользователь, и отобразить их внутри только этих команд
    def teamsUUIDs = user?.teams.UUID
    def textfilter = []
    teamsUUIDs.each(){teamUUID ->
    def emplcollect = [];
    def empls = api.team.getTeamMembers([teamUUID], false).UUID;
    empls.each(){emplUUID ->
    emplcollect.add(emplUUID);
    }
    textfilter.add([(teamUUID.toString()) : emplcollect]);
    }
    return textfilter

    Список сотрудников отделов. В интерфейсе оператора для выбора доступны только сотрудники в рамках определенных отделов.

    Пример скрипта:

    Copy
    ou = utils.get('ou$38493501')
    ou2 = utils.get('ou$38407901')
    textfilter = [];
    textfilter.add([(ou) : ou.activitiesEmpl]);
    textfilter.add([(ou2) : ou2.activitiesEmpl]);
    return textfilter

    Описанные выше варианты можно комбинировать в скрипте фильтрации, например: Список команд (пример 2) и список сотрудников - участников определенных команд (пример 4) ([{team$1=[employee$1, employee$2]}, {team$2=[employee$3, employee$4]}], team$1, team$2...). В интерфейсе оператора для выбора доступны и команды, и их сотрудники.

    Пример скрипта:

    Copy
    //получить список команд, в которых состоит пользователь, и список сотрудников только внутри этих команд
    def result = []
    def teamsUUIDs = user?.teams.UUID
    def textfilter = []
    teamsUUIDs.each(){teamUUID ->
    def emplcollect = [];
    def empls = api.team.getTeamMembers([teamUUID], false).UUID;
    empls.each(){emplUUID ->
    emplcollect.add(emplUUID);
    }
    textfilter.add([(teamUUID.toString()) : emplcollect]);
    }
    result += textfilter
    result += teamsUUIDs
  2. Скрипт фильтрации агрегирующего атрибута (команда/сотрудник). Возвращает группу с вложенными в нее сотрудниками. В качестве параметров передаются объекты (либо UUID-ы объектов). Группа доступна для выбора.

    Copy
    def PARAMS_FOR_UPDATE_ON_FORMS = [] 
    if (subject == null) {
      return PARAMS_FOR_UPDATE_ON_FORMS
    }
    //Выполняем поиск объекта, который будет отображаться в списке (в данном случае первую попавшуюся команду)
    def group = utils.findFirst('team',[:])
    //Проверяем наполненность полученного списка
    if (group == null) {
      // Если полученный список пуст, то выводим его на форме в виде выпадающего пустого списка
      return []
    //Если список не пуст, выводим его на форме в виде выпадающего списка с найденным объектом,
    //нужно выбрать один необходимый return из предложенных ниже
    } else {
      return [(group): group.members];
    }
  3. Скрипт фильтрации агрегирующего атрибута (команда/сотрудник), который возвращает только заданные команды и их участников.

    Copy
    //Коллекция кодов параметров для получения с формы (список атрибутов, от которых зависит фильтрация):
    ATTRS_FOR_UPDATE_ON_FORMS = []
    //Функции--------------------------------------------------------
    //Основной блок -------------------------------------------------
    if (!subject)
    {
       return ATTRS_FOR_UPDATE_ON_FORMS
    }
    //находим команды
    def teams = utils.find('team', ['folders':'folder$2991701'])
    //возвращаем список, состоящий из команд и их участников
    //в результате на форме добавления будут доступны для выбора сами команды и их участники
    return teams?.UUID + teams?.collect { return [ (it.UUID) : it.members?.UUID ] }