Wednesday, March 6, 2013

Apply the run-time filter on top of the security privilege in MS CRM 2011



Apply the run-time filter conditions on top of the security privilege to filter/remove/hide the entity records.

Create a plugin which will trigger on pre (stage) of retrievemultiple (plugin message) of the entity.
Context will return you the Query object which will have entity name and the Query expression details. you can append your filter conditions to query expression to filter the records for the entity.

Below please find the complete Plugin code.
It will trigger on load of every CRM view, so always check the entity name in the plugin and apply the appropriate logic.


public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the execution context from the service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));            
            
             if (context.Mode == 0 && context.Stage == 20 && context.MessageName.Equals("RetrieveMultiple"))
            
                if (context.InputParameters.Contains("Query"))
                {
                    if (context.InputParameters["Query"] is QueryExpression)
                    {
                        QueryExpression objQueryExpression = (QueryExpression)context.InputParameters["Query"];
                        
                        if (objQueryExpression.EntityName == "product")
                        {
                            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                            service = serviceFactory.CreateOrganizationService(context.UserId);
                            ConditionExpression privateFlagCondition;
                            string SaleType = string.Empty;
                            string role = string.Empty;

                            role = getUserRole(context.UserId);
                            if (role.Contains("Sales"))
                            {
                                privateFlagCondition = new ConditionExpression()
                                {
                                    AttributeName = "statustype",
                                    Operator = ConditionOperator.Equal,
                                    Values = { "1" }
                                };                                
                            }
                            

                            FilterExpression newFilter = new FilterExpression()
                            {
                                FilterOperator = LogicalOperator.Or,
                                Conditions = { privateFlagCondition }
                            };

                            objQueryExpression.Criteria.AddFilter(newFilter);
                        }

                    }
                }
            }
        }


Sunday, January 27, 2013

Direct data entry to PrincipalObjectAccess Table in MS CRM 2011

Direct data entry to PrincipalObjectAccess Table using SQL Query.
It is an unsupported approach. Try below SQL query to insert the records in PrincipalObjectAccess table from your table (i have taken the table name as backupTable).


Declare @SystemUser nvarchar(100)
Declare @ObjectId nvarchar(100)
DECLARE @ObjectTypeCode INT
DECLARE @UserType INT
DECLARE @Accessmask INT
DECLARE @InheritedAccessmask INT

declare Cur_SHAREWITHUSER cursor for
Select ObjectId,Principalid, ObjectTypeCode, PrincipalTypeCode, AccessRightsMask, InheritedAccessRightsMask from backupTable -- (CHange the backup table name)
where AccessRightsMask>0 OR InheritedAccessRightsMask>0

open Cur_SHAREWITHUSER
fetch Cur_SHAREWITHUSER into @ObjectId,@SystemUser,@ObjectTypeCode, @UserType, @Accessmask, @InheritedAccessmask

while(@@fetch_status=0)
BEGIN
INSERT INTO PrincipalObjectAccess
(Principalid,ObjectId,ObjectTypeCode,[PrincipalTypeCode],[AccessRightsMask],ChangedOn,
[InheritedAccessRightsMask] ,PrincipalObjectAccessId )
values (@SystemUser , @ObjectId ,@ObjectTypeCode,@UserType,@Accessmask,GETDATE(),@InheritedAccessmask,NEWID())

fetch Cur_SHAREWITHUSER into @ObjectId,@SystemUser,@ObjectTypeCode, @UserType,@Accessmask, @InheritedAccessmask

END

close Cur_SHAREWITHUSER
deallocate Cur_SHAREWITHUSER

Monday, January 21, 2013

Reopened incident count using FetchXML in MS CRM 2011

Get all reopened incident count using FetchXML. It will include those tickets also for which state code changed more than twice.

<fetch aggregate='true'>
  <entity name='incident'>
    <attribute name='incidentid' aggregate='countcolumn' alias='countincident' distinct='true' />
    <filter type='and'>
      <condition attribute='statecode' operator='eq' value='0' />
    </filter>
    <link-entity name="incidentresolution" from="incidentid" to="incidentid" alias="aa" distinct='true'>
    </link-entity>
  </entity>
</fetch>


<fetch distinct='false' mapping='logical' aggregate='true'>
  <entity name='incident'>
    <attribute name='title' alias='IncidentReOpenCount' aggregate='countcolumn' />
    <filter type='and'>
      <condition attribute='statecode' operator='eq' value='0' />
    </filter>
    <link-entity name='incidentresolution' from='incidentid' to='incidentid' alias='aa'>
      <attribute name='incidentidname' alias='IncidentName' groupby='true' />
    </link-entity>
  </entity>
</fetch>












Get shared records for a User/Team in MS CRM 2011


Get shared records for a User/Team:

We get very frequent requirement on how to get the shared records for a User/Team in Plugin/web application using CRM SDK/service.

I prepared below fetchXML which returns all shared records of an entity for a user/Team.

Its a generic fetchXML. Just we need to replace 3 value.
1. Entity name (just replace account with any crm entity).
2. Primary field (for account it is accountid). It is used to join principalobjectaccess and the entity. So just provide the entity primary field in "to".
3. User/Team GUID. (just replace the user/team GUID in value).

<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>
  <entity name='account'>
<link-entity name='principalobjectaccess' to='accountid' from='objectid' link-type='inner' alias='share'>
<filter type='and'>
<condition attribute='principalid' operator='eq' value='E36D3084-8135-E211-AC03-000C29AD15D1' />
</filter>
</link-entity>
  </entity>
</fetch>

Tuesday, January 8, 2013

Hide Entity from Advanced Find in MS CRM 2011


Hide Entity from Advanced Find

As you know You should be able to handle this through security role, don't provide read permission on that entity to particular user, and it will be hidden for him.
But if you have read privilege on the entity and still you want that entity not to be shown in Advanced find then there is no supported way.

But there is an unsupported way to achieve the same. CRM exposes below Boolean property in EntityMetadata to identify which entity should appear in Advanced Find.

EntityMetadata.IsValidForAdvancedFind Property - Gets or sets whether the entity is will be shown in Advanced Find.
AttributeMetadata.IsValidForAdvancedFind Property - Gets or sets the property that determines whether the attribute appears in Advanced Find.

Try below query to hide Account entity from Advanced Find.

update MetadataSchema.Entity set IsValidForAdvancedFind = 0 where Name = 'account'

update MetadataSchema.Relationship set IsValidForAdvancedFind = 0
where ReferencingEntityId = (select MetadataSchema.Entity.EntityId from MetadataSchema.Entity where Name = 'account')
and IsValidForAdvancedFind  = 1


Reset IIS and clear server(and client) cache.

This will hide the entity for all users on the Advanced Find.

CRM 2011 views: getting more than 5000 records


If you access any CRM views for example account page and if it got more the 5000 records you will see “5000+”. You can update this limit by running following query again MSCRM_Config database, so IntColumn contains number of maximum records to be run for CRM. If you put value -1 it will retrieve all the records.

Update DeploymentProperties Set IntColumn=-1 Where ColumnName = 'TotalRecordCountLimit'

So IntColumn contains number of maximum records to be run for CRM. If you put value -1 it will retrieve all the records


Note
1. Above change is unsupported so make sure you apply this change to Dev, Test environment before applying this to Live environment. Also make sure you take back up of database before doing this change
2. This change might impact performance as well since system will retrieve all the records.

Reference : https://community.dynamics.com/product/crm/crmtechnical/b/crmmayankp/archive/2012/06/15/crm-2011-views-getting-more-than-5000-records.aspx

Read Subject sub-child from tree structure in MS CRM 2011


Always its difficult to get the Subject Tree structure to implement your business logic.
I have written CTE to access the sub-child just by passing the Root level Subject.

Create the function in CRM database.

CREATE FUNCTION [dbo].[GetDownSubjectHierarchy] ( @SubjectId NVARCHAR(100))
RETURNS TABLE
AS
RETURN
(
WITH DirectReports (ParentSubject, ParentSubjectName, SubjectId, Title, Level)
AS
(
-- Anchor member definition
SELECT FSU1.ParentSubject,FSU1.ParentSubjectName, FSU1.SubjectId, FSU1.Title,0 AS Level
FROM dbo.Filteredsubject AS FSU1
WHERE SubjectId = @SubjectId

UNION ALL
-- Recursive member definition
SELECT FSU1.ParentSubject,FSU1.ParentSubjectName, FSU1.SubjectId, FSU1.Title, Level + 1
FROM dbo.Filteredsubject AS FSU1
INNER JOIN DirectReports AS d
ON FSU1.ParentSubject = d.SubjectId
)

    -- Statement that executes the CTE
    SELECT Distinct * FROM DirectReports d
)

Execute the below query to get the Subject sub-child of (down) level 2  by passing the subjectid.

SELECT * FROM [GetDownSubjectHierarchy]('35344367-8535-E211-AC03-000C29AD15D1')
WHERE Level=2

Just execute the Query and store the result in array/list/data set/data table as you want to execute your business logic.

You can get the sub-child of any level, just change the value of level (0 is the root subject).

Thursday, January 3, 2013

Adding a view to the sitemap in MS CRM 2011

Follow the below steps to Add a view to the sitemap.
  1. Open the sitemap editor.
  2. Load the Sitemap for your organization.
  3. Add a new Sub Area (under any group you want to add)
  4. Go to the property of the sub area (right pan).
  5. Enter the title, description and define other properties as needed.
  6. Enter the entity Name. It can be the entity you want to load the view or any other entity/custom entity. 
  7. Enter the URL to load the entity view.
  8. Save the Properties and  click on update sitemap.
  9. Refresh CRM to view the Account view added in sitemap.
Example : To load the account view named "Accounts: No Campaign Activities in Last 3 Months" in sitemap use the below URL.  /_root/homepage.aspx?etn=account&viewid={CFBCD7AF-AEE5-4E45-8ECC-C040D4020581}&viewtype=1039

Entity name as : account
Query the CRM database SavedQuery table to get the viewid of any entity. Also you can copy the Viewid from CRM by navigating to the corresponding view and then click on "Copy a link" of current View.
Viewid for the account view named "Accounts: No Campaign Activities in Last 3 Months" is {CFBCD7AF-AEE5-4E45-8ECC-C040D4020581}


Viewtype 1039 is the objecttypecode of the SavedQuery entity.



Note : If the entered viewid doesn't belongs to the corresponding entity, sitemap will load the default view for the entity. 

Reference take from : http://blogs.infinite-x.net/2011/04/18/crm-2011-adding-a-view-to-the-sitemap/

Sunday, December 9, 2012

Release Update News For Microsoft Dynamics CRM 2011


The next CRM release scheduled for Q4 2012 will include:

• Cross Browser Support
• Microsoft Dynamics CRM Mobile
• Office 2013 Compatibility
• New process driven user interface
• Updated opportunity management processes
• Improved case management
• Service monitoring & analytics

Lined up for the first release of 2013, due in Q1 2013 are:

• Further process driven CRM enhancements
• Extended Office 2013 capabilities for CRM
• Sales hierarchy levels
• Service hierarchies
• Server side sync with Exchange


For more information, follow below link :
http://www.preact.co.uk/preact_blog/release-update-news-for-microsoft-dynamics-crm
http://www.preact.co.uk/preact_blog/microsoft-dynamics-crm-cross-browser-update-2013-release-schedule

Thursday, November 29, 2012

Jscript Reference for Microsoft Dynamics CRM 2011


Here’s a quick reference guide covering Microsoft CRM 2011’s syntax for common jscript requirements. 
Most of the examples are provided as functions that you can easily test in the OnLoad event of the Entity form to see a working example. 


Sunday, November 25, 2012

Custom Lookup with multiple entity in CRM 2011

If you create custom lookup in CRM, this lookup is oriented only for one entity.

A very good post to create customer lookup using simple JS.

In a custom lookup we can configure our own entity list. Give a try.

http://mscrmgoodies.blogspot.in/2012/02/custom-lookup-in-crm-2011.html

Friday, August 24, 2012

Set the CRM Form as Read Only in MS CRM 2011


function setFormAsReadOnly() {
    // define the logic here
    disableFormFields(true);
}

function doesControlHaveAttribute(control) {
    var controlType = control.getControlType();
    return controlType != "iframe" && controlType != "webresource" && controlType != "subgrid";
}

function disableFormFields(onOff) {

    Xrm.Page.ui.controls.forEach(function(control, index) {
        if (doesControlHaveAttribute(control)) {
            control.setDisabled(onOff);
        }
    });
}

Custom Button on CRM Form in MS CRM 2011


Create a text box. (or use any unsed field)
Place the field on the CRM Form.
Through the script convert them to a Button on the CRM Form.
Attach the OnCLick event to the Button.
Define your own custom logic on Button Click.


function CreateButton() {
    ConvertToButton('new_testbutton', 'New Button', '100px', OpenSearchPage, 'Button Label');
}


function ConvertToButton(fieldname, buttontext, buttonwidth, clickevent, title) {
    //check if object exists; else return
    if (document.getElementById(fieldname) == null) {
        return;
    }
    functiontocall = clickevent;
    crmForm.all[fieldname].DataValue = buttontext;
    crmForm.all[fieldname].readOnly = true;
    crmForm.all[fieldname].style.borderRight = "#3366cc 1px solid";
    crmForm.all[fieldname].style.paddingRight = "5px";
    crmForm.all[fieldname].style.borderTop = "#3366cc 1px solid";
    crmForm.all[fieldname].style.paddingLeft = "5px";
    crmForm.all[fieldname].style.fontSize = "11px";
    crmForm.all[fieldname].style.backgroundImage = "url(/_imgs/btn_rest.gif)";
    crmForm.all[fieldname].style.borderLeft = "#3366cc 1px solid";
    crmForm.all[fieldname].style.width = buttonwidth;
    crmForm.all[fieldname].style.cursor = "hand";
    crmForm.all[fieldname].style.lineHeight = "18px";
    crmForm.all[fieldname].style.borderBottom = "#3366cc 1px solid";
    crmForm.all[fieldname].style.backgroundRepeat = "repeat-x";
    crmForm.all[fieldname].style.fontFamily = "Tahoma";
    crmForm.all[fieldname].style.height = "20px";
    crmForm.all[fieldname].style.backgroundColor = "#cee7ff";
    crmForm.all[fieldname].style.textAlign = "center";
    crmForm.all[fieldname].style.overflow = "hidden";
    crmForm.all[fieldname].attachEvent("onmousedown", push_button);
    crmForm.all[fieldname].attachEvent("onmouseup", release_button);
    crmForm.all[fieldname].attachEvent("onclick", functiontocall);
    crmForm.all[fieldname].style.lineHeight = "14px";
    crmForm.all[fieldname + '_c'].style.visibility = 'hidden';
    crmForm.all[fieldname].title = title;
    window.focus();

    function push_button() {
        window.event.srcElement.style.borderWidth = "2px";
        window.event.srcElement.style.borderStyle = "groove ridge ridge groove";
        window.event.srcElement.style.borderColor = "#3366cc #4080f0 #4080f0 #3366cc";
    }

    function release_button() {
        window.event.srcElement.style.border = "1px solid #3366cc";
    }
}

function OpenSearchPage() {
    var features = "location=no,menubar=no,status=no,toolbar=no";
    // Open the window
    window.open("http://SearchPage.aspx"_blank", features, false);
}


Monday, August 20, 2012

CRM 2011 Online Fetch XML Reporting


Very informative post on CRM 2011 Online Fetch XML Reporting.

Getting Started with CRM 2011 Online Fetch XML Reporting

More details on Fetch-Xml based Reports

Tuesday, August 14, 2012

Secure / Unsecure Configuration of Plugin Registration tool in MS CRM 2011

Difference between Secure / Unsecure Configuration of Plugin Registration tool in CRM 2011

http://crmdm.blogspot.in/2011/06/difference-between-secure-unsecure.html
Very nice post. I had problem while using Secure Configuration for few users, so i used to change the user context in plugin registration as CRM admin. Was not aware of the route cause.