Tuesday, August 23, 2011

CRM 2011: Notification area

Hello Gang,

I was working on a solution for a client and wanted to put some information into the notification area.  As usual this is not supported by Microsoft.  I wanted to add fields in the notification area that needed to be populated to move a picklist field on the lead object forward.

We need to create some JavaScript (Web Resource) and load it into the form we're working against:


function DC_Notification() {
    var attributes = Xrm.Page.data.entity.attributes;
    
    var notificationsArea = document.getElementById('crmNotifications');
    /*clear out notification area*/
    notificationsArea.SetNotifications(null, null);

    if (notificationsArea == null)
    {
        alert('div not found');
        return;
    }
    /*
    The integer is the notification type
    1 = Error
    2 = Warning
    3 = Info
    notificationsArea.AddNotification("<;unique value>;", 3, "","Your text here");
    */
    /*Create some notifications*/
    notificationsArea.AddNotification("1", 1, "1","Test 1");
    notificationsArea.AddNotification("2", 2, "2","Test 2");
    notificationsArea.AddNotification("3", 3, "3","Test 3");
}

This gives us the following:


The JS code the defines the notification behavior is located in \Microsoft Dynamics CRM\CRMWeb\_static\_controls\notifications.  

You should be able to use the .setNotifications method to clear out a single notification if needed.  I've just never had this need.  If you do drop me a note and I'll figure it out.

Happy slinging!

---------

Update!

With the release of R12 the above JS has some trouble working.  I took the solution from a comment against this post.
function DC_Notification() {
    var attributes = Xrm.Page.data.entity.attributes;
    
    var notificationsArea = $find('crmNotifications');
    /*clear out notification area*/
    notificationsArea.SetNotifications(null, null);

    if (notificationsArea == null)
    {
        alert('div not found');
        return;
    }
    /*
    The integer is the notification type
    1 = Error
    2 = Warning
    3 = Info
    notificationsArea.AddNotification("&lt;;unique value&gt;;", 3, "","Your text here");
    */
    /*Create some notifications*/
    notificationsArea.AddNotification("1", 1, "1","Test 1");
    notificationsArea.AddNotification("2", 2, "2","Test 2");
    notificationsArea.AddNotification("3", 3, "3","Test 3");
}





Friday, May 13, 2011

CRM 2011 and getIsDirty JavaScript function

Hello Gang,

Every once in a while there arises a need to perform some sort of JavaScript calculation/data manipulation on a CRM form.  We all know that the folks at Microsoft were thoughtful enough to write a function that alerts you when you close of a form if there is modified data on it.  However it would be nice to be able to work around that helpful functionality at times.  Say you have code that formats a phone number on form load or performs a JavaScript calculation; it would be nice if the form didn't alert you every time you went to close it.

I pulled out my debugger and went to work.  After digging around for a while I found that this function is what gets called to figure out if the attribute is dirty:

 
function(){return this.$3N_1||this.$N_1!==this.get_value()}


So now it was really easy to solve the problem.  I just had to set the value of $N_1 to get_value().  Real easy...

this._attribute.$N_1 = this._attribute.get_value()

Next I had to create a function to call and perform all of this JavaScript goodness.  See below:

function DC_SetIsDirtyToFalse(attributeNameArray) {

    for(var x in attributeNameArray) {
        var attribute = Xrm.Page.data.entity.attributes.get(attributeNameArray[x]);
        /*set the appropriate values*/
        attribute._attribute.$N_1 = attribute._attribute.get_value();                
    }    
}
 
Now just copy and paste the above JavaScript code into a global.js file and call the DC_SetIsDirtyToFalse function right after you finish performing all of your onload calculations/manipulations.  You'll note that is consumes an array.  So you can pass in a number of attribute names and it will make sure that the getIsDirty() function will return false.

Cheers!

Bit Slinger 

Thursday, April 28, 2011

SSRS Reporting

I recently was asked to figure out to use a more complex security model for reporting in CRM 2011.  The issue is that CRM doesn't have a way of hiding reports from users.  The only choices you have is the security roles that are implemented by the filtered views and by removing the ability for the user to see reports from their roles.  This functionality was not granular enough to meet the security requirement.  To solve the problem I suggested adding an entry to the sitemap that would allow the user access to SSRS reports from inside the CRM application.  We would then use the SSRS security model to get the desired level of granularity.  Here's how I did it:

Edit the site map:

<Area Id="SSRSReports" ResourceId="Area_SSRSReports" Icon="/_imgs/bar_bottom_ico_reports.gif" DescriptionResourceId="SSRSReports_Area_Description" Title ="SSRS Reports">
    <Group Id="Reports" ResourceId="Homepage_SSRSReports" DescriptionResourceId="Homepage_SSRSReports" >
        <Titles>
            <Title Title="Reports" LCID="1033" />
        </Titles>
        <SubArea Id="report_link" ResourceId="report_link_resource" DescriptionResourceId="Reports_SubArea_Description" Icon="/_imgs/bar_bottom_ico_reports.gif" Url="http://crm2011/reports" AvailableOffline="false">
            <Titles>
                <Title Title="SSRS Reports: Accounts" LCID="1033" />
            </Titles>
          </SubArea>
          <SubArea Id="report_link2" ResourceId="report_link_resource2" DescriptionResourceId="Reports_SubArea_Description" Icon="/_imgs/bar_bottom_ico_reports.gif" Url="http://crm2011/reports" AvailableOffline="false">
            <Titles>
                <Title Title="SSRS Reports: Contacts" LCID="1033" />
            </Titles>
        </SubArea>
    </Group>
</Area>

The above xml will add a new entity to the lower left hand corner of the menu.  It will allow users to browse to the SSRS reports.  To edit the sitemap you need to add it to a solution, export the solution, open the .zip, remove the customizations.xml file and make the appropriate edits.  To import the changes put the customizations.xml file back into the .zip and import into CRM.  See this link for more details on the finer points of importing/exporting changes to the sitemap.  If you have users that you don't want to see this link you'll need to apply the appropriate 'Privilege' tag.  See this link for more details.  The tag would allow you to suppress the account subarea for all users unless they had account read privileges.    

Here's a screen shot of the SSRS reports added to the lower left hand corner:


Here's a screen shot of what the user would see once they click the 'SSRS Reports' link:


You can now use the SSRS security model to manage the report permissions to a much more ganular level.  See this link for more details.

Cheers...

Monday, April 18, 2011

Adding custom JavaScript in CRM 2011

Hello Gang,

In this post I want to cover adding JavaScript phone number formatting to a CRM form.  We'll go through adding the library as a web resources and attaching the function to a form attribute.

The first thing that we need to do is create the web resources:

  • Open the customizations tool in crm (opens in new windows)
  • Find the web resources node and open it
  • Click new in the toolbar.  You'll see the below screen pop up:
  •  Name the library, set the desplay name and description if needed.  Set the type to Script (JScript) and the Language to 'English'.  Click the 'Text Editor' button and paste in the following JavaScript:
function DC_FormatPhoneNumber(e) {
    /*Figure out what attribute called this*/
    if(!e) {e = window.event;}
    var element = e.srcElement;
    var value = Xrm.Page.data.entity.attributes.get(element.id).getValue(); 

    /*remove the non alpha characters*/
    value = value.replace(/[^0-9]/gi, "");


    if(value.length == 10) {
        var re = /^(\d{3})(\d{3})(\d{4})$/
        if(re.test(value) == true)
        {
            value = "("+RegExp.$1 + ") " + RegExp.$2 + "-" + RegExp.$3;
        }
    }else if(value.length == 11) {
        var re = /^(\d{1})(\d{3})(\d{3})(\d{4})$/
        if(re.test(value) == true)
        {
            value = RegExp.$1+" ("+RegExp.$2 + ") " + RegExp.$3 + "-" + RegExp.$4;
        }
    }else if(value.length == 7) {
        var re = /^(\d{3})(\d{4})$/
        if(re.test(value) == true)
        {
            value =  RegExp.$1 + "-" + RegExp.$2;
        }
    }

    Xrm.Page.data.entity.attributes.get(element.id).setValue(value);

}
  • Here's a screen shot of the text editor:
  • Now click 'Ok' and save the web resource.  Click publish after the save is complete
  • We are now ready to reference the newly created web resource from a CRM form.  It this case we'll use the account object.  Open the account object inside of the customizations tool:
  • Double click on the 'main form' line and open up the main form for editing.
  • At the top of the form there is a button labeled 'Form Properties.'  Click on this button.  The below window will open:
  •  We need to add the newly created web resource.  Click the first 'add' button in the 'Manage libraries that will be available in the form' section.  The below window will open: 

  • Select the web resource that you created and click 'OK'.  Back on the Form properties screen set the 'Control' field to 'Main Phone' and the 'Event' to 'OnChange.'  Now click the 'Add' button

  • This will bring up the below screen.  In the 'Library' field set the picklist to the web resource name.  In the Function field set the value to 'DC_FormatPhoneNumber' or what ever function you'd like to call.  

  • Click 'Ok.'  You can now save the form and publish it.  Phone numbers will be formated for the 'Main Phone' attribute.
Cheers and happy coding...

Monday, February 7, 2011

C# and custom date formatting

I'm always forgetting how this all works.  So I'm posting this link to a great MSDN article on custom date formatting with c#.

Sunday, January 30, 2011

Installing CRM on a 2008 web server

I was installing CRM 2011 today on a 2008 web server.  CRM requires the indexing service to be installed (for the help files).  I was unable to figure out how to add this feature through the GUI.  So I used the powershell to get this done:

servermanagercmd -install Resource-Manager
servermanagercmd -install Indexing-Service

Tuesday, January 25, 2011

Registering Plugins against Many to Many relationship changes

I recently needed to register a plugin against the creation and deletion of a many to many relationship (N:N) in CRM 4. I did a little searching and found a couple really good blogs regarding this issue:

Have fun...

Wednesday, January 19, 2011

Problem with CRM 4.0 SSRS report with 2008 R2

I was working away on a custom SSRS report for CRM 4.0 and ran into a strange issue when I ran the report from inside CRM:

The report parameter 'P1' is read-only
and cannot be modified

I found the solution on Microsoft's site.  You have to log into the report server and set any CRM related parameters to 'Hide.'  Really???  Let's get this fixed people...

Error when creating a new organization

I was trying to create a new crm organization the other day and ran into a strange error:

Cannot create a file when that file already exists. 
(Exception from HRESULT: 0x800700B7) 

This left me scratching my head for a while as it's not a very helpful message.  I did a quick inventory of the things I had recently changed on the server and realized that the website that runs the report server was off because I had installed SharePoint on port 80.  I just shutdown the SharePoint website, fired up the SSRS website and tried to re-create the new crm organization.  It worked without a hitch...

Have fun,

C

Sunday, January 16, 2011

Using the CRM API to move users to another Business Unit

Hello Gang,

I recently had to write a piece of code to move users to different business units via the CRM API (v4).  To to move the user to a new business unit API uses a SetBusinessSystemUserRequestmessage.  We ran into a problem with this message.  The SetBusinessSystemUserRequest message needs Security Principal to assign the moving users' records to.  If you want to move the user between business units and retain record ownership you can set the Security Principal to the moving user:

SetBusinessSystemUserRequest sbsur = 
new SetBusinessSystemUserRequest(); sbsur.BusinessId = businessId; SecurityPrincipal sp = new SecurityPrincipal(); sp.PrincipalId = movingUserId; sp.Type = SecurityPrincipalType.User; sbsur.ReassignPrincipal = sp; sbsur.UserId = movingUserId;

This code will not work.  Each entity in CRM has a owningbusinessunit column in its base table.  When executing this code the owningbusinessunit column is not updated.  To work around this bug.  Do the following:

SetBusinessSystemUserRequest sbsur = 
new SetBusinessSystemUserRequest(); sbsur.BusinessId = businessId; SecurityPrincipal sp = new SecurityPrincipal(); sp.PrincipalId = Guid.Empty; sbsur.ReassignPrincipal = sp; sbsur.UserId = movingUserId;

Kind of silly if you ask me...  But it works.

Happy coding!

Friday, January 14, 2011

IIS and missing line numbers from stack traces

Hello...

So I ran into an interesting problem today.  I was trying to get line numbers to show up in stack traces.  I made sure that I compiled the code to generate .pdb file and also made sure that the code was compiled without optimization.  I then had some code devide by zero to generate an error.  The line numbers didn't get printed out until I set the IIS authentication to be only 'Windows Authentication' (logged in as a domain admin).  So it looks like there are some permissions needed to get the line numbers in a stack trace.  When I get more time I dig into this more.... 

Happy coding!