Showing posts with label crm2011. Show all posts
Showing posts with label crm2011. Show all posts

Thursday, April 26, 2012

CRM UI Tip: Chnaging prefix of custom entities

1. Go to the default publisher record. Its located in the Customizations section of CRM 2011.
2. Locate the prefix box at the bottom left of the form.
3. Update and save.

CRM 2011: Disable Duplicate Detection Save button on Popup

So in my efforts to reduce usage of plug-ins in CRM 2011, I decided to re-evaluate the duplicate detection I had designed.

Quick Overview:
CRM 2011 allows you to create duplicate detection rules that will attempt to find duplicates on criteria you select. However, the user has the ability to save the record regardless. My first inclination was to create a couple of reference entities and utilize the Create and Update message of the plug-ins. After talking with some other CRM guys, I've learned that handling writing of any entity is just too costly.
This technique I will describe below will change the behavior of the duplicate detection view duplicates page. If you don't want to do this proceed no further.

Instructions:
1. Navigate to your CRM instance on your app server.
2. Navigate to \CRMWeb\Tools\DuplicateDetection\ViewDuplicates\
3. Edit this file in Visual Studio or Notepad.
4. Add this line to the ShowPage() javascript member or any member that is called by onLoad():
document.getElementById("btn_id_Ok").disabled="true";
5. Save your change.

This simply disables the button as you can tell. The fun part would be to allow not allow by the current user's role. I suggest using WhoAmI() or any AJAX call to accomplish what you want.

Happy Coding!

Monday, April 9, 2012

CRM 2011: Changing an entity from organization owned to team or user owned without dropping

So after my testing with role based security, it became obvious that the entities that are newly created should be given team or user based ownership to ensure the security would be used correctly.
However what if you already have entities created and are unwilling to drop and recreate the entity?

I have to preface this by saying this is unsupported by Microsoft but will do the trick.
The key is updating not only the customizations xml file but also the EntityView in the SQL database.
To do this you will need the proper role such as System Administrator.

Steps:
1. Gather the necessary xml needed to add owner columns and a team relationship. I find this easier if you can create a sample entity that is user or team owned and copy the specific xml. Always keep a backup of your initial solution to ensure you can roll back.

2. Locate the EntityView inside your database. Navigate to the specific entity in question. Notice the OwnershipTypeMask column. This will be set to 8 and will be updated to 1.

3. Update the EntityView record to OwnershipTypeMask to 1.

4. Once this is done, you can now push your updates to CRM using the solution. The next steps will help you attempt to locate the nodes you need to update.

5. Add the atrributes you gathered from the test entity. These include
OwnerId
OwnerIdName
OwnerIdType
OwnerIdYomiName
OwningBusinessUnit

6. Scroll to the <OwnershipTypeMask> node. If you are using a solution exported from before your sql change, you will have to change the value to say UserOwned.

7. Add to the EntityRelationship section of the file. Again, if you have the test entity do a search for team_ and it should find it. Duplicate this and insert accordingly.

I would only attempt this if you are familiar with modifying the customizations file extensively. One wrong move and you will have to try various routes to revert back.

It can be done but the road is slippery when wet! :)

CRM 2011: Utilizing Role Based Security to hide and show records

One of the interesting features of CRM 2011 is the expansion of the team concept in role based security.
In the past, ownership of a record was on a user or organization basis. However now, a team can now own a record which can affect everything from adding roles to teams instead of users to adding multiple teams to a user.

After testing out various theories using role based security, I have found that for a standard end user, implementing and maintaining roles for each is cumbersome. By removing roles from the user and adding them to the team, maintainability is often easier.

A useful way of implementing teams is allowing access to individual records in an entity. Each team can have certain access, such as read or write, but also you can hide individual records from users who shouldn't have access.

Example:

1.       Create 2 entities.
2.       Create 2 Business units.
a.       These business units represent a client such as Apple and Microsoft.
b.      When creating a business unit, you must declare a parent. The parent in this case will be the master data. An example would be something like software.
3.       Create 2 Teams.
a.       These teams are assigned to their respective Business Unit. This step is optional since creating a Business Unit above also creates a Team with the same name.
4.       Update a standard role in CRM to only show business unit when reading.
a.       This is represented by the yellow half circle.
5.       Remove role from user.
a.       If a role is set to the user, it will override roles implemented in the team.
6.       Add update role to the each team.
a.       This step and the before mentioned are gotchas.
7.       Add three records to the team owned parent entity.
a.       Three records were created, one owned by the master data team. One owned by Apple and one by Microsoft.
b.      Ideally in this step we should only see 2 records. Master and whatever team(s) the user is a part of.

So say your three records consist of Photoshop, Final Cut Studio and Microsoft Office.
You would want Photoshop accessible by both since it runs on both Apple and MS software.
However you wouldn't want to see Final Cut Studio as a MS Employee not MS Office as an Apple Employee.
By following the above example, you can add users to teams associated to each record and they will only see the two specific records.
The reason they both see Photoshop is because its owned by the master BU which both BUs are a child of.

If implemented correctly, this feature can be utilized and all facets of CRM; including xRM, dashboards, reporting, etc.

Also if you have a developer or system admin user and want to see all records, simply add the system administrator role to the user.

If a role is set to a user, it will override any team roles.


Happy Coding!

Tuesday, March 20, 2012

CRM 2011 and OData: Retrieve Example Using Async and Sync Methods

I've found in my transition from CRM 4 to CRM 2011 the ability to use REST and SOAP to be the two biggest improvements to developers. The benefit of both is essentially making the CRM 2011 UI fluid similiar to AJAX. In fact, this example used an AJAX call.

In this example I have successfully used oData to query the db and return a value which can be used to validate ribbon buttons, data, etc.

At the moment this is only configured to retrieve but we can easily extend to create and update.

retrieveRecord: function (id, odataSetName, successCallback, errorCallback) {
        //GetGlobalContext function exists in ClientGlobalContext.js.aspx so the
        //host HTML page must have a reference to ClientGlobalContext.js.aspx.
        var context = this.GetCrmContext();
        //Retrieve the server url, which differs on-premise from on-line and
        //shouldn't be hard-coded.
        var serverUrl = context.Page.context.getServerUrl();
        //The XRM OData end-point
        var ODATA_ENDPOINT = "/XRMServices/2011/OrganizationData.svc";

        //id is required
        if (!id) {
            alert("record id is required.");
            return;
        }
        //odataSetName is required, i.e. "AccountSet"
        if (!odataSetName) {
            alert("odataSetName is required.");
            return;
        }
        if (successCallback != null) {
            //Asynchronous AJAX function to Retrieve a CRM record using OData
            $.ajax({
                type: "GET",
                contentType: "application/json; charset=utf-8",
                datatype: "json",
                url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')",
                beforeSend: function (XMLHttpRequest) {
                    //Specifying this header ensures that the results will be returned as JSON.            
                    XMLHttpRequest.setRequestHeader("Accept", "application/json");
                },
                success: function (data, textStatus, XmlHttpRequest) {
                    if (successCallback) {
                        successCallback(data.d, textStatus, XmlHttpRequest);
                    }
                },
                error: function (XmlHttpRequest, textStatus, errorThrown) {
                    if (errorCallback)
                        errorCallback(XmlHttpRequest, textStatus, errorThrown);
                    else
                        errorHandler(XmlHttpRequest, textStatus, errorThrown);
                }
            });
        }
        else {
            var request = new XMLHttpRequest();
            request.open("GET", serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')", false);
            request.setRequestHeader("Accept", "application/json");
            request.setRequestHeader("Content-Type", "application/json; charset=utf-8");
            request.send();
            var $objJquery = jQuery.parseJSON(request.responseText);
            return $objJquery.d;
        }
    }
 GetCrmContext: function () {
        var params = null;
        var myXrm = null;
        // Get XRM object (if possible)
        try {
            if (typeof (Xrm) != 'undefined' && Xrm != null) {
                myXrm = Xrm;
            }
        }
        catch (ex) {
            // DO NOTHING
        }
        return myXrm;
    }


The method has 4 parameters, 2 of which are required:

1.       The guid of the record. This is found by using the following command:

a.       var _id = Xrm.Page.data.entity.getId();

2.       string of the entity set. i.e. new_AccountSet. As with all javascript, proper capitalization is required.

3.       (optional) success Callback method. If you want to run async, provide a method and be ready to handle the return object.

4.       (optional) failure Callback method. Also, if async, provide a method for failure.



NOTE: If you do not set callback methods, then the method will try to run the query inline. If successful you’ll have to provide it something to set:

                var _id = Xrm.Page.data.entity.getId();
                var objAccount = retrieveRecord(_id, "new_AccountSet", null, null);

If you choose to provide a success method, if might look something like this:

function retrieveEntityCompleted(data, textStatus, XmlHttpRequest) {
    _recordData = data;
}

Monday, June 6, 2011

PreFiltering CRM 2011 Reports

Report prefiltering in CRM 2011 narrows the scope of a report, return faster results and can lead to more revelant data.  Instead of just creating a report parameter, report prefiltering uses the Advanced Find fetch queries.  This allows the creation of end user defined queries while still in CRM.

A sample query:
SELECT name, accountnumber
FROM FilteredAccount as CRMAF_Account


For more information click the link below!

Happy Coding!

Dynamics Blog Link:
http://blogs.msdn.com/b/crm/archive/2009/03/06/microsoft-dynamics-crm-pre-filtering-tips.aspx

Thursday, December 9, 2010

ISVConfig/SiteMap Tip #1: Point to an ASPX page to extend functionality

So far it's been about 2 months since I've been working with the CRM 2011 Beta and while many things have changed drastically, the SiteMap and ISVConfig still adhere to the same rules as in CRM 4.

When creating a link for the Workplace I prefer to use an ASPX page as opposed to a JS page or otherwise. The reason I use it is not only can I embed JS I can also render my own webpages, silverlight controls, etc.

In a real world example,  you are tasked with creating a link in the workplace that not only points to the Active View of the desired entity but also opens a new window that allows you to create an instance of that particular entity. I pointed my SiteMap to an ASPX page that simply ran JS onLoad:

<beginscript language="javascript" type="text/javascript">
//Open popup and set location using CRM global var
window.open('/' + parent.top.ORG_UNIQUE_NAME + '/userdefined/edit.aspx?etc=10002', null);
window.location.href =
'/' + parent.top.ORG_UNIQUE_NAME + '/_root/homepage.aspx?etc=10002&pagemode=iframe';</endscript>


*Note: Replace the begin and endscript tags with script. Blogger apparently doesn't like that tag!

However if I needed some silverlight or a webpage I can easily modify the ASPX page outside of CRM and not have to worry about importing. Using this method provides me enough abstraction to pretty much do what I want.

Tips about the code above:
  • Using the CRM provided JS variables helps out tremendously. Familiarize yourself with them!
  • The pagemode=iframe parameter in the url will give you the correct view to show in the window.location. It removes the ribbon and anything else besides the core view.