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

# Запись JEXL-макросов

Сервис записи JEXL-макросов преобразует действия пользователя в готовые JEXL-скрипты. Инструмент создает сценарии автоматизации без ручного написания кода и глубокого изучения JEXL.

Основные сценарии использования:

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

- Пакетное обновление данных — изменение реквизитов у группы объектов.

- Формирование отчетных форм — создание печатных форм с настройкой шаблонов.

- Импорт данных из файлов — обработка XLSX-файлов для переноса информации.

Примечание

Записываются только вызовы `Api` и `Pkg`. Макросы не содержат вызовы интерактивной логики.

## Создание макросов

### Начало записи

1. Перейдите в Сервис -> Инструменты -> Начать запись JEXL-скрипта.

2. В главном меню появится красный флаг — индикатор записи.

Примечание

Перед записью сохраните или откатите все несохраненные данные во всех формах.

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

### Запись действий

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

### Завершение и сохранение

1. Остановите запись через:

   - Красный флаг в главном меню.

   - Сервис -> Инструменты -> Закончить запись JEXL-скрипта.

2. Просмотрите записанный скрипт в появившемся окне.

3. При закрытии окна подтвердите сохранение.

4. Выберите папку (по умолчанию — Личные).

5. Скрипт сохранится в Библиотеке скриптов.

## Просмотр и редактирование

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

Путь: `Настройка системы > Настройки и сервисы > Сервисы JEXL > Библиотека JEXL`.

В библиотеке отображается дерево каталогов и скриптов. По умолчанию доступны два каталога:

- Личные — содержит скрипты, доступные только текущему пользователю.

- Общего назначения — содержит скрипты, доступные всем пользователям.

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

Чтобы открыть скрипт в редакторе, дважды нажмите на нужный пункт дерева. Открытый скрипт можно просмотреть, изменить и выполнить.

Аудит запусков скрипта

На вкладке Аудит отображаются результаты запуска выбранного скрипта.

Данные можно отфильтровать:

- по дате выполнения;

- по пользователю, который выполнил запуск.

Если запуск завершился с ошибкой, подробности отображаются в окне Стек ошибок.

В окне Дополнительная информация отображаются данные, которые автор скрипта добавил в лог с помощью команды `audInfo`.

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

## Примеры скриптов

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

    var rop_Rpt_Report1 = Rpt_ReportApi.insert();
    Btk_ObjectGroupApi.register(rop_Rpt_Report1, 27851L, 1B, 1B);
    Rpt_ReportApi.setsSystemName(rop_Rpt_Report1, 'SomeReportName');
    Rpt_ReportApi.setsCaption(rop_Rpt_Report1, 'Отчет');
    Rpt_ReportApi.setidModule(rop_Rpt_Report1, 901L);
    var rop_Rpt_ReportVersion1 = Rpt_ReportVersionApi.insertByParent(rop_Rpt_Report1);
    Rpt_ReportVersionApi.setidReportType(rop_Rpt_ReportVersion1, 451L);

В сформированном скрипте все идентификаторы имеют исходный вид. Если этот скрипт планируется использовать на других базах данных, где идентификаторы будут отличаться, необходимо заменить их получение в скрипте - например, на метод `findByMnemoCode`.

Видоизмененный скрипт:

    var rop_Rpt_Report1 = Rpt_ReportApi.insert();
    Btk_ObjectGroupApi.register(rop_Rpt_Report1, 27851L, 1B, 1B);
    Rpt_ReportApi.setsSystemName(rop_Rpt_Report1, 'SomeReportName');
    Rpt_ReportApi.setsCaption(rop_Rpt_Report1, 'Отчет');
    Rpt_ReportApi.setidModule(rop_Rpt_Report1, Btk_ModuleApi.findByMnemoCode('btk'));
    var rop_Rpt_ReportVersion1 = Rpt_ReportVersionApi.insertByParent(rop_Rpt_Report1);
    Rpt_ReportVersionApi.setidReportType(rop_Rpt_ReportVersion1, Rpt_ReportTypeApi.findByMnemoCode('jasper'));

## Обработка данных Excel

Для работы с `xlsx` в `jexl` используется библиотека poi.apache.org.

Для удобства загрузки файлов написана функциональная библиотека `Bts_XlsxPkg`. Метод `uploadParseFiles` открывает диалог выбора файла и парсит его, предоставляя разработчику возможность его обработки. Создается объект класса `org.apache.poi.ss.usermodel.Workbook`.

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

    lib("Btk_XlsxLib").uploadParseFiles(fun);

Где `fun` - это функция Jexl, которая будет выполняться для обработки данных из Excel.

Пример обработки xlsx:

    var fun = x -> {
      var sheet = x.getSheet("Материалы");
      var lastRowNum = sheet.getLastRowNum();
      var i = 1;
      while (i <= lastRowNum ){
        var svNomName = sheet.getRow(i).getCell(3).getStringCellValue(); //  Условное наименование
        var idvMSRItem = sheet.getRow(i).getCell(4).getNumberCellValue().toBigDeсimal(); // ЕИ
        var idvGost = sheet.getRow(i).getCell(5).getStringCellValue(); // ГОСТ
        var idvSortamentType = sheet.getRow(i).getCell(6).getNumberCellValue().toBigDeсimal(); // Тип сортамента

       var rop_Bs_Goods1 = Bs_GoodsApi.insert();
       Bs_GoodsApi.setsNomName(rop_Bs_Goods1, svNomName); // установка условного наименования
       Bs_GoodsApi.setidMeasureItem(rop_Bs_Goods1, idvMSRItem); // установка ЕИ
       Bs_GoodsApi.setsGost(rop_Bs_Goods1, svNomName); // установка условного наименования
       Bs_GoodsApi.setsNomName(rop_Bs_Goods1, svNomName); // установка условного наименования

       commit();
       i = i+1;
      }
      true;
    }

    lib("Btk_XlsxLib").uploadParseFiles(fun);

Приведенный ниже пример функции `fun` иллюстрирует, как обработать данные из файла Excel и создать объекты в системе на их основе.

Расширенная обработка с разными типами данных:

    var fun = x -> {
    // Получение листа "Лист1" из файла Excel
    var sheet = x.getSheet("Лист1");

    // Определение количества заполненных строк в файле
    var lastRowNum = sheet.getLastRowNum();
    var i = 0;

    while (i <= lastRowNum) {
    // Класс для которого мы создаем объекты
    var rop_RplTst_AllDbTypes1 = RplTst_AllDbTypesApi.insert();

        // Получение значений из ячеек Excel и преобразование их к необходимым типам
        // Для получения значения типа Long нужно дополнительно использовать метод toLong
        var vjson = sheet.getRow(i).getCell(0).getStringCellValue();
        var vsystemname = sheet.getRow(i).getCell(1).getStringCellValue();
        var vcaption = sheet.getRow(i).getCell(2).getStringCellValue();
        var vgidrefclassany = sheet.getRow(i).getCell(3).getStringCellValue();
        var vidobjecttype = sheet.getRow(i).getCell(4).getNumericCellValue().toLong();
        var vdate = toDate(sheet.getRow(i).getCell(5).getStringCellValue());

        // Преобразование для NNumber
        var vNumber = sheet.getRow(i).getCell(6).getNumericCellValue().toBigDecimal();

        // Установка значений для созданного объекта
        RplTst_AllDbTypesApi.setjJson(rop_RplTst_AllDbTypes1, vjson);
        RplTst_AllDbTypesApi.setsSystemName(rop_RplTst_AllDbTypes1, vsystemname);
        RplTst_AllDbTypesApi.setsCaption(rop_RplTst_AllDbTypes1, vcaption);
        RplTst_AllDbTypesApi.setgidRefAny(rop_RplTst_AllDbTypes1, vgidrefclassany);
        RplTst_AllDbTypesApi.setNumber(rop_RplTst_AllDbTypes1, vNumber);

        // Проверка и установка idObjectType только если он не равен 0
        if (vidobjecttype != 0) {
          RplTst_AllDbTypesApi.setidObjectType(rop_RplTst_AllDbTypes1, vidobjecttype);
        }

        // Установка даты
        RplTst_AllDbTypesApi.setdDate(rop_RplTst_AllDbTypes1, vdate);

        // Сохранение изменений
        commit();

        // Увеличение счетчика строк
        i = i + 1;
    }

    // Возврат булевого значения, необходимого для выполнения скрипта
    true;
    }

Запуск скрипта

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

С помощью этой библиотеки вы можете эффективно работать с данными Excel и использовать записанные Jexl-скрипты для массовой обработки и создания объектов по сложным сценариям.

Полный тестовый скрипт обработки Excel:

    var fun = x -> {
      var sheet = x.getSheet("Лист1");
      var lastRowNum = sheet.getLastRowNum();
      var i = 0;
      while (i <= lastRowNum ){
        var rop_RplTst_AllDbTypes1 = RplTst_AllDbTypesApi.insert();
        var vjson = sheet.getRow(i).getCell(0).getStringCellValue();
        var vsystemname = sheet.getRow(i).getCell(1).getStringCellValue();
        var vcaption = sheet.getRow(i).getCell(2).getStringCellValue();
        var vgidrefclassany = sheet.getRow(i).getCell(3).getStringCellValue();
        var vidobjecttype = sheet.getRow(i).getCell(4).getNumericCellValue().toLong();
        var vdate = toDate(sheet.getRow(i).getCell(5).getStringCellValue());

        RplTst_AllDbTypesApi.setjJson(rop_RplTst_AllDbTypes1, vjson);
        RplTst_AllDbTypesApi.setsSystemName(rop_RplTst_AllDbTypes1, vsystemname);
        RplTst_AllDbTypesApi.setsCaption(rop_RplTst_AllDbTypes1, vcaption);
        RplTst_AllDbTypesApi.setgidRefAny(rop_RplTst_AllDbTypes1, vgidrefclassany);
        if (vidobjecttype != 0) RplTst_AllDbTypesApi.setidObjectType(rop_RplTst_AllDbTypes1, vidobjecttype);
        RplTst_AllDbTypesApi.setdDate(rop_RplTst_AllDbTypes1, vdate);

        commit();
        i = i+1;
      }
    true;
    }

    lib("Btk_XlsxLib").uploadParseFiles(fun);

Внимание

- Пустые ячейки: могут возвращать 0 вместо null — добавляйте проверки.

- Типы данных: следите за соответствием типов Excel и системы. В приведенном примере, используется метод getStringCellValue() для получения текстовых значений, и getNumericCellValue().toLong() для числовых значений.

- Возвращаемое булево значение: функция должна возвращать true/false.

## Работа с файлами

### Загрузка во временный каталог

    files.uploadFileToTemp(res -> {
      var file = res.file(); //java.io.File
      //чтение содержимого файла
      var utils = new('org.apache.commons.io.FileUtils');
      var content = utils.readFileToString(file, "UTF-8");

      dialogs.showMessage(content);
      true;
    });

Примечание

Работает только для jexl-скриптов в контексте выборки.

### Выгрузка строки как файла

    var text = "Привет!"
    files.downloadBytes(text.getBytes("UTF-8"), "Имя_Файла.txt", true, false);

Примечание

Работает только для jexl-скриптов в контексте выборки.

## Необходимые права

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

1. Стандартные права на приложение и доступ к Сервис -> Инструменты -> Закончить запись JEXL-скрипта.

2. Привилегия Доступ к инструментам меню Сервиса для объекта `Btk_ManagementPkg`.