При разработке отчетов на системе компоновки данных (СКД) часто возникает необходимость передать в параметры запроса не просто статическое значение или выбор пользователя, а результат вычисления функции. Например, нам нужно найти конкретную статью затрат по ее коду непосредственно в схеме компоновки, не прибегая к написанию кода в модуле отчета. Разберем подробно, как работает этот механизм, какие ошибки часто допускают разработчики и как сделать решение надежным.
В конструкторе схемы компоновки данных существует вкладка Параметры. В колонке Выражение мы можем писать конструкции на языке выражений СКД, которые будут вычисляться перед выполнением запроса. Типичный пример, который мы рассмотрим — получение ссылки на элемент справочника:
Справочники.СтатьиЗатрат.НайтиПоКоду("00-000001")
На первый взгляд кажется, что это обычный встроенный язык 1С, но это не совсем так. Рассмотрим нюансы, из-за которых данные могут "не вставать в компоновку", то есть параметр остается пустым.
Проанализируем ситуацию: выражение написано, синтаксических ошибок нет, но отчет не выводит данные. Выясним основные причины:
Строка, так и Число. Если код числовой, а вы передаете в функцию строку в кавычках (например, "101"), поиск вернет пустую ссылку. Для числового кода выражение должно выглядеть так: Справочники.СтатьиЗатрат.НайтиПоКоду(101).Иногда логика получения параметра сложнее, чем простой поиск. В этом случае мы можем вызвать функцию общего модуля. Разберем, как это сделать правильно, чтобы избежать блокировок системы безопасности.
Во-первых, функция в общем модуле должна быть объявлена с ключевым словом Экспорт. Сам модуль должен иметь установленные флаги Сервер и Вызов сервера. Пример функции в модуле РаботаСОтчетами:
Функция ПолучитьОсновнуюСтатьюЗатрат() Экспорт
Возврат Справочники.СтатьиЗатрат.НайтиПоКоду("000000001");
КонецФункции
В поле выражения параметра СКД мы прописываем вызов:
РаботаСОтчетами.ПолучитьОсновнуюСтатьюЗатрат()
Важный момент: начиная с версии платформы 8.3.15, по умолчанию может быть запрещено выполнение функций встроенного языка в выражениях СКД. Чтобы это работало, при программном выводе отчета необходимо устанавливать настройки расшифровки и проверять права доступа, либо использовать безопасный режим с разрешением вызова конкретных модулей.
Если элемент справочника, который мы ищем, является предопределенным, крайне не рекомендуется использовать НайтиПоКоду. Поиск по коду — это "хрупкое" решение: пользователь может изменить код в режиме предприятия, и отчет сломается. Проанализируем более надежный способ — использование функции ПредопределенноеЗначение.
Это специальная функция языка выражений СКД, которая работает быстрее и надежнее:
ПредопределенноеЗначение("Справочник.СтатьиЗатрат.ПрочиеРасходы")
Такой подход гарантирует, что даже при изменении кода или наименования элемента в базе, отчет продолжит работать корректно, так как привязка идет к внутреннему имени метаданных.
Если вы столкнулись с тем, что параметр не заполняется, воспользуемся проверенным способом отладки без использования конфигуратора:
ТестПараметра.Справочники.СтатьиЗатрат.НайтиПоКоду("00001").Теперь запустим отчет. Если в колонке ТестПараметра мы увидим пустое значение или объект не найден — значит, проблема в самом выражении или в данных (элемент с таким кодом действительно не существует). Если же в колонке ссылка отображается корректно, а параметр в запросе всё равно пустой — стоит проверить настройки самого параметра (флаги "Доступность", "Запрет незаполненных значений" и т.д.).
Если выражения в СКД кажутся вам недостаточно гибкими или их сложно отлаживать, рассмотрим вариант программной установки значений в модуле объекта отчета (в событии ПриКомпоновкеРезультата). Это позволяет добавить проверку на пустые значения и выдать пользователю понятную ошибку.
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Получаем настройки отчета
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
// Ищем параметр по имени
ПараметрСсылка = Настройки.ПараметрыДанных.Элементы.Найти("СтатьяЗатрат");
Если ПараметрСсылка <> Неопределено Тогда
СсылкаНаОбъект = Справочники.СтатьиЗатрат.НайтиПоКоду("00-000001");
Если СсылкаНаОбъект.Пустая() Тогда
Сообщить("Внимание: Статья затрат с кодом 00-000001 не найдена!");
КонецЕсли;
ПараметрСсылка.Значение = СсылкаНаОбъект;
ПараметрСсылка.Использование = Истина;
КонецЕсли;
// Выполняем компоновку
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Этот метод более трудоемкий, но он дает полный контроль над процессом. Однако в большинстве случаев достаточно правильно настроенного выражения на вкладке параметров и внимательной проверки кодов справочников. Для сокращения рутинного кода при таком подходе можно использовать модуль-обёртку СКДБилдер для программного управления компоновкой данных.