Workflow scripting
Scripts are used to perform automatic actions and fine-tune the behavior of the workflow. There are two basic types of scripts:
-
Visibility scripts are executed to control the availability of the activity.
-
Regular scripts are executed when a certain action is performed or event takes place.
In addition, some elements and adornments have scripts with special purposes, as for example the decision script which determines the exit which a case takes when running through a decision node.
There are two ways of managing scripts:
-
Using embedded scripts:
Embedded scripts are provided directly in the workflow editor, i.e., you open the script editor for the desired element, type the script content and save the script.
-
Using scripts of the type Workflow:
Workflow scripts are saved on the Scripts page of the Web Admin Suite, see Scripts of the type Workflow. They can be referenced in an embedded script, i.e., you create an embedded script which executes a workflow script:
scriptExecutionService.execute("myscript.groovy")
The following table shows a comparison between both modes:
Mode |
Description |
Advantages |
Disadvantages |
---|---|---|---|
Embedded script |
The complete script content is provided in the workflow editor. |
|
|
Workflow script |
The script is saved as a script of the type Workflow on the Scripts page. The embedded script references this workflow script. |
|
|
Scripts are written in Groovy. Since Groovy code runs in the Java Virtual Machine, you can also write Java code. Groovy code allows you to use dynamic typing, and to omit getter and setter methods, thus providing a shorter syntax. The following table shows some examples of the differences between Groovy and Java:
Goal |
Groovy |
Java |
---|---|---|
Retrieve the subject of a case |
def mysubject = ticket.subject |
String mysubject = ticket.getSubject(); |
Retrieve the main contact of a case |
def mymaincontact = ticket.mainContact |
Unit mymaincontact = ticket.getMainContact(); |
Retrieve the value of a certain case field from a case |
def myprio = ticket.get("helpdesk_fields.prio") |
String myprio = ticket.get("helpdesk_fields", "prio"); |
Set the subject of a case |
ticket.subject = "asd" |
ticket.setSubject("asd"); |
ConSol CM API methods
The ConSol CM API provides various convenience interfaces and methods which make access to the most commonly used objects easy. Most of these convenience interfaces are part of the package com.consol.cmas.common.service and its sub-packages.
The implementing instance of the interface is always available by replacing the first letter, which is a capital letter, in the class name by a lower case one, e.g., use engineerService to call methods of the interface EngineerService. The only exception to this rule is the class WorkflowContextService whose object workflowApi provides many useful methods.
Please refer to the ConSol CM API documentation for details about the available classes and methods.
Features of the script editor
The script editor has the following features:
-
Syntax highlighting
The editor uses syntax highlighting for Groovy. -
Code autocompletion
As soon as you type a dot, the methods for the current object are suggested. You can continue typing to narrow down the results. Only methods for explicitly declared variables are displayed.You can press CTRL + SPACE to display suggestions for service classes.
-
Code validation
The code validation results are displayed when hovering the line with the error. There are three modes:- No validation: The code validation feature is turned off.
- Simple validation: A simple code validation is performed.
- Strict validation: A more detailed code validation, which also checks if the invoked methods exist for the objects, is performed.
-
Code snippets
You can insert code snippets related to the following objects into your scripts:- Script generators: generate and insert code for email scripts based on selections made in a modal window
- Data fields: get and set values of case, contact and resource fields, get the technical and localized value of enum fields, iterate over list fields, add rows to list fields
- Labels: insert a label with or without locale
- Queues: insert a queue
- Scripts: execute a script
- System properties: insert a system property
- Templates: insert a template with or without locale
You can access the code snippets by selecting the >> Insert code snippet option from the autocomplete suggestions, by clicking the Insert code snippet button in the toolbar, or by using the keyboard shortcut CTRL + J.
The Code snippets window includes a search field to search for the desired piece of code, e.g., search for a contact field to display the available snippets. You can apply additional filters by entering the type of object followed by a colon in the search field:
- label: searches for labels
- property: search for system properties
- queue: searches for queues
- resource: searches for resource fields
- script: searches for scripts
- template: searches for templates
- ticket: searches for case fields
- unit: searches for contact fields
-
Keyboard shortcuts
There are keyboard shortcuts for common operations. Examples:- Save: CTRL + S
- Undo: CTRL + Z
- Find: CTRL + F
- Insert code snippet: CTRL + J
- Autocompletion: CTRL + space
- Jump to line: CTRL + L
- Jump to the referenced script: ALT + J
- Open a preview of the referenced script: ALT + P
- Open a preview o the script template: ALT + T
- Format code: ALT + F
The shortcuts related to referenced scripts are available once the user has selected the script name in the code.
-
Text highlighting
You can double-click a word or mark some text to highlight all its occurrences within the script.
You can see where a script is used by clicking the Usage button. The popup window lists the places where the script is referenced and provides links to jump to the referencing objects.
Scripting examples
The following sections contain short descriptions of the most important aspects of scripting. Larger topics are covered in sub-pages:
Referencing workflow elements
Workflow elements are always referenced by their path. The path reflects the hierarchical structure of the workflow. It starts with defaultScope and contains the technical names of the scopes where the element is located and the technical name of the element.
Example: Activity information_received in the sub-scope on_hold of the scope work_in_progress:
defaultScope/work_in_progress/on_hold/information_received
You can copy the path using the Copy button in the details panel of the respective element.
Working with data fields
Data fields are always referenced by their technical names using the following pattern:
<ticket|unit|resource>.<get|set|add|remove>("<technical name of the field group>.<technical name of the field>")
The content of a data field depends on the data type, it can be either a value or an object.
Please see Using data fields in scripts for details about the available methods for different objects and field types.
Using data fields for variables
Sometimes you need variables which are required for workflow programming but should not be visible on the GUI of the Web Client and CM/Track. Depending on the object for which they are needed, you can use case, contact or resource fields for these variables.
-
Create a data field with the required data type.
-
Set Visibility to Never to hide the field from the GUI.
Working with user data
When working with user data, you need to distinguish between the current user, i.e., the user who is logged in and performs the action which leads to the execution of the script, and the assignee of a case.
-
Retrieve the current user:
workflowApi.getCurrentEngineer()
engineerService.getCurrent()
-
Retrieve the assignee of the current case:
ticket.getEngineer()
-
Assign the current case to the current user:
ticket.engineer = engineerService.current
-
Retrieve the users which have a certain role:
engineerRoleRelationService.getEngineersWithRoles(roleService.getByName("Supervisor"))
-
Retrieve the roles of the current user:
engineerRoleRelationService.getRolesForEngineer(engineerService.current)
Displaying messages
Messages are useful to provide dynamic information to the user regarding the process or the entered data. They can be displayed in a red box below the menu bar or next to a case field in an activity form. If the message should be localized, it is recommended to use labels, see Labels.
-
Display a localized message in a red box. The message text is based on the label defined for the locale of the current user.
workflowApi.addValidationError("INFO", messageProviderService.getMessage("label key", engineerService.currentLocale))
-
Display a simple message next to a case field.
workflowApi.addValidationError(ticket.getField("field group", "field"), "Message text")
Working with overlays
Overlays stay on the case icon according to the selected overlay range. You can remove an overlay by script using the following piece of code:
def si = ticket.scopeInfo
for (ov in si.getActivatedOverlays().toArray() ) {
if (ov.parent.name == "defaultScope/ServiceDeskTicketInProgressScope/Email_received") {
si.removeOverlay(ov)
}
}
The overlay is identified by the path of the activity where it was attached.
Working with system properties
You can use methods of the class ConfigurationService to retrieve the value of system properties.
configurationService.getValue("module name","property name")
Working with text classes
You can retrieve and set text classes for case history entries.
-
Retrieve the text class of a history entry:
ContentEntry.getContentEntryClass()
-
Modify the text class of a history entry:
ticketContentService.updateContentEntryClass(ContentEntry pContentEntry, ContentEntryClass pContentEntryClass)
Working with attachments
You can add and retrieve attachments with the following methods:
-
Retrieve all attachments:
workflowApi.getAttachmentList()
-
Retrieve attachments from incoming emails:
ticketContentService.getAttachmentEntries(ticket, ContentEntryCategory.INCOMING_MAIL)
-
Retrieve attachments from outgoing emails:
ticketContentService.getAttachmentEntries(ticket, ContentEntryCategory.OUTGOING_MAIL)
-
Add an attachment:
def filePath = "/home/hotline/fileToAdd.xml"
def file = new File(filePath)
def stream = new ByteArrayInputStream(file.readBytes() );
def content = new ContentFile("newFileName.xml", "application/xml", stream, file.length());
def attachment = new AttachmentEntry();
attachment.setMimeType ("application/xml")
attachment.setFile(content)
// in workflow context
workflowApi.addAttachment(attachment);
// in non-workflow context
ticketContentService.createContentEntry(ticket, attachment)
Modifying the visibility of data field groups
You can control the display of data field groups with the setting Visible. A common use case is to hide field groups initially by setting false, implement activity forms where the data is filled in, and show the field groups on the GUI afterwards. This helps to keep the case data concise by displaying certain fields only when they are needed in the process.
The following methods can be used for controlling the visibility of case field groups:
-
Show a case field group:
workflowApi.setGroupProperty("ticket field group",GroupPropertyType.VISIBLE,"true")
-
Hide a case field group:
workflowApi.setGroupProperty("ticket field group",GroupPropertyType.VISIBLE,"false")
-
Show a contact field group:
def fieldGroupDefinition = fieldDefinitionService.getGroupByName("field group")
unit.getGroupsConfiguration().setProperty(fieldGroupDefinition, GroupPropertyType.VISIBLE, "true")
-
Show a resource field group:
def fieldGroupDefinition = fieldDefinitionService.getGroupByName("field group")
resource.getGroupsConfiguration().setProperty(fieldGroupDefinition, GroupPropertyType.VISIBLE, "true")
Searching for objects
You can search for cases, contacts and resources using criteria objects.
-
Search for cases:
ticketService.getByCriteria(TicketCriteria pTicketCriteria)
-
Search for contacts:
unit.Service.getByCriteria(UnitCriteria pUnitCriteria)
-
Search for resources:
resourceService.getByCriteria(ResourceCriteria pResourceCriteria)
The criteria object is configured by using the provided methods to add one or several criteria. If you use a data field as a search criterion, the respective data field must be indexed.
The search methods return the complete objects, so they can consume a lot of memory if you perform a search. If you only need the number of objects matching certain criteria, you can use the methods getCountByCriteria() of the same classes instead.
Considering case update events
Certain methods cause so called update events (class TicketUpdateEvent). These events can decrease the system performance. Therefore, they should be avoided as long as they are not necessary for the business process.
Example: Assigning a user to a case
-
workflowApi.assignEngineer(workflowApi.currentEngineer) throws an update event.
-
ticket.setEngineer(workflowApi.currentEngineer) does not throw an update event.
In addition, update events occur after a workflow element is executed. If there is a chain of elements, you should avoid triggering an update event after every single element. Select the Skip update event checkbox for all elements except for the last one to update the case only once, after the last workflow element.
Adding log output
You can add log output to your scripts by using the following syntax:
log.info "This is my debug message."
You can log messages at other log levels by using log.debug, log.warn, or log.error. The log messages are written to the server.log file.
See Log files for details about the available log files and their configuration.
Modifying the execution flow
You can treat a trigger execution with automatic activities as an exception instead of an interrupt by using the method skipInterruptRestore() of the class ScopeInfo. This method can be used only in automatic activities connected to triggers. If you add it to the script of such an activity, the case does not return to the original activity where it was located before the trigger fired, but stays in the flow of the activity where this method is called.
This allows for example to implement workflows where the case is moved to a waiting scope by a trigger and remains there until another trigger fires.