IntraVision

СПЕЦИФИКАЦИЯ. Клиентские скрипты (правила автоматизации). BETA версия. Планируем развивать!

В релизе r_3.7.0 появилась возможность настраивать кастомные правила автоматизации для карточки заявки в виде скриптов. 
Такие скрипты позволяют реализовывать разные сценарии:
  • Показать/скрыть какое-то поле в зависимости от значения другого поля
  • Заполнить значение одного поля в зависимости от значения другого поля
  • Заполнить значение доп. поля заявки значением поля пользователя, клиента или сотрудника
  • Показать плашку об ошибке, если при сохранении заявки не соблюдено какое-то условие
  • Настроить заполнение текста в комментарии или переключить вид комментария (публичный или внутренний)
  • И многие другие..

Порядок настройки скрипта
Скрипты настраиваются в разделе "Настройки -> Заявки -> Скрипты заявок". На карточке создания скрипта нужно:
  • Заполнить название
  • Указать тип заявки, для которого должен применяться этот скрипт
  • Нажать на кнопку "Открыть редактор" в поле "DSL"
  • Написать там (или вставить туда) код скрипта
  • Сохранить
  • !Переавторизоваться (для того, чтобы скрипт заработал)

Структура скрипта
В общем виде скрипт выглядит так:
script v1.0 {
rule {
name: "Example Rule 1" //Название скрипта
on { //Блок с событиями применения
taskEvent: save //Событие применения
}
action { //Блок с действиями
if (bool.true(task.statusid.value)) { //Условие
setCommentMode: public //Само действие
}
}
}
}

Ниже описаны спецификации и основные функции, доступные на данный момент при работе со скриптами. С примерами готовых скриптов можно ознакомиться в Статье №66549. 


Основные блоки, функции и синтаксис скриптов:


1. События применения скрипта (блок "On")
//проверка будет по ИЛИ
on {
      taskEvent: open-create-form    //открытие формы создания заявки
      taskEvent: open-edit-form      //открытие формы созданной заявки
      taskEvent: save                //сохранение заявки
      changeField: client            //изменение поля "Клиент" 
      changeField: initiator         //изменение поля "Заявитель" 
      changeField: executor          //изменение поля "Исполнитель"
      changeField: priority          //изменение поля "Приоритет"}
}

//также в changeField можно указать alias доп. поля заявки
//добавлен контекст event
//вместо обобщенных условий в блоке "on" можно создавать динамичные условия для проверок событий

//шаблон
event.is(...)

//примеры
//проверяем что сейчас событие "изменение приоритета"
if(event.is(changeField:priority)) { 
 ...
}

//проверяем что сейчас событие "сохранение заявки"
if(event.is(taskEvent:save)) {
 ...
}


2. Условия (блок "If")
//операции для строк: "==", "!="
if(string.bool(task.addfield_vyp_spisokSingleSelect.value == '1')) {
task.addfield_dop_textText.setValue('value 1')
}

//операции для чисел : "==", "!=", ">", ">=", "<", "<="
if(number.bool(task.serviceid.value == 1055)) {
task.addfield_dop_textText.setValue('service is 1055')
}
//доступна группировка по and и or
//как массив из bool условий

if(
bool.or
[
number.bool(task.statusid.value == 0)
bool.and
[
number.bool(task.statusid.value == 313)
string.bool(task.addfield_strokovoeString.value == '')
]
]
) {
user.load(task.initiatoruserid.value as initiatorUserData)
task.addfield_strokovoeString.setValue(user#initiatorUserData.defaultphone)
setAccess(edit){
addfield_strokovoeString
}
//пример if - elseif - else
if(string.empty(task.name.value)) {  
  notify('name empty')
}
elseif(string.empty(task.description.value)) {  
  notify('desc empty')
}
else {  
  notify.success('ok')
}
//для проверки отрицания можно использовать символ "!"
if(!string.empty(task.name.value)) { 
 notify.success('ok')
}


3. Получение значений полей заявки
task.name.value                 //название заявки
task.description.value          //описание заявки
task.serviceid.value            //id сервиса
task.tasktypeid.value           //id типа заявки
task.statusid.value             //id статуса
task.priorityid.value           //id приоритета
task.clientid.value             //id клиента
task.initiatoruserid.value      //id пользователя-заявителя
task.initiatorgroupid.value     //id клиента-заявителя
task.executoruserid.value       //id сотрудника-исполнителя
task.executorgroupid.value      //id группы-исполнителя
task.observeruserids.value      //массив из id пользователей-наблюдателей
task.observergroupids.value     //массив из id групп-наблюдателей
task.resolutiondateplan.value   //срок выполнения план
task.resolutiondatefact.value   //срок выполнения факт
task.reactiondateplan.value     //срок реакции план
task.reactiondatefact.value     //срок реакции факт
task.assets.value               //массив из id активов
task.tags.value                 //массив из id тегов
task.comment.value              //текст нового комментария
// доп поля заявки, поддерживаемые типы: 
//Число, Число (дроб.), Строка, Текс, Дата, Дата и время, Да-нет, Вып. список, Html
//пример:
task.addfield_pole1Number.value


4. Получение значений данных пользователей
//загрузить пользователя в переменную 'initiatorUser'
//загруженный пользователь кешируется на 10 минут
user.load(task.initiatoruserid.value as initiatorUser)

//пример использования загруженного пользователя в переменную 'initiatorUser'
task.addfield_pole_textText.setValue(user#initiatorUser.fullname)
//Доступные функции для пользователя:

//полное ФИО
user#initiatorUser.fullname

//дефолтный телефон
user#initiatorUser.defaultphone

//все телефоны через запятую
user#initiatorUser.phones.toString()

//телефон по индексу в массиве, начиная с 0
user#initiatorUser.phones[2]

//основная почта
user#initiatorUser.email

//дополнительные почты через запятую
user#initiatorUser.additionalemails.toString()

//дополнительная почта по индексу в массиве, начиная с 0
user#initiatorUser.additionalemails[1]

//теги через запятую
user#initiatorUser.tags.toString()

Новые функции по контексту пользователей
//текущий пользователь 'selfuser'
//доступны функции как при работе с загруженным пользователем через 'user.load(...)'
//пример
//получить id
selfuser.id
//получить фио
selfuser.fullname

//--------------------------
//проверка что пользователь состоит в нужной группе
user#testUser.hasGroup(12345)

//проверка что текущий пользователь состоит в нужной группе
selfuser.hasGroup(12345)

//--------------------------
//проверка что у пользователя есть роль на заявке
//доступные значения: initiator, executor, observer
user#testUser.isTaskRole(executor)

//проверка что у текущего пользователя есть роль на заявке
selfuser.isTaskRole(executor)



5. Получение значений данных групп пользователей
//загрузить группу в переменную 'initiatorGroup'
//кешируется на 10 минут
usergroup.load(task.initiatorgroupid.value as initiatorGroup)

//пример использования
task.addfield_pole_textText.setValue(usergroup#initiatorGroup.name)
//Доступные функции для группы:

//название группы
usergroup#initiatorGroup.name

//дефолтный телефон
usergroup#initiatorGroup.defaultphone

//все телефоны через запятую
usergroup#initiatorGroup.phones.toString()

//телефон по индексу в массиве, начиная с 0
usergroup#initiatorGroup.phones[2]

//основная почта
usergroup#initiatorGroup.email

//дополнительные почты через запятую
usergroup#initiatorGroup.additionalemails.toString()

//дополнительная почта по индексу в массиве, начиная с 0
usergroup#initiatorGroup.additionalemails[1]

//теги через запятую
usergroup#initiatorGroup.tags.toString()

//id менеджера
usergroup#initiatorGroup.manager.id

//name менеджера
usergroup#initiatorGroup.manager.name

//email менеджера
usergroup#initiatorGroup.manager.email

Новые функции по работе с группой пользователя
//проверка что в группе есть пользователь
userGroup#testGroup.hasUser(12345)

//проверка что у группы есть роль на заявке
//доступные значения: client, initiator, executor, observer
userGroup#testGroup.isTaskRole(initiator)


6. Работа с датами
//добавлена функция для получение текущей даты
date.now

//unit - разрядность, доступные значения:
// year | month | day | hour | minute | second | millisecond

//функция diff для вычисления разницы между двумя датами
//при вызове происходит вычитание date2 из date1
//если date1 меньше чем date2, то результатом будет отрицательное число
//шаблон: date.diff(date1, date2, unit)

//пример
//выдавать ошибку если в дату выполнения заявки установили значение меньше чем 5 дней от текущей даты
if(number.bool(date.diff(task.resolutiondateplan.value, date.now, day) < 5)) {
throw 'Дата выполнения должна быть больше 5 дней от текущей даты'
}

//изменение даты
//доступны операции "+", "-"
//пример, к текущей дате прибавить 5 дней
date.modify(date.now + 5, day)

//сравнение 2х дат
//доступны операции ">", ">=", "<", "<=", "==", "!="
//пример
//выдавать ошибку если в дату выполнения заявки установили значение меньше чем текущая дата
//сравнение идет по day разрядности
if(date.bool(task.resolutiondateplan.value < date.now, day) {
throw 'Дата выполнения меньше текущей даты'
}


7. Установка значений полей
//обнуление значения поля
task.initiatoruserid.setValue(#NULL)

//пример использования загруженного пользователя в переменную 'initiatorUser'
task.addfield_olga_textText.setValue(user#initiatorUser.fullname)

//задать текст
task.addfield_olga_textText.setValue('тест строка')

//установить значение из другого поля заявки
task.addfield_olga_textText.setValue(task.addfield_testpoleText.value)

//получить значение из поля "Заявитель"
task.initiatoruserid.valuetask.initiatorgroupid.value

//установить значение в поле "Заявитель"
task.initiatoruserid.setValue(...)
task.initiatorgroupid.setValue(...)

//получить значение доп. полей с типами "Date" и "DateTime"
task.addfield_test1Date.value
task.addfield_test1DateTime.value

//установить значение доп. полей с типами "Date" и "DateTime"
task.addfield_test1Date.setValue('2026-01-01')
task.addfield_test1DateTime.setValue('2026-01-01T10:00:00')

//получить значение "Срок выполнения (план/факт)"
task.resolutiondateplan.value
task.resolutiondatefact.value

//установить значение "Срок выполнения (план/факт)"
task.resolutiondateplan.setValue(...)
task.resolutiondatefact.setValue(...)

//получить значение "Срок реакции (план/факт)"
task.reactiondateplan.value
task.reactiondatefact.value

//установить значение "Срок реакции (план/факт)"
task.reactiondateplan.setValue(...)
task.reactiondatefact.setValue(...)

Проверка на пустое значение
//строка
string.empty(task.name.value)

//число
number.empty(task.addfield_testNumber.value)

//дата
date.empty(task.resolutiondateplan.value)

//булевое
bool.empty(task.addfield_testBoolean.value)

Работа со списками
//проверка на пустой списокarray.empty(...)//получить размер спискаarray.length(...)


8. Настройка видимости полей (setVisibility)
setVisibility(hide) {    //скрыть поле
priority
}

setVisibility(show) { //показать поле
addfield_strokovoeString
}

setVisibility(default) { //отобразить в зависимости от настроек прав доступа
addfield_strokovoeString
}
*Перед применением видимости сначала проверяются права доступа. Это значит, что если поле недоступно по правам доступа, то оно не отобразится при использовании метода setVisibility(show). 


9. Работа с полем комментария
//получить html текст комментария
task.comment.value

//установить html текст комментария
task.comment.setValue(...)

//преобразовать html text в plain text
html.toPlainText(...)

//пример скрипта
//в доп поле с типом "текст" установить plain text из комментария
task.addfield_testText.setValue(html.toPlainText(task.comment.value))

//по умолчанию включить добавление публичных комментариев
setCommentMode: public

//по умолчанию включить добавление внутренних комментариев
//(применяется только для пользователей-сотрудников)
setCommentMode: private

10. Работа с доп. полями с типами "SingleSelect" и "MultiSelect"
//добавлена возможность менять значения выпадающих списков на форме заявки для доп полей с типом "SingleSelect" и "MultiSelect"

//возможно установить 2 значнения:
// [...], строковый массив значений
// default, для загрузки полного списка

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

script {
rule {
name: 'test rule'
action {

//секция по работе с внешним видом формы заявки
ui {
//alias доп поля
addfield_testSingleSelect {
//загрузить стандартный список
list = default
}

//alias доп поля
addfield_testMultiSelect {
//показать только заданные значения
list = ['1', '2']
}
}
}
}
}


11. Работа с активами 
//загрузить данные по активу
asset.load(...)

//пример загрузить актив по id
asset.load(123 as testAsset)

//пример, загрузить данные по последнему активу в списке на заявке
asset.load(task.assets.value as taskAsset)

//-----------------

//получение данных по загруженному активу
//доступные поля: id, name, description, доп поля через префикс assetfield_

//ранее мы загрузили актив в поле taskAsset
//теперь можем к нему обратиться для доступа к данным
asset#taskAsset.name

//-----------------
//работа в внешним видом активов
//переключение режима выбора
//будет полезно если потребуется чтобы пользователь мог устанавливать только 1 актив

//доступные значения: single, multiple
ui {
assets {
mode = single
}
}


12. Вывод сообщений 
//показать сообщение со стандартными настройками: цвет - синий, исчезает через 3 сек.
notify('test message')

//изменение цвета сообщения
//синий
notify.info('test message')
//красный
notify.error('test message')
//зеленый
notify.success('test message')
//желтый
notify.warning('test message')

//показать сообщение которое исчезает через 10 сек
notify.warning('test message', 10000)

13. Создание кастомных функций с возвращаемым значением 
//пример с построчным комментарием возможностей

script {

helpers {
//создана функция test1
function test1(nFactor, mFactor){

//в v1 и v2 запомнили значения доп полей
var v1 = task.addfield_dopPoleNumber.value
var v2 = task.addfield_factorNumber.value

//в v3 вычислили произведение v1 на v2
var v3 = number.math(vars#v1 * vars#v2)

//в v4 вычислили деление v3 на динамичный аргумент nFactor
var v4 = number.math(vars#v3 / args#nFactor)

//результатом функции будет умножение v4 на mFactor
return number.math(vars#v4 * args#mFactor)
}

//можно создать функцию без аргументов
function getServiceId() {
return task.serviceid.value
}
}

rule {
name: 'rule test'
action {
//вызов функции с аргументами
task.comment.setValue(func#test1(10, 15))

//вызов функции без аргументов
task.comment.setValue(func#getServiceId())
}
}


В релизе 3.8.0, со скриптами, работают следующие доп.поля

  • Число (целое)
  • Число (дробное)
  • Строка
  • Текст
  • Выпадающий список
  • Дата (без времени)
  • Дата/время
  • Да/Нет
  • Вып. список
  • Мн. выбор
СкриптыНаЗаявке