Skip to content

Working with workflows

Content Script Workflow Steps

The Content Script Extension for Workflows is automatically available upon installation of the Content Script module. The extension enables a new workflow package in Workflow maps (Content Script package) and custom type of workflow step (Content Script step).

To create workflow maps programmatically from Content Script, see How to: Build workflows with ProcessBuilder.

Content Script Package

The Content Script package must be enabled in order to use Content Script steps within a workflow map.

Once enabled, it will be possible to define the set of Content Script objects that will be available for inclusion in the current workflow map.

Content Script Workflow Step

Content Scripts enabled in the workflow package can be used in the workflow map as Content Script steps.

Here below is an example of a Content Script step performing some basic operations on the current workflow task.

// Fetch the menu in its original format
def workflowStatus  = workflow.getWorkflowStatus(workID, subWorkID)
def workflowTask  = workflow.getWorkFlowTask(workID, subWorkID, taskID)
def allTasks   = workflowStatus.tasks 

// Edit Workflow Attribute values
def workflowAttributes = workflowStatus.getAttributes()
workflowAttributes.setAttributeValues("Customer", "ACME inc.")
workflowAttributes.setAttributeValues("Country", "Switzerland")
workflow.updateWorkflowData(workID,  subWorkID, [workflowAttributes]) //Updates attributes

// Edit  Workflow Attribute values - different flavour
try{

    def atts =workflowStatus.getAttributes()

    // This API is not just for reading values...  
    // Set the value
    atts.data.Customer = "ACME inc."
    atts.data.Country = "Switzerland"

    workflowStatus.updateData() // COMMIT CHANGES

}catch(e){
    log.error("Unable to access workflow's attributes ",e)
}

// Access a workflow form
def form = forms.getWorkFlowForm(workflowTask, "Form")  
form.myattribute.value = "A new value"
forms.updateWorkFlowForm(workflowTask, "Form", form, false)

// Update Task's title
workflow.updateTaskTitle( 
                          workID, 
                          subWorkID, 
                          taskID, 
                          "Title with form field: ${form.myattribute.value}"
                        )

// Access a workflow form and workflow attributes - different flavour
//Mapping
node = asCSNode(path:"Some Path:On Content Server:Node")

workflowStatus.attributes."Account Folder" = node.ID
workflowStatus.forms.Form.data."Lead Owner" = node.Account."Account Manager"
workflowStatus.forms.Form.data."Company" = node.Account."Company name"
workflowStatus.forms.Form.data."First Name" = node.Account."Contacts"."First Name"
workflowStatus.forms.Form.data."Last Name" = node.Account."Contacts"."Last Name"
workflowStatus.forms.Form.data."Email" = node.Account."Contacts"."Email"
workflowStatus.forms.Form.data."Addresses"."Street" = node.Account."Addresses"."Street"
workflowStatus.forms.Form.data."Addresses"."City" = node.Account."Addresses"."City"
workflowStatus.forms.Form.data."Addresses"."Zip Code" = node.Account."Addresses"."ZipCode"
workflowStatus.forms.Form.data."Addresses"."Country" = node.Account."Addresses"."Country"
workflowStatus.updateData()   // COMMIT CHANGES

// Updating Workflow title
workflow.updateWorkFlowTitle( 
                              workID, 
                              subWorkID,
                              "Company: ${workflowStatus.forms.Form.data."Company" as String}"
                            )

// Add documents to the attachments folder (an empty spreadsheet in this case)
def workflowAttachments = workflowStatus.getAttachmentsFolder()
workflowAttachments.createDocument("Spreadsheet", xlsx.createSpreadsheet().save()) 

In the above example, the script is:

  • fetching information related to the current workflows status and tasks

  • performing changes on some workflow attributes

  • fetching and updating a workflow form

  • adding attachments to the workflow attachments folder

Note that the above script makes use of some context variable available in the execution context that are peculiar only to workflow steps. The variables are:

Expression type Type Description
workID Integer The workflow ID
subWorkID Integer The subworkflow ID
taskID Integer The current task ID

The above variables can be used in combination with the workflow service API to access all the information related to the current workflow. See the complete API documentation for a complete list of operations available on workflow instances.

Workflow routing

Content Script execution outcome, which MUST always be a String, can be interpreted in different ways, and used to route the next steps of the workflow.

The following routing expression types are currently supported:

Expression type Values Description
Content Script Outcome Success or Error Error in case the script returns an exception
Content Script Outcome (Integer) Any Integer value Supports evaluation based on numeric comparison
Content Script Outcome (String) Any String value Evaluation based on string comparison

Starting with Module Suite 4.1.0, a workflow map retrieved through the workflow service exposes the steps it defines and the transition links that connect them. This makes it possible to inspect the structure of a map from Content Script, for example to list the steps of a process or to find which steps follow a given one.

A workflow map is obtained with workflow.getWorkflowMap(workflowMapID) or workflow.getWorkflowMapEx(workflowMapID) (the latter also includes activity permissions). On the returned CSWorkflowMap:

  • getActivities() returns a list of CSWorkflowMapActivity, one per step defined in the map

  • getTransitionLinks() returns a list of CSWorkflowTransitionLink, one per link between two steps

Each transition link references its source and destination steps by identifier, so activities and links together describe the map as a graph:

flowchart LR
    Start[Start step] -->|link| Review[Review step]
    Review -->|link| Approve[Approval step]
    Review -->|link| Rework[Rework step]
    Rework -->|link| Review

CSWorkflowMapActivity

A CSWorkflowMapActivity represents a step defined in a workflow map.

Method Description Since
getID() Returns the identifier of the step within its workflow map (long) 4.1.0
getTitle() Returns the title of the step 4.1.0
getInstructions() Returns the instructions shown to the step performer 4.1.0
getDuration() Returns the duration allotted to the step (Integer), or null if none is set 4.1.0
getPriority() Returns the priority of the step (Integer) 4.1.0
getStartDate() Returns the start date set on the step (Date), or null if none is set 4.1.0
getMemberID() Returns the ID of the user or group assigned to the step (Long), or null if the step is unassigned 4.1.0
getType() Returns the type of the step 4.1.0
getSubtype() Returns the subtype of the step 4.1.0
getDelegate() Returns the underlying Content Server web service object (com.opentext.livelink.service.workflowservice.Activity) 4.1.0

A CSWorkflowTransitionLink represents a link between two steps of a workflow map.

Method Description Since
getSourceActivity() Returns the identifier of the step the link leaves from (int) 4.1.0
getDestinationActivity() Returns the identifier of the step the link leads to (int) 4.1.0
getTransitionType() Returns the kind of transition the link represents 4.1.0
getDelegate() Returns the underlying Content Server web service object (com.opentext.livelink.service.workflowservice.TransitionLink) 4.1.0

Activity identifiers are returned as long, while the step references on a transition link are returned as int; convert them to a common type before comparing.

// Retrieve a workflow map by its ID
def map = workflow.getWorkflowMap(mapID)

// Index the steps by their identifier
def activitiesByID = map.getActivities().collectEntries { [(it.ID as long): it] }

activitiesByID.values().each { activity ->
    out << "Step ${activity.ID}: ${activity.title} (${activity.type}/${activity.subtype})"
    if (activity.memberID != null) {
        out << " assigned to ${activity.memberID}"
    }
    out << "<br>"
}

// Print every transition link as "source -> destination"
map.getTransitionLinks().each { link ->
    def source      = activitiesByID[link.sourceActivity as long]
    def destination = activitiesByID[link.destinationActivity as long]
    out << "${source?.title} -> ${destination?.title} [${link.transitionType}]<br>"
}

Example: finding the steps that follow a given step

def map = workflow.getWorkflowMap(mapID)
def activitiesByID = map.getActivities().collectEntries { [(it.ID as long): it] }

// Steps reachable in one transition from the step titled "Review"
def review = activitiesByID.values().find { it.title == "Review" }

def nextSteps = map.getTransitionLinks()
                   .findAll { (it.sourceActivity as long) == review.ID }
                   .collect { activitiesByID[it.destinationActivity as long] }

nextSteps.each { out << "${it.title}<br>" }