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