Заполнение полей шаблонов документов средствами Word

19 39

На написание данного материала меня натолкнул вопрос Антона Максунова заданный им на форуме Как можно вставлять в шаблон логотип компании? Процитирую сам вопрос:

Есть задача - надо переписку между нашими компаниями перевести в рамки шаблонов в Directum. У всех компаний разный логотип и он обязательно должен быть в письмах. В связи с этим несколько вопросов:

  1. можно ли хранить в справочнике изображение?
  2. можно ли такое изображение передавать в карточку ЭД?
  3. можно ли из карточки ЭД вставлять не просто поле, а это изображение?

Если это слишком сложный путь, то может кто подскажет другое решение?

Немного поразмыслив, я подумал, а почему бы не реализовать какой-нибудь готовый вспомогательный механизм, который позволит при разработке шаблонов документов использовать возможности объектной модели Word, при этом избавит от необходимости изучения нюансов взаимодействия Directum и Word. Как говориться, дело было вечером, делать было нечего и в результате родилось что-то наподобие технического решения, которое будет описано ниже.

Само решение состоит из следующих компонент:

RITWordTemplate - справочник шаблонов документов Word;

RITOrgLogo - справочник логотипов "Наших организаций";

RITGenerateEDocFromWordTemplate(EDocument: Вариантный; VersionNumber: Целое число; WTCode: Строка) - функция заполнения полей в документе Word, где 

EDocument - объект типа IEDocument, документ, в котором мы хотим заполнить поля;

VersionNumber - версия электронного документа, в которой необходимо заполнить поля;

WTCode - код записи справочника RITWordTemplate, в котором содержатся имена полей и их вычисления.

RITGetWordTemplateFieldValue(EDocID: Целое число; CalculateText: Строка) - функция вычисления значения поля документа, где

EDocID - ИД документа, для которого выполняется вычисление значения полей;

CalculateText - текст вычисления значения поля.

RITTestCreateEDocFromWordTemplate - сценарий примера использования данного решения.

Справочник RITWordTemplate выглядит так:

Карточка записи справочника RITWordTemplate:

Назначение реквизитов карточки понятно из их заголовков.

По кнопке Шаблон можно открыть для просмотра или изменения шаблон документа, указанный в реквизите "Шаблон электронного документа":

По кнопке Просмотр можно посмотреть результат заполнения полей шаблона:

В табличной части записи справочника RITWordTemplate задаются имена полей шаблона и вычисления для этих полей на языке ISBL. Результат вычисления необходимо вернуть в строковой переменной Result. В вычислениях доступна предопределенная переменная EDocument, с помощью которой можно обращаться к реквизитам карточки документа. Для полей, в которые нужно будет вставить картинку, необходимо установить реквизит "Картинка" в значение "Да". Для таких полей результат вычисления должен возвращать путь до картинки (другого способа вставки картинки в документ я не нашел). Путь может быть как локальный, так и сетевой (у пользователя должен быть доступ к сетевой папке, где хранятся картинки, на чтение). Поля, для которых не задано вычисление, пропускаются (для примера, поле [Тема] на скриншотах). Если результат вычисления будет пустая строка, то такие поля тоже заполняться не будут.

Для поля [Должность подписанта] вычисление выглядит так:

Для поля [Логотип] вычисление выглядит так:

Пример использования:

  TypeKode = "ПЭА"
  KindCode = "Г000043"
  TemplateCode = "Д000066"
  EDocument = EDocuments.CreateNewFromTemplate(TypeKode; KindCode; TemplateCode)
  EDocument.ISBEDocName = "Документ из тестового шаблона"
  EDocument.Save()
  RITGenerateEDocFromWordTemplate(EDocument;;"Д000005")
  EDocument.Open(True; -1)

Бонусом к решению добавлен справочник логотипов организаций RITOrgLogo:

Карточка записи справочника RITOrgLogo:

С помощью этого справочника можно хранить логотипы наших организаций и потом их использовать в вычислениях на ISBL или вставлять в шаблоны документов.

В итоге мы получили:

  1. Возможность вставлять значения текстовых реквизитов в поля шаблонов документов размером более 255 символов.
  2. Возможность вставлять картинки в шаблоны документов.
  3. Возможность "вешать" вычисления на поля шаблонов документов.
  4. Возможность заполнить поле шаблона документа не только значением из карточки документа.
  5. И много чего еще :)

Разработка велась в версии DIRECTUM 4.6.1. В 4.7 тоже проверял, все работает. Ниже прилагаю архив с самой разработкой. Структура архива:

  1. Dev - папка с разработкой.
  2. Ref - папка с записями справочников для примера.
  3. Шаблон для тестирования (110124 v1).DOC - шаблон документа, на котором я все это тестировал. 

WordTemplate.zip (153,46 Кб)

-------------------------------------------------------------------------------------------

Решение обновилось до версии 2.0

Список изменений:

1. Карточка записи справочника RITWordTemplate теперь выглядит так:

2. При выборе Вида электронного документа в реквизите Тип карточки доступны для выбора типы карточек только для данного вида электронного документа. Если доступен только один вид карточки, то он подставляется автоматически.

3. При выборе Вида электронного документа в реквизите Шаблон электронного документа доступны для выбора шаблоны только для данного вида электронного документа. Если доступен только один шаблон, то он подставляется автоматически.

4. Добавился реквизит Запоминать реквизиты. Если реквизит установлен в значение "Да", то будут запоминаться значения реквизитов, которые указываются при заполнении карточки, что избавляет от постоянного заполнения карточки документа при тестировании шаблона. Для каждой записи справочника RITWordTemplate запоминается свой набор значений реквизитов. Т.к. значения реквизитов хранятся в окружении, они будут храниться, пока не будет закрыт справочник RITWordTemplate.

5. Добавился реквизит Удалять временные документы. Если реквизит установлен в значение "Да", то при каждом просмотре шаблона (по кнопке Просмотр) будет удаляться временный документ, созданный при предыдущем просмотре. Если вам мешает то, что перед следующим просмотром, предыдущий временный документ, созданный из шаблона, надо закрыть (иначе его не получится удалить), то установите реквизит в значение "Нет". В этом случае вы можете потом после отладки шаблона удалить все временные документы, созданные во время отладки шаблона, по кнопке Эл.документы.

6. Добавилась кнопка Эл.документы. По этой кнопке отображается список всех временных документов, которые создавались во время тестирования шаблона. Вы можете их после отладки удалить или произвести с ними какие-либо другие действия.

7. Добавилась функция RITGenerateEDocFromWordTemplateFieldsList(EDocument: Вариантный; VersionNumber: Целое число; FieldsList: Вариантный) - функция заполнения полей в документе Word, где

EDocument - объект типа IEDocument, документ, в котором мы хотим заполнить поля;

VersionNumber - версия электронного документа, в котором необходимо заполнить поля;

FieldsList - список полей и их значений типа IList, которые необходимо заполнить в документе. В списке значений в Name заносится имя поля, в Value массив вида (Значение_поля; Признак_картинки).

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

  RECORDS_DOES_NOT_EXIST = 0
  FIRST_WORKER_INDEX = 0
  if Job.ExecutionResult.Code = 1
    // Получим ИД документа из параметров задачи
    DocID = ТМПолучитьПараметрЗадачи('ИДПНК')
    EDoc = EDocuments.GetObjectByID(DocID)
    // Добавим подпись руководителя и дату подписания
    Performer = Job.Info.Performer
    WorkerCodeList = GetEmployeesByUserID(Performer.ID)
    if WorkerCodeList.Count > RECORDS_DOES_NOT_EXIST
      WorkerCode = WorkerCodeList.Values(FIRST_WORKER_INDEX)
      Worker = References.РАБ.GetObjectByCode(WorkerCode)
      FieldsList = CreateList()
      if Assigned(Worker.Requisites('Текст').AsString)
        FileName = Worker.SYSREQ_NAME & '.' & Worker.Requisites('Текст').Extension
        Path = GetTempFolder()
        FileName = Path & FileName
        Worker.Requisites('Текст').SaveToFile(FileName)
        FieldsList.Add('[Подпись2]'; ArrayOf(FileName; YES_VALUE))
      endif
      FieldsList.Add('[Дата2]'; ArrayOf(ToDay(); NO_VALUE))
      RITGenerateEDocFromWordTemplateFieldsList(EDoc; ; FieldsList)
      FieldsList = nil
    endif
  endif

8. Исправлено много мелких ошибок, выявленных в ходе тестирования решения.

Разработка тестировалась в версиях DIRECTUM 4.6.0, 4.6.1, 4.7.0.

WordTemplate_ver2.zip (100,63 Кб)

P.S. данный механизм удобно использовать при разработке и тестировании шаблонов и с использованием стандартной интеграции DIRECTUM с MS Office. По крайней мере вы будете избавлены от необходимости выполнять действия по созданию шаблона и заполнению реквизитов карточки документа при тестировании шаблона. Сейчас все гораздо проще:

1. Нажал кнопку "Шаблон" - поправил шаблон и сохранил его.

2. Нажал кнопку "Просмотр" - посмотрел результат. 

 

Елена Питомцева

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

Антон Максунов

Не хватает тяму понять что и куда, новый реквизит добавить не могу =) Если честно даже не понял причину ошибки http://savepic.org/1964769.jpg

Дмитрий Тарасов

А шаблон точно вордовский? Вичисления для поля [Лого] есть? В сам шаблон поле [Лого] добавлено? И если добавлено то как?

Дмитрий Тарасов

Я такую ошибку повторить не смог, даже с чистым документом без полей. И еще, у вас действительно есть Вид документа "Документы произвольной формы"? Если есть, то у него указан тип карточки и доступные шаблоны?

Дмитрий Тарасов

А Word вообще установлен на том компьютере, на котором проверяете? :)

Дмитрий Тарасов

Еще хотелось бы взглянуть на сам шаблон.

Антон Максунов

Сейчас взял готовый шаблон "шаблон для тестирования", готовую вашу запись в шаблонах, ошибка осталась.

Дмитрий Тарасов

В списке процессов ворд не болтается?

Антон Максунов

Болтается, я параллельно шаблоны уже делаю )

Антон Максунов

Убил несколько висящих процессов, запустил. Опять ошибка и висящий процесс.

Дмитрий Тарасов

В командной строке выполнить: dcomcnfg

В открывшемся окне выбрать Службы компонентов -> Компьютеры -> Мой компьютер-> правой кнопкой мышки -> свойства -> Закладка "Свойства по умолчанию" -> Проверить что стоит галочка "Разрешить использование DCOM на этом компьютере"; Закладка "Безопасность COM" -> Раздел "Права доступа" -> кнопка "Изменить настройки по умолчанию" -> Добавьте себя и поставьте обе галки; Раздел "Разрешения на запуск и активацию" -> кнопка "Изменить настройки по умолчанию" -> Добавьте себя и поставьте все 4 галки  

Дмитрий Тарасов

И если еще есть антивирус, то его можно попробовать временно отключить, чтобы убедиться что это не он мешает.

Антон Максунов

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

Дмитрий Тарасов

А офис какой стоит? Я тестировал на 2003 и 2007. Еще я забыл в функции RITGenerateEDocFromWordTemplate в конце добавить WordApp = nil

...
WordDoc.Close
WordApp.Quit
WordApp = nil

 

Антон Максунов

Офис 2007. Исправление внес, ошибка та же ) Еще, кстати, ворд пишет "неверно указана единица измерения"

Дмитрий Тарасов

Это он в какой момент пишет?

Антон Максунов

Ошибка ворда и через секунду ошибка директума. Её из под ошибки директума не видно вот и забыл сказать.

Дмитрий Тарасов

Попробуй создать файл TestWord.vbs с таким содержимым:

Set objWord = CreateObject("Word.Application")
objWord.Caption = "Test Caption"
objWord.Visible = True

Set objDoc = objWord.Documents.Add()
Set objSelection = objWord.Selection

objSelection.Font.Name = "Arial"
objSelection.Font.Size = "18"
objSelection.TypeText "Тестовый документ"
objSelection.TypeParagraph()

objSelection.Font.Size = "14"
objSelection.TypeText "Количество полей = " & objDoc.Fields.Count
objSelection.TypeParagraph()
objSelection.TypeParagraph()

objDoc.SaveAs("C:\testdoc.doc")
objWord.Quit

 

Set objWord = CreateObject("Word.Application")
objWord.Caption = "Test Caption"
objWord.Visible = True

Set objDoc = objWord.Documents.Add()
Set objSelection = objWord.Selection

objSelection.Font.Name = "Arial"
objSelection.Font.Size = "18"
objSelection.TypeText "Тестовый документ"
objSelection.TypeParagraph()

objSelection.Font.Size = "14"
objSelection.TypeText "Количество полей = " & objDoc.Fields.Count
objSelection.TypeParagraph()
objSelection.TypeParagraph()

objDoc.SaveAs("C:\testdoc.doc")
objWord.Quit

и запусти его. Должен появиться файл  C:\testdoc.doc

Антон Максунов

"неверно указана единица измерения"

документ с содержанием "тестовый документ, количество полей = 0"

зависший процесс ворда.

Дмитрий Тарасов

А в в панели управления - язык и региональные стандарты - Языковые стандарты и форматы стоит "Русский"?  Там же расположение стоит Россия? По кнопке настройка разделитель целой и дробной части стоит запятая или точка (должна быть запятая)?

И еще гугл выдал:

Исправление ошибки "Неверно указана единица измерения" в Microsoft Word 2007

Если в Microsoft Word при изменении межстрочного интервала возникает ошибка "Неверно указана единица измерения", то нужно скачать и установить исправленную библиотеку WWINTL.DLL (http://spisok-literaturi.ru/filez/WWINTL.RAR)

Так же устраненяется некорректное отображение настроек.

Установка: файл WWINTL.DLL(с заменой) скопировать в *:\Program Files\Microsoft Office\Office12\1049.




 

Дмитрий Тарасов

Проблему с Word-ом решили. Если у кого-то такая же проблема "неверно указана единица измерения" (ошибка никак не связана с разработкой и присутствует в самом "криво" русифицированном офисе 2007), то вам поможет это:

Исправление ошибки "Неверно указана единица измерения" в Microsoft Word 2007 Если в Microsoft Word при изменении межстрочного интервала возникает ошибка "Неверно указана единица измерения", то нужно скачать и установить исправленную библиотеку WWINTL.DLL (http://spisok-literaturi.ru/filez/WWINTL.RAR) Так же устраненяется некорректное отображение настроек. Установка: файл WWINTL.DLL(с заменой) скопировать в *:\Program Files\Microsoft Office\Office12\1049.

Придумал как мне избавиться от 1-го пункта в разделе "Что мне не нравится в текущей реализации". Идею подсказала жена :))))))
Также хочу добавить проверку на то, что ворд вообще установлен.
Как реализую, выложу свежую разработку.
Дмитрий Тарасов

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

Ирина Оносова

Здравствуйте. Очень полезной оказалась Ваша разработка. Подскажите, пожалуйста, почему может быть такая ошибка?

Ирина Оносова

Ирина Оносова

http://imglink.ru/show-image.php?id=16981606b48e430c2ac82d4566c157eb

Дмитрий Тарасов

Попробуйте перезапустить сервер сеансов.

Ирина Оносова

Спасибо. Решение нашла, изменив немного код в функции "RITGenerateEDocFromWordTemplate".А именно строчку 37 поправила на: WTRecord = References.ReferenceFactory('RITWordTemplate').GetObjectByCode(WTCode).

Ирина Оносова

Теперь у меня по функции "RITGenerateEDocFromWordTemplateFieldsList" возник вопрос. Для понимания ее работы упростила пример сценария до:

EDoc = EDocuments.GetObjectByID(136932) // документ, созданный на основе шаблона

      FieldsList = CreateList()

      FieldsList.Add('[дата]'; ArrayOf(ToDay(); NO_VALUE))
      RITGenerateEDocFromWordTemplateFieldsList(EDoc; ; FieldsList)
      FieldsList = nil

всё проходит без ошибок, но с файлом ничего не происходит. Подскажите, пожалуйста, что я делаю не так? Может нужно брать файл самого шаблона?

 

Ирина Оносова

работаю в 4.7.

Дмитрий Тарасов
Спасибо. Решение нашла, изменив немного код в функции "RITGenerateEDocFromWordTemplate".А именно строчку 37 поправила на: WTRecord = References.ReferenceFactory('RITWordTemplate').GetObjectByCode(WTCode).

Достаточно было просто перезапустить сервер сеансов. Это особенность версии 4.7, после каждого приема новой разработки необходимо перезапускать сервер сеансов, чтобы изменения "подхватились".

Подскажите, пожалуйста, что я делаю не так? Может нужно брать файл самого шаблона?

В документе должно присутствовать поле [дата]. Нужно либо добавить его в этот документ вручную (открыть документ в MS Word и вставить поле через соответствующее меню), либо создать документ на основе шаблона, имеющего поле [дата] и уже потом вызывать данную функцию, чтобы она заполнила это поле передаваемым значением в нужном месте документа. 

 

 

Ирина Оносова

В документе всё есть. Не выходит. ((

Дмитрий Тарасов

Можете мне прислать этот документ, я на него взгляну?

Дмитрий Тарасов

Также интересует версия установленного MS Word.

Дмитрий Тарасов
EDoc = EDocuments.GetObjectByID(136932) // документ, созданный на основе шаблона       FieldsList = CreateList()       FieldsList.Add('[дата]'; ArrayOf(ToDay(); NO_VALUE))       RITGenerateEDocFromWordTemplateFieldsList(EDoc; ; FieldsList)       FieldsList = nil

Т.к. при извлечении значения параметра из списка FieldsList используется метод IndexOfName объекта IList, то имя параметра '[дата]' в списке полей FieldsList, передаваемом функции RITGenerateEDocFromWordTemplateFieldsList, и в документе должны совпадать с точностью до регистра. Т.е. '[Дата]' и '[дата]' - это два разных параметра.

Чтобы было понятно о чем речь, приведу пример небольшого сценария для тестирования работы с методом IndexOfName объекта IList

  TestList = CreateList()
  TestList.Add("ИмяПараметра"; "1")
  TestList.Add("имяпараметра"; "2")
  Index = TestList.IndexOfName("имяпараметра")
  if Index > -1
    ShowMessage(TestList.Values(Index))
  else
    ShowMessage("Параметра с таким именем не существует")
  endif
  TestList = nil

Результат работы сценария:

 

 

Алексей Пестов

А поля после сохранения обновляются, если внести исправления в карточку документа?

Дмитрий Тарасов

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

Только в текущей реализации привязка идет к содержимому поля и если оно уже изменялось, то в качестве имени поля надо будет передать его текущее значение. Если при многократном обновлении полей необходима привязка к имени поля, то разработку необходимо будет доработать. Например, получать имя поля в функциях заполнения полей из свойства Code (а не Result, как в текущей разработке) объекта Field объектной модели MS Word.

Анна Добрук

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

Дмитрий Тарасов

Причина кроется скорее всего тут: "Разработка тестировалась в версиях DIRECTUM 4.6.0, 4.6.1, 4.7.0." 

Попробуйте вот это решение: Заполнение полей шаблонов документов средствами Word, в том числе и из табличной части. оно посвежее будет.

Анна Добрук

Заполнение полей шаблонов документов средствами Word, в том числе и из табличной части. 

При импорте пакета разработки,при заполнении справочника выходит сообщение "Class TSBReferenceRecordCardForm not found",такая же ошибка появляется при просмотре формы

Авторизуйтесь, чтобы написать комментарий