Sunday, May 23, 2010

Release: MSCRM4 Web Service Toolkit for JavaScript v2.0

[UPDATE - July 4, 2010] A new version has been released at http://danielcai.blogspot.com/2010/07/crm-web-service-toolkit-for-javascript.html, please ensure to check out.

Here is another update of CRM Web Service Toolkit for JavaScript that I released to codeplex site today, most likely this is going to be the last release before CRM5. This new release is based on previous version (v1.0), and it comes with a few more enhancements:
  1. A new method called queryByAttribute() has been added, which allows to retrieve a specific entity's record by using one or more than one pair of attribute and value
  2. Three new methods have been added to help facilitate user and user security role related queries, including getCurrentUserId(), getCurrentUserRoles(), isCurrentUserInRole()
  3. The toBoolean() prototype function that I added to JavaScript Number type in the previous version is now obsolete, instead I have added a new prototype function to the toolkit's BusinessEntity object. So if you want to retrieve a CRM Boolean type field's value, you should use something like this: businessEntity.getValueAsBoolean('new_mybooleanfield')
  4. A new prototype function called getValueAsLookup has been added to the toolkit's BusinessEntity object, which allows you to parse the values of a CRM lookup field that you retrieved through the toolkit and convert it to a CRM lookup control's DataValue. For instance, you could do something like this: crmForm.all.new_mylookup.DataValue = businessEntity.getValueAsLookup("new_mylookup", "new_mylookupentity")
Again, here are a few samples that might help you get started with the toolkit.
  1. Use CrmServiceToolkit.Create() to create a CRM record.
    // Use CrmServiceToolkit. Create() to create a CRM contact record.
    var contact = new CrmServiceToolkit.BusinessEntity("contact");
    contact.attributes["firstname"] = "Diane";
    contact.attributes["lastname"] = "Morgan";
    contact.attributes["gendercode"] = 2;
    contact.attributes["familystatuscode"] = 1; // Picklist : Single - 1
    contact.attributes["creditlimit"] = 3000;
    
    var createResponse = CrmServiceToolkit.Create(contact);
  2. Use CrmServiceToolkit.Update() to update a CRM record.
    //Use CrmServiceToolkit.Update() to update a CRM contact record. 
    var contactId = '3210F2BC-1630-EB11-8AB1-0003AAA0123C';
    var contact = new CrmServiceToolkit.BusinessEntity("contact");
    contact.attributes["contactid"] = contactId;
    contact.attributes["firstname"] = "Diane";
    contact.attributes["lastname"] = "Lopez";
    contact.attributes["familystatuscode"] = 2; // Married
    
    var updateResponse = CrmServiceToolkit.Update(contact);   
  3. Use CrmServiceToolkit.Retrieve() to retrieve a CRM record.
    // Use CrmServiceToolkit.Retrieve() to retrieve a CRM contact record.
    var contactId = '3210F2BC-1630-EB11-8AB1-0003AAA0123C'; 
    var cols = ["firstname", "lastname", "familystatuscode", "creditlimit", "birthdate", "donotemail"];
    var retrievedContact = CrmServiceToolkit.Retrieve("contact", contactId, cols);
    
    alert(retrievedContact.getValue('lastname'));
    alert(retrievedContact.getValue('firstname'));
    alert(retrievedContact.getValue('familystatuscode')); // Picklist's value (integer)
    alert(retrievedContact.getValue('familystatuscode', 'name')); // Picklist's selected text
    alert(retrievedContact.getValue('creditlimit')); // Currency field's value
    alert(retrievedContact.getValue('creditlimit', 'formattedvalue')); // Currency field's formatted value (string)
    alert(retrievedContact.getValue('birthdate')); // Datetime field's date/time value
    alert(retrievedContact.getValue('birthdate', 'date')); // Datetime field's date string
    alert(retrievedContact.getValue('birthdate', 'time')); // Datetime field's time string
    alert(retrievedContact.getValueAsBoolean('donotemail')); // Bit field's value
  4. Use CrmServiceToolkit.RetrieveMultiple() to retrieve a collection of CRM records.
    // Retrieve all contacts whose first name is John. 
    var firstname = 'John'; 
    var query = [
    "<q1:EntityName>contact</q1:EntityName>",
    "<q1:ColumnSet xsi:type='q1:ColumnSet'>",
       "<q1:Attributes>",
          "<q1:Attribute>firstname</q1:Attribute>",
          "<q1:Attribute>lastname</q1:Attribute>",
          "<q1:Attribute>familystatuscode</q1:Attribute>",
          "<q1:Attribute>ownerid</q1:Attribute>",
          "<q1:Attribute>creditlimit</q1:Attribute>",
          "<q1:Attribute>birthdate</q1:Attribute>",
          "<q1:Attribute>donotemail</q1:Attribute>",
       "</q1:Attributes>",
    "</q1:ColumnSet>",
    "<q1:Distinct>false</q1:Distinct>",
    "<q1:Criteria>",
       "<q1:FilterOperator>And</q1:FilterOperator>",
       "<q1:Conditions>",
          "<q1:Condition>",
             "<q1:AttributeName>firstname</q1:AttributeName>",
             "<q1:Operator>Equal</q1:Operator>",
             "<q1:Values>",
                "<q1:Value xsi:type='xsd:string'>", firstname, "</q1:Value>",
             "</q1:Values>",
          "</q1:Condition>",
       "</q1:Conditions>",
    "</q1:Criteria>"
    ].join("");
    
    var retrievedContacts = CrmServiceToolkit.RetrieveMultiple(query);
    
    alert(retrievedContacts.length);
    alert(retrievedContacts[0].getValue('lastname'));
    alert(retrievedContacts[0].getValue('firstname'));
    alert(retrievedContacts[0].getValue('familystatuscode');
    alert(retrievedContacts[0].getValue('familystatuscode', 'name'));
    alert(retrievedContacts[0].getValue('creditlimit'));
    alert(retrievedContacts[0].getValue('creditlimit', 'formattedvalue'));
    alert(retrievedContacts[0].getValue('birthdate'));
    alert(retrievedContacts[0].getValue('birthdate', 'date'));
    alert(retrievedContacts[0].getValue('birthdate', 'time'));
    alert(retrievedContacts[0].getValueAsBoolean('donotemail'));
  5. Use CrmServiceToolkit.Fetch() to retrieve a collection of CRM records using FetchXML query.
    // Fetch all contact records whose first name is John using FetchXML query
    var firstname = 'John';
    var fetchXml = [
    "<fetch mapping='logical'>",
       "<entity name='contact'>",
          "<attribute name='contactid' />",
          "<attribute name='firstname' />",
          "<attribute name='lastname' />",
          "<attribute name='familystatuscode' />",
          "<attribute name='ownerid' />",
          "<attribute name='creditlimit' />",
          "<attribute name='birthdate' />",
          "<attribute name='accountrolecode' />",
          "<attribute name='donotemail' />",
          "<filter>",
             "<condition attribute='firstname' operator='eq' value='", firstname, "' />",
          "</filter>",
       "</entity>",
    "</fetch>"
    ].join("");
    
    var fetchedContacts = CrmServiceToolkit.Fetch(fetchXml);
    
    alert(fetchedContacts.length);
    alert(fetchedContacts[0].getValue('lastname'));
    alert(fetchedContacts[0].getValue('firstname'));
    alert(fetchedContacts[0].getValue('familystatuscode');
    alert(fetchedContacts[0].getValue('familystatuscode', 'name'));
    alert(fetchedContacts[0].getValue('creditlimit'));
    alert(fetchedContacts[0].getValue('creditlimit', 'formattedvalue'));
    alert(fetchedContacts[0].getValue('birthdate'));
    alert(fetchedContacts[0].getValue('birthdate', 'date'));
    alert(fetchedContacts[0].getValue('birthdate', 'time'));
    alert(fetchedContacts[0].getValueAsBoolean('donotemail'));
  6. Use CrmServiceToolkit.Delete() to delete a CRM record.
    // Use CrmServiceToolkit.Delete() to delete a CRM contact record. 
    var contactId = '3210F2BC-1630-EB11-8AB1-0003AAA0123C';
    var deleteResponse = CrmServiceToolkit.Delete("contact", contactId);
    alert(deleteResponse);
  7. Use CrmServiceToolkit.Execute() to execute a message.
    // Use CrmServiceToolkit.Execute() to execute a message. 
    var whoAmI = CrmServiceToolkit.Execute("<Request xsi:type='WhoAmIRequest' />");
    currentUserId = whoAmI.getElementsByTagName("UserId")[0].childNodes[0].nodeValue;
    alert("Current user's ID is " + currentUserId);
  8. Use CrmServiceToolkit.queryByAttribute() to retrieve a CRM record using one criterion.
    // Use CrmServiceToolkit.queryByAttribute() to retrieve a set of CRM records.
    var retrievedContacts = CrmServiceToolkit.queryByAttribute("contact", "firstname", "John"); // Retrieve all contacts whose first name is John.
    
    alert(retrievedContacts[0].getValue('lastname'));
    alert(retrievedContacts[0].getValue('firstname'));
    NOTE: In this example, I didn't specify columnSet parameter, so it will return all available fields of the contact entity, which is a really BAD practice. You should always specify what you want to get, if that's possible.

    NOTE: The signature of this method has been changed in v2.1, please refer to the latest release page if you are using v2.1.

  9. Use CrmServiceToolkit.queryByAttribute() to retrieve a CRM record using more than one criterion, with specified column set and sorting order.
    // Use CrmServiceToolkit.queryByAttribute() to retrieve a set of CRM records using more than one criterion with specified column set or sorting order
    var attributes = ["firstname", "lastname"];
    var values = ["John", "Wayne"];
    var cols = ["familystatuscode", "ownerid", "creditlimit", "birthdate", "donotemail", "donotphone"];
    var orderby = ["jobtitle"]; // Sort by Job Title
    var retrievedContacts = CrmServiceToolkit.queryByAttribute("contact", attributes, values, cols, orderby);
    
    alert(retrievedContacts[0].getValue('middlename'));
    NOTE: Again, the signature of this method has been changed in v2.1, please refer to the latest release page if you are using v2.1.

  10. Use CrmServiceToolkit.getCurrentUserId() to get the current user's ID.
    // Use CrmServiceToolkit.getCurrentUserId() to get the current user's ID.
    var currentUserId = CrmServiceToolkit.getCurrentUserId();
    
    alert(currentUserId);
  11. Use CrmServiceToolkit.getCurrentUserRoles() to get all the system roles that the current user has been assigned to.
    // Use CrmServiceToolkit.getCurrentUserRoles() to get all the system roles that the current user has been assigned to.
    var roles = CrmServiceToolkit.getCurrentUserRoles();
    
    alert(roles[0]); // Prompt the user's first role. 
  12. Use CrmServiceToolkit.isCurrentUserInRole() to check if the current user has a particular role.
    // Use CrmServiceToolkit.isCurrentUserInRole() to check if the current user has a particular role.
    var isSystemAdministrator = CrmServiceToolkit.isCurrentUserInRole("System Administrator");
    
    alert("I " + (isSystemAdministrator ? "AM" : "AM NOT") + " a System Administrator. "); 
As usual, here are a few notes about using the toolkit.
  1. The following CRM JavaScript functions have been used in order to keep the file size minimal (Aside from this reason, I am not a big fan of reinventing the wheel).
    • GenerateAuthenticationHeader() function
    • _HtmlEncode() function
    • CrmEncodeDecode.CrmXmlDecode() function
    • CrmEncodeDecode.CrmXmlEecode() function

    If you ever need to run the toolkit out of the context of a CRM form, you'll need to make the above functions available to the toolkit script.

  2. When you retrieve records from CRM using the toolkit's Fetch, Retrieve, RetrieveMultiple, or the new queryByAttribute methods, what you get will be the instance(s) of CrmServiceToolkit.BusinessEntity, which contains all CRM attributes (fields) that have been returned from CRM. However, you should not try to access those attributes directly, instead you use the instance function - getValue() or getValueAsBoolean() to get the value of the CRM field. The reason behind this is, CRM doesn't return anything if a field's value is null, in which case your JS code will blow up if you try to access the field (attribute) directly. With that being said, you should also be informed that a CRM filed's value could be null, be sure to handle it properly in your JS code.
  3. As mentioned previously, when dealing with the value of CRM bit data type that you have retrieved from CRM (Only Fetch, Retrieve, RetrieveMultiple, queryByAttribute methods are really concerned), you should use getValueAsBoolean() method to get the value. This seems to be the only field type that the toolkit cannot detect correctly. For all other type of CRM fields, you can pretty much use getValue() instance method to do the job.
  4. The toolkit will throw error if the CRM service calls failed with any exceptions, it's always a good idea to use try/catch block to manage the potential errors. An example would be:
    // It's always a good idea to contain any errors that could be thrown be the toolkit.
    try
    {
        var contactId = '3210F2BC-1630-EB11-8AB1-0003AAA0123C'; 
        var cols = ["firstname", "lastname", "familystatuscode", "creditlimit", "birthdate", "donotemail"];
        var retrievedContact = CrmServiceToolkit.Retrieve("contact", contactId, cols);
    
        // Do the rest of work
    }
    catch(err) {
        var errMsg = "There was an error when retrieving the contact information...\n\n";
        errMsg += "Error: " + err.description + "\n";
        alert(errMsg);
    }
  5. CRM's Execute message is a versatile message. Anything that you cannot easily achieve through the other 6 messages, you should resort to the toolkit’s Execute() method. Again, please refer to MSCRM 4.0 SDK for more CRM messages.
  6. The toolkit release has a test page included (CrmServiceToolkitTest.aspx), which utilizes QUnit as the test engine. In order to run the test script, you should deploy it along with all other files to ISV/CrmServiceToolkit folder (Please create this folder first), then you can launch http://crmserver:port/MyOrgName/ISV/CrmServiceToolkit/CrmServiceToolkitTest.aspx to run it. If you are in good luck, you should see a screen like this:
    CrmWebServiceToolkit2Test
    NOTE: The unit tests will actually write a contact record to your CRM database, and it will be deleted as part of the unit tests. 
I hope that I have covered everything.

[CREDITS] The idea behind CrmServiceToolkit.BusinessEntity was inspired by Ascentium CrmService JavaScript Library, after I have finished most of version 1.0 coding. Hats off to Ascentium CRM practice team.

P.S. You should probably have noticed that I have repeated most of the content in my previous toolkit release page, the reason is that I want to provide a single updated page for you to have all the information, so you don't have to go back and forth between the old release page and this release page.

Have fun with the toolkit, hope the toolkit can help you become a more productive CRM developper.

[UPDATE - July 4, 2010] A new version has been released at http://danielcai.blogspot.com/2010/07/crm-web-service-toolkit-for-javascript.html, please ensure to check out.

40 comments:

  1. This is excellent work. Thanks a lot.

    ReplyDelete
  2. Great work, but it's still missing the functions to:

    - Associate
    - Disassociate
    - SetState

    And all your functions are synchronous. An asynchronous option with callback function would complete the package.

    If you include those, it would be final and beat the Ascentium library.

    ReplyDelete
  3. Thanks Sanjay and Ms./Mr. Anonymous.

    Ms./Mr. Anonymous, It was not my intention to beat anybody or anything by writing the toolkit, not to mention that Ascentium is a respectable CRM team. :-)

    Speaking about Associate, Disassociate, and SetState functions, it's pretty easy to implement them using the toolkit's Execute method, if necessary. I don't seem to see they are so often used, my intention is to keep the toolkit library as small as possible.

    With regard to the callback support, you can start a new topic on codeplex site. If there are enough votes, I will try to find time to do it.

    Cheers,
    Daniel

    ReplyDelete
  4. I just wrote a new blog post, which has provided the implementation of the following functions using the toolkit:

    - Associate
    - Disassociate
    - SetState

    Hope it helps.

    -Daniel

    ReplyDelete
  5. Very basic implementation question... I have downloaded the files from the Codeplex and placed them as instructed and the test page launches as expected. Then I copied one of your sample function calls into an OnLOad() event on Account just to test that the functions would fire. They do not. Am I missing a step? I then attemped to use the code you have in your blog entry http://danielcai.blogspot.com/search/label/MSCRM%20Client%20Script to reference the external jscript but that didn't help. Any thoughts?

    ReplyDelete
  6. Hi Andrew,

    So are you sure that you can successfully run the toolkit test page, and you can see that all the tests passed?

    If yes, you should be able to use the following script to load the toolkit.

    function loadExternalScript(url)
    {
    var x = new ActiveXObject("Msxml2.XMLHTTP");
    x.open("GET", url, false);
    x.send(null);
    window.execScript(x.responseText);
    }

    loadExternalScript("/ISV/CrmServiceToolkit/CrmServiceToolkit.min.js");
    // Do the rest of your work using CrmServiceToolkit

    ReplyDelete
  7. Thank you! Either my external call was incorrect or the gods are just shining on me today... solved! Love your code, thanks again!

    Andrew

    ReplyDelete
  8. @Andrew, good to know that you have made it! Thanks for your feedback.

    ReplyDelete
  9. Hi Daniel,

    Thanks for sharing the is a great tool you have made :-)

    I hope it's okay if I link to this post as I need to share this with my CRM geeks.

    one thing there would have been nice would be a small installation guide, and the example on how to get the script working, I could not see it else where that in your answers - or maybe it's me there need new glasses...

    Take care

    /Anders

    ReplyDelete
  10. @Anders, you are more than welcome to link to the post.

    Speaking about the installation, I have included a quick guideline in the notes section (#6) of the post. The simplest way is to copy the entire script (either the full copy or the minified version) to your CRM form's onLoad event. Alternatively, you can use the script snippet that I illustrated in my another blog post at http://danielcai.blogspot.com/2010/02/another-talk-about-referencing-external.html to consume the toolkit from external file.

    I admit this is still a vague instruction, but I hope that you got the point. :-)

    Cheers,
    Daniel

    ReplyDelete
  11. Hi,

    I got the point and I did figur it out :-)

    It was just for your next readers os they don't have to use their time looking for the "missing" information - but then again now it's all over because of our post :-D

    Have a nice day.

    Cheers,


    Anders

    ReplyDelete
  12. Hi Daniel,
    Thank you for your post. I want to know how can I get the GUID of the record created by service toolkit.
    Regards
    Faisal

    ReplyDelete
  13. @Faisal, it's quite simple, the response from the Create method is the GUID of the new record if it succeeds.

    Hope it helps.
    Daniel

    ReplyDelete
  14. The oUnit test page works fine but when I try a simple test on a new page like this:

    function doSomething()
    {
    var roles = CrmServiceToolkit.getCurrentUserRoles();

    alert(roles[0]); // Prompt the user's first role.

    }

    I always get Object Expected. Any ideas?

    ReplyDelete
  15. Hi Daniel,
    I am trying to create an opportunity but getting error on customerid field as I am not passing type.
    opportunity.attributes["customerid"] = oContact;
    what is the correct syntax for this?
    Regards
    Faisal

    ReplyDelete
  16. @brenden, I assume that you are trying to use the toolkit in your custom page. In this case, you can add the following two lines of code to your custom page in order to consume some native CRM functions that the toolkit is using:

    <%@ Register TagPrefix="cnt" Namespace="Microsoft.Crm.Application.Controls" Assembly="Microsoft.Crm.Application.Components.Application" %>

    <cnt:AppHeader id="crmHeader" runat="server" />

    Check CrmServiceToolkitTest.aspx for details about where and how to add those two lines.

    Alternatively, you can find the following functions from CRM native script files, and include them in your custom page:

    * GenerateAuthenticationHeader() function
    * _HtmlEncode() function
    * CrmEncodeDecode.CrmXmlDecode() function
    * CrmEncodeDecode.CrmXmlEecode() function

    Hope this helps.

    Cheers,
    Daniel

    ReplyDelete
  17. @Faisal,

    Please try the following code:
    opportunity.attributes["customerid"] = { $value: oContact, type: "contact" };

    ReplyDelete
  18. I am having trouble using teh Retrieve Multiple based on sample #4. I wanted to have two criteria using an "OR" operator, but I was getting an error. I turned on tracing using CRM Diag Toolkit and saw the following error in teh trace logs:

    System.Web.Services.Protocols.SoapException: Server was unable to read request. ---> System.InvalidOperationException: There is an error in XML document (1, 1310). ---> System.InvalidOperationException: There is an error in XML document (1, 1310). ---> System.InvalidOperationException: Instance validation error: 'OR' is not a valid value for LogicalOperator.

    But I know the "OR" will work because I can build my own CRM soap query and call teh CRM web service myself and it works. but when I use the CRMServiceToolkit I get the error.

    How can I use the CRMServiceToolkit with an "OR" operator to retrieve a CRM contact record?

    Thanks,
    Glenn

    ReplyDelete
  19. @Glenn,

    Try the following code, it worked for me:

    var query =
    "<q1:EntityName>contact</q1:EntityName>" +
    "<q1:ColumnSet xsi:type='q1:ColumnSet'>" +
    "<q1:Attributes>" +
    "<q1:Attribute>firstname</q1:Attribute>" +
    "<q1:Attribute>lastname</q1:Attribute>" +
    "<q1:Attribute>middlename</q1:Attribute>" +
    "<q1:Attribute>familystatuscode</q1:Attribute>" +
    "<q1:Attribute>ownerid</q1:Attribute>" +
    "<q1:Attribute>creditlimit</q1:Attribute>" +
    "<q1:Attribute>birthdate</q1:Attribute>" +
    "<q1:Attribute>donotemail</q1:Attribute>" +
    "<q1:Attribute>donotphone</q1:Attribute>" +
    "</q1:Attributes>" +
    "</q1:ColumnSet>" +
    "<q1:Distinct>false</q1:Distinct>" +
    "<q1:Criteria>" +
    "<q1:FilterOperator>And</q1:FilterOperator>" +
    "<q1:Conditions>" +
    "<q1:Condition>" +
    "<q1:AttributeName>contactid</q1:AttributeName>" +
    "<q1:Operator>Equal</q1:Operator>" +
    "<q1:Values>" +
    "<q1:Value xsi:type='xsd:string'>" + contactId + "</q1:Value>" +
    "</q1:Values>" +
    "</q1:Condition>" +
    "<q1:Condition>" +
    "<q1:AttributeName>firstname</q1:AttributeName>" +
    "<q1:Operator>Equal</q1:Operator>" +
    "<q1:Values>" +
    "<q1:Value xsi:type='xsd:string'>Diane</q1:Value>" +
    "</q1:Values>" +
    "</q1:Condition>" +
    "</q1:Conditions>" +
    "</q1:Criteria>";

    var retrievedContacts = CrmServiceToolkit.RetrieveMultiple(query);

    Cheers,
    Daniel

    ReplyDelete
  20. Hi Daniel,

    Thank you for the response but that is not quite what I want. I have a string of text that is EITHER the contact's FullName OR the contact's Email Address, I do not know which it will be at the time of the query, I do not know the contactid. So I need to do an "OR" on the fullname and emailaddress1 attributes with the same text string. I use the following calling the web service myself and it works.

    // Prepare the SOAP message.
    var xml = "<?xml version='1.0' encoding='utf-8'?>" +
    "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'" +
    " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'" +
    " xmlns:xsd='http://www.w3.org/2001/XMLSchema'>" +
    authenticationHeader +
    "<soap:Body>" +
    "<RetrieveMultiple xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>" +
    "<query xmlns:q1='http://schemas.microsoft.com/crm/2006/Query'" +
    " xsi:type='q1:QueryExpression'>" +
    "<q1:EntityName>contact</q1:EntityName>" +
    "<q1:ColumnSet xsi:type='q1:ColumnSet'>" +
    "<q1:Attributes>" +
    "<q1:Attribute>emailaddress1</q1:Attribute>" +
    "</q1:Attributes>" +
    "</q1:ColumnSet>" +
    "<q1:Distinct>false</q1:Distinct>" +
    "<q1:Criteria>" +
    "<q1:FilterOperator>Or</q1:FilterOperator>" +
    "<q1:Conditions>" +
    "<q1:Condition>" +
    "<q1:AttributeName>fullname</q1:AttributeName>" +
    "<q1:Operator>Equal</q1:Operator>" +
    "<q1:Values>" +
    "<q1:Value xsi:type='xsd:string'>" + user + "</q1:Value>" +
    "</q1:Values>" +
    "</q1:Condition>" +
    "<q1:Condition>" +
    "<q1:AttributeName>emailaddress1</q1:AttributeName>" +
    "<q1:Operator>Like</q1:Operator>" +
    "<q1:Values>" +
    "<q1:Value xsi:type='xsd:string'>" + user + "</q1:Value>" +
    "</q1:Values>" +
    "</q1:Condition>" +
    "</q1:Conditions>" +
    "</q1:Criteria>" +
    "</query>" +
    "</RetrieveMultiple>" +
    "</soap:Body>" +
    "</soap:Envelope>";

    // Prepare the xmlHttpObject and send the request.
    var xHReq = new ActiveXObject("Msxml2.XMLHTTP");
    xHReq.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
    xHReq.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
    xHReq.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    xHReq.setRequestHeader("Content-Length", xml.length);
    xHReq.send(xml);
    // Capture the result.
    var resultXml = xHReq.responseXML;


    I want to do the same thing with the CRMServiceToolkit but I canot seem to get it to work.

    Thanks
    Glenn

    ReplyDelete
  21. Heeelp pleasee, How to set atrributes datetime in CrmServiceToolkit.Create()? How to set format?

    ReplyDelete
  22. @Anonymous, if you set the attribute to a JavaScript datetime object, the toolkit will automatically encode it in the format that CRM takes. Give it a try and let me know if it helps.

    For instance, you may do something like this:

    mycontact.attributes["birthdate"] = new Date(1988, 2, 20);

    ReplyDelete
  23. Ups, I have found out that first case is not displayed OK. Nevertheless, second case is identical..

    ReplyDelete
  24. @Borut,

    There is no "user" entity in CRM, you should use "systemuser" instead of "user".

    ReplyDelete
  25. hello, i'm trying to execute a FulfillSalesOrderRequest by javascript, but i can't. Have you any idea to how that?

    ReplyDelete
  26. @Anonymous, try the following function:

    var fulfillOrder = function(orderId) {
    var request = [
    "<Request xsi:type='FulfillSalesOrderRequest'>",
    "<OrderClose>",
    "<salesorderid type='salesorder'>", orderId, "</salesorderid>",
    "</OrderClose>",
    "<Status>",
    100001,
    "</Status>",
    "</Request>"
    ].join("");

    var resultXml = CrmServiceToolkit.Execute(request);
    var response = resultXml.selectSingleNode("//ExecuteResponse/Response");
    var result = CrmEncodeDecode.CrmXmlDecode(response.text);
    return result;
    };

    To use the function, make a call like this:

    fulfillOrder(orderId);

    Hope it helps.

    ReplyDelete
  27. Although it's late but I am using multiple conditions:-
    var fetchXml = [
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
    ].join("");

    ReplyDelete
  28. Hi Daniel,
    Thank you for your contribution. I am trying to create an email using this kit:-
    var oEmail = new CrmServiceToolkit.BusinessEntity("email");
    oEmail .attributes["subject"] = subject.text;
    oEmail .attributes["description"] = emailBody.text;
    oEmail .attributes["regardingobjectid"] = { $value: EntityId, type: "opportunity" };
    oEmail .attributes["to"] = { $value: Customer.id, type: "contact" };
    var createResponse = CrmServiceToolkit.Create(oEmail );
    I am getting error "$value is null or not an object". I suspect it is coming from To activityparty. Can you please suggect something?
    Regards
    Faisal Fiaz

    ReplyDelete
  29. @Faisal, I tried your script, it worked fine for me. I am suspecting that you possibly have a syntax error somewhere else, but I am not too sure. However the script just worked fine for me.

    ReplyDelete
  30. Thank you Daniel for your prompt response. Actually I am trying to create an email from template. How can I get 'InstantiateTemplateRequest' using servicetoolkit. Another question is that I am using .htm page. Can I included service toolkit to .htm page. If so do I have to do anything extra?. I apologies for taking your time. Thank your for your valuable support.
    Regards
    Faisal Fiaz

    ReplyDelete
  31. Hi Faisal, the toolkit is capable to do any execute request. I am not familiar with 'InstantiateTemplateRequest', but you may borrow the idea from 'FulfillSalesOrderRequest' that I previously responded to another commenter above.

    For your second question, yes, it's possible to use the toolkit in .htm page. What you need to do is to make the following 4 functions available to the toolkit.

    GenerateAuthenticationHeader()
    _HtmlEncode()
    CrmEncodeDecode.CrmXmlDecode()
    CrmEncodeDecode.CrmXmlEecode()

    You can easily get them from CRM script files though they are not in the same file.

    Hope this helps.

    ReplyDelete
  32. Thank you for your help. I have tried the following code but it is coming up with error message object expected.
    var CreateEmail = function(TemplateId, EntityTypeName, EntityId) {
    try
    {
    var request = [
    "",
    " " + TemplateId + "",
    " " + EntityTypeName + "",
    " " + EntityId + "",
    " ",
    ].join("");

    var resultXml = CrmServiceToolkit.Execute(request);
    var response = resultXml.selectSingleNode("//ExecuteResponse/Response");
    var result = CrmEncodeDecode.CrmXmlDecode(response.text);
    return result;
    alert(response.text);
    }
    catch(err) {
    var errMsg = "There was an error when retrieving the information...\n\n";
    errMsg += "Error: " + err.description + "\n";
    alert(errMsg);
    }
    }
    CreateEmail('{5144455C-B6FB-DF11-AEDE-0019B9D8525E}', 'opportunity', crmForm.ObjectId);
    Regards
    Faisal

    ReplyDelete
  33. Not sure what happended to the code. If you can send me email address I can send you the code.
    Thank you

    ReplyDelete
  34. Hi Danial,
    Sorry for being a pain for you. I need to know how can I make the four functions mentioned above available to Toolkit?

    ReplyDelete
  35. Hi Faisal,

    When you post comment with code, you should always use HTML encoder to encode the code first, otherwise the code will not be shown properly.

    It's not difficult to find the 4 functions if you have a proper grep or editor tool (I use Notepad++ Find in Files function).

    Don't worry about asking questions. I know you are a diligent person.

    ReplyDelete
  36. Hi Faisal,

    You may write email to me by danielwcai at gmail dot com.

    Cheers,
    Daniel

    ReplyDelete
  37. Does the following statement work in CRM 2011?
    CrmServiceToolkit.Fetch()
    Because it is sayin that the above statement is undefined. Do i have to add something else while using that statement?
    As in do i have to paste this also somewhere?
    // Fetch all contact records whose first name is John using FetchXML query
    var firstname = 'John';
    var fetchXml = [
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    "",
    ""
    ].join("");

    var fetchedContacts = CrmServiceToolkit.Fetch(fetchXml);

    alert(fetchedContacts.length);
    alert(fetchedContacts[0].getValue('lastname'));
    alert(fetchedContacts[0].getValue('firstname'));
    alert(fetchedContacts[0].getValue('familystatuscode');
    alert(fetchedContacts[0].getValue('familystatuscode', 'name'));
    alert(fetchedContacts[0].getValue('creditlimit'));
    alert(fetchedContacts[0].getValue('creditlimit', 'formattedvalue'));
    alert(fetchedContacts[0].getValue('birthdate'));
    alert(fetchedContacts[0].getValue('birthdate', 'date'));
    alert(fetchedContacts[0].getValue('birthdate', 'time'));
    alert(fetchedContacts[0].getValueAsBoolean('donotemail'));

    ReplyDelete
  38. Many small businesses target local market and end consumers, while large corporations may aim at national or global market and try to please business users.small business website design

    ReplyDelete
  39. Hi Daniel,
    I am trying to create an appointment via CrmServiceToolkit.Create().
    In that Create I try to set some Lookups. I do in that way:

    var appointment = new CrmServiceToolkit.BusinessEntity("appointment");
    appointment.attributes["requiredattendees"] = { $value: accountID, type: "account" };
    appointment.attributes["new_accountid"] = { $value: accountID, type: "account" };
    appointment.attributes["new_contactid"] = { $value: contactID, type: "contact" };
    var createResponse = CrmServiceToolkit.Create(appointment);

    Everything works fine. I get no error. But when I open my new appointment the attributes "requiredattendees", "new_accountid" and "new_contactid" are empty.

    Can you help me what am I doing wrong?

    Regards
    David

    ReplyDelete
    Replies
    1. @David, the problem is the toolkit doesn't support activity party field. I have a private build which has this support. Please drop me a note at danielwcai at gmail dot com so that I can send you the copy of the script.

      Delete