The main entry point is the SyncmyCompany()
function.
I have a interesting scenario where I'm syncing data from a Company to a destination system. In this case Dynamics 365 is the destination system. The main flow of the code is:
- Get the configuration defined in Dynamics 365 and store data in my configuration object.
- Only once complete step 1, pass in company user creds to get a sts token I used in the company's api calls and store it in my configuration object.
- Only once complete step 2, get task from the company api.
- Only once complete step 3, get task that exists in Dynamics 365 if any.
- Only once complete step 4, if there are task in Dynamics 365 delete them using the task id and Xrm WebApi helper delete method. This requires some behind the scenes deletion of sdk message and task trigger dependencies too.
- Only once complete step 5, use the Xrm WebApi helper create method to repopulate the dropped task data with new data from the source company.
I am using Promises in order to make this possible.
What changes can I make to my Promise logic to make this cleaner and have a stronger order enforced in my code?
Code
"use strict";
var MyCompanyDynamicsClientApi = MyCompanyDynamicsClientApi || {};
MyCompanyDynamicsClientApi.configuration = {
clientUrl: "",
MyCompanyApiUrl: "",
MyCompanyChallengeHostEmail: "",
MyCompanyChallengeHostPassword: "",
MyCompanyChallengeId: "",
MyCompanyChallengeTasks: [],
MyCompanyChallengeTasksInDynamics: {},
MyCompanyClientSecret: "",
MyCompanyUsername: "",
MyCompanyPassword: "",
stsToken: ""
}
MyCompanyDynamicsClientApi.runSyncMyCompanyProcess = function() {
Xrm.Utility.showProgressIndicator("Syncing MyCompany Data...");
MyCompanyDynamicsClientApi.retrieveMyCompanyConfiguration().then(function () {
return MyCompanyDynamicsClientApi.getMyCompanyTokenAsync();
}).then(function () {
return MyCompanyDynamicsClientApi.getMyCompanyTasksAsync();
}).then(function () {
return MyCompanyDynamicsClientApi.getMyCompanyTasksInDynamicsAsync();
}).then(function () {
return MyCompanyDynamicsClientApi.deleteMyCompanyTasksAsync();
}).then(function () {
return MyCompanyDynamicsClientApi.createMyCompanyTasksAsync();
}).then(function () {
return MyCompanyDynamicsClientApi.openSyncMyCompanyCompleteDialog();
}).catch(function (error) {
return MyCompanyDynamicsClientApi.openSyncMyCompanyFailedDialog(error());
});
}
MyCompanyDynamicsClientApi.retrieveMyCompanyConfiguration = function() {
console.log("Trying Promise for MyCompanyConfiguration");
return new Promise(function(resolve, reject) {
MyCompanyDynamicsClientApi.configuration.clientUrl = window.parent.Xrm.Utility.getGlobalContext().getClientUrl();
var MyCompanyConfigurationFetchXml = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true" no-lock="false">';
MyCompanyConfigurationFetchXml = MyCompanyConfigurationFetchXml.concat(
'<entity name="MyCompany_MyCompanyconfiguration">',
'<attribute name="MyCompany_apiurl" />',
'<attribute name="MyCompany_challengehostemail" />',
'<attribute name="MyCompany_challengehostpassword" />',
'<attribute name="MyCompany_clientsecret" />',
'<attribute name="MyCompany_MyCompanyconfigurationid" />',
'<filter type="and">',
'<condition attribute="MyCompany_apiurl" operator="not-null" />',
'<condition attribute="MyCompany_challengehostemail" operator="not-null" />',
'<condition attribute="MyCompany_challengehostpassword" operator="not-null" />',
'<condition attribute="MyCompany_clientsecret" operator="not-null" />',
'<condition attribute="statecode" operator="eq" value="0" />',
'</filter>',
'<link-entity name="MyCompany_MyCompanychallenge" from="MyCompany_MyCompanyconfigurationid" to="MyCompany_MyCompanyconfigurationid" link-type="inner" alias="MyCompany_MyCompanychallenge">',
'<attribute name="MyCompany_MyCompanyid" />',
'<attribute name="MyCompany_name" />',
'<attribute name="MyCompany_MyCompanyconfigurationid" />',
'<filter type="and">',
'<condition attribute="MyCompany_MyCompanyid" operator="not-null" />',
'<condition attribute="MyCompany_name" operator="not-null" />',
'<condition attribute="MyCompany_MyCompanyconfigurationid" operator="not-null" />',
'<condition attribute="statecode" operator="eq" value="0" />',
'</filter>',
'</link-entity>',
'</entity>',
'</fetch>'
);
var MyCompanyConfigurationFetchXmlEncoded = encodeURI(MyCompanyConfigurationFetchXml);
var MyCompanyConfigurationRequestPath = "";
MyCompanyConfigurationRequestPath = MyCompanyConfigurationRequestPath.concat(
MyCompanyDynamicsClientApi.configuration.clientUrl,
"/api/data/v9.0/MyCompany_MyCompanyconfigurations?fetchXml=",
MyCompanyConfigurationFetchXmlEncoded
);
MyCompanyDynamicsClientApi.request("GET", MyCompanyConfigurationRequestPath, "application/json").then(function (response) {
try {
MyCompanyDynamicsClientApi.configuration.MyCompanyApiUrl = response.value[0].MyCompany_apiurl.toString();
MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeHostEmail = response.value[0].MyCompany_challengehostemail.toString();
MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeHostPassword = response.value[0].MyCompany_challengehostpassword.toString();
MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeId = response.value[0]["MyCompany_MyCompanychallenge.MyCompany_MyCompanyid"].toString();
MyCompanyDynamicsClientApi.configuration.MyCompanyClientSecret = response.value[0].MyCompany_clientsecret.toString();
resolve();
} catch (error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.retrieveMyCompanyConfiguration" + error.message)); }
}).catch(function(error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.retrieveMyCompanyConfiguration" + error.message)); });
});
}
MyCompanyDynamicsClientApi.getMyCompanyTokenAsync = function() {
console.log("Trying Promise for MyCompanyTokenAsync");
return new Promise(function(resolve, reject) {
var stsToken = "";
var tokenRequestParams = "grant_type=password&scope=MyCompanyApi&username=" + MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeHostEmail + "&password=" + MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeHostPassword;
var tokenRequestHeaders = { "Authorization": "Basic TWljcm9zb2Z0RmxvdzI6W0k0JjUoXVtPZUJsTk4laGduIXo5cH1TMmp5Wlt4Xmk5" };
var stsTokenRequestUri = "https://playMyCompanydev.azurewebsites.net/sts/connect/token";
MyCompanyDynamicsClientApi.request("POST", stsTokenRequestUri, "application/x-www-form-urlencoded", tokenRequestHeaders, tokenRequestParams).then(function (response) {
try {
MyCompanyDynamicsClientApi.configuration.stsToken = response.access_token.toString();
resolve();
} catch (error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.getMyCompanyTokenAsync" + error.message)); }
}).catch(function(error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.getMyCompanyTokenAsync" + error.message)); });
});
}
MyCompanyDynamicsClientApi.getMyCompanyTasksAsync = function() {
console.log("Trying Promise for getMyCompanyTasksAsync");
return new Promise(function(resolve, reject) {
var taskRequestHeaders = { "Authorization": "Bearer " + MyCompanyDynamicsClientApi.configuration.stsToken };
var taskRequestUri = MyCompanyDynamicsClientApi.configuration.MyCompanyApiUrl + "dynamics/" + MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeId + "/tasks";
MyCompanyDynamicsClientApi.request("GET", taskRequestUri, "application/json", taskRequestHeaders).then(function (response) {
try {
MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks = response;
resolve();
} catch (error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.getMyCompanyTasksAsync" + error.message)); }
}).catch(function(error) { reject(new Error("Failed Promise MyCompanyDynamicsClientApi.getMyCompanyTasksAsync" + error.message)); });
});
}
MyCompanyDynamicsClientApi.getMyCompanyTasksInDynamicsAsync = function() {
console.log("Trying Promise for getMyCompanyTasksInDynamicsAsync");
return new Promise(function(resolve, reject) {
var MyCompanyTasksFetchXml = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true" no-lock="false">';
MyCompanyTasksFetchXml = MyCompanyTasksFetchXml.concat(
'<entity name="MyCompany_MyCompanytask">',
'<attribute name="MyCompany_MyCompanytaskid" />',
'<attribute name="MyCompany_MyCompanytaskidreference" />',
'<attribute name="MyCompany_sdkmessagestepid" />',
'<filter type="and">',
'<condition attribute="MyCompany_MyCompanytaskid" operator="not-null" />',
'<condition attribute="MyCompany_MyCompanytaskidreference" operator="not-null" />',
'<condition attribute="MyCompany_sdkmessagestepid" operator="not-null" />',
'</filter>',
'<link-entity name="MyCompany_MyCompanytrigger" from="MyCompany_MyCompanytriggerid" to="MyCompany_MyCompanytriggerid" link-type="inner" alias="MyCompany_MyCompanytrigger" >',
'<attribute name="MyCompany_MyCompanytriggerid" />',
'<filter type="and">',
'<condition attribute="MyCompany_MyCompanytriggerid" operator="not-null" />',
'</filter>',
'</link-entity>',
'</entity>',
'</fetch>'
);
// TODO: Add filter to fetch xml to merge task instead of just drop and recreate table
// '<condition attribute="MyCompany_apiurl" operator="not-null" />',
// '<filter type="and">',
// '<condition attribute="MyCompany_MyCompanytaskidreference" operator="eq" value="' + MyCompanyTaskIdReference + '" />',
// '</filter>',
var MyCompanyTasksFetchXmlEncoded = encodeURI(MyCompanyTasksFetchXml);
var MyCompanyTasksRequestPath = "";
MyCompanyTasksRequestPath = MyCompanyTasksRequestPath.concat(
MyCompanyDynamicsClientApi.configuration.clientUrl,
"/api/data/v9.0/MyCompany_MyCompanytasks?fetchXml=",
MyCompanyTasksFetchXmlEncoded
);
MyCompanyDynamicsClientApi.request("GET", MyCompanyTasksRequestPath, "application/json").then(function (response) {
try {
MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics = response;
resolve();
} catch (error) { }
}).catch(function(error) { });
});
}
MyCompanyDynamicsClientApi.deleteMyCompanyTasksAsync = function() {
console.log("Trying Promise for deleteMyCompanyTasksAsync");
return new Promise(function(resolve, reject) {
var deleteSdkMessage = function (sdkmessagestepid) {
return new Promise(function(resolve, reject) {
if (sdkmessagestepid) {
Xrm.WebApi.deleteRecord("sdkmessageprocessingstep", sdkmessagestepid).then(
function success(result) {
console.log("Deleted sdkmessageprocessingstep " + result);
resolve();
},
function (error) { console.log("ERROR: Xrm.WebApi.deleteRecord " + error.message.toString()); }
).catch(function(error) {
reject(new Error("Failed Promise MyCompanyDynamicsClientApi.deleteMyCompanyTasksAsync " + error.message));
});
} else {
resolve();
}
});
};
var deleteMyCompanyTrigger = function (triggerid) {
return new Promise(function(resolve, reject) {
if (triggerid) {
Xrm.WebApi.deleteRecord("MyCompany_MyCompanytrigger", triggerid).then(
function success(result) {
console.log("Deleted MyCompany_MyCompanytrigger " + result);
resolve();
},
function (error) { console.log("ERROR: Xrm.WebApi.deleteRecord " + error.message.toString()); }
).catch(function(error) {
reject(new Error("Failed Promise MyCompanyDynamicsClientApi.deleteMyCompanyTasksAsync " + error.message));
});
} else {
resolve();
}
});
};
var deleteMyCompanyTask = function (taskid) {
return new Promise(function(resolve, reject) {
if (taskid) {
Xrm.WebApi.deleteRecord("MyCompany_MyCompanytask", taskid).then(
function success(result) {
console.log("Deleted MyCompany_MyCompanytask " + result);
resolve();
},
function (error) { console.log("ERROR: Xrm.WebApi.deleteRecord " + error.message.toString()); }
).catch(function(error) {
reject(new Error("Failed Promise MyCompanyDynamicsClientApi.deleteMyCompanyTasksAsync " + error.message));
});
} else {
resolve();
}
});
};
var deleteMyCompanyTasksAsyncPromises = [];
var MyCompanytaskid = "";
var MyCompanysdkmessagestepid = "";
var MyCompanytriggerid = "";
for (var i = 0; i < MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value.length; i++) {
if (MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i]) {
MyCompanysdkmessagestepid = MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i].MyCompany_sdkmessagestepid.toString();
deleteMyCompanyTasksAsyncPromises.push( deleteSdkMessage(MyCompanysdkmessagestepid) );
}
if (MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i]["MyCompany_MyCompanytrigger.MyCompany_MyCompanytriggerid"]) {
MyCompanytriggerid = MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i]["MyCompany_MyCompanytrigger.MyCompany_MyCompanytriggerid"].toString();
deleteMyCompanyTasksAsyncPromises.push( deleteMyCompanyTrigger(MyCompanytriggerid) );
}
if (MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i].MyCompany_MyCompanytaskid) {
MyCompanytaskid = MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasksInDynamics.value[i].MyCompany_MyCompanytaskid.toString();
deleteMyCompanyTasksAsyncPromises.push( deleteMyCompanyTask(MyCompanytaskid) );
}
}
Promise.all(deleteMyCompanyTasksAsyncPromises).then(function() {
resolve();
});
});
}
MyCompanyDynamicsClientApi.createMyCompanyTasksAsync = function() {
console.log("Trying Promise for createMyCompanyTasksAsync");
return new Promise(function(resolve, reject) {
var createMyCompanyTask = function (trigger) {
return new Promise(function(resolve, reject) {
if (trigger) {
Xrm.WebApi.createRecord("MyCompany_MyCompanytrigger", trigger).then(
function success(result) {
console.log("Created task and attached trigger to it, trigger is " + MyCompanyTrigger);
resolve();
},
function (error) {
console.log("ERROR: Xrm.WebApi.createRecord " + error.message.toString());
}
).catch(function(error) {
reject(new Error("Failed Promise MyCompanyDynamicsClientApi.createMyCompanyTasksAsync" + error.message));
});
} else {
resolve();
}
});
};
var createMyCompanyTasksAsyncPromises = [];
var MyCompanyTrigger = { };
var MyCompanyEntityName = "";
for (var i = 0; i < MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks.length; i++) {
MyCompanyEntityName = MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].primaryobjecttypecode[0].toUpperCase() + MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].primaryobjecttypecode.slice(1);
MyCompanyTrigger =
{
"MyCompany_name": MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].name + " " + MyCompanyEntityName,
"MyCompany_entityname": MyCompanyEntityName,
"MyCompany_messagename": MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].name,
// MyCompany_MyCompany_MyCompanytask_MyCompany_MyCompanytrigger navigation property (1:N), from DataModel/MyCompanyCrmSdkTypes, generated class using the CrmSvcUtil.exe
"MyCompany_MyCompany_MyCompanytrigger_MyCompany_MyCompanytask_MyCompanytriggerid":
[
{
"MyCompany_name": MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].Title,
"MyCompany_MyCompanytaskidreference": MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].TaskId,
"MyCompany_enabled": true,
"MyCompany_pointvalue": MyCompanyDynamicsClientApi.configuration.MyCompanyChallengeTasks[i].EligiblePoints
}
]
};
createMyCompanyTasksAsyncPromises.push( createMyCompanyTask(MyCompanyTrigger) );
}
Promise.all(createMyCompanyTasksAsyncPromises).then(function() {
resolve();
});
});
}
MyCompanyDynamicsClientApi.request = function(method, uri, contentType, otherHeaders, data) {
if (!RegExp(method, "g").test("POST PATCH PUT GET DELETE")) {
throw new Error("MyCompanyDynamicsClientApi.request: method must be: " +
"POST, PATCH, PUT, GET, or DELETE.");
}
if (!typeof uri === "string" || !typeof contentType === "string") {
throw new Error("MyCompanyDynamicsClientApi.request: uri or contentType is not a string.");
}
if ((RegExp(method, "g").test("POST PATCH PUT")) && (!data)) {
throw new Error("MyCompanyDynamicsClientApi.request: data must contain data for operations that create or modify data.");
}
return new Promise(function (resolve, reject) {
var request = new XMLHttpRequest();
request.open(method, encodeURI(uri), true);
request.setRequestHeader("Content-Type", contentType);
request.setRequestHeader("Cache-Control", "no-cache");
request.onreadystatechange = function () {
if (this.readyState === 4 && this.status === 200) {
var response = JSON.parse(this.responseText);
resolve(response);
}
};
if (otherHeaders) {
var value = "";
for (var header in otherHeaders) {
if (otherHeaders.hasOwnProperty(header)) {
value = otherHeaders[header];
request.setRequestHeader(header, value);
}
}
}
if (data) { request.send(data); }
else { request.send(); }
});
}
MyCompanyDynamicsClientApi.openSyncMyCompanyConfirmDialog = function() {
console.log("Opening confirm dialog...");
var confirmStrings = {
cancelButtonLabel: "No",
confirmButtonLabel: "Yes",
title: "MyCompany Sync",
subtitle: "Are you sure you want to start a sync?"
};
var confirmOptions = { height: 200, width: 450 };
Xrm.Navigation.openConfirmDialog(confirmStrings, confirmOptions).then(
success => {
if (success.confirmed) {
console.log("openSyncMyCompanyConfirmDialog confirmed.");
MyCompanyDynamicsClientApi.runSyncMyCompanyProcess();
}
else {
console.log("openSyncMyCompanyConfirmDialog closed.");
}
},
error => {
console.log(error.message);
});
}
MyCompanyDynamicsClientApi.openSyncMyCompanyCompleteDialog = function() {
return new Promise(function(resolve, reject) {
Xrm.Utility.closeProgressIndicator();
var alertStrings = {
confirmButtonLabel: "Close",
text: "Sync Complete! You can safely close this window."
};
var alertOptions = { height: 120, width: 260 };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(
function success(result) {
resolve();
console.log("openSyncMyCompanyCompleteDialog dialog closed");
},
function (error) { console.log(error.message); }
);
});
}
MyCompanyDynamicsClientApi.openSyncMyCompanyFailedDialog = function(error) {
return new Promise(function(resolve, reject) {
Xrm.Utility.closeProgressIndicator();
var alertStrings = {
confirmButtonLabel: "Close",
text: "ERROR :( the sync failed... please contact your admin. Error details below\n" + error.toString()
};
var alertOptions = { height: 120, width: 260 };
Xrm.Navigation.openAlertDialog(alertStrings, alertOptions).then(
function success(result) {
resolve();
console.log("openSyncMyCompanyFailedDialog dialog closed");
},
function (error) { console.log(error.message); }
);
});
}
function SyncMyCompany() {
console.log("SyncMyCompany running...");
MyCompanyDynamicsClientApi.openSyncMyCompanyConfirmDialog();
}