User Rating: 5 / 5

Star ActiveStar ActiveStar ActiveStar ActiveStar Active
 

Добрый день.

В предыдущей статье мы создавали шаблон печатной формы для управляемого приложения. Он у нас выводил простую фразу "Привет мир" в табличный документ. На базе того образца можно создавать печатные формы формирующие табличные документы. Однако как известно они обладаю рядом ограничений и неудобств. Перечислю те, которые мне известны:

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

2. Плохо переносятся крупные ячейки. Если ячейка

не влезает на текущую страницу целиком, она начнется на следующей странице, пополам она не разрежется.

3. Не всегда (особенно в платформе 8.3 в управляемых формах) работает правило шрифтов True Type. Правило "что вижу, то печатаю" в 1С работает плохо, очень часто на экране все помещается в ячейку, на бумаге обрезается, и наоборот, на экране вылезает за границы, на бумаге все ок.

4. Редактировать полученный табличный документ средствами 1С - неудобная задача. Требуется сохранение в другой формат.

5. Следствие пункта "4" - сохранение в Excel не всегда происходит один к одному. Все же mxl и xls - разные форматы.

И тут приходит в голову мысль, а что если выводить на экран не табличный макет, а документ Microsof Word, уже заполненный нужными данными!

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

Ну что, приступим?

Шаг первый - смотрим предыдущую статью и берем от туда образец.

Шаг второй - подготавливаем шаблон документа.

Тут я Вам хучу предложить технологию работающую через переменные документа DocVariable. Для начала открываем MS Word пишем в нем текст нашего договора. В моем примере это будет трудовой договор состоящий из одного абзаца.

Подготовка шаблона печатной формы в MS Word

После составления самого договора, будем определяться с тем, что у нас будет заполняться в нем само. Т.е. выявлять переменную часть документа. Предлагаю печатать договор из справочника сотрудники. В качестве номера договора будем печатать табельный, в качестве даты - дату приема. Так же выведем ФИО принимаемого сотрудника, краткое название организации и полное. Я на картинке красным выдели то, что мы превратим в переменные.

Определяемся с переменными

Начинаем размещать переменные. Убираем номер договора и добавляем на его место переменную. Для этого меню вставка/ экспресс блоки / поле

Создаём DocVariable в шаблоне печатной формы для 1С

В открывшемся окне выбираем тип поля DocVariavle и присваиваем ему осмысленное латинское имя tabelNum. Жмем ОК.

Создаем переменную документа (docVariable) для дальнейшего заполнения в 1С

На экране Вы скорее всего ничего не увидите, но не спешите повторять операцию!!! Просто у Вас режим не отображающий коды полей. Для того, чтобы увидеть код поля нажмите Alt + F9.

Отобразить коды полей Alt + F9

Таким макаром мы заменяем весь красный текст переменными документа.

Все готово для Внешняя печатная форма открывающая документ Microsof Word для управляемых приложений

Шаг третий - создание макета.

Теперь сохраняем файл на диск и возвращаемся в 1С. В обработке грохаем наш макет со словами "Привет мир". Добавляем новый макет с типом "двоичные данные" и грузим в него наш документ MS Word. Не забудьте закрыть документ в ворде, а то 1С и Word ругануться на совместный доступ к файлу.

Создаем макет во внешней обработке в 1С на основе файла MS Word

Шаг четвертый - программируем.

Лезем в модуль обработки. Тут есть нюанс, который надо знать. Команда печати выполняется на клиенте, а получаем данные мы на сервере. На сервере у нас нет приложения MS Word, которым мы создадим документ, соответсвенно документ мы формируем на клиенте. Так же мы не выводим табличный документ. Подумав об этих нюансов кидаемся в бой.

Первым делом стираем процедуру печати из модуля обработки и процедуру формирования макета. После этого открываем процедуру СведенияОВнешнейОбработке() и правим строку с добавлением команды следующим образом:

ДобавитьКоманду(ТаблицаКоманд, "Привет мир", "Макет", "ВызовКлиентскогоМетода", Истина, "");

Так же правим привзку внешней печатной формы:

МассивНазначений.Добавить("Справочник.Сотрудники");

И отключим безопасный режим, т.к. внешние компоненты в безопасном режиме не доступны:

ПараметрыРегистрации.Вставить("БезопасныйРежим", ЛОЖЬ); 

Теперь закрываем модуль обработки и добавляем в обработку основную форму. Переходим в модуль формы.

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

&НаСервере
Функция ПолучитьДанные(Сотрудник)
 Запрос = Новый Запрос("ВЫБРАТЬ
                       | Сотрудники.Код КАК Табельный,
                       | ПриемНаРаботу.ДатаПриема КАК Дата,
                       | ПриемНаРаботу.Организация.НаименованиеПолное КАК ОргДлинно,
                       | ПриемНаРаботу.Организация.НаименованиеСокращенное КАК ОргКртако,
                       | ФИОФизическихЛицСрезПоследних.Фамилия,
                       | ФИОФизическихЛицСрезПоследних.Имя,
                       | ФИОФизическихЛицСрезПоследних.Отчество
                       |ИЗ
                       | Справочник.Сотрудники КАК Сотрудники
                       |  ЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриемНаРаботу КАК ПриемНаРаботу
                       |  ПО (ПриемНаРаботу.Сотрудник = Сотрудники.Ссылка)
                       |   И (ПриемНаРаботу.Проведен)
                       |  ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ФИОФизическихЛиц.СрезПоследних КАК ФИОФизическихЛицСрезПоследних
                       |  ПО Сотрудники.ФизическоеЛицо = ФИОФизическихЛицСрезПоследних.ФизическоеЛицо
                       |ГДЕ
                       | Сотрудники.Ссылка = &Ссылка");
 Запрос.УстановитьПараметр("Ссылка", Сотрудник);
 рез = Запрос.Выполнить();
 выб = рез.Выбрать();
 Если выб.Следующий() Тогда
  стр = Новый Структура("Табельный,Дата,ОргКртако,ОргДлинно,ФИО");
  ЗаполнитьЗначенияСвойств(стр, выб);
  стр.ФИО = СокрЛП(выб.Фамилия) + " " + СокрЛП(выб.Имя) + " " + СокрЛП(выб.Отчество);
  Возврат стр;
 Иначе
  Возврат Неопределено;
 КонецЕсли;
КонецФункции

Комментировать тут нечего, все должно быть понятно. Суем сотрудника, получаем структуру. Просьба сильно не критиковать запрос, цель урока не правильно получать данные в ЗУП 3.0, а научиться выводить документы в MS Word.

Еще нам потребуется получить OLE объект MS Word. Сунуть ему наш шаблон и заполнить в нем переменные. Шаблон мы можем получить только в контектсте сервера, поэтому пишем короткую серверную функцию:

 &НаСервере
Функция ПолучитьМакетСервер()
 Возврат РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
КонецФункции

Ну теперь пишем процедуру печати. 

Процедура Печать(ИдентификаторКоманды, МассивОбъектов) Экспорт
 Для Каждого сотрудник Из МассивОбъектов Цикл
  Данные = ПолучитьДанные(сотрудник);
  Если данные <> Неопределено Тогда
   Word = Новый COMОбъект("Word.Application");
   Макет = ПолучитьМакетСервер();
   временныйПуть = КаталогВременныхФайлов();
   имяВременногоФайла = временныйПуть + "gph.doc";
   Макет.Записать(имяВременногоФайла);
   ТекДок = Word.Documents.ADD(имяВременногоФайла);
   
   
   ТекДок.Variables("tabelNum").Value=Данные.Табельный;
   ТекДок.Variables("orgNameS").Value=Данные.ОргКртако;
   ТекДок.Variables("DocDate").Value=Данные.Дата;
   ТекДок.Variables("fio").Value=Данные.ФИО;
   ТекДок.Variables("orgNameLong").Value=Данные.ОргДлинно;
   
   
   ТекДок.Fields.Update();
   Word.ActiveWindow.View.ShowFieldCodes = False;
   Word.Visible=Истина;
  КонецЕсли;
 КонецЦикла;
КонецПроцедуры

Прокомментирую её пошагово на русском языке:

1. Получаем данные

2. Если данные получены выполняем алгорим формирования

3. Создаем COM объект MS Word

4. Получаем макет

5. получаем каталог временных файлов

6. Сохраняем туда наш макет под произвольным именем

7. Создаем документ MS Word указывая в качестве параметра Template наш макет.

8-12. Заполняем переменные документа данными

13. Обновляем поля документа

14. Прячем коды полей (аналог Alt + F9)

15. Показываем (наверное лишнее, т.к. команда add уже сделал его видимым по умолчанию)

 

Вот и все. Спасибо за внимание жду вопросов в комментах.

 

Авторизуйтесь пожалуйста

Comments   

+2 # Дмитрий 2014-07-15 12:06
Добрый день. Спасибо за статью, но уж больно это сложно - создавать переменные в вордовском документе. Мне больше нравится через поиск и замену по ключевым полям. Ставим в документе какую-нибудь ключесвую краказябру, а в 1С меняем её на нужный текст.
+1 # Антон Филоненко 2014-07-15 12:15
Насчет предпочтений - спорный вопрос, каждому свое. На Вашей стороне скорость создания шаблона, на моей четкое отличие переменных от фиксированного текста.
Наверное, про способ замены в MS Word можно написать отдельную статью.
+6 # Дмитрий 2014-07-15 12:18
Скорость создания шаблона - не самое главное. Метод замены можно реализовать и в ворде и в опен офисе, а вот это уже так сказать МЕГА плюс
0 # Антон Филоненко 2014-07-16 13:02
Добавлена новая статья по теме
http://prosto1s.ru/index.php/24-pechat-v-word-chast-2-metod-zameny-tegov-klonirovanie-abzatsev-stok-tablitsy
0 # сергей 2015-04-15 11:06
Добрый день! а для 1с8.2 УПП подойдет?
0 # Антон Филоненко 2015-04-15 11:23
Логика заполнения документа WORD подойдет для чего угодно. Но в целом, если смотреть предыдущую статью, то я рассказываю о внешних формах для новых редакций на управляемых формах (ЗУП 3.0, бух 3.0 ERP).
т.е. статья http://prosto1s.ru/index.php/3-auto-generate-from-title - вам не подойдет
а текущая не привязана к конфе и платформе
+4 # сергей 2015-04-15 12:17
Выложите пожалуйста обработку А то я пытался сделать договор поставки ну никак не получается. Запускаю обработку, а она даже по коду не проходит в отладке!
0 # Антон Филоненко 2015-04-16 13:36
Вам нужен образец для обычного приложения или для управляемого?
0 # Рашид 2016-02-27 23:04
для управл плиз
0 # Антон Филоненко 2016-02-29 07:09
Quoting Рашид:
для управл плиз

попробуйте все внимательно прочитать и делать как написано, все должно получиться, проверено :)
цель статьи научить, а не дать Вам готовое решение, чтобы Вы заработали денег так и не разобравшись в вопросе.
0 # Рашид 2016-02-27 23:05
выходит такая ошибка - {ВнешняяОбработ ка.ОбразеПечати .МодульОбъекта( 103,10)}: Процедура или функция с указанным именем не определена (РеквизитФормыВ Значение)
Возврат
+1 # Антон Филоненко 2016-02-29 07:07
Привет.
Вы написали код в модуле объекта, а все надо делать в форме обработки. Вот цитат из статьи, которую Вы пропустили:
Quote:
Теперь закрываем модуль обработки и добавляем в обработку основную форму. Переходим в модуль формы.
Образец тут не требуется, т.к. копипастя сами не научитесь. Поэтому я не всегда прилагаю образцы обработок.
0 # Андрей 2016-12-01 16:04
Здравствуйте.
А как можно поменять размер текста в вставках?
Очень нужно.
0 # Антон Филоненко 2016-12-02 06:56
Здравствуйте. В данном методе "вставки" не используются, есть другой метод, где используется буфер обмена в паре с поиском и заменой вхождений. Он описан в другой статье. Там можно что-то придумать с изменением шрифта, например выделить символы с N по M и задать им форматирование.
Тут мы просто переменным документа задаем текстовое значение, без формата и формат определяется форматом шрифта самой переменной.
0 # Владимир 2017-02-20 14:41
Добрый день, Антон.
Сделал всё, как описано. Всё здорово, всё выводится, за исключением одного: контактная информация по контрагенту (юр. адрес, факт.адрес, телефон, эл.почта, которые хранятся в табличной части КонтактнаяИнфор мация справочника Контрагенты. Их можно вытянуть дополнительным циклом по выборке контактной информации из результатов запроса по Контрагентам).
С выводом табличного документа - вопросов нет, а как это реализовать в случае выгрузки данных для печати в Структуру?
Конфигурация Комплексная автоматизация-2 .2.2.199
0 # Антон Филоненко 2017-02-21 05:12
Здравствуйте.
На самом деле сложно сходу помочь, т.к. непонятно как вы получаете информацию по контрагенту.
Если вы работаете запросом, то в запросе , который получает данные шапки документа левым соединением привяжите табличную часть с КИ контрагента столько раз сколько информации вам нужно. Нужно два адреса - привязываем две таблицы.
В связях указываем контрагент = ссылка, тип КИ = &НужныйТип, ВидКИ = &НужныйВид. И из каждой привязаной таблицы тащим поле "представление" назначая ему соответсвующий псевдоним.

Если вы работаете с объектной моделью, то создаете структуру:
данные = Новый Структура("Ки1,Ки2,Ки3)
Для Каждого стрКи Из Контр.КИ Цикл
Если стрКи.Тип = тип1 И стрКИ.Вид = вид1 Тогда
данные.КИ1 = стрКи.Предствал ение;
ИначеЕсли....
КонецЦикла;
0 # Владимир 2017-02-21 06:24
Quoting Антон Филоненко:

Если вы работаете с объектной моделью, то создаете структуру:
данные = Новый Структура("Ки1,Ки2,Ки3)
Для Каждого стрКи Из Контр.КИ Цикл
Если стрКи.Тип = тип1 И стрКИ.Вид = вид1 Тогда
данные.КИ1 = стрКи.Предстваление;
ИначеЕсли....
КонецЦикла;

Спасибо, Антон.
Я, в общем-то, так и делал, но из-за того, что писал не "данные.КИ1 =", а просто "КИ1 = ", получал ошибку.
Теперь всё работает замечательно!
Большое спасибо!
0 # Владимир 2017-02-28 10:07
Антон, здравствуйте.
Еще одна проблема возникла:
Все данные вытягиваются корректно, но при запуске обработки в клиент-серверно м режиме выскакивает ошибка:
"{ВнешняяОбработка.ПФПартнерскоеСоглашение.Форма.Форма.Форма(74)}: Ошибка при вызове метода контекста (Add)
ТекДок = Word.Documents.ADD(имяВременногоФайла);
по причине:
Произошла исключительная ситуация (Microsoft Word): Ошибка в Word."
С чем это может быть связано и как с этим бороться?
Перезагрузка не помогла, Word открывается и дает в нем работать нормально.
В файловом варианте базы - работает.
Спасибо
0 # Антон Филоненко 2017-02-28 12:36
Quoting Владимир:

ТекДок = Word.Documents.ADD(имяВременногоФайла);


Если ругается только в серверной базе надо думать чем отличается контекст сервера от клиента.

Первое на что следует обратить внимание, где эта строка кода расположена? В статье я писал, что это клиентская процедура (&НаКлиенте), а значит разницы быть не должно файловая или не файловая.

Второе, я бы посомтрел что за путь в переменной "имяВременногоФ айла", существует ли он там и есть ли у пользователя винды права на этот каталог. Добавьте строку кода Сообщить(имяВре менногоФайла) перед этой строкой.

Третье, я бы убедился, что файл в макете является документом word и формат соответсвует расширению (doc и docx - разные форматы)
0 # Владимир 2017-02-28 14:46
Quoting Антон Филоненко:
Quoting Владимир:

ТекДок = Word.Documents.ADD(имяВременногоФайла);


Если ругается только в серверной базе надо думать чем отличается контекст сервера от клиента.

Первое на что следует обратить внимание, где эта строка кода расположена? В статье я писал, что это клиентская процедура (&НаКлиенте), а значит разницы быть не должно файловая или не файловая.

Да, действительно, не была указана директива &НаКлиенте.
Спасибо!
Остался один вопрос: как добавить в структуру данные из второй структуры (в которой собраны данные из табличной части КонтактнаяИнфор мация справочника Контрагенты).
Пробовал так:
Для Каждого Элт Из контакт Цикл
стр.Вставить(Эл т.Ключ, Элт.Значение);
КонецЦикла;
но что-то данные из второй структуры не выводятся
0 # Владимир 2017-03-01 10:23
Разобрался. Вопрос снимаю. Всё работает
0 # Владимир 2017-03-30 12:36
Антон, спасибо! Всё отлично работает!
Подскажите, пожалуйста, как заставить заполненный шаблон открываться поверх окна 1С.
По умолчанию открывается где-то позади, что не очень нравится пользователям.
Спасибо!
0 # Владимир 2017-03-31 14:20
Quoting Владимир:
Антон, спасибо! Всё отлично работает!
Подскажите, пожалуйста, как заставить заполненный шаблон открываться поверх окна 1С.
По умолчанию открывается где-то позади, что не очень нравится пользователям.
Спасибо!

Вопрос снят. Решено