I recently had the opportunity to work on an interesting project where we needed to sync Dynamics CRM and Dynamics NAV. The goal was to have CRM and NAV talk back and forth for certain pieces of data (i.e., Contacts, Account). For other pieces of data, CRM needed to only push data to NAV. This push also needed to incorporate a good amount of business logic. An example of this is that we needed to set certain fields in NAV based on values from CRM.
Microsoft does provide an out-of-the-box solution to handle the normal sync of data. They have a connector available that can be configured per your needs. Most of the entities only flow one direction from NAV to CRM, making NAV the system of record. There are a few entities (Account, Contact and Order) that are bidirectional. For our requirements, we were able to leverage the connector for Contacts and Accounts. Since Dynamics, in general, expose webservices, setting up the connector took understanding where to point the connector. Proper permissions for each of the accounts were the biggest headache to getting everything to play nicely with each other.
This left us still needing to push data from CRM to NAV. One custom entity in CRM was going to create different record types in NAV based on actions in the CRM application. For this requirement, we wrote a custom plugin. Since this was the first time I had worked with NAV, I found it interesting at how finicky NAV was regarding the order in which things must happen. In my first iteration, I thought I could simply set up my NAV object with all my appropriate values and call the create method. It took some hard blows to my head, and a lot of guidance from the NAV team I was working with, to understand that you must first create a record in the NAV system. With a reference to that record, you can them populate all the necessary fields and then call the update method.
In the below code the ‘_job’ object is a data transformation object where we are populating fields directly from CRM.
if (_crmNAVService == null) _crmNAVService = new CRMJobWS.CRMJobWS_Service();
if (_crmNAVJob == null) _crmNAVJob = new CRMJobWS.CRMJobWS();
_crmNAVService.Url = _navJobURL;
_crmNAVService.UseDefaultCredentials = false;
_crmNAVService.Credentials = new NetworkCredential(_navUserName, _navPassWord, _navDomain);
//First check to ensure the job doesn't already exist. Only create if the job doesn't already exist
CRMJobWS.CRMJobWS _jobRetrieved = _crmNAVService.Read(_job.WorkOrderNo);
if (_jobRetrieved == null)
_crmNAVJob.No = _job.WorkOrderNo;
_crmNAVJob.Description = _job.Description;
_crmNAVJob.Division_Code = _job.DivisionCode;
_crmNAVJob.Job_Address_1 = _job.Address;
_crmNAVJob.Job_City = _job.City;
_crmNAVJob.Job_State = _job.State;
_crmNAVJob.Bill_to_Customer_No = _job.AccountNumber;
_crmNAVJob.Department_Code = "SERV";
_crmNAVJob.Contract_Type = CRMJobWS.Contract_Type.Time_and_Material;
_crmNAVJob.Job_Class = CRMJobWS.Job_Class.Master_Job;
_crmNAVJob.Job_Setup_Type = CRMJobWS.Job_Setup_Type.Service;
_crmNAVJob.Work_Class = CRMJobWS.Work_Class.Service;
_crmNAVJob.Status = CRMJobWS.Status.Order;
_crmNAVJob.Manager_Job_Status = CRMJobWS.Manager_Job_Status.Running;
_crmNAVJob.Manager_Job_StatusSpecified = true;
_crmNAVJob.Time_And_Material = true;
It is also worth mentioning that there is a lot you can do in the webservices realm within NAV. There were several times that when a call was failing, it was either a permission issue, or another field needed to be exposed from NAV.
If you are not an expert of NAV, it is great to make friends with someone who is.