Переход на управляемое приложение в «1С:Предприятии 8.3» часто вызывает трудности у начинающих разработчиков. Типичный сценарий: создается внешняя обработка, в нее добавляется макет печатной формы, пишется код вывода, но при попытке печати платформа выдает различные ошибки. Самые популярные из них — это «Недопустимое значение параметра 1» при вызове функции РеквизитФормыВЗначение() и ошибки, связанные с попыткой отобразить печатную форму непосредственно на сервере.
В этой статье мы подробно разберем, почему возникают эти ошибки, как устроена работа с контекстами клиента и сервера при печати из внешних обработок, а также рассмотрим несколько рабочих способов решения этой задачи.
Для начала проанализируем, почему код автора из первого сообщения темы не работал. Автор пытался выполнить следующий код на сервере:
&НаСервере
Функция ПолучитьМакетНаСервере
Возврат РеквизитФормыВЗначение("Макет").ПолучитьМакет("Макет");
КонецФункции
Здесь кроется первая критическая ошибка. Функция РеквизитФормыВЗначение() предназначена для преобразования реквизита управляемой формы в прикладной объект базы данных или обработки. На управляемой форме нет реквизита с именем «Макет». Основным реквизитом управляемой формы внешней обработки является Объект (имеющий тип ДанныеФормыСтруктура). Именно его и нужно конвертировать в реальный объект внешней обработки, чтобы получить доступ к его модулю, свойствам и макетам.
Вторая ошибка автора заключалась в попытке вызвать метод Показать() на сервере:
&НаСервере
Процедура ПечатьНаСервере
// ... формирование табличного документа ...
ТабличныйДокумент.Показать(Строка(ТО.Ссылка)); // Ошибка!
КонецПроцедуры
Метод Показать() объекта ТабличныйДокумент отвечает за интерактивное отображение формы с табличным документом на экране пользователя. Сервер «1С:Предприятия» работает в фоновом режиме и не имеет визуального интерфейса. Любые попытки вызвать диалоговые окна, предупреждения или методы отображения форм (такие как Показать() или Открыть()) на сервере неизбежно приведут к аварийному завершению работы программы.
---
Рассмотрим самый простой, элегантный и современный способ вывода печатной формы. Объект ТабличныйДокумент является сериализуемым. Это означает, что его можно без проблем передать из серверного контекста в клиентский в качестве возвращаемого значения функции.
Разберем этот алгоритм по шагам:
Объект в прикладной объект обработки, получаем макет, заполняем области данными и возвращаем готовый табличный документ на клиент.Показать().Вот как выглядит правильный и рабочий код реализации этого способа:
&НаКлиенте
Процедура Печать(Команда)
// Получаем заполненный табличный документ с сервера
ТабличныйДокумент = СформироватьТабличныйДокументНаСервере();
// Показываем документ пользователю (метод доступен только на клиенте)
ТабличныйДокумент.Показать("Печать макета внешней обработки");
КонецПроцедуры
&НаСервере
Функция СформироватьТабличныйДокументНаСервере()
ТабличныйДокумент = Новый ТабличныйДокумент;
// Конвертируем данные формы в прикладной объект внешней обработки
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
// Получаем макет, принадлежащий этому объекту
Макет = ОбработкаОбъект.ПолучитьМакет("Макет");
// Получаем область "Шапка" из макета
Шапка = Макет.ПолучитьОбласть("Шапка");
// Заполняем параметры области, если они есть
// Например, если в макете есть параметр "СсылкаНаДокумент"
// Шапка.Параметры.СсылкаНаДокумент = Объект.ДокументСсылка;
// Выводим область в итоговый табличный документ
ТабличныйДокумент.Вывести(Шапка);
Возврат ТабличныйДокумент;
КонецФункции
---
Этот способ часто применяется в сложных системах или при работе в неконтекстных вызовах &НаСервереБезКонтекста. Если табличный документ содержит тысячи строк, картинок и диаграмм, передавать его напрямую между клиентом и сервером «в лоб» может быть неэффективно с точки зрения расхода оперативной памяти. В таких случаях используется механизм временного хранилища платформы.
Давайте проанализируем, как работает данный подход:
ПоместитьВоВременноеХранилище(). Данный метод возвращает уникальный адрес (строку) во временном хранилище.ТабличныйДокумент с помощью функции ПолучитьИзВременногоХранилища().Показать().Реализуем этот вариант в коде:
&НаКлиенте
Процедура ПечатьЧерезХранилище(Команда)
// Инициализируем уникальный идентификатор формы для привязки хранилища
АдресХранилища = "";
// Формируем документ на сервере и получаем адрес его размещения
АдресХранилища = СформироватьДокументВХранилищеНаСервере();
Если Не ПустаяСтрока(АдресХранилища) Тогда
// Извлекаем табличный документ на клиенте
ТабличныйДокумент = ПолучитьИзВременногоХранилища(АдресХранилища);
ТабличныйДокумент.Показать("Печать через временное хранилище");
КонецЕсли;
КонецПроцедуры
&НаСервере
Функция СформироватьДокументВХранилищеНаСервере()
ТабличныйДокумент = Новый ТабличныйДокумент;
// Получаем объект внешней обработки для работы с макетом
ОбработкаОбъект = РеквизитФормыВЗначение("Объект");
Макет = ОбработкаОбъект.ПолучитьМакет("Макет");
Шапка = Макет.ПолучитьОбласть("Шапка");
ТабличныйДокумент.Вывести(Шапка);
// Помещаем во временное хранилище, привязывая к уникальному идентификатору формы
Адрес = ПоместитьВоВременноеХранилище(ТабличныйДокумент, УникальныйИдентификатор);
Возврат Адрес;
КонецФункции
---
При изучении материалов форума важно уметь отсеивать неверные или устаревшие решения. Рассмотрим Сообщение 8, в котором пользователю предлагают следующий вариант:
&НаСервереБезКонтекста
Функция ПолучитьМакетНаСервере()
ОбработкаОбъект = Новый ("ВнешняяОбработкаОбъект.ИмяМоейОбработки");
Возврат ОбработкаОбъект.ПолучитьМакет("Макет");
КонецФункции
Внимание: этот код содержит грубую ошибку и работать не будет!
Конструкция Новый ("ВнешняяОбработкаОбъект.Имя...") синтаксически не поддерживается платформой 1С:Предприятие. Создание объекта внешней обработки программным путем на сервере возможно только через менеджер внешних обработок. Правильный вариант выглядел бы так:
ОбработкаОбъект = ВнешниеОбработки.Создать(ПутьКФайлуОбработки, Ложь);
Однако этот способ крайне неудобен для практического применения, так как серверу потребуется знать точный физический путь к файлу обработки .epf на диске (который в клиент-серверном варианте работы вообще может находиться на компьютере пользователя, а не на сервере приложений). Поэтому контекстный вызов &НаСервере и использование функции РеквизитФормыВЗначение("Объект") — это самый простой, надежный и отказоустойчивый путь получения макета из открытой формы внешней обработки.
---
В современной коммерческой разработке (будь то ERP, Управление торговлей, Бухгалтерия предприятия или ЗУП) практически никогда не создают собственные уникальные формы с кнопками печати внутри внешних обработок. Вместо этого используется механизм Дополнительных отчетов и обработок, входящий в состав БСП (Библиотеки Стандартных Подсистем).
Если вы хотите разрабатывать решения профессионально, рекомендуем отказаться от создания собственных форм для печати макетов. Вместо этого настройте вашу внешнюю обработку как внешнюю печатную форму (ВПФ) для БСП:
СведенияОВнешнейОбработке(), которая регистрирует обработку в системе и указывает, для каких документов она предназначена.Печать() со стандартной сигнатурой БСП.При интеграции такой обработки в информационную базу кнопка печати вашего макета автоматически появится в стандартном подменю «Печать» целевого документа. БСП сама возьмет на себя открытие формы предпросмотра, отправку печатной формы по электронной почте, сохранение в форматы PDF/Excel и вывод на принтер, избавив вас от необходимости писать лишний код интерфейса.