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