В практике разработки на платформе 1С:Предприятие нередко возникает задача автоматического формирования отчетов: когда одна внешняя обработка должна вызвать другой внешний отчет или обработку, передать в него параметры формирования, получить итоговый табличный документ и выгрузить его в файл (например, в формате Excel или PDF). Разберем, как правильно реализовать эту задачу, какие существуют подходы и с какими подводными камнями можно столкнуться.
Проанализируем архитектуру клиент-серверного взаимодействия в управляемом приложении. Открытие визуальной формы отчета для последующего "тихого" сохранения файла в фоновом режиме считается неоптимальным и ресурсоемким решением. Наиболее надежный способ — создание экземпляра внешнего отчета на стороне сервера без привлечения экранных форм.
Для создания объекта отчета или обработки используется менеджер ВнешниеОтчеты или ВнешниеОбработки. Если файл расположен на диске сервера, можно создать объект напрямую методом Создать():
&НаСервере
Процедура СформироватьИСохранитьОтчетНаСервере(ПутьКФайлуОтчета, ЗначениеЛС, ПутьВыгрузки)
// Создаем экземпляр объекта внешнего отчета.
// Второй параметр Ложь отключает безопасный режим, позволяя сохранять файлы на диск.
ОбъектОтчета = ВнешниеОтчеты.Создать(ПутьКФайлуОтчета, Ложь);
// Вызываем экспортную функцию формирования из модуля объекта внешнего отчета
ТабДок = ОбъектОтчета.Сформировать(ЗначениеЛС);
// Сохраняем полученный табличный документ в файл
ТабДок.Записать(ПутьВыгрузки, ТипФайлаТабличногоДокумента.XLSX);
КонецПроцедуры
Обратим внимание на важный нюанс: процедура или функция Сформировать должна быть объявлена в модуле объекта подключаемого отчета с ключевым словом Экспорт:
Функция Сформировать(ЛС) Экспорт
ТабличныйДокумент = Новый ТабличныйДокумент;
// Алгоритм заполнения табличного документа по переданному значению параметра ЛС
// ...
Возврат ТабличныйДокумент;
КонецФункции
Если файл внешнего отчета выбирается на клиенте или передается через сеть в двоичных данных, его сначала необходимо поместить во временное хранилище, а затем зарегистрировать во внешней информационной базе на сервере.
Разберем по шагам клиент-серверный сценарий:
НачатьПомещениеФайла().ВнешниеОтчеты.Подключить(), который возвращает внутреннее имя подключенного отчета.Создать() и выполняем выгрузку.Посмотрим на пример клиентского и серверного кода:
&НаКлиенте
Процедура ЗапуститьФормирование()
АдресХранилища = "";
Оповещение = Новый ОписаниеОповещения("ПослеПомещенияФайла", ЭтотОбъект);
// Помещаем внешнюю обработку во временное хранилище
НачатьПомещениеФайла(Оповещение, АдресХранилища, "\\server\share\Отчет.erf", Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, АдресХранилища, ВыбранноеИмяФайла, ДополнительныеПараметры) Экспорт
Если НЕ Результат Тогда
Возврат;
КонецЕсли;
ПутьДляСохранения = "C:\Reports\Выгрузка.xls";
ПараметрЛС = "00-001234";
ВыполнитьСохранениеНаСервере(АдресХранилища, ПараметрЛС, ПутьДляСохранения);
КонецПроцедуры
&НаСервере
Процедура ВыполнитьСохранениеНаСервере(АдресХранилища, ПараметрЛС, ПутьДляСохранения)
// Подключаем отчет без безопасного режима
ИмяОтчета = ВнешниеОтчеты.Подключить(АдресХранилища, , Ложь);
// Создаем объект по внутреннему имени
ОбъектОтчета = ВнешниеОтчеты.Создать(ИмяОтчета, Ложь);
// Передаем параметры в реквизиты или вызываем метод
ТабДок = ОбъектОтчета.Сформировать(ПараметрЛС);
// Удаляем предыдущую версию файла при необходимости
Файл = Новый Файл(ПутьДляСохранения);
Если Файл.Существует() Тогда
УдалитьФайлы(Файл.Путь, Файл.Имя);
КонецЕсли;
ТабДок.Записать(ПутьДляСохранения, ТипФайлаТабличногоДокумента.XLS);
КонецПроцедуры
Если логика построения отчета жестко привязана к управляемой форме и перенести её в модуль объекта не представляется возможным, форму приходится открывать с передачей параметров. Рассмотрим, как передать параметры при открытии и обработать их.
В вызывающей обработке формируем структуру параметров и передаем её в функцию ПолучитьФорму():
&НаКлиенте
Процедура ОткрытьФормуВнешнегоОтчета(ИмяПодключенногоОтчета)
ПараметрыОткрытия = Новый Структура;
ПараметрыОткрытия.Вставить("АвтоматическийРежим", Истина);
ПараметрыОткрытия.Вставить("ПараметрЛС", "00-001234");
ФормаОтчета = ПолучитьФорму("ВнешнийОтчет." + ИмяПодключенногоОтчета + ".Форма.ФормаОтчетаУправляемая", ПараметрыОткрытия);
ФормаОтчета.Открыть();
КонецПроцедуры
В форме вызываемого внешнего отчета в обработчике ПриСозданииНаСервере выполняем чтение переданных параметров и запуск формирования:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Если Параметры.Свойство("АвтоматическийРежим") И Параметры.АвтоматическийРежим Тогда
ЗначениеЛС = "";
Параметры.Свойство("ПараметрЛС", ЗначениеЛС);
// Формируем табличный документ
ТабДок = СформироватьНаСервере(ЗначениеЛС);
ИмяФайла = "D:\Share\Протокол.xls";
ТабДок.Записать(ИмяФайла, ТипФайлаТабличногоДокумента.XLS);
// Флаг для закрытия формы после открытия на клиенте
ЗакрытьПриОткрытии = Истина;
КонецЕсли;
КонецПроцедуры
Важное предостережение: использование оператора Отказ = Истина в процедуре ПриСозданииНаСервере приведет к ошибке вызова на клиенте. Не следует также вызывать метод ЗавершитьРаботуСистемы(), так как это приведет к полному закрытию программы у пользователя. Для корректного закрытия формы в обработчике ПриОткрытии на клиенте достаточно вызвать стандартный метод ЭтаФорма.Закрыть().
Выясним ключевые технические ограничения, о которых необходимо помнить при реализации:
БезопасныйРежим = Истина. В таком режиме запрещены любые файловые операции на диске. Чтобы метод ТабДок.Записать() не вызывал исключений, при подключении и создании объекта обязательно передавайте значение Ложь в качестве параметра безопасного режима.&НаСервере, работает в файловой системе сервера 1С, а не локального компьютера пользователя. Каталог сохранения должен быть доступен службе сервера 1С на запись.