Разработка внешних печатных форм в среде 1С:Предприятие 8.3 — одна из самых частых задач программиста. Использование шаблонов Microsoft Word (файлов формата docx) позволяет создавать красивые, легко редактируемые договоры, соглашения и акты. Однако при интеграции таких форм в типовые конфигурации, работающие на базе Библиотеки стандартных подсистем (БСП), разработчики часто сталкиваются с неприятным поведением системы. Программа успешно формирует и открывает документ Word, но сразу после этого выдает ошибку: «Поле объекта не обнаружено (КоличествоЭкземпляров)».
В этой статье мы подробно разберем, почему возникает данная ошибка, как работает механизм вывода печатных форм в БСП и какими способами можно обойти это ограничение — от простых «костылей» до правильного современного использования механизмов БСП без привлечения COM-объектов.
Давайте проанализируем, что происходит в недрах БСП, когда мы нажимаем кнопку «Печать». Стандартный механизм БСП спроектирован в первую очередь для работы с объектом ТабличныйДокумент (стандартный печатный лист 1С). Системные модули печати ожидают, что результатом выполнения процедуры печати будет коллекция печатных форм, содержащая именно табличные документы.
Когда управление возвращается в общий модуль БСП, система пытается настроить параметры печати для полученных макетов. В коде это выглядит примерно так:
ПечатнаяФорма.ТабличныйДокумент.КоличествоЭкземпляров = ПечатнаяФорма.Экземпляров;
Если в качестве печатной формы мы передали COM-объект Word (или структуру, в которой вместо табличного документа находится ссылка на приложение Word), БСП пытается обратиться к свойству КоличествоЭкземпляров у этого объекта. Разумеется, у COM-объекта Microsoft Word такого свойства нет, из-за чего платформа генерирует исключение и аварийно завершает работу обработчика печати.
Если же мы вообще ничего не возвращаем в структуру печатных форм, БСП выдает другую ошибку — о том, что печатная форма не была сформирована вовсе.
Ниже мы рассмотрим три способа решения этой проблемы.
Это самое быстрое и простое решение, которое обсуждалось на форуме. Оно идеально подходит, если ваша печатная форма уже написана с использованием COM-объекта Word.Application, отлично работает, и вам нужно лишь избавиться от назойливой ошибки БСП, не переписывая весь код генерации файла.
Суть метода заключается в том, чтобы обмануть БСП: мы формируем и открываем документ Word самостоятельно через COM, а в вызывающую процедуру БСП возвращаем абсолютно чистый, пустой объект ТабличныйДокумент. Система видит, что документ возвращен, успешно считывает у него свойство КоличествоЭкземпляров и завершает работу без ошибок.
Рассмотрим пример реализации этого обхода в модуле внешней печатной формы:
Процедура Печать(МассивОбъектовНазначения, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// 1. Находим нужную строку в коллекции печатных форм
ПараметрыПечати = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ИдентификаторВашейКоманды");
Если ПараметрыПечати <> Неопределено Тогда
// 2. Запускаем наш собственный алгоритм генерации Word через COM
СформироватьИОткрытьДокументWord(МассивОбъектовНазначения);
// 3. Создаем "заглушку" - пустой табличный документ
ТабДокЗаглушка = Новый ТабличныйДокумент;
// Передаем заглушку в параметры печати, чтобы БСП успокоилась
ПараметрыПечати.ТабличныйДокумент = ТабДокЗаглушка;
ПараметрыПечати.СинонимМакета = "Договор в формате Word";
КонецЕсли;
КонецПроцедуры
Плюсы метода: простота внедрения, минимальные изменения в существующем коде.
Минусы метода: у пользователя на долю секунды может мелькать пустое окно предварительного просмотра 1С (хотя при правильной настройке параметров вывода этого можно избежать). Кроме того, сохраняются все недостатки работы с COM-объектами.
Если мы регистрируем внешнюю обработку в справочнике «Дополнительные отчеты и обработки» с видом «Печатная форма», БСП жестко контролирует возвращаемые типы данных. Но мы можем пойти другим путем.
Если в сведениях о внешней обработке (функция СведенияОВнешнейОбработке) указать вид «Заполнение объекта» или «Дополнительная обработка», то БСП не будет ожидать возврата табличного документа. В таком сценарии мы можем повесить формирование Word-документа прямо на команду выполнения обработки.
Однако здесь есть важный нюанс, о котором упоминали участники форума: стандартную печатную форму пользователь привык видеть в меню «Печать» конкретного документа. Если зарегистрировать ее как «Дополнительную обработку», она появится в меню «Заполнение» или в кнопке «Дополнительные обработки», что может быть не совсем интуитивно для конечных пользователей.
Использование COM-технологии (Новый COMОбъект("Word.Application")) в современных реалиях считается устаревшим подходом и «плохим тоном» разработки. Оно имеет критические недостатки:
winword.exe часто «зависают» в памяти сервера, забивая оперативную память и снижая производительность системы.Современные версии БСП (начиная с версии 3.0) предоставляют мощный штатный механизм для работы с офисными документами напрямую, без использования COM. Документ формируется на сервере путем работы с XML-структурой zip-архива docx. Для этого используется встроенное свойство структуры печатной формы — ОфисныеДокументы.
Давайте разберем по шагам, как реализовать этот современный подход:
Шаг 1. Подготовка шаблона. Создайте обычный документ в MS Word (docx). Вместо заполняемых полей вставьте параметры в фигурных скобках, например: {v8 НомерДоговора}, {v8 ДатаДоговора}. Сохраните файл и загрузите его во внешнюю обработку как макет с типом Двоичные данные. По стандартам БСП имя макета должно начинаться префиксом ПФ_DOC_.
Шаг 2. Код формирования документа. В процедуре печати мы используем программный интерфейс общего модуля УправлениеПечатью. Мы инициализируем макет, заполняем параметры и помещаем готовый файл во временное хранилище 1С. Адрес этого хранилища мы передаем в специальное соответствие ОфисныеДокументы.
Посмотрим на пример правильного кода:
Процедура Печать(МассивОбъектовНазначения, КоллекцияПечатныхФорм, ОбъектыПечати, ПараметрыВывода) Экспорт
// Получаем пустую структуру для нашей печатной формы
ПечатнаяФорма = УправлениеПечатью.СведенияОПечатнойФорме(КоллекцияПечатныхФорм, "ИдентификаторКоманды");
// БСП все еще требует инициализации ТабличногоДокумента (оставляем пустой как заглушку)
ПечатнаяФорма.ТабличныйДокумент = Новый ТабличныйДокумент;
// Создаем соответствие для хранения двоичных данных файлов Word
ОфисныеДокументы = Новый Соответствие;
Для Каждого СсылкаИзМассива Из МассивОбъектовНазначения Цикл
// 1. Получаем двоичные данные нашего макета-шаблона .docx
ДвоичныеДанныеМакета = ПолучитьМакет("ПФ_DOC_Договор");
// 2. Инициализируем макет средствами БСП
Макет = УправлениеПечатью.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, Неопределено);
// 3. Создаем объект печатной формы
ПечатнаяФормаWord = УправлениеПечатью.ИнициализироватьПечатнуюФорму(Неопределено, Макет.НастройкиСтраницыМакета, Макет);
// 4. Описываем области шаблона
СтруктураОбластей = Новый Структура;
УправлениеПечатью.ДобавитьОписаниеОбласти(СтруктураОбластей, "ТелоДоговора", "Общая");
// 5. Заполняем параметры данными из информационной базы 1С
ДанныеЗаполнения = Новый Структура;
ДанныеЗаполнения.Вставить("НомерДоговора", СсылкаИзМассива.Номер);
ДанныеЗаполнения.Вставить("ДатаДоговора", Формат(СсылкаИзМассива.Дата, "ДЛФ=DD"));
ДанныеЗаполнения.Вставить("Контрагент", Строка(СсылкаИзМассива.Контрагент));
ОбластьТело = УправлениеПечатью.ОбластьМакета(Макет, СтруктураОбластей.ТелоДоговора);
УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФормаWord, ОбластьТело, ДанныеЗаполнения);
// 6. Получаем адрес сформированного docx-файла во временном хранилище
АдресХранилища = УправлениеПечатью.СформироватьДокумент(ПечатнаяФормаWord);
// 7. Помещаем файл в соответствие (АдресХранилища - ключ, ИмяФайла - значение)
ИмяФайла = "Договор_" + СокрЛП(СсылкаИзМассива.Номер) + ".docx";
ОфисныеДокументы.Вставить(АдресХранилища, ИмяФайла);
// Очищаем занятые ресурсы сервера
УправлениеПечатью.ОчиститьСсылки(ПечатнаяФормаWord);
УправлениеПечатью.ОчиститьСсылки(Макет);
КонецЦикла;
// Передаем коллекцию готовых файлов Word в БСП
ПечатнаяФорма.ОфисныеДокументы = ОфисныеДокументы;
КонецПроцедуры
При использовании этого метода БСП видит заполненное свойство ОфисныеДокументы, понимает, что печать производится в офисный формат, автоматически скачивает временный файл на клиентский компьютер и открывает его в локальном текстовом редакторе пользователя (MS Word, LibreOffice, OpenOffice, в зависимости от того, что установлено по умолчанию для файлов .docx).
При этом никаких ошибок о количестве экземпляров не возникает, а на экране 1С не открываются пустые раздражающие окна просмотра табличных документов!
Мы рассмотрели три способа борьбы с ошибкой инициализации реквизитов печатной формы БСП. Если вам нужно быстро исправить старый код, используйте Способ 1 с возвратом пустого табличного документа в качестве заглушки. Если вы проектируете новую печатную форму под современную конфигурацию 1С, настоятельно рекомендуем использовать Способ 3 — это спасет вас от проблем производительности COM-соединений, обеспечит стабильную работу на веб-клиенте и под операционными системами семейства Linux.