Как распечатать документ Word, подставив параметры из 1С?

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При формировании печатных форм договоров, коммерческих предложений и соглашений разработчики часто сталкиваются с необходимостью сохранить сложное исходное форматирование документа. Переносить многостраничный текст в табличный документ 1С вручную долго и трудоемко, а макет типа ActiveDocument нередко вызывает трудности при программном заполнении и может работать медленно. Разберем по шагам, как правильно подготовить шаблон в Microsoft Word, загрузить его в конфигурацию 1С, быстро заполнить реквизитами из базы данных и отправить на печать.

Подготовка шаблона договора в Microsoft Word

Прежде чем приступать к написанию кода в 1С, подготовим файл шаблона. Существует два основных способа разметки мест для вставки данных:

  1. Текстовые маркеры-заполнители. В нужных местах документа вставляем уникальные строковые комбинации, которых нет в обычном тексте, например: [НомерДоговора], [ДатаДоговора], [НаименованиеКонтрагента]. Этот способ наиболее прост и нагляден.
  2. Переменные документа (DocVariable) или поля. В Word через меню «Вставка» — «Экспресс-блоки» — «Поле» создается специальное поле типа DocVariable с уникальным именем. Значение такого поля можно изменять напрямую через коллекцию переменных объекта Word.
  3. Закладки (Bookmarks). В местах подстановки создаются закладки Word, к которым впоследствии можно обращаться по имени через объектную модель.

Хранение шаблона в конфигурации: почему лучше использовать «Двоичные данные»

Макет типа ActiveDocument напрямую интегрируется с COM-сервером Word при обращении через метод Получить(). Однако такой подход часто приводит к длительным задержкам инициализации интерфейса и зависаниям. Оптимальным решением является использование макета с типом Двоичные данные или хранение файла в реквизите с типом ХранилищеЗначения.

Выясним причину ошибки: объект ДвоичныеДанные не имеет метода Получить(). Чтобы открыть такой документ в Word, его необходимо сначала выгрузить во временный файл на диске с помощью метода Записать().

Решение 1. Заполнение документа методом поиска и замены через COM

Рассмотрим классический и надежный алгоритм: извлекаем двоичные данные шаблона, сохраняем их во временный файл, открываем файл в фоновом режиме через COMОбъект("Word.Application"), заменяем ключевые текстовые метки на актуальные данные и отправляем документ на печать.


// 1. Получаем макет двоичных данных и записываем во временный файл
МакетДвоичныеДанные = ПолучитьМакет("МакетДоговор");
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("docx");
МакетДвоичныеДанные.Записать(ИмяВременногоФайла);

// 2. Инициализируем COM-соединение с приложением Word
Попытка
    MSWord = Новый COMОбъект("Word.Application");
Исключение
    Сообщить("Не удалось запустить Microsoft Word: " + ОписаниеОшибки());
    Возврат;
КонецПопытки;

Попытка
    // Открываем документ в невидимом фоновом режиме
    MSWord.Application.Visible = Ложь;
    Документ = MSWord.Documents.Open(ИмяВременногоФайла);
    
    // 3. Выполняем поиск и замену маркеров
    Замена = Документ.Content.Find;
    
    НаименованиеКонтрагента = "ООО ""Торгуем всем""";
    НомерДоговора = "№ 128/24";
    
    // Заменяем номер договора
    Замена.Execute("[НомерДоговора]", Ложь, Истина, Ложь, , , Истина, , Ложь, НомерДоговора, 2);
    
    // Заменяем контрагента
    Замена.Execute("[НаименованиеКонтрагента]", Ложь, Истина, Ложь, , , Истина, , Ложь, НаименованиеКонтрагента, 2);
    
    // 4. Отправляем на печать или открываем пользователю
    ПечататьНаПринтер = Истина;
    
    Если ПечататьНаПринтер Тогда
        // Отправка сразу на принтер по умолчанию
        Документ.PrintOut();
        // Даем время спулеру печати принять задание перед закрытием
        Документ.Close(Ложь);
        MSWord.Quit();
    Иначе
        // Отображаем заполненный документ пользователю
        MSWord.Application.Visible = Истина;
        MSWord.Activate();
    КонецЕсли;

Исключение
    Сообщить("Ошибка при обработке документа: " + ОписаниеОшибки());
    MSWord.Quit(Ложь);
КонецПопытки;

// Удаляем временный файл при необходимости
УдалитьФайлы(ИмяВременногоФайла);

Обратите внимание на последний параметр метода Find.Execute — значение 2 (константа wdReplaceAll), которое предписывает заменить сразу все вхождения маркера в документе.

Решение 2. Подстановка через переменные документа (Variables)

Проанализируем второй вариант, когда в шаблоне Word используются поля типа DocVariable. Этот подход удобен тем, что в шаблоне визуально не отображаются служебные скобки.


// Задаем значения переменным документа
Документ.Variables("Контрагент").Value = "ООО ""Торгуем всем""";
Документ.Variables("ИНН").Value = "7701234567";
Документ.Variables("Сумма").Value = "150 000 руб.";

// Обязательно обновляем поля документа, иначе новые значения не отобразятся на листах
Документ.Fields.Update();

Важный нюанс: при изменении свойства Variables("Имя").Value значение в тексте документа не перерисовывается само по себе. Обязательно вызывайте Документ.Fields.Update(), чтобы обновить все поля перед печатью.

Решение 3. Быстрая замена через закладки (Bookmarks)

Если в документе много реквизитов, сквозной поиск по всему тексту методом Find.Execute может занять ощутимое время. Быстрее всего работает прямая подстановка в предварительно расставленные закладки:


Если Документ.Bookmarks.Exists("Контрагент") Тогда
    Документ.Bookmarks("Контрагент").Range.Text = "ООО ""Торгуем всем""";
КонецЕсли;

Причины медленной работы Word и сбоев при перехвате фокуса

Разберем типичные проблемы, упомянутые в обсуждении, и способы их решения:

  1. Зависание на строке открытия файла (30–60 секунд). Word при инициализации и открытии файла обращается к драйверу принтера по умолчанию, чтобы пересчитать макет страниц. Если системный принтер по умолчанию является сетевым, выключен или недоступен, Word ждет таймаута сети. Назначение локального виртуального принтера (например, Microsoft Print to PDF) принтером по умолчанию полностью решает проблему зависания.
  2. Ошибки при переключении окон (Skype, браузер и т.д.). Ошибка возникает, если в коде вызываются методы Activate() или интерактивный объект Selection. Если другое приложение перехватывает фокус операционной системы, интерактивная работа завершается аварийно. Для стабильной работы в фоне следует манипулировать объектом Range (например, Документ.Content) и избегать вызова Activate() до момента, пока документ не сформирован окончательно.
  3. Ограничение длины строки в 255 символов при поиске и замене. Метод Find.Execute в Word COM не принимает строковые параметры длиной более 255 символов. Если реквизит (например, полный юридический адрес с реквизитами банка) превышает этот лимит, вставляйте его через закладки или разбивайте на несколько параметров.
  4. Завершение работы процесса. В блоке Исключение всегда вызывайте MSWord.Quit(Ложь), чтобы в диспетчере задач Windows не накапливались зависшие фоновые процессы WINWORD.EXE.
← На главную