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

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

При разработке отчетов и кастомных обработок в конфигурации «1С:Зарплата и управление персоналом 3.1» программисты часто сталкиваются с необходимостью получить «нарезанную» по периодам историю кадровых перемещений сотрудников внутри одного или нескольких подразделений. Стандартные методы получения сотрудников на определенную дату не подходят, если один и тот же сотрудник в течение одного месяца несколько раз переводился с одной должности на другую в рамках одного подразделения. Нам важно получить хронологическую последовательность со всеми интервалами работы.

Анализ проблемы и почему не работают простые методы

Рассмотрим классический пример. Сотрудник Иванов устроен в подразделение «Отдел продаж». С 2 по 5 октября он работал на должности «Младший менеджер», с 6 по 25 октября его перевели на должность «Ведущий менеджер» внутри того же подразделения, а с 26 октября он был переведен в «Отдел маркетинга» (другое подразделение). Наша задача — получить следующую таблицу:

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

Решение 1. Прямой запрос к регистру «КадроваяИсторияСотрудниковИнтервальный»

Самым быстрым и простым способом решить эту задачу является написание прямого запроса к регистру сведений КадроваяИсторияСотрудниковИнтервальный. В конфигурации 1С:ЗУП 3.1 этот регистр спроектирован специальным образом: разработчики фирмы «1С» уже хранят в нем предварительно рассчитанные и «нарезанные» временные интервалы по каждому сотруднику. Это избавляет нас от необходимости писать тяжелые запросы со сложными соединениями для вычисления даты окончания предыдущего периода.

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


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

Важные нюансы данного запроса:

  1. Ограничение по периоду регистрации: С помощью конструкции ВЫБОР мы принудительно ограничиваем даты начала и окончания интервалов рамками выбранного месяца (параметр &Период). Если кадровый интервал начался раньше начала месяца или закончился позже окончания месяца, система «обрежет» даты под границы анализируемого периода.
  2. Корректировка даты окончания: Для красивого вывода мы уменьшаем ДатаОкончания на 1 день с помощью функции ДОБАВИТЬКДАТЕ, так как в интервальных регистрах дата окончания часто пишется как начало следующего дня (например, «06.10.2023 00:00:00»).
  3. Фильтрация увольнений: Мы исключаем события увольнения, чтобы не выводить «пустые» строки после фактического прекращения трудовых отношений.

Несмотря на то, что этот запрос прост и отлично решает локальную задачу, прямое обращение к интервальным регистрам имеет существенные недостатки:

Решение 2. Использование программного интерфейса БСП (Рекомендованный способ)

Чтобы сделать код устойчивым к обновлениям и полностью соответствующим стандартам разработки фирмы «1С», мы можем применить программные функции общего модуля ЗарплатаКадрыПериодическиеРегистры. Данный подход гарантирует корректность получаемых данных за счет использования платформенных механизмов формирования интервалов.

Разберем по шагам, как реализовать этот алгоритм в своем коде:

  1. Сначала мы формируем временную таблицу с базовым списком сотрудников и требуемым периодом.
  2. Затем с помощью специального метода создаем временную таблицу кадровой истории с автоматической разбивкой на периоды.

Посмотрим на пример кода, реализующего этот подход:


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

// Заполняем таблицу сотрудниками подразделения за выбранный период
ПараметрыПолучения = КадровыйУчет.ПараметрыПолученияСотрудниковОрганизацийПоСпискуФизическихЛиц();
ПараметрыПолучения.Организация = Справочники.Организации.ОрганизацияПоУмолчанию();
ПараметрыПолучения.НачалоПериода = НачалоМесяца(Объект.ПериодРегистрации);
ПараметрыПолучения.ОкончаниеПериода = КонецМесяца(Объект.ПериодРегистрации);
ПараметрыПолучения.Подразделение = Объект.Подразделение;

ТЗСотрудникиПодразделения = КадровыйУчет.СотрудникиОрганизации(Истина, ПараметрыПолучения);

Для Каждого СтрокаСотрудник Из ТЗСотрудникиПодразделения Цикл
    НоваяСтрока = ТаблицаСотрудников.Добавить();
    НоваяСтрока.Сотрудник = СтрокаСотрудник.Сотрудник;
    НоваяСтрока.ДатаНачала = НачалоМесяца(Объект.ПериодРегистрации);
    НоваяСтрока.ДатаОкончания = КонецМесяца(Объект.ПериодРегистрации);
КонецЦикла;

// Помещаем таблицу во временную таблицу в запросе
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос.Текст = "ВЫБРАТЬ * ПОМЕСТИТЬ ВТСотрудникиПериоды ИЗ &ТаблицаСотрудников КАК ТаблицаСотрудников";
Запрос.УстановитьПараметр("ТаблицаСотрудников", ТаблицаСотрудников);
Запрос.Выполнить();

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

ЗарплатаКадрыПериодическиеРегистры.СоздатьВТИмяРегистраПериоды(
    "КадроваяИсторияСотрудников",
    Запрос.МенеджерВременныхТаблиц,
    Истина,
    ОписаниеФильтра,
    ПараметрыПостроения,
    "ВТСотрудникиИнтервалы"
);

// Теперь у нас есть временная таблица ВТСотрудникиИнтервалы со всеми периодами и кадровыми данными!
Запрос.Текст = 
"ВЫБРАТЬ
    Интервалы.Сотрудник,
    Интервалы.ДатаНачала,
    Интервалы.ДатаОкончания,
    Интервалы.Подразделение,
    Интервалы.Должность
ИЗ
    ВТСотрудникиИнтервалы КАК Интервалы
УПОРЯДОЧИТЬ ПО
    Интервалы.Сотрудник.Наименование,
    Интервалы.ДатаНачала";

КадроваяИстория = Запрос.Выполнить().Выгрузить();

Этот метод гарантирует получение абсолютно корректных кадровых интервалов по должностям и подразделениям. На выходе мы получаем временную таблицу ВТСотрудникиИнтервалы, структура которой совпадает со стандартными отчетами ЗУП. Метод автоматически обрабатывает ситуации с исправлениями кадровых документов и разграничением прав доступа.

Решение 3. Использование механизма представлений (для СКД-отчетов)

Если вы разрабатываете отчет на базе Системы компоновки данных (СКД), то лучшим решением будет использование виртуальных таблиц-представлений. В ЗУП 3.1 разработчики внедрили концепцию динамической подстановки текстов запросов. Вместо реальных таблиц баз данных вы можете использовать конструкцию:

Представления_ТаблицаРегистра_КадроваяИсторияСотрудников

Для того чтобы система развернула эту виртуальную таблицу в оптимизированный запрос при выводе отчета, достаточно в модуле объекта отчета прописать вызов предопределенного метода:

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

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

Методологические рекомендации при частых перемещениях сотрудников

Часто в обсуждениях подобных задач на форумах всплывает важный методологический аспект. Если у вас на предприятии сотрудники перемещаются между должностями или бригадами каждые 2–3 дня, то оформление каждого такого шага полноценным документом «Кадровый перевод» создаст колоссальную бумажную нагрузку на кадровую службу. Трудовой кодекс обязывает подписывать дополнительное соглашение к трудовому договору при каждом изменении должности или подразделения.

Чтобы избежать бумажной рутины и не засорять официальную кадровую историю техническими перемещениями, проанализируйте возможность использования альтернативных механизмов ЗУП 3.1:

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

← На главную