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