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