Как вывести табличную часть 1С в печатную форму MS Word?

Программист 1С v8.3 (Обычные формы) 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

В этой статье мы подробно разберем несколько практических способов решения этой задачи: от классического копирования областей через буфер обмена до прямого заполнения таблиц через COM-соединение и современных серверных механизмов без использования стороннего ПО.

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

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

Для начала проанализируем разметку шаблона в Word. Нам необходимо пометить строку таблицы специальными тегами:

{v8 Область.СтрокаТЧ} и {/v8 Область.СтрокаТЧ}

Внутри ячеек этой строки мы размещаем параметры для автозамены, например: {НомерСтроки}, {Номенклатура}, {Цена}, {Сумма}.

Рассмотрим код, который выполняет поиск этих областей, их копирование и вставку. Обратите внимание на важный нюанс: при интенсивной работе с буфером обмена Windows операции могут выполняться асинхронно, что иногда приводит к ошибкам заполнения. Мы добавим небольшую программную задержку (так называемый «костыль»), чтобы буфер обмена успевал обновляться.


Функция ПолучитьОбластьМакетаMSWord(Знач Handler, Знач ИмяОбласти, Знач СмещениеНачало = 1, Знач СмещениеОкончание = -1) Экспорт
    Результат = Новый Структура("Document,Start,End");
    ПозицияНачало = СмещениеНачало + ПолучитьПозициюНачалаОбласти(Handler.COMСоединение, ИмяОбласти);
    ПозицияОкончание = СмещениеОкончание + ПолучитьПозициюОкончанияОбласти(Handler.COMСоединение, ИмяОбласти);
    
    Если ПозицияНачало >= ПозицияОкончание Или ПозицияНачало < 0 Тогда
        Возврат Неопределено;
    КонецЕсли;
    
    Результат.Document = Handler.COMСоединение.ActiveDocument;
    Результат.Start = ПозицияНачало;
    Результат.End = ПозицияОкончание;
    Возврат Результат;
КонецФункции

Функция ПолучитьПозициюНачалаОбласти(Знач COMСоединение, Знач ИдентификаторОбласти)
    ИдентификаторОбласти = "{v8 Область." + ИдентификаторОбласти + "}";
    ВесьДокумент = COMСоединение.ActiveDocument.Content;
    ВесьДокумент.Select();
    Поиск = COMСоединение.Selection.Find;
    Поиск.Text = ИдентификаторОбласти;
    Поиск.ClearFormatting();
    Поиск.Forward = Истина;
    Поиск.execute();
    
    Если Поиск.Found Тогда
        Возврат COMСоединение.Selection.End;
    КонецЕсли;
    Возврат -1;
КонецФункции

Функция ПолучитьПозициюОкончанияОбласти(Знач COMСоединение, Знач ИдентификаторОбласти)
    ИдентификаторОбласти = "{/v8 Область." + ИдентификаторОбласти + "}";
    ВесьДокумент = COMСоединение.ActiveDocument.Content;
    ВесьДокумент.Select();
    Поиск = COMСоединение.Selection.Find;
    Поиск.Text = ИдентификаторОбласти;
    Поиск.ClearFormatting();
    Поиск.Forward = Истина;
    Поиск.execute();
    
    Если Поиск.Found Тогда
        Возврат COMСоединение.Selection.Start;
    КонецЕсли;
    Возврат -1;
КонецФункции

Функция ПрисоединитьОбласть(Знач ПечатнаяФорма, Знач ОбластьHandler, Знач ПереходНаСледСтроку = Истина, Знач ПрисоединитьСтрокуТаблицы = Ложь) Экспорт
    // Копируем область шаблона в буфер обмена
    ОбластьHandler.Document.Range(ОбластьHandler.Start, ОбластьHandler.End).Copy();
    
    // Искусственная пауза для синхронизации буфера обмена Windows
    ТекущаяДата = ТекущаяДата();
    ВремяОстановки = ТекущаяДата + 1;
    Пока ТекущаяДата < ВремяОстановки Цикл
        ТекущаяДата = ТекущаяДата();
    КонецЦикла;
    
    ПФ_ActiveDocument = ПечатнаяФорма.COMСоединение.ActiveDocument;
    ПозицияОкончанияДокумента = ПФ_ActiveDocument.Range.End;
    ОбластьВставки = ПФ_ActiveDocument.Range(ПозицияОкончанияДокумента - 1, ПозицияОкончанияДокумента - 1);
    
    Если ПрисоединитьСтрокуТаблицы Тогда
        // Метод вставляет скопированную строку в существующую таблицу
        ОбластьВставки.PasteAppendTable();
    Иначе
        ОбластьВставки.Paste();
    КонецЕсли;
    
    Результат = Новый Структура("Document, Start, End", ПФ_ActiveDocument, ПозицияОкончанияДокумента - 1, ПФ_ActiveDocument.Range.End - 1);
    
    Если ПереходНаСледСтроку Тогда
        // Вставка символа перевода строки, если необходимо
        ПФ_ActiveDocument.Range(ПФ_ActiveDocument.Range.End - 1, ПФ_ActiveDocument.Range.End - 1).InsertParagraphAfter();
    КонецЕсли;
    
    Возврат Результат;
КонецФункции

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

Метод 2. Прямое заполнение таблицы Word через COM (Рекомендуемый и надежный способ)

Выясним причину, почему разработчики часто избегают предыдущего метода. Главный минус работы через буфер обмена — его нестабильность в многопользовательской среде. Чтобы сделать печатную форму максимально надежной, мы можем напрямую обращаться к объектной модели MS Word, добавлять строки в существующую таблицу и записывать данные в конкретные ячейки.

Проанализируем алгоритм работы этого метода:

  1. В макете Word мы заранее создаем таблицу с шапкой и одной пустой строкой, которая будет служить шаблоном оформления (шрифты, границы, выравнивание).
  2. В коде 1С мы находим эту таблицу по ее порядковому номеру или предварительно установленной закладке (Bookmark).
  3. Запускаем цикл по выборке из табличной части документа 1С.
  4. Для каждой строки добавляем новую строку в таблицу Word и заполняем ячейки.
  5. В конце удаляем исходную пустую строку-шаблон, если это необходимо.

Посмотрим на практический пример реализации этого алгоритма:


Процедура ВывестиТабличнуюЧастьНапрямую(ДокументСсылка)
    // Получаем макет из конфигурации
    Макет = ПолучитьМакет("ДоговорСпецификация");
    MsWord = Макет.Получить();
    
    Попытка
        ДокументWord = MsWord.Application.Documents(1);
        ДокументWord.Activate();
        
        // Предположим, что таблица спецификации — первая в документе
        ТаблицаWord = ДокументWord.Tables(1);
        
        // Получаем данные из табличной части документа 1С
        Запрос = Новый Запрос;
        Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);
        Запрос.Текст = 
            "ВЫБРАТЬ
            |   ЗаказТовары.НомерСтроки КАК НомерСтроки,
            |   ЗаказТовары.Номенклатура.Наименование КАК Товар,
            |   ЗаказТовары.Количество КАК Количество,
            |   ЗаказТовары.Цена КАК Цена,
            |   ЗаказТовары.Сумма КАК Сумма
            |ИЗ
            |   Документ.ЗаказПокупателя.Товары КАК ЗаказТовары
            |ГДЕ
            |   ЗаказТовары.Ссылка = &Ссылка";
            
        РезультатЗапроса = Запрос.Выполнить();
        Выборка = РезультатЗапроса.Выбрать();
        
        НомерСтрокиТаблицы = 2; // Первая строка — это шапка таблицы
        
        Пока Выборка.Следующий() Цикл
            // Если это не первая итерация, добавляем новую строку в таблицу Word
            Если НомерСтрокиТаблицы > 2 Тогда
                ТаблицаWord.Rows.Add();
            КонецЕсли;
            
            // Заполняем ячейки добавленной строки данными
            ТаблицаWord.Cell(НомерСтрокиТаблицы, 1).Range.Text = Строка(Выборка.НомерСтроки);
            ТаблицаWord.Cell(НомерСтрокиТаблицы, 2).Range.Text = Выборка.Товар;
            ТаблицаWord.Cell(НомерСтрокиТаблицы, 3).Range.Text = Строка(Выборка.Количество);
            ТаблицаWord.Cell(НомерСтрокиТаблицы, 4).Range.Text = Формат(Выборка.Цена, "ЧЦ=15; ЧДЦ=2");
            ТаблицаWord.Cell(НомерСтрокиТаблицы, 5).Range.Text = Формат(Выборка.Сумма, "ЧЦ=15; ЧДЦ=2");
            
            // Переходим к следующей строке таблицы Word
            НомерСтрокиТаблицы = НомерСтрокиТаблицы + 1;
        КонецЦикла;
        
        MsWord.Application.Visible = Истина;
        
    Исключение
        Сообщить("Произошла ошибка: " + ОписаниеОшибки(), СтатусСообщения.Важное);
        MsWord.Application.Quit();
    КонецПопытки;
КонецПроцедуры

Этот способ работает стабильно, не зависит от состояния системного буфера обмена и гарантирует, что оформление строк (границы, цвет текста) унаследуется от первой шаблонной строки таблицы.

Метод 3. Генерация DOCX файлов на стороне сервера без использования MS Word

Рассмотрим современную альтернативу использованию COM-технологии. Начиная с платформы 8.3.5 и в составе БСП доступен функционал генерации файлов в формате .docx непосредственно на сервере 1С. Это особенно важно, если сервер 1С работает под управлением операционной системы Linux, где запустить MS Word через COM-объект физически невозможно.

При таком подходе макет договора загружается в 1С как двоичные данные (обычный файл .docx). Внутри него табличная часть размечается тегами вида {v8 Область.СтрокаТЧ}. 1С считывает этот файл на сервере как ZIP-архив, парсит XML-структуру (файл word/document.xml) и программно дублирует XML-узлы строк таблицы необходимое количество раз.

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


// Пример использования БСП для формирования печатной формы DOCX
ПараметрыПечати = Новый Структура;
ПараметрыПечати.Вставить("ВыводитьТабличнуюЧасть", Истина);

ДанныеОбъекта = Новый Структура;
ДанныеОбъекта.Вставить("НомерДоговора", Объект.Номер);
ДанныеОбъекта.Вставить("ДатаДоговора", Формат(Объект.Дата, "ДЛФ=DD"));

// Формируем таблицу для вывода
ТаблицаТоваров = Новый ТаблицаЗначений;
ТаблицаТоваров.Колонки.Добавить("НомерСтроки");
ТаблицаТоваров.Колонки.Добавить("Товар");
ТаблицаТоваров.Колонки.Добавить("Количество");
ТаблицаТоваров.Колонки.Добавить("Сумма");

Для Каждого Стр Из Объект.Товары Цикл
    НоваяСтр = ТаблицаТоваров.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтр, Стр);
    НоваяСтр.Товар = Стр.Номенклатура.Наименование;
КонецЦикла;

ДанныеОбъекта.Вставить("ТаблицаТоваров", ТаблицаТоваров);

// Вызов функции генерации печатной формы через подсистему УправлениеПечатью БСП
// МакетOffice - это имя макета с типом ДвоичныеДанные (docx)
АдресХранилищаПечатнойФормы = УправлениеПечатью.СформироватьПечатнуюФормуMsoffice(
    "ДоговорКуплиПродажи", 
    "ДвоичныеДанныеМакета", 
    ДанныеОбъекта
);

Преимущества этого метода неоспоримы: высокая скорость работы (формирование происходит в разы быстрее, чем через COM), полная кроссплатформенность и отсутствие необходимости устанавливать дорогостоящий пакет MS Office на серверную машину.

Метод 4. Обходной путь: генерация HTML-документа с расширением DOC

Если вам требуется максимально быстро решить задачу без написания сложного кода по управлению COM-объектами или XML-структурами, проанализируем самый простой «лайфхак». Мы можем сформировать обычный текстовый документ с HTML-разметкой, вывести таблицу с помощью стандартных тегов <table>, <tr>, <td>, а затем сохранить полученный файл на диск с расширением .doc.

Microsoft Word умеет автоматически распознавать HTML-код внутри файлов с расширением .doc и преобразовывать их в красивый форматированный текст. Для пользователя этот процесс будет абсолютно бесшовным.

Посмотрим на пример реализации такого генератора:


Процедура СформироватьДоговорЧерезHTML(ДокументСсылка)
    // Начинаем сборку HTML-текста договора
    HTML_Текст = "<html><head><meta charset='utf-8'></head><body style='font-family: Arial; font-size: 12pt;'>";
    HTML_Текст = HTML_Текст + "<h2 style='text-align: center;'>ДОГОВОР ПОСТАВКИ № " + ДокументСсылка.Номер + "</h2>";
    HTML_Текст = HTML_Текст + "<p>Ниже представлена спецификация поставляемого оборудования:</p>";
    
    // Строим HTML-таблицу
    HTML_Текст = HTML_Текст + "<table border='1' cellspacing='0' cellpadding='5' style='width: 100%; border-collapse: collapse;'>";
    HTML_Текст = HTML_Текст + "<tr style='background-color: #f2f2f2;'><th>№</th><th>Наименование товара</th><th>Кол-во</th><th>Цена</th><th>Сумма</th></tr>";
    
    Для Каждого СтрокаТЧ Из ДокументСсылка.Товары Цикл
        HTML_Текст = HTML_Текст + "<tr>";
        HTML_Текст = HTML_Текст + "<td style='text-align: center;'>" + СтрокаТЧ.НомерСтроки + "</td>";
        HTML_Текст = HTML_Текст + "<td>" + СтрокаТЧ.Номенклатура.Наименование + "</td>";
        HTML_Текст = HTML_Текст + "<td style='text-align: right;'>" + СтрокаТЧ.Количество + "</td>";
        HTML_Текст = HTML_Текст + "<td style='text-align: right;'>" + СтрокаТЧ.Цена + "</td>";
        HTML_Текст = HTML_Текст + "<td style='text-align: right;'>" + СтрокаТЧ.Сумма + "</td>";
        HTML_Текст = HTML_Текст + "<tr>";
    КонецЦикла;
    
    HTML_Текст = HTML_Текст + "</table>";
    HTML_Текст = HTML_Текст + "</body></html>";
    
    // Записываем полученный текст в файл с расширением .doc
    ПутьКФайлу = КаталогВременныхФайлов() + "Договор_" + СокрЛП(ДокументСсылка.Номер) + ".doc";
    ТекстовыйДокумент = Новый ТекстовыйДокумент;
    ТекстовыйДокумент.УстановитьТекст(HTML_Текст);
    ТекстовыйДокумент.Записать(ПутьКФайлу, КодировкаТекста.UTF8);
    
    // Открываем созданный файл в MS Word на клиенте
    ЗапуститьПриложение(ПутьКФайлу);
КонецПроцедуры

Этот метод невероятно прост в отладке. Вы можете использовать CSS-стили для точной настройки внешнего вида таблицы, изменения цвета заголовков, настройки границ и отступов. При этом вам не нужно изучать сложные свойства COM-объектов MS Word.

Подведем итоги: для старых конфигураций 1С на обычных формах (например, УТ 10.3) лучшим выбором будет прямое заполнение ячеек таблицы Word через COM (Метод 2) или генерация HTML-файла (Метод 4). Для современных конфигураций (ERP, КА 2, БП 3.0) на управляемых формах всегда стоит отдавать приоритет штатным механизмам БСП и серверной сборке файлов DOCX без использования COM-соединений.

← На главную