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