Особенности работы в системе Global#

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

Наименование переменных для nullable типов и атрибутов#

Правила именования переменных: [Variable][a][t][Scope][Name][Suffix].

Компоненты именования:

  • [Variable] — определяет тип данных:

    • n — число;

    • s — строка;

    • j — строка в формате JSON;

    • d — дата;

    • r, x — запись;

    • u, cur — курсор;

    • l, blob — бинарные данные;

    • с — символьные данные;

    • b — булево значение;

    • id — идентификатор;

    • gid — глобальный идентификатор.

  • [a] — определяет, является ли переменная последовательностью;

  • [t] — определяет пользовательский тип;

  • [Scope] — область действия:

    • v — переменная процедуры;

    • p — параметр процедуры;

  • [Name] — имя переменной;

  • [Suffix] — суффикс:

    • _dz — системные атрибуты;

    • _z — проектные атрибуты.

Примеры именования параметров:

  • dStart — дата начала в таблице;

  • dvStart — дата начала переменной процедуры;

  • dgMaxDate — максимальная дата переменной пакета;

  • tvdaDate — тип коллекции дат в процедуре;

  • davDate — коллекция дат в процедуре;

  • uvStudents — курсор в процедуре.

Основные методы и принципы работы#

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

Для просмотра доступных методов любого класса выполните следующие шаги:

  1. Перейдите в Настройки системыОбозреватель проектов.

  2. Введите имя класса (например, Stm_OrderOut).

  3. Откройте файл с суффиксом Api (например, Stm_OrderOut_Api).

  4. Перейдите на вкладку Методы.

В этом разделе отображаются все доступные методы класса. Большинство классов содержат стандартный набор методов для работы.

Работа с текущей выборкой#

При запуске JEXL-скрипта часто происходит работа внутри существующей выборки (например, при выделении строки в таблице).

С помощью selection.getVar можно получить атрибуты текущей выборки:

var id = selection.getVar("атрибут");
var idvOrder = selection.getVar("id"); // "id" — название атрибута

Загрузка строки через rop#

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

Принцип работы:

  1. Сначала проверяет наличие данных в кэше.

  2. Если данных нет — загружает их из базы.

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

Получить строку можно с помощью метода load. Полученное значение будет типа rop:

ropOrder = Stm_OrderOutApi.load(idvOrder);

Доступ к атрибутам строки#

Обычные атрибуты (колонки таблицы) доступны напрямую через точку:

var svNumDoc = ropOrder.sNumDoc; // Номер документа
var idvClient = ropOrder.idClient; // ID клиента

Работа с JSON-атрибутами на примере Stm_OrderOut

Получение значений атрибутов:

  1. Получение всего JSON объекта:

var jvParams = ropOrder.jParams_dz; // Получаем полный JSON-объект параметров
  1. Получение конкретного значения по имени атрибута:

var svStation = Stm_OrderOutApi.getObjAttrValue(ropOrder, 'station'); // Получаем значение атрибута 'station'
  1. Получение значения по ID атрибута:

// Получаем ID класса из текущей выборки
var idvClass = selection.getVar('idClass'); // Получим id класса
// Находим ID атрибута по мнемокоду 'station' для указанного класса
var idvAttrStation = Btk_AttributeApi.findByMnemoCode(idvClass, 'station');
// Получаем значение атрибута для указанного заказа
var svStationById = Stm_OrderOutApi.getObjAttrValue(ropOrder, idvAttrStation);

Установка значений атрибутов:

  1. Установка по имени атрибута — передать название класса и название атрибута:

Stm_OrderOutApi.setObjAttrValue(ropOrder, 'station', "Новая станция");
  1. Установка по ID атрибута:

// Получаем ID класса из текущей выборки
var idvClass = selection.getVar('idClass');
// Находим ID атрибута по мнемокоду 'station' для указанного класса
var idvAttrStation = Btk_AttributeApi.findByMnemoCode(idvClass, 'station');
// Получаем значение атрибута для указанного заказа
var svStationById = Stm_OrderOutApi.getObjAttrValue(ropOrder, svStationById);
Stm_OrderOutApi.setObjAttrValue(ropOrder, svStationById, "Новое значение"); // Установка значения для атрибута с указанным ID

Изменение значений#

Чтобы изменить значение в строке, используйте специальные методы-сеттеры. У каждого класса свои сеттеры (смотрите в методах API):

// Меняем номер документа
Stm_OrderOutApi.setsNumDoc(ropOrder, "НОВЫЙ-001");

// Меняем клиента
Stm_OrderOutApi.setidClient(ropOrder, 12345L);

Поиск по мнемокоду#

Часто нужно получить ID по коду (например, код способа доставки):

// Получаем ID способа доставки "ЖД"
var idvZHD = Bs_DeliveryMethodApi.findByMnemoCode('ZHD');

Внимание

код чувствителен к регистру! „ZHD“ и „zhd“ — разные коды.

Пример полного скрипта:

// 1. Получаем ID из текущей выборки
var idvOrder = selection.getVar("id");

// 2. Загружаем строку заказа
var ropOrder = Stm_OrderOutApi.load(idvOrder);

// 3. Получаем атрибуты
var svNumDoc = ropOrder.sNumDoc; // Номер
var idvStationEndJson = Stm_OrderOutApi.getObjAttrValue(ropOrder, 'idStationEndJson');

// 4. Меняем номер
Stm_OrderOutApi.setsNumDoc(ropOrder, "НОВЫЙ-002");

// 5. Ищем ID способа доставки
var idvDelivery = Bs_DeliveryMethodApi.findByMnemoCode('ZHD');

Преобразование типов данных#

Метод

Пример использования

.asJLong()

"123".asJLong()

.toLong()

"456".toLong()

.toInteger()

"789".toInteger()

.toDouble()

"12.34".toDouble()

.toBigDecimal()

"123.45".toBigDecimal()

.asDate()

"2024-01-01".asDate()

.toDate("формат")

toDate("01.01.24", "dd.MM.yy")

.toString()

123.toString()

.asString()

321.asString()

.asList()

sql("SELECT...").asList()

.asSingle()

sql("SELECT...").asSingle()

.asScala()

[1,2,3].asScala()

.asJava()

scalaSeq.asJava()

.toJObject()

toJObject('{"id":1}')

Работа с датами#

Метод

Описание

Пример

getFirstDayOfMonth

Возвращает дату начала месяца от текущей даты

var a = getFirstDayOfMonth(); var b = getFirstDayOfMonth('27.01.2025 12:42:10');

getFirstDayOfPeriod

Возвращает первый день указанного периода

var a = getFirstDayOfPeriod(sysDate(), 'M'); var b = getFirstDayOfPeriod('27.01.2025 12:42:10', 'Q');

getLastDayOfMonth

Возвращает дату конца месяца от текущей даты

var a = getLastDayOfMonth(); var b = getLastDayOfMonth('27.01.2025 12:42:10');

getLastDayOfPeriod

Возвращает последний день указанного периода

var a = getLastDayOfPeriod(sysDate(), 'M'); var b = getLastDayOfPeriod('27.01.2025 12:42:10', 'Q');

nanoTime

Получить значение System.nanoTime()

var a = nanoTime();

sysDate

Возвращает текущую дату

var a = sysDate();

toDate

Переводит строку в дату по указанному формату

var a = toDate("27.02.2020 12:42:10"); var b = toDate("27.02.2020 12:42:10", "dd.MM.yyyy HH:mm:ss");

truncDate

Получение даты на начало дня от переданной

var a = truncDate(sysDate());

truncYear

Получение даты на начало года от переданной

var a = truncYear(sysDate());

-

Вычитает из даты указанное количество дней

var dYesterday = sysDate() - 1;

+

Добавляет к дате указанное количество дней

var dTomorrow = sysDate() + 1;

Работа в контексте выборки#

Контекст выборки (JexlSelScript) расширяет контекст бизнес-логики возможностью работы с выборками и пользовательским интерфейсом. Используется в тех случаях, когда необходимо получить данные из полей для пользовательского ввода.

Метод

Описание

Пример использования

varExists(name)

Проверяет существование переменной в текущей и мастер-выборках

if (varExists("client_id")) { ... }

selfVarExists(name)

Проверяет существование переменной только в текущей выборке

if (selection.selfVarExists("temp_value")) { ... }

getVar(name)

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

var id = selection.getVar("doc_id").asLong();

getSelfVar(name)

Получает значение только из текущей выборки

var code = selection.getSelfVar("product_code");

setVar(name, value)

Устанавливает значение переменной (ищет в иерархии выборок)

selection.setVar("status", "approved");

setSelfVar(name, value)

Устанавливает значение только в текущей выборке

selection.setSelfVar("comment", "Не заполнено");

addVar(name, value)

Добавляет новую переменную в текущую выборку

selection.addVar("processed_at", sysDate());

newForm()

Создает новую форму

Act_DocEdit.newForm().params(...).open();

.form()

Возвращает форму текущего контекста

selection.form();

.opers('Операция')

Возвращает указанную операцию для дальнейшего выполнения

selection.opers("CREATESTMORDERIN");

.execute()

Выполняет ранее полученную операцию

selection.opers("CREATESTMORDERIN").execute();

Работа с формой выборки#

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

var res = Btk_ClassAvi // Класс, предоставляющий форму выбора
.list() // Инициализация формы списка (табличное отображение)
.newForm() // Создание новой формы
.params({ // Передача параметров в форму в виде мапы
    "one": 1,
    "two": 2,
    "three": 3,
    "more": "many more"
})
.locates({"id": 146800}) // Выбор строки
.results(["id", "idClass"]) // Какие поля вернуть после выбора
.openLookup(); // Открытие окна

Метод

Описание

.list()

Форма будет отображаться как таблица (список записей). Возможные отображения можно посмотреть в обозревателе проекта в классе с расширением Avi

.newForm()

Создает новую формы

.params()

Передает параметры в форму (могут использоваться для фильтрации/логики)

.locates()

Установка строки на активную

.results()

Задает поля, которые вернутся после выбора

.openLookup()

Открывает окно выбора

.findSelection('Отображение')

Ищет и возвращает выборку, содержащую указанное отображение

.baseRep()

Возвращает ссылку на объект, к которому был вызван метод

Пример: Поиск и выполнение операций в связанной выборке

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

var sel = selection.form() // получает форму по выделенному элементу
.findSelection(Stm_OrderOutAvi.Card() // Ищет и возвращает **выборку**, содержащую указанное отображение
.baseRep()); // возвращает базовое представление объекта (ссылку)

if (sel != null) { // если выборка найдена, то выполняет действие
    sel.opers("CREATESTMORDERIN").execute(); // выполняет переданную операцию
}

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

selection.opers("CREATESTMORDERIN").execute();

Обработка результата:

if (res.getLookupResult() == LookupResult.ok()) {
    // Пользователь выбрал значение и нажал "OK"
    for(var i: 1 .. res.size()) { // Цикл по всем выбранным записям
        dialogs.showMessage("id " + res.getData(i, 0) + " idClass " + res.getData(i, 1));
    }
} else {
    // Пользователь закрыл форму или нажал "Отмена"
    dialogs.showMessage("Значение не было выбрано");
}
  • res.getLookupResult() — проверяет, как закрыли форму:

    • LookupResult.ok() — нажали «Выбрать»;

    • LookupResult.cancel() — нажали «Отмена» или закрыли окно.

  • res.size() — количество выбранных записей (если форма поддерживает множественный выбор).

  • res.getData(i, 0) — доступ к данным:

    • i — номер строки (начинается с 1);

    • 0 — индекс поля (соответствует порядку в .results([«id», «idClass»])).

Пример работы с мастер-выборками:

// Получаем значение из атрибута "id" выборки, приводим его к типу NString и пишем в переменную idTree
var idTree = getVar("id").asNString();

// Получаем атрибут DGLOBALENDDATE из мастер-выборки
var dEndDate = getVar("super$DGLOBALENDDATE").asNDate();

// Вызываем метод из пакета с передачей параметров
// Обратите внимание, для обращения к Api или пакетам используются их короткие имена (без скобок)
var fltCond = Act_UniversalReportPkg.getUniFilterCondByIdTree(idTree, dEndDate);

// Вызывается ещё один метод, возвращающий объект scala-класса immutable.Map[NString, Any]
var filters = Act_UniversalReportPkg.getFilterValues(idTree);

/* Определение Map-ы внутри jexl-скрипта. Отметим, что Map внутри jexl и объект scala-класса
Map (неважно mutable или immutable) - это разные объекты. Наиболее важным
фактом является то, что передать scala-объект Map, полученный в предыдущей
строке,
в пакетный метод, принимающий scala-объект Map, в jexl-скрипте напрямую нельзя,
именно поэтому приходится получать значения из переменной filters,
перезаписывать
их в jexl-Map param и потом передавать param в scala-метод. */

var param = {
    "flt_idDepOwner" : filters['flt_idDepOwner'],
    "flt_idAcc" : filters['flt_idAcc'],
    "flt_dFrom" : filters['flt_dFrom'],
    "flt_dTo" : filters['flt_dTo'],
    "flt_idAdjustMethod" : filters['flt_idAdjustMethod'],
    "flt_idAccCor" : filters['flt_idAccCor'],
    "uniFilterCondition_dz": fltCond
};

// Открываем новую форму с переданными параметрами
Act_TransAvi.defList().newForm().params(param).open();

Мастер-выборки:

  • Доступ через префикс super$;

  • Пример: getVar("super$PARENT_ID").

Типизация:

  • Используйте .asString(), .asDate() для явного преобразования;

  • Для чисел: .asBigDecimal(), .asJLong().

Дополнительные методы работы с формой выборки#

Открывает мастер пользовательского ввода по указанному идентификатору формы.

Btk_WizardLib().launch(getSelfVar("id").asNLong); // В качестве параметра передается id формы.

Работа с SQL#

Для работы с SQL используются команды:

  1. Для запросов на чтение:

sql(sqlText:String)
  1. Для запросов на запись:

tsql(sqlText:String).execute()

Методы обработки для sql:

Метод

Описание

Пример

.asList()

Вернуть список записей

sql("SELECT * FROM users").asList()

.asSingle()

Вернуть одну запись

sql("SELECT * FROM users WHERE id=1").asSingle()

Методы обработки для tSql:

Метод

Описание

Пример

.execute()

Выполнить запрос

tsql("DELETE FROM temp").execute()

Примеры:

Простые запросы:

// Чтение
var activeUsers = sql("SELECT name FROM users WHERE is_active=true").asList();

// Запись
tsql("UPDATE orders SET status='done' WHERE id=42").execute();

Обработка результатов:

// Вывод имен пользователей
sql("SELECT name FROM users").foreach(row -> {
    logInfo("User: " + row.name);
});

// Подсчет суммы
var total = 0;
sql("SELECT amount FROM payments").foreach(p -> {
    total = total + p.amount;
});

Параметризация:

var productId = selection.getVar('id');
var product = sql("SELECT * FROM products WHERE id=${productId}").asSingle();

var productId = selection.getVar('id');
var sSqlText = ''; // объявляем переменную, в которой будем собирать sql-выражение
sSqlText = "SELECT * FROM products WHERE id="; //
sSqlText += toString(productId);
sSqlText += "\r\n order by id";
var product = sql(sSqlText).asSingle();

var productId = selection.getVar('id');
var product = sql(`
    SELECT *
    FROM products
    WHERE id=${productId}`)
.asSingle();

Дополнительные методы#

Метод

Описание

Пример использования

lpad(str, len, ch)

Дополнение строки слева

lpad("5", 3, "0") "005"

rpad(str, len, ch)

Дополнение строки справа

rpad("5", 3, "0") "500"

flush()

Синхронизация с БД

flush()

commit()

Подтверждение транзакции

commit()

nvl(a, b)

Возвращает a, если не null, иначе b

nvl(var, "default")

isNull(x)

Проверка на null

isNull(obj)

isNotNull(x)

Проверяет, что переданное значение не null

isNotNull(obj)

pgArrayToNLongList

Конвертация массива в список

pgArrayToNLongList(arr)

parseId(gid: Object): Long

Получение идентификатора объекта из NGid-а Работает для строкового или NGid-значения

var sGid = "14323/44334"; var id = parseId(sGid);

parseIdClass(gid: Object): Long

Получение идентификатора класса из NGid-а Работает для строкового или NGid-значения

var sGid = "14323/44334"; var idClass = parseIdClass(sGid);

toJRops(rops: Traversable[Rop]): JexlToJRops

Обход записей, возвращенных объектным запросом, например byParent Выполняет запрос на чтение к базе данных и позволяет обойти записи

var l = toJRops(Btk_SomeEntityApi.byParent(rop)).asList(); for(r:l){ logInfo(r.id); logInfo(r.sSystemName); }

toJObject(json: String): JexlToJObject

Парсинг json-объекта

var jData = toJObject('{"id": 1}'); logInfo(jData.getLong("id"));

Работа с BTS процедурами#

Переход в раздел процедур:

Для того чтобы открыть перечень BTS-процедур, перейдите в Настройки системыНастройки и сервисыПроцедуры. Здесь можно просмотреть различные варианты существующих процедур. Можно перейти в карточку любой процедуры и посмотреть, какие действия там описаны.

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

Написание JEXL-кода:

Предположим, мы хотим рассчитать некоторую формулу на основе входящих параметров. Чтобы процедура вернула значение, объявим раздел с результатом и вернем соответствующее значение. Объявим входные параметры и расчетную формулу:

var nvParam1 = npInParam1;
var nvParam2 = npInParam2;
var nvParam3 = npInParam3;
var nvSum = (npInParam1 + npInParam2) * npInParam3;

// Для того чтобы процедура вернула значение, добавим возврат результата:
return nvSum;

Сохраните код.

Вызов процедуры через JEXL-редактор:

Перейдите в отдельный редактор JEXL. Объявите служебную функцию для типизации данных. Данная функция будет возвращать тип данных scala.Tuple2, состоящий из двух переменных.

var tuple2 = (v1, v2) -> { return new(`scala.Tuple2`, v1, v2); };

Заведите массив параметров, в котором запишите входящие значения. В нем будет объявлен массив Scala (это делается за счет указания последнего элемента с троеточием). Первые три элемента будут объявлены с помощью функции tuple2. В каждом таком элементе массива будет указано название параметра и его значение.

var tuple2Params = asScala([
    tuple2("npInParam1", 10l),
    tuple2("npInParam2", 125l),
    tuple2("npInParam3", 1000l),
    ...
]);

Объявите переменную, в которую при помощи API-функции findByMnemoCode поместите идентификатор ранее созданной процедуры:

val idvBtsProcedure = Bts_ProcedureApi.findByMnemoCode(`Sale_Test1`);

Далее вызовите конструкцию для расчета значения BTS-процедуры и запишите результат в переменную. Для этого используйте API-метод Bts_ProcedureLib, передав в него:

  • идентификатор процедуры;

  • массив параметров;

  • дополнительный контекст выборки для расчета.

var nvSumCalc = Bts_ProcedureLib.execById(idvBtsProcedure, tuple2Params, selection.coreRep());

Метод Bts_ProcedureLib.execById ожидает параметры в формате, который понимает Scala, поэтому мы используем кортеж. Кортежи здесь — это «мост» между JEXL и Scala, обеспечивающий четкую, безопасную и удобную передачу параметров.

Верните результат процедуры и выведите его на экран.

dialogs.showMessage(toString(nvSumCalc));

Аналогичным образом можно создавать и более сложные BTS-процедуры.

Работа с мониторингом сессий сервера приложений#

Система автоматически ведет метаинформацию о сессиях всех пользователей. Доступ к этой информации организован следующим образом:

Настройки системыСервисИнструментыМониторинг сессий сервера приложений.

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

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

Получение текущего действия:

session.applicationInfo().action();

Обновление информации о действии:

session.applicationInfo().action_$eq("Значение текущего действия");

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

for (ropWW: ropaIntWar) {
    session.applicationInfo().action_$eq(```Phosagro_SB0205_NEW - ВП - ${toString(ropWW.gid)}```);
    Stk_InternalWarrantApi.setdExecDateOut(ropWW, cDate);
    session.applicationInfo().action_$eq(```Phosagro_SB0205_NEW - выполняем ВП - ${toString(ropWW.gid)}```);
    Stk_InternalWarrantApi.setidStateOut(ropWW, idvStateIntWar);
    session.applicationInfo().action_$eq(```Phosagro_SB0205_NEW - Создаем РСО```);
    var ropWarOut = Stk_WarrantOutApi.createWarrantOutByInternalWarrant(ropWW);
    // Заполняем даты исполнения
    Stk_WarrantOutApi.setdDocDate(ropWarOut, cDate);
    Stk_WarrantOutApi.setdExecDate(ropWarOut, cDate);
    // Выполняем РСО
    session.applicationInfo().action_$eq(```Phosagro_SB0205_NEW - выполняем ВП - ${toString(ropWarOut.gid)}```);
    Stk_WarrantOutApi.setidState(ropWarOut, idvStateWarr);
};

Метод setUniCharValue используется для установки значения универсальной характеристики (универсального атрибута) объекта в системе.

setUniCharValue(rop: ApiRop, idpUniChar: Long, pValue: Any): Unit

Параметр

Тип (Scala)

Описание

rop

Rop

Контекст выполнения операции (объект, к которому применяется изменение)

idpUniChar

Long

Идентификатор универсальной характеристики

pValue

Any

Новое значение характеристики (может быть Long, String и др)

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

// 1. Получаем GID значения "." из справочника
val gidChr = sql("""
    SELECT r.gid
    FROM Btk_UniversalReference r
    JOIN btk_objecttype b ON r.idobjecttype = b.id
    WHERE r.sSystemname = '.'
    AND b.scode = 'ur_O2C_sort_type'
""").asSingle();

Stm_OrderOutApi.setUniCharValue(rop, 'O2C_sort_type', gidChr.gid);

Работа с печатью#

Пользователь может:

  • Сформировать отчёт по его системному имени;

  • Запустить JEXL-скрипт печатной формы, привязанной к типу объекта.

Создание отчета происходит с помощью следующего метода:

Rpt_Lib.createReportExJexl(
    reportName: String,
    reportVersionDate: Date,
    postBuildAction: PostBuildAction,
    propertyMap: Map[String, Any],
    idpObjectTypePrintForm: NLong = None.nl
): Unit

Параметр

Тип (Scala)

Описание

idpObjectTypePrintForm

Long

id ПФ на типе объекта. Может быть null

reportName

String

Имя отчета

reportVersionDate

Date

Дата

postBuildAction

PostBuildAction

Действие, которое необходимо произвести после заполнения отчёта

propertyMap

Map[String, Any]

Карта входящих параметров

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

var idvOrderClass = selection.getVar("idClass");
var idvOrder = selection.getVar("id");

var NLong = function(number) { // локальная функция для преобразования Long в NLong
    return new ("ru.bitec.app.gtk.lang.NLong", number);
};

var spReportName = "Stm_InvoiceOut";
var dpReportVersionDate = sysDate();
var vPostBuildAction = session
    .sbtClassLoader()
    .loadClass('ru.bitec.app.gtk.gl.postbuildaction.PostBuildAction')
    .design();

var propertyMap = {
    "idSrcObject" : NLong(idvOrder),
    "idSrcClass" : NLong(idvOrderClass)
};

var idpObjectTypePrintForm = null;

Rpt_Lib.createReportExJexl(
    spReportName,
    dpReportVersionDate,
    vPostBuildAction,
    asScala(propertyMap),
    idpObjectTypePrintForm
);

Тип PostBuildAction:

PostBuildAction — это перечисление (enum) из класса ru.bitec.app.gtk.gl.postbuildaction.PostBuildAction, определяющее действия после построения отчета.

Доступные значения:

  • .show() — загружает отчет на клиент;

  • .save() — сохраняет отчет;

  • .print() — загружает отчет на клиент и, если в конфигурации системы включена опция печати (Configuration.Printing.enableNetworkPrinting), печатает отчет на локальном (для сервера) принтере.

Примечание: Для .print() поведение зависит от конфигурации сервера. Если печать не настроена, отчет просто загружается на клиент.

Особенности:

  • Для работы с ID используется тип NLong (внутренний класс системы);

  • asScala() преобразует Java-коллекции в Scala-совместимые;

  • Если idpObjectTypePrintForm = null — отчёт строится по reportName.