Как программно получить количество рабочих дней и часов за месяц по графику в 1С:ЗУП 3.1

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

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

В этой статье мы подробно разберем несколько практических способов решения данной задачи. Мы изучим прямые запросы к регистрам сведений, проанализируем ключевые ошибки начинающих разработчиков, разберем влияние индивидуальных графиков и рассмотрим наиболее надежный и рекомендуемый фирмой «1С» метод получения данных с помощью встроенного программного API. Для комплексной настройки учета доступен раздел с решениями для подбора переносов данных 1С:ЗУП из других программ.

Метод 1. Простой запрос к регистру «Графики работы по видам времени» и его оптимизация

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

Рассмотрим типовой вариант запроса, который часто пытаются использовать начинающие разработчики, и разберем его критические уязвимости:


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

Давайте детально проанализируем этот код и выясним, почему использовать его в коммерческой разработке категорически не рекомендуется:

  1. Фильтрация по наименованию (ВидУчетаВремени.Наименование = "Явка"): Это классическая ошибка. Если в пользовательском режиме переименовать вид времени «Явка» или запустить данное решение в базе с другой языковой локализацией, запрос перестанет возвращать данные. Вместо текстового сопоставления необходимо использовать обращение к предопределенному элементу справочника через конструкцию ЗНАЧЕНИЕ().
  2. Смешивание дней и часов: В регистре ГрафикиРаботыПоВидамВремени показатели хранятся параллельно в двух измерениях. Для одного и того же дня система записывает как количество часов (с признаком ВремяВЧасах = ИСТИНА), так и количество дней (обычно равное 1, с признаком ВремяВЧасах = ЛОЖЬ). Если мы не установим жесткий фильтр по этому флагу, то при суммировании получим хаотичную цифру, объединяющую и дни, и часы в одну общую сумму.
  3. Выбор между показателями «ОсновноеЗначение» и «ОсновноеЗначениеНорма»: В конфигурации ЗУП 3.1 для сотрудников, работающих на неполной ставке, норма времени может рассчитываться по другому графику (например, по стандартной пятидневке). Если нам требуется получить реальные плановые показатели, которые сотрудник должен отработать по своему графику, нужно использовать поле ОсновноеЗначение. Если же нам нужна норма, которая будет выступать знаменателем при расчете оклада, необходимо обращаться к полю ОсновноеЗначениеНорма.

Теперь, учитывая все вышеперечисленные факторы, напишем корректный и безопасный прямой запрос для раздельного получения дней и часов за указанный месяц:


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

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

Метод 2. Проблема индивидуальных графиков и их влияние на результаты запроса

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

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

Внимание, главный архитектурный подвох: в измерениях этого регистра поле ГрафикРаботы имеет составной тип данных. При записи планового графика туда помещается ссылка на элемент справочника ГрафикиРаботыСотрудников. Но при записи индивидуального графика программа помещает в это измерение ссылку на... самого Сотрудника (справочник Сотрудники)!

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

Чтобы обойти эту проблему в прямом запросе, придется выстраивать сложную логику «ветвления»:

  1. Определить, по каким сотрудникам за выбранный период зарегистрированы записи в регистре, где измерение ГрафикРаботы соответствует ссылке на самого сотрудника.
  2. Если такие записи найдены — брать плановые показатели из них.
  3. Если записей по сотруднику нет — обращаться к его плановому кадровому графику работы.

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

Метод 3. Рекомендуемый подход — использование программного интерфейса (API) ЗУП 3.1

Чтобы избежать написания громоздких запросов, которые могут сломаться при очередном обновлении конфигурации от фирмы «1С», настоятельно рекомендуется использовать готовые методы общих модулей. Для работы с рабочим временем сотрудников предназначен модуль УчетРабочегоВремениРасширенный.

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

Мы воспользуемся методом СоздатьВТДанныеУчетаРабочегоВремениСотрудников. Эта процедура автоматически учитывает:

Посмотрим на пример кода, который подготавливает менеджер временных таблиц и извлекает плановые данные:


// Создаем менеджер временных таблиц для сбора данных
МенеджерВТ = Новый МенеджерВременныхТаблиц;

// Формируем структуру параметров получения данных
ПараметрыПолученияДанных = УчетРабочегоВремениРасширенный.ПараметрыПолученияДанныхУчетаВремени();
ПараметрыПолученияДанных.Период = КонецМесяца(Объект.ПериодРегистрации);
ПараметрыПолученияДанных.ДатаНачала = НачалоМесяца(Объект.ПериодРегистрации);
ПараметрыПолученияДанных.ДатаОкончания = КонецМесяца(Объект.ПериодРегистрации);

// Заполняем массив сотрудников, по которым нужны данные
МассивСотрудников = Новый Массив;
МассивСотрудников.Добавить(ВыбранныйСотрудник);
ПараметрыПолученияДанных.Сотрудники = МассивСотрудников;

// Вызываем метод БСП, который создаст временную таблицу ВТДанныеУчетаРабочегоВремениСотрудников
УчетРабочегоВремениРасширенный.СоздатьВТДанныеУчетаРабочегоВремениСотрудников(
    МенеджерВТ, 
    Истина, 
    ПараметрыПолученияДанных
);

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

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

Пока Выборка.Следующий() Цикл
    Сообщить(Шаблон"Сотрудник: %1 | План дней: %2, План часов: %3", 
        Выборка.Сотрудник, 
        Выборка.ПлановыеДни, 
        Выборка.ПлановыеЧасы);
КонецЦикла;

Рассмотрим детально, почему этот способ является наиболее предпочтительным:

Резюме и рекомендации

Выбор оптимального метода зависит от конкретного контекста решаемой задачи:

  1. Если вам нужно получить плановые показатели внутри отчета на базе СКД (Схемы компоновки данных), то писать запросы вручную также не стоит. Используйте встроенные виртуальные таблицы БСП, такие как Представления.ДанныеОВремениИСостоянииСотрудников.
  2. Если вы пишете алгоритм заполнения документа или обработку заполнения табличной части, используйте связку программного интерфейса БСП из общего модуля УчетРабочегоВремениРасширенный. Это самый чистый, надежный и профессиональный подход.
  3. Прямые запросы к регистру ГрафикиРаботыПоВидамВремени допустимы только в простых сервисных задачах, когда вы гарантированно работаете со статичными графиками работы вне привязки к конкретным сотрудникам и их кадровой истории. При этом всегда помните о разделении данных по полю ВремяВЧасах и правильном обращении к предопределенным видам времени.
← На главную