Thursday, August 2, 2012

Create offline filters for Custom Entity for each user in MS CRM 2011


In almost every CRM implementation we create custom entities. When user goes offline we need to create the offline filters for all the custom entities user wants to take in offline. To achieve this either we train users to create the offline filters or we create some package to do the same.

I achieve the same by creating offline filters in database by inserting new entry in UserQuery for each user for each custom entity.  Below find the Query. 

Declare @UserId nvarchar(100)
declare @OwningBusinessUnit nvarchar(100)
DECLARE @FetchXml nvarchar(max)
Declare @Description nvarchar(100)
Declare @Name nvarchar(100)
Declare @ObjectTypeCode int 

set @FetchXml ='<fetch version="1.0"
mapping="logical" output-format="xml-platform"><entity
name="new_salesgroup"><attribute name="new_salesgroupid" /><filter type="and"><condition attribute="statecode" operator="eq" value="0"
/></filter></entity></fetch>'

set @Description = 'Sales Groups owned by me'
set @Name = 'My Sales Groups'
select @ObjectTypeCode = ObjectTypeCode from EntityView where name='new_salesgroup'

declare cur_accounts cursor for
select SystemUserId from SystemUser where FullName not in ('SYSTEM','INTEGRATION')

open cur_accounts
fetch cur_accounts into @UserId
while (@@FETCH_STATUS =0)
begin
if not exists (select * from UserQueryBase where QueryType = 16 and FetchXml = @FetchXml and StateCode = 0 and Name=@Name and OwnerId = @UserId)
begin
select @OwningBusinessUnit=BusinessUnitId from SystemUser where SystemUserId = @UserId
Insert into UserQueryBase (QueryType,ModifiedOn,ModifiedBy,FetchXml,Description,StateCode,UserQueryId,Name,CreatedBy,ReturnedTypeCode,
OwningBusinessUnit,CreatedOn,OwnerId,OwnerIdType)
values (16, GETUTCDATE(),@UserId,@FetchXml,@Description,0, NEWID(),@Name,@UserId,@ObjectTypeCode,@OwningBusinessUnit,GETUTCDATE(),@UserId,8)
end
fetch cur_accounts into @UserId
end

close cur_accounts
deallocate cur_accounts

Force user to use CRM form for task, email appointment and contact for outlook in MS CRM 2011


Just execute below Query in CRM database, it will update the user settings for all user to use CRM form for task, email appointment and contact in outlook client for CRM.

UPDATE UserSettings 
SET UseCrmFormForTask=1, UseCrmFormForAppointment=1, UseCrmFormForContact=1, UseCrmFormForEmail=1 

Stop Outlook Contact Synchronization with MS CRM 2011

Just execute below Query in CRM database, it will stop outlook contact to sync with CRM.


update userquery set StateCode = 1
where QueryType = 256
and ReturnedTypeCode=2;

Get all user/team an object (account/contact/lead) is shared with in MS CRM 2011

Get all user/team an object (account/contact/lead) is shared with using OrganizationService service.

public void ProcessSharedUser()
        {
            PrincipalAccess[] sharedUsersOfAccount = getSharedUsersforAccount("account", accountId, service);
            if (sharedUsersOfAccount.Length > 0)
            {
                for (int i = 0; i < sharedUsersOfAccount.Length; i++)
                {
                    Guid user = sharedUsersOfAccount[i].Principal.Id;
                    // define your logic here
                }
            }
        }
        public PrincipalAccess[] getSharedUsersforAccount(string entityName, Guid accountId, IOrganizationService service)
        {
            RetrieveSharedPrincipalsAndAccessRequest retrieveSharedRequest = new RetrieveSharedPrincipalsAndAccessRequest()
            {
                Target = new EntityReference(entityName, accountId)
            };
            RetrieveSharedPrincipalsAndAccessResponse retrieveSharedResponse = (RetrieveSharedPrincipalsAndAccessResponse)service.Execute(retrieveSharedRequest);

            return retrieveSharedResponse.PrincipalAccesses;
        }

Tuesday, August 9, 2011

Hide/Show the CRM modules based on roles in MS CRM 2011

We have sale, marketing and service modules in the CRM. We want to show the sale module only to the sales user, marketing module only to marketing users, service module to service users.

Create a custom Entity named “link”.

Edit the sitemap.
In sales for all the SubArea add the Privilege only to “create” on the custom entity “link”.
<Privilege Entity="new_link" Privilege="Create" />
In Marketing for all the SubArea add the Privilege only to “Read” for the custom entity “link”.
<Privilege Entity="new_link" Privilege="Read" />
In Settings for all the SubArea add the Privilege only to “Write” for the custom entity “link”.
<Privilege Entity="new_link" Privilege="Write" />

Save and import the soluntion.

In security roles give the Create Privilege on “link” to all sales roles, Read Privilege on “link” to all marketing roles, Write Privilege on “link” to all service roles.

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();