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