При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с необходимостью вычисления различных показателей «на лету». Одним из классических примеров является вывод признака в пользовательском или вычисляемом поле на основе сравнения реквизита с конкретным значением справочника. Например, нам нужно установить флаг или вывести единицу, если результатом осмотра животного является «Брак».
Однако при написании формул в СКД легко запутаться в синтаксисе. Платформа 1С:Предприятие использует несколько различных языков в рамках одного отчета: язык запросов, встроенный язык 1С и язык выражений СКД. Ошибки в их смешивании приводят к непонятным предупреждениям системы, таким как «Поле не найдено» или «Ожидается ключевое слово "Тогда"». В этой статье мы подробно разберем, почему возникают эти ошибки, чем отличается синтаксис в разных частях СКД и как правильно решать подобные задачи.
Рассмотрим выражение, которое изначально пытался использовать разработчик:
Выбор
Когда РезультатОсмотра = Значение(Справочник.РезультатыОсмотра.Наименование.Брак)
Тогда 1
Иначе 0
Конец
При попытке сохранить такое выражение система выдает ошибку «Поле не найдено». Давайте проанализируем ситуацию и выясним причину ее возникновения.
Конструкция Значение() (или ЗНАЧЕНИЕ() в верхнем регистре) в языке запросов предназначена для получения ссылок на предопределенные элементы, значения перечислений, пустые ссылки или точки системных перечислений. Главное правило этой конструкции — в скобках должен быть указан строгий и прямой путь к метаданным предопределенного элемента, заданный в конфигураторе.
В ошибочном примере была предпринята попытка обратиться к реквизиту наименования через точку: .Наименование.Брак. Парсер запросов не понимает такого обращения. Он ожидает увидеть имя предопределенного элемента, а не обращение к физическим полям таблицы БД. Если в справочнике РезультатыОсмотра создан предопределенный элемент с именем Брак, то правильный синтаксис обращения к нему в запросе будет выглядеть следующим образом:
Значение(Справочник.РезультатыОсмотра.Брак)
Обратите внимание, что здесь нет кавычек, и мы не обращаемся к наименованию или коду. Мы получаем непосредственно ссылку на сам предопределенный элемент базы данных.
В процессе обсуждения возникла еще одна показательная ошибка при попытке обойти ограничение:
Выбор
Когда РезультатОсмотра = Справочники.рав_РезультатыОсмотра["Брак"]
Тогда 1
Иначе 0
Конец
Данный код вызывает ошибку парсера: «Ожидается ключевое слово "Тогда"» (или «Ожидается ключевое слово "Конец"»). Почему так происходит?
Дело в том, что Язык выражений СКД — это не встроенный язык 1С. Это отдельный декларативный язык со своими правилами и ограничениями. В выражениях пользовательских или вычисляемых полей компоновки данных нельзя использовать конструкции типа Справочники.ИмяСправочника[...], Документы.ИмяДокумента или квадратные скобки для получения элементов по индексу или имени. Парсер СКД просто не понимает эти объекты, спотыкается на них и выдает синтаксическую ошибку в самом неожиданном месте (например, жалуясь на отсутствие слова Тогда).
Для успешной работы в СКД крайне важно разделять, где именно вы пишете выражение сравнения: в самом тексте запроса или на вкладках вычисляемых/пользовательских полей.
Используем классическую конструкцию языка запросов без кавычек:
ЗНАЧЕНИЕ(Справочник.РезультатыОсмотра.Брак)
В самом интерфейсе схемы компоновки данных для получения предопределенных элементов используются встроенные системные функции СКД. Путь к элементу в этом случае обязательно передается в виде строки в кавычках:
ПредопределенноеЗначение("Справочник.РезультатыОсмотра.Брак")
или сокращенный вариант:
Значение("Справочник.РезультатыОсмотра.Брак")
Если в вычисляемом поле написать путь без кавычек (как в запросе), СКД воспримет это как обращение к полям набора данных и сообщит об ошибке.
В рассматриваемом примере все значения справочника были предопределенными, что значительно упростило задачу. Однако на практике структура данных может быть иной, и нужный элемент может быть создан пользователем непосредственно в режиме «1С:Предприятие». В таком случае функции Значение() и ПредопределенноеЗначение() использовать не получится. Рассмотрим три надежных альтернативных варианта решения этой проблемы.
Этот способ является наиболее гибким и профессиональным, так как не привязывает логику отчета к жесткому коду конфигурации.
Разберем реализацию по шагам:
&РезультатБрак.СправочникСсылка.РезультатыОсмотра.
Выбор
Когда РезультатОсмотра = &РезультатБрак Тогда 1
Иначе 0
Конец
Сам параметр мы можем заполнить несколькими способами. Например, предоставить пользователю возможность самостоятельно выбрать значение в настройках отчета. Если же параметр должен быть заполнен строго определенным элементом по умолчанию, мы можем сделать это программно в модуле объекта отчета в процедуре ПриКомпоновкеРезультата:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Получаем настройки отчета
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Ищем нужный параметр
ПараметрБрак = Настройки.ПараметрыДанных.Элементы.Найти("РезультатБрак");
Если ПараметрБрак <> Неопределено Тогда
// Находим элемент справочника по уникальному коду или иному признаку
СсылкаНаБрак = Справочники.РезультатыОсмотра.НайтиПоКоду("000000001");
ПараметрБрак.Значение = СсылкаНаБрак;
ПараметрБрак.Использование = Истина;
КонецЕсли;
// Применяем настройки обратно в компоновщик
КомпоновщикНастроек.ЗагрузитьНастройки(Настройки);
КонецПроцедуры
Если в вашей конфигурации часто требуется обращаться к конкретным элементам справочников, хорошей практикой будет создание специальной экспортной функции в общем модуле.
Предположим, у нас есть общий модуль РаботаСПроверками с установленными свойствами «Вызов сервера» и «Клиент (управляемое приложение)». Напишем в нем функцию:
Функция ПолучитьСсылкаНаБрак() Экспорт
Возврат Справочники.РезультатыОсмотра.НайтиПоРеквизиту("Код", "000000001");
КонецФункции
Теперь мы можем напрямую вызвать эту функцию в выражении пользовательского или вычисляемого поля СКД:
Выбор
Когда РезультатОсмотра = РаботаСПроверками.ПолучитьСсылкаНаБрак() Тогда 1
Иначе 0
Конец
Этот метод позволяет централизованно управлять получением конкретных ссылок. Если код элемента в базе данных изменится, вам потребуется исправить его только в одном месте — в общем модуле, не переписывая настройки множества отчетов.
В крайних случаях, когда нет возможности использовать параметры или общие модули, можно прибегнуть к прямому сравнению по текстовому реквизиту (коду или наименованию):
Выбор
Когда РезультатОсмотра.Код = "000000001" Тогда 1
Иначе 0
Конец
Важное предупреждение: Данный метод считается плохим стилем разработки. Если пользователь в режиме предприятия изменит код элемента справочника или его наименование, логика отчета мгновенно сломается, и отчет перестанет выводить правильные данные. Используйте этот подход только в самых безвыходных ситуациях или при полной уверенности в неизменности данных.
Мы подробно разобрали особенности работы с выражениями СКД при обращении к справочникам. Для успешного решения подобных задач всегда определяйте тип элементов справочника (предопределенные или пользовательские) и место написания выражения (запрос или поля СКД). Правильное разграничение этих понятий позволит вам писать чистый, надежный и быстродействующий код без синтаксических ошибок.