Sunday, November 15, 2009

GoogleMaps within MSCRM

Here’s a way to have GoogleMaps integrated with Microsoft Dynamics CRM.

The aim in this example is as follows: On the account form show the route to the account, having:
- address1 as the destination point
- a flexible starting point (home, office or otherwise)

GMapsMSCRM

The setup used is as follows:
- a new tab named ‘GMaps’
- a new section on the tab 
- a new picklist field named ‘new_gmstartpointselect’ values ‘Office’, ‘Home’ and ‘Otherwise’
- a new nvarchar field named ‘new_gmstartpoint’
- a new IFRAME named ‘IFRAME_GMaps’

Make sure you have the following attributes on the account form to set destination address:
- address1_line1
- address1_line2 (used for housenumber in this example)
- address1_city

In everyday use end users may want to use different starting points. In this example I assumed that the user might want to depart from a) a predefined office address or b) from the end users home address or c) any other address.

To use the end user address, make sure to fill out address1 on the user form.  EndUserAddress

On the picklist field ‘new_gmstartpointselect’ a javascript is used to determine the starting point:

if(crmForm.all.new_gmstartpointselect.SelectedText == "Home")
{
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\">" +
GenerateAuthenticationHeader() +
" <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>systemuser</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>address1_line1</q1:Attribute>" +
" <q1:Attribute>address1_line2</q1:Attribute>" +
" <q1:Attribute>address1_postalcode</q1:Attribute>" +
" <q1:Attribute>address1_city</q1:Attribute>" +
" <q1:Attribute>address1_country</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:Criteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>systemuserid</q1:AttributeName>" +
" <q1:Operator>EqualUserId</q1:Operator>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:Criteria>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";
var xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction", "
http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);

var resultXml = xmlHttpRequest.responseXML;
var entityNode = resultXml.selectSingleNode("//RetrieveMultipleResult/BusinessEntities/BusinessEntity");

var line1Node = entityNode.selectSingleNode("q1:address1_line1");
var line2Node = entityNode.selectSingleNode("q1:address1_line2");
var postalcodeNode = entityNode.selectSingleNode("q1:address1_postalcode");
var cityNode = entityNode.selectSingleNode("q1:address1_city");
var countryNode = entityNode.selectSingleNode("q1:address1_country");

var line1 = (line1Node == null) ? "" : line1Node.text;
var line2= (line2Node == null) ? "" : line2Node.text;
var postalcode = (postalcodeNode == null) ? "" : postalcodeNode.text;
var city = (cityNode == null) ? "" : cityNode.text;
var country = (countryNode == null) ? "" : countryNode.text;

if((line1 == null) || (line1 == ""))
    {
        alert("End User Home address undefined");
    }
    else
    {
        crmForm.all.new_gmstartpoint.DataValue = line1 + "  " + line2 + ", " + city + ", " + country;
        crmForm.all.new_gmstartpoint.FireOnChange();
    }
}

if(crmForm.all.new_gmstartpointselect.SelectedText == "Office")
{
    crmForm.all.new_gmstartpoint.DataValue = "Amsterdamsestraatweg 1, Utrecht, Nederland";
    crmForm.all.new_gmstartpoint.FireOnChange();   
}

if(crmForm.all.new_gmstartpointselect.SelectedText == "Otherwise")
{
    crmForm.all.new_gmstartpoint.DataValue = null;
    crmForm.SetFieldReqLevel("new_gmstartpoint", 1);
}

The first part of this script retrieves the end users address when ‘Home’ is chosen. When ‘Office’ is chosen, a predefined address (Amsterdamsestraatweg 1, Utrecht, Nederland) is used. The script sets the value of ‘new_gmstartpoint’ is set and the onchange is fired. When ‘Otherwise’ is chosen, the end user will have to fill out the starting point manually.

On the ‘new_gmstartpoint’ field is a second javascript that will check if both starting point and destination are filled. If so, the innerHTML of the IFRAME will be replaced by the code needed to show GoogleMaps.

if((crmForm.all.new_gmstartpoint.DataValue == null) ||(crmForm.all.new_gmstartpoint.DataValue == ""))
{
    alert("Startingpoint undefined");
}
else if ((crmForm.all.address1_line1.DataValue == null) ||(crmForm.all.address1_line1.DataValue == "")||(crmForm.all.address1_city.DataValue == null)||(crmForm.all.address1_city.DataValue == ""))
{
    alert("Destination undefined");
}
else
{
    document.getElementById("IFRAME_GMaps_d").innerHTML = "<iframe id=IFRAME_GMaps_d class=ms-crm-Custom width='100%' height='100%' frameborder='0' scrolling='no' marginheight='0' marginwidth='0' src='
http://maps.google.com/maps?f=d&amp;source=s_d&amp;saddr=" + crmForm.all.new_gmstartpoint.DataValue + "&amp;daddr="  + crmForm.all.address1_line1.DataValue +  "  " +crmForm.all.address1_line2.DataValue + ", " + crmForm.all.address1_city.DataValue +   "&amp;hl=nl&amp;output=embed'></iframe>";
}

If the end user wants to, he or she can just change the value of starting point and the map will refresh.

To clear the starting point fields when saving the account, just put the next line on the onsave event of the form:

crmForm.SetFieldReqLevel("new_gmstartpoint", 0); crmForm.all.new_gmstartpoint.DataValue = null;
crmForm.all.new_gmstartpointselect.DataValue = null;

Some final remarks: to view the actual directions and duration, it is possible to click the Google logo in the lower left-hand corner. This will open a new screen.

It is possible to add fields for more accurate address specification.
Integration with Google Maps will not work when offline.
This blog post does not deal with any licensing  or cost issues. Please check Google for more info.

 

2 comments:

  1. Beste Bertil,

    Ik heb deze oplossing, overigens super voor een non developer als ik, draaien bij een klant.
    Nu ben ik benieuwd hoe je streetview actief krijgt binnen deze optie?
    Of is dat niet mogelijk?

    ReplyDelete
  2. Hoi,
    Ik denk dat het wel mogelijk is om de StreetView weergave te krijgen. Ik heb het niet precies uitgezocht. Maar je zult waarschijnlijk daar waar staat output=embed moeten vervangen door output=svembed.
    Het kan zijn dat er nog meer parameters nodig zijn, maar dat heb ik niet uitgezocht.

    ReplyDelete