Как правильно получить графики работы сотрудников по дням в ЗУП 3.1 при смене графика в периоде?

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

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

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

Почему СрезПоследних не подходит для решения задачи

Рассмотрим типичную ситуацию: сотрудник работал по графику «Пятидневка» с 1 по 15 число, а с 16 числа переведен на «Сменный 2/2». Если мы обратимся к виртуальной таблице СрезПоследних, указав дату конца месяца, система вернет нам только «Сменный 2/2». Если мы попытаемся соединить этот результат с данными за весь месяц, норма времени за первую половину месяца будет рассчитана неверно.

Выясним причину: в ЗУП 3.1 архитектура хранения данных о состояниях сотрудников (включая графики) построена на интервальных регистрах. Вместо того чтобы вычислять состояние на каждую дату «на лету», система заранее подготавливает периоды действия тех или иных настроек.

Использование интервальных регистров — правильный путь

Для решения нашей задачи в ЗУП 3.1 предназначен регистр сведений ГрафикРаботыСотрудниковИнтервальный. Его главное преимущество заключается в наличии готовых полей ДатаНачала и ДатаОкончания. Это избавляет нас от необходимости вручную вычислять моменты изменения данных.

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


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

В данном примере мы используем ЛЕВОЕ СОЕДИНЕНИЕ по условию вхождения даты конкретного дня в интервал действия графика. Это гарантирует, что для каждого дня будет выбран именно тот график, который действовал в этот момент.

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

Часто при выполнении подобных запросов пользователи замечают «потерю» последнего дня периода или некорректное отражение данных при бессрочном назначении графика. Рассмотрим важные технические нюансы:

  1. Дата окончания 31.12.3999: В интервальных регистрах открытая дата окончания хранится как 31.12.3999 23:59:59. При использовании условия МЕЖДУ в запросе важно следить, чтобы параметры &ДатаНач и &ДатаКон имели корректное время (начало и конец дня соответственно).
  2. Разность дат: Если вы вычисляете длительность интервала, учитывайте, что разница между началом и концом может составлять неполные сутки в секундах, что иногда приводит к отсечению последнего дня при группировках.
  3. Виды времени: В регистре ГрафикиРаботыПоВидамВремени на одну дату может быть несколько строк (например, Явка и Ночные). Всегда используйте фильтр по ВидУчетаВремени, чтобы не получить завышенную норму часов.

Комплексное решение: Соединение кадровой истории и графиков

Наиболее надежный способ, который учитывает и подразделение сотрудника, и возможные изменения графиков, — это соединение двух интервальных таблиц: КадроваяИсторияСотрудниковИнтервальный и ГрафикРаботыСотрудниковИнтервальный. Посмотрим на практический пример реализации такого запроса:


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

Разберем, что мы здесь сделали. Мы применили перекрестное наложение интервалов кадров и графиков. Это позволяет нам точно знать, в каком подразделении числился сотрудник и какой график у него был в каждую конкретную секунду времени. Флаг ВремяВЧасах = ЛОЖЬ используется для того, чтобы не дублировать данные, если в графике указаны и дни, и часы (в зависимости от настроек регистра).

Дополнительные рекомендации

Для получения максимально точных данных (с учетом праздников и переносов) рекомендуется также выполнять соединение с регистром ДанныеПроизводственногоКалендаря. Это позволит вам фильтровать выходные дни или определять праздничные коэффициенты прямо в запросе, не полагаясь только на заполнение графиков в системе.

Если ваша задача — построение табеля или расчет зарплаты, помните о существовании Индивидуальных графиков. Они имеют наивысший приоритет над общими графиками. Чтобы их учесть, необходимо проверять наличие записей в регистре ДанныеОперативногоУчетаРабочегоВремениСотрудников, который агрегирует все отклонения и индивидуальные планы.

Таким образом, использование интервальных регистров ГрафикРаботыСотрудниковИнтервальный в сочетании с ГрафикиРаботыПоВидамВремени является стандартом для ЗУП 3.1, позволяющим корректно обрабатывать любые изменения в расписании работы сотрудников.

← На главную