Как получить список сотрудников, работавших в организации в заданном периоде в 1С:ЗУП 2.5?

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

Разработка отчетов и запросов по кадровой истории в программе «1С:Зарплата и Управление Персоналом 2.5» (ЗУП 2.5) — классическая задача, с которой сталкивается каждый программист 1С. Казалось бы, что может быть проще, чем вывести список сотрудников, работавших в компании в выбранном интервале дат? Однако именно здесь начинающие разработчики совершают наибольшее количество архитектурных ошибок, приводящих к искажению данных в отчетах.

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

Разбор типичных ошибок: почему простые запросы врут?

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

Ошибка №1: Срез последних на конец периода

Самая распространенная ошибка — попытка получить данные из виртуальной таблицы СрезПоследних регистра сведений РаботникиОрганизаций на дату окончания периода. Разработчик рассуждает так: «Если я возьму срез на конец периода, то увижу актуальное состояние сотрудников». Это в корне неверно. Если сотрудник уволился в середине выбранного периода (например, 15 числа при периоде с 1 по 30 число), то на конец периода его состояние в регистре будет равно «Увольнение». Нам же нужно, чтобы он попал в отчет, так как первые 15 дней месяца он честно работал в организации. Срез последних на конец периода просто «отрежет» всех уволенных внутри интервала.

Ошибка №2: Получение дат через точку от сотрудника

Попытка обратиться к реквизитам справочника через точку вида Сотрудник.ДатаПриемаНаРаботу или Сотрудник.ДатаУвольнения — это грубейшая ошибка проектирования по двум причинам:

  1. Падение производительности: Каждое такое обращение заставляет СУБД выполнять неявные левые соединения (LEFT JOIN) таблиц базы данных. На больших базах это гарантированно приведет к зависанию отчета.
  2. Потеря историчности: В справочнике СотрудникиОрганизаций хранятся только самые последние, финальные даты. Если сотрудник сначала работал, потом уволился, а через год его приняли снова (создав новый элемент или используя старый в зависимости от методологии учета), простые реквизиты справочника не покажут вам реальную хронологию за прошлые года. Вся кадровая история пишется исключительно в регистры сведений.

Ошибка №3: Игнорирование механизма временных кадровых изменений

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

Проектируем правильный алгоритм работы запроса

Чтобы решить задачу корректно и собрать абсолютно всех сотрудников, которые работали хотя бы один день в интервале между &НачалоПериода и &КонецПериода, нам необходимо объединить три независимых подмножества данных:

  1. Сотрудники, уже работавшие на начало периода. Нам нужно получить состояние всех сотрудников на самую первую секунду нашего периода (срез последних на &НачалоПериода) и отсечь тех, кто к этому моменту уже был уволен.
  2. Сотрудники, по которым были кадровые движения внутри периода. Любые записи в физической таблице регистра РаботникиОрганизаций, дата которых (поле Период) попадает в наш интервал. Сюда войдут вновь принятые, переведенные и даже уволенные (ведь до момента увольнения внутри периода они работали!).
  3. Сотрудники, у которых завершились временные кадровые события. Нам необходимо отследить поле ПериодЗавершения, если оно попадает в границы нашего интервала.

Объединение этих трех выборок с помощью оператора ОБЪЕДИНИТЬ (который автоматически удаляет дубликаты записей) даст нам максимально точный и быстрый результат.

Пишем корректный запрос для ЗУП 2.5 по шагам

Рассмотрим детально, как выглядит реализация данного алгоритма на языке запросов 1С.

Шаг 1. Выбираем работающих на начало периода

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


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

Шаг 2. Выбираем движения внутри периода

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


ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
	РаботникиОрганизаций.Сотрудник
ИЗ
	РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ГДЕ
	РаботникиОрганизаций.Период МЕЖДУ &НачалоПериода И &КонецПериода

Шаг 3. Учитываем завершение временных событий в периоде

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


ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
	РаботникиОрганизаций.Сотрудник
ИЗ
	РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ГДЕ
	РаботникиОрганизаций.ПериодЗавершения МЕЖДУ &НачалоПериода И &КонецПериода

Полный текст готового запроса

Ниже представлен готовый текст запроса, который вы можете скопировать и сразу использовать в своих разработках (в отчетах, обработках или динамических списках обычных форм):


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

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
	РаботникиОрганизаций.Сотрудник
ИЗ
	РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ГДЕ
	РаботникиОрганизаций.Период МЕЖДУ &НачалоПериода И &КонецПериода

ОБЪЕДИНИТЬ

ВЫБРАТЬ РАЗЛИЧНЫЕ
	РаботникиОрганизаций.Сотрудник
ИЗ
	РегистрСведений.РаботникиОрганизаций КАК РаботникиОрганизаций
ГДЕ
	РаботникиОрганизаций.ПериодЗавершения МЕЖДУ &НачалоПериода И &КонецПериода

Для справки: Как эта задача решается в современных конфигурациях (ЗУП 3.1)

Если вы планируете переходить на современные версии программ 1С (например, 1С:ЗУП 3.1 на управляемых формах), то вам будет полезно узнать, что там архитектура работы с кадрами была кардинально переработана. Разработчикам больше не нужно вручную собирать сложные запросы с объединением таблиц.

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

← На главную