Часто при доработке отчетов или печатных форм в 1С:ЗУП возникает задача получить какую-либо начальную дату, связанную с сотрудником, например, дату самого первого приема на работу в организацию. Начинающие разработчики могут столкнуться с трудностями, так как стандартные срезы данных, такие как СрезПервых, не всегда дают ожидаемый результат. Это связано с особенностями хранения кадровых данных и различиями в ключевых понятиях системы.
Разберем ситуацию на примере. Пользователь пытается доработать печатную форму графика отпусков и хочет вывести дату первого приема на работу для расчета стажа. Он пишет запрос, но получает неверные данные. Проанализируем, в чем заключается ошибка, как ее исправить, и выясним, действительно ли для поставленной задачи нужна именно эта дата.
Давайте посмотрим на первоначальный запрос, который вызвал затруднения. Его главная цель — получить данные из документа ГрафикОтпусков и для каждого сотрудника найти дату его первого приема на работу.
ВЫБРАТЬ
ГрафикОтпусковСотрудники.Ссылка.Дата КАК ДатаДоговора,
// ... другие поля
КадроваяИсторияСотрудниковСрезПервых.Регистратор.Дата КАК РегистраторДата
ИЗ
Документ.ГрафикОтпусков.Сотрудники КАК ГрафикОтпусковСотрудники
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(&КонецПериода, ) КАК КадроваяИсторияСотрудниковСрезПоследних
ПО (ГрафикОтпусковСотрудники.Сотрудник = КадроваяИсторияСотрудниковСрезПоследних.Сотрудник)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников.СрезПервых КАК КадроваяИсторияСотрудниковСрезПервых
ПО (ГрафикОтпусковСотрудники.Сотрудник = КадроваяИсторияСотрудниковСрезПервых.Сотрудник)
ГДЕ
// ... другие условия
И ТИПЗНАЧЕНИЯ(КадроваяИсторияСотрудниковСрезПервых.Регистратор) = ТИП(Документ.ПриемНаРаботу)
Проблема этого запроса кроется в фундаментальном непонимании двух ключевых сущностей 1С:ЗУП: Физическое лицо и Сотрудник.
Справочник.ФизическиеЛица — это запись о человеке как о персоне. Она хранит его личные данные: ФИО, дату рождения, ИНН, СНИЛС. Эти данные не меняются от одного места работы к другому. Одно физическое лицо может работать в организации несколько раз.
Справочник.Сотрудники — это запись, описывающая конкретное трудоустройство физического лица в организации. Она связана с должностью, подразделением, табельным номером и условиями труда. Каждый раз, когда человек увольняется и принимается на работу заново (например, сезонный работник), для него создается новый элемент в справочнике «Сотрудники», который ссылается на то же самое физическое лицо.
В исходном запросе все соединения выполняются по полю ГрафикОтпусковСотрудники.Сотрудник. Это значит, что для каждого конкретного трудоустройства (для каждой записи в справочнике «Сотрудники») мы ищем первую запись в регистре КадроваяИсторияСотрудников. Но у одного элемента справочника Сотрудники может быть только один прием на работу. Поэтому СрезПервых по сотруднику не даст нам историю всех его трудоустройств.
Чтобы найти самую первую дату, когда человек был принят в организацию, независимо от того, сколько раз он увольнялся и принимался снова, нужно строить запрос от физического лица.
Рассмотрим по шагам правильный алгоритм:
КадроваяИсторияСотрудников и для всего найденного списка сотрудников выбрать записи с видом события «Прием».Вот как может выглядеть запрос, реализующий эту логику:
ВЫБРАТЬ
МИНИМУМ(КадроваяИстория.Период) КАК СамаяПерваяДатаПриема
ИЗ
РегистрСведений.КадроваяИсторияСотрудников КАК КадроваяИстория
ГДЕ
КадроваяИстория.Сотрудник.ФизическоеЛицо = &ФизическоеЛицо
И КадроваяИстория.ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Прием)
Этот запрос найдет все приемы на работу для указанного физического лица по всем его "инкарнациям" в справочнике «Сотрудники» и вернет самую первую дату.
Даже если мы правильно найдем дату первого приема, использовать ее для расчета стажа по формуле "ТекущаяДата - ДатаПервогоПриема" — грубая методологическая ошибка.
Стаж — это сумма всех периодов работы. Если сотрудник работал год, потом уволился на пять лет, а потом снова устроился и проработал еще год, его общий стаж составит два года, а не семь. Подход с вычитанием дат полностью игнорирует возможные перерывы в работе.
В 1С:ЗУП 3.1 существуют готовые механизмы для хранения и расчета различных видов стажа (основной для больничных, северный, для права на отпуск и т. д.).
Вывод: не нужно пытаться изобретать собственный механизм расчета стажа. Используйте стандартные функции и данные, которые предоставляет конфигурация. Это надежнее и правильнее с точки зрения методологии учета.
Как выяснилось в ходе обсуждения, первоначальная задача была связана не с расчетом общего стажа, а с заполнением поля «Период работы» в печатной форме графика отпусков.
В контексте отпусков «Период работы» — это не общий стаж, а рабочий год, за который сотруднику предоставляется ежегодный оплачиваемый отпуск.
Для определения рабочего года нам нужна дата не самого первого, а самого последнего приема на работу. Получить ее можно с помощью виртуальной таблицы РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних с отбором по виду события.
Посмотрим на пример кода, который решает именно эту задачу:
// ... фрагмент запроса ...
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КадроваяИсторияСотрудников.СрезПоследних(
,
ВидСобытия = ЗНАЧЕНИЕ(Перечисление.ВидыКадровыхСобытий.Прием)) КАК ДатыПриема
ПО ГрафикОтпусковСотрудники.Сотрудник = ДатыПриема.Сотрудник
// ... в секции ВЫБРАТЬ можно получить ДатыПриема.Период КАК ДатаПоследнегоПриема ...
Таким образом, для корректного решения исходной задачи нужно было не искать самую первую дату приема, а получить дату последнего приема и на ее основе вычислять границы рабочего года, за который планируется отпуск. Это классический пример «проблемы XY», когда пользователь ищет решение для предполагаемой им промежуточной задачи (X), вместо того чтобы решать исходную конечную задачу (Y).
Итог: всегда четко определяйте конечную цель. Различайте понятия Сотрудник и Физическое лицо, используйте встроенные механизмы программы для расчета стажа и правильно определяйте рабочий год для предоставления отпусков.