Tag Archives: Call Centre

Call Centre Optimised CRM–An Example Solution

CRM in the Call Centre is a different beast from regular CRM with factors such as telephony integration and click minimisation playing a big influence.  In this post I will present an example approach to optimising the Call Centre Agent experience in a Customer Service environment.  Every customer scenario is different so this is not meant to be an all encompassing solution, rather its just an example of how we can streamline the user experience with Microsoft CRM 2011.

In this scenario the CTI is going to always pop the Phone Call form.  If the CTI can match the caller the Phone Call will be pre-populated with the CRM Contact.  Otherwise a dummy “Unknown Caller” Contact will be populated.  The Phone Call will be created by custom code and then launched to the user as a saved record.  

Here’s my phone call screen, as the Call Centre Agent would receive when the CTI has successfully matched to a Contact:

image

And when not matched:

image

When the caller has been matched to an existing Contact in CRM their Case History is displayed on the form (with the help of an HTML web resource):

image

The Call Centre Agent greets the caller and determines their identity and the reason for their call.  Here’s what can happen:

Use Case 1:

If the caller has been correctly matched by the CTI and they are calling in regards to an existing Case the Agent will click the Existing Case button on the Ribbon:

image

This pops a Case lookup window displaying the Cases related to the Caller:

image

The Agent selects the relevant Case, and the lookup window closes, as does the Phone Call form and then the Case form pops for the user:

image 

Also note the Caller’s phone number and email address are populated directly onto the Case record for ease of access.

The user can then progress the Case with the Customer (add Notes, check the status of open activities, resolve the Case, etc.).

Behind the scenes the Phone Call has been linked to the Case (so that it appears under the Case’s History) and it has been auto-completed.   

This scenario has been completed in 2 clicks.  That’s pretty good!

Use Case 2:

If the caller was not matched by the CTI and they are legitimately a first time caller who is not yet in CRM the Agent will click the New Case button on the Ribbon:

image

Immediately the Phone Call form closes and a Case form is popped:

image

Now if we cater for anonymous callers then this Case can be progressed just like any other case.  It is already attached to our “Unknown Caller” Contact.

Otherwise, you will notice the Case form has a Quick Create New Contact section on the form (a customisation I have blogged about previously).  The Agent can easily populate this section…

image

… and the Contact will be created and the Case re-associated accordingly:

image

Again, behind the scenes the Phone Call has been linked to the Case and has been auto-completed.

This solution also supports the following use cases:

– The caller is not auto-matched by the CTI as they have called from a different number.  The Agent can simply use the Contact lookup field on the Phone Call form to locate their Contact record.   The process flow then continues as if they were matched by the CTI.

– The caller is matched by the CTI but they are calling in regards to a new issue.  This scenario starts of like Use Case 1 but the user would click the New Case button, and then the scenario follows Use Case 2.

What I like about the solution is:

  • Simplicity for the user – the Phone Call pops, they click either the New Case button or the Existing Case button
  • Processing speed – this solution has the minimal number of clicks possible and does not require the use of the Contact form at any stage
  • Consistent process for emails – this same design could be applied to the Email form for handling inbound customer service emails
  • Automatic activity history – every inbound call results in a (saved) Phone Call activity without any risk of the user not creating/saving the record.  And the Phone Calls are auto-completed for the user.
  • Distinct Cases for each unique Service Request – we are not creating a Case for every call, only when the Agent identifies the call relates to a new issue.
    Hopefully this gives you an idea of what Microsoft CRM is capable of.  Out of the box Microsoft CRM like any CRM system can be a little clunky but the power of Microsoft CRM is its rich (and upgrade friendly!) extensibility.  Don’t be scared of this sort of customisation, Microsoft have designed Microsoft CRM expecting us to configure this types of solutions, and it is more configuration then it is customisation.  After all, I was able to build this out and I’ve never compiled a piece of code in my life.
    If you are not seeing the sort of rich user experience I have described here in your CRM system, well, it’s probably time you found yourself a decent CRM vendor. Smile
      This example solution is available for download here
      To deploy, import the Solution and publish.  Then edit the Configuration entity definition so that it appears in the Settings area (this is meant to appear but didn’t for me when I tested this), create a Contact called “Unknown Caller” and create a Configuration record like the below:

    image

     

    The “Value” you need is the GUID of the Active Contacts view which you can get by opening that view to customise it and then selecting Copy Link from the Actions menu.

     

    Technical Notes

    For those that are curious here’s how I’ve achieved the above.  It’s all real apart from the Case History view which I didn’t bother to build out.

    Phone Call Java Script

    • Change the lookup view of the Sender field to search against Contacts rather than Accounts by default
    • Custom “Existing Case” lookup field added
    • The 2 ribbon buttons were added
    • The “Existing Case” button pops the lookup view of the “Existing Case” lookup field (by firing it’s Click event)
    • Once the “Existing Case” field is populated it is replicated into the “Regarding” field.  Then the SaveAsCompleted function behind the Mark Complete ribbon button is fired.  Then the Case form is launched for the Case GUID specified in the “Existing Case” field.
    • The “New Case” button calls the CRM REST service and creates a new Case record for the Contact specified in the Sender field.  It then populates this Case GUID into the “Regarding” field, fires the SaveAsCompleted function and then launches the Case form.

    Case Java Script

    • Change the lookup view of the Customer field to search against Contacts rather than Accounts by default
    • Hide the Quick Create section unless the Customer field is blank or “Unknown Contact”
    • Once all Quick Create fields are populated the CRM REST service is called to create the new Contact and then that new Contact is populated into the Customer field and the Quick Create section is then hidden
    • Whenever the Customer field changes the CRM REST service is called to retrieve the Contact’s Email Address and Phone Number and these are then populated onto the CRM form

    I have provided sample code for these components in my previous posts. 

    Advertisements

    Quick Create Contact from the Phone Call Form

    Here’s a solution I’ve mocked up to speed up call handling times in a particular Call Centre scenario. 

    Here we have Microsoft Dynamics CRM 2011 deployed into a Call Centre where our CSR’s are tasked with processing inbound calls.   The CRM system has been integrated to the telephony system such that when the caller can be matched to a CRM Contact record that Contact record pops for the user.  

    But when the caller can’t be matched we want the CRM Phone Call form to pop for the user instead and we want to give the user a minimal-click solution that allows them to both record the Phone Call and the Contact.   Here’s what I came up with:

    image

    The telephony integration takes care of popping this form and provides us with the phone number of the caller.  It also populates the subject field for us as well.

    If the CSR’s conversation with the caller indicates they should be in CRM (suggesting that the number they have called in from is new/different) then the CSR can use the out-of-the-box Sender field to search for the caller.

    If the caller is new to us though the user can simply complete these steps to quickly create the Contact and link the Phone Call to the new Contact record:

    1. The CSR clicks into the Title field in the Quick Create New Contact section of the form and populates:

    image

    Note: As soon as the CSR populates one of the fields in this section all the fields in the section become mandatory.

    2. The CSR tabs out of the first field and then populates the second, and then the third:

    image

    3. The user tabs out of the Last Name field and custom code (jscript) is triggered. 

    The code detects that all 3 mandatory fields have now been populated.  The jscript collects the field values from the form and then executes a REST call to create a new Contact based on those values.  On success, the code then updates the Sender field to reflect the Contact that was created and then disables the Quick Create fields:

    image

    For the user, the back end processing is invisible.  They simply followed an intuitive process. 

    A little bit of jscript used in an supported (upgrade friendly) manner has allowed us to streamline the process by removing 6 clicks and one form load.   In a Call Centre environment this is gold.  

    Here’s the jscript behind this.  The OnLoad function needs to be attached to the form’s OnLoad event.  The NewContact function needs to be attached to the OnChange event of the Title, First Name and Last Name fields.  The CreateContact function does the heavy lifting.

    // Set lookup value of a field 
    function SetLookupValue(fieldName, id, name, entityType) { 
        if (fieldName != null) { 
            var lookupValue = new Array(); 
            lookupValue[0] = new Object(); 
            lookupValue[0].id = id; 
            lookupValue[0].name = name; 
            lookupValue[0].entityType = entityType; 
            Xrm.Page.getAttribute(fieldName).setValue(lookupValue); 
        } 
    } 
    
    function DisableFields() { 
        Xrm.Page.ui.controls.get("new_title").setDisabled(true); 
        Xrm.Page.ui.controls.get("new_firstname").setDisabled(true); 
        Xrm.Page.ui.controls.get("new_lastname").setDisabled(true); 
        Xrm.Page.ui.controls.get("phonenumber").setDisabled(true); 
    } 
    
    function MakeFieldsMandatory() { 
        Xrm.Page.data.entity.attributes.get("new_title").setRequiredLevel("required"); 
        Xrm.Page.data.entity.attributes.get("new_firstname").setRequiredLevel("required"); 
        Xrm.Page.data.entity.attributes.get("new_lastname").setRequiredLevel("required"); 
        Xrm.Page.data.entity.attributes.get("phonenumber").setRequiredLevel("required"); 
    } 
    
    function MakeFieldsNonMandatory() { 
        Xrm.Page.data.entity.attributes.get("new_title").setRequiredLevel("none"); 
        Xrm.Page.data.entity.attributes.get("new_firstname").setRequiredLevel("none"); 
        Xrm.Page.data.entity.attributes.get("new_lastname").setRequiredLevel("none"); 
        Xrm.Page.data.entity.attributes.get("phonenumber").setRequiredLevel("none"); 
    } 
    
    function OnLoad() { 
        if (Xrm.Page.ui.getFormType() == 1) { 
            Xrm.Page.getAttribute("subject").setValue("Inbound phone call"); 
            Xrm.Page.getAttribute("phonenumber").setValue("+65 9784 5862"); 
        } 
        else if (Xrm.Page.ui.getFormType() != 1) { 
            DisableFields(); 
        } 
    } 
    
    function NewContact() { 
        if (Xrm.Page.getAttribute("new_title").getValue() == null && 
                Xrm.Page.getAttribute("new_firstname").getValue() == null && 
                Xrm.Page.getAttribute("new_lastname").getValue() == null && 
                Xrm.Page.getAttribute("phonenumber").getValue() == null) { 
            MakeFieldsNonMandatory(); 
        } 
        else if (Xrm.Page.getAttribute("new_title").getValue() != null && 
                    Xrm.Page.getAttribute("new_firstname").getValue() != null && 
                    Xrm.Page.getAttribute("new_lastname").getValue() != null && 
                    Xrm.Page.getAttribute("phonenumber").getValue() != null && 
                    Xrm.Page.data.entity.attributes.get("from").getValue() == null) { 
            CreateContact(); 
            DisableFields(); 
        } 
        else { 
            MakeFieldsMandatory(); 
        } 
    } 
    
    function CreateContact() { 
        // Get the CRM URL 
        var serverUrl = Xrm.Page.context.getServerUrl(); 
    
        // Cater for URL differences between on premise and online 
        if (serverUrl.match(/\/$/)) { 
            serverUrl = serverUrl.substring(0, serverUrl.length - 1); 
        } 
    
        // Specify the ODATA end point (this is the same for all CRM 2011 implementations) 
        var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc"; 
    
        // Specify the ODATA entity collection 
        var ODATA_EntityCollection = "/ContactSet"; 
    
        // Define an object for the CRM record you want created 
        var CRMObject = new Object(); 
    
        // Define attribute values for the CRM object 
        CRMObject.FirstName = Xrm.Page.getAttribute("new_firstname").getValue(); 
        CRMObject.LastName = Xrm.Page.getAttribute("new_lastname").getValue(); 
        CRMObject.Salutation = Xrm.Page.getAttribute("new_title").getValue(); 
        CRMObject.Telephone1 = Xrm.Page.getAttribute("phonenumber").getValue(); 
    
        //Parse the entity object into JSON 
        var jsonEntity = window.JSON.stringify(CRMObject); 
    
        //Asynchronous AJAX function to Create a CRM record using OData 
        $.ajax({ 
            type: "POST", 
            contentType: "application/json; charset=utf-8", 
            datatype: "json", 
            url: serverUrl + ODATA_ENDPOINT + ODATA_EntityCollection, 
            data: jsonEntity, 
            beforeSend: function (XMLHttpRequest) { 
                //Specifying this header ensures that the results will be returned as JSON.      
                XMLHttpRequest.setRequestHeader("Accept", "application/json"); 
            }, 
            success: function (data, textStatus, XmlHttpRequest) { 
                //This function will trigger asynchronously if the Retrieve was successful 
                //alert("ajax call successful"); 
                var NewCRMRecordCreated = data["d"]; 
                var FullName = Xrm.Page.getAttribute("new_firstname").getValue() + " " + Xrm.Page.getAttribute("new_lastname").getValue(); 
                SetLookupValue("from", NewCRMRecordCreated.ContactId, FullName, "contact"); 
            }, 
            error: function (XmlHttpRequest, textStatus, errorThrown) { 
                //This function will trigger asynchronously if the Retrieve returned an error 
                alert("ajax call failed"); 
            } 
        }); 
    }
    

    You will need to upload the json and jquery libraries as web resources and reference in the On Load event along with the OnLoad function:

    image

    A CRM solution file containing these web resources and the changes to the Phone Call form are available for download here.

    Smile