Справка

Архитектура

Облачный Pyrus
Безоблачный Pyrus

Скрипт представляет собой исполняемый JavaScript-код, который подписывается на события изменения полей формы и задает логику вычисления зависимых полей. Рассмотрим пример:

Есть форма с полями «Цена единицы товара», «Количество» и «Общая сумма». Поле «Общая сумма» можно заполнять автоматически (как произведение цены на количество) с помощью следующего кода:

form
  .onChange(['Цена единицы товара', 'Количество'])
  .setValue('Общая сумма', state => {
    const [price, quantity] = state.changes;

    if (!price || !quantity)
      return null;

    return price.value * quantity.value;
  });

Разберем подробнее этот код.

В контексте исполнения скрипта доступен глобальный объект form типа FormProxy, обеспечивающий взаимодействие кода скрипта с формой в Pyrus:

interface FormProxy {
  onChange(fieldNames: string[]): ChangeHandler;

  fetchSelfRegister(
    filterFn: (filter: RegisterFilter) => RegisterFilter,
    fieldNames: string[]
  ): Promise<RegisterResponse>;

  getDateWithTimezoneOffset(date: string): Date;
  
  getDaysCount(
    startDate: Date | string,
    endDate: Date | string,
    options?: {
      exclude: "nonWorkingHoliday" | "nonWorking",
      calendar: "ru" | "kz" | "us"
    }
  ): number;
}

Подсказка: функция getDateWithTimezoneOffset преобразует переданное значение поля типа Дата в значение, в котором учтено смещение по часовому поясу.

Метод onChange принимает первым аргументом массив названий полей формы (Цена единицы товара и Количество), при изменении которых нужно вычислить значения зависимых полей, и возвращает объект типа ChangeHandler.

Метод onChange вызывается при изменении любого из полей, упомянутых в первом параметре. Результатом работы скрипта является заполнение зависимых полей или валидация. Но иногда этот процесс нарушается. Например, если значения исходных полей заполняются методами API, с помощью бота или клиентского приложения, которое не поддерживает скрипты, то в нужный момент скрипт не сработает и зависимые поля не заполнятся.

В этом случае при настройке onChange следует указать второй параметр true. Благодаря ему скрипт будет запускаться не только при изменении указанных полей, но и каждый раз при входе в задачу (если параметр не указан как true, то по умолчанию он считается false). Настройка работает так: при первом входе пользователя в задачу после заполнения исходных полей через веб-браузер или другой клиент Pyrus с поддержкой скриптов, скрипт выполняется, то есть зависимые поля заполняются и/или валидация производится.

Подробнее про метод fetchSelfRegister см. Реестр формы.

Метод getDaysCount используется для получения количества дней между датами согласно рабочему календарю. По умолчанию используются настройки организации или пользователя, но при желании можно указать опции через необязательный аргумент options.

Например, чтобы вычислить нерабочие праздничные дни для поля Даты отпуска (поле типа Срок вида Дата и период) и заполнить числовое поле Количество дней используется следующий скрипт:

form.onChange(['Даты отпуска']).setValue('Количество дней', state => {
  const [due] = state.changes;
  return form.getDaysCount(due.start_date, due.end_date, { 
    exclude: 'nonWorkingHoliday', 
    calendar: 'ru' 
  });
});

ChangeHandler позволяет задать логику вычисления зависимых полей (Общая сумма), которая будет выполняться каждый раз при изменении любого из полей, перечисленных в методе onChange.

interface ChangeHandler {
  setValue(
    fieldName: string,
    calcFunction: (state: FormState) => CompositeValue
  ): void;

  setValues(
    fieldNames: string[],
    calcFunction: (state: FormState) => CompositeValue[]
  ): void;

  setValueAsync(
    fieldName: string,
    calcFunction: (state: FormState) => Promise<CompositeValue>
  ): void;

  setValuesAsync(
    fieldNames: string[],
    calcFunction: (state: FormState) => Promise<CompositeValue[]>
  ): void;

  validateAsync(
    fieldName: string,
    validateFunction: (state: FormState) => Promise<{errorMessage: string} | null>
  ): void;
  
  setAssignee(
    calcSync: (state: FormState) => Nullable<number>
  ): void;
  
  setAssigneeAsync(
    calcAsync: (state: FormState) => Promise<Nullable<number>>
  ): void;
}

Аргументы метода setValue:

  • fieldName — название поля, значение которого нужно вычислить
  • calcFunction — функция вычисления значения поля.

Функция calcFunction получает на вход единственным аргументом объект типа FormState и возвращает новое значение (см. Формат значений полей) вычисленного поля, объявленного в методе setValue.

Для случаев, когда нужно вычислить сразу несколько полей на основе одних и тех же данных, удобно воспользоваться методом setValues — он принимает массив имен полей, а calcFunction в этом случае должна вернуть соответствующий массив значений этих полей.

Если для вычислений требуется произвести асинхронные операции (например, дождаться завершения запроса реестра или загрузки справочника), воспользуйтесь асинхронными версиями методов: setValueAsync и setValuesAsync. Их отличие в том, что в calcFunction возвращается Promise («обещание»), который вернет значения полей. Пример использования приведен в разделе Реестр формы.

Обратите внимание: применение метода setValue делает невозможным ручное заполнение автоматически вычисляемых полей.

Методы validate и validateAsync позволяют реализовать гибкую валидацию заполнения формы и отображение ошибок. Подробнее см. Валидация.

Методы setAssignee и setAssigneeAsync позволяют устанавливать ответственного в зависимости от значений полей формы, см. пример.

Объект FormState позволяет получить значения зависимых полей (Цена единицы товара и Количество), на основе которых вычисляется значение поля «Общая сумма»:

interface FormState {
  changes: FieldValue[];
  prev: FieldValue[];
}

Поле changes содержит массив текущих значений полей, перечисленных в методе onChange. Поле prev содержит массив «предыдущих» значений вычисляемых полей.

Была ли эта статья полезной?