При разработке внешних печатных форм в системе 1С:Предприятие 8 очень часто возникает задача вывода данных не в стандартный табличный документ, а непосредственно в шаблон офисного документа Microsoft Word (форматы .doc или .docx). Однако при попытке реализовать такую печатную форму в конфигурациях, использующих Библиотеку стандартных подсистем (БСП), разработчики часто сталкиваются с неприятной ошибкой: «В обработчике печати не был сформирован табличный документ для...».
Выясним причину этой ошибки и подробно разберем три различных способа ее решения: от простого обхода системы до реализации печати по современным стандартам БСП без использования нестабильных COM-объектов.
Для того чтобы понять природу проблемы, проанализируем, как работает механизм печати БСП под капотом. Когда пользователь нажимает кнопку печати, подсистема БСП вызывает экспортную процедуру Печать() в модуле нашей внешней обработки.
В эту процедуру в качестве параметров передается специальная таблица — КоллекцияПечатныхФорм. БСП ожидает, что для каждого зарегистрированного макета в этой коллекции разработчик сформирует табличный документ и запишет его в соответствующее поле строки коллекции. Если после выполнения процедуры Печать() система обнаруживает, что колонка ТабличныйДокумент для команды осталась пустой (имеет значение Неопределено), она прерывает выполнение и выводит упомянутое исключение.
Рассмотрим по шагам, как исправить эту ошибку тремя различными методами.
Если вам нужно срочно запустить отчет, а логика заполнения файла Word уже написана через COM-соединение, можно применить простой обходной маневр. Мы просто создадим минимальный или пустой табличный документ и запишем его в коллекцию печатных форм, чтобы подсистема БСП успешно завершила свою проверку.
Рассмотрим пример реализации этого способа в модуле внешней обработки:
Процедура Печать(МассивОбъектов, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// 1. Сначала запускаем вашу процедуру формирования и открытия документа Word
ЗаполнитьИОткрытьДокументWord(МассивОбъектов);
// 2. Находим нашу печатную форму в коллекции БСП
ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ИдентификаторМоейКоманды");
Если ПечатнаяФорма <> Неопределено Тогда
// Создаем пустой табличный документ, чтобы "успокоить" БСП
ТабДок = Новый ТабличныйДокумент;
// Записываем его в коллекцию
ПечатнаяФорма.ТабличныйДокумент = ТабДок;
ПечатнаяФорма.СинонимМакета = "Печать договора Word";
КонецЕсли;
КонецПроцедуры
Вместо поиска строки вручную можно также воспользоваться стандартным методом БСП для вывода табличного документа в коллекцию:
УправлениеПечатью.ВывестиТабличныйДокументВКоллекцию(
КоллекцияПечатныхФорм,
"ИдентификаторМоейКоманды",
"Печать договора Word",
Новый ТабличныйДокумент
);
Этот способ крайне прост в реализации, однако у него есть существенные недостатки: вам все равно приходится создавать лишний объект на сервере, а открытие Word происходит через медленный механизм COM на стороне клиента, что ведет к потенциальным зависаниям процессов.
Начиная с современных версий БСП, фирма «1С» добавила полноценную поддержку офисных документов на уровне платформы. Это позволяет отказаться от нестабильных COM-объектов Word.Application, осуществлять генерацию файлов прямо на сервере (включая сервера под управлением Linux) и корректно передавать готовые двоичные данные клиенту.
Разберем по шагам, как настроить внешнюю обработку по новому стандарту:
.docx.{v8 ИмяПараметра} для одиночных параметров или структурных тегов для областей и таблиц.Печать() заполняйте не свойство ТабличныйДокумент, а специальное свойство ОфисныеДокументы.Посмотрим на пример кода, реализующего этот современный подход:
Процедура Печать(МассивОбъектов, ПараметрыПечати, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
Если УправлениеПечатью.НужноПечататьМакет(КоллекцияПечатныхФорм, "ИдентификаторМоейКоманды") Тогда
ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ИдентификаторМоейКоманды");
Если ПечатнаяФорма <> Неопределено Тогда
// Вызываем функцию формирования структуры файлов Office на сервере
ПечатнаяФорма.ОфисныеДокументы = СформироватьДокументыWordНаСервере(МассивОбъектов);
ПечатнаяФорма.СинонимМакета = "Договор (Word)";
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Функция СформироватьДокументыWordНаСервере должна возвращать Соответствие, где ключом выступает объект печати (ссылка на документ), а значением — двоичные данные сгенерированного файла. Для сборки файлов используются методы общего модуля УправлениеПечатью, работающие с zip-архивом docx-контейнера напрямую.
Если вам критически важно запускать заполнение Word именно на стороне клиента через установленное локальное приложение Microsoft Office и вы не хотите генерировать пустые табличные документы на сервере, есть изящное архитектурное решение. Мы можем изменить режим запуска команды печати.
Проанализируем этот подход. По умолчанию команды печати регистрируются с типом ВызовСерверногоМетода. Но если мы зарегистрируем команду как клиентскую, БСП передаст управление на клиент и вообще не будет проверять наличие табличного документа на сервере!
Для реализации этого способа выполним следующие действия:
СведенияОВнешнейОбработке() для нашей команды указываем тип запуска на клиенте:
// Вместо стандартного ВызовСерверногоМетода указываем ВызовКлиентскогоМетода
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
ВыполнитьКоманду. Обратите внимание, что имя процедуры должно быть именно таким, так как БСП вызывает ее автоматически при активации команды пользователем:
&НаКлиенте
Процедура ВыполнитьКоманду(ИдентификаторКоманды, ОбъектыНазначения) Экспорт
Если ИдентификаторКоманды = "ИдентификаторМоейКоманды" Тогда
// Запускаем заполнение Word непосредственно на компьютере пользователя
ЗаполнитьШаблонНаКлиенте(ОбъектыНазначения);
КонецЕсли;
КонецПроцедуры
При использовании клиентского вызова вся логика работы с COM-объектом (Новый COMОбъект("Word.Application")) безопасно отрабатывает на стороне локальной операционной системы пользователя. При этом серверная часть БСП не участвует в обработке печатного макета, а значит, никаких ошибок об отсутствии табличного документа не возникнет.
Таким образом, мы рассмотрели все три возможных сценария обхода и решения проблемы. Выбор конкретного метода зависит от требований к вашей системе: для простых и быстрых решений подойдет первый способ, для кроссплатформенных надежных систем выбирайте второй способ, а для сохранения сложной клиентской автоматизации Word незаменим третий способ.