Фильтр по закрытым записям справочника

17 29

Система DIRECTUM не мыслима без справочников, а справочники - без закрытых записей. Все бы ничего, но когда справочник открывается в режиме выбора (например, при заполнении реквизита другого справочника) в список попадают все записи, даже закрытые. Вид на справочник «Работники» при выборе куратора договора:



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

Более изящный вариант решения выглядит так:
1. При открытии справочника определяется режим его отображения.
2. Если справочник открыт в режиме выбора или внешнее отображение справочника отсутствует, то применяется фильтр, который отбрасывает закрытые записи (вид на справочник «Работники» при выборе куратора договора с применением фильтра):



Как видно, в списке отсутствуют три записи с состоянием «Закрытая». Фишка этого решения в том, что независимо от места, в котором выбирают работника, в списке всегда будут присутствовать только действующие записи.

Для внесения изменений в вашу систему вставьте этот код в событие «Набор данных \ Открытие» нужного справочника:


// Проверить существование представления справочника
View = Sender.Component.View
if Assigned(View)
  // Представление создано
  // Проверить режим представления справочника
  if Object.View.ViewMode == vmSelect
    // Справочник открыт в режиме выбора
    // Наложить ограничение на состояние записей
    Sender.AddWhere(Format("(%s.%s = 'Д')"; ArrayOf(Sender.TableName; Sender.Requisites(SYSREQ_STATE).SQLFieldName)))
  endif
else
  // Представление не создано
  // Наложить ограничение на состояние записей
  Sender.AddWhere(Format("(%s.%s = 'Д')"; ArrayOf(Sender.TableName; Sender.Requisites(SYSREQ_STATE).SQLFieldName)))
endif

Добавлено
Практика использования описанного выше кода показала, что возникают ситуации, когда механизм работает не так как надо (подробности в комментариях к записи). Спешу исправиться.
В событие справочника «Набор данных \ Открытие» необходимо поместить следующий код:


// Получить справочник
Reference = Sender.Component
// Снять все фильтры со справочника
Reference.Filtered = False
// Проверить существование представления справочника
View = Reference.View
if Assigned(View)
  // Представление создано
  // Проверить режим представления справочника
  if View.ViewMode == vmSelect
    // Справочник открыт в режиме выбора
    // Наложить фильтр на состояние записей
    Reference.Filter = Sender.Requisites(SYSREQ_STATE).Name & ' = "Д"'
    Reference.Filtered = True
  endif
endif

А в событие «Набор данных \ Закрытие» такой:


// Проверить существование представления справочника
View = Sender.Component.View
if Assigned(View)
  // Представление создано
  // Проверить режим представления справочника
  if View.ViewMode == vmSelect
    // Справочник открыт в режиме выбора
    // Изменить режим открытия справочника на Просмотр (необходимо для случаев, когда запись открывается по Ctrl+F4, после открытия по ...)
    View.ViewMode = vmView
  endif
endif

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

Добавлено 22.10.2010
Решение не работает в случае со справочником «Пользователи». Проявляется это в следующем. Предположим, что есть пользователь «Иванов Петр» и «Иванов Иван» (не важно — действующие или закрытые). Если при добавлении прав доступа на документ like-вводом набрать «Иванов», то откроется абсолютно весь список действующих пользователей. 

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

Функция ПоказатьТолькоДействующие() содержит в себе следующие вычисления (у функции есть параметр «Reference» типа «Вариантный»):

// Снять все фильтры со справочника 
Reference.Filtered = False 
// Проверить режим представления справочника 
if Reference.View.ViewMode == vmSelect 
  // Справочник открыт в режиме выбора 
  // Наложить фильтр на состояние записей
  Reference.Filter = Reference.Requisites(SYSREQ_STATE).Name & ' = "Д"' 
  Reference.Filtered = True
  // Заблокировать возможность изменения реквизита "Состояние" 
  Reference.Requisites(SYSREQ_STATE).CanGUIWrite = False
endif

Тем временем в собятие справочника «Набор данных \ Открытие» следующие вычисления:

// Проверить существование представления справочника 
if not VarIsClear(Sender.Component.View) 
  // Представление создано 
  // Показать только действующие записи 
  ПоказатьТолькоДействующие(Sender.Component)   
endif
17
Авторизуйтесь, чтобы оценить материал.
1
Иван Середкин

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

Антон ИСУПОВ

Отлично, Иван. Разбираться подробно с кодом не стал. По "Ctrl+F4" карточка открытой записи откроется?


Антон ИСУПОВ
открытой

закрытой

Alexey Okishev
Отлично, Иван. Разбираться подробнос к одом не стал. По "Ctrl+F4" карточка открытой записи откроется?

Действующей откроется, закрытой - нет.

Иван Середкин

Да, после открытия Работников по "..." потом по "Ctrl+F4" не открывает. Но ситуация редкая. Когда бывает надо "Ctrl+F4" для "Закрытой" записи? Только если мы обращаеися к старой записи, в которой в Кураторе (Работнике) запись уже была заполнена когда-то, т.е. перевыбирать её уже не надо. Значит пользоваться можно, но помня об особенности.

Иван Середкин

Постараюсь на днях найти решение этого ограничения.

Андрей Озеров

Спасибо, очень нужная вещь!

Иван Середкин

Запись обновлена (описал новую версию механизма фильтрации).

Сергей Жолобов

В карточке поручения по РКК фильтрация не происходит. Кроме того перестает работать выбор работника. По двойному клику вместо выбора происходит открытие карточки работника. Это только у меня так?

Иван Середкин

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

Иван Середкин

Красивого решения найти не удалось. В поручениях все заработает, если убрать код с события "Набор данных \ Закрытие", но тогда возможна следующая ситуация: если пользователь открыл поручение, в котором указана закрытая запись работника и сначала нажал на кнопку "...", но ничего не выбрал, закрыл окно и после этого нажал Ctrl+F4, то карточка закрытой записи не откроется. Такая ситуация может возникнуть крайне редко, но исключать ее нельзя. Если оставить код в событии "Набор данных \ Закрытие", то тогда могут возникать ситуации, что некоторые решения работают не так, как запланировано. Лучше, на мой взгляд, убрать код из закрытия набора данных.

Что касается кода в событие "Набор данных \ Закрытие", то он был добавлен потому, что IS-Builder явно не устанавливает режим просмотра справочника при его открытии по Ctrl+F4. Поэтому после того, как справочник был открыт по кнопке "..." IS-Builder запоминает, что справочник был открыт в режиме выбора и при следующем нажатии на Ctrl+F4 получаем, что срабатывает фильтр и закрытая запись не отображается (хотя при нажатии на Ctrl+F4 справочник должен открываться в режиме просмотра). Обойти эту особенность решил вот таким способом - при закрытии набора данных "обнулять" режим просмотра справочника. Хотел как лучше, а получилось как всегда :) В логике работы пользовательского выбора из справочника поручений досконально разбираться не стал, но выяснил, что мой метод фильтрации и пользовательский выбор из справочника поручений не совместимы.

Не исключаю, что как-то можно решить сложившуюся ситуацию, поэтому если у кого-нибудь есть идеи, то буду рад их выслушать :)

Сергей Жолобов

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

// Получить справочник
Reference = Sender.Component
// Снять все фильтры со справочника
Reference.Filtered = False
// Проверить существование представления справочника
View = Reference.View
if not VarIsClear(View)
  if Assigned(View)
    // Представление создано
    // Проверить режим представления справочника
    if View.ViewMode == vmSelect
      // Справочник открыт в режиме выбора
      // Наложить фильтр на состояние записей
      Reference.Filter = Sender.Requisites(SYSREQ_STATE).Name & ' = "Д"'
      Reference.Filtered = True
    endif
  endif
endif

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

Как бороться с этим?

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

Иван Середкин

Сергей, спасибо за дополнение (я про if not VarIsClear(View)). Под ошибкой имеете ввиду такую "Кэшированная компонента "НОР" не может быть родительской"?

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

Кстати, с этими справочниками (пользователи, наши организации) нужно быть поокуратнее, а то, как вы и описали, можно сильно поломать систему.

Сергей Жолобов

Да, ошибка в этом.

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

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

 

 

Степан Мурашов

Факты:

1. При вызове ISBL-функции из события справочника она получается для выполнения как компонента дочерняя по отношению справочнику который ее вызвал.

2. Кэшированный справочник не может быть родительской компонентой (т.е. у него не может быть дочерних компонент).

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

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

PS Как определить что справочник получен в режиме кэширвания чтобы в такой ситуации не вызывать функции не разобрался.

Иван Середкин

Но, как показали вычисления справочника Пользователи, системные функции ведут себя нормально. Отсюда появилось решения - вынести проверку на существование представление за функцию фильтрации. Решение работает даже в справочнике пользователей и наших организациях.
Итак, функция ПоказатьТолькоДействующие() приняла следующий вид (у функции есть параметр "Reference" типа "Вариантный"):

// Снять все фильтры со справочника
Reference.Filtered = False
// Проверить режим представления справочника
if Reference.View.ViewMode == vmSelect
  // Справочник открыт в режиме выбора
  // Наложить фильтр на состояние записей
  Reference.Filter = Reference.Requisites(SYSREQ_STATE).Name & ' = "Д"'
  Reference.Filtered = True
endif

Тем временем в собятие справочника помещается такой код:

// Проверить существование представления справочника
if not VarIsClear(Sender.Component.View)
  // Представление создано
  // Показать только действующие записи
  ПоказатьТолькоДействующие(Sender.Component)  
endif

Что касается справочника пользователей, то проверка на существование представления там уже есть. Достсточно в последних строчках вызвать функцию ПоказатьТолькоДействующие(Sender.Component)

Максим Суздалев

Хотел бы выразить благодарность за проделаную работу, Функция работает отлично.

Иван Середкин

Максим, спасибо, приятно слышать. Но не забывайте про возможную ситуацию: после нажатия на кнопку "..." не будет показываться карточка у закрытой записи по Ctrl+F4.

Алексей Баранов

2Иван: на каких версиях будет работать это решение (есть ли ограничения по используемой версии IS-Builder)?

К тем, кто пользовался реально - поделитесь отзывами, пожалуйста (интересует - не выявились ли какие-то другие ограничения, кроме "не будет показываться карточка у закрытой записи по Ctrl+F4") ?

Иван Середкин

Писал для IS-Builder 7.7.0, но не вижу причин, из-за которых это решение не будет работать на других версиях. 

Александр Савин

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

Решение нашел такое - проверять существование переменной окружения ISDESIGNMODE. Если она есть, значит справочник открыт в режиме выбора и можно использовать механизм фильтрации, иначе справочник не фильтруется.

Пример:

Env = Object.Environment
index = Env.IndexOfName("ISDESIGNMODE")
if Index <> -1

  <код из материала>

endif

Иван Жижик

 

 

 

 

а у меня вапче никакой риакции у справочника на этот код, в чем может быть проблема не работоспособности кода?

справочник работники, код расположен в открытии данных первый и в закрытии второй ... что  я сделал не так ? версия 4.6.1

Иван Середкин

Иван, посмотрите мой комментарий от 18 марта 2010, 17:44. В нем описан обновленный вариант + совместите его с комментарием от Александра Савина.

Павел Стрекалов

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

Reference.Requisites(SYSREQ_STATE).CanGUIWrite = False
Иван Середкин

Павел, спасибо за дополнение. Собрал все замечания из комментариев и дополнил статью окончательным решением.

Marina Kobzar

Установила даный фильтр для справочника "Виды электронных документов" при входе в системы выдает ошибку

[Window Title]
Ошибка

[Main Instruction]
Кэшированная компонента "ВЭД" не может быть родительской.

[Expanded Information]
Событие "ОТКРЫТИЕ ДО" карточки справочника "ВЭД": ошибка в строке 7.

[^] Меньше сведений  [ОК]

Иван Середкин

Марина, посмотрите мой комментарий от 18 марта 2010 в 17:44 - в нем описано решение этой ситуации.

Алсу Башарова

Спасибо за материал!В случае со справочником "Пользователи" очень помогло!

Юлия Мартыненко

спасибо за разработанное решение! применила ко многим спраочникам)

применила так же к справочникам "типовые маршруты" и "организации", однако для них получила ошибки:

1. кешированная компонента ТМТ не может быть родительской (ошибка в строке 16 события открытие)

2. при выборе организации, она не выбирается, а открывается ее карточка 

Авторизуйтесь, чтобы написать комментарий