Как объединить несколько сгенерированных документов Word в один файл в 1С?

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

При автозаполнении печатных форм в MS Word по списку сотрудников или документов часто возникает проблема: программа генерирует и открывает отдельное окно MS Word на каждого сотрудника. В результате пользователь получает десятки открытых окон вместо одного итогового документа, готового к печати.

Рассмотрим, почему так происходит, и разберем практические варианты объединения всех сформированных макетов в один общий документ средствами 1С и MS Word COM-объекта, а также с использованием Библиотеки стандартных подсистем (БСП).

Почему возникает проблема при заполнении в цикле

Когда вы получаете макет из двоичных данных и вызываете метод Получить() для COM-объекта на каждой итерации цикла, 1С запускает новый экземпляр документа. Если выполнять поиск и замену текста (метод Content.Find.Execute) прямо в открытом шаблоне, исходные текстовые метки (плейсхолдеры вроде <ФИО> или <НомерДоговора>) заменяются на конкретные значения первого сотрудника. При попытке повторно использовать тот же документ для следующего сотрудника заменять становится нечего.

Выясним основные способы решения этой задачи.

Способ 1. Объединение документов через COM-объект и буфер обмена

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

Разберем пример кода с обходом выборки сотрудников и заполнением меток:


// 1. Инициализируем COM-сервер Word и получаем макет
Макет = ПолучитьМакет("МакетРЕГ"); 
MSWord = Макет.Получить();
ДокументWord = MSWord.Application.Documents(1);
ДокументWord.Activate();

// Копируем исходный шаблон в буфер обмена
ДокументWord.Content.Copy();

Индекс = 0;
Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
    Индекс = Индекс + 1;
    
    Если Индекс > 1 Тогда
        // Переходим в конец итогового документа
        ОбластьWord = ДокументWord.Range();
        ОбластьWord.Collapse(0); // wdCollapseEnd = 0
        
        // Вставляем разрыв страницы
        ОбластьWord.InsertBreak(7); // wdPageBreak = 7
        
        // Вставляем копию исходного шаблона из буфера обмена
        ОбластьWord.Paste();
    КонецЕсли;

    // Заполнение параметров в текущем фрагменте или всем документе
    ТекстПоиска = "<номер трудового договора>"; 
    ТекстЗамены = ВыборкаДетальныеЗаписи.НомерДоговора;
    Замена = ДокументWord.Content.Find;
    Замена.Execute(ТекстПоиска, Ложь, Истина, Ложь, , , Истина, , Ложь, ТекстЗамены, 2); // wdReplaceAll = 2
    
    ТекстПоиска = "<фамилия имя отчество сотрудника>"; 
    ТекстЗамены = Строка(ВыборкаДетальныеЗаписи.Физлицо);
    Замена = ДокументWord.Content.Find;
    Замена.Execute(ТекстПоиска, Ложь, Истина, Ложь, , , Истина, , Ложь, ТекстЗамены, 2);
    
    ТекстПоиска = "<адрес по прописке>"; 
    ТекстЗамены = ВыборкаДетальныеЗаписи.ПредставлениеАдреса;
    Замена = ДокументWord.Content.Find;
    Замена.Execute(ТекстПоиска, Ложь, Истина, Ложь, , , Истина, , Ложь, ТекстЗамены, 2);
КонецЦикла;

// Делаем итоговый документ видимым пользователю
ДокументWord.Application.Visible = Истина;
ДокументWord.Activate();

Важное примечание: при замене текста через метод Find.Execute рекомендуется передавать значение 2 в качестве параметра типа замены (Replace), что соответствует константе wdReplaceAll. Это гарантирует, что все совпадающие плейсхолдеры в текущей секции будут заменены с первого раза.

Способ 2. Объединение через временные файлы и InsertFile (надежный COM-способ)

Использование системного буфера обмена (методы Copy и Paste) в частых циклах может приводить к сбоям, если параллельно с работой 1С пользователь копирует другие данные или в системе работают сторонние утилиты. Более стабильным решением является сохранение заполненого документа по каждому сотруднику во временный файл и подгрузка файлов в общий документ через метод MS Word InsertFile.

Рассмотрим пошаговый алгоритм этого способа:

  1. Создаем главный документ Word, который станет итоговым файлом.
  2. В цикле открываем шаблон, заполняем мета-данные конкретного сотрудника через Find.Execute.
  3. Сохраняем заполненный индивидуальный документ во временную папку с помощью SaveAs и закрываем его.
  4. В главном документе перемещаем курсор в конец (метод Collapse), вставляем разрыв страницы (или разрыв раздела wdSectionBreakNextPage, если у документов разная ориентация страниц) и вызываем метод InsertFile(ПутьКФайлу).
  5. Удаляем временные файлы с диска после формирования.

Способ 3. Использование типовых функций Библиотеки стандартных подсистем (БСП)

Если ваша конфигурация построена на базе БСП (например, «1С:Зарплата и Управление Персоналом», «1С:ERP» или «1С:Комплексная автоматизация»), рекомендуется использовать штатный модуль УправлениеПечатьюКлиент. Это избавляет от необходимости вручную писать вызовы COM-объектов и работать с низкоуровневыми командами MS Word.

Посмотрим на пример формирования печатной формы через БСП:


// Двоичные данные макета
ДвоичныеДанныеМакета = ПолучитьМакет("МакетРЕГ");

// Инициализация макета офисного документа
Макет = УправлениеПечатьюКлиент.ИнициализироватьМакетОфисногоДокумента(ДвоичныеДанныеМакета, "DOC", "ПФ_Договор");

// Подготовка структуры печатной формы
ПечатнаяФорма = УправлениеПечатьюКлиент.ИнициализироватьПечатнуюФормуОфисногоДокумента("DOC", Макет.Настройки, Макет);

// Получаем области
ОбластьШапка = УправлениеПечатьюКлиент.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти", "Документ", "Общая"));
ОбластьРазрыв = УправлениеПечатьюКлиент.ОбластьМакета(Макет, Новый Структура("ИмяОбласти, ТипОбласти", "Разрыв", "Общая"));

Индекс = 0;
Пока Выборка.Следующий() Цикл
    Индекс = Индекс + 1;
    
    Если Индекс > 1 Тогда
        // Добавляем разрыв между документами сотрудников
        УправлениеПечатьюКлиент.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьРазрыв, Новый Структура, Ложь);
    КонецЕсли;
    
    // Подготовка структуры заполнения параметров
    ДанныеЗаполнения = Новый Структура;
    ДанныеЗаполнения.Вставить("НомерДоговора", Выборка.НомерДоговора);
    ДанныеЗаполнения.Вставить("ФИО", Выборка.ФизлицоПредставление);
    ДанныеЗаполнения.Вставить("ПаспортныеДанные", Выборка.Паспорт);
    
    // Присоединение области с заполнением плейсхолдеров
    УправлениеПечатьюКлиент.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, ОбластьШапка, ДанныеЗаполнения, Ложь);
КонецЦикла;

// Вывод итогового файла пользователю
УправлениеПечатьюКлиент.ПоказатьДокумент(ПечатнаяФорма);
УправлениеПечатьюКлиент.ОчиститьСсылки(ПечатнаяФорма);

Для автоматического получения всех параметров, заложенных в макете DOCX, в БСП можно воспользоваться функцией УправлениеПечатью.ПараметрыМакета() (или УправлениеПечатьюКлиент.ПараметрыМакета()). Она сканирует файл и возвращает массив найденных имен плейсхолдеров.

Рекомендации по выбору технологии

  1. БСП (УправлениеПечатьюКлиент): Оптимальный выбор для современных конфигураций 1С 8.3. Код получается компактным, кроссплатформенным и не зависящим напрямую от установленных версий MS Office.
  2. COM-объект через InsertFile: Подходит при отсутствии БСП в старых конфигурациях или самописных системах, когда требуется объединить сложную верстку с сохранением стилей колонтитулов и фоновых изображений.
  3. Переход на Табличный документ (MXL): Если нет жесткой необходимости выдавать файл именно в формате `.docx`, целесообразно сверстать макет средствами 1С (Табличный документ). Формирование реестра договоров через `Секция` и `ВывестиГоризонтальныйРазрывСтраницы()` выполняется в разы быстрее, работает на стороне сервера под любой ОС и легко сохраняется в PDF или DOCX.
← На главную