При разработке интеграционных решений часто возникает задача программного формирования отчетов на стороне сервера 1С с последующей передачей результата во внешние системы через Web-сервисы. Однако разработчики нередко сталкиваются с ситуацией, когда код, успешно работающий во внешней обработке или в обычном сеансе, выдает ошибку "Метод объекта не обнаружен" при вызове через Web-сервис. В этой статье мы подробно разберем, почему это происходит и как правильно организовать генерацию отчетов в серверном контексте.
Рассмотрим ситуацию: у нас есть Web-сервис, который должен принять параметры (код пользователя, имя отчета, настройки), сформировать отчет и вернуть путь к файлу или сами данные. Типичная ошибка заключается в попытке вызвать стандартные процедуры инициализации отчета, такие как УстановитьНачальныеНастройки(), непосредственно из модуля Web-сервиса.
Проанализируем причину сбоя. В конфигурациях, использующих "Универсальный отчет" (например, УПП 1.3, УТП 1.2 или УТ 10.3), многие процедуры в модулях объектов отчетов обернуты в инструкции препроцессора:
#Если Клиент Тогда
Процедура УстановитьНачальныеНастройки() Экспорт
// Код инициализации построителя или настроек
КонецПроцедуры
#КонецЕсли
Когда мы вызываем эту функцию через Web-сервис, код выполняется на сервере (в контексте Server или External Connection). Для сервера методов, находящихся внутри блока #Если Клиент, просто не существует. Именно поэтому система выдает ошибку, несмотря на то что в конфигураторе мы видим эту процедуру как экспортную.
Выясним, можно ли просто убрать инструкции препроцессора. В некоторых случаях — да, но нужно быть осторожными. Если процедура УстановитьНачальныеНастройки() обращается к объектам, доступным только на клиенте (например, к формам или элементам управления), серверный вызов все равно завершится ошибкой.
Рассмотрим правильный алгоритм адаптации:
#Если Клиент Тогда на #Если Клиент Или Сервер Или ВнешнееСоединение Тогда.Если отчет построен на базе СКД, мы можем полностью обойтись без вызова клиентских методов модуля объекта. Это наиболее надежный и современный способ для работы через Web-сервисы. Разберем этот процесс по шагам:
Во-первых, нам необходимо инициализировать схему и настройки без обращения к экранным формам. Посмотрим на пример кода, который можно разместить непосредственно в функции Web-сервиса или в серверном общем модуле:
Функция СформироватьОтчетНаСервере(ИмяОтчета, ИмяНастройки)
ОтчетОбъект = Отчеты[ИмяОтчета].Создать();
СхемаКД = ОтчетОбъект.СхемаКомпоновкиДанных;
// Получаем настройки (из Хранилища или стандартные)
Настройки = ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
// Подготовка макета компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКД, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Инициализация процессора компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// Вывод результата в ТабличныйДокумент
ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат ТабДок;
КонецФункции
Этот подход гарантирует работу кода в любом контексте, так как объекты ПроцессорКомпоновкиДанных и СхемаКомпоновкиДанных являются серверными.
Часто задача требует восстановить настройки, которые пользователь сохранил в интерфейсе. В старых конфигурациях они хранятся в специальных регистрах или системных таблицах. Чтобы получить их на сервере, воспользуемся методом программного восстановления настроек без использования диалоговых окон.
Проанализируем, как это реализовано в БСП (Библиотеке стандартных подсистем). Вместо обращения к УниверсальныеМеханизмы.ПолучитьНастройку(), которые могут дергать клиентский код, лучше использовать прямое чтение из ХранилищеОбщихНастроек или ХранилищеВариантовОтчетов.
// Пример получения настроек СКД из хранилища
КлючОбъекта = "ОтчетОбъект." + ИмяОтчета;
НастройкиПользователя = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта, ИмяНастройки, , ИмяПользователя);
Если НастройкиПользователя <> Неопределено Тогда
ОтчетОбъект.КомпоновщикНастроек.ЗагрузитьНастройки(НастройкиПользователя);
КонецЕсли;
Когда мы формируем отчет на сервере, возникает вопрос: как передать результат клиенту? В исходном сообщении автор возвращает ИмяВременногоФайла. Рассмотрим, почему это плохое решение для Web-сервиса:
Правильный подход: Возвращать двоичные данные файла. Посмотрим, как это реализовать:
// Внутри функции Web-сервиса
ИмяФайла = ПолучитьИмяВременногоФайла("xlsx");
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLSX);
ДанныеФайла = Новый ДвоичныеДанные(ИмяФайла);
// Удаляем временный файл после чтения в память
УдалитьФайлы(ИмяФайла);
// Возвращаем данные (тип возвращаемого значения в WS должен быть base64Binary)
Возврат ДанныеФайла;
Подведем итоги нашего разбора. Для успешного формирования отчетов через Web-соединение необходимо:
Если ваша конфигурация содержит БСП, рекомендуем обратить внимание на подсистему "Варианты отчетов". В ней уже реализованы методы для программного формирования отчетов на сервере, которые учитывают права доступа и корректно работают в фоновых заданиях и веб-сервисах.