При создании пользовательских отчетов в 1С:ЗУП часто возникает задача вывести актуальное подразделение, в котором числится сотрудник на определенную дату или в котором он работал на момент какого-либо события. На первый взгляд, задача простая, но существует несколько подходов к ее решению, и выбор правильного зависит от контекста отчета. Рассмотрим основные способы получения этих данных с помощью запросов.
В этой статье мы разберем три основных метода:
Самый прямой и часто используемый способ получить данные на конкретную дату — это использовать виртуальную таблицу СрезПоследних регистра сведений КадроваяИсторияСотрудников. Этот регистр хранит всю историю кадровых перемещений: приемы, переводы, увольнения.
Этот метод идеально подходит, если вам нужно получить срез данных на одну конкретную дату, например, на конец отчетного периода.
Посмотрим на пример. Предположим, мы делаем отчет на основе документа ПрогулНеявка и хотим для каждого сотрудника в документе показать его текущее подразделение.
Запрос можно составить из двух частей. Сначала получим актуальные подразделения для всех сотрудников во временную таблицу, а затем присоединим ее к основной выборке.
Запрос.Текст =
"ВЫБРАТЬ
| КадроваяИсторияСотрудниковСрезПоследних.Сотрудник КАК Сотрудник,
| КадроваяИсторияСотрудниковСрезПоследних.Подразделение КАК Подразделение
|ПОМЕСТИТЬ ВТ_ПодразделенияСотрудников
|ИЗ
| РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&Период, ) КАК КадроваяИсторияСотрудниковСрезПоследних
|;
|
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
| ПрогулНеявка.Сотрудник КАК Сотрудник,
| ЕСТЬNULL(ВТ_ПодразделенияСотрудников.Подразделение, ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка)) КАК Подразделение
|ИЗ
| Документ.ПрогулНеявка КАК ПрогулНеявка
| ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ПодразделенияСотрудников КАК ВТ_ПодразделенияСотрудников
| ПО ПрогулНеявка.Сотрудник = ВТ_ПодразделенияСотрудников.Сотрудник";
Разберем по шагам:
КадроваяИсторияСотрудников.СрезПоследних(&Период, ). В качестве параметра &Период передается дата, на которую нужно получить актуальные данные. Результат (сотрудник и его подразделение) помещается во временную таблицу ВТ_ПодразделенияСотрудников.Документ.ПрогулНеявка).ЛЕВОЕ СОЕДИНЕНИЕ мы присоединяем нашу временную таблицу по полю Сотрудник.ЕСТЬNULL используется для подстраховки: если для какого-то сотрудника не найдется подразделение, поле не останется пустым, а заполнится пустой ссылкой на справочник.Важный момент: этот способ может давать неверные результаты, если вам нужно узнать подразделение сотрудника на дату самого события (например, на дату начала прогула), а не на дату окончания периода отчета. Если сотрудник был переведен в другое подразделение после прогула, но до конца периода, отчет покажет его новое, а не старое подразделение.
Когда мы строим отчет за период и для каждой записи отчета (например, для каждого дня отсутствия) важно знать, в каком подразделении сотрудник числился именно в тот момент, использование СрезПоследних некорректно. Для таких задач предназначен специальный интервальный регистр КадроваяИсторияСотрудниковИнтервальный.
Этот регистр хранит данные не в виде записей на дату, а в виде интервалов с датой начала и датой окончания действия. Это позволяет точно определить состояние на любой момент времени внутри периода.
Посмотрим на пример запроса, который решает ту же задачу, что и в первом способе, но уже корректно для событий внутри периода.
ВЫБРАТЬ
ПрогулНеявка.Сотрудник КАК Сотрудник,
ПрогулНеявка.ДатаНачала КАК ДатаНачала,
КадроваяИсторияСотрудниковИнтервальный.Подразделение КАК Подразделение
ИЗ
Документ.ПрогулНеявка КАК ПрогулНеявка
ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК КадроваяИсторияСотрудниковИнтервальный
ПО ПрогулНеявка.Сотрудник = КадроваяИсторияСотрудниковИнтервальный.Сотрудник
И (КОНЕЦПЕРИОДА(ПрогулНеявка.ДатаНачала, ДЕНЬ) МЕЖДУ КадроваяИсторияСотрудниковИнтервальный.ДатаНачала И КадроваяИсторияСотрудниковИнтервальный.ДатаОкончания)
Проанализируем ключевое отличие:
Соединение таблиц происходит не только по сотруднику, но и по условию попадания даты события в интервал кадровой записи:
(КОНЕЦПЕРИОДА(ПрогулНеявка.ДатаНачала, ДЕНЬ) МЕЖДУ КадроваяИсторияСотрудниковИнтервальный.ДатаНачала И КадроваяИсторияСотрудниковИнтервальный.ДатаОкончания)
Это условие гарантирует, что для каждой записи документа ПрогулНеявка будет найдена та запись из кадровой истории, которая была актуальна именно на дату начала прогула. Этот подход является более надежным и правильным для анализа данных за период.
Прямые запросы к регистрам — это рабочий, но не всегда лучший метод. В типовых конфигурациях, таких как 1С:ЗУП, разработчики предоставляют специальные программные интерфейсы и механизмы, которые абстрагируют нас от структуры данных. Их использование делает отчеты более стабильными при обновлениях конфигурации. Для отчетов на СКД в ЗУП существует специальный механизм "Представлений".
Этот подход состоит из двух частей: специального текста запроса в макете СКД и вызова процедуры в модуле объекта отчета.
Шаг 1. Запрос в наборе данных СКД.
Вместо реального запроса к регистру, мы создаем "заглушку", которая определяет структуру полей и указывает системе, какие данные нам нужны.
ВЫБРАТЬ
ДАТАВРЕМЯ(1, 1, 1) КАК Период,
ЗНАЧЕНИЕ(Справочник.Сотрудники.ПустаяСсылка) КАК Сотрудник,
ЗНАЧЕНИЕ(Справочник.ПодразделенияОрганизаций.ПустаяСсылка) КАК Подразделение
ПОМЕСТИТЬ Представления_КадровыеДанныеСотрудников
ИЗ
ВТСотрудникиПериоды КАК СотрудникиПериоды;
Ключевую роль здесь играет имя временной таблицы — Представления_КадровыеДанныеСотрудников. Система 1С:ЗУП поймет по этому имени, что эту таблицу нужно заполнить кадровыми данными. Источником для отбора сотрудников (ВТСотрудникиПериоды) обычно служит другая временная таблица с перечнем сотрудников, для которых нужно получить данные.
Шаг 2. Код в модуле объекта отчета.
Чтобы этот механизм сработал, необходимо в процедуре формирования отчета (например, ПриКомпоновкеРезультата) добавить вызов специальной общей процедуры.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// ... ваш код подготовки ...
ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект);
// ... ваш код компоновки ...
КонецПроцедуры
Вызов ЗарплатаКадрыОбщиеНаборыДанных.ЗаполнитьОбщиеИсточникиДанныхОтчета(ЭтотОбъект) "оживляет" нашу заглушку. Процедура анализирует запросы в СКД, находит таблицы с префиксом Представления_ и самостоятельно заполняет их актуальными данными, используя внутреннюю, оптимизированную логику конфигурации.
Преимущества этого подхода:
Мы рассмотрели три разных способа получения данных о подразделении сотрудника. Выбор конкретного метода зависит от вашей задачи:
СрезПоследних из регистра КадроваяИсторияСотрудников.КадроваяИсторияСотрудниковИнтервальный.ЗаполнитьОбщиеИсточникиДанныхОтчета.Использование встроенных механизмов конфигурации, где это возможно, является наиболее профессиональным и дальновидным подходом, который обеспечит стабильную работу ваших доработок в долгосрочной перспективе.