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