.. _transformation: Transformations микросервис ============================= .. note:: Доступно только в Enterprise версии. Опциональный микросервис **ecos-transformations** для генерации документов по шаблонам, которые можно подгрузить с проектом или добавить через инструменты администратора. .. contents:: :depth: 3 Подключение микросервиса ------------------------- **Микросервис Трансформации (ecos-transformations)** - самостоятельный микросервис, не требующих развертывания дополнительных баз данных (все шаблоны хранятся в БД ecos-model). Для обеспечения работоспособности необходимы: * ecos-model:2.13.0 Параметры подключения через docker-compose.yml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: #=== TRANSFORMATIONS ===# transformations-app-dev: container_name: transformations-app-dev image: nexus.citeck.ru/ecos-transformations:1.0.0 ports: - 8087:8087 environment: - _JAVA_OPTIONS=-Xmx256m -Xms256m - SPRING_PROFILES_ACTIVE=dev,swagger - ECOS_INTEGRATIONS_ONLYOFFICE_HOST=only-office-app - ECOS_WEBAPP_RABBITMQ_HOST=rabbitmq-dev - EUREKA_CLIENT_SERVICE_URL_DEFAULTZONE=http://admin:$${jhipster.registry.password}@ecos-registry:8761/eureka - SPRING_CLOUD_CONFIG_URI=http://admin:$${jhipster.registry.password}@ecos-registry:8761/config - ECOS_INIT_DELAY=0 depends_on: - ecos-registry .. _doc_template: Создание нового шаблона ------------------------ Для работы с новыми шаблонами документов в Citeck есть журнал **"Шаблоны документов" (Рабочее пространство "Раздел администратора" - Трансформации)**: .. image:: _static/transformation/trans_1.png :width: 700 :align: center Существует 2 способа создавать шаблоны документов в системе: 1. Располагая их в проекте в определенной директории. 2. Загрузив их через действие Добавить в журнале Шаблоны документов. Создание шаблона документа в проекте ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Для успешного добавления в систему вашего шаблона необходимо учитывать некоторые вещи: * Вместе с самим шаблонов должен храниться файл ``meta.yml``, который будет хранить метоинформацию о шаблоне. **Особенность наименования файлов:** Если файл шаблона один, то мета-файл называется по шаблону ``${Полное_имя_файла_с_расширением}.meta.yml`` Пример: .. image:: _static/transformation/trans_2.png :width: 200 :align: center Если файлов шаблона несколько в результате разделения их по локализации, то мета-файл именуется по следующему шаблону ``&{Имя_файла_до_указания_локали}.meta.yml`` Пример: .. image:: _static/transformation/trans_3.png :width: 200 :align: center **Структура мета-файла** Мета-файл должен содержать следующие поля в своей структуре: .. list-table:: :widths: 10 50 :header-rows: 1 :class: tight-table * - Поле - Описание * - **id** - | Уникальный идентификатор шаблона в системе .. code-block:: id: test-template * - **engine** - | Наименования движка, который будет обрабатывать заполнение шаблона | Доступные движки: | - ``freemarker`` - для формирования документов в формате docx, txt с обработкой Freemarker. | - ``ecos-table`` - для формирования xlsx таблиц, которые поддерживают обработку Freemarker | - ``none`` - для обработки шаблонов без какой-либо трансформации. Возвращается шаблон как есть. .. code-block:: engine: freemarker * - **name** - | Имя шаблона .. code-block:: name: TestTemplate * - **mimeType** - | Тип файла шаблона .. code-block:: mimeType: application/vnd.openxmlformats-officedocument.wordprocessingml.document * - **model** - | Представляет собой мапу ключ-значение, где в качестве ключа используется атрибут из шаблона, а в качестве значения атрибут, который возмется из карточки. .. code-block:: model: regNumber: registrationNumber regDate: registrationDate|fmt('dd.MM.yyyy') initiator: initiator.firstName | В значениях можно использовать все возможности обращения с атрибутами через :ref:`Records API` * - **computedAttributes** - | Вычисляемые атрибуты модели. | Задается списком атрибутов. | Перед генерацией шаблона преобразует полученные атрибуты в моделе согласно типу преобразования. .. code-block:: computedAttributes: - id: docInvestigationInfo type: html-to-text | См. подробнее :ref:`Вычисляемые атрибуты для шаблонов` * - **tags** - | Список вспомогательных меток где удобного поиска .. code-block:: tags: - Template - Test - Example Пример: .. code-block:: --- id: test-docx-template engine: freemarker name: TestDocxTemplate mimeType: application/vnd.openxmlformats-officedocument.wordprocessingml.document model: modelValue: ?disp * Файлы должны располагаться в проекте по определенному пути. Путь для расположения файлов имеет следующий паттерн: В микросервисе: ``${home_dir}/src/main/resources/eapps/artifacts/transformation/template/`` В старых проектах: ``${module_name}/src/main/resources/alfresco/module/${module_name}/transformation/template/`` В данных директориях вы можете создавать создавать внутреннюю структуру папок. Поиск артифактов шаблонов происходит рекурсивно по папкам, но начинается именно с этих директорий. Создание шаблона через журнал ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Для создания шаблона документа необходимо перейти в журнал **"Шаблоны документов" (Рабочее пространство "Раздел администратора" - Трансформации)** и создать новую запись. .. image:: _static/transformation/trans_4.png :width: 400 :align: center | .. image:: _static/transformation/trans_5.png :width: 600 :align: center Необходимо заполнить следующие поля: .. list-table:: :widths: 5 10 :header-rows: 1 :class: tight-table * - Поле - Описание * - **ID** - Уникальный идентификатор шаблона в системе * - **Имя** - Имя шаблона * - **Движок** - | Наименования движка, который будет обрабатывать заполнение шаблона | (На данный момент существует только Freemarker) * - **Шаблоны** - | Загружается файл шаблона | Шаблон должен быть добавлен в zip архиве. (Так как именно так шаблоны хранятся в базе) | В архиве должен быть файл с шаблоном в формате docx или ftl. Строгих правил к его наименованию нет, но желательно придерживаться общей концепции и называть файл как id шаблона. | Если шаблонов несколько (разделены по локализации), то при названии файлов в конце нужно приписывать суффиксы _ru, _en и т.п. * - **Модель** - Представляет собой мапинг ключ-значение, где в качестве ключа используется атрибут из шаблона, а в качестве значения атрибут, который берется из карточки. * - **Вычисляемые атрибуты** - | Лист объектов с информацией о вычисляемых атрибутах. | См. подробнее :ref:`Вычисляемые атрибуты для шаблонов ` * - **Теги** - | Список вспомогательных меток для удобного поиска | См. подробнее :ref:`Вычисляемые атрибуты для шаблонов ` .. _calculated_attr: Вычисляемые атрибуты для шаблонов ---------------------------------- Вычисляемые атрибуты в метафайле шаблона предназначены для тоже, чтобы совершить какую-то постобработку над значениями, которые пришли в модели, и обновить эти значения в модели или добавить под новыми именами. **Структура записи:** Указания вычисляемых атрибутов начинается с указания ключевого атрибута ``computedAttributes`` в корневой структуре метафайла, содержащего в себе список объектов следующего вида: .. list-table:: :widths: 10 10 :header-rows: 1 :class: tight-table * - Поле - Описание * - **ID** - | Уникальный идентификатор атрибута. Именно с этим значением атрибут попадет в итоговую модель. | Если в модели есть аттрибут с таким именем, то значение в модели обновится. * - **type** - Указания типа преобразования значения. * - **config** - | Представляет собой мапу ключ-значение, из дополнительных параметров конфигурации и их значений. .. code-block:: config: attribute: test1 | Имеет общий параметр для всех видов - ``attribute``. Данный параметр в качетве значения принимает имя атрибута, значение которого возмется для преобразования. | Если данный параметр не задан, то из модели возметря значение атрибута с именем из поля **id** вычисляемого атрибута. **Пример:** .. code-block:: model: test1: ecos:text1 test2: ecos:text2 computedAttributes: - id: test3 type: html-to-text config: attribute: test1 - id: test2 type: html-to-text Типы вычисляемых атрибутов ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. list-table:: :widths: 10 10 :header-rows: 1 :class: tight-table * - Тип - Описание * - **html-to-text** - Преобразует входной текст из HTML кода в текст, убирая из него лишние теги (такие как

,
,

  • ). Действие сгенерировать и скачать документ ----------------------------------------- .. _download_by_template: В системе предусмотрено действие, позволяющее на основе карточки, сгенерировать документ из шаблона документов и сразу его скачать. Для это необходимо в системе создать новое действие (Подробнее о: :ref:`действиях`) с типом ``download-by-template``. Для работы действия необходимо заполнить следующие атрибуты в конфиге действия: .. list-table:: :widths: 10 10 :header-rows: 1 :class: tight-table * - Атрибут - Значение * - **resultName** - | Имя итогового документа. .. code-block:: resultName: 'test-docx.docx' | Если данный атрибут будет отсутствовать, то возьмется имя документа шаблона. * - **templateRef** - | Ссылка на вызываемый шаблон .. code-block:: templateRef: 'transformations/template@test-template' **Принцип работы:** Вызывая действие из меню действий карточки система сделает запрос к шаблону, достанет модель из шаблона, заполнит ее соответствующими значениями и отправит все данные в микросервис транснформации, где на основе модели и шаблона сгенерируется документ и вернется обратно на UI, где просто скачается. Особенность: Если используются зашифрованные поля (зашифрованы в БД и расшифровываются непосредственно у пользователя), то такие поля передадутся в расшифрованном виде и в сгенерированном документе они будут корректно отображаться. Примеры действий: .. code-block:: --- id: download-by-test-template type: download-by-template config: templateRef: 'transformations/template@test-template'' .. code-block:: --- id: download-by-test-docx-template type: download-by-template name: ru: Скачать DOCX шаблон en: Download DOCX template config: templateRef: 'transformations/template@test-docx-template' resultName: 'test-docx.docx'' Импорт/экспорт шаблонов ------------------------ Импорт и экспорт шаблонов помогает легко и просто переносить шаблоны документов между стендами. Мы скачиваем необходимые нам шаблоны на одном стенде и импортируем их на другом без особой нагрузки. Также можно сгенерировать архив с шаблоном самому, и импортировать нужный шаблон на стенд в одно несложное действие. При импорте/экспорте будет осуществляться работа с zip-архивом, который содержит метоинформацию шаблона и непосредственно сам шаблон документа: .. image:: _static/transformation/trans_6.png :width: 600 :align: center Импорт ~~~~~~ Импорт шаблонов осуществляется через вариант создания шаблона **Импортировать шаблон документа** в журнале **Шаблоны документов**: .. image:: _static/transformation/trans_7.png :width: 400 :align: center Для импорта необходимо приложить zip-архив с файлами: * Файл с метаданными от шаблона. Имя файла должно быть сформировано по принципу: **Имя_файла.meta.yml** * Непосредственно сам шаблон (или шаблоны с разной локализацией). .. important:: Именно такой архив формируется при экспорте шаблона Экспорт ~~~~~~~ Экспорт осуществляется с помощью действия **Скачать** при наведении на необходимый нам шаблон документа. .. image:: _static/transformation/trans_8.png :width: 700 :align: center После нажатия на действие будет осуществляться скачивание zip-архива с шаблоном и его метаданными. Автоматическая генерация контента из шаблона ------------------------------------------------ .. _templated_content: Для автоматической генерации контента из шаблона при создании рекорда необходимо: 1. В тип данных добавить :ref:`аспект ` ``templated-content`` 2. В конфигурации аспекта выбрать шаблон: .. image:: _static/transformation/templated_content.png :width: 600 :align: center .. note:: Если при создании рекорда включен аспект ``templated-content``, но автоматическую генерацию нужно выключить, то можно выставить атрибут ``templated-content:autoGenerate`` в ``false``. При создании рекорда автоматическая генерация выполняется синхронно, результат будет записан в атрибут ``_content``. Сгенерированный контент будет доступен для скачивания, предпросмотра и сравнения версий. Синтаксис условных операторов ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В микросервис трансформации перенесена логика из класса **DocxFreeMarkerProcessor** из проекта ecos-community-core. Расположена в классе **DocxFreemarkerTemplateService**. Необходимо обратить внимание на описание сервиса, а именно на синтаксис условных операторов: .. image:: _static/transformation/template_syntax_01.png :width: 600 :align: center Выражения, которые содержат открывающий и закрывающий теги, необходимо оборачивать в теги группировки ``[#`` ``#]`` : .. image:: _static/transformation/template_syntax_02.png :width: 800 :align: center .. _transformation_onlyoffice: Параметры работы с документом во встроенном редакторе OnlyOffice ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В действии, в **url**, через **"&config=JSON"** необходимо прописать конфиг, предварительно сгенерировав его в **encodeURIComponent** прямо в браузере: .. image:: _static/transformation/doc_param_1.png :width: 800 :align: center | .. image:: _static/transformation/doc_param_2.png :width: 800 :align: center В данном примере мы разрешаем пользователю редактировать только определённые поля, и при этом убираем возможность скачать файл. Варианты конфигурации редактора описаны в `официальной документации `_ .. image:: _static/transformation/doc_param_3.png :width: 400 :align: center Для создания документа с редактируемыми полями необходимо исходный .docx файл локально открыть в редакторе OnlyOffice и сохранить в формате **.docxf** .. image:: _static/transformation/doc_param_4.png :width: 400 :align: center Открыть уже в этом формате, и с помощью вкладки **Формы → Текстовое поле**, разметить необходимые поля. При этом нужно убедиться, что **"Заполнитель"** и **"Значение по умолчанию"** пустые (для избежание проблем вёрстки и изменения цвета текста после генерации по шаблону) .. image:: _static/transformation/doc_param_5.png :width: 200 :align: center Отметив необходимые поля, необходимо снова сохранить документ в формате **.docx**, открыть в Word, заполнить необходимыми тегами и сохранить: .. image:: _static/transformation/doc_param_6.png :width: 300 :align: center Далее опять открыть с помощью OnlyOffice и через вкладку **Защита→ Защитить документ**: .. image:: _static/transformation/doc_param_7.png :width: 500 :align: center Указать **пароль** и **"Заполнение форм"**: .. image:: _static/transformation/doc_param_8.png :width: 300 :align: center В итоге получаем готовый **.docx** файл, который перед тем как загружать в систему, следует поправить, пользуясь статьей :ref:`Временное решение ошибки при генерации шаблона с условиями` .. _temporary_solution: Временное решение ошибки при генерации шаблона с условиями ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ При генерации документа из шаблона документа, в котором есть условие (т.е. if, else или elseif), возникает ошибка. .. image:: _static/transformation/error_1.png :width: 500 :align: center так как файл **document.xml** дробит условие на множество тегов: .. image:: _static/transformation/error_2.png :width: 500 :align: center Work around для решения проблемы: 1. Открыть **docx** как архив. .. image:: _static/transformation/error_3.png :width: 500 :align: center 2. В папке **word** открыть файл **document.xml** .. image:: _static/transformation/error_4.png :width: 500 :align: center Найти условие, разбитое на теги: .. image:: _static/transformation/error_5.png :width: 700 :align: center 3. Собрать в один тег: .. image:: _static/transformation/error_6.png :width: 700 :align: center 4. Сохранить. Загрузить Движок «ECOS table» ------------------- Данный движок в системе ECOS служит для работы с шаблонами документов в формате **xlsx**. Движок представляет собой смесь обработчика **xlsx файлов** и обработчика **Freemarker**, что дает следующие возможности: - использование в ячейках полноценного синтаксиса Freemarker для заполнения ячеек значениями; - использование специального синтаксиса для генерирования строк в xlsx файле. Общий принцип работы движка: - сканирует все страницы шаблона, заменяя, где необходимо, значения в ячейках на значения из модели, используя обработчик Freemarker - при нахождении строк с определенным синтаксисом (для генерации новых строк) начинает генерировать новые строки, заменяя ячейки в них значениями из объектов снутри соответствующего списка из модели. Другими словами, в модели должен быть список с объектами, на основе которого будут сгенерированы строки (число строк будет совпадать с киличеством элементов в списке). При генерировании строки будут использоваться значения объекта списка, для которого генерируется строка. Вывод данных в ячейку ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В ячеках можно полноценно использовать синтаксис обработчика Freemarker. Конструкция: .. code-block:: Карточка: ${name} подставит значение переменной **name** в указанное место, взяв его из модели данных. Также можно использовать и более сложные конструкции, которые поддерживаются обработчиком Freemarker. .. code-block:: <#if annotations??><#list annotations as annotation>"${annotation.annotation.ru}"<#sep>, Вывод в шаблон произвольного количества строк ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Для вывода в шаблон произвольного количества строк в виде таблицы необходимо использовать следующую конструкцию: На том месте, где ожидаются сгенерированные на основе списка объектов строки в первой ячейке пишется следующая конструкция: .. code-block:: #LIST list_name где **list_name** - название переменной из модели, в которой записан список объектов. Следующие строки строятся таким образом, как мы хотим их сгенерировать на основе объектов из списка **list_name** Например: .. image:: _static/transformation/xlsx_1.png :width: 500 :align: center | В строках при заполнении ячеек используем имена переменных из объектов данного списка. (Также можем использовать и переменные из общей модели. Если имена у переменной из объекта и из общей моделе совпадут, то возьмется значение из объекта). После описания шаблонных(ой) строк(и) необходимо поставить в первую ячейку на новой строке конструкцию: .. code-block:: #END Она будет указывать на то, что далее строки не являются шаблонными и их не нужно генерировать. .. image:: _static/transformation/list_1.png :width: 600 :align: center Пример ~~~~~~ Мы имеем тип данных со следующими атрибутами: .. image:: _static/transformation/xlsx_2.png :width: 600 :align: center Атрибут **empls** - является списком пользователей системы. Для данного типа мы делаем шаблон со следующей моделью: .. image:: _static/transformation/xlsx_3.png :width: 600 :align: center Перемення **empls** - хранит список объектов, состоящих из 3 полей, на основе пользователей системы. Шаблон xlsx выглядит следующим образом: .. image:: _static/transformation/xlsx_4.png :width: 500 :align: center Где: - В ячейке **А2** мы хотим записать значение из модели с ключом **name** - В ячейке **А5** мы указываем, что дальше мы хотим строки на основе объектов из списка с ключом **empls** в моделе - В ячеках **A6-C6** указываем как должны быть заполнены ячейки в сгенерированных строках - В ячейке **А7** мы указываем, что здесь заканчиваются шаблонные строки для списка с ключом **empls** (т.е. мы можем сделать 2 шаблонные строки и для каждой записи из списка будет генерироваться по 2 строки в итоговом файле) В итоге, для карточки с данными параметрами: .. image:: _static/transformation/xlsx_5.png :width: 500 :align: center Будет сгенерирован следующий шаблон: .. image:: _static/transformation/xlsx_6.png :width: 500 :align: center