Как в отчете 1С:ЗУП получить актуальное подразделение сотрудника с помощью запроса?

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

При создании пользовательских отчетов в 1С:ЗУП часто возникает задача вывести актуальное подразделение, в котором числится сотрудник на определенную дату или в котором он работал на момент какого-либо события. На первый взгляд, задача простая, но существует несколько подходов к ее решению, и выбор правильного зависит от контекста отчета. Рассмотрим основные способы получения этих данных с помощью запросов.

В этой статье мы разберем три основных метода:

  1. Простой запрос к регистру сведений через срез последних.
  2. Более точный метод с использованием интервального регистра для отчетов за период.
  3. Рекомендуемый и наиболее правильный способ для отчетов на СКД с использованием встроенных механизмов конфигурации.

Способ 1: Получение данных через "СрезПоследних"

Самый прямой и часто используемый способ получить данные на конкретную дату — это использовать виртуальную таблицу СрезПоследних регистра сведений КадроваяИсторияСотрудников. Этот регистр хранит всю историю кадровых перемещений: приемы, переводы, увольнения.

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

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

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


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

Разберем по шагам:

  1. В первой части запроса мы обращаемся к виртуальной таблице КадроваяИсторияСотрудников.СрезПоследних(&Период, ). В качестве параметра &Период передается дата, на которую нужно получить актуальные данные. Результат (сотрудник и его подразделение) помещается во временную таблицу ВТ_ПодразделенияСотрудников.
  2. Во второй части запроса мы выбираем данные из основной таблицы (в нашем примере это Документ.ПрогулНеявка).
  3. С помощью ЛЕВОЕ СОЕДИНЕНИЕ мы присоединяем нашу временную таблицу по полю Сотрудник.
  4. Функция ЕСТЬNULL используется для подстраховки: если для какого-то сотрудника не найдется подразделение, поле не останется пустым, а заполнится пустой ссылкой на справочник.

Важный момент: этот способ может давать неверные результаты, если вам нужно узнать подразделение сотрудника на дату самого события (например, на дату начала прогула), а не на дату окончания периода отчета. Если сотрудник был переведен в другое подразделение после прогула, но до конца периода, отчет покажет его новое, а не старое подразделение.

Способ 2: Использование интервального регистра для точных данных за период

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

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

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


ВЫБРАТЬ
    ПрогулНеявка.Сотрудник КАК Сотрудник,
    ПрогулНеявка.ДатаНачала КАК ДатаНачала,
    КадроваяИсторияСотрудниковИнтервальный.Подразделение КАК Подразделение
ИЗ
    Документ.ПрогулНеявка КАК ПрогулНеявка
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК КадроваяИсторияСотрудниковИнтервальный
        ПО ПрогулНеявка.Сотрудник = КадроваяИсторияСотрудниковИнтервальный.Сотрудник
            И (КОНЕЦПЕРИОДА(ПрогулНеявка.ДатаНачала, ДЕНЬ) МЕЖДУ КадроваяИсторияСотрудниковИнтервальный.ДатаНачала И КадроваяИсторияСотрудниковИнтервальный.ДатаОкончания)

Проанализируем ключевое отличие:

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

(КОНЕЦПЕРИОДА(ПрогулНеявка.ДатаНачала, ДЕНЬ) МЕЖДУ КадроваяИсторияСотрудниковИнтервальный.ДатаНачала И КадроваяИсторияСотрудниковИнтервальный.ДатаОкончания)

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

Способ 3: Правильный подход для отчетов на СКД (Система Компоновки Данных)

Прямые запросы к регистрам — это рабочий, но не всегда лучший метод. В типовых конфигурациях, таких как 1С:ЗУП, разработчики предоставляют специальные программные интерфейсы и механизмы, которые абстрагируют нас от структуры данных. Их использование делает отчеты более стабильными при обновлениях конфигурации. Для отчетов на СКД в ЗУП существует специальный механизм "Представлений".

Этот подход состоит из двух частей: специального текста запроса в макете СКД и вызова процедуры в модуле объекта отчета.

Шаг 1. Запрос в наборе данных СКД.

Вместо реального запроса к регистру, мы создаем "заглушку", которая определяет структуру полей и указывает системе, какие данные нам нужны.


ВЫБРАТЬ
    ДАТАВРЕМЯ(1, 1, 1) КАК Период,
    ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка) КАК Сотрудник,
    ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Подразделение
ПОМЕСТИТЬ Представления_КадровыеДанныеСотрудников
ИЗ
    ВТСотрудникиПериоды КАК СотрудникиПериоды;

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

Шаг 2. Код в модуле объекта отчета.

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


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)

    СтандартнаяОбработка = Ложь;
    
    // ... ваш код подготовки ...

    ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект);

    // ... ваш код компоновки ...

КонецПроцедуры

Вызов ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект) "оживляет" нашу заглушку. Процедура анализирует запросы в СКД, находит таблицы с префиксом Представления_ и самостоятельно заполняет их актуальными данными, используя внутреннюю, оптимизированную логику конфигурации.

Преимущества этого подхода:

Заключение

Мы рассмотрели три разных способа получения данных о подразделении сотрудника. Выбор конкретного метода зависит от вашей задачи:

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

← На главную