Как в 1С открыть форму списка с отбором по вычисляемому реквизиту?

Программист 1С v8.3 (Управляемые формы) 1С:Зарплата и Управление Персоналом Сфера услуг, туризм и социальный сектор
← На главную

Часто перед разработчиками 1С встает задача: из внешней обработки или другой формы открыть список элементов справочника, применив к нему отбор по определенному условию. Проблема усложняется, когда условие отбора — это не реквизит самого справочника, а некое вычисляемое значение, которое мы видим в форме элемента. Классический пример — справочник «Сотрудники» в конфигурации «Зарплата и управление персоналом», где нужно отобрать персонал по «Текущему виду занятости».

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

Почему нельзя отфильтровать список по «реквизиту формы»?

Ключ к пониманию проблемы лежит в фундаментальных отличиях управляемых форм от обычных. В управляемом приложении клиентская часть (то, что видит пользователь) — это лишь «тонкое» отображение данных. Вся основная логика, работа с базой данных и вычисления происходят на сервере.

Реквизиты, которые мы видим на форме (например, ТекущийВидЗанятости в карточке сотрудника), часто являются несохраненными данными. Это реквизиты формы, а не реквизиты объекта базы данных. Их значения вычисляются программно на сервере в момент открытия формы на основании данных из других объектов, чаще всего — из регистров сведений. В нашем примере информация о виде занятости сотрудника хранится в регистре сведений ТекущиеКадровыеДанныеСотрудников.

Из этого следует важный вывод: нельзя установить отбор по данным, которых физически нет в таблице справочника в базе данных. Стандартный механизм передачи отбора при открытии формы через структуру ПараметрыФормы работает только для полей, которые являются реквизитами самого объекта (например, «Наименование», «Код», «Родитель» и т.д.).

Правильный алгоритм решения

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

  1. Получение данных на сервере. Создаем серверную функцию, которая будет выполнять запрос к источнику данных (в нашем случае — к регистру сведений ТекущиеКадровыеДанныеСотрудников). В запросе мы устанавливаем необходимое условие (например, ТекущийВидЗанятости = &НужныйВидЗанятости).
  2. Формирование массива ссылок. Результатом запроса будет выборка, содержащая ссылки на нужных нам сотрудников. Эту выборку необходимо обойти в цикле и сложить все полученные ссылки в массив.
  3. Передача данных на клиент. Серверная функция должна вернуть этот массив на клиент. Важно: с сервера на клиент нельзя передавать такие объекты, как Запрос, РезультатЗапроса или Выборка. Это приведет к ошибке «Ошибка передачи данных между клиентом и сервером. Значение недопустимого типа». А вот массивы, структуры и ссылки передаются без проблем.
  4. Открытие формы с отбором. На клиенте, получив массив ссылок, мы открываем форму списка справочника, передавая ей специальный параметр отбора. Система 1С понимает конструкцию Отбор.Ссылка = &МассивСсылок как условие ГДЕ Ссылка В (&МассивСсылок).

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

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

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

Клиентская процедура:


&НаКлиенте
Процедура ОткрытьСписокСОтбором(Команда)
    // 1. Вызываем серверную функцию, чтобы получить массив ссылок на сотрудников.
    // Передаем в нее значение для отбора из реквизита формы обработки.
    СписокСотрудников = ПолучитьСписокСотрудниковНаСервере(Объект.ВидЗанятостиДляОтбора);

    // Если серверная функция вернула пустой массив, можно не открывать форму.
    Если СписокСотрудников.Количество() = 0 Тогда
        ПоказатьПредупреждение("Сотрудники с указанным видом занятости не найдены.");
        Возврат;
    КонецЕсли;

    // 2. Формируем структуру параметров для открытия формы.
    // Ключевой момент: мы создаем отбор по полю "Ссылка",
    // а в качестве значения передаем наш массив.
    ПараметрыФормы = Новый Структура;
    ПараметрыФормы.Вставить("Отбор", Новый Структура("Ссылка", СписокСотрудников));

    // 3. Открываем форму списка справочника с нашими параметрами.
    ОткрытьФорму("Справочник.Сотрудники.ФормаСписка", ПараметрыФормы);
КонецПроцедуры

Серверная функция:


&НаСервере
Функция ПолучитьСписокСотрудниковНаСервере(пВидЗанятости)
    // Создаем пустой массив, в который будем собирать ссылки
    МассивСотрудников = Новый Массив;

    // Создаем и настраиваем запрос
    Запрос = Новый Запрос;
    Запрос.Текст =
        "ВЫБРАТЬ
        |    ТекущиеКадровыеДанныеСотрудников.Сотрудник КАК Ссылка
        |ИЗ
        |    РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанныеСотрудников
        |ГДЕ
        |    ТекущиеКадровыеДанныеСотрудников.ТекущийВидЗанятости = &ТекущийВидЗанятости";

    // Устанавливаем параметр запроса из аргумента функции
    Запрос.УстановитьПараметр("ТекущийВидЗанятости", пВидЗанятости);

    // Выполняем запрос и получаем выборку
    Выборка = Запрос.Выполнить().Выбрать();

    // Обходим выборку в цикле
    Пока Выборка.Следующий() Цикл
        // Добавляем ссылку на сотрудника в наш массив
        МассивСотрудников.Добавить(Выборка.Ссылка);
    КонецЦикла;

    // Возвращаем готовый массив на клиент
    Возврат МассивСотрудников;
КонецФункции

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

Возможные проблемы и их решение

Иногда при выполнении запроса к регистру сведений, например, к ТекущиеКадровыеДанныеСотрудников, результат может оказаться пустым, даже если вы уверены, что данные по сотрудникам есть. В чем может быть причина?

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

В заключение: при работе с управляемыми формами всегда помните о клиент-серверной архитектуре. Для задач сложной фильтрации данных всегда идите по пути:
Сбор данных на сервере (запрос) -> Формирование массива ссылок -> Передача массива на клиент -> Открытие формы с отбором по этому массиву.
Этот подход не только корректен, но и наиболее производителен.

← На главную