Featured Post

Web API Requests Series

Web API Series:  Create and Retrieve , Update and Delete , Retrieve Multiple , Associate/Disassociate , Impersonation

07 April 2016

Activities Timeline

I have recently been playing with a very nice HTML Timeline control and have integrated within the Account form in CRM using the new Web API, of course! The Timeline is used to display activities related to the current Account record, it could be used on any record type though.

Here is a screenshot of the beta version:

Some of the functionalities so far:
  • Add new activities (phone calls, emails, tasks, appointments)
  • Drag to reschedule activities
  • Select activities to display
  • Zoom in and out to adjust the period displayed
  • Refresh view
  • Go to Today's activities

04 March 2016

Web API Requests Series

Web API Series: Create and Retrieve, Update and Delete, Retrieve Multiple, Associate/Disassociate, Impersonation

CRM 2016 - WEB API Operations - Associate/Disassociate for Many to Many

Associate and Disassociate for Many to Many (i.e. Collection-Valued navigation property) relationships using the new CRM 2016 Web API in Javascript.
In this example I am going to show you how to Associate/Disassociate two out of the box records: an opportunity and an account.
You can find more information about Single and Collection-Valued properties here and here

this.associateRecords = function (parentId, parentType, relationshipName, childId, childType, successCallback, errorCallback) {
        var req = new XMLHttpRequest();
        req.open("POST", encodeURI(getWebAPIPath() + parentType + "(" + parentId + ")/" + relationshipName + "/$ref"), true);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204 || this.status == 1223) {
                    successCallback();
                }
                else {
                    errorCallback(bd_Utilities.WebAPI.errorHandler(this));
                }
            }
        };
        var childEntityReference = { "@odata.id": getWebAPIPath() + "/" + childType + "(" + childId + ")" };

        req.send(JSON.stringify(childEntityReference));  
    };

//Account: E48456EE-49B0-E611-810F-3863BB357C39
//Opportunity: F45D2DF7-6DBF-E511-8109-3863CB343C91
associate: function () {
        bd_Utilities.WebAPI.associateRecords("E48333EE-49B9-E511-810F-3863BB357C38", "accounts", "opportunity_customer_accounts", "F25D2DF7-6CBF-E511-8109-3863BB343C90", "opportunities",
            function () {

            },
            function () {

            });
    }

And the Disassociate

this.disassociateRecords = function (parentId, parentType, relationshipName, childId, childType, successCallback, errorCallback) {
        var req = new XMLHttpRequest();
     
        var webApiPath = getWebAPIPath();
        var parentUri = webApiPath + "/" + parentType + "(" + parentId + ")/";
        var childUri = webApiPath + "/" + childType + "(" + childId + ")";

        req.open("DELETE", encodeURI(parentUri + relationshipName + "/$ref?$id=" + childUri), true);

        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204 || this.status == 1223) {
                    successCallback();
                }
                else {
                    errorCallback(bd_Utilities.WebAPI.errorHandler(this));
                }
            }
        };
        req.send(JSON.stringify());
    };

function getWebAPIPath() {
        return getClientUrl() + "/api/data/v8.0/";
}

function getClientUrl() {
        //Get the organization URL
        if (typeof GetGlobalContext == "function" &&
            typeof GetGlobalContext().getClientUrl == "function") {
            return GetGlobalContext().getClientUrl();
        }
        else {
            //If GetGlobalContext is not defined check for Xrm.Page.context;
            if (typeof Xrm != "undefined" &&
                typeof Xrm.Page != "undefined" &&
                typeof Xrm.Page.context != "undefined" &&
                typeof Xrm.Page.context.getClientUrl == "function") {
                try {
                    return Xrm.Page.context.getClientUrl();
                } catch (e) {
                    throw new Error("Xrm.Page.context.getClientUrl is not available.");
                }
            }
            else { throw new Error("Context is not available."); }
        }
    }

CRM 2016 - WEB API CRUD Operations - Impersonate another User

Web API series Part 1, Part 2, Part 3
Impersonating another user is very simple, you just need to set the XMLHttpRequest header as shown below.
Here are a couple of basic examples on how to impersonate a User in CRUD operations with the new CRM 2016 Web API in Javascript, here I am just going to show you impersonation in Create and Update. Impersonating another user should also be possible in Delete and Retrieve operations. I haven't tried it yet.

updateRecordOnBehalfOf = function (id, object, entitySetName, successCallback, errorCallback, impersonatedUserId) {

        var req = new XMLHttpRequest();
        req.open("PATCH", encodeURI(getWebAPIPath() + entitySetName + "(" + id + ")"), true);
        req.setRequestHeader("MSCRMCallerID", impersonatedUserId);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204 || this.status == 1223) {
                    successCallback();
                }
                else {
                    errorCallback(bd_Utilities.WebAPI.errorHandler(this));
                }
            }
        };
        req.send(JSON.stringify(object));
    };

createOnBehalfOf = function (entitySetName, entity, successCallback, errorCallback, impersonatedUserId) {
        var req = new XMLHttpRequest();
        req.open("POST", encodeURI(getWebAPIPath() + entitySetName), true);      
        req.setRequestHeader("MSCRMCallerID", impersonatedUserId);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204) {
                    if (successCallback)
                        successCallback(this.getResponseHeader("OData-EntityId"));
                }
                else {
                    if (errorCallback)
                        errorCallback(bd_Utilities.WebAPI.errorHandler(this.response));
                }
            }
        };
        req.send(JSON.stringify(entity));
    };

I hope this help you getting started with the new CRM 2016 Web API.

02 March 2016

CRM 2016 - WEB API CRUD Operations (Part 3)

Following Part 1 and Part 2 here is how to "Update" and "Delete" using the new CRM WebAPI.

    this.updateRecord = function (id, object, entitySetName, successCallback, errorCallback) {

        var req = new XMLHttpRequest();
        req.open("PATCH", encodeURI(getWebAPIPath() + type + "(" + id + ")"), true);
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {
            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204 || this.status == 1223) {
                    successCallback();
                }
                else {
                    errorCallback(bd_Utilities.WebAPI.errorHandler(this));
                }
            }
        };
        req.send(JSON.stringify(object));
    };

    this.deleteRecord = function (id, entitySetName, successCallback, errorCallback) {

        var req = new XMLHttpRequest();
        req.open("DELETE", encodeURI(getWebAPIPath() + type + "(" + id + ")", true));
        req.setRequestHeader("Accept", "application/json");
        req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
        req.setRequestHeader("OData-MaxVersion", "4.0");
        req.setRequestHeader("OData-Version", "4.0");
        req.onreadystatechange = function () {

            if (this.readyState == 4 /* complete */) {
                req.onreadystatechange = null;
                if (this.status == 204) {
                    successCallback();
                }
                else {
                    errorCallback(bd_Utilities.WebAPI.errorHandler(this));
                }
            }
        };
        req.send();
    };