Примеры скриптов
Ниже представлены примеры готовых скриптов по категориям: заполнение полей, валидация и фильтрация значений. Скрипты могут быть использованы в различных формах, если скорректировать названия полей. Примеры можно комбинировать и расширять, усложняя логику под конкретные бизнес-задачи.
Заполнение полей
Скопировать значение одного поля в другое
Копируем значение из поля Поле-источник в поле Поле-приемник (типы полей должны совпадать).
form.onChange(['Поле-источник'], true) .setValue('Поле-приемник', state => { const [value] = state.changes; return value; });
Вычислить сумму (разницу, процент) нескольких полей
В этом примере скрипт прибавляет премию сотрудника к его окладу и рассчитывает НДФЛ от полученной суммы. Затем вычитает НДФЛ из этой суммы и выводит итоговую выплату за месяц.
form.onChange(['Оклад', 'Премия']) .setValues(['НДФЛ (13%)', 'Итого к выплате за месяц'], state => { const [salary, bonus] = state.changes; if (!salary || !bonus) return null; const ndflTax = (salary.value + bonus.value) * 0.13; const result = (salary.value + bonus.value) - ndflTax; return [ndflTax, result]; });
Вывести значение колонки справочника
Здесь Справочник — название поля с вашим справочником, Колонка — название колонки справочника, а Текст — поле типа Текст, в котором будет сохранено значение.
form.onChange(['Справочник']) .setValue('Текст', state => { const [item] = state.changes; return item?.columns['Колонка']; });
Перенос крайнего срока в зависимости от приоритета
C возможностью установки произвольного срока.
form.onChange(['Высокий приоритет', 'Перенос даты']) .setValue('Срок', state => { const [checkmark, customDue] = state.changes; if (customDue?.date) return {date: customDue.date}; if (checkmark?.checked) return {days_from_create: 1}; return {days_from_create: 3}; });
Установка срока за N дней до указанной даты
В этом примере в зависимости от указанной при заполнении даты срок будет автоматически устанавливаться за семь дней до этой даты.
form.onChange(['Дата']) .setValues(['Срок'], state => { const [dateValue] = state.changes; if (!dateValue) return null; const dueDate = new Date(dateValue.date + 'T10:00:00Z'); const daysBeforeDate = 7; dueDate.setDate(dueDate.getDate() - daysBeforeDate); return [{date: dueDate.toDateString()}]; });
Назначение ответственного в задаче
Скрипт устанавливает ответственного в задаче в зависимости от значения числового поля.
form.onChange(['Сумма контракта']) .setAssignee(state => { const [summaKontrakta] = state.changes; if (summaKontrakta.value > 50000) // ID пользователя, отвечающего за крупные контракты return 321; // ID пользователя, отвечающего за обычные контракты return 123; });
Подсчёт рабочих дней между датами
Скрипт считает количество рабочих дней между указанными датами (поля start_date
и end_date
) с использованием производственного календаря РФ записывает результат в числовое поле days
.
form.onChange(['start_date', 'end_date']).setValue('days', state => { const [start_date, end_date] = state.changes; return form.getDaysCount(start_date.date, end_date.date, { exclude: 'nonWorking', calendar: 'ru' }); });
Подсчёт суммы в строках таблицы и скидки
Скрипт считает сумму значений в заполненной таблице и применяет указанную скидку.
form.onChange(["product", "quantity", "discount"]) .setValues(["price_for_one", "total_price"], state => { const [product, quantity, discount] = state.changes; if (!product?.columns) return [null, null]; const discount_rate = discount?.value ? discount.value / 100 : 0; const item_price = product.columns["Цена"] ? Number(product.columns["Цена"]) * (1 - discount_rate) : 0; return quantity?.value ? [item_price, item_price * quantity.value] : [item_price, 0]; });
Выбор значения из справочника по полю с типом Контакт
Иногда требуется подставлять в заявку ФИО сотрудника в родительном падеже. Простой пример — заявление на отпуск. Чтобы Pyrus делал это автоматически, создаём справочник со списком сотрудников и колонкой с их ФИО в родительном падеже. И подключаем к форме такой скрипт:
const catalogPromise = form.getCatalog(ID_справочника); form.onChange(['Отпускник']) .setValueAsync('От (ФИО):', async state => { const [contactField] = state.changes; const catalogItems = await catalogPromise; if (!catalogItems || !contactField || !contactField.person_id) return null; const filteredRow = catalogItems .find(item => item.columns['Сотрудник'] == `${contactField.first_name} ${contactField.last_name}`); return filteredRow ? filteredRow.columns['ФИО Род'] : null; });
В этом примере:
- Отпускник — название поля типа Контакт;
- Сотрудник и ФИО Род — название колонок справочника, в котором мы ищем значение по выбранному полю;
- От (ФИО): — поле типа Текст, в котором сохраняем найденное значение из справочника.
Автоматическое заполнение срока SLA
Укажите в скрипте своё время решения и названия полей. Вместо числовых констант вы можете использовать переменные или формулы для расчёта времени решения. При изменении в заявке полей Приоритет и Клиент скрипт будет выполняться и устанавливать один из указанных в нём сроков.
form.onChange(['Приоритет', 'Клиент']) .setValue('Срок', state => { const [priority, client] = state.changes; if (!priority || !priority.columns || !client || !client.columns) return null; const tariff = client.columns['Тариф']; const priorityValue = priority.columns['Приоритет']; const hours = getSlaHoursByTariffAndPriority(tariff, priorityValue); if (hours === undefined) return null; return {hours_from_create: hours}; }); function getSlaHoursByTariffAndPriority(tariff, priority) { switch (tariff) { case 'Базовый': switch (priority) { case 'Низкий' : return 64; case 'Средний': return 32; case 'Высокий': return 16; } case 'Стандарт': switch (priority) { case 'Низкий' : return 32; case 'Средний': return 16; case 'Высокий': return 8; } case 'Премиум': switch (priority) { case 'Низкий' : return 16; case 'Средний': return 8; case 'Высокий': return 4; } default: return undefined; } }
Валидация
Дата окончания не раньше даты начала
form.onChange(['Дата начала', 'Дата окончания']) .validate('Дата окончания', state => { const [start, end] = state.changes; if (!start || !end) return null; if (start.date && end.date && start.date >= end.date) return { errorMessage: 'Не может быть раньше даты начала' }; return null; });
Заполнено хотя бы одно поле
form.onChange(['Эл. почта', 'Телефон'], true) .validate('Эл. почта', state => { const [email, phone] = state.changes; const emailIsEmpty = !email || !email.text; const phoneIsEmpty = !phone || !phone.text; if (emailIsEmpty && phoneIsEmpty) return { errorMessage: 'Заполните электронную почту или телефон' }; return null; });
Проверяем правильность заполнения текстового поля
Скрипт проверяет, чтобы текстовое поле было заполнено только заглавными латинскими буквами.
form.onChange(["fio_text"], true) .validate("fio_text", state => { const [text] = state.changes; if (!text?.text) return null; const reg = new RegExp(/^[A-Z'\s]+$/); if (!reg.test(text.text)) return { errorMessage: "Обнаружены недопустимые символы" }; });
Запрет удаления строк в таблице
Скрипт не даёт удалить сохранённые строки из таблицы в форме.
let exist_table = null; form.onChange(["no_delete_table"], true) .validate("no_delete_table", state => { const [table] = state.changes; if (state.currentStep == 0) return null; if (!exist_table) { exist_table = []; if (table?.value) { for (let i in table.value) { exist_table.push(table.value[i].Id); } } return null; } if (exist_table.length == 0) return null; if (!table?.value || table.value.length == 0) return { errorMessage: "Нельзя удалять строки таблицы. Перезагрузите страницу" }; for (let i in exist_table) { if (!table.value.find(x => x.Id == exist_table[i])) return { errorMessage: "Нельзя удалять строки таблицы. Перезагрузите страницу" }; } return null; });
Ограничение на добавление файлов определённого типа
Скрипт позволяет добавить в поле только PDF-файлы и никакие другие.
form.onChange(["files"]) .validate("files", state => { const [files] = state.changes; const correct_extensions = ["pdf"]; if (!files?.files) return null; for (let i in files.files) { let extension = files.files[i].name.split(".").slice(-1); if (correct_extensions.indexOf(extension[0]) < 0) return { errorMessage: "Можно приложить только pdf" }; } return null; });
Проверка оставшихся дней отпуска
Скрипт рассчитывает, сколько у сотрудника ещё осталось дней оплачиваемого отпуска. Данные для расчёта берутся из реестра формы.
form.onChange(["vacation_start", "vacation_end", "employee", "vacation_type"]) .validateAsync("vacation_type", async state => { const [start, end, employee, vacation_type] = state.changes; if (!start?.date || !end?.date || !employee?.person_id || !vacation_type?.choice_name) return null; if (vacation_type.choice_name != "Оплачиваемый") return null; const max = 28; let this_time = daysBetween(new Date(start.date), new Date(end.date)) + 1; if (this_time > max) return { errorMessage: `Выбран промежуток в ${this_time} дней. Максимально ${max}` }; let today = new Date(); let already_taken = await form.fetchRegister(1027552, f => f .fieldGreaterThen("Дата начала", {date: `01-01-${today.getFullYear()}`}) .fieldLessThen("Дата окончания", {date: `01-01-${today.getFullYear()+1}`}), ["Дата начала", "Дата окончания"], {activeOnly: false} ); if (!already_taken.tasks || already_taken.tasks.length == 0) return null; let taken_days = 0; for (let i in already_taken.tasks) { if (!already_taken.tasks[i].fields[0] || !already_taken.tasks[i].fields[1]) continue; taken_days += daysBetween( new Date(already_taken.tasks[i].fields[0].date), new Date(already_taken.tasks[i].fields[1].date) ) + 1; } if (taken_days + this_time > max) return { errorMessage: `Уже использовано ${taken_days} дней. Осталось ${max - taken_days}. Превышение на ${this_time + taken_days - max}` }; return null; });
Фильтрация значений
Фильтрация справочника
Этот скрипт позволяет фильтровать список городов по выбранному региону.
const catalogPromise = form.getCatalog("Города по регионам"); form.onChange(["Регион"]).setFilterAsync("Город", async state => { const [region] = state.changes; const catalogItems = await catalogPromise; if (!catalogItems || !region.columns) return null; const regionCol = region.columns["Регион"]; const filtered = catalogItems .filter(item => item.columns["Регион"] === regionCol) .map(item => item.columns["Город"]); return filtered.length > 0 ? { values: filtered } : null });
Фильтрация значений поля типа Форма
Скрипт фильтрует список задач в поле «contragent» типа Форма: отображаются те задачи связанной формы, в которых в поле «Менеджер» указан тот же пользователь, что и в поле «manager» исходной формы.
form.onChange(["manager"], true) .setFilter("contragent", state => { const [manager] = state.changes; if (!manager?.person_id) return null; return { filters: [{ fieldName: "Менеджер", value: manager.person_id }] } });