This chapter discusses the following:
The access to data fields is an essential part of ConSol CM programming. It is potentially required in all scripts of the system, workflow as well as Admin Tool scripts, no matter of which type. Here, we will set the focus on workflow programming, but the access to data fields is basically the same in all scripts.
Starting with ConSol CM version 6.9.0, there are two types of data fields:
The work with Custom Fields of the new (version 6.9 and higher) customer data model (FlexCDM) is explained in detail in the ConSol CM Administrator Manual - Customer Data Model 6.9: FlexCDM and in the ConSol CM Administrator Manual (Version 6.9), section The CM Customer Data Model: FlexCDM.
Rules for work with data fields CM 6.9 and higher:
When you work with Custom Fields and Data Object Group Fields, there are three main rules you have to keep in mind:
In ConSol CM version 6.10, the module CM.Resource Pool was introduced. A detailed explanation of all objects in the new module is provided in the ConSol CM Administrator Manual, section CM.Resource Pool. Thus, in addition to the data fields already known from version 6.9, there is a new type of data fields: resource fields. In CM versions 6.10 and up, we work with the following data fields:
A data field is always of a certain data type. As for any variable in programming, it depends on the data type how you have to handle the value of the field, e.g. a string field cannot be used for calculating numbers, an enum field needs a specific access method.
The following data types are available for Custom Fields, Data Object Group Fields and Resource Fields.
If you work with scripts, either in CM workflows or in the Admin Tool, please note that the behavior of boolean fields which are represented as checkboxes, i.e. with annotation boolean-type = checkbox (default) is different depending on the CM version!
Fields which have already been filled with values in the database will not be changed during an update from a version prior to 6.9.4.0 to a version 6.9.4.0 and up.
Boolean fields represented as radio buttons (annotation boolean-type = radio) or drop-down menu (annotation boolean-type = select) are always shown and behave as described for versions 6.9.4.0 and up, i.e., with NULL value if untouched.
Figure 118: Scheme: List of Structs
Technically spoken, the list is an array which contains a map (= key:value pairs) in each field.
Figure 119: List of structs, tecnical principle
Restriction when using an Oracle database: at most 4000 bytes can be saved in UTF encoding. Starting with Oracle12c.
For long strings the limit depends on the database system used for ConSol CM: MS SQL Server: 2 GByte; MySQL: 4 GByte; Oracle: 16 - 64 GByte (depending on page size of tablespace).
For string fields, you can use specific annotations to fine-tune the field definition. For example, a string field can be defined to contain a URL which will automatically be displayed as hyperlink. Please read the following section.
The data type you choose on creating a data field cannot be changed afterwards!
String fields are widely used for customer, ticket, and resource data and strings can be used to contain various content, for example, a text box with a comment, a simple input field with only 20 characters, a URL or a password. The fine-tuning of string fields is implemented using specific annotations which are all listed on the Annotations page. However, since work with these annotations is an every-day task of CM administrators, the most important and most commonly used annotations will be explained here as well.
Value for annotation text-type: textarea
The size of the text box can be adjusted, displayed as standard text box depending on web browser. Use the field-size annotation in case a specific size of the text box is required.
Value for annotation text-type: password
Only dots will be displayed. This annotation does not define the field to contain a password! It only defines the display mode! Use the password annotation to define a string field to contain the CM.Track password.
Value for annotation text-type: url
Input will be displayed as a hyperlink in view mode. String has to match a specific URL pattern:
First part of the string is the link (url), second part is the name which should be displayed.
Example: "http://consol.de ConSol"
Value for annotation text-type: file-url
Input will be displayed as a link to a file on the file system. The web browser has to allow/support those links!
Example: Enabling file:// URLs in a Firefox browser
Add the following lines to either the configuration file prefs.js or to user.js in the user profile. On a Windows system usually in a folder like C:\Users\<USERNAME>\AppData\Roaming\Mozilla\Firefox\Profiles\uvubg4fj.default
Alternatively a Firefox browser add-on like Local Filesystem Links can be installed for better access to the referenced files and folders.
The link will also be displayed as tooltip.
The URL is correctly formed if the following conditions are met:
Example URLs:
Value for annotation text-type: label
This will be a read-only field which is displayed in gray, use the label-group annotation to link label and input fields which belong together.
Value for annotation username: true
Will be used for authentication against CM.Track server. Only for Data Object Group Fields in a contact object.
Value for annotation password: true
Will be used for authentication against CM.Track server (in DATABASE mode). Only for Data Object Group Fields in a contact object.
Value for annotation email: true
The field may only contain valid e-mail addresses. Input will be validated according to standard e-mail format <name>@<domain>.
In the Admin Tool, the Custom Fields for ticket data are defined in the Custom Field Administration: navigation group Tickets, navigation item Custom Fields.
Figure 120: ConSol CM Admin Tool: Custom Field administration for ticket data (CM version 6.10)
Three methods are of major importance for programming CF access in CM scripts. They all are methods of the class Ticket:
Another method might be used when a field should be emptied, i.e. when its value should be set to null:
To retrieve data from a Custom Field in a script, you have to reference it by using the technical names of the Custom Field Group and of the Custom Field.The method which has to be used can vary depending on the data type of the CF.
The following examples refer to the Custom Fields in the figure above.The method which should to be used (because it is the most convenient way) is:
ticket.get("<Group_name>.<CF_name>")
Please keep in mind that the getter method for a field might return either a value or an object, depending on the type of data field! Please see the following exampl efor an explanation
The following Admin Tool script, e.g. called from a workflow, will display ticket data:
// display info from custom types of various data types:
import com.consol.cmas.common.model.ticket.Ticket
Ticket ticket = workflowApi.ticket
println 'Display enum from helpdesk CF group ... '
def myfield = ticket.get("helpdesk_standard.priority")
println 'Class of helpdesk_standard.priority field is ' + myfield.getClass()
println 'Value of helpdesk_standard.priority field is ' + myfield.getName()
println 'Retrieve value directly, method 1, using getter method ... '
def my_new_field1 = ticket.get("helpdesk_standard.priority").getName()
println 'Result is ' + my_new_field1
println 'Retrieve value directly, method 2, using direct access to attribute ... '
def my_new_field2 = ticket.get("helpdesk_standard.priority").name
println 'Result is ' + my_new_field2
println 'Display value of simple data field ...'
def fb = ticket.get("helpdesk_standard.feedback")
println 'Value of feedback boolean field is ' + fb
Code example 24: Admin Tool script used to display Custom Fields
The following output will be displayed in the server.log file:
Explanation:
If you want to retrieve the value of a Custom Field which contains an object (e.g., an EnumValue), you have to use methods like getName() to retrieve the actual value, becaue ticket.get ... only provides the object. The .name notation is a simplified (Groovy) version of the getter method.
If you want to retrieve the value of a simple data field, you can do this "directly": ticket.get ... will provide the value.
A precondition script of a workflow activity could look like the following code:
boolean vip_info = ticket.get("am_fields.vip")
if(vip_info == true){
return true
}
else {
return false
}
Code example 25: Precondition script where boolean value is checked
Or shorter:
return ticket.get("am_fields.vip")
Code example 26: Precondition script where boolean value is checked, short version
An enum (ordered list) field is a field where the value is one of various list values. For example, a list with priorities is the basis for an enum field. To retrieve the value of an enum field, you can use the same syntax as for simple data types. The get method provides the enum list value, the getName() method provides the string attribute with the name of the value.
def prio = ticket.get("helpdesk_standard.priority")
println "Priority is now " + prio.getName()
//or shorter:
println "Priority is now " + prio.name
Code example 27: Retrieving an enum value for a CF
The Java class for MLAs (Multi Level Attributes) is MultiEnumField. It is handled like a regular enum field, i.e. to retrieve the current value of an MLA field, you can use the Java/Groovy code like the one shown in the example below.
Figure 121: Admin Tool: Definition of a Custom Filed of type MLA
Figure 122: Admin Tool: MLA definition
Figure 123: Web Client: Setting a value (technically: name) of the MLA
// Get
def myEnumValueName = ticket.get("GROUP_NAME.MLA_FIELD_NAME").name
// Set
EnumValue enumValue = enumService.getValueByName("ENUM_NAME","ENUM_VALUE_NAME")
ticket.set("GROUP_NAME.MLA_FIELD_NAME", enumValue)
Example with technical name of the field and localized name:
import com.consol.cmas.common.model.customfield.enums.EnumValue
println 'Displaying MLA value ...'
def my_mla_field = ticket.get("helpdesk_standard.categories")
println 'MLA value categories (technical name) is now ' + my_mla_field.name
def my_mla_field_localized = localizationService.getLocalizedProperty(EnumValue.class, "name", my_mla_field.id, engineerService.getCurrentLocale())
println 'MLA value categories (localized name) is now ' + my_mla_field_localized
Code example 28: Code (Workflow or Admin Tool script) for displaying MLA data
Figure 124: Log output for the example above
If you need to retrieve the entire path to the selected MLA value, you can proceed as follows:
println 'Displaying MLA branch ...'
List<EnumValue> mlaPathElements = mlaService.getAssignedMla(ticket, "helpdesk_standard", "categories")
def mlaPath1=""
mlaPathElements.each() {elem ->
mlaPath1 = elem.name + ' -- ' + mlaPath1
}
println 'mlaPath1 is now ' + mlaPath1
//or shorter:
def mlaPath2 = mlaService.getAssignedMla(ticket, "helpdesk_standard", "categories").reverse()*.name.join(" -- ")
println 'mlaPath2 is now ' + mlaPath2
Code example 29: Retrieving the entire path to the selected MLA value
Figure 125: Log output for the example above
A list of simple data types consists of a list (= array) which has a value of a simple data type in each line, a date in our example. The CF of type date has to have the parameter Belongs to which points to the list.
Figure 126: ConSol CM Admin Tool - CFs for a list of date fields
Figure 127: ConSol CM Web Client - List of date fields in a ticket (edit mode)
For access to each date CF within a list use the following lines of code:
def convs = ticket.get("conversation_data.conversation_list").each() { conv ->
println "NEXT DATE is :" + conv
println "CLASS of NEXT DATE is " + conv.getClass()
}
Code example 30: Displaying the content of a list of date objects
Figure 128: Log output of the script above
To access a certain line, you can use the following syntax:
def mydate = ticket.get("conversation_data.conversation_list[1]")
Code example 31: Retrieve a certain value from a list of simple data types
The data construct list of structs is the technical basis for a multi-column table structure in the Web Client. The list is the parent object which contains lines. Each line is an instance of a struct. Each line (struct) contains as many Custom Fields (table columns) as required. PLease see the figures in the introductory part of this section.
To retrieve the data from a list of structs you can work with an iteration over the lines (= structs). In the following example (from an order system, not displayed in the figure above) we work with a table where ...
Figure 129: ConSol CM Admin Tool - Custom Fields for list
Figure 130: ConSol CM Web Client - Ticket with filled-in table
def structs = ticket.get("order_data.orders_list").each() { str ->
println("CLASS of LINE is " + str.getClass())
println("FIELD VALUE HARDWARE is " + str.orders_hardware.getName())
println("CLASS of FIELD VALUE HARDWARE is " + str.orders_hardware.getName().getClass())
println("FIELD VALUE CONTACT is " + str.orders_contact)
println("CLASS of FIELD VALUE CONTACT is " + str.orders_contact.getClass())
println("FIELD VALUE NUMBER is " + str.orders_number)
println("CLASS of FIELD VALUE NUMBER is " + str.orders_number.getClass())
}
Code example 32: Retrieve data from a list of structs
Figure 131: Log File - Script Output
To set values for ticket CFs, you follow the same principle as for getting data: use the CF group name and the technical name of the CF as a reference. Of course, additionally, the new value is required. And of course it has to be of the correct data type.
ticket.set("<Group_name>.<CF_name>", <value>)
ticket.set("fields.reaction_time", new Date());
Code example 33: Set a CF value for a Date CF
When you work with number or date fields, you can even calculate with the CF values in a very comfortable way, see following example.
//add 24 hours (in millis) to current field value
ticket.add("fields.deadline", 24*60*60*1000)
Code example 34: Calculate with value of date CF
Setting a value to null (i.e. emptying the field) is the same as removing the value:
ticket.set("fields.numberOfEmployees", null)
Code example 35: Setting a CF value to null
Or shorter:
ticket.remove("fields.numberOfEmployees" )
Code example 36: Setting a CF value to null via removing the value
To set an enum value use the following syntax. Of course, the new value has to be present in the ordered list (enum) which is referenced by the CF.
ticket.set("Group_name.CF_name",<technical name of value>)
ticket.set("fields.priority", "URGENT");
Code example 37: Setting an enum value
When you want to add a line, you can simply use the add method:
ticket.add("fields.tags", "my new String")
Code example 38: Adding a new line in a list of strings
When you want to refer to a certain value to set a new value for it, you have to use the syntax for an array:
ticket.set("fields.tags[last]", "consol cm6")
Code example 39: Setting a value in a list of strings
Working with structs, you always have to work with the key of the value you would like to add or set. When you want to add a new line, you have to build a new struct as new line. The set method can be used one after another for each new field.
ticket.add("order_data.orders_list", new Struct()
.set("tA_Id", id).set("orders_hardware",mynewhardware_model)
.set("orders_contact", thenewcontactname)
.set("orders_number",thenewnumber)
Code example 40: Adding a new line in a list of structs
A Custom Field Group (CF group) can be faded-in (made visible) and faded-out (made invisible) using a workflowApi method. This works for CF groups which are displayed in the main ticket data section as well as for CF groups which are displayed in the tabbed section.
A typical use case is a CF group which is invisible at first (CF group annotation group-visibility = false) and is faded-in when the engineer needs to work with the data in the process. For example, a CF group which contains reasons for the dismissal of a request is only displayed (faded-in) when the engineer has used the workflow activity Dismiss ticket .... This prevents an information overload of the ticket.
workflowApi.setGroupProperty("CF_Group_Dismissal",GroupPropertyType.VISIBLE,"true")
Code example 41: Fade-in a CF group
To fade-out some CF groups, e.g. when the ticket has been qualified and some of the CF groups will no longer be required in the process, use code according to the following example:
workflowApi.setGroupProperty("CF_Group_HardwareInfo",GroupPropertyType.VISIBLE,"false")
workflowApi.setGroupProperty("CF_Group_SoftwareInfo",GroupPropertyType.VISIBLE,"false")
Code example 42: Fade-out CF groups
In CM version 6.9 and higher, the customer Data Object Groups are part of the new customer data model (FlexCDM). In version 6.9 they are defined in the Admin Tool, section User attributes, file card Customer data model. In version 6.10 they are defined in the Admin Tool, navigation group Customers, navigation item Data Models (also see Data Object Group Fields for Customer Data (CM Version 6.10 and Higher).
Figure 132: ConSol CM Admin Tool - Data Object Group Field administration for customer data (CM Version 6.9)
The fields, which were called Custom Fields in the customer data model of previous versions, are now called Data Object Group Fields. However, the principle you use to retrieve and set values for the data fields is principally the same as in CM version 6.8 and older.
Three methods are of major importance for programming access to Data Object Group Fields (DOGF) in CM scripts. They all are methods of the class Unit:
Another method might be used when a field should be emptied, i.e. when its value should be set to null:
Because the name of a Data Object Group Field might appear in more than one Data Object Group, the name of the Data Object Group has to be provided when accessing the customer data. For example, in the customer data model shown in the figure above, the Data Object Groups ResellerCompanyData and DirCustCompanyData could have a Data Object Group Field named city. Therefore, it is important to mention group name and field name.
Please use the following syntax:
unit.get("group1:name")
For example:
def mycity = company.get("ResellerCompanyData:city")
Code example 43: Retrieving a field value for a company
There are various objects and methods to work with data on different levels of the FlexCDM. Please see the following example where several common objects and methods have been applied. It is an Admin Tool script which is accessed from a workflow activity. The only purpose is to display some data of the ticket's main customer. The following figure shows the Java objects used in the script and the ConSol CM objects in the Admin Tool which are referenced.
Figure 133: ConSol CM customer objects in script and Admin Tool
Please keep in mind that you might also use the short notation like unit.definition.type for getter methods like unit.getDefinition().getType().
import com.consol.cmas.common.model.ticket.Ticket
import com.consol.cmas.common.model.customfield.meta.UnitDefinitionType
def ticket = workflowApi.getTicket()
def mcont = ticket.getMainContact()
println "CustomerGroup of main contact is now " + mcont.getCustomerGroup().getName()
println "Customer definition of main contact is now " + mcont.getCustomerDefinition().getName()
println "UnitDefinition of main contact is now " + mcont.getDefinition().getName()
def custmod = mcont.getCustomerDefinition().getName()
// println "CUSTMOD is now " + custmod
def cityfield
switch (custmod) {
case "BasicModel" : cityfield = "company:city";
break;
case "DirectCustomerModel" : cityfield = "DirCustCompanyData:dir_cust_company_city";
break;
case "ResellerModel": cityfield = "ResellerCompanyData:city";
break;
}
println "CITYFIELD is now " + cityfield
def utype1 = mcont.getDefinition().getType()
def utype2 = mcont.definition.type
println "UTYPE1 is now " + utype1
println "UTYPE2 is now " + utype2
def company = mcont
if (utype2 == UnitDefinitionType.CONTACT) {
company = mcont.get("company()")
}
def mycity = company.get(cityfield)
println " CITY is now " + mycity
Code example 44: Admin Tool script (called from workflow) for displaying customer data
For the following data set the log file output is shown below. The Reseller model of the figure above is used.
Figure 134: ConSol CM Web Client - Customer data set
Figure 135: Log file - Script output FlexCDM
String firstName = company.get("responsibleConsultants[0].firstName");
Code example 45: Retrieving a value from a list of structs using index notation
The set and add methods work as described for ticket Custom Fields. For example:
//set number field
company.set("numberOfEmployees", 1);
//add 1 to field value, afterwards the value of the field is 2
company.add("numberOfEmployees", 1);
Code example 46: Set and add values for a Data Object Group Field of type integer
company.set("responsibleConsultants", [
new Struct().set("lastName", "Miller").set("email", "miller@consol.com"),
new Struct().set("lastName", "Smith").set("email", "smith@consol.com"),
new Struct().set("lastName", "Burger").set("email", "burger@consol.com")
]);
Code example 47: Creating a new list of structs, version 2
company.add("responsibleConsultants", new Struct().set("lastName", " Nowitzki ").set("email", "dnowitzki@consol.us"));
Code example 48: Adding a new line in a list of structs for company data
company.set("responsibleConsultants[0].firstName", "John");
Code example 49: Setting a value in a list of structs using index notation
company.set("responsibleConsultants[last]", null);
Code example 50: Removing a struct (= line) from a list of structs (= table)
Unit mainContact = ticket.getMainContact();
// "company" extension returns company for contact
Unit company = mainContact.get("company()");
// it is also possible to set company using "company" extension
mainContact.set("company()", company);
// "contacts" extension returns list of contacts for company
List contacts = company.get("contacts()");
// "tickets" extension returns list of tickets for contact or company
List tickets = company.get("tickets()");
tickets = mainContact.get("tickets()");
// extensions can be chained
Integer count = contact.get("company().contacts()[0].tickets()[count]");
// parentheses can be omitted, but it is not recommended (possible collision with name of group or field)
count = contact.get("company.contacts[0].tickets[count]"); // here "company" is not extension but name of field
Code example 51: Convenience methods for access to customer data
In CM version 6.10 and higher, as in version 6.9, the customer Data Object Groups are part of the customer data model (FlexCDM). They are defined in the Admin Tool, navigation group Customers, navigation item Data Models.
Figure 136: ConSol CM Admin Tool - Data Object Group Field administration for customer data (CM version 6.10)
Everything you have learned about Data Object Groups Fields in version 6.9 also applies to CM version 6.10. But some methods have become deprecated!
In CM version 6.9, it is still possible to use Unit methods which do not include the Data Object Group name as parameter, e.g.,
Unit.getField(String pFieldName)
This only works smoothly when a Data Object Group Field has the same name over all customer groups where the script is applied, or when the surrounding code ensures that it is not used in ambiguous runtime situations. In Version 6.10, the Unit methods without Data Object Group name have become deprecated, and they will no longer be supported in version 6.11 and up. The following table lists all those methods:
CM versions up to 6.9, deprecated in 6.10, not in 6.11 | CM version 6.10 and up |
---|---|
getField(String pFieldName) | getField(String pGroupName, String pFieldName) |
getFieldValue(String pFieldName) | getFieldValue(String pGroupName, String pFieldName) |
setFieldValue(String pFieldName, Object pFieldValue) | setFieldValue(String pGroupName, String pFieldName, Object pValue) |
removeField(String pFieldName) | removeField(String pGroupName, String pFieldName) |
Starting with version 6.10.0, ConSol CM can contain the optional module CM.Resource Pool. This module allows it to extends the CM database and store resource objects. This can be various objects like IT assets, contracts, shop items or whatever is required in the respective company. Similar to the Customer Data Model, the Resource Data Model is defined using the Admin Tool. In the navigation group Resources, navigation item Data Models, the model is defined. In order to be able to work with resource data in workflow scripts, you should first get a profound knowledge of the Resource Pool principle and the set-up of the data model, so please read the section about the CM.Resource Pool in the ConSol CM Administrator Manual first.
Similar to ticket and customer data, resource data is stored in Resource Field Groups which contain Resource Fields.
Figure 137: Admin Tool: Definition of the resource data model
To retrieve data from Resource Fields, you can use methods as the ones shown in the following examples.
// Display info about HP Printer, priting infos about resource fields into server.log
def my_resource_name = resource.get("HP_Printer_Fields_basic.name")
println 'Displaying resource information ...'
println ' Name is : ' + my_resource_name
def my_resource_inv_number = resource.get("HP_Printer_Fields_basic.inventory_number")
println ' Inventory number is : ' + my_resource_inv_number
Code example 52: Simple resource action script which displays information about the resource in the log file
Figure 138: Web Client: Resource page of a HP printer resource
Figure 139: Log output of the script for the printer shown in the GUI example
In the real world, the circumstances usually are more complex. Often it is required to retrieve all resources of a certain type which are linked by a certain type of relation to a ticket or to a resource. This topic is treated in detail in the section Working With Resource Relations.
More coding examples, taken from the ConSol CM Action Framework, are provided in the ConSol CM Administrator Manual, section Scripts for the Action Framework.
Sometimes it is necessary to work with variables which are not used as values for Custom Fields, Data Object Group Fields or Resource Fields, which are not visible on the GUI, but which are only used as containers for internal programming variables.
Those of you who know how to program ConSol CM5 workflows know those containers as global variables. In ConSol CM6, you can achieve the same goal by creating regular Custom Fields (for ticket data), Data Object Group Fields (for customer data) or Resource Fields (for resource data) with the required data type and setting the field to invisible. This has to be done by using the annotation visibility = none. You can even let the variable be visible during the development of the process and control the field's value. Then you can set it to invisible when the system is handed-over to QA and users.