При разработке различных отчетов, доработке документов или создании механизмов расчета заработной платы в программе «1С:Зарплата и управление персоналом» (редакция 3) часто возникает необходимость оперативно получить норму рабочего времени за определенный месяц. Как правило, ориентироваться нужно на общегосударственный производственный календарь и стандартную 40-часовую рабочую неделю.
В этой статье мы подробно разберем, как устроена структура хранения данных производственных календарей в 1С:ЗУП 3, почему сам справочник ПроизводственныеКалендари не содержит нужных цифр, и какими способами (через запросы или готовые функции БСП) можно быстро решить эту задачу.
Прежде чем переходить к написанию кода, проанализируем структуру метаданных конфигурации. Справочник ПроизводственныеКалендари сам по себе является лишь классификатором. Он хранит только названия календарей (например, «Российская Федерация», региональные календари или календари стран СНГ) и их базовые реквизиты. Непосредственно календарные данные — рабочие, выходные, праздничные и предпраздничные дни — хранятся в подчиненных регистрах сведений.
Для оптимизации расчетов и быстрого извлечения информации разработчики фирмы «1С» предусмотрели два регистра сведений:
РегистрСведений.ДанныеПроизводственногоКалендаря — это подневный регистр. В нем хранится детальная информация по каждому дню каждого календаря (вид дня, перенос выходного и т. д.).РегистрСведений.ДанныеПроизводственногоКалендаряПомесячно — это агрегированный периодический регистр. В нем для каждого месяца уже рассчитаны и сохранены итоговые показатели: количество рабочих дней, а также норма рабочих часов для 40-часовой, 36-часовой и 24-часовой рабочих недель.Давайте рассмотрим несколько практических способов получения нормы часов в зависимости от ваших задач.
Если перед нами стоит задача получить готовую норму часов ровно за один или несколько календарных месяцев, использование регистра ДанныеПроизводственногоКалендаряПомесячно — это самое простое, быстрое и производительное решение.
Рассмотрим структуру запроса, который выбирает норму времени для 40-часовой рабочей недели за конкретный месяц:
ВЫБРАТЬ
КалендарьПомесячно.РабочихЧасовДлительностьНедели40Часов КАК Норма40Часов,
КалендарьПомесячно.РабочихЧасовДлительностьНедели36Часов КАК Норма36Часов,
КалендарьПомесячно.РабочихЧасовДлительностьНедели24Часа КАК Норма24Часа,
КалендарьПомесячно.РабочихДней КАК РабочихДней
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаряПомесячно КАК КалендарьПомесячно
ГДЕ
КалендарьПомесячно.ПроизводственныйКалендарь = &ПроизводственныйКалендарь
И КалендарьПомесячно.Год = &Год
И КалендарьПомесячно.Месяц = &Месяц
Разберем параметры этого запроса подробнее:
&ПроизводственныйКалендарь — ссылка на элемент справочника ПроизводственныеКалендари. Обычно по умолчанию используется предопределенный календарь РФ, который можно получить через код: Справочники.ПроизводственныеКалендари.РФ.&Год — числовой формат года (например, 2024).&Месяц — числовой формат месяца от 1 до 12 (например, 10 для октября).Пример выполнения данного запроса во фрагменте кода на языке 1С:
Функция ПолучитьНормуЧасовЗаМесяц(ВыбранныйМесяц, ВыбранныйКалендарь) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(Календарь.РабочихЧасовДлительностьНедели40Часов, 0) КАК НормаЧасов
|ИЗ
| РегистрСведений.ДанныеПроизводственногоКалендаряПомесячно КАК Календарь
|ГДЕ
| Календарь.ПроизводственныйКалендарь = &Календарь
| И Календарь.Год = &Год
| И Календарь.Месяц = &Месяц";
Запрос.УстановитьПараметр("Календарь", ВыбранныйКалендарь);
Запрос.УстановитьПараметр("Год", Год(ВыбранныйМесяц));
Запрос.УстановитьПараметр("Месяц", Месяц(ВыбранныйМесяц));
УстановитьПривилегированныйРежим(Истина);
Выборка = Запрос.Выполнить().Выбрать();
УстановитьПривилегированныйРежим(Ложь);
Если Выборка.Следующий() Тогда
Возврат Выборка.НормаЧасов;
КонецЕсли;
Возврат 0;
КонецФункции
Иногда возникают ситуации, когда стандартный помесячный регистр не подходит. Например, если вам требуется рассчитать норму часов за нестандартный период (скажем, с 15 октября по 14 ноября) или если в вашей конфигурации по какой-то причине помесячный регистр не заполнен.
В этом случае мы можем самостоятельно рассчитать норму, обратившись к подневному регистру РегистрСведений.ДанныеПроизводственногоКалендаря. Логика расчета базируется на классификации дней в соответствии со значением перечисления Перечисления.ВидыДнейПроизводственногоКалендаря:
Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий) — при 40-часовой неделе равен 8 часам.Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный) — сокращается на 1 час и равен 7 часам.Суббота, Воскресенье, Праздник) — равны 0 часов.Проанализируем пример запроса, который динамически рассчитывает норму часов за любой произвольный период дат:
ВЫБРАТЬ
СУММА(ВЫБОР
КОГДА ДанныеКалендаря.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Рабочий)
ТОГДА 8
КОГДА ДанныеКалендаря.ВидДня = ЗНАЧЕНИЕ(Перечисление.ВидыДнейПроизводственногоКалендаря.Предпраздничный)
ТОГДА 7
ИНАЧЕ 0
КОНЕЦ) КАК НормаЧасов
ИЗ
РегистрСведений.ДанныеПроизводственногоКалендаря КАК ДанныеКалендаря
ГДЕ
ДанныеКалендаря.ПроизводственныйКалендарь = &ПроизводственныйКалендарь
И ДанныеКалендаря.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
Этот способ более гибкий, так как позволяет уйти от жесткой привязки к границам календарного месяца и корректно рассчитывает норму даже для интервалов в несколько дней.
Современные версии 1С:ЗУП 3 построены на базе Библиотеки стандартных подсистем (БСП). Разработчики БСП настоятельно рекомендуют минимизировать количество прямых запросов к системным регистрам и использовать готовые методы общего модуля КалендарныеГрафики. Это гарантирует, что ваш код не сломается при очередном обновлении конфигурации, если фирма «1С» решит изменить структуру или названия регистров.
Для работы с календарями в БСП реализован общий модуль КалендарныеГрафики. Выясним, как с помощью его функций можно получить сведения о нормах времени:
// Получаем таблицу дней за период со всеми свойствами
ТаблицаДней = КалендарныеГрафики.ДанныеПроизводственногоКалендаряЗаПериод(ПроизводственныйКалендарь, ДатаНачала, ДатаОкончания);
// Теперь мы можем программно обойти таблицу и рассчитать норму
НормаЧасов = 0;
Для Каждого СтрокаДня Из ТаблицаДней Цикл
Если СтрокаДня.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Рабочий Тогда
НормаЧасов = НормаЧасов + 8;
ИначеЕсли СтрокаДня.ВидДня = Перечисления.ВидыДнейПроизводственногоКалендаря.Предпраздничный Тогда
НормаЧасов = НормаЧасов + 7;
КонецЕсли;
КонецЦикла;
Использование методов БСП делает программный код чистым, понятным и значительно упрощает последующую поддержку и обновление программного продукта.
При написании логики расчета обязательно помните о том, что в базе данных может использоваться далеко не один производственный календарь. В Российской Федерации, помимо федерального календаря, действуют региональные календари (например, для Республики Татарстан, Башкортостана, Крыма и других субъектов).
В этих регионах объявляются дополнительные нерабочие праздничные дни (например, Ураза-Байрам, Курбан-Байрам, День Республики), из-за чего месячная норма часов будет отличаться от общероссийской.
Поэтому золотое правило разработчика в ЗУП 3: никогда не зашивайте в код жесткий поиск календаря по коду «РФ» или «Российская Федерация», если вы разрабатываете тиражное решение. Всегда получайте производственный календарь динамически:
ПроизводственныйКалендарь).Если вы решаете задачу настройки пересчета оклада в часовую ставку (например, для оплаты ночных или сверхурочных часов) и думаете, как реализовать это программно, спешим вас обрадовать — в ЗУП 3 этот функционал уже встроен и доступен обычным пользователям без программирования.
Выполним настройку по шагам в пользовательском интерфейсе:
После активации этой настройки система при расчете любых начислений, требующих пересчета дневного или месячного оклада сотрудника в часовую ставку, будет автоматически обращаться к описанному нами регистру ДанныеПроизводственногоКалендаряПомесячно, получать оттуда норму часов за текущий месяц по календарю сотрудника и производить точный математический расчет.