Wednesday, October 6, 2010

Deploying Wizard Report to Different Server in MS CRM 4.0

When we create a wizard report in CRM, it’s really difficult to move the same report to production. Once you download the wizard report, we get an RDL file.

When we upload this RDL file to production, we get a report but wizard is lost. User can’t update the report (like column, group etc).

I searched into the database and found a solution (its unsupported) to enable the wizard of the wizard report after uploading the RDL.

Steps to upload a wizard report to production:

Create a wizard report in CRM in Dev environment.
Download the wizard report, it will give an RDL file.
Upload the same RDL file to the Production as “Existing file”.
Login to ORG_MSCRM DB, update the Report table entry, set IsCustomReport = 1 for the corresponding report.

Monday, June 28, 2010

CRM update web service call in Java Script in MS CRM 4.0

// Record Owner
var Owner = new Array;
Owner = crmForm.all.ownerid.DataValue;
var oppOwner = Owner[0].name;

// updating Opportunity
/* setting opportunuty owner name to a text field in the same record using crm update web service call in JScript */
try
{
var xml1 = "<?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>"+
"<Update xmlns='http://schemas.microsoft.com/crm/2007/WebServices'>"+
"<entity xsi:type='opportunity'>" +
"<new_text>"+ xmlencode(oppOwner) +"</new_text>" +
"<opportunityid>" + crmForm.ObjectId + "</opportunityid>" +
"</entity>"+
"</Update>"+
"</soap:Body>"+
"</soap:Envelope>";

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

var errorCount1 = resultXml1.selectNodes('//error').length;
}
catch (e)
{ }

/* xml encoding to convert "&" and single quote (') symbol*/
function xmlencode(string) {
return string.replace(/\&/g,'&'+'amp;').replace(/</g,'&'+'lt;').replace(/>/g,'&'+'gt;').replace(/\'/g,'&'+'apos;').replace(/\"/g,'&'+'quot;');
}

Friday, June 25, 2010

Set the account lookup when new contact is created from the Contact lookup new button in Account form in MS CRM 4.0

function getAccountLookup()
{
try
{
var stringXml = window.opener.document.getElementById("fetchxml").value;

xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
xmlDoc.async="false";
xmlDoc.loadXML(stringXml)

var name = xmlDoc.selectNodes('fetch/entity/filter/condition')[1].attributes[2].value;
var id = xmlDoc.selectNodes('fetch/entity/filter/condition')[1].attributes[4].value;

//Create an array to set as the DataValue for the lookup control.
var lookupData = new Array();

//Create an Object add to the array.
var lookupItem= new Object();

//Set the id, typename, and name properties to the object.
lookupItem.id = id;
lookupItem.typename = 'account';
lookupItem.name = name;

// Add the object to the array.
lookupData[0] = lookupItem;

// Set the value of the lookup field to the value of the array.
crmForm.all.parentcustomerid.DataValue = lookupData;

}
catch (e)
{}
}

Remove Add Existing Button From CRM Iframe in MS CRM 4.0

/* _MBtoplocAssocOneToMany2contactcustomeraccounts is the Id of the AddExisting button appearing in CRM grid. this id can be find out using IE developer tool bar */

function RemoveAddExistingFromIframe()
{
var iFrame1 = null;
iFrame1 = crmForm.all.IFRAME_Test;
var iDoc1 = iFrame1.contentWindow.document;
iFrame1.attachEvent( "onreadystatechange" , Ready1);
RemoveWhiteSpace(iFrame1);
}

function Ready1()
{

var iFrame1 = crmForm.all.IFRAME_Test;
var iDoc1 = iFrame1.contentWindow.document;
if(iDoc1.getElementById("_MBtoplocAssocOneToMany2contactcustomeraccounts") != null)
iDoc1.getElementById("_MBtoplocAssocOneToMany2contactcustomeraccounts").style.display = "none";
}


function RemoveWhiteSpace(iframe)
{
try
{
var IFRAME_test = iframe;
IFRAME_test.onreadystatechange = function ()
{
if( IFRAME_test.readyState != 'complete' )
return;
IFRAME_test.style.border = "0px";
var IframeWindo = IFRAME_test.contentWindow;
IframeWindo.document.body.scroll = "no";
IframeWindo.document.body.childNodes[0].rows[0].cells[0].style.padding = "0px";
}
}catch (e)
{alert('Error : '+e);}
}

Hide CRM form Button/menu/sort cuts/isv buttons in MS CRM 4.0

function HideISVButtons()
{

var toolBar = document.getElementById('mnuBar1');
if (toolBar != null && toolBar.rows.length > 0 && toolBar.rows[0].cells.length > 0)
{
try
{

var toolBarItems = toolBar.rows[0].cells[0].getElementsByTagName('li')
if (toolBarItems != null && toolBarItems.length > 0) {
for (var i = 0; i < toolBarItems.length; i++) {
var toolBarbuttonName = toolBarItems[i].getAttribute('title');
switch (toolBarbuttonName) {
case "Attach a File":
toolBarItems[i].style.display = 'none';
toolBarItems[i - 1].style.display = 'none';
break;
case "Print Preview":
toolBarItems[i].style.display = 'none';
break;
case "Actions":
toolBarItems[i].style.display = 'none';
toolBarItems[i - 1].style.display = 'none';
break;
break;
case "Follow Up":
toolBarItems[i].style.display = 'none';
toolBarItems[i - 1].style.display = 'none';
break;
case "Test ISV Button":
toolBarItems[i].style.display = 'none';
toolBarItems[i - 1].style.display = 'none';
toolBarItems[i + 1].style.display = 'none'; break;
}
}
}
}
catch (e)
{ }
}
}

Advanced find view in an IFRAME in CRM from in MS CRM 4.0

// Fetch xml for the data we want to show in a CRM grid

fetchXml = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true'>"+
"<entity name='opportunity'>"+
"<attribute name='name'/>"+
"<attribute name='createdon'/>"+
"<attribute name='ownerid'/>"+
"<attribute name='new_finalstage'/>"+
"<attribute name='opportunityid'/>"+
"<order attribute='name' descending='false'/>"+
"<filter type='and'><condition attribute='statecode' operator='eq' value='0'/></filter>"+
"</entity></fetch>";

/* Layout of the adv find Grid
In object - is the objecttypecode of the result entity
jump - is the name of the primary column in the result view */

var layoutXml = ""+
"<grid name='resultset' object='3' jump='name' select='1' icon='1' preview='1'>"+
"<row name='result' id='opportunity'>"+
"<cell name='name' width='230' />"+
"<cell name='createdon' width='80' />"+
"<cell name='ownerid' width='120' />"+
"<cell name='new_finalstage' width='160' />"+
"</row>"+
"</grid>";

/* the main method to retrieve and bind the data to the CRM Grid according to the fetch XML and Layout XML
IFRAME_TEST- an IFRAME to show the advance find view
opportunity – is the main entity name
fetchXml – the fetchXml query we want to retrieve from CRM
layoutXml – the layout to show the retrieved data
name – sorting of records in CRM advanced find grid
false – sort order Descending
{350D0AA8-3EF5-496B-A714-15B2DE896D20} – advance find view id for the same entity (opportunity) */

EmbedAdvancedFindView("IFRAME_TEST", "opportunity", fetchXml, layoutXml, "name", "false", "{350D0AA8-3EF5-496B-A714-15B2DE896D20}");

// to remove the toolbar items from the advance find grid
var iFrame1 = null;
iFrame1 = crmForm.all.IFRAME_TEST;
var iDoc1 = iFrame1.contentWindow.document;
iFrame1.attachEvent( "onreadystatechange" , Ready1);
RemoveWhiteSpace(iFrame1);


function Ready1(){
try{
var iFrame = crmForm.all.IFRAME_TEST;
var iDoc1 = iFrame.contentWindow.document;
if(iDoc1.getElementById("gridMenuBar") != null)
iDoc1.getElementById("gridMenuBar").style.display = "none";
}catch (e)
{}
}


function EmbedAdvancedFindView(iFrameId, entityName, fetchXml, layoutXml, sortCol, sortDescend, defaultAdvFindViewId) {
try {

var iFrame = document.getElementById(iFrameId);
var httpObj = new ActiveXObject("Msxml2.XMLHTTP");
var url = "/" + ORG_UNIQUE_NAME + "/advancedFind/fetchData.aspx";

var params = "FetchXML=" + fetchXml
+ "&LayoutXML=" + layoutXml
+ "&EntityName=" + entityName
+ "&DefaultAdvFindViewId=" + defaultAdvFindViewId
+ "&ViewType=1039" // According to Michael Hohne over at Stunnware
+ "&SortCol=" + sortCol
+ "&SortDescend=" + sortDescend;

httpObj.Open("POST", url, true);

httpObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
httpObj.setRequestHeader("Content-length", params.length);

httpObj.onreadystatechange = function() {
if (httpObj.readyState == 4 && httpObj.status == 200) {
var doc = iFrame.contentWindow.document;
iFrame.src = null;
doc.open();
doc.write(httpObj.responseText);
doc.close();

doc.body.style.padding = "0px";
doc.body.style.backgroundColor = "#eaf3ff";
}
}
httpObj.send(params);
}
catch (e) {
}
}

// to expand the adv find grid to full width
function RemoveWhiteSpace(iframe)
{
var IFRAME_test = iframe;
IFRAME_test.onreadystatechange = function ()
{
if( IFRAME_test.readyState != 'complete' )
return;
IFRAME_test.style.border = "0px";
var IframeWindo = IFRAME_test.contentWindow;
if(IframeWindo.document.body.childNodes[0]!=null){
if(IframeWindo.document.body.childNodes[0].rows!=null){
IframeWindo.document.body.scroll = "no";
IframeWindo.document.body.childNodes[0].rows[0].cells[0].style.padding = "0px";
}
}
}
}

Thursday, June 24, 2010

Xmlencode the text in fetchXML in Jscript in MS CRM 4.0

While passing text as a parameter in fetchXml in CRM OnLoad/OnSave/OnChange event Jscript, it required to xmlencode the text before use the same as parameter.
This is because the fetchXml contains “&” or single quote(‘) is not executed in Jscript CRM service call.


function xmlencode(string) {
return string.replace(/\&/g,'&'+'amp;').replace(//g,'&'+'gt;').replace(/\'/g,'&'+'apos;').replace(/\"/g,'&'+'quot;');
}

Refresh a CRM grid on the CRM Form in MS CRM 4.0

try
{
var _locAssocObj = locAssocObj;
locAssocObj = this.locAssocObj;

//fucntion definition for overloading the N:N Grid association
this.locAssocObj = function(iType, sSubType, sAssociationName, iRoleOrdinal) {
_locAssocObj(iType, sSubType, sAssociationName, iRoleOrdinal);
switch (sAssociationName) {
case "new_new_opportunity_systemuser":
crmForm.all.IFRAME_OpportunityUser.contentWindow.document.all.crmGrid.Refresh();
break;
}
}

} catch (e)
{ }


“sAssociationName” is the relationship name (we can find this in entity customization).
Here there is an N:N relationship in between Opportunity and SystemUser named “new_new_opportunity_systemuser”.
And the system user grid is there on the CRM. On addition/removal of any entry in the user list will refresh the corresponding grid.

Set Focus to a field in CRM form in MS CRM 4.0

function SetFocustoaField()
{
var oField = crmForm.all.new_name;
oField.onblur = function() {
oField.SetFocus();
oField.onblur = null;
}
oField.SetFocus();
}

Call External JS file in CRM from OnLoad/OnSave/OnChange event in MS CRM 4.0

Take an example. I have a JS file named “Entity_OnLoad.js” in “ISV/Org_Name/JavaScript” folder. There is a method named “CommonAction” in “Entity_OnLoad.js” file.

With the help of following Jscript we can call the “CommonAction” method from “Entity_OnLoad.js” in the OnLoad/OnSave/OnChange event of the CRM form.


var netRequest = new ActiveXObject("Msxml2.XMLHTTP");
netRequest.open("GET", "/ISV/Org_Name/JavaScript/Entity_OnLoad.js", false);
netRequest.send(null);
eval(netRequest.responseText);

CommonAction();

Sunday, March 14, 2010

Trigger N:N Association event and Dassiciation event in CRM Plugin in MS CRM 4.0

-- ===================================================================================================
-- Enable Associate and Disassociate Plug-in Events
-- execute the following query to CRM database, it will add two entries in SdkMessageFilterBase
-- 'DisassociateEntities' and 'AssociateEntities' from SdkMessageBase which is not listed
-- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
USE CrmDev_MSCRM
GO

-- Find the deployments SDK Filter ID for the
-- Associate and Disassociate Entity SDK Messages
DECLARE @DisassociateEntitiesFilterId uniqueidentifier
DECLARE @AssociateEntitiesFilterId uniqueidentifier
SET @DisassociateEntitiesFilterId = (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = 'DisassociateEntities')
SET @AssociateEntitiesFilterId = (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = 'AssociateEntities')

-- Enable the Associate and Disassociate Filters to be valid for custom processing
-- Custom Processing means "you register plug-ins against it"
-- Note: We only do this for the "generic" (OTC == 0) case, just to be safer
UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1 WHERE SdkMessageId = @DisassociateEntitiesFilterId AND PrimaryObjectTypeCode = 0
UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1 WHERE SdkMessageId = @AssociateEntitiesFilterId AND PrimaryObjectTypeCode = 0
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The above query will enable the 'DisassociateEntities' and 'AssociateEntities' message in the plugin registration tool. While registering the plugin select the entity name as ‘none’

While executing the plugin you will be getting four parameter as input parameters from the plugin context along with the other properties :

1. Related Entity1 guid and entity name
2. Related Entity2 guid and entity name
3. Relation hsip name (nothing but intersect hidden N:N entity name)
4. Optional parameter.

Using these value you can implement you logic.

Sample Code for N:N relationship with a custom entity and Sytem User:

public void Execute(IPluginExecutionContext context)
{
try
{
crmservice = context.CreateCrmService(true);

if (context.MessageName == "AssociateEntities")
{

if (context.InputParameters.Properties["RelationshipName"].ToString() == "new_new_customentity_systemuser")
{
string oId = string.Empty;
string SharedUserId = string.Empty;

oId = (context.InputParameters.Properties["Moniker1"] as Moniker).Id.ToString();

SharedUserId = (context.InputParameters.Properties["Moniker2"] as Moniker).Id.ToString();

// write you logic here

}
}

}
catch (System.Web.Services.Protocols.SoapException ex)
{
LogWriter.LogInfo(ex.ToString());
}

catch (Exception ex)
{
LogWriter.LogInfo(ex.ToString());
}
}

Note : As we have defined 'none' as the entity name while registering the plugin, so this plugin will get triggered when ever user will do add existing or romove existing, for any entity. So while writing the logic relationship name is required to identify from where plugin has been triggered.

Referance : http://consulting.ascentium.com/blog/crm/Post533.aspx

Friday, March 12, 2010

Disable CRM form in MS CRM 4.0

Here is the JScript to Disable all the fields/attributes of the CRM From.

function DisableForm() {
var iLen = crmForm.all.length;
for (i = 0; i < iLen; i++) {
crmForm.all[i].Disabled = true;
}
}

HIde Left Nav Bar of CRM from in MS CRM 4.0

Here is the JScript to hide the left navigation area (completly) of any CRM form.

document.all.crmNavBar.parentElement.style.display = "none";
document.all.tdAreas.colSpan = 2;

Maximize the CRM form in MS CRM 4.0

Here is the JScript to maximise the CRM form.

window.moveTo(0, 0);
window.resizeTo(screen.availWidth, screen.availHeight);

Button on CRM form in MS CRM 4.0

There is a workaround of creating a button on the CRM form.
The logic behind is , just place a text box attribute on the CRM form, hide the label/textbox of the corresponding attribute and make the textbox/label (other half) of the same attribute to a button.

Here we have an attribute name new_button (textbox). The first half(label) has been made hidden always and second half of the attribute (textbox) has been converted to a button. And the event has been added to the button.

Example:
crmForm.all.new_ button_c.style.display = 'none'
crmForm.all.new_button_d.innerHTML = "<button class='ms-crm-Button' onclick='ButtonClick();'>Click Here</button>";

ButtonClick = function() {
// write your logic here..

}

Sunday, February 14, 2010

More Than 8 Tabs on a CRM Form in MS CRM 4.0

Friends,

We can have more than 8 tabs on a CRM Form if required. (It is unsupported but very easy to implement).


Procedure :
In: C:\Program Files\Microsoft CRM Server\CRMWeb\Tools\FormEditor find your formeditor.aspx and select edit. Find the JavaScript variable _iMaxTabs and notice that it is set to 8. Change the value to your desired limitation, save and close, reset IIS and you should then be able to create the additional tabs needed from within the forms customization area.


Note : This change will be refelected in all the CRM form.

Wednesday, February 3, 2010

Changing the entity’s default print preview in MS CRM 4.0

http://adrian-alexan.blogspot.com/2009/12/customizing-entities-print-preview-form.html

Monday, February 1, 2010

Custom Entities are not available for Mail Merge in MS CRM 4.0

As we all know in CRM 4.0 most of the entities(including the custom entities) are available for the Mail Merge. But often we see that few custom entities are not available while Mail Merge.

This happen only when we import CRM 3.0 customization to the CRM 4.0 CRM. Actually in CRM 3.0 Mail Merge future was not available for custom entity and custom attribute added to the system entity.
So when we import 3.0 customization to 4.0 still Mail Merge future has not been added to the custom entity. Even we don’t have anything in CRM so that we can enable (Or disable) the mail merge future for an entity from UI.

But there is a work around to enable the Mail Merge future for the custom entity.

Export the entity customization, open the customization.xml in Visual Studio. In bottom of the xml file you will see the xml nodes named like <IsoutlookEnabled>, <IsDuplicateDetectionEnabled> .
Likewise we need to add one more node as <IsMailMergeEnabled> and set the value as "yes".

Save and close the customization.xml and import the same to the CRM. Wait for 2-3 minutes lets synchronized the customization with the outlook. Close and launch the outlook again and start the Mail Merge for the corresponding entity.


Note – These steps we need to follow for every custom entity. Be very care full while making changes in Customization.xml.

Disabled Fields in Bulk Edit in MS CRM 4.0

When we do Bulk Edit in MSCRM, we see few fields has been disabled or in read only format. We can’t provide any input to those fields.

This is because if we have enabled the OnChange event for the fields, those fields appear as disabled on the Bulk Edit form. This is because for multiple records CRM won’t be able to trigger the OnChange event and take the defined action in OnChange Jscript.

Note - Even though we don’t have any Jscript in OnChange event of the field but if we have enabled the OnChange event, the corresponding field will appear as read only.