.. _transformation: Transformations микросервис ========================================== .. note:: Доступно только в Enterprise версии. Опциональный микросервис **ecos-transformations** для генерации документов по шаблонам, которые можно подгрузить с проектом или добавить через инструменты администратора. .. contents:: :depth: 2 Подключение микросервиса ------------------------------------------------ **Микросервис Трансформации (ecos-transformations)** — самостоятельный микросервис, не требующего развертывания дополнительных баз данных (все шаблоны хранятся в БД ecos-model). Для обеспечения работоспособности необходимы: * ecos-model:2.13.0 Параметры подключения через docker-compose.yml ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: yaml #=== 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:: yaml id: test-template * - **engine** - | Наименование движка, который будет обрабатывать заполнение шаблона | Доступные движки: | - ``freemarker`` — для формирования документов в формате docx, txt с обработкой Freemarker. | - ``ecos-table`` — для формирования xlsx таблиц, которые поддерживают обработку Freemarker | - ``none`` — для обработки шаблонов без какой-либо трансформации. Возвращается шаблон как есть. .. code-block:: yaml engine: freemarker * - **name** - | Имя шаблона .. code-block:: yaml name: TestTemplate * - **mimeType** - | Тип файла шаблона .. code-block:: yaml mimeType: application/vnd.openxmlformats-officedocument.wordprocessingml.document * - **model** - | Представляет собой мапу ключ-значение, где в качестве ключа используется атрибут из шаблона, а в качестве значения — атрибут, который возьмется из карточки. .. code-block:: yaml model: regNumber: registrationNumber regDate: registrationDate|fmt('dd.MM.yyyy') initiator: initiator.firstName | В значениях можно использовать все возможности обращения с атрибутами через :ref:`Records API ` * - **computedAttributes** - | Вычисляемые атрибуты модели. | Задается списком атрибутов. | Перед генерацией шаблона преобразует полученные атрибуты в модели согласно типу преобразования. .. code-block:: yaml computedAttributes: - id: docInvestigationInfo type: html-to-text | См. подробнее :ref:`Вычисляемые атрибуты для шаблонов ` * - **tags** - | Список вспомогательных меток для удобного поиска .. code-block:: yaml tags: - Template - Test - Example Пример: .. code-block:: yaml --- 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:: yaml config: attribute: test1 | Имеет общий параметр для всех видов — ``attribute``. Данный параметр в качестве значения принимает имя атрибута, значение которого возьмется для преобразования. | Если данный параметр не задан, то из модели возьмется значение атрибута с именем из поля **id** вычисляемого атрибута. **Пример:** .. code-block:: yaml 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:: yaml resultName: 'test-docx.docx' | Если данный атрибут будет отсутствовать, то возьмется имя документа шаблона. * - **templateRef** - | Ссылка на вызываемый шаблон .. code-block:: yaml templateRef: 'transformations/template@test-template' **Принцип работы:** Вызывая действие из меню действий карточки, система сделает запрос к шаблону, достанет модель из шаблона, заполнит её соответствующими значениями и отправит все данные в микросервис трансформации, где на основе модели и шаблона сгенерируется документ и вернется обратно на UI для скачивания. В TemplateServiceImpl перед передачей модели данных в шаблонизатор реализована рекурсивная санитизация всех строковых значений. Из строк удаляются управляющие символы u0000 u0008, u000B, u000C, u000E, u001F. Допустимые символы — табуляция, перевод строки и возврат каретки — сохраняются. Санитизация централизована и покрывает все типы шаблонов (DOCX, XLSX, текстовые). Особенность: если используются зашифрованные поля (зашифрованы в БД и расшифровываются непосредственно у пользователя), то такие поля передадутся в расшифрованном виде и в сгенерированном документе они будут корректно отображаться. Примеры действий: .. code-block:: yaml --- id: download-by-test-template type: download-by-template config: templateRef: 'transformations/template@test-template' .. code-block:: yaml --- 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» --------------------------- Данный движок в системе Citeck служит для работы с шаблонами документов в формате **xlsx**. Движок представляет собой смесь обработчика **xlsx файлов** и обработчика **Freemarker**, что дает следующие возможности: - использование в ячейках полноценного синтаксиса Freemarker для заполнения ячеек значениями; - использование специального синтаксиса для генерирования строк в xlsx файле. Общий принцип работы движка: - сканирует все страницы шаблона, заменяя, где необходимо, значения в ячейках на значения из модели, используя обработчик Freemarker; - при нахождении строк с определенным синтаксисом (для генерации новых строк) начинает генерировать новые строки, заменяя ячейки в них значениями из объектов внутри соответствующего списка из модели. Другими словами, в модели должен быть список с объектами, на основе которого будут сгенерированы строки (число строк будет совпадать с количеством элементов в списке). При генерировании строки будут использоваться значения объекта списка, для которого генерируется строка. Вывод данных в ячейку ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ В ячейках можно полноценно использовать синтаксис обработчика Freemarker. Конструкция: .. code-block:: text Карточка: ${name} подставит значение переменной **name** в указанное место, взяв его из модели данных. Также можно использовать и более сложные конструкции, которые поддерживаются обработчиком Freemarker. .. code-block:: text <#if annotations??><#list annotations as annotation>"${annotation.annotation.ru}"<#sep>, Вывод в шаблон произвольного количества строк ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Для вывода в шаблон произвольного количества строк в виде таблицы необходимо использовать следующую конструкцию: На том месте, где ожидаются сгенерированные на основе списка объектов строки, в первой ячейке пишется следующая конструкция: .. code-block:: text #LIST list_name где **list_name** — название переменной из модели, в которой записан список объектов. Следующие строки строятся таким образом, как мы хотим их сгенерировать на основе объектов из списка **list_name** Например: .. image:: _static/transformation/xlsx_1.png :width: 500 :align: center | В строках при заполнении ячеек используем имена переменных из объектов данного списка (также можем использовать и переменные из общей модели; если имена у переменной из объекта и из общей модели совпадут, то возьмется значение из объекта). После описания шаблонных строк необходимо поставить в первую ячейку на новой строке конструкцию: .. code-block:: text #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