Руководство прикладного разработчика#
Термины#
Термин |
Значение |
|---|---|
Platform V |
Набор программных продуктов Platform V, представляющих совокупность функциональных возможностей и позволяющих обеспечить быстрое конструирование информационных систем из множества готовых компонентов |
Редакция |
Отдельный расчетный алгоритм, который использует зафиксированный в версии набор входных/выходных параметров |
Продуктовая фабрика |
Подсистема, которая выполняет обслуживание группы продуктов или автоматизацию группы функций продуктов |
Сокращения#
Сокращение |
Значение |
|---|---|
АС |
Автоматизированная система |
НСИ |
Нормативно-справочная информация |
DSL |
Domain-Specific Language, предметно-ориентированный язык, который используется в Продукте |
Системные требования#
Аппаратные требования#
В качестве клиентской части Конструктора Стратегий Продукта используется АРМ, реализуемое по технологии "тонкого" клиента (WEB-интерфейс). Минимальные требования к составу оборудования системного блока типового АРМ по WEB-технологии и их характеристики:
процессор — Pentium III;
объем оперативной памяти — 512 Мб;
сетевая карта;
видеокарта — SVGA 32 Мб с поддержкой видео режима с глубиной цвета не хуже HiColor (65536 цветов);
жёсткий диск — 10 Гб;
мониторы с разрешающей способностью не менее 1024х768 пикселей.
Программные требования#
Требования к ПО:
сервер приложений WildFly 10.1.0.Final;
OpenJDK 1.8.
Подключение и конфигурирование#
Для корректной установки Продукта требуется наличие следующих компонентов – модулей в сервере приложений, от которых зависит Продукт:
<dependencies>
<module name="org.dom4j"/>
<module name="deployment.custodian-distr-impl-ear.ear" services="import" optional="true"/>
<module name="deployment.dpl-lite-ear-${version}.ear" meta-inf="import" optional="true"/>
<module name="deployment.seap-lib-${version}.ear" meta-inf="import" services="import" optional="true" />
</dependencies>
Миграция на текущую версию#
Возможности Продукта доступны сторонним Продуктовым фабрикам и другим приложениям исключительно через API. Поэтому выполнять миграцию приложения на текущую версию Продукта нужно только в случае изменения используемой приложением части спецификации пользовательского API.
Сведения о способах использования API Product Pricing можно найти в документе Описание API и в разделе Описание параметров API.
Разработка первого приложения с использованием программного продукта#
Требования к окружению приведены в разделе "Системные требования" документа "Руководства по установке". Подключение и конфигурирование продукта описано в разделе "Подключение и конфигурирование" документа "Руководство прикладного разработчика". Примеры использования API программного продукта, а также описание параметров запроса и ответа, приведены в приведены в разделе “Описание параметров API” и в документе "Описание API".
Использование программного продукта#
Примеры использования API программного продукта описаны в разделе “Описание параметров API” и в документе "Описание API". Продукт Platform V Product Pricing – решение для быстрой реализации алгоритмов и управления бизнес-логикой на основе специализированного языка, формально описывающего процесс принятия решений в виде системы бизнес-правил – декларативных утверждений, указывающих на выполнение некоторых действий в случае выполнения определенных условий. Сферы применения: организация алгоритмов в области принятия решений и расчетов по гибкой тарификации услуг, процентных ставок, комиссий, страховых премий, инвестиционных предложений, прочих финансовых услуг с учетом динамически меняющихся параметров (объемов потребления услуг, применения тарифных планов, ставок межбанковского кредитования и т.д.).
Часто встречающиеся проблемы и пути их устранения#
В настоящее время информации о возможных проблемах не имеется.
Предметно-ориентированный язык (DSL)#
В рамках Product Pricing реализован внешний предметно-ориентированный язык (DSL=DomainSpecific Language) с ограниченным набором конструкций и упрощенной грамматикой, созданной для удобства чтения, понимания и написания кода.
Грамматика состоит из простых односложных конструкций (присваивание, вызов функции, арифметические действия, сравнение). Основной акцент при определении грамматики был сделан на то, что в процессе выполнения программы нам необходимо вычислить результат (набор выходных параметров). Соответственно большая часть конструкций ориентирована на присвоение переменной какого-либо значения.
В грамматике не предполагается введение операторов перехода (goto). Также не предполагается введение циклов с задаваемым количеством шагов или условием (for, while).
Описание грамматики DSL#
Каждое правило DSL состоит из набора присвоений переменных, объявления функций и результата. В конце строки обязательно ставится точка с запятой (";").
Типы данных#
Поддерживаемые типы данных делятся на простые, составные и списковые:
Простые типы данных:
Строка — задаётся в кавычках:
"успешно".Целое число:
14.Дробное число:
17.6.Логическое выражение – ДА / НЕТ:
ДА.Дата:
13.01.1998.
Составные типы данных:
Наборы полей:
[название: "базовый", код: "base", значение: 15].Встроенные наборы полей.
Списковые типы. Тип элементов списка в свою очередь также может быть простым, набором полей или встроенным набором полей:
список;список([имя: "Иван", возраст: 47], имя: "Федор", возраст: 14]).
Переменные#
Правила именования переменных#
В имени переменной могут быть использованы русские буквы (в верхнем/нижнем регистре), цифры, символ подчеркивания ("_"). Первым символом в названии обязательно должна идти буква. Именем переменной не могут являться зарезервированные слова.
Зарезервированные слова представлены в таблице ниже:
к |
списку |
максимум |
минимум |
первый |
|---|---|---|---|---|
и |
это |
задана |
задан |
задано |
не |
список |
результат |
ДА |
НЕТ |
или |
вход |
выход |
добавить |
ошибка |
все |
индекс |
Итого, корректные названия переменных:
ставка;Процент1_;средний_остаток.
Некорректные названия переменных:
1сумма (в начале имени переменной должна идти буква);
___сумма (в начале имени переменной должна идти буква);
Summ (в имени не могут использоваться латинские буквы);
Клиент!возраст (допустимые специальные символы для использования - "." и "_");
список (зарезервированное слово).
Категории переменных#
Для читабельности переменные разделены на следующие категории:
Входные параметры (идут с префиксом "вход.") – те параметры, которые передаются на вход правилу: вход.возраст_ клиента.
Выходные параметры (идут с префиксом "выход.") – те параметры, которые возвращаются из правила: выход.процентная_ ставка.
Временные переменные – те переменные, которые создаются в самом правиле (идут без префикса): переменная.
Присвоение значений переменным#
Присвоение значений переменным бывает двух типов - с условием и без него. В свою очередь присвоение с условием может быть как однострочным (в случае единственного условия), или многострочным (блоковым), когда условий несколько.
Присвоение без условий#
DSL оперирует с переменными, которым может быть присвоено:
конкретное значение:
переменная: = 14.0;
переменная: = "успешно";
переменная: = ДА;
значение другой переменной:
переменная_1:= 3;
переменная_2:= переменная_1;
набор полей:
переменная:= название:"базовый", значение:10];
список:
переменная:=("а","б","в");
переменная:=(67.5);
переменная:=(переменная_1, переменная_2, переменная_3);
результат вычисления функции:
переменная:=разница_в_днях(вход.дата_открытия_вклада, текущая_дата);результат выполнения арифметического выражения с участием, как конкретных значений, так и других переменных, и функций:
переменная:=вход.сумма * 2 + 50;
переменная:=(вход.сумма * вход.процент + 1) * 2;
Присвоение с одним условием (однострочное)#
В случае если переменной должно быть присвоено значение только при выполнении определенного условия, необходимо использовать условную операцию присвоения:
<переменная>:=<логическое_выражение> =><результат_вычисления>;
Например:
комиссия:=сумма>500=>0;
Логические выражение#
Каждое отдельное логическое выражение должно возвращать значения: истина, ложь.
Логическое выражение может представлять собой:
Конструкцию сравнения вида:
<операнд_1> <оператор сравнения> <операнд_2>
Операндом может являться переменная, константа, вызов функции или арифметическое выражение.
Проверку на существование значения у переменной:
<переменная> [не] задан.
Результат выполнения функции, которая возвращает значения ДА или НЕТ.
Значение логической переменной.
Примеры логических выражений:
вход.возраст_клиента > 55;вход.возраст_клиента > получить_пенсионный_возраст();55 < вход.возраст_клиента;вход.сумма * 2 < 10000;разница_в_днях(вход.дата_открытия_вклада, текущая_дата) < 365;вход.возраст_клиента задан;вход.пол_клиента не задан;список_содержит(список_строк, "123").
Логические выражения могут быть скомбинированы с использованием операторов "и", "или" и сгруппированы между собой при помощи скобок. Пример:
(вход.возраст_клиента > 60 и вход.пол_клиента = "мужской") или
(вход.возраст_клиента > 55 и вход.пол_клиента = "женский")
В логических выражениях могут быть использован оператор отрицания "не". Пример:
не (вход.возраст_клиента > 55);не (вход.пол_клиента = "Мужской").
Результат вычисления#
Результат вычисления представляет собой одну из конструкций: переменная, константа, арифметическое выражение, вызов функции. Результат вычисления всегда идет после логического выражения и отделяется от логического выражения специальным символом "=>". Пример результата вычисления (выделен жирным):
вход.возраст_клиента > 60 => 15.0;вход.возраст_клиент > 60 => получить_базовую_ставку_из_НСИ();вход.возраст_клиент > 60 => получить_базовую_ставку_из_НСИ() + 1.0.
Присвоение с несколькими условиями (блоковое)#
При необходимости группировки условий выбора используется блоковое присвоение переменных с использованием группирующих фигурных скобок "{", "}". Блоковое присвоение переменных имеет вид:
переменная := < первый, все, максимум, минимум> {
логическое_выражение_1 => результат_1;
логическое_выражение_2 => результат_2;
...
логическое_выражение_N => результат_N;
}
Если условие не требуется, логическое выражение и символ "=>" опускаются.
Алгоритм и результат выполнения блокового присвоения переменных зависят от ключевого слова перед блоком (первый, все, максимум, минимум). Если ключевое слово не указано, вычисление происходит как в случае "первый".
В случае, когда в блоке все условия являются ложными, значение переменной не изменяется.
Первый#
В этом случае будет выполнено первое "сработавшее" присвоение.
// Пример 1.
переменная := первый {
1 > 0 => 1;
2 > 0 => 2;
3 > 0 => 3;
}
В данном примере, как только будет обнаружено первое истинное условие (1 > 0), Продукт прервёт обработку блока (то есть, оставшиеся два условия не будут проверены) и выполнит присвоение. Таким образом, результат этого присвоения:
переменная = 1
// Пример 2
переменная := первый {
0 > 0 => 1;
1 > 0 => 2;
2 > 0 => 3;
}
В данном примере, первое условие (0 > 0) является ложным. Поэтому обработка блока прервётся только после проверки второго условия. Таким образом, результат этого присвоения:
переменная = 2
Все#
В этом случае будут выполнены все "сработавшие" присвоения.
// Пример 3
переменная := все {
1 > 0 => 1;
2 > 0 => 2;
3 > 0 => 3;
}
В данном примере все три условия (1 > 0, 2 > 0, 3 > 0) являются истинными, значит, последовательно переменной будет присвоено три значения(1, 2, 3). Таким образом, результат этого присвоения:
переменная = 3
// Пример 4
переменная := все {
1 > 0 => 1;
1 > 2 => 2;
1 > 3 => 3;
}
В данном примере первое условие (1 > 0) является истинным, и после его проверки в переменную запишется первое значение (1). Оставшиеся два условия являются ложными и никак не изменят значение переменной. Результат этого присвоения:
переменная = 1
В данном примере результат вычисления зависит от предыдущего вычисления:
// Пример 5
переменная := все {
1 > 0 => 1;
2 > 0 => переменная + 2;
3 > 0 => переменная + 3;
}
В результате вычисления первой строки блока, в переменную будет записано значение 1 (так как 1 > 0). После этого выполнится вторая строка – и результат вычисления будет равен переменная (=1) + 2 = 1 + 2 = 3. После этого выполнится третья строка – и результат вычисления будет равен переменная (=3) +3 = 3 + 3 = 6. Итоговый результат:
переменная = 6
Максимум / Минимум#
В этом случае будут вычислены все "сработавшие" значения, и из них только максимальное (минимальное) значение будет присвоено переменной.
// Пример 6
переменная := максимум {
1 > 0 => 1;
2 > 0 => 2;
3 > 0 => 3;
}
В данном случае все три условия (1 > 0, 2 > 0, 3 > 0) истинны. Однако, выберется только максимальное значение ( = 3). Таким образом, в результате
переменная = 3
Работа с числовыми типами данных#
Описание#
В DSL к числовым типам данных относятся целые и дробные числа. В качестве разделителя дробной части используется точка:
8;
9.05.
С числами можно выполнять арифметические операции: сложение(+), вычитание(-), умножение(*), деление(/), остаток от деления(%). Для изменения порядка действий используются круглые скобки, например, следующим образом: 9*(5+1).
Предопределённые математические функции#
Для работы с числами можно использовать предопределённые функции:
целое_от_деления(делимое, делитель): функция возвращает целую часть от частного.
возвести_в_степень(основание, показатель): функция возвращает значение аргумента основание, возведённое в степень показатель.
округлить(число, количество_знаков): функция возвращает число, округлённое до знака, переданного в качестве аргумента.
округлить_вверх(число, количество_знаков), округлить_вниз(число, количество_знаков): функция возвращает число, округлённое в большую/меньшую сторону до знака, переданного в качестве аргумента.
число_Пи(), число_е(): функция возвращает значение числа Pi/e.
синус(угол), косинус(угол), тангенс(угол), котангенс(угол): функция возвращает синус/ косинус / тангенс / котангенс угла. Угол задан в радианах.
градусы_в_радианы(градусы): функция переводит градусы в радианы.
радианы_в_градусы(радианы): функция переводит радианы в градусы.
модуль(число): функция возвращает модуль числа.
натуральный_логарифм(число): функция возвращает натуральный логарифм числа.
логарифм(число, основание): функция возвращает натуральный логарифм числа с основанием, переданным в качестве аргумента.
случайное_число(): функция возвращает случайное число в диапазоне от 0 до 1.
Работа со строками#
Описание#
Строки задаются внутри двойных кавычек:
"Мужской"
Для объединения нескольких строк используется операция конкатенации строк (+). При попытке конкатенации строки со значением другого типа, оно неявно преобразуется к строке, например, следующим образом.
"Клиент с именем " + имя_клиента + " отсутствует.";
"Результат = " + ДА;
"строка" + 1 +2;
1 + 2 + "строка".
Результатом третьего выражения будет строка «строка12», а четвёртого «3 строка», т.к. операции выполняются слева направо.
Предопределённые функции для работы со строками#
Для работы со строками можно использовать предопределённые функции:
строка(строка): функция возвращает строковое представление объекта.
верхний_регистр(строка), нижний_регистр(строка): функция возвращает строку, в которой все символы преобразованы в верхний/нижний регистр
целое_число(строка), дробное_число(строка): функция преобразовывает строковое представление числа в целое/дробное число*.*
подстрока(строка, начало, длина): возвращает подстроку, первый символ и длина которой переданы в аргументах.
содержит_подстроку(строка, подстрока): функция проверяет, входит ли подстрока в строку.
равны_без_учета_регистра(строка_1, строка_2): функция проверяет, равны ли две строки без учёта регистра.
первое_вхождение(строка, подстрока), последнее_ вхождение(строка, подстрока): функция возвращает индекс первого/последнего вхождения подстроки в строку. Если подстрока в строку не входит, то функция возвращает 0.
длина(строка): функция возвращает длину строки. Если строка не задана, функция возвращает 0.
заменить_все(строка, подстрока, новая_подстрока), заменить_первое_вхождение(строка, подстрока, новая_ подстрока): функция возвращает строку, с которой все подстроки/первое вхождение подстроки заменены на новые, переданные в качестве аргументов.
разбить_ строку(строка, разделитель): функция возвращает список подстрок, полученных разделением строки с помощью разделителя, переданного в качестве аргумента.
соответствует_шаблону(строка, шаблон): функция проверяет, соответствует ли строка заданному шаблону.
получить_ группы(строка, шаблон): функция проверяет, соответствует ли строка заданному шаблону и возвращает список групп. Если строка не соответствует шаблону, возвращается пустой список.
Работа с датами#
Описание#
Даты можно задавать в следующем формате:
**<день>.<месяц>.<год>**
Например: 01.10.2015
Предопределённые функции для работы с датами#
Для работы с датами можно использовать предопределённые функции:
разница_в_днях(дата_1, дата_2), разница_в_неделях(дата_1, дата_2), разница_в_месяцах(дата_1, дата_2), разница_в_годах(дата_1, дата_2): возвращают разницу между датами в днях, неделях, месяцах и годах соответственно.
первая_дата_раньше(дата_1, дата_2): функция сравнивает две даты, и если дата_1 меньше дата_2, то возвращает ДА, в противном случае возвращает НЕТ.
число(дата), месяц(дата), год(дата): возвращает число, месяц и год даты соответственно. Возвращаемое значение – число.
день_недели(дата): возвращает день недели.
прибавить_дни(дата, дни), прибавить_месяцы(дата, месяцы), прибавить_года(дата, года): возвращает дату, которая больше дата на указанное количество дней, месяцев или лет.
даты_равны(дата_1, дата_2): функция сравнивает две даты, и если дата_1 равна дата_2, то возвращает ДА, в противном случае возвращает НЕТ.
Работа со списками#
Описание#
Списком является набор однотипных элементов. Значения перечисляются внутри круглых скобок через запятую. Например:
список(2.0, 4.0, 10.5);;список("Лучший", "Самый лучший");.
Заполнение списков#
Задавать значения в списке можно либо копированием значений другого списка, либо добавлением новых значений к уже существующим. Как и присвоение, добавление значений может быть с условием и без, однострочным и блоковым.
Копирование списков#
Копирование значений осуществляется с помощью операции присвоения. Копировать можно как значения вновь создаваемых списков, так и списковых переменных. Примеры копирования списков:
// Пример
список_счетов := список(123, 456);
выход.список_пакетов_клиента := список_пакетов;
список_пакетов := возраст_клиента > 60 => список(“Пенсионный”);
список_пакетов := {
вход.ТБ = 38 => список_пакетов_для_38;
список(“Лучший”, “Премьер”, “Пенсионный”);
}
Однострочное добавление элементов к списку#
К списку можно добавлять:
константы:
к списку список_переменных добавить 10;;к списку список_переменных добавить;список_содержит(список_переменных, "123") => "123";*.
переменные:
к списку список_переменных добавить вход.ставка;.
результат вычисления арифметического выражения или функции:
к списку список_ставок добавить получить_ставку();;к списку список_переменных добавить 1 + 0.9 * (переменная_1 + переменная_2);.
Блоковое добавление элементов к списку#
Если добавление значений зависит от нескольких условий, их можно объединить в блок, который имеет следующий вид:
к списку <списковая_переменная> добавить <первый, все, максимум, минимум> {
<логическое_выражение_1> => <значение_1>;
<логическое_выражение_2> => <значение_2>;
...
<логическое_выражение_N> => <значение_N>;
}
// Пример 7
к списку список_1 добавить все {
1 > 0 => 1;
2 > 100 => 2;
3 > 0 => 3;
}
к списку список_2 добавить первый {
1 > 0 => 1;
2 > 100 => 2;
3 > 0 => 3;
}
к списку список_3 добавить максимум {
1 > 0 => 1;
2 > 100 => 2;
3 > 0 => 3;
}
Все три блока содержат одинаковый набор условий, из которых истинны первое (1 > 0) и третье (3 > 0). В результате список_1 будет содержать все подошедшие значения список_2 – первое подошедшее значение, список_3 – максимальное из подошедших.
список_1 = (1, 3)
список_2 = (1)
список_3 = (3)
Перебор элементов списка#
Перебор элементов списка при присвоении#
Для формирования блока присвоений можно использовать список. В этом случае будет выполнен перебор его элементов и будут проверены соответствующие условия. Алгоритм обработки условий зависит от ключевого слова (первый, все, максимум, минимум) и аналогичен алгоритму блокового присвоения. Для того чтобы иметь возможность использовать элементы списка внутри блока, необходимо задать имя элемента. Таким образом, блок присвоения с перебором элементов имеет следующий вид:
<переменная> := <первый, все, максимум, минимум>
<списковая_переменная> [<имя_элемента>] {
<логическое_выражение> => <значение>;
}
<переменная> := <первый, все, максимум, минимум>
<списковая_переменная> х<имя_элемента>] {
<логическое_выражение> => <значение>;
}
// Пример 8
список_переменных := список(1, 2, 3, 4);
переменная := первый список_переменных[элемент] {
элемент > 2 => элемент;
}
В данном примере последовательно берётся каждый элемент списка, и если он больше двух, присваивается в качестве значения переменной. То есть, для первых двух элементов списка (1 и 2) условие будет ложным, следовательно, присвоение не выполнится. Далее берётся третий элемент (3), и т.к. условие выполняется истинно, в переменную записывается значение элемента. На этом перебор заканчивается, т. к. было использовано ключевое слово "первый". В итоге переменная = 3.
Перебор элементов списка при добавлении#
Аналогично можно использовать перебор списка для добавления значений к другому списку при выполнении заданных условий. В этом случае блок принимает вид:
к списку <списковая_переменная_1> добавить
<первый, все, максимум, минимум>
<списковая_переменная_2> [<имя_элемента>]{
<логическое_выражение> => <значение>;
}
// Пример 9
список_переменных := список(1, 2, 3, 4);
к списку новый_список добавить все список_переменных[элемент] {
элемент > 2 => элемент;
}
В данном примере перебираются все элементы списка список_переменных, и если их значение больше двух, то добавляются к списку новый_список. Т. к. используется ключевое слово "все", перебор продолжается до конца. Таким образом, в список добавятся два элемента – новый_список = (3, 4).
Ключевое слово «индекс»#
Внутри блока присвоения, при котором происходит перебор значений списка, для получения номера элемента в списке можно использовать ключевое слово «индекс». Таким образом, значение индекс может принимать значения от 1 до значения, равного длине списка.
// Пример 10
список_переменных := список(2, 3, 4, 5);
переменная := все список_переменных[элемент] {
индекс = 3 => элемент;
}
В данном примере перебираются все элементы списка список_переменных, и если порядковый номер элемента в списке (то есть индекс) равен 3, то значение этого элемента записывается в переменную. Таким образом переменной будет присвоено значение третьего элемента списка – переменная = 4.
Предопределённые функции#
Для работы со списками существуют предопределённые функции:
длина_списка(список): возвращает количество элементов в списке.
максимальный_элемент(список), минимальный_элемент(список): возвращает максимальный / минимальный элемент в списке.
список_содержит(список, значение) – проверяет, содержится ли значение в списке. Если содержится, возвращает ДА, в противном случае – НЕТ.
сортировать_список(список, направление), сортировать_список_строк(список, направление), сортировать_список_дат(список, направление): возвращает список чисел/строк/дат, отсортированный по убыванию или по возрастанию.
объединить_списки(список_1, список_2) возвращает список, в котором содержатся все элементы список_1 и список_2.
получить_элемент_по_индексу(список, индекс) возвращает элемент списка с индексом, переданным в качестве аргумента. Если такой элемент не найден, возвращается пустой результат.
// Пример 11
список_переменных := список(1, 2, 6, 3, 4);
длина_списка := длина_списка(список_переменных);
макс := максимальный_элемент(список_переменных);
мин := минимальный_элемент(список_переменных);
переменная_1 := список_содержит(список_переменных, 1);
переменная_5 := список_содержит(список_переменных, 5);
сортированный_список := сортировать_список(список_переменных, “по-убыванию”);
объединенный_список := объединить_списки(список_переменных, список_переменных);
третий_элемент := получить_элемент_по_индексу(список_переменных, 3);
Результат вычислений:
длина_списка = 5
макс = 6
мин = 1
переменная_1 = ДА
переменная_5 = НЕТ
сортированный_список = (6, 4, 3, 2, 1)
объединенный_список = (1, 2, 6, 3, 4, 1, 2, 6, 3, 4)
третий _элемент = 6
Работа с наборами полей#
Описание#
Может потребоваться работать не с одиночными переменными, а с наборами полей. Количество и имена полей внутри набора жёстко фиксируется, при этом типы полей не зависят друг от друга. Перед использованием необходимо описать набор:
<имя_набора> это [<имя_1> это <тип_1>,
<имя_2> это <тип_2>,
... ,
<имя_N> это <тип_N>];
Примеры объявление аргументов для разных типов данных:
Простой:
параметр это [код это строка, значение это дробное_число];Набор полей.
клиент это [имя это строка, документ это [тип это строка, номер это целое_число]];Встроенный набор полей.
предложение это [название это строка, пакет_услуг это продукт];Список.
предложение это [название это строка, номера_счетов это список(целое_число) ), продукт это список([название это строка, номер это целое_число]) ];
Присвоение значений#
Присвоение значения набору может происходить несколькими способами:
Присвоение значения всему набору:
<переменная> := х<имя_1>: <значение_1>,
<имя_2>: <значение_2>,
… ,
<имя_N>:< значение_N>];
При этом порядок следования полей не важен. Если присвоение какому-нибудь полю отсутствует, считается, что его значение не задано. Все значения полей, которые содержались в наборе до этого, стираются.
Присвоение значения конкретному полю:
<имя_набора>.<имя_поля>:= <значение>;
Обратиться к значению поля можно по его имени:
<**имя_набора>.<имя_поля>**
// Пример 12
параметр это [код это строка, значение это дробное_число];
параметр := [код: “комиссия”, значение: 11.6];
параметр.значение := параметр.значение > 10 => 10;
Списки наборов полей#
Чаще всего требуется работать со списком наборов. В этом случае объявление переменной будет выглядеть так:
<имя_списка> это список([<имя_1> это <тип_1>,
<имя_2> это <тип_2>,
... ,
<имя_N> это <тип_N>]);
// Пример
список_фигур это список([название это строка,
число_углов это целое_число]);
список_ фигур := список(
[название: “Круг”, число_углов: 0],
[название: “Треугольник”, число_углов: 3],
[название: “Квадрат”, число_углов: 4],
[название: “Ромб”, число_углов: 4]
);
к списку список_фигур добавить
[название: “Трапеция”, число_углов: 4];
к списку список_четырёхугольников добавить
все список_фигур[фигура] {
фигура.число_углов = 4 => фигура.название;
}
В данном примере создаётся список наборов. В первой строчке происходит описание полей, во второй списку присваивается список из 4 элементов, а в третьей – добавляется ещё один элемент. В следующем блоке перебираются все элементы из списка, и названия фигур с 4 углами добавляются к списку список_четырёхугольников. В результате, список_четырёхугольников = ("Квадрат", "Ромб", "Трапеция").
Предопределённые функции для работы со списками наборов полей#
сортировать_по_полю(список, поле, направление): возвращает список наборов полей, отсортированный по убыванию или по возрастанию значений в поле поле.
сортировать_список_структур(список): Функция возвращает новый список, который является отсортированной копией переданного в качестве аргумента списка. Работает только для списков предопределённых наборов полей (11.2), описанных в системе, а не созданных пользователем. (пример: выходная структура договоров функции получить_договоры_на_продукт_и_сервис)
максимальный_элемент(список, поле), минимальный_элемент(список, поле): возвращает элемент с максимальным / минимальным значением поля поле.
Предопределённые функции и наборы полей#
Предопределённые функции#
В тексте правил можно вызывать предопределённые функции:
Вспомогательные функции: для работы с датами, списками, и наборами полей.
Функции, использующие внешние источники данных.
Предопределённые наборы полей#
Предопределённые функции могут возвращать значения или списки значений предопределённого типа. Список предопределенных типов можно найти в редакторе создания/редактирования функций раскрыв список доступных типов данных для входных параметров и возвращаемого значения. Они представляют набор полей, которому сопоставлено определённое имя. Например, предопределённый тип вклад – набор следующих полей:
номер_счета: строка;
вид: целое число;
подвид: целое число;
валюта: строка;
дата_открытия: дата;
остаток: дробное число.
Тип данных вклад имеет возвращаемое значение функции получить_вклад_по_номеру_счета(ид_клиента, регион, номер_счета). Такой же тип будет и у переменной, которой присваивается результат выполнения функции.
// Пример 14
список_вкладов это список([счет это целое_число, вклад это вклад]);
список_счетов := список(123, 456);
к списку список_вкладов добавить все список_счетов[счет] {
получить_вклад_по_номеру_счета(вход.клиент_ид, вход.ТБ, счет);
}
Если необходимо значение функции записать в поле набор, достаточно указать название предопределённого типа – в данном примере вклад.
Аналогично объявляется тип аргумента пользовательской функции.
Формирование комментариев#
Для пояснения хода расчёта есть возможность формировать комментарий. Комментарий оформляется с помощью конструкции:
( <текст комментария> )
Комментарий может вставляться после операции присвоения либо после результата вычисления внутри блока присвоения.
// Пример 15
переменная := 1; (* переменной присвоено значение 1*)
переменная := первый {
переменная > 0 => 1; (* вам $возраст лет, поэтому мы уменьшили комиссию до $комиссия 1*)
0; (* переменной присвоено значение 0 *)
}
При необходимости вставить значение переменной внутрь комментария, перед именем переменной ставится знак доллара – «$»:
( … $<Имя_переменной_1> … $<Имя_переменной_N> … )
Например:
Переменная := 1; ( переменной присвоено значение $Переменная )
В результате сформируется комментарий: переменной присвоено значение 1.
Результат правила#
Каждое правило должно заканчиваться списком выходных переменных, для которых были вычислены значения. В случае возврата одного значения, конструкция имеет вид:
результат выход.<параметр>;
Если необходимо указать несколько выходных параметров, то они объединяются в блок:
результат [выход.<параметр_1>,
выход. < параметр _2>,
... ,
выход. < параметр _N>];
Генерация ошибок#
Если во время выполнения правила может возникнуть ситуация, когда невозможно вернуть корректное значение или продолжить вычисления, необходимо генерировать ошибку. Для генерации ошибки необходимо проверить условие и указать сообщение о причине ошибки.
В общем виде конструкция выглядит так:
ошибка: <условие> => <сообщение_об_ошибке>;
Например:
ошибка: длина_списка(список_сервисов) = 0 =>
"Не удалось получить список сервисов";
Блоковая генерация ошибок#
Если в зависимости от условий необходимо формировать несколько разных сообщений, их можно сгруппировать в блок:
ошибка: {
<условие_1> => <сообщение_об_ошибке_1>;
<условие_2> => <сообщение_об_ошибке_2>;
...
<условие_N> => <сообщение_об_ошибке_N>;
}
// Пример 16
ошибка: {
вход.сумма_по_дб задан и вход.сумма_по_кр задан =>
“Одновременно заданы суммы по дебету и кредиту”;
вход.сумма_по_дб не задан и вход.сумма_по_кр не задан =>
“Не задана ни сумма по дебету ни сумма по кредиту”;
}
Генерация ошибок внутри блока#
Сгенерировать ошибку можно внутри любого блока присвоения. Для этого достаточно добавить одну или несколько строчек вида:
ошибка: <условие> => <сообщение_об_ошибке>;
// Пример 17
переменная := первый список_условий[условие] {
ошибка: условие.число_дней не задано => “Не задано число дней”;
ошибка: условие.число_дней = 0 => “Число дней равно нулю”;
условие.сумма / условие.число_дней;
}
Пользовательские функции#
Описание#
Для повторного использования одного и того же кода его можно оформлять в виде пользовательских функций и затем вызывать из текста правила. У каждой функции должно быть задано имя и список аргументов. Функция состоит из набора присвоений переменных и результата. Функции бывают двух видов: созданные в виде отдельных правил через интерфейс ДП (глобальные) и описанные внутри правила (встроенные).
В общем виде объявление функции выглядит следующим образом:
/*
<описание_функции>
*/
<имя_функции> это <тип_функции> (<аргумент_1> это <тип_аргумента_1>,
<аргумент_2> это <тип_аргумента_2>,
... ,
<аргумент_N> это <тип_аргумента_3>) {
<присвоение_1>;
<присвоение_2>;
…
<присвоение_N>;
результат <переменная, константа, арифметическое выражение, вызов функции>;
}
Примеры объявление аргументов для разных типов данных:
Простые:
код это целое_число
Наборы полей.
условие это [тип_условия это строка, параметр это дробное_число]
Встроенные наборы полей.
*проверяемый_сервис это сервис
Списки (8). Тип элементов списка в свою очередь также может быть простым, набором полей или встроенным набором полей.
номера_счетов это список(целое_число)
Глобальные функции#
Глобальная функция может быть вызвана из любого правила, а также из других глобальных функций. Такие функции описываются в отдельных правилах.
// Пример 18
/* Проверяет наличие договора у клиента
по переданному сервису (опции) */
проверить_наличие_договора это логическое_выражение (
сервис это сервис,
идентификатор_клиента это строка) {
список_договоров :=
получить_договора_на_продукт_и_сервис(
сервис,
идентификатор_клиента
);
результат длина_списка(список_договоров) > 0;
}
Встроенные функции#
В коде правила можно объявлять собственные вспомогательные функции и использовать их внутри правила (в том числе и внутри других встроенных функций). При этом встроенные функции не доступны внутри других правил. В этом случае описание функции, типы функции и аргументов можно не указывать.
// Пример 19
/* Функция вычисления площади квадрата */
площадь_квадрата это (сторона_квадрата) {
результат сторона_квадрата * сторона_квадрата;
}
площадь := площадь_квадрата(4); // Вызов функции в тексте правила
В данном примере вызывается встроенная функция площадь_квадрата, текст которой находится в том же правиле. В качестве аргумента передаётся число 4. После выполнения функции переменная площадь примет значение 4 * 4:
площадь = 16
Имя встроенной функции должно быть уникальным, то есть в правиле не должно быть двух функций с одним и тем же именем. Также имя встроенной функции не должно совпадать с именами глобальных функций за исключением тех случаев, когда требуется переопределить глобальную функцию.
Переопределение глобальных функций#
Иногда требуется изменить поведение глобальной функции для отдельно взятого правила. Для этого в тексте правила необходимо объявить соответствующую функцию с сохранением её имени, типа, количества, порядка, имён и типов всех аргументов. Теперь при выполнении этого правила всегда будет вызывать переопределённая функция, в то время как другие правила останутся без изменений.
Например, в правиле вызывается глобальная функция проверить_условия, которая в свою очередь вызывает другую глобальную функцию выполняется_условие. Предположим, возникла необходимость для данного конкретного правила изменить логику проверки условия. Но поскольку функция выполняется_условие явно из правила не вызывается, заменить вызов функции на другую возможности нет. Вместо этого можно определить встроенную функцию, которая переопределит глобальную. В этом случае код будет выглядеть следующим образом:
// Пример 20
/* Глобальная функция для проверки условий сервиса */
проверить_условия это логическое_выражение(сервис это сервис) {
пройдено := ДА;
пройдено := первый сервис.условия[условие] {
не(выполняется_условие(условие)) => НЕТ;
}
результат пройдено;
}
/* Глобальная функция для проверки условия сервиса */
выполняется_условие это логическое_выражение(условие это условие) {
// Код для проверки условия
. . .
}
// Текст правила
/* Переопределённая функция для проверки условия сервиса */
выполняется_условие это логическое_выражение(условие это условие) {
// Новый код для проверки условия
. . .
}
. . .
к списку проверенный_список_сервисов
добавить все список_сервисов[сервис] {
проверить_условия(сервис) => сервис;
// Вызов функции в тексте правила
}