
Часто у клиентов возникает необходимость создания печатных форм, непредусмотренных в типовой конфигурации. В этом случае возникает 2 варианта решения этой проблемы: дорабатывать конфигурацию или же создать внешнюю печатную форму. Оба этих варианта рабочие, но почему же всё-таки лучше прибегнуть к внешним печатным формам?
● Главным преимуществом таких форм является то, что при их создании не вносятся изменения в типовую конфигурацию, что упрощает в дальнейшем обновление базы. ● Еще одним плюсом внешних печатных форм является то, что после их доработки нет необходимости обновлять базу, достаточно зайти в справочник «Дополнительные отчеты и обработки» и загрузить новый вариант обработки в нужный элемент справочника. ● Так же, если регламенты компании изменятся, и эта печатная форма больше не будет использоваться, у клиента не возникнет необходимость дорабатывать конфигурацию снова, будет достаточно отключить использование обработки в справочнике, с чем сможет справиться пользователь, не прибегая к помощи разработчика. ● В типовом функционале CRM есть возможность использования автотекста для печатных форм, но список документов, для которых ее можно использовать ограничен. Поэтому для создания печатных форм других объектов конфигурации гораздо удобнее использовать именно внешние печатные формы.
Рассмотрим создание внешней печатной формы Word. Для начала необходимо создать макет. Это должен быть документ Word, в котором каждый параметр обозначается как , название параметра при этом может быть любым, но желательно, чтобы оно отображало смысл выводимых в него данных. Области в таких макетах тоже необходимо выделить, их обозначают как: для открытия области и , чтобы показать, что область закончилась.
Например, чтобы документ после печати из 1С принял такой вид:
Пример документа для печати Необходимо создать вот такой макет:
Макет для документа Затем создаем внешнюю обработку, добавляем макет типа «Двоичные данные» и загружаем в него созданный ранее макет Word. В модуле объекта обработки необходимо описать сведения о внешней обработке. Для того чтобы печатную форму можно было увидеть в группе «Печать», необходимо указать Назначение – это те объекты конфигурации, откуда будет производиться печать, а также указать Вид обработки. 
re>МассивНазначений = Новый Массив; МассивНазначений.Добавить("Документ.ТАСС_ЗаявкаНаДоговор");

re>РегистрационныеДанные.Вставить("Вид", "ПечатнаяФорма"); РегистрационныеДанные.Вставить("Назначение", МассивНазначений);

В таблицу команд нужно добавить команду печати:
re>НоваяКоманда = ТаблицаКоманд.Добавить(); НоваяКоманда.Представление = "Заявка на договор для ЮЛ"; НоваяКоманда.Идентификатор = "ЗаявкаНаДоговорДляЮЛ"; НоваяКоманда.Использование = "ВызовКлиентскогоМетода"; НоваяКоманда.ПоказыватьОповещение = Истина; НоваяКоманда.Модификатор = "ПечатьMXL";

Теперь переходим в модуль формы обработки, в нем мы и будем описывать процедуры печати. Создаём экспортную процедуру «Печать». В данном случае документ после создания автоматически не открывается, а добавляется в присоединенные файлы объекта конфигурации.
re> ИмяМакета = "ПФ_DOC_ЗаявкаНаДоговорЮЛ"; МакетИДанныеОбъекта = ПолучитьДанныеПечати(СсылкаНаОбъект, ИмяМакета); АдресХранилищаПечатнойФормы = ВыполнитьПечатьВWordНаСервере(СсылкаНаОбъект, МакетИДанныеОбъекта, ИмяМакета); Если АдресХранилищаПечатнойФормы <> Неопределено Тогда ИмяБезРасширения = МакетИДанныеОбъекта.Данные[СсылкаНаОбъект][ИмяМакета].ИмяДокументаБезрасширения; РасширениеБезТочки = МакетИДанныеОбъекта.Данные[СсылкаНаОбъект][ИмяМакета].Расширение; ПараметрыФайла = Новый Структура; ПараметрыФайла.Вставить("Автор", ПользователиКлиентСервер.ТекущийПользователь()); ПараметрыФайла.Вставить("ВладелецФайлов", СсылкаНаОбъект); ПараметрыФайла.Вставить("ИмяБезРасширения", ИмяБезРасширения); ПараметрыФайла.Вставить("РасширениеБезТочки", РасширениеБезТочки) ПараметрыФайла.Вставить("ВремяИзмененияУниверсальное", Неопределено); ПараметрыФайла.Вставить("кпд_ИДРоли", "Основной"); РаботаСФайлами.ДобавитьФайл(ПараметрыФайла, АдресХранилищаПечатнойФормы); ПоказатьОповещениеПользователя("Вложение", ,"Документ прикреплен в ""Документы по проекту""", БиблиотекаКартинок.Скрепка); КонецЕсли; КонецПроцедуры

При этом функция ПолучитьДанныеПечати возвращает структуру с данными макета и значениями параметров, используемых в макете печатной формы. Для получения значения параметров в данном случае используется функция ПолучитьДанныеОбъекта, которая возвращает структуру, где ключ – название параметра из макета, а значение – это значение данного параметра.
re>НаСервере Функция ПолучитьДанныеПечати(Знач СсылкаНаОбъект, Знач ИмяМакета) ДанныеОбъектаПоМакетам = Новый Соответствие; ДанныеОбъектаПоМакетам.Вставить(ИмяМакета, ПолучитьДанныеОбъекта(СсылкаНаОбъект)) ДанныеПоВсемОбъектам = Новый Соответствие; ДанныеПоВсемОбъектам.Вставить(СсылкаНаОбъект, ДанныеОбъектаПоМакетам); ОписаниеОбластей = Новый Соответствие; ОписаниеОбластей.Вставить(ИмяМакета, ПолучитьОписаниеОбластейМакетаОфисногоДокумента()); ТипыМакетов = Новый Соответствие; // Для обратной совместимости. ТипыМакетов.Вставить(ИмяМакета, "DOC"); ДвоичныеДанныеМакета = РеквизитФормыВЗначение("Объект").ПолучитьМакет(ИмяМакета); ДвоичныеДанныеМакетов = Новый Соответствие; ДвоичныеДанныеМакетов.Вставить(ИмяМакета, ДвоичныеДанныеМакета);; Макеты = Новый Структура; Макеты.Вставить("ОписаниеОбластей", ОписаниеОбластей); Макеты.Вставить("ТипыМакетов", ТипыМакетов); // Для обратной совместимости. Макеты.Вставить("ДвоичныеДанныеМакетов", ДвоичныеДанныеМакетов); Результат = Новый Структура; Результат.Вставить("Данные", ДанныеПоВсемОбъектам); Результат.Вставить("Макеты", Макеты); Возврат Результат; КонецФункции
Для того чтобы вывести области в документ и заполнить параметры, опишем функцию ВыполнитьПечатьВWordНаСервере:

Эта функция возвращает адрес хранилища печатной формы для прикрепления полученного файла к присоединенным. Таким образом мы создали простейшую внешнюю печатную форму Word.
Теперь более детально рассмотрим, как сделать так, чтобы печатная форма Word выглядела красиво и читабельно, чтобы клиенту не приходилось исправлять её перед тем, как отправить на печать. В данной статье мы расскажем о некоторых лайфхаках, которые пригодятся каждому при создании печатной формы Word.
Иногда в печатных формах есть текст, который всегда должен начинаться с новой страницы, не сливаясь с предыдущим, например, это могут быть приложения к договору. Если обозначить эти части в отдельные области, то текст склеится. Для того чтобы это исправить, необходимо правильно настроить макет.
Во-первых, необходимо, чтобы область заканчивалась хотя-бы после первой строки новой страницы.
Текст, который должен начинаться с новой страницы Во-вторых, необходимо воспользоваться функцией разрыв страницы, только так текст не будет съезжать и всегда будет выглядеть аккуратно.
Функция "Разрыв страницы" Теперь разберем, как вывести нумерованные списки в печатную форму, когда один или несколько пунктов этого списка выводятся по условию.
Нумерование списков в печатной форме В данном варианте строки генерируются программно. Предполагаем, что строка выводится по одному условию, а строки , , , выводятся, если выполняется другое условие. В коде прописываем получение этих строк: 
re>СтрокаЕслиСтокИстина2 = ?(СтрокаЕслиСтокИстина = "",СтрЗаменить(Выборка.СтрокаЕслиСтокИстина2,"2.9.","2.8."),Выборка.СтрокаЕслиСтокИстина2); СтрокиНовостиАрхивСток2 = ""; СтрокиНовостиАрхивСток229 = ""; СтрокиНовостиАрхивСток2291 = ""; СтрокиНовостиАрхивСток2292 = ""; СтрокиНовостиАрхивСток2293 = ""; СтрокиНовостиАрхивСток2294 = ""; Если Выборка.АКАМ_ВПапкеСток Тогда СтрокиНовостиАрхивСток2 = "2.2.8. Для Произведений формата сток — право на переработку Произведений любыми способами не запрещёнными" ; КонецЕсли; Если Выборка.АКАМ_ВПапкеНовости И Выборка.АКАМ_ВПапкеАрхив Тогда Если СтрокиНовостиАрхивСток2 = "" Тогда СтрокиНовостиАрхивСток2 = "2.2.8. Для новостных и архивных Произведений:"; СтрокиНовостиАрхивСток2291 = "2.2.8.1. создание скриншотов на основе Произведений — видео, при условии приобретения лицензии"; СтрокиНовостиАрхивСток2292 = "2.2.8.2. изменение Произведения путём кадрирования и цветокоррекции"; СтрокиНовостиАрхивСток2293 = "2.2.8.3. редактирование Произведений для объединения с другим контентом (создание коллажей)"; СтрокиНовостиАрхивСток2294 = "2.2.8.4. обрезка персоны, изображенной на Произведении и изменение фона Произведения на однородный."; Иначе СтрокиНовостиАрхивСток229 = "2.2.9. Для новостных и архивных Произведений:"; СтрокиНовостиАрхивСток2291 = "2.2.9.1. создание скриншотов на основе Произведений — видео, при условии приобретения лицензии"; СтрокиНовостиАрхивСток2292 = "2.2.9.2. изменение Произведения путём кадрирования и цветокоррекции"; СтрокиНовостиАрхивСток2293 = "2.2.9.3. редактирование Произведений для объединения с другим контентом (создание коллажей)"; СтрокиНовостиАрхивСток2294 = "2.2.9.4. обрезка персоны, изображенной на Произведении и изменение фона Произведения на однородный."; КонецЕсли; КонецЕсли;

Так же прописываем условия присоединения областей:
re>Если ДанныеОбъекта.СтрокиНовостиАрхивСток229 <> "" Тогда Область = УправлениеПечатью.ОбластьМакета(Макет, ОбластиМакета["ОсновнойДоговор2"]); УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта, Ложь); КонецЕсли; Если ДанныеОбъекта.СтрокиНовостиАрхивСток2291 <> "" Тогда Область = УправлениеПечатью.ОбластьМакета(Макет, ОбластиМакета["ПеречислениеСтрок"]); УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта, Ложь); КонецЕсли;
Вариант с обычными, не сгенерированными сроками можно организовать подобным образом:
Вариант с обычными строками Соответственно, в данном случае условием видимости областей будет являться заполненность параметра : 
re>Если ДанныеОбъекта.СтрокаЕслиСтокИстина <> "" Тогда Область = УправлениеПечатью.ОбластьМакета(Макет, ОбластиМакета["Общая27или26"]); УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта, Ложь); Иначе Область = УправлениеПечатью.ОбластьМакета(Макет, ОбластиМакета["Общая26или27"]); УправлениеПечатью.ПрисоединитьОбластьИЗаполнитьПараметры(ПечатнаяФорма, Область, ДанныеОбъекта, Ложь); КонецЕсли;
Во многих документах происходит проблема съезжания подписи из-за объема выведенных реквизитов. Подписи всегда должны располагаться на одном уровне. В этой ситуации поможет справиться таблица.
Таблица, чтобы не съезжали подписи После того, как таблица выглядит аккуратно, и все строки находятся на одинаковом уровне, просто обесцвечиваем её границы.
Обесцвечивание границ таблицы
Примеры, описанные в данной статье, можно адаптировать под любую печатную форму Word — это те навыки, которые необходимы для того, чтобы клиент остался доволен проделанной работой и забыл о ручном исправлении документов.
Работа с ActiveDocument в клиент-серверном варианте. Работа с ActiveDocument в клиент-серверном варианте Выгрузка из 1с в шаблон word

Публикация — своего р ода памятка, содержащая примеры кода для:
1. заполнение шаблона Word данными из 1С; 2. заполнение колонтитулов Word данными из 1С; 3. заполнение таблицы в Word данными из 1С;
Начало работы
В большинстве случаев перед нами ставится следующая задача: Нужно открыть документ Word, заполненный данными из 1С.
Читатель может справедливо заметить, что используется модальный вызов, и погрозить автору пальцем. И будет прав.
//Создадим структуру параметров документа ПараметрыДокумента = ПодготовитьСтрукутруПараметров(); //Заполним структуру параметров документа ЗаполнитьСтруктуруПараметров(ПараметрыДокумента);
Углубимся немножко в принципы работы Word.
Каждый документ Word разделен на разделы, которые состоят из страниц.
Для каждого раздела есть возможность создавать свою нумерацию элементов, уникальные колонтитулы и настройки параметров страницы. Так, например, чтобы повернуть одну из страниц (вывести на печать как альбомную), нужно создать под неё отдельный раздел.
Каждая страница Word разделена на несколько областей:
- Верхний колонтитул
- Основной текст
- Нижний колонтитул
Нужно заметить, что в каждом разделе может быть уникальный колонтитул для первой страницы.
//Объект, содержит весь основный текст из всех разделов ДокументВорд.Content //Объект содержит коллекцию разделов документа ДокументВорд.Sections //В каждом разделе есть своя коллекция для верхних колонтитулов ДокументВорд.Sections(1).Headers //И своя коллекция для нижних колонтитулов ДокументВорд.Sections(1).Footers //При этом, если стоит галочка "Уникальный колонтитул для первой страницы", то коллекции Headers и Footers будут содержать два элемента
Заполнение пользовательских параметров
При обращении к этим коллекциям мы можем выполнять в них поиск и получать встроенные объекты, например, таблицы.
Теперь мы более-менее поняли, как обращаться к областям Word, можем в них пошуровать и выполнить замену наших параметров:
//Переберем все параметры и заменим их в документе Для каждого Параметр Из ПараметрыДокумента Цикл ВыполнитьЗамену(ДокументВорд.Content, Параметр.Ключ, Параметр.Значение); //Ищим вхождения параметра в верхнем колонтитуле ВыполнитьЗамену(ДокументВорд.Sections(1).Headers.Item(1).Range(), Параметр.Ключ, Параметр.Значение); //Ищим вхождения параметра в нижнем колонтитуле первой и последующих страниц ВыполнитьЗамену(ДокументВорд.Sections(1).Footers.Item(1).Range(), Параметр.Ключ, Параметр.Значение); ВыполнитьЗамену(ДокументВорд.Sections(1).Footers.Item(2).Range(), Параметр.Ключ, Параметр.Значение); КонецЦикла; //Выполнить поиск и замену Функция ВыполнитьЗамену(знач Object, Параметр, Значение) Object.Find.Execute(Параметр,,Значение,2) КонецФункции
Рассмотри подробнее метод Execute. Его параметры идентичны диалоговуму окну при замене/поиске непоседресвенно из MS Word:
А вот и основные параметры (вольный перевод справки MSDN):
- Искомый текст — Строка — Текст для замены. Текст может содержать специальные параметры. Например, ^p — абзац, ^t — табуляция
- Чувствительность к регистру — Булево — Если истина, то поиск будет осуществляться с учетом регистра
- Слова целиком — Булево — Если истина, то ищутся слова целиком. Вхождение слов не учитываются. Например, при поиске слова дом будет пропущено слово домашний
- Использовать подстановочные знаки — Булево — Если истина, то используются встроенные регулярные выражения.
- Искать похожие — Булево — Если истина, то результат поиска будет содержать похожие слова
- Искать все формы — Булево — Если истина, то результат поиска будет содержать различные формы слов.
- Поиск сначала — Булево — Если истина, то будет осуществляться с начала до конца документа
- Охват — WdFindWrap — Опредяляет направление поиска
- Формат — Format — Формат искомого текста
- Строка замены — Строка — Строка, на которую будет заменен исходный текст
- Количество замен — WdReplace — Определяет сколько раз выполнять замену
- и т.д.
WdReplace — Constant Value: wdReplaceAll 2 wdReplaceNone 0 wdReplaceOne 1
Данный метод не позволяет получить "Строка замены" как выделенную область, но он работает где-то в 10 раз медленнее. Для получения выделенной области можно воспользоваться немножко откорректированной типовой функцией:
//УправлениеПечатьюMSWordКлиент c незначительными изменениями для конфигурации УПП 1.3 Функция ВыполнитьЗамену(знач Object, Параметр, Значение) СтрокаПоиска = "[" + Параметр + "]"; СтрокаЗамены = Строка(Значение); //Необходимо выделить областей, в которой мы осуществляем замену Object.Select(); //Получаем выделенную область Selection = Object.Application.Selection; //Найдем все вхождения параметра и заменим его на нужное нам значение FindObject = Selection.Find; FindObject.ClearFormatting(); Пока FindObject.Execute(СтрокаПоиска) Цикл Если ПустаяСтрока(СтрокаЗамены) Тогда Selection.Delete(); Иначе Selection.TypeText(СтрокаЗамены); КонецЕсли; КонецЦикла; //Отменим выделение Selection.Collapse(); КонецФункции
Уже получив выделенную область можно отредактировать стиль текста, шрифт и т.д.
//Редактирование шрифта Selection.Font //Редактирование цвета Selection.HighlightColorIndex
Также есть второй подход, использующий такой объект Word, как поля. Мне он не очень нравится, т.к. в больших документах, порядка 100 страниц, эти поля начинают глючить (исчезать, не подставлять нужные значения) и прочая ерунда. Ну по крайней мере в Word 2007. Но я его все равно приведу:
При подготовке шаблона в тело документа необходимо навставлять полей с типом DOCVARIABLE (можно вставлять горячими клавишими Ctrl+F9).
Доступ к таким полям можно получить следующим нехитрым образом:
Заполнение таблиц по шаблону
Итак, мы заполнили параметры в основном тексте документа, заменили параметры в колонтитулах, но у нас еще есть одна неприятность — нужно заполнить таблицу.
Подход, описанный ниже, годится только для таблиц с заранее известным форматом. Т.е. мы можем как угодно отформатировать таблицу и её строки изначально. Но потом изменять довольно-таки проблематично.
К таблицам можно получить доступ через области документа.
//Получаем доступ к первой таблице в основном тексте Таблица = ДокументВорд.Content.Tables(1)
Для задания форматирования легче в шаблоне создать таблицу с пустой первой строкой, которую мы в последующем удалим.
//Данные для заполнения ПараметрыТЧ = ПараметрыДокумента.ПриложениеТЧ; //Нужно оставить шапку и первую строку нетронутой Итератор = 2; Таблица = ДокументВорд.Content.Tables(3); Для каждого Строка Из ПараметрыТЧ Цикл //По умолчанию добавляет строку выше первой Таблица.Rows.Add(); ЗаполнитьСтрокуТаблицы(Таблица, Итератор, Строка,"ПП,НоменклатураНаименование,ЕдИзмерения,ЦенаСтрокой",ПараметрыТЧ); Итератор = Итератор + 1; КонецЦикла; //Структура шаблонов содержит Наименование колонок и их порядок Процедура ЗаполнитьСтрокуТаблицы(Таблица, НомерСтроки, ЗначениеЗаполнения, СтруктураШаблонов,ТаблицаЗначений) МассивСтрок = ОбщегоНазначения.РазложитьСтрокуВМассивПодстрок(СтруктураШаблонов,","); Итератор = 1; Для каждого Строка Из МассивСтрок Цикл Если ТаблицаЗначений.Колонки.Найти(Строка) = Неопределено И Строка <> "ПП" Тогда Итератор = Итератор + 1; Продолжить; //Не забываем, что Шапка тоже строка, а при нумерации нам нужно её исключить ИначеЕсли Строка = "ПП" Тогда Таблица.Cell(НомерСтроки, Итератор).Range().Text = Строка(НомерСтроки-1); Итератор = Итератор + 1; Продолжить; КонецЕсли; Таблица.Cell(НомерСтроки, Итератор).Range().Text = Строка(ЗначениеЗаполнения[Строка]); Итератор = Итератор + 1; КонецЦикла; КонецПроцедуры
Вот, в принципе, и все. Основные вопросы, возникающие при работе с Word, я постарался осветить. Надеюсь, данный обзор поможет вам в работе =)
Спасибо за советы и комментарии: ,
Критика только приветствуется. Чем больше замечаний, тем лучше будет гайд =)
Доброго времени суток!
Для большинства организаций стандартная печатная форма какого-либо договора в программах 1С не подходит. Поэтому фирма 1С предоставила возможность добавлять дополнительные печатные формы для документов и других объектов. В этой статье я хочу рассказать, как создать и подключить внешнюю печатную форму договора, которая будет открываться в Microsoft Word.
Подключение дополнительных внешних печатных форм
Запускаем 1С:Предприятие. Открываем справочник «Дополнительные внешние печатные формы» через меню «Сервис» — «Дополнительные отчеты и обработки».
Нажмем кнопку «Добавить», затем зарегистрируем новую печатную форму, нажав «Заменить файл внешней обработки». Автоматически заполнится принадлежность печатной формы документу «Реализация товаров и услуг». Выбираем «Договор» в колонке «Заменяемая печатная форма», чтобы стандартная печатная форма более не использовалась.
Запускаем 1С:Предприятие, открываем справочник "Контрагенты", выбираем контрагента, для которого будет печататься наш договор и по кнопке "Файлы" переходим в справочник "Хранилище дополнительной информации", загружаем в него шаблон для договора и,обязательно, называем его "Договор", как показано на рисунке ниже, иначе программа не сможет найти макет для печатной формы.


Теперь открываем любой документ "Реализация товаров и услуг" и нажимаем кнопку «Печать» — «Договор». Откроется документ Microsoft Word с договором.

Внешнюю печатную форму "Договор" и макет к ней можно скачать по ссылкам ниже.
Макет трудового договора в формате Microsoft Word
Существует, по меньшей мере, три способа создания шаблона:
1. В документе Word создаются опорные фразы, например, "[НомерДоговора]", затем, в модуле обработки производится поиск и замена значений.
2. В документе Word создаются закладки, к которым потом можно обращаться по имени. Минус этого способа в том, что метка должна быть уникальна, т.е., если нужно вставить фамилию сотрудника в каждый абзац текста, то придется сделать несколько закладок с разными именами.
3. В документе Word добавляются служебные поля, например, «DocVariable» или «Author». Используя DocVariable можно обращаться к переменной по имени, например, «ДокументВорд.Variables.Add(ИмяПеременной, ЗначениеПеременной);», но ее не видно в шаблоне. Поле «Author» отображается в шаблоне, но обращаться к нему придется в цикле по индексу: «ДокументВорд.Fields.item(Индекс).Result.Text = Значение;».
На мой взгляд, первый способ является самым оптимальным. Шаблон документа легко редактируется, опорные фразы видны в тексте. Поэтому шаблон создаём этим способом.
Открываем программу Microsoft Office. Для примера добавляем пару строк, как показано на рисунке ниже и сохраняем шаблон.

Создание внешней печатной формы "Договор"
Запускаем 1С:Предприятие в режиме «Конфигуратор» и через меню «Файл» — «Новый» создаём внешнюю обработку. Добавляем реквизит "Ссылка на объект" и макет "Параметры_Авторегистрации" с типом "Табличный документ". Тип реквизита "Ссылка на объект" зависит от того, для каких объектов будет использоваться печатная форма, в нашем случае печатная форма будет использовать для документа "Реализация товаров и услуг", поэтому указываем тип "ДокументСсылка.РеализацияТоваровУслуг".

Разработка процедуры печати

Введение. Предметная область
Макет – это один из самых универсальных объектов 1С Предприятия 8. Использование макетов широко применяется как в оформлении различных документов (отчеты, печатные формы и т.д.), так и в решении нестандартных задач (например хранение файлов внутри конфигурации).
Для чего нужен и применяется такой прекрасный тип макета как ActiveDocument? Самый банальный пример – это шаблон договора, сделанный юристом на скорую руку в MS Word. Тип макета ActiveDocument позволяет загрузить этот шаблон MS Word в конфигурации и осуществлять редактирование напрямую из конфигуратора.
Т.е. вот вы сделали шаблон договора, загрузили в конфигурацию, проработали с этим шаблоном 1 год, и потом вдруг выяснилось, что нужно изменить кусок текста этого договора. Без проблем – открываем конфигуратор, 2 щелчка на нужном макете и можем править word-вский файлик прямо в конфигураторе. Закрываем, обновляем конфигурацию – дело сделано!
Принцип работы.
К сожалению (или к счастью) работа с макетом ActiveDocument возможно только программная. Т.е. чтобы при нажатии кнопки пользователю открылся наш word-вский файлик, нужно написать код! (ВАУ)
Сама схема кода следующая:
1 – Получаем макет ActiveDocument
2 – Инициализируем COM-объект нашего ActiveDocument
3 – Работаем с этим COM-объектом (заполняем данные, редактируем, выводим на экран)
И вот тут начинается самое интересное…
Когнитивный диссонанс
Вот самые первые строчки, на которые натыкается в гугле юный неофит. В файловом варианте такой код сработает корректно (неважно в толстом или тонком клиенте). Т.к. и сервер и клиент у нас находятся на одной машине, и MS Word тоже установлен на этой машине.
А давайте представим, что у нас клиент-сервер, да ещё и сервер находится на другой машине. Будет оно работать в тонком клиенте? Нет. И тут возникнет когнитивный диссонанс. WTF? O_o
Во-первых, получить макет (любой) можно только НаКлиент, как и в случае с табличным документом!»
Не фигня. Оболочка ActiveDocument существует только на сервере и вернуть её на клиент не получится (а нам-то нужно запустить Word именно на клиентской машине).
Во-вторых, инициализировав COM-объект НаСервере Получаем макет ActiveDocument
2 – НаКлиенте Инициализируем COM-объект из файла
4 — )
P.S. кстати, обратите внимание, какая изящная задача получилась для тестирования опытного кандидата на работу. Если вам нужен человек, для интеграции 1С с другими ПО, да еще и чтоб в Управляемых формах шарил — вы легко сможете это определить.
Итак, в чем суть моей статьи?
1. Есть сервер (x64), с установленным Office 2016 (x64), есть 1С 8.3.8 также x64 (имеется в виду сервер 1С). Пользователи подключаются как через тонкого клиента, так и через веб клиент.
2. Есть куча типовых договоров и накладных счет-фактур, оформленных (подготовленных) отделом продаж. Там шрифт, абзац и т.д., естественно, все оформлено в Word,Excel 2016 (x64), естественно, нет желания все это рисовать в 1С, а есть желание засунуть в макеты формата ActiveDocument
Решение банальное, вроде бы 🙂 , не буду описывать весь механизм, как это делается, как заполняются данные из 1С в макет ActiveDocument — думаю, вы это знаете прекрасно и без меня. Но в ходе работы выяснилось, что не все так гладко в царстве COM объектов, а именно:
2. Какой вариант лучше выбрать: ActiveDocument или ДвоичныеДанные? Хотя для меня это звучит примерно как, что выбрать Водку С Пивом или Пиво С Водкой 🙂 . Один фиг, надо забить документы данными из 1С и передать их Клиенту.
Ну да ладно пропустим лирику, я выбираю ActiveDocument, не буду описывать весь алгоритм, просто перечислю "подводные" камни и их решение. Все нижеизложенное это мои личные измышления и в никакой мере не претендуют на истину в последней инстанции. Возможно, вы решили эти проблемы или решите по другому.
1. Камень "первый ". Не работает метод SaveAs (как для MSWord, так и для MSExcel). При попытке записать ДвоичныеДанные 1С просто вылетает. Смотрим фрагмент листинга:
Спасибо огромное.
Создание папок C:WindowsSysWOW64configsystemprofileDesktop C:WindowsSystem32configsystemprofileDesktop проблему решило. Тема закрыта.
В чем причина? Причина в том, что код
Всегда вызывает экземпляр объекта COM (x32) независимо от того какой разрядности Office установлен. Вы никогда не задумывались, почему в макет ActoveDocument нельзя вставить файлы с расширением docx,xlsx
это можно проверить и через ДиспетчерЗадач, но факт есть факт — макет ActiveDocument вызывает неявно экземпляр COM (x32) и поэтому все дальнейшие манипуляции нужно делать учитывая это особенность.
1. Либо сервер и все ПО должно быть x32. Тогда ничего делать (в смысле переписывать код) не надо
2. Либо переписать код, таким образом
// получаем имя временного файла ВремФайл = ПолучитьИмяВременногоФайла("doc"); // этот код точно вызовет экземпляр COM нужной разрядности, в нашем случае x64 Word = Новый COMОбъект("Word.Application"); Word.Displayalerts = 0; ДокументН = Word.Application.Documents.Add(); ДокументН.SaveAs(ВремФайл,0); Word.Quit(); // далее все по старому Макет = УправлениеПечатью.МакетПечатнойФормы("Документ.АктПередачиОборудования."+НазваниеМакета); MSWord = Макет.Получить(); Попытка Документ = MSWord.Application.Documents(1); Документ.Activate(); // здесь что-то делаем, заполняем данные // здесь мы пересохраним наш файл из COM x62 в COM x64 MSWord.Application.Selection.WholeStory(); MSWord.Application.Selection.Copy(); ДокументН = MSWord.Application.Documents.Open(ВремФайл); ДокументН.Activate(); MSWord.Application.Selection.Paste(); ДокументН.SaveAs(ВремФайл,0); ДокументН.Close(); MSWord = Неопределено; Исключение // Если произойдет ошибка выводятся данные об ошибке и объект закрывается. Информация = ИнформацияОбОшибке(); ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка — "+Информация.Описание+" код ошибки — "+СокрЛП(Информация.ИсходнаяСтрока)); MSWord.Application.Quit(); КонецПопытки;
Думаю, тут все понятно, сначала мы создали экземпляр COM нужной разрядности, создали пустой файл и сохранили во временную папку, далее работает с COM x32, заполняем данными и напоследок копируем содержимое всего документа и сохраняем в ранее подготовленный файл.
Все то же самое, но только для Excel
ВремФайл = ПолучитьИмяВременногоФайла("xls"); Excel = Новый COMОбъект("Excel.Application"); Excel.Displayalerts = 0; КнигаН = Excel.WorkBooks.Add(); ЛистН = КнигаН.WorkSheets(1); КнигаН.SaveAs(ВремФайл, -4143); Excel.Quit(); Макет = УправлениеПечатью.МакетПечатнойФормы("Документ.НакладнаяОборудования."+НазваниеМакета); MSExcel = Макет.Получить(); КнигаН = MSExcel.Application.Workbooks.Open(ВремФайл); ЛистН = КнигаН.WorkSheets(1); Попытка WBook = MSExcel.Application.Workbooks(1); Лист = WBook.WorkSheets(1); Лист.Activate(); // что-то делаем, заполняем данными из 1С MSExcel.Application.WorkBooks(1).WorkSheets(1).Cells.Copy(ЛистН.Cells); КнигаН.Save(); КнигаН.Close(); Исключение // Если произойдет ошибка выводятся данные об ошибке и объект закрывается. Информация = ИнформацияОбОшибке(); ОбщегоНазначенияКлиентСервер.СообщитьПользователю("Ошибка — "+Информация.Описание+" код ошибки — "+СокрЛП(Информация.ИсходнаяСтрока)); MSExcel.Application.Quit(); КонецПопытки;
ну вот "первый " камень я решил, на сервере x64 с Office x64, все работает точно как часы, без ошибок и не надо создавать никаких папок и все прочее.
Камень "второй ". фрагмент кода
есть не очень хорошо, потому как идет запись в папку: "c:Users че там. ", вообще эта папка всегда в черном списке всех фаерволов, антивирусов и прочее, прочее, хотя бы открыть центр управления безопасностью Word или Excel. Глянем и мы туда

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

здесь мы будем хранить наши готовые Word, Excel файлы уже заполненные, конечно:
НазваниеМакета — Идентификатор макета
ДокументOffice — ХранилищеЗначений, здесь мы и держим наш готовый файл
2. Дописываем выше написанный код следующим образом:
МЗ = РегистрыСведений.ВременноеХранилищеOffice.СоздатьМенеджерЗаписи(); МЗ.Объект = Выборка.Ссылка; МЗ.НазваниеМакета = НазваниеМакета; МЗ.Прочитать(); МЗ.Объект = Выборка.Ссылка; МЗ.НазваниеМакета = НазваниеМакета; МЗ.ДокументOffice = Новый ХранилищеЗначения(Новый ДвоичныеДанные(ВремФайл)); МЗ.Записать(); УдалитьФайлы(ВремФайл);
Что мы делаем, мы записываем готовый файл в регистр сведений и затем удаляем сам временный файл, решаем проблему "Центра безопасности Word,Excel". Осталось только одно показать этот готовый файл Клиенту (клиент тонкий и веб)
3. Камень "третий " — передача файла клиенту, тут просто выложу весь код, что-то взял из БСП, что-то из Демонстрационная конфигурация "Управляемое приложение", что-то из Инета, но в общем вот код (целиком)
1.
Во-первых, клиент у нас работает как через Тонкий, так и через Веб режимы, поэтому заранее в свойствах Конфигуратор ставим следующие значения:

Чтобы не было проблем при работе с браузером
2. Используем обработчики ожидания, чтобы избежать проблем с синхронностью вызов (это касается только режим Веб)
3. И последнее, подключаем Расширение для работы с Файлами (помним что в режиме Тонкий клиент, это расширение включено всегда). И через код:
передаем файл Клиенту используя механизм НавигационнаяСсылка, получаем следующие сообщения в браузере (Тонкий само собой работает):


ну вот, кажется, все. Надеюсь, это поможет кому-нибудь.
По поводу Word, Excel файлы вставлять в виде ДвоичныхДанные? проблема-то в чем?
1. Мы либо должны вытащить из макета эти ДвоичныеДанные и заполнить данными из 1С и ВНИМАНИЕ снова записать в виде ДвоичныхДанных (Водка С Пивом или Пиво С Водкой)
2. Либо мы должно получить макет ДвоичныеДанные на стороне Клиента и там заполнить его, НО COM объект поддерживается только браузером IE и то с танцами с настройками ActiveX, другие браузеры давно отказались от использования ActiveX




