При разработке отчетов или выгрузок в 1С:Зарплата и управление персоналом 3.1 (ЗУП) программисты часто сталкиваются с тем, что стандартные запросы к срезу последних регистра сведений КадроваяИсторияСотрудников выдают некорректные данные. Типичная ситуация: сотрудник был временно переведен в другое подразделение, срок перевода истек, и он вернулся на основное место работы. Однако в регистре последней записью остается именно этот временный перевод, из-за чего отчет показывает неактуальное место работы. Разберем подробно, как решить эту задачу правильно и получить точные данные для выгрузки в CSV.
Проанализируем, почему обычный подход через виртуальную таблицу СрезПоследних не работает. В системе 1С:ЗУП 3.1 кадровые события записываются последовательно. При временном переводе создается запись с указанием нового подразделения. Когда срок перевода заканчивается, система методологически предполагает «возврат», но в обычном регистре сведений не всегда автоматически появляется новая запись «текущей датой», если не было проведено новое кадровое событие. В итоге СрезПоследних просто находит хронологически последнюю запись, которая может быть уже не актуальна по срокам действия.
Выясним, какой инструмент разработчики 1С предусмотрели для решения этой проблемы. В конфигурации существуют специальные вспомогательные регистры с суффиксом «Интервальный». Для нашей задачи идеально подходит КадроваяИсторияСотрудниковИнтервальный. В отличие от базового регистра, здесь каждая запись имеет четкие границы: ДатаНачала и ДатаОкончания.
Рассмотрим структуру запроса к этому регистру. Чтобы получить актуальное подразделение на нужную нам дату (например, на сегодня), нам не нужен срез последних. Нам нужно найти запись, в интервал которой попадает искомая дата.
ВЫБРАТЬ
КадроваяИстория.Подразделение КАК Подразделение,
КОЛИЧЕСТВО(РАЗЛИЧНЫЕ КадроваяИстория.Сотрудник) КАК КоличествоСотрудников
ИЗ
РегистрСведений.КадроваяИсторияСотрудниковИнтервальный КАК КадроваяИстория
ГДЕ
КадроваяИстория.ДатаНачала <= &ДатаСреза
И КадроваяИстория.ДатаОкончания >= &ДатаСреза
И КадроваяИстория.Сотрудник.ПометкаУдаления = ЛОЖЬ
СГРУППИРОВАТЬ ПО
КадроваяИстория.Подразделение
Важно помнить про нюанс со временем: в ЗУП кадровые события могут фиксироваться с точностью до секунд (например, 00:00:05 или 00:00:20). Чтобы не «потерять» сотрудника, всегда используйте в параметре &ДатаСреза конец дня или ту конкретную точку времени, которую использует система для актуализации кадровых данных.
Посмотрим на ситуацию шире. Если вы пишете код во внешней обработке, наиболее надежным и методологически верным способом будет использование встроенных функций ЗУП. В типовом решении есть модуль КадровыйУчет, который содержит мощные инструменты для подготовки временных таблиц. Метод СоздатьВТКадровыеДанныеСотрудников самостоятельно учитывает все нюансы: временные переводы, подработки, совмещения и даже исправления документов.
Разберем по шагам, как использовать этот механизм в коде для подготовки данных к выгрузке:
// 1. Подготовка менеджера и параметров
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;
// 2. Формирование временной таблицы с кадровыми данными
// Метод сам выберет нужные регистры и обработает временные переводы
КадровыйУчет.СоздатьВТКадровыеДанныеСотрудников(
МенеджерВТ,
Истина, // Признак формирования таблицы
ПараметрыПолученияДанных // Здесь указываем Дату и нужные поля (Подразделение)
);
// 3. Итоговый запрос для агрегации
Запрос.Текст =
"ВЫБРАТЬ
| ВТКадровыеДанные.Подразделение КАК Подразделение,
| КОЛИЧЕСТВО(ВТКадровыеДанные.Сотрудник) КАК Количество
|ИЗ
| ВТКадровыеДанныеСотрудников КАК ВТКадровыеДанные
|СГРУППИРОВАТЬ ПО
| ВТКадровыеДанные.Подразделение";
РезультатЗапроса = Запрос.Выполнить();
Этот способ гарантирует, что ваша «тыква» не превратится в карету (и наоборот) после очередного обновления конфигурации, так как вы используете официальный программный интерфейс вендора.
Проанализируем важный методологический момент. В ЗУП 3.1 у одного физического лица может быть несколько карточек Сотрудник (основное место работы, внутреннее совместительство, подработка). Если ваша задача — выгрузить количество «физических лиц» по подразделениям, то группировать данные нужно не по полю Сотрудник, а по полю ФизическоеЛицо.
Кроме того, обратите внимание на следующие фильтры в запросе:
ВидЗанятости).ГоловнойСотрудник.Рассмотрим ситуацию: вам нужно выгрузить в CSV все подразделения организации, даже если в них сейчас никто не работает. Если вы будете строить запрос только по регистру кадровой истории, пустые подразделения просто не попадут в выборку.
Для решения этой задачи необходимо строить запрос от справочника ПодразделенияОрганизаций и использовать ЛЕВОЕ СОЕДИНЕНИЕ с таблицей кадровых данных. В этом случае в колонке количества для пустых подразделений вы получите NULL, который легко заменить на 0 с помощью функции ЕСТЬNULL.
ВЫБРАТЬ
Подразделения.Ссылка КАК ПодразделениеНаименование,
ЕСТЬNULL(ДанныеКадров.Количество, 0) КАК КоличествоСотрудников
ИЗ
Справочник.ПодразделенияОрганизаций КАК Подразделения
ЛЕВОЕ СОЕДИНЕНИЕ (
// Здесь ваш вложенный запрос или ВТ с подсчетом сотрудников
) КАК ДанныеКадров
ПО Подразделения.Ссылка = ДанныеКадров.Подразделение
ГДЕ
Подразделения.ПометкаУдаления = ЛОЖЬ
После того как мы получили таблицу результатов запроса, нам необходимо сформировать текстовый файл в формате CSV. Проанализируем простую схему реализации:
ТекстCSV = Новый ТекстовыйДокумент;
ТекстCSV.ДобавитьСтроку("Подразделение;Количество");
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
СтрокаДляЗаписи = Строка(Выборка.ПодразделениеНаименование) + ";" + Формат(Выборка.КоличествоСотрудников, "ЧГ=0");
ТекстCSV.ДобавитьСтроку(СтрокаДляЗаписи);
КонецЦикла;
ТекстCSV.Записать("C:\Export\EmployeesCount.csv", КодировкаТекста.ANSI);
Используя предложенные методы — особенно работу с интервальными регистрами и программными методами модуля КадровыйУчет — вы сможете создать надежный инструмент для выгрузки, который будет корректно обрабатывать даже самые сложные случаи временных перемещений сотрудников в 1С:ЗУП 3.1.