При разработке корпоративных систем на базе 1С:Предприятие 8.3 часто возникает задача формирования сложных печатных форм, таких как трудовые договоры, дополнительные соглашения или приказы, где требуется строгое соответствие разметке Microsoft Word. Стандартные табличные документы 1С не всегда удобны для этих целей, поэтому использование ActiveDocument или шаблонов Word через COM-соединение становится оптимальным решением.
В этой статье мы подробно разберем, как превратить обычную обработку во внешнюю печатную форму, как правильно извлекать данные из справочников (например, «Сотрудники» или «Физические лица») и как программно заполнять поля в документе Word.
Чтобы ваша обработка появилась в меню «Печать» справочника или документа, она должна соответствовать требованиям Библиотеки стандартных подсистем (БСП). Рассмотрим, что необходимо добавить в Модуль объекта внешней обработки. Выясним, что ключевым звеном является функция СведенияОВнешнейОбработке().
Проанализируем структуру этой функции:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиПечатнаяФорма();
ПараметрыРегистрации.Назначение.Добавить("Справочник.Сотрудники"); // Указываем объект привязки
ПараметрыРегистрации.Наименование = "Трудовой договор (Word)";
ПараметрыРегистрации.БезопасныйРежим = Ложь;
ПараметрыРегистрации.Версия = "1.0";
НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
НоваяКоманда.Представление = "Сформировать трудовой договор";
НоваяКоманда.Идентификатор = "ПечатьТрудовогоДоговора";
НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовКлиентскогоМетода();
НоваяКоманда.ПоказыватьОповещение = Истина;
Возврат ПараметрыРегистрации;
КонецФункции
Важно: Обратите внимание на ТипКомандыВызовКлиентскогоМетода. Поскольку работа с COM-объектом Word возможна только на стороне клиента (где установлен Microsoft Office), мы должны инициировать процесс именно с клиентской стороны.
Перед тем как открывать Word, нам необходимо собрать все данные из информационной базы. Рассмотрим пример запроса, который извлекает сведения о сотруднике, его паспортных данных, окладе и контактной информации. Мы будем использовать левые соединения, чтобы корректно обработать ситуации, когда некоторые данные (например, ИНН или СНИЛС) могут отсутствовать.
&НаСервере
Функция ПолучитьДанныеДляПечати(СсылкаНаОбъект)
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ПриемНаРаботу.Сотрудник КАК Сотрудник,
| ПриемНаРаботу.ТрудовойДоговорНомер КАК НомерДоговора,
| ПриемНаРаботу.ТрудовойДоговорДата КАК ДатаДоговора,
| ДокументыФизическихЛиц.Представление КАК ПаспортныеДанные,
| ФизЛицо.ИНН КАК ИНН,
| ФизЛицо.СтраховойНомерПФР КАК СНИЛС,
| ПриемНаРаботу.Должность.Наименование КАК Должность,
| ПриемНаРаботу.ДолжностьПоШтатномуРасписанию.ОкладТариф КАК Оклад
|ИЗ
| Документ.ПриемНаРаботу КАК ПриемНаРаботу
| ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ДокументыФизическихЛиц.СрезПоследних КАК ДокументыФизическихЛиц
| ПО ПриемНаРаботу.Сотрудник.ФизическоеЛицо = ДокументыФизическихЛиц.Физлицо
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.ФизическиеЛица КАК ФизЛицо
| ПО ПриемНаРаботу.Сотрудник.ФизическоеЛицо = ФизЛицо.Ссылка
|ГДЕ
| ПриемНаРаботу.Сотрудник = &Сотрудник";
Запрос.УстановитьПараметр("Сотрудник", СсылкаНаОбъект);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Разберем по шагам алгоритм взаимодействия 1С и Word. Основная проблема часто заключается в передаче файла макета из конфигурации на диск пользователя. Мы используем временное хранилище для передачи двоичных данных макета с сервера на клиент, а затем сохраняем их во временный файл.
Рассмотрим клиентскую процедуру СобратьМакет:
ActiveDocument с сервера.ПолучитьИмяВременногоФайла("doc") для создания пути.Новый COMОбъект("Word.Application").Fields в документе.
&НаКлиенте
Процедура СобратьМакет(СсылкаНаОбъект)
// 1. Получаем макет во временное хранилище
АдресМакета = ПолучитьМакетНаСервере();
ДанныеМакета = ПолучитьИзВременногоХранилища(АдресМакета);
// 2. Сохраняем на диск
ИмяФайла = ПолучитьИмяВременногоФайла("doc");
ДанныеМакета.Записать(ИмяФайла);
// 3. Запускаем Word
Попытка
WordПриложение = Новый COMОбъект("Word.Application");
Исключение
Сообщить("MS Word не установлен!");
Возврат;
КонецПопытки;
Документ = WordПриложение.Documents.Open(ИмяФайла);
WordПриложение.Visible = Истина;
// 4. Получаем данные из 1С
ТаблицаДанных = ПолучитьДанныеДляПечати(СсылкаНаОбъект);
Если ТаблицаДанных.Количество() = 0 Тогда Возврат; КонецЕсли;
Данные = ТаблицаДанных[0];
// 5. Заполнение полей MERGEFIELD
Для Каждого Поле Из Документ.Fields Цикл
КодПоля = Поле.Code.Text;
Если Найти(КодПоля, "MERGEFIELD") > 0 Тогда
// Извлекаем имя поля, отсекая лишние символы
ИмяПоля = СокрЛП(СтрЗаменить(СтрЗаменить(КодПоля, "MERGEFIELD", ""), "\* MERGEFORMAT", ""));
ЗначениеДляЗамены = "";
Если ИмяПоля = "НомерДоговора" Тогда
ЗначениеДляЗамены = Данные.НомерДоговора;
ИначеЕсли ИмяПоля = "Оклад" Тогда
ЗначениеДляЗамены = Формат(Данные.Оклад, "ЧЦ=15; ЧДЦ=2");
КонецЕсли;
Если ЗначениеДляЗамены <> "" Тогда
Поле.Select();
WordПриложение.Selection.TypeText(Строка(ЗначениеДляЗамены));
КонецЕсли;
КонецЕсли;
КонецЦикла;
Документ.Activate();
КонецПроцедуры
Проанализируем ситуацию, описанную пользователем: почему макет может отображаться «неправильно» или выводиться как «срань»? Существует несколько причин:
.docx, а вы записываете его с расширением .doc, Word может открыть его в режиме восстановления или с нарушением кодировки. Всегда проверяйте соответствие расширения фактическому формату файла.WINWORD.EXE остается висеть в памяти. Если таких процессов станет много, новые документы перестанут открываться корректно. Рекомендуем в блоке Исключение всегда вызывать WordПриложение.Quit().TypeText при замене поля MERGEFIELD фактически удаляет объект поля и вставляет текст. Если вы планируете обновлять данные в одном и том же открытом документе повторно, этот метод не подойдет.Если работа с Fields кажется слишком громоздкой, рассмотрим более простой способ — использование заполнителей в тексте (например, [НомерДоговора]). Проанализируем этот подход:
// Пример поиска и замены
Замена = Документ.Content.Find;
Замена.Execute("[НомерДоговора]", Ложь, Истина, Ложь, , , Истина, 1, , Строка(Данные.НомерДоговора), 2);
Этот метод более устойчив к случайным изменениям структуры документа пользователем, так как обычный текст сложнее «сломать», чем скрытые коды полей Word.
Мы рассмотрели полный цикл создания внешней печатной формы Word. Подведем итоги: во-первых, логика подготовки данных должна быть на сервере, а взаимодействие с Word — на клиенте. Во-вторых, использование временных файлов требует аккуратности и очистки после завершения работы. В-третьих, для стабильной работы в веб-клиенте данный метод не подходит, так как требует установленного локального приложения Microsoft Office.
Для повышения надежности системы старайтесь использовать закладки (Bookmarks) или метод поиска и замены, а также всегда предусматривайте обработку исключительных ситуаций при создании COM-объектов.