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