Getting started with processes

Business processes are one of the key tools that are used to automate work in the system. Using processes, you can perform various operations with different system elements.

Getting started

To start working with processes in custom scripts, you need to have some configured and published business processes that don’t contain errors. Using scripts, you can work with existing business processes, process instances, and tasks assigned to users.

Start a process

You can start a business process using a custom script. To do that, use the Process.run method. It allows you to start any published business process. It is always the most recent published version of the business process that is started. You may need to run a process from a script if app items or other data needed to start the process are generated in the script in a dynamic way or when a process needs to start independently, without involving a user. To run a process in a custom script after publishing it, you need to access its template (ProcessTemplate). In the first example, let’s see how to start the Send document/app item global business process.

Let’s say the process is used to send a document along with some information about it to an external system. The following fields will be added to the context to make it possible:

  • documentNumber. The document number.
  • documentContent. The document file.
  • authorName. The author’s name.

It should be noted that you can access a business process in a custom script using its code. Here is an example of a script starting a process:


async function runProcess(): Promise<void> {
    // Writing the `my_process` business process to the `processTemplate` variable
    // to make it possible to start the process
    const processTemplate = Global.processes.send_document;
    // Getting the document number from the context
    const documentNumber = Context.data.documentNumber;
    // Getting the name of the author from the context
    const authorName = Context.data.authorName;
    
    // Uploading data using a function
    const bytesContent = await downloadDocumentFile();
    // Creating a temporary file in the system to store it in the process context
    const temprorayFile = await System.files.createTemporary('file.docx', bytesContent);
    
    // Starting the process using the input data from its context as the argument
    // Data transmission format is an object with field codes as keys
    await processTemplate.run({
        authorName: authorName,
        documentContent: temprorayFile,
        documentNumber: documentNumber,
    });
}

When this script is executed, you can find a new process instance with the pre-defined context in the Process Monitor.

Apart from global business processes, the system includes processes associated with apps and workspaces. In this case, to start a process, you need to access it using a path to its location in the system. Here is an example of starting the my_process business process stored in the process_app app of the process_workspace workspace:

async function runProcess(): Promise<void> {
    // Writing the `my_process` business process to the `processTemplate` variable
    // to make it possible to start the process
    // Using the `ns` object to access the process and `process_workspace` to access the workspace
    // It is also possible to use the `Namespace` object
    const processTemplate = Global.ns.process_workspace.app.process_app.processes.my_process;

    // Getting the document number from the context
    const documentNumber = Context.data.documentNumber;
    // Getting the name of the author from the context
    const authorName = Context.data.authorName;

    // Uploading data using a function
    const bytesContent = await downloadDocumentFile();
    // Creating a temporary file in the system to store it in the process context
    const temprorayFile = await System.files.createTemporary('file.docx', bytesContent);

    // Starting the process using the input data from its context as the argument
    // Data transmission format is an object with field codes as keys
    await processTemplate.run({
        authorName: authorName,
        documentContent: temprorayFile,
        documentNumber: documentNumber,
    });
}

Search for process instances

You can use custom scripts to interrupt certain processes or change their initiators. To call the corresponding functions, you need to access a process instance. To do that, you need a way to get instances of all running processes. You can search by any fields of the ProcessInstanceItem object. For example, you can find running processes stored in the workspace discussed above using ProcessInstanceItemRef.namespace and ProcessInstanceItemRef.code fields of the process:

    // `_searchInstances()` is a method that allows you to make a search query in the system and set different conditions
    const processess = await Global.processes._searchInstances().all();

Using this script, we will get 10 most recently started processes. Using the where method of the ProcessInstanceSearch object, you can find different processes in the system.

Search for completed processes

Custom scripts also allow you to find process instances that have already been completed.

async function searchFinishedProcessess(): Promise<void> {
    // Searching for completed processes using the `ProcessInstanceState.done` constant
    // The `where` method allow you to filter processes by state
    const processTemplate = await Global.processes._searchInstances().where(q => q.__state.eq(ProcessInstanceState.done)).all();
}

Search for the last process with an error

Using the ProcessInstanceState.error constant, you can get processes interrupted with an error:

async function searchFinishedProcessess(): Promise<void> {
    // Searching for process instances interrupted with an error using the `ProcessInstanceState.error` constant
    // The `where` method allow you to filter processes by state
    const processTemplate = await Global.processes._searchInstances().where(q => q.__state.eq(ProcessInstanceState.error)).all();
}

To get the most recent process, you need to apply the sorting and call the first method:

async function searchFinishedProcessess(): Promise<void> {
    // Searching for process instances interrupted with an error using the `ProcessInstanceState.error` constant
    // The `where` method allow you to filter processes by state
    const processTemplate = await Global.processes._searchInstances()
        .where(q => q.__state.eq(ProcessInstanceState.error)) // Choosing the necessary state
        .sort('__createdAt', false) // Sorting by creation date
        .first() // Getting the first instance in the search results
}

Interrupt a process

In some cases, it may be needed to interrupt the execution of a business process. To do that, use the ProcessInstanceItem.interrupt method. For example, if you need to interrupt all instances of all outdated business process versions, you need to find them using the search function and call the ProcessInstanceItem.interrupt method for each one:

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

    const interruptings = processTemplate.map(process => process.interrupt('elapsed execution time'))
    await Promise.all(interruptings);
}

Change the process initiator

To set a new responsible, use the ProcessInstanceItem.setResponsible method. This method can only be used for process instances, which can be found with the use of different filters set in Processes._searchInstances. You can use this method when a process needs to be started by one user, but later the initiator has to be changed. For instance, this can be used in the process of adding new employees to the system, as when the process starts, the user who needs to perform some actions does not exist yet:

// `setResponsible` reassigns processes from `author` to `responsible`
async function setResponsible(author: string, responsible: string): Promise<void> {
    // Getting a link to the new initiator
    // In this case, it’s the user added to the system in the business process
    const responsibleRef = await System.users.search().where(q => q.__id.eq(responsible)).first()

    // Searching for processes where the original user is the initiator
    const authorProcesses = await Global.processes._searchInstances()
        .where(q => q.__createdBy.eq(author)) 
        .where(q => q.__state.in([ProcessInstanceState.exec, ProcessInstanceState.wait]))
        .all()

    // Starting a script that reassigns processes from the original user to the new responsible
    const replacements = authorProcesses.map(process => process.setResponsible(responsibleRef, 'Reassigning'))
    await Promise.all(replacements);
}