Как правильно передать параметры и настроить отбор в типовой функции КадровыеДанныеСотрудников в 1С

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

При разработке отчетов и обработок в типовых конфигурациях (например, 1С:ЗУП, 1С:ERP, 1С:Комплексная автоматизация) разработчики часто обращаются к функции КадровыйУчет.КадровыеДанныеСотрудников. Она позволяет одной строкой получить срез множества кадровых реквизитов на заданную дату: подразделение, должность, состояние, табельный номер, ФИО и другие периодические данные.

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

Почему при передаче пустого массива сотрудников возвращается пустой результат

Проанализируем исходный код вспомогательной процедуры КадровыйУчет.СоздатьНаДатуВТКадровыеДанныеСотрудников, которую вызывает функция КадровыеДанныеСотрудников:


Запрос.Текст = 
    "ВЫБРАТЬ РАЗЛИЧНЫЕ
    |    &ДатаПолученияДанных КАК Период,
    |    ДанныеСотрудников.Ссылка КАК Сотрудник
    |ПОМЕСТИТЬ ВТСписокСотрудников
    |ИЗ
    |    Справочник.Сотрудники КАК ДанныеСотрудников
    |ГДЕ
    |    ДанныеСотрудников.Ссылка В(&МассивСотрудников)";

Обратите внимание на условие ГДЕ ДанныеСотрудников.Ссылка В(&МассивСотрудников). В платформе 1С:Предприятие при передаче пустого массива или пустого списка значений в условие с оператором В результат проверки всегда равен Ложь. Соответственно, временная таблица ВТСписокСотрудников создается пустой, и итоговая таблица кадровых данных не содержит ни одной строки.

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

Способ 1. Использование низкоуровневого вызова с собственной временной таблицей (Рекомендуемый)

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

Разберем реализацию по шагам:

  1. Создаем МенеджерВременныхТаблиц и запрос.
  2. Формируем временную таблицу со списком нужных сотрудников с учетом отбора по подразделению на дату отчета.
  3. Вызываем типовую процедуру формирования кадровых данных.
  4. Считываем готовые данные из итоговой временной таблицы.

Посмотрим на пример программного кода:


МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;

Запрос.УстановитьПараметр("Период", ПериодОтчета);
Запрос.УстановитьПараметр("ОтборСотрудник", Отчет.Сотрудник);
Запрос.УстановитьПараметр("ЕстьОтборПоСотруднику", ЗначениеЗаполнено(Отчет.Сотрудник));
Запрос.УстановитьПараметр("ОтборПодразделение", Отчет.Подразделение);
Запрос.УстановитьПараметр("ЕстьОтборПоПодразделению", ЗначениеЗаполнено(Отчет.Подразделение));

Запрос.Текст = 
    "ВЫБРАТЬ
    |    &Период КАК Период,
    |    Сотрудники.Ссылка КАК Сотрудник
    |ПОМЕСТИТЬ ВТСписокСотрудников
    |ИЗ
    |    Справочник.Сотрудники КАК Сотрудники
    |        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&Период, ) КАК КадроваяИстория
    |        ПО Сотрудники.Ссылка = КадроваяИстория.Сотрудник
    |ГДЕ
    |    (&ЕстьОтборПоСотруднику = ЛОЖЬ ИЛИ Сотрудники.Ссылка = &ОтборСотрудник)
    |    И (&ЕстьОтборПоПодразделению = ЛОЖЬ ИЛИ КадроваяИстория.Подразделение = &ОтборПодразделение)
    |    И КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)";

Запрос.Выполнить();

// Формируем структуру-описатель для типовой процедуры
ОписательВТ = КадровыйУчет.ОписательВременныхТаблицДляСоздатьВТКадровыеДанныеСотрудников(МенеджерВТ, "ВТСписокСотрудников");

// Вызываем типовое наполнение кадровыми данными
ЧтоИщу = "Подразделение, Должность, ТабельныйНомер, ФИО, Состояние";
КадровыйУчет.СоздатьВТКадровыеДанныеСотрудников(ОписательВТ, Истина, ЧтоИщу);

// Считываем результат
Запрос.Текст = "ВЫБРАТЬ * ИЗ ВТКадровыеДанныеСотрудников КАК ВТКадровыеДанныеСотрудников";
ТаблицаРезультат = Запрос.Выполнить().Выгрузить();

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

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

Проанализируем алгоритм:

  1. Выполняем предварительный запрос к базе, который выбирает сотрудников с учетом условий отборов.
  2. Выгружаем полученные ссылки в массив через метод ВыгрузитьКолонку("Ссылка").
  3. Передаем сформированный массив в функцию КадровыеДанныеСотрудников.

Посмотрим на пример кода:


Запрос = Новый Запрос;
Запрос.УстановитьПараметр("Период", ПериодОтчета);
Запрос.УстановитьПараметр("Сотрудник", Отчет.Сотрудник);
Запрос.УстановитьПараметр("Подразделение", Отчет.Подразделение);
Запрос.УстановитьПараметр("ОтборПоСотруднику", ЗначениеЗаполнено(Отчет.Сотрудник));
Запрос.УстановитьПараметр("ОтборПоПодразделению", ЗначениеЗаполнено(Отчет.Подразделение));

Запрос.Текст = 
    "ВЫБРАТЬ
    |    КадроваяИстория.Сотрудник КАК Сотрудник
    |ИЗ
    |    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&Период, ) КАК КадроваяИстория
    |ГДЕ
    |    (&ОтборПоСотруднику = ЛОЖЬ ИЛИ КадроваяИстория.Сотрудник = &Сотрудник)
    |    И (&ОтборПоПодразделению = ЛОЖЬ ИЛИ КадроваяИстория.Подразделение = &Подразделение)
    |    И КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)";

РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
    МассивСотрудников = РезультатЗапроса.Выгрузить().ВыгрузитьКолонку("Сотрудник");
    ЧтоИщу = "Подразделение, Должность, ТабельныйНомер, ФИО, Состояние";
    КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников, ЧтоИщу, ПериодОтчета);
Иначе
    // Если по отбору сотрудники не найдены, возвращаем пустую таблицу нужной структуры
    КадровыеДанные = Новый ТаблицаЗначений;
КонецЕсли;

Важное замечание: При работе с большим количеством сотрудников (более 1000–2000 записей) передача списка через массив в параметр функции может приводить к снижению производительности или ограничению СУБД на число параметров запроса. В таких сценариях рекомендуется использовать Способ 1 с временными таблицами.

Способ 3. Пост-фильтрация полученной таблицы значений

Если сотрудников в базе относительно немного и предварительный запрос писать нецелесообразно, можно запросить данные по всем сотрудникам, а затем профильтровать полученную ТаблицуЗначений:


Если ЗначениеЗаполнено(Отчет.Сотрудник) Тогда
    МассивСотрудников = Отчет.Сотрудник;
Иначе
    // Получаем всех сотрудников из справочника
    Запрос = Новый Запрос("ВЫБРАТЬ Ссылка ИЗ Справочник.Сотрудники ГДЕ Не ВАрхиве");
    МассивСотрудников = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
КонецЕсли;

ЧтоИщу = "Подразделение, Должность, ТабельныйНомер, ФИО, Состояние";
КадровыеДанные = КадровыйУчет.КадровыеДанныеСотрудников(Истина, МассивСотрудников, ЧтоИщу, ПериодОтчета);

// Фильтрация по подразделению средствами ТаблицыЗначений
Если ЗначениеЗаполнено(Отчет.Подразделение) Тогда
    СтруктураОтбора = Новый Структура("Подразделение", Отчет.Подразделение);
    КадровыеДанные = КадровыеДанные.Скопировать(СтруктураОтбора);
КонецЕсли;

Способ 4. Реализация логики отборов в отчете на СКД

Если отчет строится с использованием Системы компоновки данных (СКД), ручную передачу массивов можно исключить. В СКД управление опциональными параметрами реализовано на уровне расширения языка запросов с помощью фигурных скобок {}:


ВЫБРАТЬ
    КадроваяИстория.Сотрудник КАК Сотрудник,
    КадроваяИстория.Подразделение КАК Подразделение,
    КадроваяИстория.Должность КАК Должность
ИЗ
    РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&Период, ) КАК КадроваяИстория
ГДЕ
    КадроваяИстория.ВидСобытия <> ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Увольнение)
    {ГДЕ
    КадроваяИстория.Сотрудник.* КАК Сотрудник,
    КадроваяИстория.Подразделение.* КАК Подразделение}

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

← На главную