Работа с ActiveDocument в клиент-серверном варианте. Работа с ActiveDocument в клиент-серверном варианте Создание внешней печатной формы "Договор"

Подписаться
Вступай в сообщество «passport13.com»!
ВКонтакте:

Доброго времени суток!

Для большинства организаций стандартная печатная форма какого-либо договора в программах 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». «Фигня!» - скажет опытный гуру конфигурирования – «вернём &НаКлиент, как и в случае с табличным документом!»

Не фигня. Оболочка ActiveDocument существует только на сервере и вернуть её на клиент не получится (а нам-то нужно запустить Word именно на клиентской машине).

Во-вторых, инициализировав COM-объект &НаСервере, вернуть его на клиент, также не получится

(и кстати, если сделать наоборот - с клиента на сервер, тоже не прокатит)

Танцы с бубном

Как быть? Ведь нужно инициализировать COM-объект на клиенте, причем из данных, получаемых только на сервере и которых на клиент передать нельзя.

Решение у этой задачи самое корявое, которое только может быть. Но давайте вспомним, зачем мы вообще используем ActiveDocument? Правильно, чтобы внести изменения в шаблон через конфигуратор «на лету». Это и есть та единственная причина, по которой мы используем ActiveDocument. Иначе бы мы использовали тип макета «Двоичные данные».

А вот само решение точно такое же, как при использовании макета с двоичными данными! Т.е. сначала нам нужно сохранить ActiveDocument в файл, а потом, используя этот файл, инициализировать COM-объект (причем сделать это нужно на клиенте!).

Таким образом наша предыдущая схема превращается вот во что:

1 – &НаСервере Получаем макет ActiveDocument

2 – &НаСервере Сохраняем полученный макет в файл и возвращаем на клиент полное имя файла (полный путь + наименование с расширением)

3 – &НаКлиенте Инициализируем COM-объект из файла

4 - &НаКлиенте заполняем и выводим этот COM-объект

Небольшой листинг кода:

&НаКлиенте Процедура ПоказатьМакет(Документ) Макет = ОбщийМодуль.ПолучитьМакет(Документ); //серверная функция, записывает макет в файл и возвращает полное имя файла Попытка Шаблон = ПолучитьCOMОбъект(Макет); //инициализируем COM-объект Исключение КомОбъект = 0; Сообщение = Новый СообщениеПользователю; Сообщение.Текст = ОписаниеОшибки(); Сообщение.Сообщить(); Возврат; КонецПопытки; Если Шаблон = Неопределено Тогда Возврат; КонецЕсли; //здесь делаем всякие штуки типа заполнения и прочего Шаблон.Fields.UpDate(); Шаблон.Activate(); Шаблон.Application.Visible = 1; //указываем, что надо показать юзеру наш COM-объект Шаблон.Save(); //записываем изменения Шаблон = 0; КонецПроцедуры //Получает макет ActiveDocument и записывает его в файл &НаСервере Функция ПолучитьМакет(Документ) Экспорт Каталог = ПараметрыСеанса.ТекущийПользователь.РабочийКаталог; Каталог = ?(Прав(Каталог,1) = "\", Каталог, Каталог+"\"); Если ЗначениеЗаполнено(Каталог) Тогда Попытка ПолноеИмяФайла = Каталог+Документ.Номер+".doc"; Макет = Документы.ДоговорыКонтрагентов.ПолучитьМакет("ActiveDocument"); Макет.Записать(ПолноеИмяФайла); Возврат ПолноеИмяФайла; Исключение Сообщение = Новый СообщениеПользователю; Сообщение.Текст = "Не удалось записать файл "+ОписаниеОшибки(); Сообщение.Сообщить(); Возврат Неопределено; КонецПопытки; Иначе Сообщение = Новый СообщениеПользователю; Сообщение.Текст = "Не указан каталог. Сохранение файла невозможно"; Сообщение.Сообщить(); Возврат Неопределено; КонецЕсли; КонецФункции // ()

Заключение

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

Надеюсь статья кому-то сэкономит 10мин:) Удачи! ;)

P.S. кстати, обратите внимание, какая изящная задача получилась для тестирования опытного кандидата на работу. Если вам нужен человек, для интеграции 1С с другими ПО, да еще и чтоб в Управляемых формах шарил - вы легко сможете это определить.

ВНИМАНИЕ! При использовании кодов описанных ниже, уберите символ _
Давайте рассмотрим на примерах как это делается! =) Мне известно 2 способа:
1. Путем замены шаблонного текста в макете Wordа.
2. Путем вставки текста с помощью закладок в Wordе,

В первом случае сразу скажу, что длина строки передаваемая в функцию замены, довольно небольшая 255 символов, да и расстановка шаблонных выражений в макете Word занимает довольно много времени. Через процедуру Content.Find.Execute.

Во втором случае длина, насколько мне известно неограниченна, также воськаться с закладками намного быстрее и удобнее, чем расставлять шаблонный текст. Используя Bookmarks().S_elect(). Поэтому давайте на коде рассмотрим второй пример.

И так, для начала необходимо добавить Word макет к документу. Добавляем макет с помощью конструктора макетов указав Active document и выбрав соответствующий макет.

Называем его Акт. Открываем макет в 1Ске, ставим курсор в нужном месте, переходим в меню Вставка закладка нажимаем добавить закладку к примеру у меня это НарушенияТекст

Теперь кидаем на форму документа кнопку Сформировать и по нажатию на нее пишем код который открывает наш макет Word ищем закладку по имени и вставляет туда текст:
Код 1C v 8.х //инициализация часть 1
СсылкаМакет = ПолучитьМакет(Акт);
MSWord = СсылкаМакет.Получить();
Попытка
СсылкаМакет = MSWord.Application.Documents(1);
СсылкаМакет.Activate();
//выгружаем табличную часть с нарушениями в строку часть 2
str = Новый COMОбъект(ADODB.Stream);
str.Open();
СтрочкаТаблицы = ЭлементыФормы.Нарушения.ТекущиеДанные;
Для Каждого СтрочкаТаблицы Из Нарушения Цикл
str.WriteText(+ СтрочкаТаблицы.Описание + Нарушены требования СНИПФЗГОСТ: + СтрочкаТаблицы.СНИПФЗГОСТ + Статья: + СтрочкаТаблицы.ЧастьСтатья + Символ(13),0);
КонецЦикла;
str.Position = 0;
НарушенияТекст = str.readText();

//вставляем в закладку текст с нарушениями часть 3
MSWord.Bookmarks(НарушенияТекст).S_elect();
MSWord.Application.S_election.TypeText(НарушенияТекст);

СсылкаМакет.Activate();
Исключение
//если ошибка
Сообщить(ОписаниеОшибки());
MSWord.Application.Quit();
КонецПопытки;
Это пример вывода множества строчек из табличной части одной строкой, если нужно просто выгрузить какой-то реквизит то можно пропустить часть 2 и перейти к части 3.

Для выгрузки табличной части в форме таблицы можно использовать функцию автоформата, примеру код выгрузки табличной части документа Предписание:
Код 1C v 8.х Word = MSWord.Application;
Документ = Word.ActiveDocument();
//Переместиться вниз на 22 строк
Word.S_election.MoveDown(,22);
Документ.Paragraphs.Add();
//подготовка таблицы:
Rng = Word.S_election.Range;
//Формируем заголовок:
Rng.I_nsertAfter(№ п/п*Установленные нарушения и меры по их устранению*Основания);
Rng.I_nsertParagraphAfter();
//сама таблица
СтрочкаТаблицы = ЭлементыФормы.НарушенияПредписание.ТекущиеДанные;
Для Каждого СтрочкаТаблицы из НарушенияПредписание Цикл
Rng.I_nsertAfter(Строка(СтрочкаТаблицы.НомерСтроки)+*+СтрочкаТаблицы.Описание + ; + СтрочкаТаблицы.Предписание +* + СтрочкаТаблицы.СНИПФЗГОСТ + + СтрочкаТаблицы.ЧастьСтатья);
Rng.I_nsertParagraphAfter();
КонецЦикла;
Rng.ConvertToTable(*);
Документ.Tables(1).AutoFormat(17); //номер таблицы в шаблоне
Word.Visible = Истина;
Ну вот и все =)

Еще способ Active document
В Конфигураторе Макеты - правый клик - Добавить
Тип макета: Active document
Создать новый - Документ Microsoft Word

Меню Вставка - Поле - Автоматизация - DocVariable
Написать имя поля в графе "Новое имя:" ДатаПриказа

В модуле формы документа создаем кнопку, и в ее обработчике пишем:



КомОбъект.Variables.Item("ДатаПриказа").Value="24.01.2007";
КомОбъект.Fields.UpDate();

КомОбъект.PrintOut(); //распечатать документ

//Ожидание окончания отправки на печать...
Пока objWord.Application.BackgroundPrintingStatus<>0 Цикл
Предупреждение("Ожидание",1);
КонецЦикла;

КомОбъект.Application.Quit(); //закрыть Word
КомОбъект = 0;
КонецПроцедуры

2) добавляем не поле, а Закладку
Меню Вставка - Закладка и далее указываем ее имя ("ИмяЗакл")
Код 1C v 8.х Процедура ОсновныеДействияФормыWord(Кнопка)
АктивныйДокумент = ПолучитьМакет("Макет");
КомОбъект = АктивныйДокумент.Получить();
КомОбъект.Application.Visible=1;
КомОбъект.Bookmarks(СокрЛП("ИмяЗакл")).S_elect();
КомОбъект.Application.S_election.TypeText(СокрЛП("тест проверка"));
КонецПроцедуры

Код 1C v 8.2 УП // Параметры договора обозначены в тексте переменными вида "[%НомерДоговора%]"
Функция ПечатьДокумента() Экспорт

Договор = ПолучитьМакет("ActiveDocument_ДоговорПоставки"); // получим макет-ActiveDocument
MSWord = Договор.Получить();
Попытка
Doc = MSWord.Application.Documents(1);
Doc.Activate();
Replace = Doc.Content.Find;

FindText = "{НомерДоговора}"; // что искать - имя_шаблона
MatchCase = Ложь; // использовать регулярные выражения
MatchWholeWord = Истина; // искать слово целиком
MatchWildcards = Ложь; // испоьзовать регулярные выражения
MatchSoundsLike = Неопределено; // искать созвучные
MatchAllWordForms = Неопределено; // искать все формы слова
Forward = Истина; // искать вперед
Wrap = Неопределено; // что должен вернуть Find-объект
Format_ = Ложь; // использовать форматирование
ReplaceWith = "N777"; // текст, на который надо заменить имя_шаблона

// кратко:
//Replace.Execute(FindText,Ложь,Истина,Ложь,Истина,Ложь,НомерДоговора);

Replace.Execute(
FindText,
MatchCase,
MatchWholeWord,
MatchWildcards,
MatchSoundsLike,
MatchAllWordForms,
Forward,
Wrap,
Format_,
НомерДоговора);

MSWord.Application.Visible = Истина;
MSWord.Activate();
Исключение
Сообщить(ОписаниеОшибки());
MSWord.Application.Quit();
КонецПопытки;

Возврат 0;

Итак, в чем суть моей статьи?

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С просто вылетает. Смотрим фрагмент листинга:

MSWord = Макет.Получить(); Попытка Документ = MSWord.Application.Documents(1); Документ.Activate(); //Далее каким-либо образом получаем данные и заполняем Word-овский документ //Получим путь во временной директории для сохранения туда файла ИмяВрем = ПолучитьИмяВременногоФайла(".docx"); Документ.SaveAs(ИмяВрем); //здесь начинается камень МойДокументВДвоичныхДанных = Новый ДвоичныеДанные(ИмяВрем); //ну а здесь этот камень нафиг выбивает 1С:) MSWord.Application.Quit();

Спасибо огромное.

Создание папок
C:\Windows\SysWOW64\config\systemprofile\Desktop
C:\Windows\System32\config\systemprofile\Desktop
проблему решило. Тема закрыта.

В чем причина? Причина в том, что код

MSWord = Макет.Получить();

Всегда вызывает экземпляр объекта 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, все работает точно как часы, без ошибок и не надо создавать никаких папок и все прочее.

Камень "второй ". фрагмент кода

ВремФайл = ПолучитьИмяВременногоФайла("xls");

есть не очень хорошо, потому как идет запись в папку: "c:\Users\ че там....", вообще эта папка всегда в черном списке всех фаерволов, антивирусов и прочее, прочее, хотя бы открыть центр управления безопасностью Word или Excel. Глянем и мы туда

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

1. Открываем Конфигуратор и добавляем новый РегистрСведений

здесь мы будем хранить наши готовые Word, Excel файлы уже заполненные, конечно:

НазваниеМакета - Идентификатор макета

ДокументOffice - ХранилищеЗначений, здесь мы и держим наш готовый файл

2. Дописываем выше написанный код следующим образом:

МЗ = РегистрыСведений.ВременноеХранилищеOffice.СоздатьМенеджерЗаписи(); МЗ.Объект = Выборка.Ссылка; МЗ.НазваниеМакета = НазваниеМакета; МЗ.Прочитать(); МЗ.Объект = Выборка.Ссылка; МЗ.НазваниеМакета = НазваниеМакета; МЗ.ДокументOffice = Новый ХранилищеЗначения(Новый ДвоичныеДанные(ВремФайл)); МЗ.Записать(); УдалитьФайлы(ВремФайл);

Что мы делаем, мы записываем готовый файл в регистр сведений и затем удаляем сам временный файл, решаем проблему "Центра безопасности Word,Excel". Осталось только одно показать этот готовый файл Клиенту (клиент тонкий и веб)

3. Камень "третий " - передача файла клиенту, тут просто выложу весь код, что-то взял из БСП, что-то из Демонстрационная конфигурация "Управляемое приложение", что-то из Инета, но в общем вот код (целиком)

//////////////////////////////////////////////////////////////////////////////// // СЛУЖЕБНЫЕ ПРОЦЕДУРЫ И ФУНКЦИИ БСП &НаСервере Функция ПолучитьМакет() ОбъектСсылка = СтруктураДанных.Объект; НазваниеМакета = СтруктураДанных.НазваниеМакета; КлючЗаписи = РегистрыСведений.ВременноеХранилищеOffice.СоздатьКлючЗаписи(Новый Структура("Объект,НазваниеМакета",ОбъектСсылка,НазваниеМакета)); // Адрес = ПолучитьНавигационнуюСсылку(КлючЗаписи,"ДокументOffice"); Возврат Адрес; КонецФункции // &НаКлиенте Процедура ПослеЗапускаПриложения(КодВозврата, ИмяПриложения) Экспорт; // КонецПроцедуры &НаКлиенте Процедура ПослеПолученияФайлов(ПереданныеФайлы, ДополнительныеПараметры) Экспорт Если НЕ ПереданныеФайлы=Неопределено Тогда Для каждого Описание Из ПереданныеФайлы Цикл ОпПослеЗапускаПриложения = Новый ОписаниеОповещения("ПослеЗапускаПриложения", ЭтотОбъект, Описание.Имя); НачатьЗапускПриложения(ОпПослеЗапускаПриложения, Описание.Имя); КонецЦикла; КонецЕсли; КонецПроцедуры &НаКлиенте Процедура ПослеВыбораКаталога(ВыбранныеФайлы, ИмяКоманды) Экспорт Если ВыбранныеФайлы = Неопределено Тогда Возврат; КонецЕсли; Каталог = ВыбранныеФайлы; ОбщегоНазначенияВызовСервера.СохранитьРабочийКаталог(Каталог); Если ИмяКоманды = "Накладная" Тогда НазваниеМакета = "Накладная" КонецЕсли; СтруктураДанных.Вставить("Каталог", Каталог); ПодключитьОбработчикОжидания("Подключаемый_ПередатьФайлКлиенту",5,Истина); КонецПроцедуры &НаКлиенте Процедура ОткрытьФайлыЧерезРасширение(ИмяКоманды) ОпПослеВыбораКаталога = Новый ОписаниеОповещения("ПослеВыбораКаталога", ЭтотОбъект, ИмяКоманды); Каталог = ОбщегоНазначенияВызовСервера.ПолучитьРабочийКаталог(); Если Каталог = Неопределено ИЛИ Каталог = "" Тогда Диалог = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.ВыборКаталога); Диалог.Заголовок = НСтр("ru = "Выбор каталога временного хранения файлов"", "ru"); Диалог.Показать(ОпПослеВыбораКаталога); Иначе ВыбранныеФайлы = Новый Массив; ВыбранныеФайлы.Добавить(Каталог); ВыполнитьОбработкуОповещения(ОпПослеВыбораКаталога, ВыбранныеФайлы); КонецЕсли; КонецПроцедуры &НаКлиенте Процедура ОбработатьПодключениеРасширенияРаботыСФайлами(РасширениеПодключено,ДополнительныеПараметры) Экспорт Если РасширениеПодключено Тогда ОткрытьФайлыЧерезРасширение(ДополнительныеПараметры.ИмяКоманды); КонецЕсли; КонецПроцедуры &НаКлиенте Процедура Подключаемый_ПередатьФайлКлиенту() Адрес = ПолучитьМакет(); Если Адрес<>Неопределено Тогда ОтключитьОбработчикОжидания("Подключаемый_ПередатьФайлКлиенту"); НомерДокумента = СтруктураДанных.НомерДокумента; Каталог = СтруктураДанных.Каталог; НазваниеМакета = СтруктураДанных.НазваниеМакета; ПутьКфайлу = Каталог+"\"+НазваниеМакета+"_№"+НомерДокумента+".xls"; Описание = Новый ОписаниеПередаваемогоФайла(ПутьКфайлу, Адрес); ПередаваемыеФайлы = Новый Массив; ПередаваемыеФайлы.Добавить(Описание); НачатьПолучениеФайлов(Новый ОписаниеОповещения("ПослеПолученияФайлов", ЭтотОбъект), ПередаваемыеФайлы, "", Ложь); КонецЕсли; КонецПроцедуры &НаСервере Процедура ВыполнитьПечатьСервер() ОбъектСсылка = СтруктураДанных.Объект; НазваниеМакета = СтруктураДанных.НазваниеМакета; СтруктураДанных.Вставить("НомерДокумента", ОбъектСсылка.Номер); МассивОбъектов = Новый Массив; МассивОбъектов.Добавить(ОбъектСсылка); Документы.НакладнаяОборудования.ПечатьНакладная(МассивОбъектов,НазваниеМакета,Истина); КонецПроцедуры &НаКлиенте Процедура Подключаемый_ВыполнитьПечать() ВыполнитьПечатьСервер(); КонецПроцедуры // СтандартныеПодсистемы.Печать &НаКлиенте Процедура Подключаемый_ВыполнитьКомандуПечати(Команда) Ссылка = Элементы.Список.ТекущиеДанные.Ссылка; СтруктураДанных = Новый Структура; СтруктураДанных.Вставить("Объект", Ссылка); СтруктураДанных.Вставить("НазваниеМакета", "Накладная"); ПодключитьОбработчикОжидания("Подключаемый_ВыполнитьПечать", 1, Истина); ОписаниеКоманды = УправлениеПечатьюКлиент.ОписаниеКомандыПечати(Команда.Имя,ИмяФормы); НачатьУстановкуРасширенияРаботыСФайлами(); НачатьПодключениеРасширенияРаботыСФайлами(Новый ОписаниеОповещения("ОбработатьПодключениеРасширенияРаботыСФайлами",ЭтотОбъект,Новый Структура("ИмяКоманды",ОписаниеКоманды.Идентификатор))); КонецПроцедуры // Конец СтандартныеПодсистемы.Печать

Немного пояснений:

1. Во-первых, клиент у нас работает как через Тонкий, так и через Веб режимы, поэтому заранее в свойствах Конфигуратор ставим следующие значения:

Чтобы не было проблем при работе с браузером

2. Используем обработчики ожидания, чтобы избежать проблем с синхронностью вызов (это касается только режим Веб)

3. И последнее, подключаем Расширение для работы с Файлами (помним что в режиме Тонкий клиент, это расширение включено всегда). И через код:

передаем файл Клиенту используя механизм НавигационнаяСсылка, получаем следующие сообщения в браузере (Тонкий само собой работает):

ну вот, кажется, все. Надеюсь, это поможет кому-нибудь...

По поводу Word, Excel файлы вставлять в виде ДвоичныхДанные? проблема-то в чем?

1. Мы либо должны вытащить из макета эти ДвоичныеДанные и заполнить данными из 1С и ВНИМАНИЕ снова записать в виде ДвоичныхДанных (Водка С Пивом или Пиво С Водкой)

2. Либо мы должно получить макет ДвоичныеДанные на стороне Клиента и там заполнить его, НО COM объект поддерживается только браузером IE и то с танцами с настройками ActiveX, другие браузеры давно отказались от использования ActiveX

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

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

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


Далее необходимо в файл шаблона для 1С, добавить текст и пару закладок. Закладка добавляется через меню «Вставка» — «Закладка». Нужно выделить текст закладки, скопировать его, открыть меню «Вставка — Закладка», вставить скопированный текст закладки и нажать «Добавить»:


Когда файл шаблона Word готов, создаем новую внешнею обработку в 1С, добавляем форму и в модуле формы вставляем следующий код: &НаКлиенте Процедура ПриОткрытии(Отказ) ЗаполнитьШаблонВорд(); КонецПроцедуры &НаКлиенте Функция ЗаполнитьШаблонВорд() //Попытка создать COM объект Попытка ОбъектВорд = Новый COMОбъект("Word.Application"); Исключение Сообщить("Ошибка при запуске Microsoft Word: " + ОписаниеОшибки(), СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; //Путь к шаблону ОбъектВорд.Documents.Add("C:\Users\Константин\Desktop\Шаблон.docx"); ШаблонВорд = ОбъектВорд.ActiveDocument; //Получаем все закладки из шаблона Для каждого ЗакладкаВорд Из ШаблонВорд.Bookmarks Цикл Сообщить(ЗакладкаВорд.Name); КонецЦикла; //Заменяем закладку1 на текст ШаблонВорд.Bookmarks("Закладка1").Select(); ШаблонВорд.Application.Selection.TypeText("Текст для закладки №1."); //Заменяем закладку2 на текст ШаблонВорд.Bookmarks("Закладка2").Select(); ШаблонВорд.Application.Selection.TypeText("Текст для закладки №2."); //Заменяем закладку3 на текущую дату ШаблонВорд.Bookmarks("Закладка3").Select(); ШаблонВорд.Application.Selection.TypeText(ТекущаяДата()); ОбъектВорд.Application.Visible = Истина; ОбъектВорд.Activate(); //Закрытие документа //ОбъектВорд.Application.Quit(); КонецФункции

В результат запуска внешней обработки 1С по формированию печатной формы на основе шаблона в виде файла Word, мы получим следующий результат:

Информацию по методам COM объекта Word, а так же дополнительные данные можно узнать из MSDN .

Дополнение к заметке Использование шаблонов Word в 1С

Выражаю благодарность, всем тем, кто комментирует запись, благодаря вам, материал дополняется новыми данными и будет полезен более широкому кругу посетителей.

1. А как поменять размер шрифта во вставляемом тексте?
Достаточно изменить размер шрифта закладки, в шаблоне. А вот, если необходимо динамически менять размерность, тогда:

//Заменяем закладку3 на текущую дату ШаблонВорд.Bookmarks("Закладка3").Select(); ШаблонВорд.Application.Selection.Font.Bold = 1; ШаблонВорд.Application.Selection.Font.Size = 20; ШаблонВорд.Application.Selection.TypeText(ТекущаяДата());

2. Картинки есть возможность выгружать в шаблон?
Да, конечно. Примеры для C# и VB описаны по ссылке: https://msdn.microsoft.com/ru-ru/library/ms178792.aspx , а для 1С код будет следующий:

// Вставка изображения ШаблонВорд.Bookmarks("Закладка3").Select(); ШаблонВорд.Application.Selection.InlineShapes.AddPicture("C:\Users\Константин\Desktop\logo_1c.png");

3. При выполнении кода: ОбъектВорд.Documents.Add(«C:/Шаблон.docx») (туда я поместил Ваш документ) получаю ошибку: «Ошибка при вызове метода контекста (Add)» в чем может быть причина?
Может попробовать изменить путь на: «C:\Шаблон.docx».

4. Подскажите пожалуйста еще почему при сохранении макета типа active document в файл word кодом:

ОбработкаОбъект = РеквизитФормыВЗначение("Объект"); Макет = ОбработкаОбъект.ПолучитьМакет("ШаблонПисьмаПросрочка"); ИмяФайла = КаталогВременныхФайлов() + "\"файл.doc"; Макет.Записать(ИмяФайла);

Я получаю вместо нормального документа вот такой http://prntscr.com/eshgjk
Предполагаю, что метод Записать(,) по умолчанию, записывает файл в формате MXL. Попробуйте вторым параметром установить значение: ТипФайлаТабличногоДокумента.DOCX, более подробно описано в «Синтакс-помощнике».

5. У меня в документе есть ссылки на файлы которые расположены на сетевом диске. Как в шаблоне сделать гиперссылку на эти файлы?
Интересный вопрос, если попробовать сделать запись макроса и посмотреть результат, то в Visual Basic добавление гиперссылки будет выглядеть следующим образом:

Sub Макрос1() " " Макрос1 Макрос " " Selection.MoveLeft Unit:=wdCharacter, Count:=15, Extend:=wdExtend ActiveDocument.Hyperlinks.Add Anchor:=Selection.Range, Address:= _ "C:\Users\Константин\Desktop\Тест.txt", SubAddress:="", ScreenTip:="", _ TextToDisplay:="ТестоваяСсылка" End Sub

Описание метода добавления в MSDN: https://msdn.microsoft.com/en-us/vba/word-vba/articles/hyperlinks-add-method-word

Соответственно код для 1С следующий:

Функция ЗаполнитьШаблонВорд() //Попытка создать COM объект Попытка ОбъектВорд = Новый COMОбъект("Word.Application"); Исключение Сообщить("Ошибка при запуске Microsoft Word: " + ОписаниеОшибки(), СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; //Путь к шаблону ОбъектВорд.Documents.Add("C:\Users\k.blagin\Desktop\Шаблон.docx"); ШаблонВорд = ОбъектВорд.ActiveDocument; //Получаем все ссылки из шаблона Для каждого ЗакладкаВорд Из ШаблонВорд.Hyperlinks Цикл Сообщить(ЗакладкаВорд.Name); КонецЦикла; //Меняем адрес уже существующей ссылки ШаблонВорд.Hyperlinks("Logs.zip").Address = "C:\Users\k.blagin\Desktop\Memory.zip"; //Заменяем закладку на ссылку ОбъектЗакладка = ШаблонВорд.Bookmarks("Закладка3"); ШаблонВорд.Hyperlinks.Add(ОбъектЗакладка.Range, "C:\Users\k.blagin\Desktop\Шаблон.docx", "", "Шаблон.docx", "C:\Users\k.blagin\Desktop\Шаблон.docx"); ОбъектВорд.Application.Visible = Истина; ОбъектВорд.Activate(); //Закрытие документа //ОбъектВорд.Application.Quit(); КонецФункции

← Вернуться

×
Вступай в сообщество «passport13.com»!
ВКонтакте:
Я уже подписан на сообщество «passport13.com»