Feedback

  • Contents
 

Sample Interaction Connect scripts

Although Interaction Connect and Scripter .NET provide similar functionality, Interaction Connect uses JavaScript promises to execute tasks asynchronously, while Scripter .NET follows a synchronous programming model. This article contains downloadable sample scripts that show how to carry out custom scripting tasks for Interaction Connect in a way that works with Scripter .NET’s synchronous behavior.

It’s important to keep this difference between synchronous and asynchronous programming in mind when you’re creating scripts for Interaction Connect, so you can avoid potentially undesirable side effects. Consider the code below, which sends a disposition request at the end of a call and attempts to set the agent back to “Available” status.

{code:java}
function callComplete(disposition) {
    // Assign the disposition to the action.
    IS_Action_CallComplete.wrapupcode = disposition;
    // Send the call disposition.     IS_Action_CallComplete.click();
    // Set the agent back to Available.     IS_Action_ClientStatus = "Available";     IS_Action_ClientStatus.click(); } {code}

If this code is run in Scripter .NET, each action is executed consecutively. The disposition request is sent and execution halts until the disposition request has completed. Once the disposition request has completed, code execution continues with the next action.

But if you run this script in Interaction Connect, execution continues immediately after the disposition request is sent. Because of this, the client status request is sent regardless of the outcome of the disposition request. This asynchronous behavior can lead to undesirable outcomes. Consider what happens if the initial disposition request fails and the client status request succeeds: the agent is “Available,” but Dialer is waiting for them to send a disposition for the call on their queue.

To avoid these issues, you can add callbacks to each action and to each scripter object method. If you do this, the actions and object methods will be executed synchronously. Here’s an improved version of the above sample code:

{code:java}
function callComplete(disposition) {
    // Assign the disposition to the action.
    IS_Action_CallComplete.wrapupcode = disposition;
    // Assign a callback to be executed when the action completes.     IS_Action_CallComplete.callback = function (error) {         if (error) {             /* The call disposition failed. Do not set the agent back to Available. Instead,             log an error and take steps necessary to alert the agent to try again. */             IS_Action_Trace.message = "The disposition failed.";             IS_Action_Trace.level = 0;             IS_Action_Trace.click();         } else {             // The call disposition was successful, set the agent back to Available.             IS_Action_ClientStatus = "Available";             IS_Action_ClientStatus.click();         }     }
    // Send the call disposition.     IS_Action_CallComplete.click(); } {code}

In this revised example, the callback function for the disposition request is only executed after the disposition has completed. If the disposition request is successful, no error is returned to the callback and the client status action is executed. This ensures that the agent does not become “Available” again until after the disposition completes successfully.

We’ve also added callbacks to each scripter object. Consider the following code snippet, which initializes a call object for the current dialer call, then attempts to disconnect the call:

{code:java}
// Create a call object.
var currentDialerCall = scripter.createCallObject();
// Initialize the call object by assigning the current dialer call id to the call object id. currentDialerCall.id = IS_Attr_CallId;
// Disconnect the call. currentDialerCall.disconnect(); {code}

When the call object’s id property is assigned, the client requests attributes for the specified interaction and initializes the call object once the appropriate information is returned. If this code is executed in Interaction Connect, the disconnect method can be executed before the call object has been initialized. You can prevent that from happening by using a new callback property (callObjectInitializedHandler) which allows execution to continue only after the call object has been initialized. Here’s a better version of this functionality:

{code:java}
// Create a call object.
var currentDialerCall = scripter.createCallObject();
// Assign a callback function to the callObjectInitializedHandler. currentDialerCall.callObjectInitializedHandler = function () {     currentDialerCall.disconnect(); }
// Initialize the call object by assigning the current dialer call id to the call object id. currentDialerCall.id = IS_Attr_CallId; {code}
By assigning a callback to the call object’s callObjectInitializedHandler property, the revised example ensures that the call object’s disconnect method is only called after this call object has been initialized.

Sample scripts

Source code is provided for the following sample scripts:
  • Example 3 is a multi-page custom script that demonstrates some of the key actions and events you can use when writing a custom script in Interaction Scripter.

These scripts use callback functions for every action that needs to  be executed in a specific order. Download  the source code.

Example 1

This script uses IS_Action_QueryContactList and IS_Action_ManualOutboundCall  actions to query the contact list and populate a table of records within  the custom script. An agent can click on records in the table to initiate  a manual outbound dialer call.

Example 1 source code

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Actions -->
    <meta name="IS_Action_CallComplete">
    <meta name="IS_Action_QueryContactList">
    <meta name="IS_Action_ClientStatus">
    <meta name="IS_Action_ManualOutboundCall">
    <meta name="IS_Action_Disconnect">
    <meta name="IS_Action_Trace">
    <!-- Attributes -->
    <meta name="IS_Attr_CampaignId">
    <!-- Enable the command toolbar -->
    <meta name="IS_CommandToolbar_Visible" content="true">
    <!-- Bootstrap is used for layout and design -->
    <link rel="stylesheet" href="./bootstrap/fonts+icons.css">
    <link rel="stylesheet" href="./bootstrap/bootstrap-material-design.min.css">
</head>
<body>
    <div class="row m-5">
    <div class="col-md-2">
        <h5>Dispositions</h5>
        <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Success')">Success</button>
        <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('No Answer')">No Answer</button>
        <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Busy')">Busy</button>
        <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Wrong Party')">Wrong Party</button>
        <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Do Not Dial')">Do Not Dial</button>
        <hr class="featurette-divider"/>
        <button type="button" class="btn btn-block btn-primary text-left m-0" onclick="queryContactList()">Refresh Table</button>
    </div>
    <div class="col-md-10">
        <table class="table table-striped table-hover" id="contactRecordsTable"></table>
    </div>
    </div>
    <!-- Load jquery and popper first as it is required by Bootstrap. -->
    <script src="./bootstrap/jquery-3.2.1.slim.min.js"></script>
    <script src="./bootstrap/popper.js"></script>
    <script src="./bootstrap/bootstrap-material-design.js"></script>
    <script type="text/javascript">
        // When the DOM is ready, initialize Bootstrap and query the contact list.
        $(document).ready(function () { $('body').bootstrapMaterialDesign(); setTimeout(function () { queryContactList(); }); });
        // The queryContactList function is called after the DOM is loaded initially,
        // or when the "Refresh Table" button is clicked.
        function queryContactList() {
            IS_Action_QueryContactList.displayName = "Example Table";
            IS_Action_QueryContactList.tableName = "EXAMPLETABLE";
            IS_Action_QueryContactList.connectionId = "{F028F7C3-089A-48D8-9DCC-C1A4CA53FB5D}";
            IS_Action_QueryContactList.statement = "select i3_identity, firstname, lastname, status, phonenumber from EXAMPLETABLE";
            /* Assign a callback which will be invoked after the action has been exectued.
            The response contains an error message indicating whether or not the query was
            successful. */
            IS_Action_QueryContactList.callback = function (response) {
                if (response.errorMessage === "") {
                    // The query was successful. Process the returned records and update
                    // the contact list table.
                    loadContactTable(response.records);
                } else {
                    // The query failed. Log an error message to the console.
                    IS_Action_Trace.message = "Failed to query the contact list.";
                    IS_Action_Trace.level = 0;
                    IS_Action_Trace.click();
                }
            }
            // Execute the action.
            IS_Action_QueryContactList.click();
        }
        /* The loadContactTable function builds an HTML string which is used to populate
        the returned records into the contact list table. The function is called whenever
        the IS_Action_QueryContactList action is successful. */
        function loadContactTable(records) {
            // Start by generating HTML for the table's headers.
            var contactTableHTML = "<thead><tr>";
            var tableHeaders = Object.keys(records[0].values);
            for (var i = 0; i < tableHeaders.length; i++) {
                contactTableHTML += "<th>" + tableHeaders[i] + "</th>";
            }
            contactTableHTML += "</tr></thead>";
            /* Next, loop through each record and generate HTML for the table body.
            Each record returned by the query will have its own row in the table.
            If a row is clicked, a manual outbound call is attempted on the corresponding
            record. */
            contactTableHTML += "<tbody style='cursor: pointer;'>";
            for (var i = 0; i < records.length; i++) {
                var contactIdentity = records[i].identity;
                var contactPhoneNumber = records[i].values.phonenumber;
                contactTableHTML += "<tr onclick='placeManualOutboundCall(\"" + contactIdentity + "\" , \"" + contactPhoneNumber + "\")'>";
                var tableValues = Object.values(records[i].values);
                for (var j = 0; j < tableValues.length; j++) {
                    contactTableHTML += "<td>" + tableValues[j] + "</td>";
                }
                contactTableHTML += "</tr>";
            }
            contactTableHTML += "</tbody>";
            // Populate the table with the generated HTML.
            document.getElementById("contactRecordsTable").innerHTML = contactTableHTML;
        }
        // The placeManualOtuboundCall function is called whenever a row in the contact
        // list table is clicked.
        function placeManualOutboundCall(identity, phoneNumber) {
            IS_Action_ManualOutboundCall.i3identity = identity;
            IS_Action_ManualOutboundCall.campaignid = "25A69636-DEE1-40E3-8FAF-EC92F0A6384F";
            IS_Action_ManualOutboundCall.contactcolumnid = "1";
            IS_Action_ManualOutboundCall.phonenumber = phoneNumber;
            // Initiate the manual outbound call.
            IS_Action_ManualOutboundCall.click();
        }
        function sendDisposition(disposition) {
            // Disconnect the call.
            IS_Action_Disconnect.click();
            IS_Action_CallComplete.wrapupcode = disposition;
            // Assign a callback to be invoked after the IS_Action_CallComplete action
            // has been executed.
            IS_Action_CallComplete.callback = function (error) {
                if (error) {
                    // The IS_Action_CallComplete action failed, log an error.
                    IS_Action_Trace.message = "The disposition failed.";
                    IS_Action_Trace.level = 0;
                    IS_Action_Trace.click();
                } else {
                    // The disposition was successful. Set the agent back to available.
                    IS_Action_ClientStatus.statuskey = "Available";
                    IS_Action_ClientStatus.click();
                }
            }
            // Execute the action.
            IS_Action_CallComplete.click();
        }
    </script>
</body>
</html>
		

Example 2

This script initiates a chat using the IS_Action_PlaceChat action. It  uses a chat object to send and receive chat messages.

Example 2 source code

<!doctype html>
<html lang="en">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- Actions -->
    <meta name="IS_Action_CallComplete">
    <meta name="IS_Action_ClientStatus">
    <meta name="IS_Action_PlaceChat">
    <meta name="IS_Action_Disconnect">
    <meta name="IS_Action_Trace">
    <!-- Enable the command toolbar -->
    <meta name="IS_CommandToolbar_Visible" content="true">
    <!-- Bootstrap is used for layout and design -->
    <link rel="stylesheet" href="./bootstrap/fonts+icons.css">
    <link rel="stylesheet" href="./bootstrap/bootstrap-material-design.min.css">
</head>
<body>
    <div class="row m-5">
        <div class="col-md-2">
            <h5>Dispositions</h5>
            <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Success')">Success</button>
            <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('No Answer')">No Answer</button>
            <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Busy')">Busy</button>
            <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Wrong Party')">Wrong Party</button>
            <button type="button" class="btn btn-block btn-secondary text-left m-0" onclick="sendDisposition('Do Not Dial')">Do Not Dial</button>
            <h5 class="mt-5">Place Chat</h5>
            <div class="pl-2">
                <input type="text" class="form-control mb-1" placeholder="User Name" id="userName" />
                <button type="button" class="btn btn-primary btn-block text-left" onclick="placeChat()">Place Chat</button>
            </div>
        </div>
        <div class="col-md-10">
            <div class="row" id="chatArea">
            </div>
        </div>
    </div>
    <!-- Load jquery and popper first as it is required by Bootstrap. -->
    <script src="./bootstrap/jquery-3.2.1.slim.min.js"></script>
    <script src="./bootstrap/popper.js"></script>
    <script src="./bootstrap/bootstrap-material-design.js"></script>
    <script type="text/javascript">
        // When the DOM is ready, initialize Bootstrap
        $(document).ready(function () { $('body').bootstrapMaterialDesign(); });
        // Keep track of the agent's chats
        var currentChats = [];
        function placeChat() {
            // Get the specified recipient from the input box
            IS_Action_PlaceChat.recipient = document.getElementById("userName").value;
            IS_Action_PlaceChat.callback = function(interactionId) {
                // Create a chat object and add it to the user's current chats
                currentChats[interactionId] = scripter.createChatObject();
                // Use the chatObjectInitializedHandler to assign a callback to be executed
                // whenever the chat object's messages have changed.
                currentChats[interactionId].chatObjectInitializedHandler = function(chatObject) {
                    currentChats[interactionId].SubObjectChangeHandler = chatMessagesChanged;
                    // Open a chat box within the script.
                    renderChatBox(currentChats[chatObject.id]);
                }
                currentChats[interactionId].id = interactionId;
            }
            IS_Action_PlaceChat.click();
        }
        function renderChatBox(chatObject) {
            // Build HTML for a chat box using a Bootstrap card and card-deck.
            var chatBoxHTML = "<div class='col-md-4 mt-3' id='" + chatObject.id + "'>";
            chatBoxHTML += "<div class='card-deck'>";
            chatBoxHTML += "<div class='card text-center'>";
            // Add a card header to indicate who the agent is chatting with.
            chatBoxHTML += "<div class='card-header'>";
            chatBoxHTML += "<h6 class='d-inline'>Chatting with " + chatObject.remoteName + "</h6>";
            chatBoxHTML += "<button type='button' class='close' onclick='closeChat(" + chatObject.id + ")' aria-label='Close'><span aria-hidden='true'>&times;</span></button>";
            chatBoxHTML += "</div>";
            // Add a body to the card which will contain the chat messages.
            chatBoxHTML += "<div class='card-body chatMessages' id='" + chatObject.id + "' style='overflow-y: scroll; height: 200px; padding: 1rem;'></div>";
            // Add a footer to the card with an input box and send button for the agent to
            // send messages.
            chatBoxHTML += "<div class='card-footer text-muted' style='border-top-style: none'>";
            chatBoxHTML += "<div class='d-flex'>";
            chatBoxHTML += "<input type='text' class='form-control chatMessage d-inline' placeholder='Chat Message' id='" + chatObject.id + "'>";
            chatBoxHTML += "<button class='btn btn-secondary' type='button' onclick='sendChat(" + chatObject.id + ")'>Send</button>";
            chatBoxHTML += "</div></div>";
            // Closing divs for the column, card-deck, and card.
            chatBoxHTML += "</div></div></div>";
            // Add the chat box html to the chat area in the script.
            $("#chatArea").append(chatBoxHTML);
        }
        // The chatMessagesChanged function is assigned to each chat object's
        // SubObjectChanged handler and is called whenever the chat object has changed.
        function chatMessagesChanged(messages) {
            if (messages.length > 0) {
                var chatId = messages[0].chatMember.interactionId;
                var messageHTML = "";
                // Build HTML for the chat message.
                messageHTML += "<p class='text-left'>" + messages[0].chatMember.displayName + ": " + messages[0].text + "</p>";
                // Append the chat message to the chat box associated with the chat.
                $("#" + chatId + ".chatMessages").append(messageHTML);
            }
        }
        function closeChat(interactionId) {
            currentChats[interactionId].disconnect();
            // Remove the chat box from the script.
            $("#" + interactionId).remove();
        }
        function sendChat(interactionId) {
            alert("Sending Chat!");
            // Get the message from the associated chat box
            var message = $("#" + interactionId + ".chatMessage").val();
            // Send the message from the associated chat object
            currentChats[interactionId].sendChatMessage(message);
        }
        function sendDisposition(disposition) {
            // Disconnect the call.
            IS_Action_Disconnect.click();
            IS_Action_CallComplete.wrapupcode = disposition;
            // Assign a callback to be invoked after the IS_Action_CallComplete action has
            // been executed.
            IS_Action_CallComplete.callback = function (error) {
                if (error) {
                    // The IS_Action_CallComplete action failed, log an error.
                    IS_Action_Trace.message = "The disposition failed.";
                    IS_Action_Trace.level = 0;
                    IS_Action_Trace.click();
                } else {
                    // The disposition was successful. Set the agent back to available.
                    IS_Action_ClientStatus.statuskey = "Available";
                    IS_Action_ClientStatus.click();
                }
            }
            // Execute the action.
            IS_Action_CallComplete.click();
        }
    </script>
</body>
</html>

Example 3

The Hawaiian Cruises script is a multi-page custom script that demonstrates  some of the key actions and events you can use when writing a custom script  in Interaction Scripter. This script works with power, predictive and  preview campaigns and allows an agent to:
  • Go available

  • Receive and view data pops

  • Update contact attributes

  • Dispose of dialer interactions

  • Skip preview calls

  • Request breaks

  • Schedule callbacks

This script is a modified version of the Hawaiian Cruises script used  in Interaction Connect. Because it has all of the functionality of the  original script, comparing the two versions can help you understand what  you need to do differently when developing custom scripts for the two  products.

Example 3 source code

Download the source  code.
See Also
Writing  custom scripts for Interaction Connect or Scripter .NET
Sample ICWS Dialer Web Application