Monday, August 20, 2012

Query a User's Schedule for Open Time Blocks Using .NET and Jscript in Microsoft Dynamics CRM 2011

This illustration shows how to query a user's schedule for open time blocks using C# or Jscript in Microsoft Dynamics CRM 2011 with QueryScheduleRequest.
    Ok, here is what the code looks like!
    First in C#:

     WhoAmIRequest reqWAI = new WhoAmIRequest();
     WhoAmIResponse respWAI = (WhoAmIResponse)_serviceProxy.Execute(reqWAI);
    
                                                  
     QueryScheduleRequest reqSchedule = new QueryScheduleRequest();
     reqSchedule.ResourceId = respWAI.UserId;
     reqSchedule.Start = DateTime.Now;
     reqSchedule.End = DateTime.Today.AddDays(3);
     reqSchedule.TimeCodes = new TimeCode[] { TimeCode.Available };
    
     QueryScheduleResponse respSchedule = (QueryScheduleResponse)service.Execute(reqSchedule);
    
     
     if (respSchedule.TimeInfos.Length > 0)
     {
         //act on time slots
     }
    

    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;
                   }, 
               QueryScheduleRequest: 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:QueryScheduleRequest\" 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>ResourceId</c:key>";
                   requestMain += "            <c:value i:type=\"d:guid\" xmlns:d=\"http://schemas.microsoft.com/2003/10/Serialization/\">6e219f51-0310-4c4d-8c60-1c524e2ba7b3</c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "          <a:KeyValuePairOfstringanyType>";
                   requestMain += "            <c:key>Start</c:key>";
                   requestMain += "            <c:value i:type=\"d:dateTime\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">2012-08-20T10:10:38.910063-05:00</c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "          <a:KeyValuePairOfstringanyType>";
                   requestMain += "            <c:key>End</c:key>";
                   requestMain += "            <c:value i:type=\"d:dateTime\" xmlns:d=\"http://www.w3.org/2001/XMLSchema\">2012-08-23T00:00:00-05:00</c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "          <a:KeyValuePairOfstringanyType>";
                   requestMain += "            <c:key>TimeCodes</c:key>";
                   requestMain += "            <c:value i:type=\"b:ArrayOfTimeCode\">";
                   requestMain += "              <b:TimeCode>Available</b:TimeCode>";
                   requestMain += "            </c:value>";
                   requestMain += "          </a:KeyValuePairOfstringanyType>";
                   requestMain += "        </a:Parameters>";
                   requestMain += "        <a:RequestId i:nil=\"true\" />";
                   requestMain += "        <a:RequestName>QuerySchedule</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.QueryScheduleResponse(req, successCallback, errorCallback); };
                   req.send(requestMain);
               },
           QueryScheduleResponse: 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.QueryScheduleRequest function from your form jscript handler.


    Thats all there is to it!
    -

    1 comment:

    1. Hi Jamie,

      I am trying to achieve this functionality and having some trouble with this where I am stuck.

      Basically I want to check if the user is available in the time range I provide as Start and End Date.
      I am using the code snippet as mentioned in your blog. The UserId seems to be proper. I have put Start and End date as Today's Date and TimeCode as Available.

      But the result in the scheduleResponse does not match the schedule as seen in the user's calendar. Also the Start and End dates in the scheduleResponse does not match the dates which I give as scheduleRequest.

      Please let me know if I need to provide any other details regarding the problem.

      ReplyDelete