Tuesday, May 25, 2010

Use CRM Web Service Toolkit to Implement Associate/Disassociate/SetState Functions

There was a comment in my new CRM Web Service Toolkit release page, complaining the following functions were missing from the toolkit when comparing to Ascentium library.

- Associate
- Disassociate
- SetState

I want to make it very clear upfront. It was never my intention to beat anyone or anything by writing the toolkit. I wrote it simply because I had too much pain to write ad-hoc JavaScript functions to make CRM Web Service calls. It was very inefficient, and also error-prone.

If any of you ever care about how and why it happened, here is a bit story behind the toolkit. I started with a few reusable JavaScript functions at the very beginning, without knowing Ascentium library exists (If I knew in the first place, I would probably never started), and gradually made it into a helper utility. To be honest, it took me quite some effort to get there, as I was an amateur JavaScript developer. I liked most of the implementation, but it was too simple, can only do a couple of things. So I decided to make it better, that's how CRM Service Toolkit 1.0 was born, which killed me almost another whole weekend time plus some evening time during that week, it was the time that I came cross Ascentium library, from which I incorporated the self-contained BusinessEntity concept. The toolkit looked a lot better, but since it's my spare time hobby project, I didn't actually bring the toolkit to my work project until almost 3 months later due to time constraint and distraction of other engagements. As soon as I started to use it in my work project, I immediately realized some problems, most significantly, adding toBoolean() prototype function to JavaScript Number object was simply a wrong decision. That's the biggest motivation for me to write a 2.0 version, as I feel obliged that I have to address this bad design. In the meantime, I wanted to incorporate some security features to the toolkit as they are very often used in CRM projects. That's where v2.0 came from. But since I can only do it on my personal time, it took me roughly a month to find some spare time to really focus on the v2.0 enhancements.

Way off-topic, I just want to make it clear about my intention of writing the toolkit.

Back to the topic of those missing functions, I actually thought about introducing them to the toolkit library, but I decided not to do so, in order to keep the toolkit as nimble as possible, I didn't seem to see they are so often used.

However if you ever need those functions, here are the implementations:

Associate and Disassociate Functions

/**
 * Associate two CRM records that have a N:N relationship. 
 * @param {String} relationshipName Name of the many-to-many relationship.
 * @param {String} entity1Name Entitiy name of the first record to be associated.
 * @param {String} entity1Id CRM Record ID (GUID) of the first record to be associated.
 * @param {String} entity2Name Entitiy name of the second record to be associated.
 * @param {String} entity2Id CRM Record ID (GUID) of the second record to be associated.
 * @return {object} The XML representation of the result.
 */
associate = function(relationshipName, entity1Name, entity1Id, entity2Name, entity2Id)
{
    var request = [
"<Request xsi:type='AssociateEntitiesRequest'>",
    "<Moniker1>",
        "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity1Id, "</Id>",
        "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity1Name, "</Name>",
    "</Moniker1>",
    "<Moniker2>",
        "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity2Id, "</Id>",
        "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity2Name, "</Name>",
    "</Moniker2>",
    "<RelationshipName>", relationshipName, "</RelationshipName>",
"</Request>"
].join("");

    return CrmServiceToolkit.Execute(request);
};

/**
 * Disassociate two CRM records that have a N:N relationship. 
 * @param {String} relationshipName Name of the many-to-many relationship.
 * @param {String} entity1Name Entitiy name of the first record to be disassociated.
 * @param {String} entity1Id CRM Record ID (GUID) of the first record to be disassociated.
 * @param {String} entity2Name Entitiy name of the second record to be disassociated.
 * @param {String} entity2Id CRM Record ID (GUID) of the second record to be disassociated.
 * @return {object} The XML representation of the result.
 */
disassociate = function(relationshipName, entity1Name, entity1Id, entity2Name, entity2Id) {
    var request = [
"<Request xsi:type='DisassociateEntitiesRequest'>",
    "<Moniker1>",
        "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity1Name, "</Name>",
        "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity1Id, "</Id>",
    "</Moniker1>",
    "<Moniker2>",
        "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity2Name, "</Name>",
        "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entity2Id, "</Id>",
    "</Moniker2>",
    "<RelationshipName>", relationshipName, "</RelationshipName>",
"</Request>"
].join("");

    return CrmServiceToolkit.Execute(request);
};

SetState Function

[Update - May 26, 2010] vlad007 left a comment pointing out the request XML was not in right sequence, so I have just updated the script. Thanks vlad007!
/**
 * Set a CRM record's state by its statecode and statuscode. 
 * @param {String} entityName Entitiy name of the CRM record to be updated.
 * @param {String} id CRM Record ID (GUID) to be updated.
 * @param {String} statecode New statecode in string, eg, "Active", "Inactive".
 * @param {Integer} statuscode New statuscode in integer, use -1 for default status.
 * @return {object} The XML representation of the result.
 */
setState = function(entityName, id, stateCode, statusCode) {
    var request = [
"<Request xsi:type='SetStateDynamicEntityRequest'>",
    "<Entity>",
        "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entityName, "</Name>",
        "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", id, "</Id>",
    "</Entity>",
    "<State>", stateCode, "</State>",
    "<Status>", statusCode, "</Status>",
"</Request>"
].join("");

    return CrmServiceToolkit.Execute(request);
};

Please be advised, those functions were not actually unit tested. Please let me know if you have problems using them.

The above code should also be ablet to give you some basic ideas about how to add support of any other CRM messages that you may need to the toolkit.

Cheers!

3 comments:

  1. setState = function(entityName, id, stateCode, statusCode) {
    var request = [
    "<Request xsi:type='SetStateDynamicEntityRequest'>",
    "<Entity>",
    "<Name xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", entityName, "</Name>",
    "<Id xmlns='http://schemas.microsoft.com/crm/2006/CoreTypes'>", id, "</Id>",
    "</Entity>", "<State>", stateCode, "</State>",
    "<Status>", statusCode, "</Status>",
    "</Request>"
    ].join("");

    return CrmServiceToolkit.Execute(request);
    };

    ReplyDelete
  2. Thanks vlad007 for pointing out the error. I have corrected the code.

    As I said, I didn't unit test the code, I basically followed the SDK document to come up the code. However the request XML that I made up was not in the right sequence.

    You can also send me email if you have trouble to paste code when commenting.

    Thanks vlad007 again, you are indeed a 007 man.

    ReplyDelete
  3. I have one doubt.
    I am trying to update the statecode and statuscode on the click of a button.
    I am just confused as to where to place the above code. It is in XML right? Can it be placed in a javasciprt?
    If not, does anyone know how to update the status using javascript code?

    ReplyDelete