Почему запрос по работающим физическим лицам в ЗУП 2.5 не сходится с типовым отчетом и как это исправить

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

Когда перед разработчиком встает задача быстро получить список работающих сотрудников (или физических лиц) на определенную дату, первое решение, которое приходит в голову — написать простой запрос к срезу последних регистра сведений РаботникиОрганизаций. Однако при сверке результатов с типовым отчетом "Список сотрудников организаций" часто обнаруживаются расхождения: то количество людей не совпадает, то уволенные сотрудники попадают в список, то не учитываются те, кто принят временно.

В рамках данной статьи мы подробно разберем, где кроются подводные камни кадрового учета в конфигурации "Зарплата и Управление Персоналом, редакция 2.5", проанализируем архитектурные ошибки запросов и соберем оптимальное, быстрое и точное решение, которое будет работать в строгом соответствии с логикой типовых механизмов фирмы 1С.

Различие методологии: физические лица и сотрудники

Прежде чем приступать к написанию запроса, проанализируем ключевое различие между объектами учета. Физические лица (справочник ФизическиеЛица) — это люди как биологические субъекты со своими персональными данными (ИНН, СНИЛС, паспорт, дата рождения). Физические лица не могут "работать" в организации с точки зрения кадрового учета. Работать могут только сотрудники (справочник СотрудникиОрганизаций), которые представляют собой трудовой договор, заключенный с конкретным физическим лицом.

На одно физическое лицо в базе данных может быть заведено несколько карточек сотрудников. Рассмотрим типичные ситуации:

  1. Внутреннее совместительство: Физическое лицо работает по основному месту работы на одной должности, и параллельно оформлено по внутреннему совместительству на другую. Это два разных элемента в справочнике сотрудников, но физическое лицо у них одно и то же.
  2. Повторный прием на работу: Человек уволился из компании, а через полгода вернулся обратно. В ЗУП 2.5 по правилам ведения учета для нового трудового договора создается новый элемент справочника СотрудникиОрганизаций, связанный со старой карточкой физического лица.

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

Главная причина расхождений: механизм "Периода завершения"

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

Выясним причину, как это работает на практике. Если сотрудника приняли на работу временно (например, по срочному трудовому договору), в регистр при проведении документа записывается дата окончания его работы в поле ПериодЗавершения, а в поле ПричинаИзмененияСостоянияЗавершения записывается значение Увольнение. При этом в основном поле ПричинаИзмененияСостояния все еще будет значиться значение ПриемНаРаботу.

Если мы просто напишем стандартное условие отбора работающих сотрудников:


ГДЕ
    РаботникиОрганизацийСрезПоследних.ПричинаИзмененияСостояния <> ЗНАЧЕНИЕ(Перечисление.ПричиныИзмененияСостояния.Увольнение)

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

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


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

Именно эта проверка используется во всех типовых отчетах конфигурации ЗУП 2.5 для корректного отсечения уволенных временных сотрудников.

Проблема отсутствия параметра даты в срезе последних

Еще одна частая ошибка начинающих разработчиков — получение среза последних без передачи конкретной даты в качестве параметра виртуальной таблицы:


РегистрСведений.РаботникиОрганизаций.СрезПоследних(, Сотрудник.Физлицо В (&СписокФизлиц))

Рассмотрим подробнее, почему так делать нельзя. Когда параметр даты (первый параметр виртуальной таблицы) не указан, система 1С формирует запрос на текущий момент времени ("на сейчас"). Кадровики же очень часто заносят документы "будущей датой" (например, приказ об увольнении сотрудника со следующего понедельника оформляют и проводят в пятницу).

Типовой отчет всегда формируется на определенную дату (как правило, на конец дня выбранной даты). Если в вашем запросе нет жесткой привязки к параметру &Период, то при формировании отчета ваши данные будут расходиться с типовым всякий раз, когда в базе присутствуют кадровые приказы, проведенные будущим числом относительно момента запуска вашего отчета.

Оптимизация производительности: убираем подзапросы из виртуальных таблиц

В попытках оптимизировать выборку разработчики иногда помещают тяжелые вложенные запросы прямо в параметры виртуальной таблицы среза последних:


// Пример неоптимального кода
РегистрСведений.РаботникиОрганизаций.СрезПоследних(&Период, Сотрудник.Физлицо В (ВЫБРАТЬ ФизическиеЛица.Ссылка ИЗ Справочник.ФизическиеЛица ГДЕ ...))

Это крайне нерекомендуемый подход с точки зрения стандартов разработки фирмы 1С. Подобные конструкции заставляют СУБД строить неоптимальные планы выполнения запросов, что на больших базах данных с кадровой историей в десятки тысяч сотрудников приводит к серьезным зависаниям системы.

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

Избавляемся от неявных соединений (обращения через "точку")

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

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

Пошаговое построение эталонного запроса

Спроектируем правильный, быстрый и точный запрос для получения работающих физических лиц, отфильтрованных по определенной группе (папке справочника), с получением всех необходимых персональных данных.

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


ВЫБРАТЬ
    ФизическиеЛица.Ссылка КАК Физлицо,
    ФизическиеЛица.ДатаРождения КАК ДатаРождения,
    ФизическиеЛица.МестоРождения КАК МестоРождения,
    ФизическиеЛица.ИНН КАК ИНН,
    ФизическиеЛица.СтраховойНомерПФР КАК СНИЛС
ПОМЕСТИТЬ ВТ_ЦелевыеФизики
ИЗ
    Справочник.ФизическиеЛица КАК ФизическиеЛица
ГДЕ
    ФизическиеЛица.Родитель = &Родитель
    И ФизическиеЛица.ЭтоГруппа = ЛОЖЬ
    И ФизическиеЛица.ПометкаУдаления = ЛОЖЬ

ИНДЕКСИРОВАТЬ ПО
    Физлицо
;

Шаг 2. Получаем актуальные кадровые данные из регистра. На этом этапе мы выбираем последние записи из регистра РаботникиОрганизаций на заданный период времени. Мы связываем виртуальную таблицу с нашей временной таблицей физических лиц, отсекаем уволенных сотрудников с учетом периода завершения и группируем результат, чтобы избежать дублирования по физическим лицам в случае совместительства.


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

ИНДЕКСИРОВАТЬ ПО
    Физлицо
;

Шаг 3. Соединяем результаты и выводим итоговые данные. Теперь нам остается лишь соединить таблицу реально работающих на выбранный период физических лиц с таблицей их персональных данных, полученных на первом шаге. Это обеспечит максимальную производительность, поскольку все тяжелые операции фильтрации и анализа кадрового состояния уже были выполнены ранее.


ВЫБРАТЬ
    ВТ_РаботающиеФизлица.Физлицо КАК ФИО,
    ВТ_ЦелевыеФизики.ДатаРождения КАК ДатаРождения,
    ВТ_ЦелевыеФизики.МестоРождения КАК МестоРождения,
    ВТ_ЦелевыеФизики.ИНН КАК ИНН,
    ВТ_ЦелевыеФизики.СНИЛС КАК СНИЛС
ИЗ
    ВТ_РаботающиеФизлица КАК ВТ_РаботающиеФизлица
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ЦелевыеФизики КАК ВТ_ЦелевыеФизики
        ПО ВТ_РаботающиеФизлица.Физлицо = ВТ_ЦелевыеФизики.Физлицо

Подведем итоги

Мы спроектировали оптимальный и методически верный запрос для конфигурации ЗУП 2.5. Давайте зафиксируем ключевые правила, которые уберегут вас от ошибок при работе с кадровыми данными:

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

← На главную