Как программно получить и проанализировать рабочие часы по графику работы в 1С:ЗУП 2.5?

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

При разработке и кастомизации конфигурации 1С:Зарплата и Управление Персоналом ред. 2.5 (Обычные формы) программисты часто сталкиваются с задачей анализа графиков работы сотрудников. Типичный пример: необходимо программно обойти все даты месяца по определенному графику (например, стандартной пятидневке) и выяснить, какие дни являются рабочими, сколько часов запланировано на конкретную дату и где именно система хранит эти заветные «восьмерки».

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

Где физически хранятся данные графиков работы?

Когда мы открываем элемент справочника ГрафикиРаботы (например, «Пятидневка») и видим на форме заполненную сетку с рабочими часами (те самые «восьмерки»), может возникнуть ошибочное предположение, что эти данные хранятся в самом справочнике — в табличной части или реквизитах. Однако это не так.

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

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

Структура регистра «Графики работы по видам времени»

Для написания корректных запросов проанализируем ключевые измерения и ресурсы этого регистра:

  1. ГрафикРаботы (Измерение) — имеет составной тип данных. Сюда может записываться как ссылка на справочник ГрафикиРаботы, так и ссылка на справочник СотрудникиОрганизаций (в случае использования индивидуальных графиков работы).
  2. Дата (Измерение) — конкретный календарный день, к которому относится запись.
  3. ВидУчетаВремени (Измерение) — тип времени (ссылка на перечисление ВидыУчетаВремени, например: ПоДням, ПоЧасам, Ночные, Вечерние).
  4. План (Измерение) — булево значение. Определяет, плановое это время (график) или фактическое (введенное документом «Табель учета рабочего времени»).
  5. ОсновноеЗначение (Ресурс) — числовое поле, в котором хранится количество часов (или дней, в зависимости от вида учета времени). Это и есть наши «восьмерки».

Важные подводные камни при программной работе с регистром

Прежде чем писать код, разберем ключевые особенности («грабли»), на которые часто наступают начинающие разработчики 1С:

1. Обязательная фильтрация по измерению «План»
В этот же регистр делают движения документы «Табель учета рабочего времени». Если вы не установите в запросе жесткий отбор План = ИСТИНА, вы получите задвоенные данные: система вернет вам и плановые часы по графику, и фактические часы по табелю.

2. Исключение дублирования (Дни vs Часы)
Для каждого рабочего дня система делает в регистр сразу две записи: одну с видом учета времени «По дням» (где значение ресурса равно 1), другую — «По часам» (где значение равно 8). Если просто просуммировать ресурс ОсновноеЗначение за день без отбора по виду учета, вы получите некорректную цифру 9 (8 часов + 1 день). Поэтому в запросе нужно обязательно фильтровать или исключать определенные виды учета времени.

3. Индивидуальные графики сотрудников
Если перед вами стоит задача проанализировать время конкретного сотрудника, нельзя слепо брать его основной график из кадровых документов. В ЗУП 2.5 может быть введен документ «Ввод индивидуальных графиков работы». В этом случае плановые данные для сотрудника будут записаны в этот же регистр, но в измерении ГрафикРаботы будет указана ссылка не на график, а на самого сотрудника из справочника СотрудникиОрганизаций.

Реализация решения: пишем запрос к графику работы

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

Для этого мы отберем записи регистра по нашему графику, установим период, отсечем фактические данные табелей (оставив только План = ИСТИНА) и исключим записи учета времени «По дням».


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

// Устанавливаем параметры запроса
Запрос.УстановитьПараметр("ГрафикРаботы", СсылкаНаГрафик); // Ссылка на справочник ГрафикиРаботы
Запрос.УстановитьПараметр("ДатаНачала", НачалоМесяца(РабочаяДата));
Запрос.УстановитьПараметр("ДатаОкончания", КонецМесяца(РабочаяДата));

РезультатЗапроса = Запрос.Выполнить();

Программная обработка полученных данных

Теперь проанализируем результат запроса в цикле. Нам нужно обойти все дни месяца, определить, где у нас рабочие часы (например, равные 8), а где выходные дни (где записей в регистре для этого дня может вообще не быть или их значение равно 0).

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


ТаблицаЧасов = РезультатЗапроса.Выгрузить();

// Заполняем соответствие для быстрого поиска по дате
СоответствиеГрафика = Новый Соответствие;
Для Каждого Строка Из ТаблицаЧасов Цикл
    СоответствиеГрафика.Вставить(НачалоДня(Строка.Дата), Строка.Часы);
КонецЦикла;

// Обходим все дни анализируемого месяца
ТекущаяДатаОбхода = НачалоМесяца(РабочаяДата);
КонецПериодаОбхода = КонецМесяца(РабочаяДата);

Пока ТекущаяДатаОбхода <= КонецПериодаОбхода Цикл
    
    // Получаем количество запланированных часов на эту дату
    ЧасовНаДату = СоответствиеГрафика.Получить(ТекущаяДатаОбхода);
    
    Если ЧасовНаДату = Неопределено Тогда
        ЧасовНаДату = 0; // Записи в регистре нет, значит это выходной день по графику
    КонецЕсли;
    
    // Выполняем анализ и необходимые действия
    Если ЧасовНаДату = 8 Тогда
        // Разбираем ситуацию, когда это стандартный рабочий день
        Сообщить("Дата " + Формат(ТекущаяДатаОбхода, "ДФ=dd.MM.yyyy") + " - рабочий день (8 часов).");
    ИначеЕсли ЧасовНаДату > 0 Тогда
        // Например, предпраздничный сокращенный день (7 часов)
        Сообщить("Дата " + Формат(ТекущаяДатаОбхода, "ДФ=dd.MM.yyyy") + " - сокращенный рабочий день: " + ЧасовНаДату + " ч.");
    Иначе
        // Выходной или праздничный день
        Сообщить("Дата " + Формат(ТекущаяДатаОбхода, "ДФ=dd.MM.yyyy") + " - выходной день.");
    КонецЕсли;
    
    // Переходим к следующему дню
    ТекущаяДатаОбхода = ТекущаяДатаОбхода + 86400; // Добавляем сутки в секундах
КонецЦикла;

Как учесть индивидуальные графики сотрудников?

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

Проанализируем универсальный алгоритм выбора графика:

  1. Сначала проверяем, введен ли для сотрудника документ «Ввод индивидуального графика работы» на исследуемый месяц. Для этого делаем запрос к регистру ГрафикиРаботыПоВидамВремени, где в качестве измерения ГрафикРаботы передаем ссылку на сотрудника.
  2. Если записи по сотруднику найдены — используем их как приоритетные.
  3. Если записей по сотруднику нет — обращаемся к кадровым данным сотрудника (например, к регистру сведений ПараметрыПериодовРаботыРаботников или ПлановыеНачисленияРаботниковОрганизаций в зависимости от настроек конфигурации), чтобы узнать его основной график работы, и далее выбираем данные уже по этому графику.

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

← На главную