При работе с типовыми конфигурациями (в частности, «Управление торговлей» и ее локализациями) пользователи могут столкнуться с ситуацией, когда отчет «Ведомость по товарам на складах в ценах номенклатуры» или аналогичный отчет по остаткам перестает формироваться, выдавая исключение с сообщением: «Некорректный текст запроса». При этом отчет в конфигурации может быть совершенно не изменен, а в демонстрационной базе формироваться без каких-либо ошибок. Разберем детально, почему это происходит и какими способами можно устранить проблему.
Проанализируем программный код модуля отчета, в котором генерируется ошибка. Для адаптации текста запроса под различные функциональные опции разработчики нередко используют динамическую модификацию текста схемы компоновки данных (СКД).
Посмотрим на пример типового фрагмента, вызывающего сбой:
СхемаКомпоновкиДанных = Отчеты.ВедомостьПоТоварамНаСкладахВЦенахНоменклатуры.ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
ТекстЗапроса = СхемаКомпоновкиДанных.НаборыДанных[0].Запрос;
ЗаменяемыйТекст =
" ВЫБОР
| КОГДА ЦеныНоменклатурыА.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
| ИЛИ ЕСТЬNULL(ЦеныНоменклатурыА.Упаковка.Коэффициент, 0) = 0
| ТОГДА ЦеныНоменклатурыА.Цена
| ИНАЧЕ ЦеныНоменклатурыА.Цена / ЦеныНоменклатурыА.Упаковка.Коэффициент
| КОНЕЦ КАК Цена,
| ВЫБОР
| КОГДА ЦеныНоменклатурыБ.Цена ЕСТЬ NULL
| ТОГДА 0
| КОГДА ЦеныНоменклатурыБ.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
| ИЛИ ЕСТЬNULL(ЦеныНоменклатурыБ.Упаковка.Коэффициент, 0) = 0
| ТОГДА ЦеныНоменклатурыБ.Цена
| ИНАЧЕ ЦеныНоменклатурыБ.Цена / ЦеныНоменклатурыБ.Упаковка.Коэффициент
| КОНЕЦ КАК СтараяЦена,
| ВЫБОР
| КОГДА ЦеныНоменклатурыА.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
| ИЛИ ЕСТЬNULL(ЦеныНоменклатурыА.Упаковка.Коэффициент, 0) = 0
| ТОГДА ЦеныНоменклатурыА.Цена
| ИНАЧЕ ЦеныНоменклатурыА.Цена / ЦеныНоменклатурыА.Упаковка.Коэффициент
| КОНЕЦ - ВЫБОР
| КОГДА ЦеныНоменклатурыБ.Цена ЕСТЬ NULL
| ТОГДА 0
| КОГДА ЦеныНоменклатурыБ.Упаковка = ЗНАЧЕНИЕ(Справочник.УпаковкиНоменклатуры.ПустаяСсылка)
| ИЛИ ЕСТЬNULL(ЦеныНоменклатурыБ.Упаковка.Коэффициент, 0) = 0
| ТОГДА ЦеныНоменклатурыБ.Цена
| ИНАЧЕ ЦеныНоменклатурыБ.Цена / ЦеныНоменклатурыБ.Упаковка.Коэффициент
| КОНЕЦ КАК Дельта";
Если Найти(ТекстЗапроса, ЗаменяемыйТекст) = 0 Тогда
ВызватьИсключение НСтр("ru='Некорректный текст запроса';uk='Некоректний текст запиту'");
КонецЕсли;
Рассмотрим, почему условие Если Найти(ТекстЗапроса, ЗаменяемыйТекст) = 0 возвращает истину и инициирует исключение:
УпаковкиНоменклатуры. Если опция включена, алгоритм идет по другой ветке, и блок проверки с заменой вовсе не выполняется (именно поэтому в демо-базе с включенными упаковками ошибка не воспроизводится).НаборыДанных[0].Запрос. Любое минимальное отличие (лишний пробел, табуляция, разница в символах переноса строки CRLF и LF, либо результат пересохранения запроса конструктором СКД) приводит к тому, что функция Найти() возвращает 0.Если требуется восстановить работоспособность базы немедленно и без доработок конфигурации, воспользуемся изменением параметров учета:
При включенной опции алгоритм перестает заходить в проблемную ветку кода с поиском текста, и отчет успешно строится.
Если опцию упаковок включать не требуется, устраним причину ошибки непосредственно в логике работы отчета. Разберем по шагам варианты исправления:
ОсновнаяСхемаКомпоновкиДанных отчета, перейдем в набор данных Запрос, скопируем фактический блок выражений полей Цена, СтараяЦена, Дельта и вставим его в строковую переменную ЗаменяемыйТекст модуля отчета.ВызватьИсключение, выполняя замену безопасным образом через СтрЗаменить().Если основная конфигурация находится на полной поддержке поставщика, наиболее удобным решением будет временное подключение внешнего отчета:
.erf).ЗаменяемыйТекст, чтобы он посимвольно совпадал с запросом из схемы.Проанализируем, почему подход с жестким поиском текста через Найти() и СтрЗаменить() является уязвимым. Любое открытие схемы компоновки данных в графическом конструкторе автоматически форматирует текст запроса по внутренним правилам платформы, изменяя отступы. В результате любые жестко заданные строки в коде перестают совпадать с запросом в схеме.
Для реализации логики, зависящей от настроек или опций, рекомендуется использовать:
КомпоновщикНастроек без прямого вмешательства в текст исходного запроса.//{БЛОК_ЦЕН_НАЧАЛО} ... //{БЛОК_ЦЕН_КОНЕЦ}), что исключает зависимость от пробелов и форматирования полей.