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