Sunday, September 30, 2012

Mobile Express: Features and Limitations

Mobile Express for CRM 2011 offers a simplified mobile client that is integrated into the product, however, it has some key limitations. This post seeks to explain with pictures which are the pros/cons, main features and limitations of Mobile Express.

This is the default “landing page” when opening CRM via mobile client

All views on the selected entities will be available in Mobile Express:

Forms: Read
You can select which fields are available in the form. You will also be able to navigate to the related (child) entities

Forms: Edit
The fields which are available to edit via ME will appear in the form “edit” mode. Note that Field Level Security works in ME the same way as in the web client.
Nota that this is not a complete list of limitations but represent those that in my experience have been the most significant limitations of Mobile Express.
1. Lookup fields have no “browse” or “auto-complete”. This is one of the most significant limitations to end users when working with ME. Imagine for example that you need to escalate a case immediately and you need to select the team to which you need to escalate. If you are in the web client, you can easily browse the team and there is also auto-complete feature:
However, in Mobile Express you will need to type the exact team name and hope you did not make any spelling mistakes because if it does not match exactly with an existing record, the save operation will fail. This limitation applies to all lookup fields. As a work-around you might consider using OptionSet fields in ME instead of lookups (and you might need to build a plugin or some logic to map between optionset values and lookup values on save, but this topic alone can be an entire blog post).
2. No Ribbon = Few buttons. Because there is not ribbon in Mobile Express, the buttons available are very limited and you can certainly not implement custom buttons. Mobile Express supports the following buttons to act on a specific record:
- New (Create new record)
- Edit
- Save
- Delete
So for example, assigning a record to another user/team is challenging from Mobile Express because there is no “Assign” button and you can also not edit the “Owner” fields. A workaround would be to create a custom Lookup field to a user/team and expose this field in the mobile form (call it “Owner”) and then have a plugin that will do the actual assignment whenever this field changes. However, this workaround will also suffer from limitation (1) above.
Custom actions (such as “Escalate”) would have to be implemented as fields instead of as custom buttons (following the plugin pattern described above).
3. No sorting / filtering. Sorting and filtering which can be easily achieved in the web client as shown in the screenshot below are not possible in ME:
4. No “select multiple”. When you have a view in ME you cannot select multiple records at once so you cannot bulk-edit, bulk-assign, etc.
5. Maximum 2 fields per view. Mobile Express views will only display the first 2 fields of the view.
6. No visualizations. ME does not support charts, dashboards or running reports.
7. On-demand processes. While automatic workflows will trigger from Mobile Express, you cannot start dialogs or workflows on-demand.
8. Form limitations. You cannot have custom JavaScript or web resources embedded in the mobile form.
9. Not available offline.

Again, this is not a complete list of pros and cons, so feel free to contribute if I left out something significant.

No additional license required. Limited functionality (see above)
Native application within CRM/xRM. Not optimized for specific device (same interface for all phones and tablets).
Same support channel as the rest of the CRM/xRM application (Microsoft directly, no third-party vendors).  
No additional IT infrastructure required.  
Simple to implement, manage and maintain.  
Access via web (no need to install applications in mobile devices).  
Lowest cost.  

Wednesday, August 29, 2012

CRM 2011: Plug-in assembly does not contain the required types or assembly content cannot be updated

This post explains why you receive this error message when trying to update a plugin assembly in CRM 2011 and how to correct it.
This is another very popular question in the community, why do I get the following error message when updating a plugin assembly?
Plug-in assembly does not contain the required types or assembly content cannot be updated (Error Code -2147204725)
The answer is not very simple as there are a number of conditions that would produce that error message, and these conditions are barely covered in the official documentation from Microsoft. So here are the things you need to check:

1. You are not allowed to update the assembly metadata (strong name)
The new plugin assembly must have the same fully qualified name (same culture, publickeytoken, name and version). You are allowed (and should!) modify the version build and/or revision number but you cannot change the major or minor version. Your assembly version is always in the form <> and you can specify the assembly version in Visual Studio before you build. Note that because the publickeytoken must be the same, then you must use the same key to sign your assembly as you used for the original assembly you are trying to replace.

2. You cannot remove or rename classes which are already registered as plugin types
A plugin type is basically a class which implements IPlugin and they might or might not be registered in CRM as plugins. If your plugin assembly has any plugin types registered under it, then you need to make sure that your new assembly contains those registered types with the same class names. It is important that the signature of each class which is registered as a plugin is not changed in your new assembly (internal and helper classes can always change with no problem, but not the public plugin classes). If you wish to change the class name of a registered plugin (for example you had a plugin called "MyPlugin" and then you changed the name of a class to "MyNewPlugin") you will have to first unregister that plugin type and then you can successfully update the plugin assembly which contains new plugin type and then you’d have to re-register the new plugin type.

3. You cannot change or remove arguments of custom workflow activities
If your plugin assembly contains custom workflow activities which are registered and which have In or Out arguments, then you are not allowed to update the assembly if you are making changes to the custom workflow activity arguments. Removing or changing the datatype or the name of the arguments is not allowed; however, adding new arguments is OK (not recommended though). If you would like to change the arguments then you’d have to unregister the custom workflow activity from the system, update the new assembly and then re-register the custom workflow activity with the updated arguments. You can find more details about how workflows behave with different version of the plugin assembly:

If you absolutely need to make a change which is not allowed in the list above, then you would need to either unregister the old assembly and re-register everything back or you can increase the major/minor version of your assembly and then register it as a new assembly (but you cannot update the existing one). Also keep in mind that in general it is a good practice to always change the build/revision number before you update an assembly. That way, the new assembly will be used immediately without having to run iisreset or restart CRM services.
If you find other conditions that cause this error message you can comment on this post. Also, I

Monday, August 20, 2012

Learn About The Microsoft Private Cloud to Win a Trip for Two to Mexico!

Microsoft has released new and exciting products that will change the way IT Pros utilize Virtualization and Microsoft Private Cloud solutions.   Two products which are a part of these great changes are the newly released System Center 2012 and the soon to be released Windows Server 2012.  Both of these solutions were designed to make virtualization and extending to the private cloud simpler and much more efficient. 

With these new changes to Infrastructure and the IT world, it’s a great time to learn about these new solutions and keep yourself and your organization ahead of the curve in terms of where technology is headed.  In fact, Microsoft has even added an incentive to learn about their Private Cloud solutions through the Skyrocket Sweepstakes! 

Entering is easy!  All you have to do is register, and then download a free TechNet evaluation like Windows Server 2012 RC or System Center 2012 to get started.  Every applicable evaluation you download gives you an entry into the sweepstakes! And the best part is the more evaluations you download, the better your chances.  And what’s the prize you may ask? Oh, just a 7 day, 8 night trip for two to Cozumel, Mexico!

The contest ends September 6th so don’t wait!  Register now!

Workflow Persistence in CRM 2011

Commonly disregarded during workflow design, persistence is critical to understand in some scenarios in which it affects the logic of the workflows in CRM. This post explains how workflow execution is affected by persistence.

I think the best way to explain this topic is in “FAQ” format:

1. What is persistence?

Persistence (in this context) means taking a snapshot of the state of a workflow job and storing it in the database. This is similar to clicking the “Save” button when you are writing a Word document. Persistence is a common term in WF (Windows Workflow Foundation) on which CRM workflow is based. The “snapshot” of the workflow job is serialized and stored in the Async Operation table.

2. When are workflows persisted?

CRM will automatically persist workflow jobs right after successfully completing any of these Out-of-the-Box workflow steps:

  • Assign Record

  • Start Child Workflow

  • Create Record

  • Send E-mail

  • Change Status

  • Stage

  • Update Record

Additionally, whenever the workflow goes into a “waiting” status (not due to an error), it will persist to database.

3. In what cases does this matter?

When a workflow is suspended due to a recoverable error, the user is allowed to manually resume the workflow. But when you click “Resume”, from what step is it going to resume? This depends on the last time that the job was persisted. In some cases, you might end up re-executing some steps because your workflow job did not persist after each step. For example, consider this workflow:

1. Create a record (CRM automatically persists after a successful Create step)

2. Custom activity to create the record in an external system

3. Send email to the record owner to notify that the record has been created in CRM and in the external system. (CRM automatically persists after a successful Send E-mail step)

Now imagine that the new record owner did not have a valid email address in CRM. In this case, the job will be suspended and you will need to enter the email address in the user record and then resume the workflow:


Note that the last persistence point is after the create step (because custom activity steps are not persisted). Therefore, when you resume the workflow, it will resume from the beginning of step 2. Thus your workflow will end up executing step 2 twice and you end up with a duplicate in the external system. I hope this example helps illustrate why persistence does matter and can affect the workflow behaviour when resuming suspended jobs.

4. So how can I control persistence?

It is very limited the amount of control you have on persistence. For example, you cannot prevent CRM from automatically persisting the workflow job for the scenarios described above. However, there are some tricks to force CRM to persist the job where it usually wouldn’t. In the example above, I would have liked to persist the workflow job after step2 completed successfully. In order to do that I could have easily used stages so if my custom activity is inside its own Stage then it will be persisted, because CRM will always persist after a stage is successfully completed.

This workaround (using stages) works most of the times, however stage steps cannot be nested and in some scenarios you want to persist a step that is nested inside another one (for example a custom activity inside a condition branch). Unfortunately, there is not much else you can do to force your custom workflow activity to persist the job upon successful completion. Stay tuned for the CRM2011WorkflowUtilities as I will soon provide a “Persist” custom workflow activity which you can use in your workflows.

5. What about the old PersistOnClose attribute?

In WWF3.5 (CRM 4.0) you could add the [PersistOnClose] attribute to your custom workflow activity (System.Workflow.ComponentModel.SequenceActivity) to force CRM to persist when your custom workflow activity is finished executing. For back-wards compatibility, this is still the case in CRM 2011. However, if you build new custom workflow activities for CRM 2011 you should use WF4 (System.Activities.CodeActivity) which does not support the [PersistOnClose] attribute. In short, if you have CRM 4.0 custom workflow activities they will continue to work in CRM 2011 and the [PersistOnClose] functionality will also work, but you should think about upgrading them to WF4.

6. What about the WF4 “Persist” activity (System.Activities.Statements.Persist)

This Out-of-the-box activity that is included in the WF4 activity palette forces the workflow host to persist. Unfortunately, you cannot use this activity in CRM unless you design your workflows in the WF4 designer and upload them as XAML workflows in CRM (which is not supported in CRM Online). Stay tuned for the CRM2011WorkflowUtilities as I will soon provide a similar “Persist” custom workflow activity which you can use in your workflows in the CRM process designer.

Monday, August 13, 2012

Custom Entity or Custom Activity in CRM 2011?

Not sure if you need a custom activity or a custom entity? This post mostly written by my co-worker Patrick Vantillard includes some of his conclusions after making some research about when to use a custom entity vs. a custom activity.

Custom Activity
Custom Entity
An activity represents an action such as making a call, or attending a meeting. This typically involves completing some “work” which is associated with the duration field (how long did it take you to complete the activity).
Activities typically have a lifecycle: opened à assigned à worked on à closed.
Activities in general cannot have sub-activities, at least not in the same native way that entities have associated activities.
Custom entities can represent any business entity. Custom entities store master data or transactional data and can have activities associated with the custom entity record.
Given a security role, the same security applies to all activities (standard & custom) at once. You cannot give a different access level or privilege for a specific activity. For example, you cannot restrict “Delete” access to your custom activity but grant “Delete” access to other activities like Task.
You can control security privileges for each custom entity separately.
Visibility in the Application
When creating a custom activity you can check the “Display in Activity Menu” option which if selected, the custom activity will appear in all the Activity menus as well as the ribbon of all the activity-able entities (of course the ribbon can always be modified after).
We can hide custom activities in the activity menus by unchecking the “Display in Activity Menu” box. NOTE: once the activity is created, that setting cannot be modified.
By hiding the custom activity from the Activity Menu, your custom activities will also NOT show up in the “Activities” or “Closed Activities” views and associated views, so you would need a separate view for your custom activity (as if it were a custom entity).
Visibility of custom entities is controlled by the sitemap and form navigation menus.

Associating to the Case Entity
Because Case is an activity-able entity then your custom activity can be associated with a Case without the need of any special custom relationship and you can re-use the “Activities” and “Closed Activities” navigation menu to show all activities including your custom activity.
Custom entities will require a custom relationship to be able to associate them to a case. Therefore, you would require a new section in the form navigation to show specifically your associated custom entities.
Resolving a Case
By default, the case has been built in order to not allow a user to resolve a case as long as any of the related activities (standard & custom) are still open.
There is no validation on the status of the related custom entities when resolving a case.
Calculation of Time Spent on a Case
By default, on completion of the case, the Total time of the case will be calculated from the sum of duration values for associated activities.
When a case is reactivated and then resolved again, Total Time field is calculated with two different options:
1. If no contract associated with case, time spent on additional activities added to original total, included in Total Time.
2. If contract associated with case, only time spent on additional activities included in Total Time.
Associated custom entities have no effect on the calculated Total Time Spent on the case.
Contracts Related to Case
While creating a contract, a user can select an Allotment Type. A user can therefore specify how the support will be “budgeted” (or, “allotted”) for a contract. You can specify number of incidents, or amount of time (linked to activities)
On the contrary, no such behavior has been created on the contract level linked to standard and custom entities.
Dashboards, Charts and Views
By default, will be able to create a single chart comparing different type of standard and custom activities. Since all activities roll up to the “Activity” (activitypointer) base entity, you can create a chart/dashboard/view which takes data from all activity types including your custom activities.
The system won’t allow a user to create a single chart comparing multiple standard or custom entities. One chart will be required by entity.
Extensions in Silverlight or SSRS would be required to combine data from multiple entities.
Some out of the box reports are available will automatically include your custom activity. In addition, the report wizard will allow the user to create very easily some reports comparing all related activities linked to a case on a single Report
No reports are available out of the box for custom entities linked to a case.

In addition, the report wizard could be used by the user but the user won’t be able to combine multiple custom entities linked to a specific case. Thus, there is no simple way to provide an overview of a specific case and its related entities. ( e.g. Case linked to two custom entities: Main entity and a Peer Review)

Sunday, July 29, 2012

Date and Time operators in CRM Explained

When you add conditions to Advanced Find in CRM to filter records based on a DateTime field, some operators such as “Today” are quite clear, while others such as “Next X Weeks” are trickier (e.g. When does the week start?). This post explains in detail what these operators mean and how to combine them to create more powerful filters.

Day Operators

Next X Days: Starts now and includes the next X days (regardless of time). E.g. If it is 3:30PM, “Next 1 Days” includes today after 3:30 PM and goes until the end of the day tomorrow (11:59PM). Note that this is not the same as “Next 24 hours”. When the field is only Date (no Time particle) then usually the time is set to 12AM (hidden) so this operator will not include today.

Last X Days: Includes all values that are before now and on/after X days ago. E.g. If it is 3:30PM, “Last 1 Days” includes today (before 3:30 PM) as well as yesterday the entire day (12AM-11:59PM). Note that this is not the same as “Last 24 hours”. Also note that when you have DateTime fields without a time component, the time will usually be se to 12AM (hidden) so this operator would include today in that case.

Next 7 Days: Behaves the same as “Next X Days” when X == 7.

Hour Operators

Next X Hours: Behaves like “Next 60*X Minutes”. It starts now and it includes X hours ahead. E.g. If it is 3:30PM then “Next 1 Hours” includes from 3:30PM – 4:30PM.

Last X Hours: Includes all values in the current hour before now, as well as all values in the past X hours. (NOT the same as “Last 60*X Minutes). E.g. If it is 3:30PM then “Last 1 Hours” includes from 2:00PM to 3:29PM).

Week Operators

Next Week: This is NOT the same as “Next X Weeks” where X == 1. It includes all values starting on the first day of next week and includes the 6 days after that one. The first day of next week is configurable in the System Settings section. For example, the week can start next Sunday (Default for U.S.) or next Monday (Default for U.K.).


This operator uses a “calendar week”. As an example, if it is Friday and the first day of the week is Sunday then “Next Week” means all values from next Sunday until next Saturday.

Last Week: This is NOT the same as “Last X Weeks” where X == 1. This operator includes all values before the current calendar week. The calendar week depends on the “Frist Day of Week” system setting. For example, if today is Saturday and the “First Day of Week” is Sunday then “Last Week” would include all values starting 2 Sundays ago and until last Saturday.

This Week: Includes all values of the current calendar week.

Next X Weeks: Same behaviour as “Next X*7 Days”. (Not the same as “Next Week” when X == 1). E.g. “Next 2 Weeks” is the same as “Next 14 Days”.

Last X Weeks: Same behaviour as “Last X*7 Days”. (Not the same as “Last Week” when X == 1). E.g. “Last 2 Weeks” is the same as “Last 14 Days”.

Month Operators

Next Month: Includes all values of the next calendar month. If we’re in August then it includes all values in September (same year).

Last Month: Includes all values of the last calendar month (before the current month). If we’re in August then it includes all values in July (same year).

This Month: Includes all values of the current calendar month. If we’re in August then it includes all values in August (same year).

Last X Months: This operator does not use the calendar year. It includes all values before now and on/after the same calendar day on the previous month. E.g. if it is 3:30PM on August 3rd then “Last 1 Months” includes all values between July 3rd all day (since 12AM) and today at 3:29PM. When X == 1, this is NOT the same as “Last Month”. Also note that when you have DateTime fields without a time component, the time will usually be se to 12AM (hidden) so this operator would include today in that case.

Next X Months: This operator does not use the calendar year. It includes all values starting now and until the same calendar day on the next month (inclusive). E.g. if it is 3:30PM on August 3rd then “Next 1 Months” includes all values between now (3:30PM) and September 3rd (until 11:59PM). When X == 1, this is NOT the same as “Next Month”. Also note that when you have DateTime fields without a time component, the time will usually be se to 12AM (hidden) so this operator would not include today in that case.

Older than X Months: This operator does not use the calendar year. It includes all values before the current calendar day of the previous month. E.g. if it is 3:30PM on August 3rd then “Older than 1 Months” operator would include all values on or before July 2nd at 11:59PM.

Year Operators

Next Year: Includes all values of the next calendar year.

Last Year: Includes all values of the last calendar year.

This Year: Includes all values of the current calendar year.

Last X Years: This operator does not use the calendar year. It includes all values before now and on/after the same calendar day on the previous year. E.g. if it is 3:30PM on August 3rd 2012 then “Last 1 Years” includes all values between August 3rd 2011 all day (since 12AM) and today at 3:29PM. When X == 1, this is NOT the same as “Last Year”. Also note that when you have DateTime fields without a time component, the time will usually be se to 12AM (hidden) so this operator would include today in that case.

Next X Years: This operator does not use the calendar year. It includes all values starting now and until the same calendar day on the next year (inclusive). E.g. if it is 3:30PM on August 3rd 2012 then “Next 1 Year” includes all values between now (3:30PM) and August 3rd 2013 (until 11:59PM). When X == 1, this is NOT the same as “Next Year”. Also note that when you have DateTime fields without a time component, the time will usually be se to 12AM (hidden) so this operator would not include today in that case.

Other Operators

Any Time: Same as “Contains Data”. It will return all values which are not blank.

Composite (logical) Operators

Given the operators in Advanced Find, you can combine them and group them to achieve more complex operators. These are some typical examples:

Older Than X Years: Simply multiple X by 12. E.g. “Older than 2 years” is the same as “Older than 24 Months” which is a supported operator.

On Year 2008: This is equivalent to combining “On Or After” 2008-01-01 and “On Or Before” 2008-12-31. You can use the same logic for filters such as “In January 2010

In the Past: You can combine “Last 1 Months” and “Older than 1 Months” to include all the values in the past.

Next 3 Calendar Weeks/Months: Unfortunately you cannot build such a query from DateTime fields. You would have to either store the week/month in a separate numeric field or otherwise build a report that applies additional Datetime expressions to filter the results. CRM only supports filtering by calendar week/month for last, this and next week/month. (same applies to year).

Note: Most of these operators depend on the user’s time zone. For example, a DateTime field value can be “Today” for users in Italy, but “Tomorrow” for users in Canada.

Monday, July 9, 2012

Triggering plugins / workflows when associating entities (N:N)

A question I get asked often is “What is the best way to trigger some custom logic when entities are associated in CRM”? While there is no “good” answer, I will provide a set of different approaches in this post which can be helpful to select the best strategy to implement your custom logic.

When you think of N:N relationships, there are multiple ways to implement them in CRM:

1. Native N:N relationships: These are the relationships you can easily create between 2 entities by customizing the entity relationships.

2. Custom “Intersect” entities: These are custom entities that act as the “glue” between 2 entities. For example if you have multiple students and multiple teachers, you might create a custom entity “Student Teacher Association” which contains a lookup to the student, a lookup to the teacher and then additional relationship metadata such as the course name and classroom. Your custom entity would act as an “intersect” entity representing an N:N relationship between teachers and students.

3. Connections or Relationships: Connections can also be used to relate any 2 entities and assign a “connection role” to the relationship (such as “partner” or “friend”).

I won’t go into details and the pros and cons of the above 3 alternatives since Richard has already done a great job at that in this post. The point I want to make is that depending on how you model your N:N relationships, then the answer around how to implement custom logic when entities are associated changes.

Native N:N Relationships

Consider for example, that you want to send an email every time a user gets assigned a new security role. There as a system N:N relationship between users and system roles called “systemuserroles_association”. If you wanted to intercept these events, you would have to register a plugin on the “Associate” message.

However, because the Associate message does not allow you to specify the primary or secondary entities then you’d need to register it as a “global plugin” (no primary entity). Therefore, your plugin will be triggered every time any 2 (or more) entities get associated by any native N:N relationship. For this reason, you must make your plugin smart enough to be able to identify if the current association is the one you are interested in or not. For the user / security roles example, you would need to add the following code to your plugin:

IExecutionContext context = (IExecutionContext)serviceProvider.GetService(typeof(IExecutionContext));
string useRoleRelationshipName = "systemuserroles_association";
if (context.InputParameters.Contains("Relationship") &&
    useRoleRelationshipName.Equals((context.InputParameters["Relationship"] as string), StringComparison.InvariantCultureIgnoreCase))
    // Assigning new role(s) to a user
    // Send a notification email
    // Another association, not interested, exit

You will need to filter in your plugin to only execute when the “Associate” is called for the relationship(s) in question.

The problem with native N:N relationships is that while you can register plugins, it is not possible to trigger workflows on these kind of events. The only workaround would be that you register a plugin which will then start a specific workflow on-demand, but the workflow engine will not be able to automatically start a workflow when you associate 2 entities with a native N:N relationship.

Custom Intersect Entities

In this case, triggering custom logic is easy because you only need to register a plugin on Create of your custom intersect entity. You will also be able to register workflows in this case because workflows can trigger on Create of any entity. Workflows will also have the ability to access fields from both sides of the relationship since each side is considered a “parent” entity of the intersect entity and you can always access parent entities and their fields from the workflow designer. This approach would also allow you to easily build queries and reports of your relationships.

This approach gives you in general much more flexibility to implement your relationships and the custom logic behind it. One disadvantage that I find with this approach is that you lose some of the neat OOB functionality to relate records. For example, if you want to associate 150 students with one teacher, you will have to create 150 records of these intersect entities one-by-one, while native N:N relationships allow you to select multiple at once and associate them all with one click. You might also miss the “Add Existing” button that you get with native N:N relationships. There are also more limitations in this approach when you want to show a related view because you would have to show a view of the intersect entity and not a view of the related record type (so things like sorting by fields of the related record type is not possible).

Connections (or Relationships)

These are similar to the custom intersect entities and you can define plugins and workflows on create of connection records. However there are a few subtle differences:

1. Connection Roles are solution aware so you can package them in your solution.
2. The connection entity is used for all connections for all entity types. For custom intersect entities you would need one custom entity per association type (which can be good and bad depending on your scenario).

3. You cannot access the fields of the entities getting connected from the workflow designer (you can do this with custom intersect entities).

4. If you register a workflow on Create of Connection, it will trigger every time any 2 records are connected and you would need some conditions in your workflow to filter out the connections you are not interested in.

5. You can customize the Connection entity but it would be strange to add fields to capture metadata about a specific relationship because the fields will be there for all relationships. In that case you should probably consider customizing your own custom intersect entity.

Note that I would not recommend using the CRM “Relationships” as these have been replaced with a more powerful model (Connections) in CRM 2011.

While it is possible to trigger custom logic on association (or disassociation) of entities, you should consider how you model your N:N relationships in CRM and how that would affect your automation possibilities in terms of plugins and workflows.

Note: If you are interested in triggering custom logic for 1:N or N:1 relationships, this is quite simple: You only need to register a plugin (or a workflow) on the “Update” event of the child entity, so whenever the “parent” field of the child is updated then your plugin / workflow will trigger.

Tuesday, July 3, 2012

Bulk Activate / Deactivate Records in CRM 2011

We all love bulk delete because it allows bulk deletion to run asynchronously in the background, it allows recurring bulk delete jobs and it lets you enter an Advanced Find query to specify the exact criteria to select which records to delete. But what about bulk de-activation? Luckily there are tools to allow you to extend the bulk delete functionality to bulk (de)activation of records.

If you follow my blog you might be familiar with the CRM 2011 Workflow Utilities project I have been maintaining. Recently, I have extended it to include a custom workflow step for setting the state of multiple records, similar to bulk delete:

1. Runs asynchronously in the background (workflow)

2. Allows you enter a query to specify exactly which records you want to bulk (de)activate (Uses Advanced Find to specify the query)


Consider this scenario: Your sales manager needs to be able to manually deactivate multiple accounts when they get old. You might need to deactivate thousands of accounts and cannot expect the sales manager to go page by page clicking the “Deactivate” button. You can certainly not expect the sales manager to write an SDK application to do so ;-)

So once you install the CRM 2011 Workflow Utilities solution available here, you can create a workflow and insert a “Bulk Activate / Deactive” step:


The first parameter is used to define the query that defines which records you want to activate/deactivate. You can click on the lookup icon and then click “New”. In this example, I will create a query to deactivate all active accounts older than 1 year:


The second parameter (Target State) correspond to the state code to which I want to set my records. In this case I want the accounts to become inactive, so the corresponding statecode is 1.Most records in CRM have statecode 0 (for Active) and 1 (for Inactive). If you wanted to bulk activate (instead of deactivate) you would select 0 as your target state.

The third parameter corresponds to the target status. The default status is -1 which corresponds to the default status code for your selected statecode. If you want a different status than the default you can always browse the entity metadata to find the correct value. In this example, I want the status to become “Archived” so I look at the account “statuscode” field to find the corresponding value (100000000):


After configuring my custom step, it will look like this:


Note: There are special entities which you cannot activate/deactivate. For example, cases cannot simply be deactivated. They need to be resolved or cancelled, these special operations are not supported by this tool. Additionally, note that the workflow primary entity is irrelevant for this step since the records to de-activate are specified by the query and it can point to a different entity type.

Tuesday, June 5, 2012

CRM 2011: Transporting System Settings with Solutions

When you export a solution you are given the option to include various system settings to be transported with your solution and take effect in the target environment. This post provides some insights into what these system settings are and provides a list of the settings that are transported with the solution.

Upon solution export you are presented with the following dialog for exporting organization system settings:

However, the list above does not correspond exactly to the tabs of the system settings dialog:
So for example, if you want to transport the Date format with your solution, which of the above settings should you include in the solution? Is it even possible to transport all system settings with the solution? The following screenshots of all the system settings specify which system settings are included in which section of the solution export settings, and which ones are not transported at all. Here are the possible settings you can include and I’m using a color code to identify them later on:


Note that the red rectangle means that those system settings cannot be transported with a solution. So here are all the different sections of the system settings mapped according to the color codes above:


Thanks to Jim Daly from Microsoft team for gathering this information and agreeing for me to share it publically. The behaviour might change with future versions or updates of CRM, but I have tested this with CRM 2011 UR6.

Tuesday, May 22, 2012

How to Force Zero Data Points in Date Charts (SSRS)

My team was recently challenged with producing a line chart that uses CRM data to provide counts of records over a period of time. What we found is that if there is not data for a given day, it is quite hard to force the line to have a zero data point instead of completely ignoring the given day. This post explains one of the solutions we found.

It is quite natural to want to report in chart data such as “Show me per day the count of cases that are open on that specific day”. However, the requirement was also that if there are no cases open on a given day, the X axis should still contain the label for that day but the data point should be zero.

The problem: If you don’t have any records for a given date, the report will automatically exclude the date from the X axis as there is simply no datapoint (notice that empty or null datapoint is not the same as not having a datapoint at all!). This is what out chart looked like initially:


Solution Attempt #1: We played with the chart properties and the X axis interval to force the chart to show the X axis per day, even if no data exists for a particular day. This was quite simple, but the result is not as expected:

Note that the line above is extrapolated over 4-Mar-12, but we expected the line to go to zero on that day so this solution did not meet our requirements.

Solution Attempt #2: Now we played with the EmtpyPoint and EmptyPointValue properties of the chart as follows:


However, it unfortunately did not have any effect on our chart because we simply did not have data points on 4-Mar-12, which is not the same as having a null or empty data point. Thus, this solution attempt did not help!

Solution Attempt #3 (CRM Only): Since this report is inside CRM, we tried to register a plugin on RetrieveMultiple which would generate some empty records for ech missing day in the date interval. However, we soon learned that CRM reports execute SQL directly and bypass the CRM pipeline which means that no plugins are ever triggered when retrieving CRM data for reports! Even though we were using FetchXML as the data source for the reports, the plugins were not triggered on either the RetrieveMultiple or the Execute message.

Solution Attempt #4: At this point it was clear that we needed a datapoint for each possible day, and if we want to line to go to zero we would need an empty/null data point for those days for which there are no records. We were using FetchXML data source for this report (CRM) which was creating some restrictions because we could not manipulate the data retrieved. So we had to change the data source to SQL to be able to build a smarter and more complex query which could “generate” the empty data points for those days for which there were no records. After applying this solution, we finally got the expected result:


Solution details:

So how do we generate empty data-points when there is no record for that particular day? We do this in 2 steps:

1. Generate a “DateRanges” table that contains a record for each day in the interval that the graph wants to display:

-- Select the Begin Interval based on Data
SET @DateFrom = (select top(1) ava_date from ('+@CRM_FilteredIncident+') AS ED order by ava_date asc)

-- Select the End Interval based on Data
SET @DateTo = (select top(1) ava_date from ('+@CRM_FilteredIncident+') AS ED order by ava_date desc)

-- Generate a table with one entry per day
;WITH DateRanges AS
SELECT @DateFrom AS 'DateValue'
FROM DateRanges
WHERE DateValue < @DateTo

2. Do an outer join with your data, so then for each possible day, there is going to be at least one record. These commands should be the query in your report DataSet.

left outer join ('+@CRM_FilteredIncident+') AS ED on ED.ava_date = DateRanges.DateValue

It is important when you define your chart’s YValue that you use Count on a field that is not the date field generated (since the count will never be zero). In the Category Groups you would need to select the generated dates so each day will have an entry in the X axis:


Also note that we are using parameterized query that makes use of @CRM_FilteredIncident which is used for supporting pre-filtering data in CRM reports. Otherwise you would just have your table name instead of ('+@CRM_FilteredIncident+').