Начало работы с процессами

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

Начало работы

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

Запуск процесса

Вы можете запустить бизнес-процесс с помощью пользовательского скрипта. Для этого используется метод Process.run, который позволяет запустить опубликованный процесс. При запуске всегда используется последняя, опубликованная версия процесса. В частности, запуск из скрипта необходим, когда в скрипте динамически создаются элементы приложения или другие данные, требуемые для запуска процесса, и выполнение должно начинаться без участия пользователя. Чтобы запустить процесс в пользовательском скрипте после его публикации, необходимо обратиться к его шаблону (ProcessTemplate). В первом примере рассмотрим запуск процесса Отправка документа, созданного на уровне всей компании:

Предположим, что процесс предназначен для отправки документа с некоторой информацией, относящейся к документу, во внешнюю систему. Для этого в контекст будут добавлены следующие поля:

  • documentNumber — номер документа;
  • documentContent — файл документа;
  • authorName — имя автора.

Важно отметить, что в пользовательских скриптах получить доступ к процессу можно через его код. Пример скрипта, запускающего такой процесс:


async function runProcess(): Promise<void> {
    // Запись процесса `my_process` в переменную `processTemplate`
    // для дальнейшего запуска
    const processTemplate = Global.processes.send_document;
    // Получаем номер документа из контекста
    const documentNumber = Context.data.documentNumber;
    // Получаем имя автора из контекста
    const authorName = Context.data.authorName;
    
    // Загружаем данные с помощью некоторой функции
    const bytesContent = await downloadDocumentFile();
    // Создаем временный файл в системе, чтобы поместить его в контекст процесса
    const temprorayFile = await System.files.createTemporary('file.docx', bytesContent);
    
    // Запуск процесса; в качестве аргумента передаются его входные данные,
    // определяемые контекстом, который указан в процессе
    // Формат передачи данных — объект, где в качестве ключей указываются
    // коды полей
    await processTemplate.run({
        authorName: authorName,
        documentContent: temprorayFile,
        documentNumber: documentNumber,
    });
}

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

Процессы также могут быть привязаны к приложениям и разделам системы. Тогда для запуска необходимо выбрать процесс по пути его расположения. Ниже указан пример запуска процесса my_process из приложения process_app раздела process_workspace:

async function runProcess(): Promise<void> {
    // Запись процесса `my_process` в переменную `processTemplate`
    // для дальнейшего запуска
    // Для обращения к процессу используем объект `ns`, для выбора раздела — `process_workspace`
    // Также можно использовать объект `Namespace`
    const processTemplate = Global.ns.process_workspace.app.process_app.processes.my_process;

    // Получаем номер документа из контекста
    const documentNumber = Context.data.documentNumber;
    // Получаем имя автора из контекста
    const authorName = Context.data.authorName;

    // Загружаем данные с помощью некоторой функции
    const bytesContent = await downloadDocumentFile();
    // Создаем временный файл в системе, чтобы поместить его в контекст процесса
    const temprorayFile = await System.files.createTemporary('file.docx', bytesContent);

    // Запуск процесса; в качестве аргумента передаются его входные данные,
    // определяемые контекстом, который указан в процессе
    // Формат передачи данных — объект, где в качестве ключей указываются
    // коды полей
    await processTemplate.run({
        authorName: authorName,
        documentContent: temprorayFile,
        documentNumber: documentNumber,
    });
}

Поиск экземпляров процесса

С помощью пользовательских скриптов можно прервать процесс или изменить его инициатора. Чтобы вызвать соответствующие функции, необходимо обратиться к экземпляру процесса. Для этого необходимо иметь возможность найти экземпляры запущенных процессов. Поиск можно выполнить по всем полям, представленным в объекте ProcessInstanceItem. Например, найти запущенные процессы в рассмотренном ранее разделе можно с помощью полей ProcessInstanceItemRef.namespace, ProcessInstanceItemRef.code процесса:

    // `_searchInstances()` — метод, позволяющий составить запрос на поиск процессов в системе по различным условиям
    const processess = await Global.processes._searchInstances().all();

В данном случае мы получим 10 последних процессов. С помощью метода where объекта ProcessInstanceSearch можно находить различные процессы в системе.

Поиск завершенных процессов

Пользовательские скрипты также помогают найти экземпляры процессов, которые уже завершились:

async function searchFinishedProcessess(): Promise<void> {
    // Выполняем поиск по процессам, которые завершены, используя константу `ProcessInstanceState.done`
    // Использование метода `where` позволяет фильтровать процессы по их состоянию
    const processTemplate = await Global.processes._searchInstances().where(q => q.__state.eq(ProcessInstanceState.done)).all();
}

Поиск последнего процесса с ошибкой

Используя константу ProcessInstanceState.error, можно получить процессы, которые завершились с ошибкой:

async function searchFinishedProcessess(): Promise<void> {
    // Выполняем поиск по экземплярам процессов, которые завершены с ошибкой, используя константу `ProcessInstanceState.error`
    // Использование метода `where` позволяет фильтровать экземпляры по их состоянию
    const processTemplate = await Global.processes._searchInstances().where(q => q.__state.eq(ProcessInstanceState.error)).all();
}

Для получения последнего процесса необходимо выполнить сортировку и вызвать метод first:

async function searchFinishedProcessess(): Promise<void> {
    // Выполняем поиск по экземплярам процессов, которые завершились с ошибкой, используя константу `ProcessInstanceState.error`
    // Использование метода `where` позволяет фильтровать экземпляры по их состоянию
    const processTemplate = await Global.processes._searchInstances()
        .where(q => q.__state.eq(ProcessInstanceState.error)) // Выбор состояния процесса
        .sort('__createdAt', false) // Сортировка по дате создания
        .first() // Получение первого экземпляра из выборки
}

Прерывание процессов

Для ситуаций, когда необходимо прервать выполнение бизнес-процесса, в объекте процесса существует метод ProcessInstanceItem.interrupt. Например, если необходимо прервать экземпляры устаревших версий всех процессов, необходимо найти их с помощью функции поиска и для каждого вызвать метод ProcessInstanceItem.interrupt:

async function interruptOldProcesses(): Promise<void> {
    const processTemplate = await Global.processes._searchInstances()
        .where(q => q.__createdAt.lt(/* Дата */)) 
        .where(q => q.__state.in([ProcessInstanceState.exec, ProcessInstanceState.wait])).all()

    const interruptings = processTemplate.map(process => process.interrupt('Истекло время выполнения'))
    await Promise.all(interruptings);
}

Смена ответственного

Для установки нового ответственного в системе существует метод ProcessInstanceItem.setResponsible. Данный метод можно использовать только для экземпляра процесса, который можно найти по различным фильтрам Processes._searchInstances. Метод можно использовать в тех случаях, когда процесс запускается одним пользователем, но в дальнейшем инициатора необходимо изменить. В частности, это можно использовать в процессе добавления новых сотрудников в систему, когда на этапе запуска процесса пользователь, который должен выполнить определенные действия, еще не существует в системе:

// `setResponsible` назначает процессы с `author` на `responsible`
async function setResponsible(author: string, responsible: string): Promise<void> {
    // Получение ссылки на нового инициатора процесса
    // В данном случае это пользователь, добавленный в систему с помощью процесса
    const responsibleRef = await System.users.search().where(q => q.__id.eq(responsible)).first()

    // Поиск процессов, выполняемых замещаемым пользователем
    const authorProcesses = await Global.processes._searchInstances()
        .where(q => q.__createdBy.eq(author)) 
        .where(q => q.__state.in([ProcessInstanceState.exec, ProcessInstanceState.wait]))
        .all()

    // Запуск скрипта переноса с автора на ответственного
    const replacements = authorProcesses.map(process => process.setResponsible(responsibleRef, 'Переназначение'))
    await Promise.all(replacements);
}