Перейти к основному содержанию
`Ctrl`+`K`

# Печатная форма

Печатная форма (сокр. `ПФ`) определяет правила построения отчета и его доступность для приложения, типа объекта и пользователя. При выполнении печатной формы система формирует отчет в файле заданного формата.
Печатную форму можно подключить к выборке на проекте без изменений в программном коде.

## Создание и настройка печатной формы

### Создание печатной формы

1. Перейдите в приложение `Настройка системы`.

2. Откройте раздел: `Отчеты → Печатные формы`.

3. Нажмите `Создать`.

4. Заполните поля:

   - Системное имя;

   - Наименование;

   - Модуль.

5. Создайте версию печатной формы.

6. Выберите тип шаблона.

7. Загрузите файл шаблона — выполните операцию Загрузить файл в базу.

### Типы шаблонов печатных форм

Определяют формат шаблона:

- JASPER — zip-архив с XML-файлами, созданными в Jasper Studio.

- XLSX — файл XLS со спец. тегами.

- DOCS — файл DOCS со спец. тегами.

### Версия печатной формы

Позволяет:

- Безопасно вернуться к предыдущей реализации.

- Запускать разные версии в зависимости от периода.

Содержит:

- тип шаблона печатной формы;

- бинарный файл для построения отчетов;

- дату версии;

- описание.

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

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

Ключевые возможности:

- Экспорт версий - можно скачать версии отчета в виде файла.

- Импорт версий - перенести сохраненные версии в другую базу данных.

- Форматы переноса - для удобства работы реализован перенос с использованием:

  - JSON - структурированный формат данных;

  - JEXL - язык выражений для сложных преобразований.

Это упрощает перенос настроенных печатных форм между различными базами данных системы.

### Настройка вставки изображений

Настройка вставки изображений в печатную форму типа DOCX и XLSX выполняется в коллекции к печатной форме. Все поля обязательны.

- Активность: поле определяет, будет ли вставлено изображение.

- Шаблон (Тег): тег, по которому будет вставлено изображение. Тег должен содержаться в печатной форме, иначе изображение не будет вставлено. Существует два вида тегов:

  - Общий: тег не имеет динамической части. Изображение будет вставлено при нахождении данного тега в документе.
    Пример:

    - в поле - `SomeTag`;

    - в документе - [SomeTag].

  - Подпись: тег для подписи состоит общей части для всех тегов (которая задается в данном поле) и имени пользователя (подпись которого необходимо вставить в данный документ).
    Пример:

    - в поле: `SomeSignTag`;

    - в документе (с динамической частью): [SomeSignTagAdmin].

- Печатная форма изображения: в поле указывается печатная форма с типом Jasper и форматом PNG. В зависимости от типа изображения данной печатной форме будут переданы следующие аргументы:

  - Подпись:

    - PSDATE - дата подписания документа;

    - PSSERNUMBER - № сертификата подписи;

    - PSDBEGIN - дата начала действия подписи;

    - PSDEND - дата окончания действия подписи;

    - PSFIO - ФИО сотрудника, подписавшего документ;

    - IDDOC - ID документа;

    - IDDOCVER - ID версии документа (если документ версионный, то подписывается именно версия а не сам документ);

    - JOBJ - JSON объект подписи документа.

  - Общий:

    - IDDOC - ID документа;

    - IDDOCVER - ID версии документа (если документ версионный, то подписывается именно версия а не сам документ).

- Масштаб и Разрешение - размер изображения высчитывается по формуле:
  `Масштаб *= Measures.DOTS_PER_INCH / Разрешение.`

- Тип - в поле указывается тип изображения:

  - Общий - изображение вставляется при печати в любом случае.

  - Подпись - изображение вставляется, если на документе есть хотя бы одна подпись.

### Вставка изображений

Для вставки изображений в печатную форму типа docx должны быть выполнены следующие условия:

1. Печатная форма должна содержать теги вида [SomeTag].

2. Тип шаблона печатной формы - DOCX или XLSX.

3. Формат печатной формы - PDF.

4. В коллекции к печатной форме(Настройки вставки изображений в печатную форму) настроены необходимые изображения для вставки.

Если все требования выполнены корректно, то при печати такой ПФ будет получен PDF-файл (для DOCX) или XLS с изображениями на месте тегов.

Примечание

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

## Вызов печатной формы

Печатные формы можно вызывать:

- из операции выборки;

- из запроса к сервису печати;

- из REST-сервиса;

- от произвольного объекта системы;

- через интерфейс Свободные отчеты.

Совет

Проверка полномочий в печатных формах.

### Из операции выборки

Для вызова отчета из операции выборки используйте функцию `ru.bitec.app.gtk.gl.Reports#createReportEx`:

      /**
        * Выполняет построение отчета по системному имени отчета.
        *
        * @param reportName        Имя отчета
        * @param reportVersionDate Дата
        * @param postBuildAction   Действие, которое необходимо произвести после заполнения отчета
        * @param propertyMap       Карта входящих параметров
        */
      @throws[ApplicationException]
      def createReportEx(reportName: String, reportVersionDate: Date, postBuildAction: PostBuildAction, propertyMap: Map[String, Any]): Unit

Данная функция может быть вызвана только в контексте интерактивной бизнес-логики (интерфейса пользователя).

Пример:

    reports.createReportEx("Mct_OrderSheetMaterials2", null, PostBuildAction.print,
            Map[String, Any]("IDSRCOBJECT" -> getVar("id").asNLong,
              "GIDSRCOBJECT" -> getVar("gid").asNString,
              "SDESIGNATION" -> getVar("sCode").asNString)
          )

### От произвольного объекта

При открытии карточки объекта отображаются стандартные операции печати.

Чтобы добавить ПФ к типу объекта:

1. Откройте приложение `Настройка системы`.

2. Откройте типы объектов `Сущности > Типы объектов > Типы объектов`.

3. Перейдите на вкладку `Печатные формы`.

4. Добавьте необходимые печатные формы.

### Из свободных отчетах

Свободные отчеты позволяют настроить для пользователя и приложения перечень отчетов, которые можно построить без привязки к каким-либо типам объектов.

Для вызова интерфейса построения свободных отчетов:

1. Откройте приложение, в котором есть пункт меню `Отчеты`.

2. Откройте свободные отчеты `Отчеты > Свободные отчеты`.

3. Выберите нужный отчет.

4. Заполните параметры.

5. Напечатайте отчет. Для этого выполните операцию `Печать`.

Для того чтобы ПФ могла быть вызвана из свободных отчетов:

1. Откройте приложение `Настройка системы`.

2. Откройте печатные формы `Отчеты > Печатные формы`.

3. Выберите требуемую печатную форму.

4. Включите признак `Свободный отчет`.

5. Настройте параметры отчета.

6. Укажите приложение для печати.

7. Укажите требуемые роли.

   Примечание

   Если роли не указаны, печатная форма будет доступна всем пользователям.

## Параметры и данные для построения отчета

### Параметры отчета

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

#### Служебные параметры

Формируются автоматически:

- SIGNDATA_DZ - блок подписи.

- IDUSER - пользователь.

- IDSRCOBJECT - объект источник. Идентификатор объекта, от которого выполняется печатная форма.

- IDSRCCLASS - класс источник. Идентификатор класса объекта, от которого выполняется печатная форма.

Совет

Видимость кнопки Печать отчета настраивается в закладке «Тип объектов» с помощью параметра «jexl-скрипт фильтрации ПФ», который определяет, будет ли кнопка доступна для данного типа объекта.

### Подписи для печатных бланков

Если отчет должен быть подписан после печати, в запрос печатной формы следует добавить атрибуты, необходимые для формирования блока подписания.

    with signs as(select * from jsonb_array_elements( $P{SIGNDATA_DZ}::jsonb ->'data'))
    select t.*
    , (select s.value ->>'sFIO' from signs s WHERE  s.value->>'idBlankSignTypeMC' = 'matching1') as sMatching1
    , (select s.value ->>'sPosition' from signs s WHERE  s.value->>'idBlankSignTypeMC' = 'matching1') as sMatching1Pos

На печатный бланк необходимо вывести блок с подписями.

Блок с подписями формируется перед печатью и передается в отчет в формате JSON, в параметр `SIGNDATA_DZ`.
Пример:

    {
        "data": [
            {
                "idBlankSignTypeMC": "HeadOfDepartment",
                "bReadOnly": 0,
                "idBlankSignTypeHL": "Руководитель подразделения",
                "nOrder": 1,
                "dDate": "10.12.2020",
                "idBlankSignType": 95401,
                "sPosition": "Начальник отдела",
                "sFIO": "Дьяченко Евгений Владимирович"
            }
        ]
    }

Где:

- idBlankSignType - идентификатор типа подписи;

- idBlankSignTypeMC - код типа подписи;

- nOrder - порядковый номер подписи;

- sPosition - должность;

- sFIO - ФИО;

- dDate - дата.

Блок формируется на основе настроек данной закладки.
Настройки могут быть переопределены\уточнены на конкретном объекте в закладке Подписи `Bs_OBjectSign`.

### Аудит построения отчета

Содержит информацию о построении отчетов пользователями.

## Формирование файла с отчетом

Для формирования файла с отчетом используйте функцию `ru.bitec.app.rpt.Rpt_Pkg#getReportStreamEx`:

      /**
        * Выполняет построение отчета по системному имени отчета.
        * Если для версии отчета указано несколько доступных для печати форматов, то будет выдана ошибка построения.
        * Требуется явно указать формат построения, указав параметр [[Rpt_Pkg.ParamFormatType]]
        *
        * @param reportName        Имя отчета
        * @param reportVersionDate Дата
        * @param propertyMap       Карта входящих параметров
        * @return InputStream, содержащий результат построения отчета. ByteArrayInputStream не требует закрытия.
        */
      def getReportStreamEx(reportName: String, reportVersionDate: Date, propertyMap: Map[String, Any]): Option[InputStream]

Функция работает в контексте автономной логики (REST-сервиса).

Внимание

- Если получен поток — его необходимо закрыть.

- При формировании файла с отчетом в потоке переменные выборки недоступны.

### Формирование имени файла отчета

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

## Профили печати

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

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

Принцип работы
Профиль печати связывает с выборкой или классом одну или несколько печатных форм. Каждая форма может обрабатывать определенные параметры из выборки, что позволяет создавать разнотипные отчеты из одних данных.

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

### Создание профиля печати

1. Откройте раздел `Отчеты - Профили печати`.

2. Создайте новый профиль печати.

3. Добавьте нужные печатные формы.

4. Укажите классы и выборки, для которых будет доступен этот профиль.

Настройка печатных форм
Для каждого профиля можно настроить печатные формы, которые будут выводиться при выборе данного профиля в операции печати.

Для каждой формы можно указать:

- порядковый номер в очереди печати;

- количество копий;

- доступность формы.

При использовании профиля в отчет включаются только доступные печатные формы в заданном порядке, каждая печатается указанное количество раз.

### Отображение профиля печати

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

## Получение дополнительных параметров печати

В печатной форме `Rpt_Report` есть возможность указать процедуру `Bts_Procedure` для получения дополнительных параметров печати (поле «Процедура получения дополнительных параметров»). Процедура получает на вход 3 параметра:

- `reportName` - имя отчета;

- `reportVersionDate` - дата версии отчета;

- `propertyMap` - изменяемая карта параметров, которые будут переданы в отчет.

Процедура не возвращает никаких значений. Ее предназначение - редактирование карты параметров `propertyMap`. Процедура может вызывать как функцию из прикладного кода, так и выполнять Jexl-функцию. Таким образом можно добавлять дополнительные параметры без изменения прикладного кода.

Пример функции, вызываемой из прикладного кода:

      def getAddReportParamTest(reportName: NString, reportVersionDate: NDate, propertyMap: mutable.HashMap[String, Any]): Unit = {
        propertyMap.addOne("idBisObj", 15723.nl)
      }

Пример jexl-функции:

      //создаем карту дополнительных параметров
      var addParamsMap = {"idBisObj", 15723L};
      //к переданной карте propertyMap добавляем карту доп.параметров, приведенную к scala типу
      propertyMap.addAll(asScala(addParamsMap));

## Функция пост-обработки

Внимание

Работает с версии сервера `1.25.0-rc45`.

Функция пост-обработки отчета позволяет выполнить дополнительные действия с уже сформированным отчетом, такие как:

- Блокировка вывода отчета — при обнаружении критических ошибок отчет можно не показывать пользователю.

- Дополнение отчета — динамическое добавление информации (например, данные из внешних источников).

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

- Взаимодействие с прикладным кодом — вызов бизнес-логики, логирование, интеграция с другими модулями системы.

Данная функция вызывается в момент окончания заполнения отчета, но до вывода его пользователю.
Чтобы использовать функцию пост-обработки, необходимо в печатной форме `Rpt_Report` в поле «Функция пост-обработки отчета» указать имя нужной процедуры `Bts_Procedure`, при этом у указанной процедуры должен быть установлен тип — «Функция пост-обработки отчета».

### Обработка ошибок

- Критические ошибки:

  - Блокируют вывод отчета.

  - Вызываются с помощью `raise(<текст ошибки>)`.

  - Останавливают выполнение пост-обработчика.

- Некритические ошибки (информационные)

  - Не блокируют вывод.

  - Вызываются с помощью `event.writeError()`.

  - Не останавливают выполнение пост-обработчика.

  - Выводят информационное сообщение в журнал печати.

### Параметры процедуры

- `propertyMap` - карта параметров, по которой строился отчет;

- `event` - событие класса `JexlEndFillTemplateEvent`.

### Описание класса JexlEndFillTemplateEvent

Событие, доступное из jexl-процедуры в пост-обработчике печатных форм.

#### Структура класса

- `fileName: String` - возвращает имя файла, с которым результат экспорта отчета будет передан клиенту.

- `inputStream: InputStream` - возвращает поток байтов с результатом экспорта заполненного шаблона в файл, который будет передан клиенту.

- `setInputStream(value: InputStream)`- устанавливает поток байтов с данными файла.

- `writeInfo(sInfo: NString)` - устанавливает значение в поле «Сообщение» журнала построения отчетных форм (Rpt_EntityExec). При повторном указании сообщения оно перезапишется.

- `writeError(sError: NString)` - устанавливает значение в поле «Текст ошибки» журнала построения отчетных форм (Rpt_EntityExec). При повторном указании сообщения оно перезапишется.

### Пример scala функции

    def postProcessing(paramMap: Map[String, Any], event: JexlEndFillTemplateEvent): Unit = {
      val img = session.sbtClassLoader.getResource("ru/bitec/app/rpt/imgForTest/meme.png")

      Using.Manager { using =>
        val imgBytes = using(img.openStream()).readAllBytes()

        val res = Btk_PDFUtilPkg().insertWithiText(
          pInpStream = event.inputStream
          , pImages = List((Btk_PDFUtilPkg.ImageInfo(name = "0",
            x = 300.nr,
            y = 300.nr,
            width = 100.nr,
            height = 100.nr,
            page = 1.nr,
          ), imgBytes))
          , bInAllPages = true
        )
        event.setInputStream(new ByteArrayInputStream(res.toByteArray))
      }.get
      event.writeInfo("Изображение успешно вставлено");
    }

В примере в поток pdf отчета производится вставка изображения при помощи пакета `Btk_PDFUtilPkg`. Таким образом можно наложить водянной знак на все страницы отчета.

### Пример проверки корректности постороения отчета

    def postProcessing(paramMap: Map[String, Any], event: JexlEndFillTemplateEvent): Unit = {
      Using(Loader.loadPDF(new RandomAccessReadBuffer(event.inputStream))) { pdfDoc =>
        val nPageCount = pdfDoc.getNumberOfPages
        if (nPageCount == 0) {
          throw AppException("Получен пустой отчет")
        } else {
          event.writeInfo(s"Количество страниц: $nPageCount")
        }
      }.get
    }

В данном примере поток отчета парсится как pdf и проверяется наличие страниц у документа. Если оно = 0, то поднимается ошибка, иначе в поле «Информация» журнала построения записывается кол-во страниц.