How to use Ticket-based IT Experience with custom tables.

By default, feedback context data can be mapped from the incident and requested item tables. With some scripting, it is possible to map data beyond the predefined tables to HappySignals.

The overall process for collecting feedback for any ServiceNow processes is two-fold:
1) sending the data to HappySignals and
2) getting data back to ServiceNow with the HappySignals API
Sending the data to HappySignals is fairly simple, but requires a bit of scripting to get the correct data from your desired table. The second part process is a bit more complicated, it requires customisation of the HappySignals application in ServiceNow and the level of customisation required depends on the available fields on the table.

An important thing to note is that the table you want to map ideally should extend the “Task” table in ServiceNow. Although, it is technically possible also to map tables that do not extend “Task”, this requires more customisation to the application. 

Sending data to HappySignals

Create a HappyCustomConfig script include

The first thing you need to do is to create a new script include in the Global application scope with the following details:
Field
Value
Name
HappyCustomConfig
API name
global.HappyCustomConfig
Client callable
false
Application
Global
Accessible from
All application scopes
Active
true
Description
[optional]
The HappyCustomConfig script include is used for generating a configuration object that contains the data that will be passed to HappySignals. The HappyCustomConfig can be used to create data mapping for custom tables or be used for script-based data fetching for the default tables. The example script below can be used as a starting point for making your custom table mappings.
var HappyCustomConfig = Class.create();
HappyCustomConfig.prototype = {
    initialize: function () {
        var currentTimeMS = new GlideDateTime().getNumericValue();
        this.datestamp = new Date(currentTimeMS).toISOString();
    },

    /**
     * Configure function can override existing data mappings or  define mappings for tables not supported by the default configuration logic.
     * @param {GlideRecord} obj GlideRecord object that triggered response link creation
     * @param {JSON object} conf object that contains configurations made in HappyLinkCreator
     * @param {string} tableName name of the table where the GlideRecord object originated
     * @returns modified configuration object
     */
    Configure: function (obj, conf, tableName) {

        /* Available keys on base object described below
        Below keys correspond to specific fields on HappySignals cloud
        // MANDATORY DETAILS
        conf.esm = 'IT'; // top level categorization for the response eg. IT, HR, Security
        conf.ticket_type = ''; // type of ticket eg. Request, Incident etc.
        conf.category = ''; // survey form key, consult with HappySignals
        conf.ticket_number = ''; // ticket number or other identifier
        conf.opened_at = ''; // time when the ticket was opened
        conf.datestamp = ''; // time for the survey delivery, should be tied to datetime field on the ticket
        conf.language = ''; // language code eg. en, fr, es etc.

        // BENCHMARK DETAILS
        conf.contact_type = '';
        conf.country = '';

        // END USER DETAILS
        conf.employment_started_at = '';
        conf.endUserId = ''; // email address of the end-user

        // OTHER DETAILS
        conf.reassign = '';
        conf.assignment_group = '';
        conf.priority = '';
        conf.location = '';
        conf.company = '';
        conf.ci = '';
        conf.service = '';
        conf.secondary_category = '';
        conf.tertiary_category = '';
        conf.region = '';
        conf.vendor = '';
        conf.business_stc = '';
        conf.time_worked = '';
        conf.made_sla = '';
        conf.source_object = '';
        conf.source_id = '';
        */

        // short example of mapping interaction table fields
        switch (tableName) {
            case 'interaction':
                conf.esm = "IT";
                conf.ticket_type = "Interaction";
                conf.category = "other";
                conf.ticket_number = this.__getFieldValue(obj, 'number');
                conf.language = this.__getFieldValue(obj, 'opened_for.preferred_language');
                conf.datestamp = this.__getFieldValue(obj, 'closed_at', 'time');

                conf.contact_type = this.__getFieldValue(obj, 'type');
                conf.country = this.__getFieldValue(obj, 'opened_for.location.country');

                conf.assignment_group = this.__getFieldValue(obj, 'assignment_group');
                break;
        }

        return conf; // return the configuration object back to HappyLinkCreator to generate the response link
    },

    /**
     * Gets field values and returns them in a format expected by HappySignals
     * @param {glideRecordObject} record gliderecord of the object where the field value is retrieved
     * @param {string} field field name where the data is retrieved, supports dot-walking to reference fields
     * @param {string} returnType in what type the value is returned, options sys_id, value, time, displayValue
     * @returns return value from the given field
     */
    __getFieldValue: function (record, field, returnType) {

        returnType = returnType || 'displayValue'; // set default return type as displayValue if defining argument is not provided
        var returnValue = '', //set default return value
            elem = record.getElement(field); // get the possibly dot-walked element

        if (!gs.nil(elem) && !gs.nil(elem.toString())) {
            try {
                switch (returnType) {
                    case 'sys_id':
                        returnValue = elem.sys_id.toString();
                        break;
                    case 'value':
                        returnValue = elem.toString();
                        break;
                    case 'time':
                        var timeInMS = new GlideDateTime(elem.toString()).getNumericValue();
                        returnValue = new Date(timeInMS).toISOString(); // time fields need to be formatted to ISO8061 format
                        break;
                    default:
                        returnValue = elem.getDisplayValue();
                }
            } catch (e) {
                gs.info("HappyCustomConfig: mapping for field ({0}) unsuccessfull due to error: {1}", field, e.message);
                return ''; // failsafe to prevent other field processing from stopping
            }
            if (returnValue == undefined || returnValue == null) {
                returnValue = '';
            }
        }
        return returnValue;
    },

    type: 'HappyCustomConfig'
};

 

Create a notification for your custom table
Once you have created the HappyCustomConfig script include then you need to add the HappySignals voting buttons to the email notifications for your custom table. The notifications determine when and who will receive the HappySignals feedback survey. 
 
To add the HappySignals voting buttons to your notifications simply add the following mail script to them:
${mail_script:happysignals_vote}
Note that the feedback survey that is shown to the recipient after they click one of the voting buttons is the same as in the case of a general request.

Getting the feedback data back to ServiceNow from HappySignals

This guide below applies to application versions 1.5.0 and higher. For lower versions consider updating your application to the latest version.

The second part of the process is to get the feedback data related to your custom table back to ServiceNow.
This consists of two parts, modifying "HappyConstants" script include so that fields on HappySignals feedback table are filled correctly and displaying data in HappySignals Agent Widgets.
If you are measuring non-IT tickets, you need to add new values to a system property under the "General Properties" of the HappySignals application. The values in this property must include all the values you are using in your measuring cases.

Modify HappyConstants to configure the integration

HappyConstant is script include that is intended to be modified by customers and is your centralized place for various integration related configurations in the application.

 

Updating ticket state based on HappySignals Responses

In HappyConstants you can find a constant called "TICKET UPDATE RULES" that determines what happens to a ticket state when a survey response is received by ServiceNow.

Ticket state update rules are defined per table basis and there are default rulesets for incidents, requested items, requests and interactions.

/* TICKET UPDATE RULES */

HappyConstants.ENABLE_WORKNOTE = gs.getProperty('x_pgo_happysignals.enableWorknoteInsertion', 'false') == 'true' ? true : false;

/** HappyConstants.TICKET_STATE_RULES
 *  Used in "HappySignals Feedback inserted" - business rule
 *  Defines table based rules to updating record states when feedback record is created to ServiceNow.
 * */
HappyConstants.TICKET_STATE_RULES = {
    "incident": {
        "state_field": "incident_state",
        "allowed_states": gs.getProperty('x_pgo_happysignals.incident_statuses', "").split(','),
        "set_new_state": gs.getProperty('x_pgo_happysignals.closeIncident', 'false'),
        "new_state": "7"
    },
    "sc_req_item": {
        "state_field": "",
        "allowed_states": [],
        "set_new_state": false,
        "new_state": ""
    },
    "sc_request": {
        "state_field": "",
        "allowed_states": [],
        "set_new_state": false,
        "new_state": ""
    },
    'interaction': {
        "state_field": "",
        "allowed_states": [],
        "set_new_state": false,
        "new_state": ""
    }
};

/* TICKET UPDATE RULES END */

To update the state for a ticket in your custom table, you will need to add a new ruleset where the object key is the name of your custom table.

Within the ruleset you have four keys that determine what is the field name for state tracking, what are the states that allow updates to happen, whether a new state should be set or not and what is the new state for the ticket.

An example rule set for setting an HR case to "Closed Complete" based on a response can be found below.

'sn_hr_core_case': {
  "state_field": "state",
   "allowed_states": ["10"], // only "Ready" state allow update to occurr
   "set_new_state": true,
   "new_state": 3 // setting the state to "Close Complete"
    }

If a choice field with integers is used, the allowed_states array elements must still be formatted as string values due to how ServiceNow returns values for the comparison.


 

Response data enrichment in ServiceNow

Integration from HappySignals back to ServiceNow uses a transform map to enrich the response information with the latest details from the related ticket. This information contains details such as the agent resolving or closing the ticket, the associated assignment groups etc. 

The transform map consists of one "onBefore" transform script and multiple "Field Map" definitions, each containing rules for data enrichment. The data enrichment rules are defined in the HappyConstants script.

onBefore Transform Script constants

There are two constants that affect the transform script functionality:

INTEGRATION_TABLES

Defines the list of table names which are used to look up whether a particular ticket can be found in the ServiceNow instance. The integration uses "ticketId", usually the ticket number, returned from the API to make the lookup to. The first table where a match is found is used as the basis for later processing. 

/** HappyConstants.INTEGRATION_TABLES
 *  Used in  "HappySignals Feedback Import" -transform map onBefore script
 *  List of table names that are used to look for records related to feedbacks.
 * */
HappyConstants.INTEGRATION_TABLES = ['incident', 'sc_req_item', 'sc_request', 'interaction', 'sn_hr_core_case'];

Lookups are made starting with the first element in the array and stopped once the first match is found. So if you have core tables like "task" or "sn_hr_core_case" in beginning of the array, then these are used instead of potential child tables where the ticket could also be found like "incident" or "sn_hr_core_case_workforce_admin" etc. 

LOG_RESPONSE_IMPORTS 

Defines if all successful record imports are logged to ServiceNow "System Logs". You should only enable this when troubleshooting issues with the integration.

/** HappyConstants.LOG_RESPONSE_IMPORTS
 *  Used in  "HappySignals Feedback Import" -transform map onBefore script
*  If true logs every succesfull response report import
* */
HappyConstants.LOG_RESPONSE_IMPORTS = false; 

 

Field Map constants

There are six constants that affect field map functionalities listed below. Each rule set is defined as table-specific and rules are applied based on the look-up result from the constant INTEGRATION_TABLES. 

There are two types of rule sets, reference field population and GlideList population.

  • Reference fields pick the first field value that is found while going through an array of field names.
  • GlideList population collects field values from multiple different fields and can also look up fields from other associated records.

RELATED_USER_RULES

These rules define who is determined as the Survey Responder. Your resolution/closure email containing HappySignals rating scale should only be delivered to one person associated with the ticket and this rule should follow that definition. 

/** HappyConstants.RELATED_USER_RULES
 *  Used in "HappySignals Feedback Import" - transform map
 *  Defines table based rules for populating related_user (Survey Responder) field in HappySignals Feedbacks table.
*  Gets single value from first match on field array.
 * */
HappyConstants.RELATED_USER_RULES = {
    'incident': ['caller_id'],
    'sc_req_item': ['request.requested_for'],
    'sc_request': ['requested_for'],
    'interaction': ['opened_for']
};

RESOLVED_BY_USER_RULES

These rules define who is determined as the person resolving or closing the ticket. See an example below for "sc_req_item" picking up a fallback value if the first defined field doesn't hold a value.

/** HappyConstants.RESOLVED_BY_USER_RULES
 *  Used in "HappySignals Feedback Import" - transform map
 *  Defines table based rules for populating resolved_by_user (Resolved by User) field in HappySignals Feedbacks table.
 *     Gets single value from first match on field array.
 * */
HappyConstants.RESOLVED_BY_USER_RULES = {
    'incident': ['resolved_by'],
    'sc_req_item': ['assigned_to', 'request.assigned_to'],
    'sc_request': ['assigned_to'],
    'interaction': ['assigned_to']
};

CLOSING_ASSIGNMENT_GROUP_RULES

These rules define who is determined as the assignment group resolving or closing the ticket. See an example below for "sc_req_item" picking up a fallback value if the first defined doesn't hold a value.

/** HappyConstants.CLOSING_ASSIGNMENT_GROUP_RULES
 *  Used in "HappySignals Feedback Import" - transform map
 *  Defines table based rules for populating closing_assignment_group (Closing Assignment Group) field in HappySignals Feedbacks table.
 *     Gets single value from first match on field array.
 * */
HappyConstants.CLOSING_ASSIGNMENT_GROUP_RULES = {
    'incident': ['assignment_group'],
    'sc_req_item': ['assignment_group', 'request.assignment_group'],
    'sc_request': ['assignment_group'],
    'interaction': ['assignment_group']
};

RELATED_USERS_RULES

These rules define who are determined as the agents related to the ticket. Users listed here will have access to the response record in ServiceNow.  Multiple users can be collected directly from the ticket and also associated records in other tables.

For example, related agents for Requests are collected from all requested items where the "Request" is referenced and from all tasks where the requested items are referenced as the task parent.

'sc_request': {
        'fields': [],
        'linkedRecords': {
            'sc_req_item': {
                'fields': ['assigned_to', 'closed_by'],
                'referenceField': 'request',
                'linkedRecords': {
                    'task': {
                        'fields': ['assigned_to', 'closed_by'],
                        'referenceField': 'parent'
                    }
                }
            }
        }
    }

Default definitions:

/** HappyConstants.RELATED_USERS_RULES
 *  Used in "HappySignals Feedback Import" - transform map
 *  Defines table based rules for populating related_users (Related Agents) field in HappySignals Feedbacks table.
*   Gets multiple values from all matching fields on main record and linked records. Supports recursive structure on linkedRecords.
 * */
HappyConstants.RELATED_USERS_RULES = {
    'incident': {
        'fields': ['assigned_to', 'closed_by', 'resolved_by'],
        'linkedRecords': {
            'task': {
                'fields': ['assigned_to', 'closed_by'],
                'referenceField': 'parent'
            }
        }
    },
    'sc_req_item': {
        'fields': ['assigned_to', 'closed_by'],
        'linkedRecords': {
            'task': {
                'fields': ['assigned_to', 'closed_by'],
                'referenceField': 'parent'
            }
        }
    },
    'sc_request': {
        'fields': [],
        'linkedRecords': {
            'sc_req_item': {
                'fields': ['assigned_to', 'closed_by'],
                'referenceField': 'request',
                'linkedRecords': {
                    'task': {
                        'fields': ['assigned_to', 'closed_by'],
                        'referenceField': 'parent'
                    }
                }
            }
        }
    },
    'interaction': {
        'fields': ['assigned_to']
    }
};

RELATED_ASSIGNMENT_GROUPS_RULES

These rules define what are determined as the assignment groups related to the ticket. Multiple groups can be collected directly from the ticket and also associated records in other tables.

For example, related assignment groups for Requests are collected from all requested items where the parent "Request" is referenced and from all tasks where any of the requested items are referenced as the task parent.

/** HappyConstants.RELATED_ASSIGNMENT_GROUPS_RULES
 *  Used in "HappySignals Feedback Import" - transform map
 *  Defines table based rules for populating related_assignment_groups (Related Assignment Groups) field in HappySignals Feedbacks table.
 *     Gets multiple values from all matching fields on main record and linked records. Supports recursive structure on linkedRecords.
 * */
HappyConstants.RELATED_ASSIGNMENT_GROUPS_RULES = {
    'incident': {
        'fields': ['assignment_group'],
        'linkedRecords': {
            'task': {
                'fields': ['assignment_group'],
                'referenceField': 'parent'
            }
        }
    },
    'sc_req_item': {
        'fields': ['assignment_group'],
        'linkedRecords': {
            'task': {
                'fields': ['assignment_group'],
                'referenceField': 'parent'
            }
        }
    },
    'sc_request': {
        'fields': ['assignment_group'],
        'linkedRecords': {
            'sc_req_item': {
                'fields': ['assignment_group'],
                'referenceField': 'request',
                'linkedRecords': {
                    'task': {
                        'fields': ['assignment_group'],
                        'referenceField': 'parent'
                    }
                }
            }
        }
    },
    'interaction': {
        'fields':['assignment_group']
    }
};

 

Showing feedbacks on HappySignals widgets

All feedbacks are displayed in the HappySignals widgets regardless of the table where the related ticket resides. 

However you can define table-specific rules for what data is displayed for the responses. To display table-specific fields, you will need to create a new view for the "HappySignals Feedback" record form that determines which fields will be visible on the Agent Feedback widget.

The application comes with four OOB views for Incidents, Requested Items, Request and a default view for any other tables.

To create a new view follow the steps below:

  1. Navigate to the HappySignals Feedback table and open any record.
  2. Right-click over the "Form Header" to bring up the context menu.
  3. In the context menu, navigate to "Configure > Form Layout"
  4. In the layout editor, open the "View Name" dropdown and select the option for "New..."

  5. Name your new view as "agent_widget_your_custom_table_name", for example "agent_widget_sn_hr_core_case" and click "OK"
  6. Select the fields that you want to show in the widget and save your changes once ready

You can change the display title of your view by navigating to table "sys_ui_view" and updating the "Title" field to be something more user friendly.