Working with Data Fields

Introduction to Data Fields

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.

There are three types of data fields:  

Rules for work with data fields

When you work with ticket fields, customer fields or resource fields, there are two main rules you have to keep in mind:

  1. All data fields are always managed and referenced in data field groups, e.g. when you want to retrieve the value of a ticket field, you use e.g., <ticket field group name>.<ticket field name>
  2. You always use the technical unique name to reference a data field group or a data field, not the localized value!

Data Types for 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 ticket fields, customer fields and resource fields.

The data type you choose on creating a data field cannot be changed afterwards!

Details about String Fields: Use Annotations to Fine-Tune Strings

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.

How can I ...

... insert a text box instead of a single line?

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.

... hide the input of the fields for passwords?

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.

... display a hyperlink, display the name instead of the link?

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"

... display a file link?

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:

See also the explanation about file-url in the section text-type

... define a label?

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. Please take a look at the annotations for labels (show-label-in-edit, show-label-in-view) before implementing special label fields!

... define a field for the valid email addresses?

Value for annotation email: true

The field may only contain valid email addresses. Input will be validated according to standard email format <name>@<domain>.

... define a scripted autocomplete list? 

Value for the annotation text-typeautocomplete

Optional: value for the annotation autocomplete-script = <name of the respective script>

A scripted autocomplete list is used to provide a drop-down menu which is filled dynamically using the input the engineer has provided so far. For example, when the user types "Mil", the possible values "Miller", "Milberg", and "Milhouse" are displayed as list and the engineer can select the one required for the field. You know this behavior from other autocomplete fields, e.g., the search for engineers for a ticket or the search for customers while creating a ticket. However, in these cases, CM generates the list automatically. The behavior cannot be influenced or customized. Scripted autocomplete lists, on the contrary, can be implemented by the CM administrator. The values are based on a result set which is dynamically created. The result set can contain strings, engineers, customers (Units), and resources.

A detailed description of scripted autocomplete lists is provided in section Scripted Autocomplete Lists in the Administrator Manual.

... define a field for the CM/Track login?

Value for annotation username: true

Will be used for authentication against CM/Track server. Only for customer fields in a contact object.

... define a field for the CM/Track password?

Value for annotation password: true

Will be used for authentication against CM/Track server (in DATABASE mode). Only for customer fields in a contact object.

... define a field containing personal data?

Value for annotation personal-data: true

This annotation can be assigned to ticket and contact fields. Contact fields with this annotation will be deleted when a contact is anonymized. Ticket fields with this annotation will be deleted when the main customer of the ticket is anonymized.

When defining a field to contain personal data, please take into account that the deletion of the field during the anonymization process is treated as a regular update. Therefore, business event triggers reacting on changes to ticket fields fire, and the contact update action script is executed.

This might lead to unwanted side-effects.

Data Fields for Ticket Data: Ticket Fields

In the Admin Tool, the ticket fields are defined in the navigation group Tickets, navigation item Ticket Fields.

Figure 132: ConSol CM Admin Tool - Ticket field administration for ticket data (CM version 6.10)

Most Important Methods for Access to Ticket Fields

Three methods are of major importance for programming ticket field 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:

Retrieve Ticket Field Values

To retrieve data from a ticket field in a script, you have to reference it by using the technical names of the ticket field group and of the ticket field. The method which has to be used can vary depending on the data type of the ticket field.

Simple Data Types

The following examples refer to the ticket fields in the figure above. The method which should to be used (because it is the most convenient way) is:

ticket.get("<ticketFieldGroupName>.<ticketFieldName>")

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 example for 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

log.info 'Display enum from helpdesk CF group ... '

 

def myfield = ticket.get("helpdesk_standard.priority")

log.info 'Class of helpdesk_standard.priority field is ' + myfield.getClass()

log.info 'Value of helpdesk_standard.priority field is ' + myfield.getName()

log.info 'Retrieve value directly, method 1, using getter method ... '

 

def my_new_field1 = ticket.get("helpdesk_standard.priority").getName()

log.info 'Result is ' + my_new_field1

log.info 'Retrieve value directly, method 2, using direct access to attribute ... '

 

def my_new_field2 = ticket.get("helpdesk_standard.priority").name

log.info 'Result is ' + my_new_field2

log.info 'Display value of simple data field ...'

 

def fb = ticket.get("helpdesk_standard.feedback")

log.info 'Value of feedback boolean field is ' + fb

Code example 28: Admin Tool script used to display ticket fields

The following output will be displayed in the server.log file: 

Explanation:

If you want to retrieve the value of a ticket field which contains an object (e.g., an EnumValue), you have to use methods like getName() to retrieve the actual value, because 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 29: Precondition script where boolean value is checked

Or shorter:

return ticket.get("am_fields.vip")

Code example 30: Precondition script where boolean value is checked, short version

Enum Values

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")

log.info 'Priority is now ' + prio.getName()

//or shorter:

log.info 'Priority is now ' + prio.name

Code example 31: Retrieving an enum value for a ticket field

MLAs

Work with One MLA Value (the Selected "Leaf" of the MLA Tree)

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 133: ConSol CM Admin Tool - Definition of a ticket field of type MLA

Figure 134: ConSol CM Admin Tool - MLA definition

Figure 135: ConSol CM 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

 

log.info 'Displaying MLA value ...'

def my_mla_field = ticket.get("helpdesk_standard.categories")

log.info '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())

log.info 'MLA value categories (localized name) is now ' + my_mla_field_localized

Code example 32: Code (Workflow or Admin Tool script) for displaying MLA data

Figure 136: Log output for the example above

Work with the Entire Branch of the Selected MLA Value

If you need to retrieve the entire path to the selected MLA value, you can proceed as follows: 

log.info 'Displaying MLA branch ...'

List<EnumValue> mlaPathElements = mlaService.getAssignedMla(ticket, "helpdesk_standard", "categories")

def mlaPath1=""

mlaPathElements.each() {elem ->

mlaPath1 = elem.name + ' -- ' + mlaPath1

}

log.info 'mlaPath1 is now ' + mlaPath1

 

//or shorter:

def mlaPath2 = mlaService.getAssignedMla(ticket, "helpdesk_standard", "categories").reverse()*.name.join(" -- ")

log.info 'mlaPath2 is now ' + mlaPath2

Code example 33: Retrieving the entire path to the selected MLA value

Figure 137: Log output for the example above

Lists

Lists of Simple Data Types

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 ticket field of type date has to have the parameter Belongs to which points to the list.

Figure 138: ConSol CM Admin Tool - Ticket fields for a list of date fields

Figure 139: ConSol CM Web Client - List of date fields in a ticket (edit mode)

For access to each date ticket field within a list use the following lines of code:

def convs = ticket.get("conversation_data.conversation_list").each() { conv ->

log.info "NEXT DATE is :" + conv

log.info "CLASS of NEXT DATE is " + conv.getClass()

}

Code example 34: Displaying the content of a list of date objects

Figure 140: 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 35: Retrieve a certain value from a list of simple data types

Lists of Structs (Tables)

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 data 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 141: ConSol CM Admin Tool - ticket fields for a multi-column list (= table)

Figure 142: ConSol CM Web Client - Ticket with filled-in table

def structs = ticket.get("order_data.orders_list").each() { str ->

log.info("CLASS of LINE is " + str.getClass())

log.info("FIELD VALUE HARDWARE is " + str.orders_hardware.getName())

log.info("CLASS of FIELD VALUE HARDWARE is " + str.orders_hardware.getName().getClass())

log.info("FIELD VALUE CONTACT is " + str.orders_contact)

log.info("CLASS of FIELD VALUE CONTACT is " + str.orders_contact.getClass())

log.info("FIELD VALUE NUMBER is " + str.orders_number)

log.info("CLASS of FIELD VALUE NUMBER is " + str.orders_number.getClass())

}

Code example 36: Retrieve data from a list of structs

Figure 143: Log File - Script output

Setting Ticket Field Values

To set values for ticket fields, you follow the same principle as for getting data: use the ticket field group name and the technical name of the ticket field 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("<ticketFieldGroupName>.<ticketFieldName>", <value>)

Setting Values for Ticket Fields with Simple Data Types

ticket.set("fields.reaction_time", new Date());

Code example 37: Set a ticket field value for a field of type Date

When you work with number or date fields, you can even calculate with the ticket field 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 38: Calculate with the value of a ticket field of type date

Setting a value to null (i.e. emptying the field) is the same as removing the value:

ticket.set("fields.numberOfEmployees", null)

Code example 39: Setting a ticket field value to null

Or shorter:

ticket.remove("fields.numberOfEmployees" )

Code example 40: Setting a ticket field value to null via removing the value

Setting Enum Values

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 ticket field.

ticket.set("ticketFieldGroupName.ticketFieldName",<technical name of value>)

ticket.set("fields.priority", "URGENT");

Code example 41: Setting an enum value

Setting List Values

Setting Values in Lists of Simple Data Types

When you want to add a line, you can simply use the add method:

ticket.add("fields.tags", "my new String")

Code example 42: 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 43: Setting a value in a list of strings

Setting Values in Lists of Structs

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 44: Adding a new line in a list of structs

Fading in and out of Ticket Field Groups

A ticket field group can be faded in (made visible) and faded out (made invisible) using a workflowApi method. This works for ticket field groups which are displayed in the main ticket data section as well as for ticket field groups which are displayed in the tabbed (Details) section.

A typical use case is a ticket field group which is invisible at first (ticket field group annotation group-visibility = false) and is faded in when the engineer needs to work with the data in the process. For example, a ticket field 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 45: Fade in a ticket field group

To fade out some ticket field groups, e.g. when the ticket has been qualified and some of the ticket field 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 46: Fade out ticket field groups

Data Fields for Customer Data: Customer Fields

The customer data model (FlexCDM) contains customer field groups and customer field. They are both defined in the Admin Tool, navigation group Customers, navigation item Data Models.

Figure 144: ConSol CM Admin Tool - Customer field administration for customer data (CM version 6.10)

Most Important Methods for Accessing to Customer Data

Three methods are of major importance for programming access to customer fields in ConSol CM scripts. They all are methods of the class Unit.

For retrieving data from a customer field: 

Unit.get()

For setting data in an already existing customer field:

Unit.set()

For calculating with a value within a customer field, e.g., to add a certain time range to a date field and for adding a new line in list fields (simple lists and tables).

Unit.add()

Another method might be used when a field should be emptied, i.e. when its value should be set to null:

Unit.remove() // Sets the value of the field to null.

Retrieving Values for Customer Data

Because the name of a customer field might appear in more than one customer field group, the name of the customer field group has to be provided when accessing the customer data. For example, in the customer data model shown in the figure above, the customer field groups ResellerCompanyData and DirCustCompanyData could have a customer 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 47: Retrieving a field value for a company

Methods to access the values of customer fields:

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 145: 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.ticket

def mcont = ticket.mainContact

log.info "CustomerGroup of main contact is now " + mcont.customerGroup.name

def custmod = mcont.customerDefinition.name

log.info "Customer definition of main contact is now " + custmod

log.info "UnitDefinition of main contact is now " + mcont.definition.name

 

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;

default: cityfield = null;

break

}

 

log.info "CITYFIELD is now " + cityfield

 

def utype1 = mcont.getDefinition().getType()

def utype2 = mcont.definition.type

 

log.info "UTYPE1 is now " + utype1

log.info "UTYPE2 is now " + utype2

 

def company = mcont

if (utype2 == UnitDefinitionType.CONTACT) {

company = mcont.get("company()")

}

 

def mycity = company.get(cityfield)

log.info " CITY is now " + mycity

Code example 48: 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 146: ConSol CM Web Client - Customer data

Figure 147: Log file - Script output FlexCDM

Setting Values for Customer Fields

Setting Values for Customer Fields with Simple Data Types

The set and add methods work as described for ticket fields. For example:

//set a string field

unit.set("ResellerCompanyData:service_status","ok")

//set number field

company.set("ResellerCompanyData:numberOfEmployees", 1);

//add 1 to field value, afterwards the value of the field is 2

company.add("numberOfEmployees", 1);

Code example 49: Set and add values for a customer field of type integer and set a value for a customer field of type string

Lists

Setting Values in a List of Structs for Customer Data

company.set("consultantsFields: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 50: Creating a new list of structs, version 2

company.add("consultantsFields:responsibleConsultants", new Struct().set("lastName", " Nowitzki ").set("email", "dnowitzki@consol.us"));

Code example 51: Adding a new line in a list of structs for company data

company.set("consultantsFields:responsibleConsultants[0].firstName", "John");

Code example 52: Setting a value in a list of structs using index notation

company.set("consultantsFields:responsibleConsultants[last]", null);

Code example 53: Removing a struct (= line) from a list of structs (= table)

Convenience Methods for Access to Customer Data

Unit mainContact = ticket.mainContact

 

// "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 54: Convenience methods for access to customer data

Resource Data

Starting with version 6.10.0, ConSol CM can contain the optional module CM/Resource Pool. This module allows it to extend 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 setup 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 148: ConSol CM 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, printing infos about resource fields into server.log

 

def my_resource_name = resource.get("HP_Printer_Fields_basic.name")

log.info 'Displaying resource information ...'

log.info ' Name is : ' + my_resource_name

 

def my_resource_inv_number = resource.get("HP_Printer_Fields_basic.inventory_number")

log.info ' Inventory number is : ' + my_resource_inv_number

Code example 55: Simple resource action script which displays information about the resource in the log file

Figure 149: ConSol CM Web Client - Resource page of a HP printer resource

Figure 150: 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.

Fading in and out of Resource Field Groups

A resource field group can be faded in (made visible) and faded out (made invisible) using a workflowApi method. This works for resource field groups which are displayed in the main resource page data section as well as for resource field groups which are displayed in the tabbed (Details) section.

In the following example, the resource HP_Printers contains a resource field group with a list of tickets. Each maintenance ticket which is created for the resource using a resource action (see ConSol CM Administrator Manual for a detailed explanation of resource actions) should be entered in the list. Initially, the resource field group is configured as invisible (group annotation group-visibility = false). Only when the action has been performed, the resource field group should be made visible on the resource page.

The code which is shown is an excerpt taken from the resource action script, but the same or similar code can be used in workflow scripts.

// set ticket number in list in resource, newtic is the newly created maintenance ticket

def newtic_id = newtic.id.toString()

def newtic_name = newtic.name

 

//resource is the HP printer from which the action script is started

resource.add("HP_Printer_MaintenanceTickets.MaintenanceTicketsList",new Struct().set("MaintenanceTicketID", newtic_id)

.set("MaintenanceTicketName", newtic_name)

)

if (!executionContext) {

return actionScriptResultFactory.getPostAction(PostActionType.FAILURE, "action.fail.wrong.activity")

}

// if ticktes are in the list in the resource, the field group should be visible

def groupName = "HP_Printer_MaintenanceTickets"

def fieldGroupDefinition = fieldDefinitionService.getGroupByName(groupName)

if (fieldGroupDefinition == null) {

throw new IllegalArgumentException("There is no group definition with name '" + groupName + "'.")

}

resource.getGroupsConfiguration().setProperty(fieldGroupDefinition, GroupPropertyType.VISIBLE, "true")

Code example 56: Excerpt from a script which adds a line to a list of tickets on a resource page and makes the resource field group which contains the list visible

Using Data Fields for (Invisible) Variables

Sometimes it is necessary to work with variables which are not used as values for ticket fields, customer fields or resource fields, which are not visible on the GUI, but which are only used as containers for internal programming variables.

The values of these data fields represent global variables. You implement global variables by creating regular ticket fields, customer fields or resource fields 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.