Pages

Showing posts with label Plugin. Show all posts
Showing posts with label Plugin. Show all posts

Monday, January 27, 2014

Workflow FetchXml Query

Out of the box, workflow does a pretty good job of allowing you to specify test conditions to perform the appropriate branching logic. For example, say you wanted to determine whether a contact's parent account has a credit hold - well... configuration-wise requirements don't get much simpler than this.



Now let's add a wrinkle. Let's say you have an account hierarchy such that you wish to determine whether the contact's grandparent account (i.e. the parent account of the contact parent account) has a credit hold in order to make the necessary branching decision. This minor change in requirement of just pushing the test condition up one level cannot be achieved with the out of the box workflow tools. This is because the workflow Check Condition (and for that matter Wait Condition too) can only interrogate attributes of the current record and of parent records. Any relationship beyond that definition cannot be queried using the standard CRM workflow UI tools.

Fortunately we have a way of breaking out of this box using workflow plugins. I have created a plugin and published it on CodePlex that allows you to pass in a FetchXml query that will be evaluated. The plugin will return to the workflow whether the said FetchXml query returns results and can therefore be used to take necessary branching logic.

Let's use the example above to illustrate how this works.

First define a FetchXml query that will perform the evaluation that you are looking to do (you can use the Advanced Find "Download Fetch XML" to help you with constructing this query). In our case this would be as follows:

<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="true">  <entity name="contact">    <attribute name="fullname" />    <attribute name="telephone1" />    <attribute name="contactid" />    <order attribute="fullname" descending="false" />    <filter type="and">      <condition attribute="contactid" operator="eq" value="{0}" />    </filter>    <link-entity name="account" from="accountid" to="accountid" alias="ae">      <link-entity name="account" from="accountid" to="parentaccountid" alias="af">        <filter type="and">          <condition attribute="creditonhold" operator="eq" value="1" />        </filter>      </link-entity>    </link-entity>  </entity></fetch>

NB: If you wish to pass in the current record's context as one of the filter criteria make sure that the following is included in FetchXml's condition clause (the attribute should be primary key of the entity that this workflow is running against):

<condition attribute="contactid" operator="eq" value="{0}" />

Now create a workflow and add the FetchXmlQuery step:



Pass in the FetchXml as a parameter to the FetchXmlQuery plugin:


And then define the rest of your branching logic based the results of this query.

If you have configured this correctly, you should be able to see the following results:


  • When the contact's grandparent account has a credit hold



  • When the contact's grandparent account does not have a credit hold


Thursday, December 26, 2013

Workflow Plugin CRM Online Compatibility

There are a lot of useful free add-ons available for Dynamics CRM that can add some serious customization features. The issue in many cases is that these add-ons were only released for the on-premise version of CRM.

For example, take the very useful CRM Manipulation Library which contain some important calculation capabilities. I especially find the Date Utilities to come in handy as there is often a requirement to calculate an off-set of days or business days as part of workflow logic. But when you try import the solution into a CRM Online instance you will receive an error that looks something like the following:



The good news is that this can be made compatible with CRM Online by following these steps:


  1. Unzip the solution into a folder
  2. Open the customizations.xml file
  3. Perform a search for the IsolationMode node
  4. Change IsolationMode value from 1 to 2
  5. Update the original zip file with the modified file


Once you have done so you should be able to import it into CRM Online. Applying this trick does not necessarily mean that the plugin will work as it might fail on something when trying to execute. However it also just may function without a problem which is indeed the case with the CRM Manipulation Library. So it's definitely worth a shot. If your plugin does not work after performing this tweak, you'll have to do some debugging at the code level.

Tuesday, April 30, 2013

Contact Address Solution

In my previous post I provided some background with regards to the challenge of managing account and contact addresses in CRM. I also provided a solution for handling a simple scenario where the contact's account only ever has a single address. But the reality in most cases is more involved than that.

We will be walking through the scenario described at the end of my previous post i.e.
It would therefore be better to stick to a single account with multiple addresses and allow for the contact records to be associated to one of these account addresses. In the next post, I will present an elegant approach to handling this requirement.
The objective of this solution is to provide the flexibility of a custom lookup solution while not compromising any features/functions in the system by ensuring that the default (out of the box) address fields are populated with the address information.

This requirement covers a number of configuration scenarios and therefore may be useful as a good overall "configuration" tutorial. Topics referenced:

  • Default vs. Custom entities - when to resort to custom
  • Use case for the "Related Records Filtering" configuration option
  • REST API
  • Distribute Workflow
  • Plugin requirement

First of all, we need to create a new address entity. The reason we do so is because the ability to leverage the default More Addresses entity is limited. Specifically, the system does not allow custom relationships to be created against More Addresses which is a key requirement to the solution we are trying to implement. So first of all, we create a custom entity like the one shown and in order to eliminate user confusion we rename and remove the default More Addresses from the account and contact forms.


 Next we create an N:1 relationship with Account - this essentially replaces the More Addresses link in the account entity.


... and a 1:N relationship with Contact - this is going to allow for an address selector at the contact level.


We now add the relationship field created in the step above to the contact form. In the "Related Records Filtering" section we need to filter it to the Parent Account. This will limit the addresses shown in the lookup dialog to addresses defined at the parent account level.



The next thing we need to do is to add some jscript to the form. The objective here is to retrieve the address fields from the address which has been selected and copy it to the corresponding address fields on the contact record. The jscript below will perform the following logic:

  • Copy/Clear Address fields based on address selected from lookup using the REST API (note this use the retrieveEntityByID function described in this post)
  • Make fields read only if address is selected via the "picker" (the idea here is that you can enter an ad-hoc address if you want at the contact level, but if you select from one of the lookup values then the address values will be controlled by the official parent address records).

function AddressPicker_OnChange() {

 var entity = "snt_address";
 var entityid = Xrm.Page.getAttribute("snt_addressid").getValue();
 var fields = "?$select=snt_Street1,snt_Street2,snt_Street3,snt_City,snt_State,snt_Zip,snt_Country"
 
 if (entityid != null) {
  entityData = retrieveEntityById(entity,entityid[0].id,fields,UpdateAddressFields);
 } else {
  Xrm.Page.getAttribute("address1_line1").setValue(null);
  Xrm.Page.getAttribute("address1_line2").setValue(null);
  Xrm.Page.getAttribute("address1_line3").setValue(null); 
  Xrm.Page.getAttribute("address1_city").setValue(null);
  Xrm.Page.getAttribute("address1_stateorprovince").setValue(null); 
  Xrm.Page.getAttribute("address1_postalcode").setValue(null); 
  Xrm.Page.getAttribute("address1_country").setValue(null);   
 }

 Xrm.Page.getAttribute("address1_line1").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_line2").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_line3").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_city").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_stateorprovince").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_postalcode").setSubmitMode("always");
 Xrm.Page.getAttribute("address1_country").setSubmitMode("always"); 
 
 AddressRender();
}

function UpdateAddressFields(entityData) {
 if (entityData != null) {  
  Xrm.Page.getAttribute("address1_line1").setValue(entityData.snt_Street1);
  Xrm.Page.getAttribute("address1_line2").setValue(entityData.snt_Street2);
  Xrm.Page.getAttribute("address1_line3").setValue(entityData.snt_Street3);
  Xrm.Page.getAttribute("address1_city").setValue(entityData.snt_City);
  Xrm.Page.getAttribute("address1_stateorprovince").setValue(entityData.snt_State);
  Xrm.Page.getAttribute("address1_postalcode").setValue(entityData.snt_Zip);
  Xrm.Page.getAttribute("address1_country").setValue(entityData.snt_Country);
 } 
}

function AddressRender() {
  -- Add function to form onload function
  var disabled;
  if (Xrm.Page.getAttribute("snt_addressid").getValue() != null)
   disabled = true;
  else
   disabled = false;
   
  Xrm.Page.getControl("address1_line1").setDisabled(disabled);
  Xrm.Page.getControl("address1_line2").setDisabled(disabled);
  Xrm.Page.getControl("address1_line3").setDisabled(disabled);
  Xrm.Page.getControl("address1_city").setDisabled(disabled);
  Xrm.Page.getControl("address1_stateorprovince").setDisabled(disabled);
  Xrm.Page.getControl("address1_postalcode").setDisabled(disabled);
  Xrm.Page.getControl("address1_country").setDisabled(disabled);  

}

For the sake of illustration, after the above jscript is implemented, when an address record is selected the fields are copied as shown:


Now we need to implement logic that will keep addresses in sync. For example, if the address shown in the screenshot is changed and there are 5 contacts that are linked to this address, then we want to make sure that the address fields are propagated to all 5 contact records. This is fairly easy to accomplish using the distribute workflow. The screenshots below show the 2 workflows required in order to configure this option.


The last piece of the puzzle requires a plugin. Basically at this juncture we can define addresses against the account entity that will appear in the lookup for contacts tied to this account:


But what about the address defined on the account itself? This in essence is the Primary address of the account and we also want it available for selection for the contacts. Therefore the plugin logic required here is to automatically maintain the PRIMARY address as shown above based on the values entered on the account form (as additional validation, you should also define jscript on the address entity to make the fields read only when the address name = PRIMARY and prevent manually keying in address with this name i.e. reserve PRIMARY for the plugin only).

The end result? A lookup on the contact form that allows you to select from the specified account addresses.



Thursday, February 28, 2013

CRM 2011 Copy Utility


This plugin allows you copy fields from a parent record to all child records in a 1:N relationship. For example, this plugin can be used to copy the address fields of an account to all the contacts of that parent account (a common scenario).

Out of the box you are able to map fields from a parent entity to a child entity when the child record gets created. However beyond this point in time if details are changed on the parent record they will no longer be copied to the child records. Similarly there is no out of the box capability to copy changes made to the parent record down to all child records.

This plugin allows this option to be configured. You are able to configure which 1:N relationship this plugin will work against as well as the fields that are to be mapped between the parent and child entities. The plugin does not validate attribute types so you will need to ensure in your configuration that the fields be mapped are of the same type.

The following is a walk through of how to configure this plugin:

  • Download the DLL from here
  • Use the Plugin Registration tool to connect to your environment and register the plugin
  • Register a New Step 
    • Message: Update
    • Primary Entity: Parent entity
    • Remaining settings: Optional


  • In the Unsecure Configuration update the XML to specify the fields to copy
    • <setting name="source"> : parent entity name e.g. account
    • <setting name="sourceid"> :  parent entity primary key e.g. accountid
    • <setting name="target">  : child entity name e.g. contact
    • <setting name="targetid"> : child entity foreign key e.g. parentcustomerid
    • <setting name="numberoffield"> : total number of fields being copied
    • <setting name="src_fieldn"> : name of source field to copy
    • <setting name="dest_fieldn"> : name of corresponding target field to be copied too
Note: There is no validation of any of these fields. You need to ensure that:

    • All the field names are correct
    • The corresponding "src" and "dest" fields have the same definition 

For example, the following XML can be used to copy the address fields from the parent account record to the child contact records: 
<Settings>
<setting name="source">  
<value>account</value>
</setting>
<setting name="sourceid">  
<value>accountid</value>
</setting>
<setting name="target">
 <value>contact</value>
</setting>
<setting name="targetid">
 <value>parentcustomerid</value>
</setting>
<setting name="numberoffield">
 <value>8</value>
</setting>
<setting name="src_field1">
 <value>Address1_line1</value>
</setting>
<setting name="src_field2">
 <value>Address1_line2</value>
</setting>
<setting name="src_field3">
 <value>Address1_line3</value>
</setting>
<setting name="src_field4">
 <value>Address1_city</value>
</setting>
<setting name="src_field5">
 <value>Address1_stateorprovince</value>
</setting>
<setting name="src_field6">
 <value>Address1_postalcode</value>
</setting>
<setting name="src_field7">
 <value>Address1_country</value>
</setting>
<setting name="src_field8">
 <value>Address1_telephone1</value>
</setting>
<setting name="dest_field1">
 <value>Address1_line1</value>
</setting>
<setting name="dest_field2">
 <value>Address1_line2</value>
</setting>
<setting name="dest_field3">
 <value>Address1_line3</value>
</setting>
<setting name="dest_field4">
 <value>Address1_city</value>
</setting>
<setting name="dest_field5">
 <value>Address1_stateorprovince</value>
</setting>
<setting name="dest_field6">
 <value>Address1_postalcode</value>
</setting>
<setting name="dest_field7">
 <value>Address1_country</value>
</setting>
<setting name="dest_field8">
 <value>Address1_telephone1</value>
</setting>
</Settings>


  • Register a New Image called "postEntityImage"


  • Test and ensure that it is working




Wednesday, February 8, 2012

Dynamics CRM Search

One feature that is still not offered out of the box as part of the Dynamics CRM offering is a cross purpose search engine. While you can effectively perform searches using Advanced Find, Quick Find, Custom Reports etc. all of those searches involve navigating to a particular area of the application and pulling up the relevant view or report. A much desired feature in many organizations is the ability to have a single search "landing page" where you can enter in your search criteria and have that search across the relevant entities in CRM. Many competitive solutions to Dynamics CRM offer such a search capability.

The Dynamics CRM Search tool is designed to fill such a gap. This solution is fairly "low tech" in that it leverages the powerful reporting capability of SSRS in order to deliver the results. And it can be configured to suit the needs of any organization. This CRM Search tool is compatible with CRM 2011 and CRM 4.0.

Below are some configuration samples to illustrate usage scenarios.

"Out of the box" deployment


When deployed out of the box this is how the CRM Search will appear. By default it is configured to search across the account, contact, lead opportunity, and case entities. As illustrated, the more search criteria specified the further the result is refined. So for example, the search criteria shown in the screenshot will return all accounts beginning with "a" along with any contacts that belong to an account beginning with "a" and have a last name beginning with "d".


Highly Modified


The search criteria can be modified to search the particular requirements of your CRM deployment. Most of the fields and search criteria represent data that do not exist in the out of the box CRM deployment.


"Search All" 


This example illustrates the ability to have a “Search All” search field. If for example, you enter “Thomp” in the Search All field – the search will run a “contains” search as follows:

  • In accounts for any accounts that have a matching name, address, contact information
  • In contacts for any contacts that have matching first name, last name, address, contact information
  • In any other entity/fields that the "search all" is configured to run against (according to your installation requirements)

The remaining fields can be used to do a more targeted search if that’s your preference


Notes search capability



This illustrates the ability to search against notes entered in the CRM database. So for example, if you remember having entered a note containing a particular phrase but cannot recall who you entered it for, you can enter it in the Notes field and have the account, contact, etc. where that note was entered returned to you.


Of course the above are just samples of how this can be configured - you can configure it to have a combination of some of the features shown or to be entirely different based on the specific requirements of your CRM installation. In addition, you are not limited to a single search console, you can create as many as necessary to meet the requirements of different departments or teams.

For more information on how to obtain a license for this tool, please visit our product page.

Monday, January 30, 2012

Dynamics CRM 2011 Grid Editor

We have recently upgraded the Sentri CRM Grid Editor to work with CRM 2011. Now you can peruse and update your CRM records using an Excel-like interface. If you know how to use Excel you know how to use the CRM Grid Editor!



This release will work for all modes of CRM deployment including:

  • On Premise
  • Internet Facing Deployment (IFD)
  • Live

In addition, the CRM Grid Editor comes in 2 flavors (UPDATE the Grid Editor full version is now freely available):

  1. Limited Edition - This version is fully functional but can only be used against system entities (i.e. custom entities will not load) and is limited to system views. 
  2. Full Edition - This version does everything the Limited Edition version does but can also be configured to work against custom entities and system views

The Limited Edition license will not expire so if this very functional version meets your needs you can download and use to your hearts content. Alternatively if you're looking to "try before you buy" feel free to download the Limited Edition and when you're ready, request a license and upgrade to the full version.

Setup is very quick involving the following steps:
  • Download the product and use the wizard setup to deploy it to your CRM installation
  • Configure which entities you wish to be available in the Grid Editor
  • Run the Grid Editor client 

Thursday, January 12, 2012

CRM 2011: Distribute Workflow

A few months ago I extolled the virtues of the distribute workflow in CRM 4.0 and wondered when it might become available for CRM 2011. Well the good news is that I recently discovered that this has now become available for CRM 2011 and can be downloaded from codeplex.

To install into your environment, all you need to do is to import the managed solution from the codeplex downloads page into your environment and once you have done so it will start showing up in the Add Step menu of the Workflow and Dialog process editor.



The codeplex site also contains pretty good documentation for configuring this option. It walks through a use case scenario for setting all cases for a particular customer to high.

There are many other scenarios where this workflow plugin can come in handy. Previously you might have gone about solving a requirement such as that presented by the use case by developing a custom plugin solution. With the distribute workflow it can be done via configuration and it is flexible in that you can specify under which specific conditions you want it to run by employing the use of some simple check conditions in the body of the workflow.

I'll provide another use case example that can further sharpen this point. Let's say you wish to close all open Campaign Responses automatically once the parent Campaign is completed. The distribute workflow can easily be used to accomplish this via simple configuration.

First design a simple manual workflow against the Campaign Response that:
  1. Evaluates whether the Campaign Response is open
  2. Changes the status of the Campaign Response to Closed



Then design another simple workflow against the parent Campaign that is triggered when the status is changed that does the following:

  1. Evaulates whether the Status Reason has changed to Completed
  2. Executes the Distribute Workflow which will call the workflow above for each child Campaign Response


And that is all there is to do.

Tuesday, December 20, 2011

CRM 2011: Plugin Registration Tool Compiled Version

The Plugin Registration Tool for CRM 2011 can of course be downloaded from CodePlex:

http://pluginregcrm2011.codeplex.com/

However the download from CodePlex contains the source code and needs to be compiled in Visual Studio before it can be used. In case you want to circumvent this compilation step, you can download the executable from the location below:

http://www.sentri.com/ProductDownloads/PluginRegistration.zip

Thursday, December 8, 2011

CRM 2011: Cannot unregister workflow PlugIn

In a previous post I covered an issue I faced with regards to being unable to unregister a regular plugin. I subsequently had some additional difficulty in unregistering some other plugins that were also carried over from the upgraded 4.0 installation.

In this case, the plugins turned out to be workflow plugins. That is, plugins that are used to extend the workflow (or Process in CRM 2011 speak) functionality.

The error message that was shown contained some text that looked like this:
>Crm Exception: Message: The PluginType(a222ddda-c78e-45c8-91f9-fa06359ac29d) component cannot be deleted because it is referenced by 1 other components. For a list of referenced components, use the RetrieveDependenciesForDeleteRequest., ErrorCode: -2147160033
[2011-12-06 12:03:51.118] Process: w3wp |Organization:9dd6ac5e-4be6-46f9-af58-7caed1001d66 |Thread:   31 |Category: Platform |User: 6b51be4f-7308-dc11-9e28-00188be6f91e |Level: Info | MiniDump.CreateDumpInternal
The key phrase of course being the "reference" issue which I have highlighted.

The only dependencies that I could think of for a workflow plugin are in fact the Process definitions and Process instances. 

I first started out by cancelling all Processes that were in a "Wait" state using Advanced Find as they could be referencing the said plugins.


However after this step, the plugin could still not be unregistered. So my next step was to disable the active Process definitions. 

That still did not bring along the desired results. Only once the calls to the plugin were removed from the Process definitions was I able to finally unregister the plugin.

Although it would be nicer if a better error message were issued highlighting the specific dependency issues (in plain English preferably), I cannot complain too much about the fact that Microsoft is in fact enforcing this dependency logic. Although it took a while to go through the above steps, it is still preferable to having to deal with the fallout of broken Process definitions and instances down the line. And of course being in an upgrade environment, this also helps ensure that certain plugins may require tweaking as part of the upgrade process. 

The only remaining step is of course to note all the above steps as far as cut over planning is concerned.

Wednesday, December 7, 2011

CRM 2011: Cannot unregister PlugIn

After having upgraded a CRM 4.0 installation to CRM 2011 I was attempting to unregister some of the plugins that were carried over from the 4.0 installation as part of the upgrade process. Yet whenever I tried to do so, I encountered an error telling me that the plugin could not be unregistered. The Error Message received was similar to the one shown below:


After a little bit of research, I discovered that the said plugin was actually a plugin that was developed way back using the CRM 3.0 plugin architecture and therefore had DLLs etc. in the "server\bin\assembly" sub-folder of the existing 4.0 environment being upgraded.

Once the files had been copied over to the corresponding sub-folder in the CRM 2011 upgrade environment, I was able to unregister the plugin successfully.

Not entirely sure that it makes sense in CRM 2011 to have to copy these DLLs present in order to unregister the plugin, but then again, I'm not sure it's worth spending any more time thinking about either.


Wednesday, July 13, 2011

There are still open activities associated with this case...

Another one for the penny series...

CRM prevents cases from being closed as long as their are open activities against the case. If you attempt to close the case when there are open activities you will be presented with an error message as shown below:


Ok. So I can understand that you may want to warn the user of such an event before allowing the case to be closed... But forcing the user to close all activities prior to closing is perhaps going a little too far.

This is especially exacerbating when dealing with "unexpected" activities. For example, if an email notification fails to get sent for whatever reason, it will sit in the open activities with a status of Failed. And you guessed it - if a user tries to close this case they will be prevented from doing so. So even if I could accept a blanket requirement that open activities need to be closed before being able to close the case, I'd really have to draw the line to suggest that somehow a Failed email message is considered to be "open"...

Unfortunately this issue has not been addressed in CRM 2011 either.

The good news is that there is a solution to such a predicament. The following link has a good write up of this issue and even better - there is a plugin that can be downloaded that will resolve it altogether. Great job!

http://blogs.msdn.com/b/ukcrm/archive/2009/07/04/closing-an-incident-case-that-has-open-activities.aspx

Tuesday, June 7, 2011

Plugin Registration not working with IFD

Recently I spent quite a bit of time troubleshooting an issue where the Plugin Registration tool was not working. The issue was attributed to the fact that I was trying to access an IFD On Premise of CRM 2011. Basically I was unable to authenticate into CRM and was receiving the following message:


I tried various other "discovery URLs" without any success.

In the end it turns out that the version of the Plugin Registration tool that I was using was in fact the problem. Luckily a new version of the CRM SDK (and along it Plugin Registration tool) has just been released.

Using the most up to date version of the Plugin Registration allowed me to authenticate. The new version can be downloaded from the following location:



Wednesday, May 18, 2011

Distribute Workflow for CRM 2011

In CRM 4.0, a wonderful little free workflow plugin was introduced that allowed workflows to be distributed. This can be downloaded from codeplex. The idea behind this workflow plugin is simple and effective. For example, say after completing a campaign, I wanted to generate a follow up activity on each opportunity generated from the campaign, I could create a single workflow against the parent campaign monitoring the campaign status and as soon it was completed, I could generate workflows to be kicked off for each of the child opportunities. So one workflow could spawn sub-workflows for all it's children. Useful in many different scenarios.

The functionality described above was not out of the box in 4.0 and I don't believe it is out of the box in CRM 2011 either (please enlighten me if I'm wrong as I haven't researched this to the Nth degree). So why am I mentioning this?

Well in light of my previous blog entry which discussed limitations with CRM 2011 Online - one of the limitations was that workflow plugins are not supported... And guess what - the utility mentioned above is in fact a workflow plugin which means that if you've deployed this feature in your on premise installation, you may have difficulty replicating this functionality if you decide to move to CRM 2011. So either you will need to dispense with the functionality or come up with another creative way for handling the requirement. Of course, upgrading to CRM 2011 on premise does not present the same challenge, since workflow plugins can be added in that case.

If anyone is aware of a way of executing the workflow distribution logic in CRM 2011 Online in a simple and elegant manner as the aforementioned plugin enabled - your input would be appreciated.

MSCRM 2011 - Going into the Cloud Considerations

In CRM 4.0 there were some major limitations if you decided to go into the cloud with CRM Online (vs. On Premise) that required careful consideration. A good detailed comparison can be viewed here.

However, from a practical point of view, the following were the most significant high level limitations:

  • Reporting - custom reports are limited to out of the box views, the report wizard or you could create with significantly greater difficulty some aspx type reporting using FetchXML
  • Plugins - no ability to add custom extensions to the application

The good news is that CRM 2011 Online has overcome these limitations to a large extent. However not completely:

  • Reporting - custom reports can now be created using a FetchXML extension to BIDS. You can find a good introduction of this capability here. While this does provide a good workaround solution it should be mentioned that you are still limited to the FetchXML framework. That is you can only retrieve data from CRM in ways that FetchXML will allow you to. FetchXML was limited to relatively simple queries in 4.0 and the good news is that it's been expanded to be able to include aggregate functions such as GROUP BY which are important when it comes to reporting. However FetchXML is still bound to be more restrictive than it's SQL counterpart - the latter can be manipulated in virtually limitless ways, if not by a SQL statement, then by employing the use of cursors, dynamic SQL etc. to achieve the desired result set. 
  • Workflow plugins - while standard "trigger" plugins can now be added to the CRM 2011 Online deployment, you are still unable to deploy workflow plugins. A "trigger" plugin is executed synchronously or asynchronously as a direct result of an event (update, insert, delete) that is made to an entity (for example, good for validation, calculation etc. logic). A workflow plugin is executed by the workflow engine which is useful if an advanced function needs to be called as a result of a more protracted workflow that gets generated due to some condition in the environment. Although through some fancy footwork it should be possible to leverage the "trigger" plugin to work around this limitation (for example, creating a custom entity that gets updated by the workflow and "trigger" plugins are designed against inserts to the custom entity - just theorizing)

In summary, while the workflow plugin limitation is not optimal I do believe it can be worked around. However if your organization has complex reporting (read: above average) or if you are upgrading an existing installation where reports have employed dynamic/advanced reporting techniques or need to join to data that sits outside of the CRM database, then you may want to give this further consideration before moving into the cloud.

One final point, if you are upgrading your existing on premise installation and you have many custom reports that have been written, you'll need to consider the effort that it will take converting those to the FetchXML cloud model equivalent.