Tuesday, April 20, 2010

Attribute Mapping using Java Script

I'm active visitor and answerer of several forums about Microsoft Dynamics CRM. I have seen a lot questions about mappings - how does it work. Mapping works only once - when new child record opened from parent record and when user just fills parent record lookup - of course mapping doesn't work. I've decided to fix this issue.



I've tested my script on mapping between account and contact. I've put following script to Onchange event handler of parentcustomerfield:

MapFields = function(sourceentity, targetentity, sourceentityid, invokeattributename)

{
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>attributemap</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>targetattributename</q1:Attribute>" +
" <q1:Attribute>sourceattributename</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
"<q1:Criteria>"+
"<q1:FilterOperator>And</q1:FilterOperator>"+
"<q1:Conditions>"+
"<q1:Condition>"+
"<q1:AttributeName>parentattributemapid</q1:AttributeName>"+
"<q1:Operator>Null</q1:Operator>"+
"</q1:Condition>"+
"</q1:Conditions>"+
"</q1:Criteria>"+
" <q1:LinkEntities>" +
" <q1:LinkEntity>" +
" <q1:LinkFromAttributeName>entitymapid</q1:LinkFromAttributeName>" +
" <q1:LinkFromEntityName>attributemap</q1:LinkFromEntityName>" +
" <q1:LinkToEntityName>entitymap</q1:LinkToEntityName>" +
" <q1:LinkToAttributeName>entitymapid</q1:LinkToAttributeName>" +
" <q1:JoinOperator>Inner</q1:JoinOperator>" +
" <q1:LinkCriteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>sourceentityname</q1:AttributeName>" +
" <q1:Operator>Equal</q1:Operator>" +
" <q1:Values>"+
" <q1:Value xsi:type='xsd:string'>"+sourceentity+"</q1:Value>"+
" </q1:Values>"+
" </q1:Condition>" +
" <q1:Condition>" +
" <q1:AttributeName>targetentityname</q1:AttributeName>" +
" <q1:Operator>Equal</q1:Operator>" +
" <q1:Values>"+
" <q1:Value xsi:type='xsd:string'>"+targetentity+"</q1:Value>"+
" </q1:Values>"+
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:LinkCriteria>" +
" </q1:LinkEntity>" +
" </q1:LinkEntities>" +
" </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 results = xmlHttpRequest.responseXML.getElementsByTagName('BusinessEntity');

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>"+
"<Retrieve xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<entityName>" + sourceentity + "</entityName>"+
"<id>" + sourceentityid + "</id>"+
"<columnSet xmlns:q1='http://schemas.microsoft.com/crm/2006/Query' xsi:type='q1:ColumnSet'>"+
"<q1:Attributes>";


var mappings = new Array();

for (var i=0; i < results.length; i++)
{
mappings[i] = new Object();
mappings[i].sourceattribute = results[i].selectSingleNode('./q1:sourceattributename').nodeTypedValue;
mappings[i].targetattribute = results[i].selectSingleNode('./q1:targetattributename').nodeTypedValue;

xml += "<q1:Attribute>" + mappings[i].sourceattribute + "</q1:Attribute>";
}


xml += "</q1:Attributes>"+
"</columnSet>"+
"</Retrieve>"+
"</soap:Body>"+
"</soap:Envelope>";

xmlHttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest.setRequestHeader("SOAPAction","http://schemas.microsoft.com/crm/2007/WebServices/Retrieve");
xmlHttpRequest.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest.send(xml);
var resultXml = xmlHttpRequest.responseXML;

for(var i = 0; i < mappings.length; i++)
{
try
{
var currentfieldtype = crmForm.all[mappings[i].targetattribute].className;
var sourcefieldvalue = resultXml.selectSingleNode("//q1:" + mappings[i].sourceattribute);
if (sourcefieldvalue != null && mappings[i].targetattribute != invokeattributename)
{
var targetfieldvalue = null;

if (currentfieldtype == "ms-crm-Text" || currentfieldtype == "ms-crm-SelectBox ")
targetfieldvalue = sourcefieldvalue.nodeTypedValue;
else if (currentfieldtype.indexOf("ms-crm-Lookup") == 0)
{
targetfieldvalue = new Array();
targetfieldvalue[0] = new Object();
targetfieldvalue[0].id = sourcefieldvalue.nodeTypedValue;
targetfieldvalue[0].name = sourcefieldvalue.getAttribute("name");
targetfieldvalue[0].type = crmForm.all[mappings[i].sourceattribute].getAttribute("lookuptypes");
}
else if (currentfieldtype == "ms-crm-DateTime")
{
var datetimestring = sourcefieldvalue.nodeTypedValue;
var firstpart = datetimestring.split('T')[0];
var secondpart = datetimestring.split('T')[1].split('+')[0];
var parts = firstpart .split('-');
var parts2 = secondpart.split(':')

targetfieldvalue = new Date();

targetfieldvalue.setYear(parts[0]);
targetfieldvalue.setMonth(parts[1] - 1);
targetfieldvalue.setDate(parts[2]);

targetfieldvalue.setHours(parts2[0]);
targetfieldvalue.setMinutes(parts2[1]);
targetfieldvalue.setSeconds(parts2[2]);
}


crmForm.all[mappings[i].targetattribute].DataValue = targetfieldvalue;
crmForm.all[mappings[i].targetattribute].ForceSubmit = true;
}
}
catch(err) {}
}
}

if (crmForm.all.parentcustomerid.DataValue != null && crmForm.all.parentcustomerid.DataValue[0].typename == "account")
MapFields("account", "contact", crmForm.all.parentcustomerid.DataValue[0].id, "parentcustomerid");