XRM
March 29, 2013
CRM Named Biggest Software Investment Priority for 2013-14
Gartner recently revealed that CRM has emerged as the number one priority for application software spending in 2013 and 2014. Besides CRM, ERP and office productivity tools rounded out the top three. The fact that CRM has vaulted past ERP and is projected to drive IT enterprise investments in upcoming years makes sense for many reasons:
Continue reading "CRM Named Biggest Software Investment Priority for 2013-14" »
Posted by Kevin Wessels on March 29, 2013 at 08:34 AM in CRM Best Practices, CRM Business Process, Dynamics CRM 2011, Web/Tech, XRM | Permalink | Comments (0) | TrackBack (0)
March 27, 2013
Understanding FetchXML Outer Joins in Dynamics CRM
I’m often asked about Outer joins and there seems to be a little bit of confusion about them. As you can see from prior posts, I’m a big fan of using FetchXML to access data from Microsoft CRM. So today, I wanted to go over the outer join feature and show you an example of where I recently used one.
Our First Example
To get started, let me show you where I recently used an outer join and why:
This is a widget on a dashboard I recently put together that shows the user’s associated contacts. The images can come from three different sources: LinkedIn, Facebook, or CRM. In my case, the CRM image is an attachment on the contact. (I know most of you are thinking that Edward Anderson is one good looking dude, but let’s focus on the Fetch)
Let’s take a look at the Outer Join:
Notice, at the end of line 20 you’ll see the “link-type” attribute. This specifies our outer join. If this was an inner join, then only contacts with a “Thumbnail” attachment would be returned. We want contacts with AND without a “Thumbnail” attachment which an outer join provides.
Another Example
With CRM 2011, Outer Joins also provide aggregate counts. For example, let’s say you want a list of accounts with the number of opportunities associated to each account. This is quite easily done with an outer join.
In this example, we’re returning the number of opportunities associated to each account.
In a case similar to this (slightly different fetch though), we displayed the results on an HTML web resource. We sorted ascendingly and then via JavaScript only showed accounts where the opportunity count was zero. We were displaying a widget to show all accounts without an opportunity.
Going Forward
When I first was programming with CRM, I mainly used Query Expression. Once I started using Fetch, I’ve never looked back. If you aren’t familiar with Fetch, I strongly recommend learning it as it’s my preferred method for accessing data from CRM. Outer joins and aggregates are just the tip of the iceberg.
In our case, we had two pretty basic examples; however, I hope these conjured up some ideas for some of the problems you are trying to solve in your environment. I hope you enjoy!
Posted by Paul Way on March 27, 2013 at 10:47 AM in CRM Development, Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
January 03, 2013
Using LEGOs to help explain xRM and the Microsoft Dynamics CRM Platform
Microsoft provides the rich foundation, the various interconnecting blocks, and the many special pieces to easily extend Microsoft Dynamics CRM. Using Microsoft Dynamics CRM as a platform and extending CRM to meet new and different business needs is often referred to as xRM.I always enjoyed playing with LEGO® sets when I was a kid. I guess I still do, just look at my handy work for the images in this blog post. Maybe that explains why many enjoy working with Microsoft CRM. The two are similar in that you can build and create completely new and different things from the common set of building blocks.
Let’s take this analogy further. You could say that Microsoft provides three pre-built “Lego sets” with Microsoft Dynamics CRM. These sets include Sales, Service, and Marketing for a compelling Customer Relationship Management solution. You can use the features in Sales and even build on top of it if you wanted like adding your own custom fields. To perform specific tasks, you could use the special pieces that Microsoft provides such as workflow or charts for example. These special pieces fit nicely with the existing blocks. You could even dismantle Sales down to the core blocks and rebuild it your way. As a matter of fact, you could dismantle all three sets and build something completely new and different that had nothing to do with Sales, Service, or Marketing.
Using Legos to explain xRM
Building a solution using CRM that is completely new and has little or nothing to do with traditional Customer Relationship Management (sales, service, marketing) is sometimes a challenging concept to grasp. Hence, the Lego analogy. What occasionally throws people off is the name of the solution, CRM. Microsoft really can’t change the name of CRM at this point. I think that is why the term xRM is so popular and used so widely. xRM is not a product but rather a strategy for innovation using CRM. This makes CRM unique - using CRM as a platform to create solutions. Since this idea is similar to the use of Microsoft Access, I have sometimes heard CRM called “Access on steroids” but that is not a fair description. Not because CRM uses a more powerful Microsoft SQL Server database but that there is so much more in CRM as well as its well documented Software Development Kit (SDK).
Snap it all together with CRM
Microsoft has different offerings for businesses and people such as Outlook, Office, Skype, Lync, SharePoint, and Yammer to name a few. Microsoft CRM helps unify your experiences and connect these solutions together. By “together”, I mean data and a central point for solutions. Companies need one source (one database) to go to for the truth - the complete truth of a customer. Companies desire a true 360 degree view of customer activities, transactions, communications, social interactions - all the layers of customer information. Companies looking to deploy CRM often have customer data, product data, inventory data, financial data, events data, accounts receivable data, you name it, stored all over the place in separate databases and Excel files. Microsoft Dynamics CRM can help integrate to or replace those systems entirely. Just like adding the right Lego blocks, CRM can be extended to bring the data AND the business process of the retired solution directly into CRM. This makes Microsoft CRM a pivotal and key component to consolidating systems, operations, and experiences across a diverse set of screens.
Before you start putting blocks together
As easy as playing with Legos may sound, most companies seek experienced assistance to properly implement and strategically extend CRM. Before you start putting blocks together in CRM, it is recommended that you form a roadmap and plan that is specific to your CRM goals and business drivers. Start strategically by asking the critical “why” questions such as why are we doing this? As you seek help, look for partners that not only have many bright and shiny CRM blocks (some of which may already be put together for you giving you a head start), but more importantly a partner that has the discipline to know when to set those blocks aside to focus on developing your plan for measurable business improvement. Otherwise, without a plan for your CRM, you may end up with a bunch of pretty and flashy blocks snapped together that few wish to use.
CRM is like using Legos
The blocks all fit together – particularly the many unique special pieces – to consolidate business systems and data, connect applications, make it easy to use, and unify experiences.
-----------------------------
The use of the word “Lego” and “Legos” is a registered trademark under the LEGO® brand.
Posted by Will Slade on January 03, 2013 at 09:26 AM in Microsoft CRM Customizations, Microsoft CRM Implementation, XRM | Permalink | Comments (0) | TrackBack (0)
October 26, 2012
JavaScript Fetch XML–Supporting IE10 and Other Browsers
Last year we looked at building FetchXML support with JavaScript and these two blog posts were quite popular. Surprisingly a few people at CRMUG thanked me for these specific blog posts. At CRMUG we got into a great discussion about the indirect benefits of using FetchXML versus OData and that led to someone mentioning the lack of support with my JavaScript code on non-IE browsers. After coming back home to Greenville, I realized the code also fails to work in IE10. Coincidentally we had some users who switched to Windows 8 mention our internal Gantt chart had to be run in compatibility mode to support IE10.
So today we’re going to look into updating the JavaScript FetchXML code to support Chrome, Firefox, Safari and especially Internet Explorer 10.
Why not use OData?
Before we get started though, I want mention that OData is great. The only reason I took the time to build out the initial fetch support was due to the complex querying that Fetch supports. Additionally, aggregates are only available with FetchXML. I still use OData but I often prefer FetchXML due to the flexibility and ease. I also prefer to use FetchXML with my C# code which offers several benefits including consistency when developing.
Secondly, I want to mention that when building your FetchXML you want to use a tool. An easy way is to use the Advanced Find and then click the Download Fetch XML button.
There are other tools available, like Stunnware Tools (which has moved to http://www.donaubauer.com/en/#!CrmInterface). Find what fits you.
Getting Started
The first thing I had to do was switch to using the DOMParser. Granted I’ve done a lot of development on non-IE browsers, but when it comes to XML, Internet Explorer has always done it very well (Gone are the days of XPath my friends).
Note: IE9 supports both parts of this IF clause but will use the DOMParser in this conditional statement.
This next bit of code highlights the slight nuances with the different parsers. The ActiveX approach would call the attribute by “baseName” and the value “text”; whereas, the DOMParser uses “localName” and “textContent” respectively.
This pretty much highlights the changes, but sadly took me a few hours to figure out. I went down the jQuery route successfully, but decided to keep these functions from requiring jQuery to be loaded. I also wasted some time on using RegEx which was for naught due to the XML namespace.
Downloading the Code
One thing I’ve noticed with my other blog posts has been issues related to getting the code downloaded. So I’ve placed everything out on GitHub and hopefully this will be more convenient for everyone.
https://github.com/paul-way/JCL
Finally, I hope this helps you with your IE 10 future and your fancy new Surface (I wish I preordered one). Let me know your thoughts by either commenting at blog.customereffective.com or tweeting me (@paul_way). Coming 10/26…
Posted by Paul Way on October 26, 2012 at 01:00 PM in CRM Development, CRM Javascript, Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
October 03, 2012
Three Megatrends Affecting Today's Mobile CRM Environment
Accessing CRM from a mobile device is one one of the hottest topics in CRM today. In a previous blog post, I outlined four choices available today for using Microsoft CRM 2011 from a mobile device. I referenced three big trends in mobility that are affecting CRM mobile strategy today. A deeper dive into those trends is below.
1. CRM Users Expect More From Mobile Devices. Our information access options are growing. Since the introduction of the smartphone in the early 2000’s, we as mobile device users have rapidly increased our expectations about what we expect to be able to do away from the office computer.
Here’s a brief refresher of recent history:
- 2005: Early smartphone and mobile devices delivered texts, emails, and some awkward browsing. In 2005, your smartphone was a two-way voice communication device, but just a one-way data consumption device. Laptops were powerful and great for consuming and creating (MS Office, enterprise apps). Heavy-duty computing and analysis was still the domain of powerful desktops and servers.
- 2010: Consumer tablets take hold. Tablets, like smartphones, took off when they got really good at helping people consume data and media. EBooks were easy to read and movies easy to download. Laptops and desktops continued to get more powerful, but tablets really become the focus. iOS devices were popular for their perceived ease of use and quick startup times, but out-of-the box they were not ready for the enterprise because they were poor at helping people create the type of work product they expected. Third party app developers stepped in to fill the gap between hardware people liked and the work they needed to produce. (Currently, 4 of the top 5 business apps in the Apple App Store help people access and create MS Office compatible documents).
- 2012: Hybrids Surface. The gap between traditional consumer tablets and laptops is closing. Hybrid devices, such as the upcoming Microsoft Surface are giving users a light-weight, easy-on, and touch enabled device with the computing power of a laptop or desktop. I’m going to read the tea leaves here and predict that users will become less satisfied with trying to use a consumer tablet (and bolt-on business applications) to create work product. They tablet-laptop hybrid model should fill the gap between the devices users want the the work they need to do.
Notice the line is getting higher and flatter. We simply expect more computing power from any and every device we use.
So what does this have to do with CRM? Users today expect to be able to create from almost any device. They know they are limited by the real estate of a small, portable screen, but they expect two-way communication, mobile data entry and mobile content creation. Successful CRM solutions (those focused on productivity gains and user adoption) need to meet the consumption and creation expectations of their users.
2.User Experiences, Across All Forms, Become Unified. If user adoption is one of your key success indicators in a CRM project, then good UX design is going to be one of your best tools. Users are quick to adopt systems that look familiar and support the same conventions across channels. If CRM on my phone has different visual cues than the CRM on my desktop browser then I may be less likely to adopt. If the data architecture is different and results in different steps to access, then I may prefer one form over the other. Either way, more mental chatter is created on the way to get what I need from my system and I become further away from satisfied.
Windows 8 is a unified platform, meaning the same OS running the same apps across tablets, PCs, phones, etc. This creates a high comfort level among users who are looking for seamless experiences across devices. However, the real power of the Universal UX is not in the UI, but in the cloud. Since this new OS was built ‘from the cloud up’, you will be able to synchronize data across all devices. The things you create on your phone, and then tweak on your Surface are instantly available on your desktop system. The in-progress folder on your desktop is always available on your phone.
This approach is not being embraced by everyone. When asked about a tablet/laptop concept Apple’s Tim Cook famously quipped, “You can converge a toaster and a refrigerator, but those aren’t going to be pleasing to the user”.
3. The “App Effect” Creates Demand for Small, Personal Experiences. The App Effect refers to a book that was published by Sogeti Group and focuses on the revolution in business, thinking and behavior that has taken place in the post-PC era. Apps in this context refer to application software written for mobile devices. The shortened name reflects the size of target device (mobile) and the scope of the software.
To illustrate, think about the problem of wanting to know a weather forecast. If you were on your laptop, you would type “weather” in Bing, choose a weather site and then (after you close a pop-up) you would have access to literally 1000’s of options of weather data. Then you would perform another search for a location and activity and you would get what you need. With a weather app, you simply open it and based on your location and previous activity, your forecast is displayed on your mobile device. Your app experience is personal, gives you exactly what you need and it is, by design, not the entire world of weather data.
“So much information enters our brain that it becomes paralyzed, so to speak, and any kind of stimulus to take action can no longer penetrate. From combat situations, we know that an overload of new signals can paralyze the executive function,” notes the authors of The App Effect (p. 43). The answer to information overload is guided process via apps. Some of our most successful stories around mobile CRM are where we designed an app for a pre-defined, line of business process. The app displayed only relevant data from CRM and guided users through on-boarding steps. The platform was CRM, but the user experience was small, personal and exactly what they needed to get their job done.
Posted by Brad Koontz on October 03, 2012 at 08:27 AM in Books, CRM Development, Microsoft CRM Mobile Clients, Mobile Express, Web/Tech, XRM | Permalink | Comments (0) | TrackBack (0)
July 31, 2012
Leveraging Microsoft Dynamics CRM for Health Insurance Exchanges
As the old saying goes “Change is the only constant”. This is especially the case with Health Plan Carriers these days. The Affordable Care Act aims to provide consumers with more choices when it comes to how they buy health insurance. As a result, there could be a significant shift from small and mid-size companies towards discontinuing group health insurance in favor of letting employees buy their own health insurance on one of the state exchanges. Instantly the health plan carriers are faced with a number of challenges to accommodate this large wave of new individual plan prospects. How will we capitalize on the former Group members who are now “warm” prospects for an Individual plan? How will we maintain our brand and drive business through the exchange? And finally, how will we measure our success?
A Customer Relationship Management (CRM) system is a great starting point. Dynamics CRM is an enterprise-class CRM solution that can manage both Group and Individual health plan environments. If you have both Group and Individual customers in a single CRM system then you are a step ahead of many carriers because, if deployed correctly, you should quickly be able to identify your warmest opportunities for those individuals who are leaving group plans and shopping for individual plans. For example, let’s assume that ACME company is a current Group plan customer with 75 employees. If tomorrow ACME decides to move away from the Group health insurance offering in favor of having their employees buy their own insurance on the exchange then you likely have 75 prospective individual customers who are about to begin shopping. It is probably reasonable to assume that most of these 75 new shoppers have never had to buy their own insurance and feel somewhat uncomfortable in the process. But if their former Health Plan Provider were to contact them and let them know that they can stay with their current carrier by just switching to this new individual product maybe this discomfort goes away, or certainly lessens. Consumers like familiarity and they very much dislike having to repeat their story over and over again. Microsoft Dynamics CRM helps carriers maintain the knowledge of their current members and prospective members to ensure that they are doing everything they need to do to maintain the customer, whether on an individual or group plan.
CRM Dashboard: Leads by Source & New Member Count
Posted by Tap Haley on July 31, 2012 at 10:27 AM in Dynamics CRM 2011, XRM | Permalink | Comments (0) | TrackBack (0)
July 20, 2012
4 Steps to Improve Data Consolidation Using Microsoft Dynamics CRM
We often hear from business executives about their concerns with duplicate systems and duplicate data sets. We also hear the desire to create or improve “a grand all-encompassing data warehouse” so executives can better understand customer trends as well as all sorts of business informatics. Mostly, there is a desire for one easy to use consolidated database – the one single database of truth for all customers, contacts, and related information AND accessible across all devices - phone, tablet, laptop.
Here are four steps to improve data consolidation and get to that one database of truth using Microsoft Dynamics CRM.
- Understand why data consolidation is important
- Recognize reasons why data silos occur
- Catalog all the data sets
- Form a strategic plan on how CRM will be leveraged
STEP 1 - Understand Why Data Consolidation is Important
The first step is to understand the value of good customer data. Many executives would already agree that consolidating customer data is critical in business today but there are some that are hesitant to invest in the endeavor or they are unsure where to start. There are many valuable advantages to data consolidation, but in a nut shell, businesses are more effective, more competitive, and have greater insight when they can see one shared customer record that has a deep 360 degree view. This view could include all customer activities, purchases, visits to your website and where they went, accounting information from the ERP, real time data from data aggregators, customer complaints and their resolutions, and yes, the customer’s correct email. That is at the record level. Good data then rolls up for quality analytics. Reporting on your key performance indicators and customer buying trends and even predictive buying just got a whole lot easier now that everything is in one place. Keep in mind, in your current state, you probably have most of this data already, but it is just spread out in too many duplicate databases and Excel files to be usable.
STEP 2 - Recognize the Reasons Why Users Create Data Silos
The next step is to try to stop data silo creation. There is usually a central system in place but then users remove the data they want to an Excel file and continue to update that Excel file outside the central system. Why? Why are users compelled to create Access databases and Excel files? There can be many reasons but usually it is because the central system is hard to use and it is just easier using Excel or their own Outlook. So how do you stop users from creating their own data sets? Improve the user interface is one way and that is where Microsoft Dynamics CRM can help. Although Microsoft CRM uses a powerful Microsoft SQL Server database to handle Big Data, it is the user Interface of Microsoft CRM that will often help reduce data silo creation. Microsoft CRM has the potential to be designed putting the user first – meaning the interface is clean and purpose driven. It also helps that Microsoft Dynamics CRM can be accessed from within the very tools that frequently drive silo creation to begin with – in this case Excel and Outlook. All of CRM can be accessed from Outlook and there is one click in CRM to bring data to Excel.
STEP 3 - Identify and Catalog all the Data Sets
Next, start to identify all your data. Data you have and even the data you don’t have. Catalog all the In-house data like main central systems, the many rogue Access databases and Excel files, as well as website databases and SharePoint Lists and so on. Just focus on the data that is being managed and updated away from a central database. Think also about the data you may not have now but could get from an online subscription to a data aggregator such as InsideView to sync real time business and social data or Trillium to validate and clean your data for total data quality.
STEP 4 - Form a Strategic Plan for Data Consolidation and How Best to Leverage CRM
The last and most important step is to form a long term strategy plan. This is where some companies may need assistance. Without going into too much detail, the plan should attempt to include what data will be migrated and what will be integrated.
· Migration: With data migration, this is the data that will be completely moved permanently to live in CRM. These aren’t just the rogue Excel files; this could potentially be retiring some completely separate business applications – meaning move the data along with the functionality and business process to CRM using the innovative xRM approach to duplicate functionality where logical.
· Integration: What data then gets integrated in and out of CRM? Is the integration one way (asynchronous) or two way (synchronous)? What are the outside data sources and services that will be utilized? What data integration tools such as Scribe may be needed?
The strategic plan may also include new reporting needs, how data will be displayed across devices, and what users get to access and not access based on their security. As you can see, having a well thought out plan divided into logical phases will provide the long term blue print and framework for continued data success.
If you understand the value of one consolidated database and you know why users make data silos and you have cataloged all your data sets and then formed and documented a well thought out plan that leverages Microsoft Dynamics CRM, well then, you should be on your way to improved data consolidation.
Posted by Will Slade on July 20, 2012 at 10:05 AM in CRM Business Process, Dynamics CRM 2011, Microsoft CRM Implementation, Microsoft SQL Server, Scribe, XRM | Permalink | Comments (1) | TrackBack (0)
June 19, 2012
CRM 2011–JavaScript Events
For the experienced developers, you might be quick to bind to HTML objects to handle events. Stop! Read my blog! And roll!
For those of you just picking up JavaScript, an Event is a way to “trigger” code to execute when something happens. For example, if a user selects something in a drop down you can use an “OnChange” event to show an otherwise hidden section. Events are a great way to enhance the user experience as well as to improve the quality of data input. Today we’re going to look at the events supplied by CRM 2011 and how to use those in a coherent way without having to bind to an event in a crazily unsupported fashion.
Posted by Paul Way on June 19, 2012 at 10:19 AM in CRM Best Practices, CRM Development, CRM Javascript, Dynamics CRM 2011, XRM | Permalink | Comments (0) | TrackBack (0)
February 06, 2012
XRM 2011 JavaScript: Another 101 Lesson in Microsoft Dynamics CRM 2011
When you’re learning JavaScript, you’ll often come across the need to do something to every field on the form. When you do, it’s important to have efficient code to make such widespread changes so the user doesn’t have to wait for the JavaScript to finish. This lesson consists of several parts, some of which you’ll probably already know but hopefully there are some things in here for everyone.
Setting up our Environment
First thing first, open your CRM 2011 development environment and browse to an account form. Once the account form is open, hit F12 on your keyboard. A window should popup that looks like this:
Continue reading "XRM 2011 JavaScript: Another 101 Lesson in Microsoft Dynamics CRM 2011" »
Posted by Paul Way on February 06, 2012 at 08:25 AM in CRM Best Practices, CRM Development, CRM Javascript, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (1) | TrackBack (0)
January 13, 2012
XRM 2011 - Microsoft Dynamics CRM 2011 Style Buttons
There is already some code floating around to create a 4.0 style button inside of CRM 2011. The button we’re creating will instead create a CRM 2011 style button (i.e. “Example Button”).
Continue reading "XRM 2011 - Microsoft Dynamics CRM 2011 Style Buttons" »
Posted by Paul Way on January 13, 2012 at 08:53 AM in CRM Best Practices, CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (4) | TrackBack (0)
January 12, 2012
CRM 2011 - iFrames & Saving
After spending time on several of the CRM forums, I noticed a few people having trouble with iFrames and saving data inside of the iFrame. While a forum post is a little difficult to write a full response, I wanted to share some insight on capturing the form save event to then trigger a save event inside of your iFrame.
From a business case, this is a fantastic way to tie multiple systems together. If all you are doing is syncing data, then look first at a plugin or scribe. However, if you are looking for the user to interact with multiple systems simultaneously, then an iFrame is a wonderful way to integrated with an existing system. A good example might be where CRM is only storing the summary information and the iFrame contains the details. The user may update the details which should save both the CRM record and the details of the web site.
Posted by Paul Way on January 12, 2012 at 01:22 PM in CRM Javascript, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Online, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (3) | TrackBack (0)
January 03, 2012
Microsoft Dynamics CRM 2011 – Pre-Populated Emails (Alternative Approach)
Recently, we came across the need for a single-click email feature on the ribbon of a custom entity. The idea was to be able to share CRM data as quickly and easily as possible. Another interesting caveat was the client wanted to have the email come directly from Outlook.
For those of you old enough to have used the internet before the iPad, you may recall that fancy-dancy “mailto” feature. (Granted I’m only 29 but my Omron body age says I’m 50 ).
Back to the point at hand though, CRM already has a few built in email features. Our situation calls for something a little different.
What’s Installed By Default
CRM already has the feature of sending a link to the CRM entity you’re working with.
CRM also has a really nice Email Template feature.
Which can automatically mail-merge information pertaining to the entity to eliminate any of that “automated” feel.
What We Need
Our situation is somewhat unique, but really we want both features combined. We want to open a new message like the link feature: inside outlook and with one click. However, we need more than just the link. We want to have a brief summary of the call report with a link to it.
Here’s an example email of what we’d like to send:
Adding the Button
The first thing we need to do is add the button to the ribbon like so:
If you are unfamiliar with the ribbon, Microsoft offers some really nice walkthroughs. I’d start with http://msdn.microsoft.com/en-us/library/gg334341.aspx.
For our situation, the XML that matters is our Action
<Actions> <JavaScriptFunction Library="$webresource:cei_example.js" FunctionName="emailContact" /></Actions>
Adding our JavaScript
At this point, the button should be on the form. From here, we need to add the JavaScript to open our populated email message.
To do this, add to the Form OnLoad events the following function:
emailContact = function() {
if (Xrm.Page.data.entity.getId() != null) {
var sRptID = Xrm.Page.data.entity.getId().replace('{', '').replace('}', '');
var sLink = "http://paul.customereffective.com/userdefined/edit.aspx?id=" + sRptID + "&etc=10011";var sSubject = 'Contact - ' + Xrm.Page.getAttribute("firstname").getValue() + ' ' + Xrm.Page.getAttribute("lastname").getValue();
var sCustomer = '';
if (Xrm.Page.getAttribute("parentcustomerid").getValue().length > 0){
sCustomer = Xrm.Page.getAttribute("parentcustomerid").getValue()[0].name;
}
var sBody = '---\n\nCustomer:\t' + sCustomer + '\n\n' + sLink + '\n\n---';
var sMailTo = 'mailto:?subject=' + escape(sSubject) +
'&body=' + escape(sBody);parent.location=sMailTo;
} else {
alert('You must save the contact before emailing.');
}
}
Note: If you change the name of the function, make sure it matches the name inside your Ribbon XML.
What about Window.Open
If you use Window.Open to trigger the email (or OpenStdWin), the user will get a blank IE page inside of Outlook. By using the parent.location for your mailto, you’ll have a consistent user experience across IE and Outlook.
Seeing the Final Results
Now whenever a user wants to share a call report, they can easily hit the “Email Call Report” button. Add any of the fields you want.
For our needs I ended up with the following; however, this technique can add whatever field you’d like.
Well this isn’t a tool in the toolbox I’d use daily, it can be valuable when the situation calls for it. I hope you enjoy!
Posted by Paul Way on January 03, 2012 at 01:58 PM in CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM for Outlook, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
December 23, 2011
Dynamically Generating URLs for Cached Web Resources for Microsoft Dynamics CRM
CRM 2011 supports several methods for accessing web resources. These includes using the $webresource: directive when referencing web resources from the site map or ribbon, a relative URL, or an absolute URL. While this allows a web resource to be accessed in virtually any situation, if a scenario arises in which an absolute URL must be used, the benefit and speed of retrieving the cached web resource is lost. The reason for this has to do with the caching mechanism used by CRM for web resources. Take the following URL that could be generated by CRM when using the $webresource: directive or when a web resource is included on a CRM form as an example.
https://yourorgname.crm.dynamics.com/%7B634594655730000000%7D/WebResources/cei_/test.htm
Notice the magic number that is highlighted in the example URL. CRM automatically inserts this token into the URL and the CRM 2011 SDK indicates that this magic number is a GUID value that ensures the latest cached version of the requested web resource is used. If you use a tool like Fiddler to examine the response returned by the GET request for the web resource, you will notice that it has caching headers that set it to be cached for one year. If the magic GUID value is removed from the URL so that the URL would resemble an absolute URL to the web resource, the response returned by the GET request for the web resource, depending upon your version of CRM, will be a non cached version or a version that is cached for a short amount time such as 24 hours.
This caching functionality provided by CRM is great, but what if you need to dynamically generate the URL for a large web resource? It would be preferable to access the cached version, but in order to do that you need the magic GUID value. Fortunately, the magic GUID value is not magic at all, and not actually a GUID. The caching token inserted into the URL for the web resource by CRM is merely a timestamp that represents the modified time of the last web resource to be modified. The timestamp is represented as ticks in UTC time as generated by the .NET Framework.
Now in order to get the URL for a web resource, it is merely necessary to generate this timestamp. The example function below shows exactly how to generate the timestamp for the caching token using a quick call to the REST service in CRM and a simple conversion from the JavaScript Date object to the timestamp value.
1: function getWebResourceUrl(webResourceName) {
2:
3: var dotNetMillisecondsAt_1970_01_01 = 62135596800000,
4: ticksPerMillisecond = 10000,
5: lastWebResourceModifiedOn = null,
6: webResourceCachingToken = null,
7: webResourceUrl = "/WebResources/" + webResourceName;
8:
9: // Retrieve the modified date of the last web resource to be modified
10: $.ajax({
11: async: false,
12: beforeSend: function (xhr, settings) {
13: xhr.setRequestHeader("Accept", "application/json");
14: },
15: contentType: "application/json; charset=utf-8",
16: datatype: "json",
17: global: false,
18: success: function (data, textStatus, xhr) {
19:
20: // Extract the modified date from the results
21: lastWebResourceModifiedOn = +(/\/Date\((\d*)\)\//.exec(data.d.results[0].ModifiedOn)[1]);
22:
23: // Convert the JavaScript Date value to the caching token value
24: webResourceCachingToken = (lastWebResourceModifiedOn + dotNetMillisecondsAt_1970_01_01) * ticksPerMillisecond;
25: },
26: type: "GET",
27: url: Xrm.Page.context.prependOrgName("/XRMServices/2011/OrganizationData.svc/WebResourceSet()?$select=ModifiedOn&$orderby=ModifiedOn%20desc&$top=1")
28: });
29:
30: // If we have a caching token value then prepend it to the current URL.
31: if (webResourceCachingToken !== null) {
32: webResourceUrl = "/%7B" + webResourceCachingToken + "%7D" + webResourceUrl;
33: }
34:
35: // Return the URL to the web resource prepended with the organization name if necessary
36: return Xrm.Page.context.getServerUrl().replace(/\/$/,"") + Xrm.Page.context.prependOrgName(webResourceUrl);
37: }
Notice the function takes the name of a web resource, e.g. cei_/mypage.htm, and prepends it with the caching token, organization name if necessary, and the server URL. Now this function can be used to dynamically generate the URL for a web resource and still retrieve the cached web resource. Of course, there could be some improvements made, such as wrapping the call to retrieve the caching token in a closure so that it is only retrieved the first time a URL is generated, but I will leave that up to you.
**Note, that generating a URL in this manner is not supported by Microsoft and the caching mechanism used by CRM for web resources could be changed in the future.
Posted by Nick Doriot on December 23, 2011 at 09:28 AM in CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
December 16, 2011
Setting Lookup Field Values on Microsoft Dynamics CRM Forms with Silverlight
Recently, I have found myself developing a lot of Silverlight customizations for CRM 2011. If you happen to find yourself in the realm of Silverlight and CRM you will more than likely have the need to interact with the CRM form in context. The tool that Silverlight provides for interacting with the hosting web page is the HTML Bridge. The types and methods exposed by the HTML Bridge allow access to the hosting pages DOM and JavaScript objects. By utilizing the types and methods of the HTML Bridge it is possible to access the Xrm JavaScript object of the CRM SDK to set field values so let’s take a look at how the HTML Bridge can be leverages to do so.
There are a couple of different methods that can be used when accessing the Xrm object of CRM. One is to create an object model around the Xrm object that mirrors the Xrm object in JavaScript and the other is to use a dynamic object in Silverlight. I am going to use a dynamic object in this instance as it requires much less code, however, the downside is that there is not any compile-time type checking and errors may not be discovered until runtime.
1: // Get a reference to the Xrm object
2: dynamic Xrm = HtmlPage.Window.GetProperty("Xrm");
3:
4: // Set a string field value
5: Xrm.Page.getAttribute("cei_stringfield").setValue("Hello World!");
6:
7: // Set a floating point field value
8: Xrm.Page.getAttribute("cei_floatfield").setValue(3.14159);
Notice in the previous example I simply use the HtmlPage.Window object to get a reference to the Xrm property on the hosting page. Also, notice that the local Xrm object is declared as a dynamic variable. Declaring the local Xrm object as a dynamic object allows the object to bypass static type checking. At this point, it is simply a matter of using the Xrm object just as if it were being used from JavaScript. In line 5 of the previous code snippet I have done just that. A reference to the cei_stringfield attribute is obtained and the value is set to a “Hello World!”. In line 8, the same approach is used to set a numeric field.
After seeing how the previous snippet of code works, you may think, as I did, that setting a lookup field’s value could be done using the same technique with an anonymous array object that mimics a lookup fields value as the argument to the setValue function. However, calling the setValue function for a lookup field will not work from within Silverlight due to the way the HTML Bridge marshals managed objects to JavaScript. Fortunately, there is another method that can be used, although it is not quite as elegant. The following snippet shows how a lookup field can be set from within Silverlight.
1: private void SilverlightSetLookupValue(string fieldName, Guid? id, string entityLogicalName, string name)
2: {
3: // Define eval statements for setting lookup to a value and null
4: string setLookupJscript = @"Xrm.Page.getAttribute(""{0}"").setValue([ {{ id: ""{1:B}"", typename: ""{2}"", name: ""{3}"" }}])";
5: string setLookupToNullJscript = @"Xrm.Page.getAttribute(""{0}"").setValue(null)";
6: string evalStatement = null;
7:
8: // Set the statement to be evaluated based upon the value of the id argument
9: if (id.GetValueOrDefault().Equals(Guid.Empty))
10: {
11: // Setting the lookup to null
12: evalStatement = string.Format(setLookupToNullJscript, fieldName);
13: }
14: else
15: {
16: // Setting the lookup to a value
17: evalStatement = string.Format(setLookupJscript, fieldName, id, entityLogicalName, name);
18: }
19:
20: // Set the lookup
21: HtmlPage.Window.Eval(evalStatement);
22: }
That’s right, I broke out the big dog, the EVIL EVAL function. As I said previously, it is not the most elegant solution, however, sometimes the heavy hitters like the eval function need to be dusted off and it works beautifully. As you can see, the method in the snippet builds the JavaScript necessary to set a lookup field dynamically as a string and then evaluates the string on the hosting page using the HtmlPage.Window.Eval method within Silverlight.
Posted by Nick Doriot on December 16, 2011 at 09:55 AM in CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
December 08, 2011
Using the CRM 2011 REST Services and Deep Insert to Create Activities
One of the nice features of CRM 2011 is the REST based OrganizationData service. Lately, I have found myself using the REST service more often as it provides a simpler and cleaner method of accessing data from client side JScript. The REST service also provides the ability to do deep inserts of entity and related records. This capability can be leveraged to provide an elegant solution to creating activity records using client side JScript.
In my particular use case, I needed to create a new email activity from the currently logged in user with the regarding record set to a new custom entity record. It would have been possible to issue a couple of calls to the REST service that created the regarding record and then the email, but it is just as easy to create the email and related records in one call avoiding the need to clean up any records should one of the calls fail.
The first thing that needs to be done is to create the activity party record for the from field on the email. The activity party is a separate entity that stores all of the parties related to an activity, i.e. sender, recipient, etc. The activity party data needs to be specified as an array of activity party entities. The following snippet creates an activity party record for the from field on the email.
1: // Create the activity party records
2: var emailPartyEntities [{
3: PartyId: { LogicalName: "systemuser", Id: Xrm.Page.context.getUserId() },
4: ParticipationTypeMask: { Value: 1 }
5: }];
As I mentioned earlier, I also needed to create a custom entity record that will be set as the regarding on the created email. In my case, this custom entity is used to track an email thread. Since this is a N:1 relationship for the email entity, the record created does not need to be stored in an array and is merely an object with properties specifying the fields of my custom entity.
1: // Build the activity thread entity
2: var activityThreadEntity = {
3: cei_Department: { Value: 29669000 },
4: cei_Subject: "Activity Thread for Account",
5: };
Finally, I need to build the email entity that will be passed to the REST service during the create request. In order for the deep insert to work, the activity party array and the activity thread object created earlier will need to be set to properties on the created object that specify the relationships to the related entities as shown below.
1: // Build the email record
2: var emailEntity = {
3: Subject: "Test Email",
4: cei_activitythread_Emails: activityThreadEntity,
5: email_activity_parties: emailPartyEntities,
6: };
In the previous snippet, notice that the activityThreadEntity object and the emailPartyEntities array are set to their corresponding relationships, i.e. cei_activitythread_Emails is the name of the N:1 relationship for my custom entity to the regarding field on the email entity, and email_activity_parties is the name of the 1:N relationship from the email entity to the activity party entity.
Now that all of the required objects have been created we can issue the call to the REST service to create the email and related records. The following snippet utilizes a jQuery plugin from our custom JScript library. It is merely doing a POST request to the REST service with the data for the POST being the JSON serialized emailEntity object that was created.
1: // Create the email by POSTing the data to the REST service
2: var createResult = $.xrm.orgData.buildRequest().
3: async(false).
4: dataset("Email").
5: data(emailEntity).
6: create();
7: if (createResult.errorExists) {
8: alert("There was an error creating the email.");
9: } else {
10: alert("Success!");
11: }
That’s it! It really is that simple. The email, activity party, and regarding records were all created in a single call.
In this example, I utilized the deep insert capabilities of the REST services to create an email, but the deep insert feature can be used on any entity in order to create multiple records in a single call. The biggest hurdle that you will probably run into is determining whether to create the related records as JScript objects or arrays of objects. Just remember that 1:N relationships require and array of objects and that N:1 relationships require a single object.
Posted by Nick Doriot on December 08, 2011 at 08:05 AM in Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (1) | TrackBack (0)
October 26, 2011
CRM 2011 and Windows Identity Foundation
This is a quick reminder that if you are deploying custom applications on servers other than where you install CRM, you need to manually install WIF (Windows Identity Foundation). These pieces are not included in the .Net Framework 4. Here is a sample error message you may receive if you run a custom application without WIF installed.
You can download and install the appropriate WIF from here. I also noticed that Microsoft upgraded the download site for this piece. You no longer need to know what OS you are on to download the appropriate file.
Posted by Sean Shilling on October 26, 2011 at 03:30 PM in CRM Development, Microsoft CRM Customizations, XRM | Permalink | Comments (0) | TrackBack (0)
October 25, 2011
Microsoft CRM 2011 -- When to Use an iFrame vs a Web Resource
Sit back and relax a bit because we aren’t going to get into any code today. Instead we are going to take a higher level look at some interesting caveats within CRM 2011.
Even if you aren’t a developer, if you customize the form with Web Resources or iFrames, this should be helpful to you.
Silverlight
First of all, I came across this due to a colleague using Silverlight. Like many of you out there, we do some crazy stuff with Silverlight. Silverlight is awesome and can be leveraged to do some serious heavy lifting. I’m actually more of a JavaScript guy, but until JavaScript supports multi-threading, Silverlight cannot be overlooked.
When using Silverlight, you have three options to put Silverlight on your form:
- Embed a Web Resource and select the XAP file (Figure A – 1)
- Embed a Web Resource and select an HTML wrapper (Figure A – 3)
- Embed an iFrame and enter an HTML wrapper (Figure A – 4)
Figure A (Before)
If you are embedding the XAP file (1), then all is good in the world and everything should behave like any other control. Problems only arise with the magnitude of what you are doing. Let’s say you have a couple of JavaScript resources you need to support your Silverlight control to talk to the form. If that’s the case, setup and maintenance is a little more cumbersome.
To make life easier for you and your customer, you could upload your own HTML file with everything self-contained. Now that you have everything nicely contained in an HTML web resource, we can either insert a web resource and select our HTML file (3) or we can use an iFrame and point to our HTML file (4). What’s the difference? Watch what happens when I select a Related entity (e.g. Activities) and then come back to my form. Notice how the Web Resource is blank? That’s because the form reloaded my web resource.
Figure B (After)
HTML
Ok, some of you out there may be saying, “but I don’t use Silverlight”. That’s fine, but this actually applies to HTML files as well. When embedding an HTML page, again you can either use a web resource or an iFrame. If you choose a web resource however, the page will reload when toggling to a new related entity. If you choose an iFrame, it will NOT reload (look back at Figure A&B paying attention to 2 and 5).
Well why?
This is all about your purpose. If you have a HTML page or Silverlight control that is read-only (e.g. graphs, charts, or accessing another system), then a Web Resource would be the better method most of the time. If you are expecting users to input data, then you’ll want to use an iFrame instead of a Web Resource so that the data is persistent. For some of you this could be a gotcha and for others it can be a feature. Hopefully none of your users are on the wrong end of this! Enjoy.
Posted by Paul Way on October 25, 2011 at 07:43 AM in CRM Best Practices, CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
August 29, 2011
CRM 2011 Form Customization (Part 2)
A while back we looked at customizing the CRM 2011 header and footer. I got some really positive feedback, but some people were tripped up. Troubleshooting via blog is difficult, so whenever you have problems feel free to tweet me (@paul_way). Today, I’m going to go into great detail of changing the form again, but this time we’re going to add a new twist. Take a look at the before and after:
Before
After
Now some of you may be wondering what I changed. First, we still have the light blue shading on the header. Secondly, we moved the footer to the left navigation. User’s may never request changing the color of the forms, but that was intended to show you that you could style the forms any which way you wanted. Moving the footer to the left hand navigation is quite practical. Some users may be faced with smaller screen resolutions and this will really free up space if you intend to put a lot of information in the footer (especially if you are adding to the header already).
Step-by-Step
Setting up our Web Resources
The first thing you’ll need to do is create a solution. I called mine “Form CSS Customization”. In it we are going to add two web resources.
For our initial web resource we’ll create is a CSS file:
.ms-crm-Form-HeaderContainer {
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffB3CAEC, endColorstr=#fff6f8faE)
}
.ms-crm-Form-Footer {
display: none;
}
.ftLabel {
color: #999;
font-style: italic;
padding-left: 4px;
}
.ftValue {
padding: 2px 2px 8px 12px;
text-align: left;
}
#myCustomNav { padding: 2px }
.myNavFoot {
margin-left: 4px;
border: solid 1px #999;
width: 99%;
}
Take note of the name of your CSS file, as we’ll use this in a minute. The CSS file contains the shading on the header as well as some custom table formatting that we’ll use with our JavaScript file.
Now, let’s add our JavaScript file:
function load_css_file(filename) {
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", filename)
document.getElementsByTagName("head")[0].appendChild(fileref)
}function myFormOnLoad() {
load_css_file('/WebResources/cei_/css/case.css'); // don’t forget to change the file!
moveFooterToNav();
}function moveFooterToNav() {
var tbl = document.getElementById('crmNavBar');
var row = tbl.insertRow(tbl.rows.length);
var cFoot = row.insertCell(0);
var txt = document.createTextNode('testing...');
cFoot.appendChild(txt);
cFoot.id = 'myCustomNav';
document.getElementById('myCustomNav').innerHTML = "<table class='myNavFoot' cellspacing='0' cellPadding='0'>" +
"<tr><td class='ftLabel'>Created</td></tr>" +
"<tr><td class='ftValue'>" + document.getElementById('footer_createdby_d').childNodes[0].innerHTML +
"<br />" + document.getElementById('footer_createdon_d').childNodes[0].innerHTML + "</td></tr>" +
"<tr><td class='ftLabel'>Modified</td></tr>" +
"<tr><td class='ftValue'>" + document.getElementById('footer_modifiedby_d').childNodes[0].innerHTML +
"<br />" + document.getElementById('footer_modifiedon_d').childNodes[0].innerHTML + "</td></tr>" +
"</table>";}
The JavaScript file is doing two important things. First, it is injecting the CSS file into the header of the page. This basically tells the browser to pickup the CSS file as if it was always part of the page. After loading the CSS file, the JavaScript will append a table to the left area nav bar. This table is completely custom and you can style it any which way you want. Be careful using Xrm.Page.getAttribute() here, because even though the field is in the footer it may not be accessible to the Xrm object. In my case, the attributes I’m using were not on any of my tabs.
Changing the JavaScript
You must change the “load_css_file” function to contain your specific web resource. To find the web resource name, it’s easiest to look at the CSS web resource inside of CRM:
Configuring the Form
Now we need to go to the form we are customizing. The first step is to add everything we want to onto the footer.
Next, we’ll edit the form properties.
When editing the Form Properties, we’ll need to add the JavaScript library and add our onLoad function to the Form OnLoad. In our example, the function we’re using is called “myFormOnLoad”.
After this, we simply hit OK, Save, and Publish.
Reviewing the Finished Product
As you can see, we made subtle changes to improve the overall look and feel for the user. We also provided a real-life situation where you may need to squeak out some additional room for the user. Hope you enjoy!
Posted by Paul Way on August 29, 2011 at 03:58 PM in CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (6) | TrackBack (0)
August 23, 2011
CRM 2011–Changing the Form Header and Footer Colors
CRM 2011 has a beautiful default theme. Microsoft has already organized the CRM 2011 folder structure to support themes, but currently only supplies the Silver theme. Office 2010 on the other hand contains Silver, Blue, and Black.
Today we aren’t going to modify the entire theme, but modify the form header and footer. The code I’m going to include is a small gradient, but you could choose a solid background or any color you’d like. I was going to use a Clemson, I mean Customer Effective, Orange, but instead focused more on the blue theme look.
Before
After
Adding our CSS Web Resource
Granted this change was very minor, but you could do about anything you wanted to with it. To accomplish this basic change you must first upload a CSS web resource (I named mine new_header.css) with the following styling:
.ms-crm-Form-HeaderContainer{
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffB3CAEC, endColorstr=#fff6f8faE);
}.ms-crm-Form-Footer{
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ffB3CAEC, endColorstr=#fff6f8faE);
background-image: none;
}
Note: The filter property is an IE specific CSS attribute. It isn’t supported in any other browsers (they will just ignore it), but Internet Explorer 7+ supports it just fine.
Modifying the OnLoad
Our next step is to modify the onLoad to inject the CSS file. We’ll do this by adding the following JavaScript to a web resource:
function load_css_file(filename){
var fileref = document.createElement("link")
fileref.setAttribute("rel", "stylesheet")
fileref.setAttribute("type", "text/css")
fileref.setAttribute("href", filename)
document.getElementsByTagName("head")[0].appendChild(fileref)
}function myFormOnLoad(){
load_css_file('/WebResources/new_header.css');
}
Changing the Form Properties
Finally we need to change the form properties to include this JavaScript web resource in the library and add our “myFormOnLoad” function to the OnLoad Event for the Form:
Conclusion
After going through this blog, hopefully you will see how easy it is to change the form header, footer, or anything else. By embedding a CSS file, our ideas are our only limits. Hope you enjoy!
Posted by Paul Way on August 23, 2011 at 08:00 AM in Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (4) | TrackBack (0)
Technorati Tags: CRM, header, Microsoft CRM, ribbon, ribbon color
July 25, 2011
Using FetchXML Aggregation to Create a Rollup Plugin in Microsoft Dynamics CRM 2011
One of the most common requirements for a CRM implementation is for a rollup of data on a set of child records to the parent record. CRM has several built in entities, e.g. Orders and Quotes, that implement rollups, but it does not natively support rolling up of fields for custom entities or for customizations of existing entities. Fortunately, it is quite easy to implement a rollup using a simple plugin. Generally, implementation of the rollup involves retrieving all of the child records related to the parent when one of the child records is created, updated, or deleted, calculating the rollup value and updating the parent. This can be done by iterating through all of the child records after retrieving them using the organization service, but why not make things a little easier and use the new aggregation features of FetchXML to calculate the rollup value.
Aggregation support was added to FetchXML with the release of CRM 2011 and it supports the basic aggregation operations of sum, average, minimum, maximum, and count. The query can be built dynamically in the plugin which allows us to create a generic configurable plugin that will work for most standard rollups.
The first piece of code that we will need is a method to build the aggregation query dynamically. The following method will allow us to build the needed query.
1: public string BuildRollupQuery(string rollupEntity, string rollupAttribute, string aggregateOperation, EntityReference parentLookup) {
2:
3: return string.Format(
4: "<fetch distinct='false' mapping='logical' aggregate='true'>" +
5: "<entity name='{0}'>" +
6: "<attribute name='{1}' aggregate='{2}' alias='{1}_rollup' />" +
7: "<filter type='and'>" +
8: "<filter type='and'>" +
9: "<condition attribute='{3}' operator='eq' value='{4:B}' />" +
10: "</filter>" +
11: "</filter>" +
12: "</entity>" +
13: "</fetch>",
14: rollupEntity,
15: rollupAttribute,
16: aggregateOperation,
17: parentLookup.Name,
18: parentLookup.Id);
19: }
This method will allow us to dynamically create the rollup query given the parameters that define the child entity and attribute that is being rolled up, the rollup operation to perform, and the lookup field to the parent of the child. The query will aggregate the rollup attribute for all of the child records related to the parent.
Using this query we can call the following method to execute the query using the organization service and return the rollup value.
1: public object GetRollupValue(IOrganizationService orgService, string rollupQuery, string rollupAttribute)
2: {
3: return orgService
4: .RetrieveMultiple(new FetchExpression(rollupQuery))
5: .Entities
6: .First()
7: .GetAttributeValue<AliasedValue>(rollupAttribute + "_rollup")
8: .Value;
9: }
As you can see, this method executes the query by passing it to the RetrieveMultiple method of the organization service and retrieves the rollup attribute returned from the first record returned by RetrieveMultiple. Notice that the attribute value is returned by RetrieveMultiple as an AliasedValue. This is how all aggregate attributes are returned by the RetrieveMultiple method. I have made a few assumptions with this method for simplicity. For example, if the attribute being rolled up, the Value property of the returned AliasedValue attribute would be returned as a Money object. If that were the case it would be necessary to return the Value property of the Money object. As I mentioned, for simplicity I have assumed that the attribute being rolled up is a simple type, i.e. decimal, int, or double.
We now have the value for our rollup and simply need to update the parent object. Finally, we can make a call to the organization service to perform the update using the following method.
1: public void UpdateParentRollupField(IOrganizationService orgService, EntityReference parentLookup, string parentRollupField, object rollupValue)
2: {
3: Entity rollupParentEntity = new Entity(parentLookup.LogicalName);
4: rollupParentEntity.Id = parentLookup.Id;
5: rollupParentEntity[parentRollupField] = rollupValue;
6:
7: orgService.Update(rollupParentEntity);
8: }
At this point we have all of the tools needed to create the rollup plugin. In order for the plugin to operate properly and efficiently it is necessary to add a few checks and images to the plugin. For example, it is only necessary to update the rollup if the parent lookup field was changed or the field being rolled up on the child record was changed. These values can be checked by examining the InputParameters object that is passed to the plugin. It will also be necessary to check to see if the parent lookup field for the rollup has changed. If it has changed it will be necessary to update the rollup field on the old parent and the new parent. The old parent lookup field value can be retrieved from a Pre Image entity that is registered for the update and delete messages. The following snippet shows an example of the required checks and assumes that the Pre Image registered for the plugin is called “Target”.
1: Entity targetInput = context.InputParameters["Target"] as Entity;
2: Entity targetPreImage = context.PreEntityImages["Target"] as Entity;
3:
4: bool parentLookupChanged = targetInput.Contains(parentLookupFieldName);
5: EntityReference parentLookupOldValue = targetPreImage.GetAttributeValue<EntityReference>(parentLookupFieldName);
6:
7: bool rollupFieldChanged = targetInput.Contains(rollupFieldName);
All that remains at this point is to wrap the code up in a plugin implementation and call the methods as needed. The plugin can be made configurable by setting a configuration when registering the plugin using the plugin registration tool supplied with the SDK and retrieving the configuration string from the configuration argument passed to the plugin constructor. Happy coding!
Posted by Nick Doriot on July 25, 2011 at 08:48 AM in CRM Development, Dynamics CRM 2011, Microsoft CRM Customizations, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (5) | TrackBack (0)
July 20, 2011
Creating Links to CRM Records from External Systems Using the CRM 2011 REST Services
A common scenario with a CRM implementation includes the need to link to CRM from an external system. The CRM SDK actually describes the URL format for accessing CRM Forms using a URL at the following link, Open Forms, Views, and Dialogs with a URL. Great, problem solved! However, if you take a close look at the URL for a CRM Form you will see that it takes the following format.
http://<mycrm>/<myOrg>/main.aspx?pagetype=entityrecord&etn=<entityLogicalName>&id=<entityId>
As you can see, the problem that presents itself is the need for the GUID of the record. However, quite often the external system/page linking into CRM may not have access to the GUIDs for CRM records. One solution to this problem is to use a tool to get the GUIDs for the CRM records into the external system. A better solution is to leverage CRM Web Resources and the REST services to create a HTML page that can redirect the user to the proper record given some identifying information from the external system, such as an external identifier from the system that is synchronized and stored in CRM.
The first thing needed is to create a HTML Web Resource within CRM. This is a very simple page that merely lets the user know that they are being redirected to a CRM record.
1: <html>
2: <head>
3: <title>Query Redirection</title>
4: <script src="../scripts/json2.min.js" type="text/javascript"></script>
5: <script src="../scripts/jquery_1.6.1.min.js" type="text/javascript"></script>
6: <script src="../scripts/jquery.xrm.orgData_1.0.1.min.js" type="text/javascript"></script>
7: <script src="../../../../ClientGlobalContext.js.aspx" type="text/javascript"></script>
8: <link href="../styles/RedirectQuery.css" rel="stylesheet" type="text/css" />
9: </head>
10: <body>
11: <table width="100%" height="100%" border="0" cellpadding="0" cellspacing="0">
12: <tr>
13: <td id="contentContainer" align="center" valign="middle">
14: <div class="content">
15: <img src="../images/spinner_circle.gif" />
16: <div>Searching for record...</div>
17: </div>
18: </td>
19: </tr>
20: </table>
21: <script src="../scripts/RedirectQuery.js" type="text/javascript"></script>
22: </body>
23: </html>
As you can see, I have included some JavaScript files to make things a little easier when calling the REST services. Also, notice the inclusion of the ClientGlobalContext.js.aspx script. This script file gives the Web Resources the needed XRM context, such as the Xrm.Page.context object. The last script included at the bottom of the page, i.e. RedirectQuery.js is where all of the magic is going to happen. Let’s take a look at what this script needs to do.
The RedirectQuery.js script is going to take a REST query that is passed as a query string parameter, execute the query, extract the logical name of the entity and the ID (GUID) of the record from the result, and redirect the user to the CRM Form for the record.
The first piece to this puzzle is to get the REST query from the query string. HTML Web Resources in CRM are only allowed to have a single query string parameter called “data”, so the REST query is going to be encoded in this query string parameter.
1: // Get the query parameters data
2: queryData = decodeURIComponent(getQueryParam("data"));
Now that we have our REST query we can execute it using a bit of jQuery and a homegrown jQuery plugin that wraps up the calls to the REST services.
1: // Get the data for the target record
2: targetData = $.xrm.orgData.retrieveMultiple({ async: false, query: targetQuery });
The next step is to extract the logical entity name from the original query and the ID (GUID) of the entity from the first record in the results of the REST query.
1: // Get the entity type name from the supplied target query
2: targetEtn = targetQuery.match(/^([a-zA-Z0-9_]+?)Set/)[1];
3:
4: // Extract the ID from the data
5: targetId = targetData[targetEtn + "Id"];
Finally, we can build the URL to the CRM Form with the data we have extracted from our original query and the query’s results and redirect to the CRM Form.
1: // Build the URL
2: targetUrl = Xrm.Page.context.getServerUrl().replace(/\/$/, "") + "/main.aspx" +
3: "?etn=" + targetEtn.toLowerCase() +
4: "&id=" + encodeURIComponent(targetId.toLowerCase()) +
5: "&pagetype=entityrecord";
6:
7: // Redirect to the CRM Form
8: window.location.replace(targetUrl);
As you can see, this CRM Web Resource can help solve the problem of linking to CRM Forms from an external system. All that is left to do is to create the REST query and link on the external web page. The REST query used can contain any criteria necessary to retrieve the desired CRM record. The criteria is commonly an external identifier stored in CRM, but the possibilities are only limited by the capabilities of the CRM REST services.
Posted by Nick Doriot on July 20, 2011 at 08:53 AM in CRM Development, Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
July 18, 2011
CRM 2011 – JavaScript Execution Context - Xrm
A while back, I had two posts concerning the execution of Fetch against the 2011 service (1 & 2). A couple days ago, I received some great comments concerning these posts. One of the comments highlighted a frequent stumbling block I have seen with CRM 2011 – JavaScript Execution Context. Mainly, I’m talking about the JavaScript variable “Xrm”. I think we all got a little spoiled with “crmForm.all”; however, after you get acquainted to using “Xrm”, I think you’ll feel “crmForm.all” was a little bloated. (With it being summer, “Xrm” is ready for the beach!)
In these examples, I’m going to demonstrate executing the getServerUrl() method from an entity’s form.
Inside of a JavaScript Web Resource
To access the getServerUrl() method, simply use:
Xrm.Page.context.getServerUrl()
Inside of an embedded HTML Web Resource (aka an IFrame)
Now since we’re talking context, you can always reference the “ClientGlobalContext.js.aspx” and use:
But I’m wanting more than what’s inside Xrm.Page.context; I want everything inside the “Xrm” variable. For this we can use:
window.parent.Xrm.Page.context.getServerUrl()
To use the “window.parent.Xrm”, you will need to make sure Cross-Scripting is enabled.
Inside of Developer Tools (F12)
I’ve seen people use crmForm.all and then use the CRM 4 to CRM 2011 conversion utility to code. Instead, it’s much easier to use:
document.getElementById('contentIFrame').contentWindow.Xrm.Page.context.getServerUrl()
Summary
If you aren’t familiar with Execution Context, I would recommend delving a little deeper. My intentions for this was merely to demonstrate how to use the “Xrm” variable in the different scenarios. So whether you are using the Console inside Developer Tools or whatever, you can see using the “Xrm” variable is easy once you have the right execution context.
Posted by Paul Way on July 18, 2011 at 08:03 AM in Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (1) | TrackBack (0)
July 08, 2011
Using the FetchXML CRM 2011 Service within a JavaScript Web Resource
Last time we looked at using the FetchUtil.js file inside of an HTML file. This time, I’m going to show you how to execute fetch from JavaScript. I’m also going to talk a little about organizing your web resources and talk briefly about when to use the fetch. Before we begin, let’s lay some of the ground work here.
Keeping it Organized
CRM 2011 has some awesome features and web resources is certainly one of them. It’s important when you create your web resources to have some organization. The more you extend CRM, the easier it would be to start messing others up. I think the best route is to use your abbreviation, followed by the the folder, followed by the file. That sounds a little confusing, so lets look at an example.
Today we are going to create two files. The first is our JavaScript Fetch utility. The second is a JavaScript file specific to our incident entity. In fact, the incident entity is all part of our incidentX project. On the other hand, the Fetch Utility is going to be used across multiple projects. Now there isn’t any need to upload the Fetch Utility inside each project that needs it. So we will create two web resources like so:
- new_utils/FetchUtil.js
- new_incidentX/showMainPhone.js
Now, if I want to add some custom icons and other things to my incidentX project, I can simply do so in the new_incidentX folder.
Adding the Web Resources
Let’s look at both of the files and how they will appear on the form.
FetchUtil.js
var XMLHTTPSUCCESS = 200;
var XMLHTTPREADY = 4;function FetchUtil(sOrg, sServer) {
this.org = sOrg;
this.server = sServer;if (sOrg == null) {
if (typeof (ORG_UNIQUE_NAME) != "undefined") {
this.org = ORG_UNIQUE_NAME;
}
}if (sServer == null) {
this.server = window.location.protocol + "//" + window.location.host;
}
}FetchUtil.prototype._ExecuteRequest = function (sXml, sMessage, fInternalCallback, fUserCallback) {
var xmlhttp = new XMLHttpRequest();
xmlhttp.open("POST", this.server + "/XRMServices/2011/Organization.svc/web", (fUserCallback != null));
xmlhttp.setRequestHeader("Accept", "application/xml, text/xml, */*");
xmlhttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlhttp.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/Execute");if (fUserCallback != null) {
//asynchronous: register callback function, then send the request.
var crmServiceObject = this;
xmlhttp.onreadystatechange = function () {
fInternalCallback.call(crmServiceObject, xmlhttp, fUserCallback)
};
xmlhttp.send(sXml);
} else {
//synchronous: send request, then call the callback function directly
xmlhttp.send(sXml);
return fInternalCallback.call(this, xmlhttp, null);
}
}FetchUtil.prototype._HandleErrors = function (xmlhttp) {
/// <summary>(private) Handles xmlhttp errors</summary>
if (xmlhttp.status != XMLHTTPSUCCESS) {
var sError = "Error: " + xmlhttp.responseText + " " + xmlhttp.statusText;
alert(sError);
return true;
} else {
return false;
}
}FetchUtil.prototype.Fetch = function (sFetchXml, fCallback) {
/// <summary>Execute a FetchXml request. (result is the response XML)</summary>
/// <param name="sFetchXml">fetchxml string</param>
/// <param name="fCallback" optional="true" type="function">(Optional) Async callback function if specified. If left null, function is synchronous </param>var request = "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">";
request += "<s:Body>";request += '<Execute xmlns="http://schemas.microsoft.com/xrm/2011/Contracts/Services">' + '<request i:type="b:RetrieveMultipleRequest" ' + ' xmlns:b="http://schemas.microsoft.com/xrm/2011/Contracts" ' + ' xmlns:i="http://www.w3.org/2001/XMLSchema-instance">' + '<b:Parameters xmlns:c="http://schemas.datacontract.org/2004/07/System.Collections.Generic">' + '<b:KeyValuePairOfstringanyType>' + '<c:key>Query</c:key>' + '<c:value i:type="b:FetchExpression">' + '<b:Query>';
request += CrmEncodeDecode.CrmXmlEncode(sFetchXml);
request += '</b:Query>' + '</c:value>' + '</b:KeyValuePairOfstringanyType>' + '</b:Parameters>' + '<b:RequestId i:nil="true"/>' + '<b:RequestName>RetrieveMultiple</b:RequestName>' + '</request>' + '</Execute>';
request += '</s:Body></s:Envelope>';
return this._ExecuteRequest(request, "Fetch", this._FetchCallback, fCallback);
}
FetchUtil.prototype._FetchCallback = function (xmlhttp, callback) {
///<summary>(private) Fetch message callback.</summary>
//xmlhttp must be completed
if (xmlhttp.readyState != XMLHTTPREADY) {
return;
}//check for server errors
if (this._HandleErrors(xmlhttp)) {
return;
}var sFetchResult = xmlhttp.responseXML.selectSingleNode("//a:Entities").xml;
var resultDoc = new ActiveXObject("Microsoft.XMLDOM");
resultDoc.async = false;
resultDoc.loadXML(sFetchResult);//parse result xml into array of jsDynamicEntity objects
var results = new Array(resultDoc.firstChild.childNodes.length);
for (var i = 0; i < resultDoc.firstChild.childNodes.length; i++) {
var oResultNode = resultDoc.firstChild.childNodes[i];
var jDE = new jsDynamicEntity();
var obj = new Object();for (var j = 0; j < oResultNode.childNodes.length; j++) {
switch (oResultNode.childNodes[j].baseName) {
case "Attributes":
var attr = oResultNode.childNodes[j];for (var k = 0; k < attr.childNodes.length; k++) {
// Establish the Key for the Attribute
var sKey = attr.childNodes[k].firstChild.text;
var sType = '';// Determine the Type of Attribute value we should expect
for (var l = 0; l < attr.childNodes[k].childNodes[1].attributes.length; l++) {
if (attr.childNodes[k].childNodes[1].attributes[l].baseName == 'type') {
sType = attr.childNodes[k].childNodes[1].attributes[l].text;
}
}switch (sType) {
case "a:OptionSetValue":
var entOSV = new jsOptionSetValue();
entOSV.type = sType;
entOSV.value = attr.childNodes[k].childNodes[1].text;
obj[sKey] = entOSV;
break;case "a:EntityReference":
var entRef = new jsEntityReference();
entRef.type = sType;
entRef.guid = attr.childNodes[k].childNodes[1].childNodes[0].text;
entRef.logicalName = attr.childNodes[k].childNodes[1].childNodes[1].text;
entRef.name = attr.childNodes[k].childNodes[1].childNodes[2].text;
obj[sKey] = entRef;
break;default:
var entCV = new jsCrmValue();
entCV.type = sType;
entCV.value = attr.childNodes[k].childNodes[1].text;
obj[sKey] = entCV;break;
}}
jDE.attributes = obj;
break;case "Id":
jDE.guid = oResultNode.childNodes[j].text;
break;case "LogicalName":
jDE.logicalName = oResultNode.childNodes[j].text;
break;case "FormattedValues":
var foVal = oResultNode.childNodes[j];for (var k = 0; k < foVal.childNodes.length; k++) {
// Establish the Key, we are going to fill in the formatted value of the already found attribute
var sKey = foVal.childNodes[k].firstChild.text;jDE.attributes[sKey].formattedValue = foVal.childNodes[k].childNodes[1].text;
}
break;
}}
results[i] = jDE;
}
//return entities
if (callback != null) callback(results);
else return results;}
function jsDynamicEntity(gID, sLogicalName) {
this.guid = gID;
this.logicalName = sLogicalName;
this.attributes = new Object();
}function jsCrmValue(sType, sValue) {
this.type = sType;
this.value = sValue;
}function jsEntityReference(gID, sLogicalName, sName) {
this.guid = gID;
this.logicalName = sLogicalName;
this.name = sName;
this.type = 'EntityReference';
}function jsOptionSetValue(iValue, sFormattedValue) {
this.value = iValue;
this.formattedValue = sFormattedValue;
this.type = 'OptionSetValue';
}
showMainPhone.js
var _oService;
var _sOrgName = "";
var _sServerUrl = Xrm.Page.context.getServerUrl();
function fetchOnLoad()
{
// Get the ID of the Customer
var sCustGUID = Xrm.Page.getAttribute(' customerid ').getValue()[0].id;
var sFetch = "<fetch mapping='logical' count='10'>" +
"<entity name='account'>" +
"<attribute name='telephone1' />" +
"<filter type='and'>" +
"<condition attribute = 'accountid' operator='eq' value='" + sCustGUID + "'/>" +
"</filter>" +
"</entity>" +
"</fetch>";_oService = new FetchUtil(_sOrgName, _sServerUrl);
_oService.Fetch(sFetch, myCallBack);
}function myCallBack(results){
alert(results[0].attributes["telephone1"].value);
}
Now I have added my code to the incident entity. I also called my files by a somewhat different name; in this case “showMainPhone.js” is the same as “usingFetch.js”. The great thing here is the only text that really has to match up is the function name in the onLoad. Everything else was made pretty much bullet proof by CRM 2011.
Seeing the Results
When opening an incident, I will now see an alert box with the phone number of the account associated.
Granted, this may not be the particular feature you users are begging for (in fact the “showMainPhone.js” file needs plenty of error handling), but hopefully you can see how easy it is to embed a fetch call into your JavaScript. Whether you are summing up values from related entities or whatever, it is quite easy to use the fetchUtil.js file to enhance your end user’s experience.
Switching to Synchronous Fetch
This example used an asynchronous callback because that is what I would recommend most of the time. An asynchronous callback will let the browser execute other code; whereas the synchronous approach will wait for the fetch to finish. To use the synchronous version, you will need to change the “fetchOnLoad()” function to like so:
function fetchOnLoad() {
// Get the ID of the Customer
var sCustGUID = Xrm.Page.getAttribute('customerid').getValue()[0].id;var sFetch = "<fetch mapping='logical' count='10'>" +
"<entity name='account'>" +
"<attribute name='telephone1' />" +
"<filter type='and'>" +
"<condition attribute = 'accountid' operator='eq' value='" + sCustGUID + "'/>" +
"</filter>" +
"</entity>" +
"</fetch>";_oService = new FetchUtil(_sOrgName, _sServerUrl);
var res =_oService.Fetch(sFetch);
alert(res[0].attributes["telephone1"].value);
}
Posted by Paul Way on July 08, 2011 at 03:34 PM in CRM Development, Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
June 06, 2011
Microsoft CRM 2011 Tops With Analysts: Nucleus, Gartner, Forrester
Three independent research analysts recently gave strong validation that Microsoft Dynamics CRM 2011 is setting itself apart from the competition in the CRM space. As you read the reviews of these very different and independent analyses, you will see a common thread of productivity. Productivity is what happens when users have familiar tools (like Outlook and Office), high adoption rates, and actionable intelligence. Productivity is what ultimately leads to high ROI.
Forrester: Microsoft Dynamics CRM 2011 gives a 243% Return on Investment
A recent in-depth review by Forrester Research focused on nine companies that have installed Microsoft Dynamics CRM 2011. They reviewed the productivity gains of sales and customer service, as well as the efficiency gains in marketing dollars spent. The study concluded that the composite organization achieved a three-year NPV of U.S. $665,086, and that the payback period was just four months. It is a large report and can be downloaded here. Forrester's summary of benefits:
- Increased sales productivity of 5 percent with the ease of use of Microsoft Dynamics CRM software and integration with Outlook leading to higher adoption, improved opportunity and lead tracking and routing, and a more accurate picture of its sales pipeline.
- Customer service productivity savings from a better UI and documented processes.
- Streamlined processes and operations leading to lower cost of sales as Microsoft Dynamics CRM enabled the composite organization’s technical consultants to shorten time spent on the proposal process by 10 percent.
- Acceleration of sales conversion cycle by 50 percent and corresponding revenue gain as teams worked better together across different business systems, processes, and geographies.
- Marketing cost savings of more than $200,000 (risk-adjusted over three years) due to more real-time insights and improved campaign management from better analytics.
- Productivity savings of 16 man-hours per month due to the better reporting tools in Microsoft Dynamics CRM with data consolidation, reporting automation, and richer dashboard capabilities.
- Improved customer service delivery with quicker response times, dialog boxes, and segmented levels of customer service through insights from Microsoft Dynamics CRM.
- Improved cross-sell collaboration within sales and customer service teams by providing access to reporting tools and other collaboration software such as Microsoft SharePoint Server 2010.
- Lower costs and effort to customize the solution to unique requirements, including extended CRM
scenarios. - Ease of integration with other business technology systems, improving process efficiencies.
Nucleus: Microsoft CRM 2011 is "easier to use" than Salesforce and half the cost!
Nucleus Research recently rolled out its "Technology Value Matrix 1H11: CRM". The report focused on international CRM software that was deployed both on-premises and in the cloud. It focused on core CRM (sales, service, and marketing) and not xRM applications. The 'Value Matrix' is based on "functionality and usability, the two core measures that Nucleus has found indicate an application's ability to deliver initial ROI and, ultimately, maximum value. "
Not surprising to those who work with Microsoft CRM every day, Microsoft was one of only two upper quadrant leaders in usability and functionality. MSCRM rated highly in usability because of:
- Office integration
- Outlook integration
- Role-based views
- Personalizable interfaces
Nucleus also took note of Microsoft's aggressive pricing strategy, which Nucleus found "in many cases is less than half the average per-user price of Salesforce.com".
After highlighting the leadership positions at the top, Nucleus noted that other CRM Offerings "do not have compelling positions".
Gartner: Microsoft CRM 2011 is leader in Customer Service Contact Centers
Gartner recently produced a report that looked at CRM in the customer service contact center. Specifically, it looked at CRM business applications, contact infrastructures (CTI, chat, email, alerts, etc.), workforce optimization tools, feedback management and analytic tools. Gartner recognized Microsoft CRM 2011 a leader in this space and noted their xRM expertise. "There are many scenarios across industries such as government, healthcare, higher education, real estate, and retailing where the flexibility of the system to support a range of interactions makes it a good shortlist product."
The Gartner report reiterated the Office integration and productivity theme of the other analysts. "The Microsoft Outlook look and feel, together with the integration with SharePoint and Microsoft Office, are commonly mentioned pluses of the system for customers."
Leadership in the Customer Service space reinforces Microsoft's commitment to deliver a comprehensive customer service solution. Microsoft recently introduced a new version of its Customer Care Accelerator (CCA) for 2011. This is available for download on the Microsoft Dynamics Marketplace.
The CCA helps customer care and contact center organizations provide a comprehensive and consistent customer service experience by combining data elements from disparate applications, such as mainframes, databases or websites, for display in a single-user interface. These disparate data sources are surfaced in the CCA and tracked CRM to complete the 360 view of a customer to a Customer Service Agent.
Posted by Brad Koontz on June 06, 2011 at 03:47 PM in Dynamics CRM 2011, Microsoft CRM for Outlook, XRM | Permalink | Comments (0) | TrackBack (0)
May 18, 2011
FetchXML 2011–Total Record Count
Fetch in 2011 has added some really nice features. One of those nice features is the total record count of the applied filter. In 4.0 you had to execute two fetch statements, but now with 2011 you can add the ReturnTotalRecordCount attribute.
<fetch mapping='logical' count='25' returntotalrecordcount='true'>
<entity name='account'>
<attribute name='accountid' />
<attribute name='accountnumber' />
<attribute name='address1_city' />
<attribute name='address1_telephone1' />
<attribute name='name' />
<order attribute='name' />
<filter>
<condition attribute='address1_city' operator='like' value='Greenville%' />
</filter>
</entity>
</fetch>
Upon executing this fetch statement with the ReturnTotalRecordCount attribute set to true, the “TotalRecordCount” is returned.
Note: This is not the total number of entities, it is the total number of records that match the filter.
Posted by Paul Way on May 18, 2011 at 11:11 PM in CRM Development, Dynamics CRM 2011, Microsoft CRM Tricks and Tips, XRM | Permalink | Comments (0) | TrackBack (0)
March 07, 2011
Trade Funds Management Application Using Microsoft Dynamics CRM 2011
Consumer Products Good (CPG) Manufacturers set up Trade Funds each year to account for the millions of dollars that are spent promoting their products with food, drug, mass and club class of trade retailers. One only has to bring up the term “Trade Funds” with a senior or regional sales manager to elicit a cringe on their faces. The reason for this lies in how complex TFM is within the company.
Some sample promotions for a given product brand might include:
- Temporary Price Reduction (TPR)
- New Distribution Allowances
- End-Cap Display Allowances
- In-Store Radio
- In-Store Advertising
- Newspaper Ad
- Television Ad
- Coupons
- Free Standing Insert (FSI) Placement
These are just a sample of the many types of advertising expenses that a sales manager for a large CPG company would encounter in dealing with a national retailer. In addition, the funds can be set up on a conditional basis, meaning the retailer must “perform” in order to receive the allowances. Typically, the list of performance criteria relate to advertising and price, but it could include store shelf placement, for example.
CPG companies usually incorporate some type of company-wide ERP solution to track Trade Funds Management (TFM) activity. Complexities arise with tracking promotion funding, in areas such as:
- Deduction Resolution Management
- Off-Invoice Performance
- Bill-Back / Check Payments
- Proof of Performance (PoP) Tracking
- Over-Spending and Under-Spending
In addition, the allocation for funding can be a very difficult issue to determine amongst the retailers. For example, should the division of funding be based upon Market Share, Dollar Share, % Growth from Previous Year, % of Total Sales or % of Brand Sales? - All of these methods could be argued as valid.
At the end of the day, however, the fact remains that at the very heart of the administration of TFM lies two basics things: 1) Trade Funds; and 2) Promotional Events. I would argue that, using Dynamics CRM, a sales organization can manage these funds and track performance very easily, without having to use a full-blown ERP solution, which can be very expensive, complex and time-consuming to the sales group.
In roughly 30 minutes, I built out a Trade Funds Management entity and Trade Fund Event entity in CRM. See screenshots below:
Figure 1: Trade Fund
Figure 2: Trade Fund Event
In these two entities, we have captured the main components of TFM and linked the funds to the fund events. These main components include:
- Fund Amounts
- Brand/Category Alignment
- Fund Status
- Fund Start/End Dates
- Account Alignment
- Promotion Dates
- Promotion Performance Type
- Event Costs
- Proof of Performance
I have seen organizations take 2 years to implement a Trade Funds Management system, spending millions and millions of dollars and utilizing hundreds of people. I think there is an inherent genius in simplicity. Just as organizations evolve, so should systems, processes and capabilities. Using Microsoft Dynamics CRM 2011, an organization could quickly implement a solution – and then build on that solution. Initial user adoption would be high due to the relative ease-of-use of the application. Over 3-6 months, feedback would help to shape “Phase 2” of the application. Lastly, if needed, integration processes can output/input data to the application, but would not be visible to the user. This would eliminate “system clutter” and help make the user interface cleaner.
Obviously, this isn’t meant to attempt to replicate the full capabilities of a traditional ERP application. However, it does represent a viable alternative for a lot of companies that are looking to quickly develop processes and skillsets in this area, and shows the power of XRM for rapid development of line of business applications.
Good luck in your 2011 implementations!!
Posted by Patrick Picklesimer on March 07, 2011 at 10:51 AM in XRM | Permalink | Comments (0) | TrackBack (0)
