﻿# Специальные функции синтаксиса шаблонов 

> [HTML Version](another-template-syntax-functions.html)

В статье описаны правила использования дополнительных функций [синтаксиса шаблонов](360027003711.md):

- [GenerateBarcode()](#barcode) — вывести содержимое переменной в документе в виде штрихкода;

- [JobPosition()](#jobposition) — подставить должность пользователя;

- [PasteImage()](#pasteimage) — вставить на месте переменной изображение;

- [Hyperlink()](#hyperlink) — преобразовать заданное значение в гиперссылку;

- [ExtText()](#exttext) — создать пользовательскую функцию для расширенных возможностей работы с шаблоном документов. 

## Функция GenerateBarcode()

Функция `GenerateBarcode()` используется для кодирования строки приложения и добавления её в документ в виде штрихкода. Например, таким образом можно сгенерировать штрихкод для регистрационного номера договора или другого уникального номера документа. В дальнейшем с помощью штрихкода можно будет сопоставить документ на бумажном носителе и электронную копию.

Взаимодействие ELMA365 с ПО для считывания штрихкодов осуществляется через модули интеграции. Подробнее о них можно прочитать в статьях [«Модули расширения системы»](360024498352.md) и в [справке по публичному API ELMA365](https://api.elma365.com/ru/public-api/guides/IntroWebAPI/).

Генерация штрихкода доступна для форматов, поддерживаемых в программах Word и Excel.

**Синтаксис:**

`\{GenerateBarcode(\{\$код\_переменной\}: строка, формат кода, \[высота штрихкода в пикселях\])`,

где:

- **код переменной** — значение в строке зависит от формата, указываемого во втором параметре;

- **формат кода** — возможные форматы штрихкодов и требования к строке:

	- **QR Code** — любая строка. Поддерживается разрешение до 300 DPI; 

	- **EAN-8** — строка до восьми цифр, где последняя используется как контрольная;

	- **EAN-13** — строка из 12 цифр или 13 цифр, где последняя — контрольная.

Вы также можете указать формат **EAN** без уточнения типа. В таком случае тип сгенерированного штрихкода будет зависеть от количества цифр в передаваемой строке;

- **высота штрихкода в пикселях** — необязательный параметр. Для корректного распознавания высота указывается в зависимости от количества используемых символов.

Если в шаблоне одна и та же строка используется для генерации QR-кода два раза, но при этом указывается разный размер, то в обоих случаях сгенерируется QR-код одинакового размера.

````
начало внимание

````
Если при использовании форматов **EAN** контрольная сумма не была указана, она добавится автоматически. Для корректной работы сканер штрихкодов следует настроить на работу с данными форматами.

````
конец внимание

````
Мы рекомендуем использовать формат **QR Code**, так как он не имеет таких строгих ограничений, как форматы **EAN**.

````
начало примера

````
Пример

Для примера возьмём переменную `\$numberstring = "5901234123457"`. Она подойдёт для формата **QR Code** и **EAN-13**. В формате **EAN-8** эту строку отобразить нельзя, так в ней должно быть восемь цифр.

1. `\{GenerateBarcode(\{\$numberstring\}, "QR Code", "125")\}.`

2. `\{GenerateBarcode(\{\$numberstring\}, "EAN-13", "125")\}`.

````
конец примера

## ````
Функция JobPosition()

Эта функция используется для получения должности пользователя. 

**Синтаксис:**

`JobPosition(\{\$код\_переменной\}: пользователь, "формат": строка)`. 

Доступные значения формата: 

- `"first"` — для передачи первой должности;

- `"all"` — для всех должностей пользователя.

````
начало примера

````
Пример

`\{JobPosition(\{\$\_\_createdBy\}, all)\}` —> функция передаст все должности пользователя, записанного в поле **Автор**.

````
конец примера

## ````
Функция PasteImage()

Чтобы вставить в шаблон документа изображение из контекстной переменной типа [Изображение](360009707032.md#image) и [Файлы](360009707032.md#file_type), используйте функцию `PasteImage()`.

**Синтаксис:**

`PasteImage(\{\$код\_переменной\}: изображение или файл, ширина в пикселях, высота в пикселях, обрезать вместо сжатия: true/false)`.

````
Начало примера

````
Примеры

1. `\{PasteImage(\{\$image\})\}` — вставка изображения с исходными значениями ширины и высоты из переменной типа **Изображение**.

2. `\{PasteImage(\{\$file.\_\_id\})\}` — вставка изображения с исходными значениями ширины и высоты из переменной типа **Файлы**.

3. `\{PasteImage(\{\$image\}, 200)\}` — изображение из свойства типа **Изображение** отобразится с шириной 200 пикселей. Значение высоты изменится, исходные пропорции сохранятся.

4. `\{PasteImage(\{\$file.\_\_id\}, 200, 400)\}` — функция масштабирует изображение из свойства типа **Файлы** до строго заданного размера.

5. `\{PasteImage(\{\$image\}, auto, 400)\}` — изображение из переменной типа **Изображение** отобразится с высотой 400 пикселей. При этом значение ширины масштабируется, исходные пропорции сохранятся.

6. `\{PasteImage(\{\$image\}, 200, 400, true)\}` — функция обрежет изображение из переменной типа **Изображение** до указанного размера без учёта исходных пропорций.

````
Конец примера

### ````
Вывести несколько изображений

По умолчанию функция `PasteImage()` позволяет вставить в документ только одно изображение или файл. Чтобы вывести несколько данных, примените функцию внутри [цикла for](360027003711.md#cycle).

````
Начало примера

````
Пример

В документе нужно отобразить список изображений. Список передаётся в переменную шаблона `\{\$image1\}` типа **Изображение (несколько)**. Цикл `for` позволяет неоднократно применить функцию `PasteImage()`, чтобы последовательно вставить в документ все изображения из списка.   
Для корректной работы цикла нужно использовать две переменные:

- `\{\$image\}` — содержит несколько изображений;

- `\{\$image1\}` — временная переменная, в которую по очереди помещается каждое изображение из `\{\$image1\}`.

````
\{for image1 in \{\$image\}\}  
\{PasteImage(\{\$image1\}, 400, 200)\}  
\{end\}

````
После выполнения цикла в документе отобразится список изображений. 

````
Конец примера

## ````
Функция Hyperlink()

Функция `Hyperlink()` используется в шаблонах формата **.docx**, **.xls** и **.xlsx** и позволяет преобразовать заданное значение в гиперссылку. 

В качестве аргументов функции можно использовать переменные типа [Строка](360009707032.md#string) из контекста приложения, а также задать значения вручную. Для корректной работы функции указывается полный URL‑адрес ссылки.  

**Синтаксис:**

1. `\{Hyperlink("URL-адрес", "Текст ссылки": \{\$код\_переменной\} или строка)\}` — отобразится текст‑гиперссылка, в которой настроен переход на указанный сайт;

2. `\{Hyperlink("URL-адрес")\}` — гиперссылка отобразится в виде URL-адреса.

Текст ссылки, передаваемый в виде строки, можно заключить в кавычки или указать без них. В шаблоне выводится тот вариант, который прописан в синтаксисе.

````
начало примера

````
Примеры функции с использованием переменных из контекста приложения:

- `\{Hyperlink("\{\$site\}", "Смотрите на официальном сайте")\}` — адрес сайта указан в виде строки в элементе приложения, текст гиперссылки задан вручную;

- `\{Hyperlink ("https://elma365.com/ru/", \{\$\_\_name\})\}` — адрес сайта прописан вручную, текст гиперссылки формируется из поля в элементе приложения. 

````
конец примера

## ````
Функция ExtText() 

Если для настройки шаблона системных функций недостаточно, вы можете использовать пользовательскую функцию `ExtText()`. Она позволяет вызывать [методы API](extention-api.md), созданные в пользовательских модулях, и подставлять результаты их работы в генерируемый по шаблону документ.

**Синтаксис:**

`\{ExtText("ID модуля", "адрес метода", дополнительный параметр: \{\$код\_переменной\} или "строка")\}`,

где:

- **ID модуля** — в качестве идентификатора используются символы из URL модуля, идущие после **/ext\_**. Например, если URL модуля **mycompany.elma365.ru/admin/extensions/ext\_12ab-1212ab-12**, в функцию передаётся значение `"12ab-1212ab-12"`;

- **адрес метода** — для получения адреса перейдите в настройки модуля, где создан метод, откройте вкладку **Методы API**. В списке найдите нужный метод и скопируйте значение из поля **Адрес**;

- **дополнительный параметр** — один или несколько параметров, которые передаются в метод API. В синтаксисе функции параметры указываются через запятую в нужном порядке. Свойства приложения заключаются в фигурные скобки, например `\{\$app\_field\}`. Другие параметры прописываются в кавычках, например `"function"`. В скрипте метода API параметры доступны как ключи **p1**, **p2** и далее в том порядке, в котором они перечислены в функции `ExtText()`.

### Ускорение обработки пользовательских функций

При использовании сложных пользовательских функций вы можете изменить режим их обработки для ускорения генерации документов по шаблону. Все переменные и функции будут обрабатываться не последовательно друг за другом, а параллельно.

Для этого включается фича-флаг `enableConcurrencyTemplateMapper`, а в конфигурационном файле с помощью специального параметра задаётся количество параллельных потоков обработки. 

Подробнее читайте в статьях [«Изменение параметров ELMA365 Enterprise»](change-settings-enterprise.md#enable-feature-flag-enterpeise) и [«Изменение параметров ELMA365 Standard»](change-elma365standard-parameters.md#enable-feature-flag-standard). Если вы используете поставку SaaS Enterprise, для включения фича‑флага обратитесь к вашему менеджеру ELMA365.

### Пример пользовательской функции для выполнения арифметических операций

С помощью метода API в модуле и функции `ExtText()` вы можете вывести в документе, сгенерированном по шаблону, результат арифметических операций: сложение, вычитание, деление, умножение. В качестве аргументов для операций в функции можно использовать произвольные числа или поля приложения типа [Число](360009707032.md#number), [Деньги](360009707032.md#money), [Строка](360009707032.md#string) — если в виде строки указано число.  

Для примера настроим генерацию документа по шаблону в приложении **Договоры**. С помощью вычислений пользовательской функции в договоре отобразим: 

- итоговую сумму с учётом фиксированной стоимости доставки; 

- остаток по платежу после оплаты аванса; 

- сумму неустойки в размере двойного аванса;

- ежемесячную выплату клиента при рассрочке на указанное количество месяцев.

#### Шаг 1. Настроить контекст приложения

Для реализации примера в приложении **Договоры** нужно создать следующие свойства:

- **Сумма договора** (`sum\_total`) — поле типа **Деньги**;

- **Авансовый платёж** (`advance\_payment`) — поле типа **Деньги**;

- **Срок рассрочки** (`installment\_months`) — поле типа **Число**. Менеджер указывает в карточке договора срок в месяцах, на который клиенту предоставляется рассрочка на оплату суммы по договору.

#### Шаг 2. Создать метод API в модуле

Все вычисления будут выполняться с помощью скрипта в методе API. Для настройки:

1. Перейдите в раздел **Администрирование > Модули**. Создайте пользовательский модуль или откройте управление существующего. Убедитесь, что модуль включён.

2. Перейдите на вкладку **Методы API**, откройте редактор методов и нажмите **+ Добавить**.

3. В качестве параметров метода укажите:

- название — **Выполнение расчёта**;

- адрес — выберите метод `Get` и укажите значение `arithmetic`, которое в дальнейшем будет указано в функции `ExtText()`;

- название функции — `doArithmetic`.

4. Сохраните настройки метода.

Подробнее читайте в [статье о создании метода в модуле](extention-api.md).

#### Шаг 3. Задать скрипт метода API

В редакторе методов перейдите на вкладку **Скрипты** и объявите функцию `doArithmetic`.

Она будет вызываться из шаблона для генерации документа с помощью указанной в нём функции: `\{ExtText("ID модуля", "адрес метода", \{\$операнд 1\}, \{\$операнд 2\}, "операция")\}`. Параметры из функции автоматически передаются в объект с ключами **p1**, **p2**, **p3**.

Скрипт принимает аргументы, преобразует значения переменных в числа и выполняет выбранную арифметическую операцию: сложение — `add`, вычитание — `subtract`, умножение — `multiply`, деление — `divide`.

Скрипт для выполнения арифметических операций через API модуля

````
async function doArithmetic(req: HttpApiRequest): Promise<HttpResponse | void> \{  
    // Создаём объект ответа, который будет возвращён в шаблон  
    const resp = new HttpResponse();  
  
    // Получаем тело запроса как строку. В нём содержатся параметры, переданные в функцию ExtText()  
    const bodystr = req.body\!.toString();  
  
    // Преобразуем JSON-строку в объект для удобной работы с параметрами  
    const parsed = JSON.parse(bodystr);  
  
    // Вспомогательная функция для преобразования значения в число.  
    // Необходимо, чтобы обработать любой формат числа из шаблона, например из переменной типа Деньги или дробное число  
    function parseNumber(value: any): number \{  
        // если число корректного формата — возвращаем в исходном виде. Подходит и для свойств типа Деньги  
        if (typeof value === 'number') return value;  
  
        // если число передано в строке — заменяем запятую на точку и преобразовываем в число  
        if (typeof value === 'string') \{  
            // убираем пробелы и заменяем запятую на точку  
            const cleaned = value.replace(/\\s/g, '').replace(',', '.');  
            const result = Number(cleaned);  
            return result;  
        \}  
  
        // для всех остальных типов (boolean, null, undefined) преобразовываем стандартным способом  
        return Number(value);  
    \}  
  
    // Извлекаем параметры из запроса. В функцию ExtText() параметры передаются как ключи p1, p2, p3 и т. д. в порядке их перечисления  
    const a = parseNumber(parsed.p1); // первое число (операнд 1)  
    const b = parseNumber(parsed.p2); // второе число (операнд 2)  
    const operator = parsed.p3; // операция: "add", "subtract", "multiply" или "divide"  
  
    // Проверяем, что оба числа корректны.  
    if (\!isFinite(a) || \!isFinite(b)) \{  
        const errorMsg = \`Ошибка: неверные числа (a=\$\{parsed.p1\}, b=\$\{parsed.p2\})\`;  
        resp.status(200)  
            .content(errorMsg)  
            .set('Content-Type', 'text/html');  
        return resp;  
    \}  
  
    // Выполняем арифметическую операцию в зависимости от переданного оператора  
    let result: string;  
    switch (operator) \{  
        case 'add':  
            result = String(a + b);  
            break;  
        case 'subtract':  
            result = String(a - b);  
            break;            
        case 'multiply':  
            result = String(a \* b);  
            break;  
        case 'divide':  
            // проверяем деление на ноль, чтобы избежать ошибки  
            if (b === 0) \{  
                result = 'Ошибка: деление на ноль\!';  
            \} else \{  
                result = String(a / b);  
            \}  
            break;  
        default:  
            // если передан неизвестный оператор, сообщаем об ошибке  
            result = \`Ошибка: неизвестная операция "\$\{operator\}"\`;  
            break;  
    \}  
  
    // Формируем HTTP-ответ:  
     \* статус 200 — успешное выполнение  
     \* Content-Type: text/html — используется, чтобы результат корректно отображался в шаблоне  
     \* В теле ответа передаём вычисленный результат  
     \*/  
    resp  
        .status(200)  
        .content(result)  
        .set('Content-Type', 'text/html');  
  
    return resp;  
\}
````

#### ````
Шаг 4. Добавить функцию ExtText() в шаблон документа

В файле шаблона договора добавьте вызовы функции `ExtText()` для каждой операции. В функции укажите идентификатор созданного модуля, например `8ca92961-2c8a-418e-abff-7761a962265a`, адрес метода, например `arithmetic`, свойства приложения или числовой аргумент и операцию:

1. Операция сложения: `\{ExtText("8ca92961-2c8a-418e-abff-7761a962265a", "arithmetic", \{\$sum\_total\}, "15 000", "add")\}` — получим итоговую стоимость по договору с учётом фиксированной суммы доставки в 15 000 рублей.

2. Операция вычитания: `\{ExtText("8ca92961-2c8a-418e-abff-7761a962265a", "arithmetic", \{\$sum\_total\}, \{\$advance\_payment\}, "subtract")\}` — получим остаток к оплате по договору после внесения авансового платежа.

3. Операция умножения: `\{ExtText("8ca92961-2c8a-418e-abff-7761a962265a", "arithmetic", \{\$advance\_payment\}, "2", "multiply")\} `— получим неустойку при досрочном расторжении договора в размере двойного авансового платежа.

4. Операция деления: `\{ExtText("8ca92961-2c8a-418e-abff-7761a962265a", "arithmetic", \{\$sum\_total\}, \{\$installment\_months\}, "divide")\} `— получим ежемесячный платёж при рассрочке в указанное количество месяцев.

Подробнее читайте в [статье о добавлении и настройке шаблона для документов](360026936731.md).

Предположим, что в карточке договора указано: общая сумма договора — 500 000, авансовый платёж — 100 000, срок рассрочки — 4 месяца. Тогда в сгенерированном по шаблону договоре рассчитаются следующие значения:

- итоговая сумма — 515 000;

- остаток к оплате — 400 000;

- неустойка — 200 000;

- ежемесячный платёж — 125 000.