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