Thursday, January 26, 2012

Calculate the Time an Incident Took to Resolve in Microsoft Dynamics CRM 2011 Using .NET or Jscript

This illustration shows how to calculate the time an incident took to resolve in Microsoft Dynamics CRM 2011 with CalculateTotalTimeIncidentRequest.  This example will be given in Jscript (SOAP) and in C# (.NET).

Ok, here is what the code looks like!
First in C#:

CalculateTotalTimeIncidentRequest req = new CalculateTotalTimeIncidentRequest();
req.IncidentId = new Guid("8586CF43-3748-E111-8D3C-1CC1DEF1353B");
CalculateTotalTimeIncidentResponse resp = (CalculateTotalTimeIncidentResponse)service.Execute(req);


If you need help instantiating a service object in .NET within a plugin check out this post:
http://mileyja.blogspot.com/2011/04/instantiating-service-object-within.html


Now here is the Jscript nicely formatted by the CRM 2011 SOAP formatter. Available at: http://crm2011soap.codeplex.com/

Now in Jscript

This example is asynchronous, if you want to learn how to make JScript SOAP calls synchronously please visit this posthttp://mileyja.blogspot.com/2011/07/using-jscript-to-access-soap-web.html

if (typeof (SDK) == "undefined")
   { SDK = { __namespace: true }; }
       //This will establish a more unique namespace for functions in this library. This will reduce the 
       // potential for functions to be overwritten due to a duplicate name when the library is loaded.
       SDK.SAMPLES = {
           _getServerUrl: function () {
               ///<summary>
               /// Returns the URL for the SOAP endpoint using the context information available in the form
               /// or HTML Web resource.
               ///</summary>
               var ServicePath = "/XRMServices/2011/Organization.svc/web";
               var serverUrl = "";
               if (typeof GetGlobalContext == "function") {
                   var context = GetGlobalContext();
                   serverUrl = context.getServerUrl();
               }
               else {
                   if (typeof Xrm.Page.context == "object") {
                         serverUrl = Xrm.Page.context.getServerUrl();
                   }
                   else
                   { throw new Error("Unable to access the server URL"); }
                   }
                  if (serverUrl.match(/\/$/)) {
                       serverUrl = serverUrl.substring(0, serverUrl.length - 1);
                   } 
                   return serverUrl + ServicePath;
               }, 
           CalculateTotalTimeIncidentRequest: function () {
               var requestMain = ""
               requestMain += "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
               requestMain += "  <s:Body>";
               requestMain += "    <Execute xmlns=\"http://schemas.microsoft.com/xrm/2011/Contracts/Services\" xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\">";
               requestMain += "      <request i:type=\"b:CalculateTotalTimeIncidentRequest\" xmlns:a=\"http://schemas.microsoft.com/xrm/2011/Contracts\" xmlns:b=\"http://schemas.microsoft.com/crm/2011/Contracts\">";
               requestMain += "        <a:Parameters xmlns:c=\"http://schemas.datacontract.org/2004/07/System.Collections.Generic\">";
               requestMain += "          <a:KeyValuePairOfstringanyType>";
               requestMain += "            <c:key>IncidentId</c:key>";
               requestMain += "            <c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">8586cf43-3748-e111-8d3c-1cc1def1353b</c:value>";
               requestMain += "          </a:KeyValuePairOfstringanyType>";
               requestMain += "        </a:Parameters>";
               requestMain += "        <a:RequestId i:nil=\"true\" />";
               requestMain += "        <a:RequestName>CalculateTotalTimeIncident</a:RequestName>";
               requestMain += "      </request>";
               requestMain += "    </Execute>";
               requestMain += "  </s:Body>";
               requestMain += "</s:Envelope>";
               var req = new XMLHttpRequest();
               req.open("POST", SDK.SAMPLES._getServerUrl(), true)
               req.setRequestHeader("Accept", "application/xml, text/xml, */*");
               req.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
               req.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");
               var successCallback = null;
               var errorCallback = null;
               req.onreadystatechange = function () { SDK.SAMPLES.CalculateTotalTimeIncidentResponse(req, successCallback, errorCallback); };
               req.send(requestMain);
           },
       CalculateTotalTimeIncidentResponse: function (req, successCallback, errorCallback) {
               ///<summary>
               /// Recieves the assign response
               ///</summary>
               ///<param name="req" Type="XMLHttpRequest">
               /// The XMLHttpRequest response
               ///</param>
               ///<param name="successCallback" Type="Function">
               /// The function to perform when an successfult response is returned.
               /// For this message no data is returned so a success callback is not really necessary.
               ///</param>
               ///<param name="errorCallback" Type="Function">
               /// The function to perform when an error is returned.
               /// This function accepts a JScript error returned by the _getError function
               ///</param>
               if (req.readyState == 4) {
               if (req.status == 200) {
               if (successCallback != null)
               { successCallback(); }
               }
               else {
                   errorCallback(SDK.SAMPLES._getError(req.responseXML));
               }
           }
       },
       _getError: function (faultXml) {
           ///<summary>
           /// Parses the WCF fault returned in the event of an error.
           ///</summary>
           ///<param name="faultXml" Type="XML">
           /// The responseXML property of the XMLHttpRequest response.
           ///</param>
           var errorMessage = "Unknown Error (Unable to parse the fault)";
           if (typeof faultXml == "object") {
               try {
                   var bodyNode = faultXml.firstChild.firstChild;
                   //Retrieve the fault node
                   for (var i = 0; i < bodyNode.childNodes.length; i++) {
                       var node = bodyNode.childNodes[i];
                       //NOTE: This comparison does not handle the case where the XML namespace changes
                       if ("s:Fault" == node.nodeName) {
                       for (var j = 0; j < node.childNodes.length; j++) {
                           var faultStringNode = node.childNodes[j];
                           if ("faultstring" == faultStringNode.nodeName) {
                               errorMessage = faultStringNode.text;
                               break;
                           }
                       }
                       break;
                   }
               }
           }
           catch (e) { };
        }
        return new Error(errorMessage);
     },
 __namespace: true
};




To understand how to parse the response please review my post on using the DOM parser.
Now you can call the SDK.SAMPLES.CalculateTotalTimeIncidentRequest function from your form jscript handler.

Thats all there is to it!
-

4 comments:

  1. Hey Jamie, would love to see how to do this taking into account the support hours configured in the contract related to the case and any business closures configured in the CRM settings!

    ReplyDelete
    Replies
    1. I don't know about all of that, but I think this call calculates actual time from the case openning to it's resolution time. I just openned one and closed one quickly and put 15 minutes billable on it in my test but the call reported back 0 minutes. Which was really how long I was on the case.

      Delete
  2. Hey Jamie,
    after solving a case the form of an incidentresolution opens. There the total time of the incident is presented.
    Do you know a possibilty to update that total time there? I want to recalculate it because i did some customizing.

    Thanks!

    ReplyDelete
  3. Hi Jamie

    I'm a newbie in C# and .Net and most of the web concepts and technologies , our Call Center wants to have a chart from resolved calls and actually have their resolve times. your post is exactly what I need and also I learned to write plugins for dynamics, but I cant figure which entity plugin this most be, and also I can't figure it what to do with Jscript, where should I put that and ...
    Beside all the things that I asked you so before, I want to know how to extract a chart from your code.

    Thanks a lot for your useful posts,

    regards

    ReplyDelete