Monday, January 26, 2009

CRM 4.0 Bulk Delete Wizard




The BDW is another cool wizard which we developed. As you all know the only way to create a bulk delete job is to programmatically develop one using CRM SDK.I decided to automate this process for a number of reasons. Mainly since our products come with sample data which needs to be erased from the system before the customer go live. Secondly we have extensive auditing and logging which needs to be deleted periodically. Of course there are other good enough reasons to having the ability to create bulk delete jobs in just a few seconds.

Global Features:

  • Supports all languages

  • Supports multi-tenancy

  • Supports IFD

  • Supports IE8



For a complete list of entities which are valid for bulk delete please see CRM advanced find entity list.
Note: The BDW wizard enables you to delete all system jobs such as Bulk delete, Duplicate Delection, Bulk Email, Import, workflows jobs.

The wizard is now available. You may also send your enquiries and questions to support@gicrm.com.


Wednesday, January 21, 2009

CRM 4.0 Creating Interactive Plug-ins




The Plug-ins model is a truly robust mechanism which makes it very easy to enforce business rules and control the way your organization data flows.
However, this model does have a few limitations. One in specific which I find very annoying is the fact you can’t return interactive html to the user and must be satisfied with static textual information. I truly believe ms should consider changing this behavior in their next version.

In order to overcome this limitation I made a small yet unsupported modification to the error dialog page that pops up when you throw an
Invalid plug-in exception. The dialog resides in inside /CRMWeb/_common/error/dlg_error.aspx

In order to make the dialog support HTML messages I added the following function that transforms the ErrorMessage Text to HTML and also added an onload event in the html body tag.


function unsupported()
{
var ErrorMessage = document.getElementById("ErrorMessage");
ErrorMessage.innerHTML = ErrorMessage.innerText;
}



<body onload="unsupported()">


To test this “theory” I created a simple duplicate detection check on the contact entity first and last name.
If a duplicate is found, I construct an HTML error message with a link to the duplicate record and
pass it as an InvalidPluginExecutionException parameter.

To test this out simply register the plug-in on the contact pre create / update event.



using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;

namespace TestPlugin
{
public class DuplicateHandler : IPlugin
{
#region IPlugin Members

public void Execute(IPluginExecutionContext context)
{
if (context.InputParameters.Properties.Contains(ParameterName.Target))
{
#region Check Duplicate Contact [FirstName LastName]

DynamicEntity contact = context.InputParameters.Properties[ParameterName.Target] as DynamicEntity;
String firstName = String.Empty;
String lastName = String.Empty;

if (contact.Properties.Contains("firstname"))
{
firstName = contact.Properties["firstname"].ToString();
}

if (contact.Properties.Contains("lastname"))
{
lastName = contact.Properties["lastname"].ToString();
}


QueryExpression query = new QueryExpression(context.PrimaryEntityName);
query.ColumnSet.AddColumn(context.PrimaryEntityName + "id");

ConditionExpression firstCondition = new ConditionExpression();
firstCondition.AttributeName = "firstname";
firstCondition.Operator = ConditionOperator.Equal;
firstCondition.Values = new object[] { firstName };

ConditionExpression lastCondition = new ConditionExpression();
lastCondition.AttributeName = "lastname";
lastCondition.Operator = ConditionOperator.Equal;
lastCondition.Values = new object[] { lastName };

FilterExpression whereFilter = new FilterExpression();
whereFilter.Conditions.Add(firstCondition);
whereFilter.Conditions.Add(lastCondition);
whereFilter.FilterOperator = LogicalOperator.And;

query.Criteria = whereFilter;

ICrmService Service = context.CreateCrmService(true);
BusinessEntityCollection resultCollection =
(BusinessEntityCollection)Service.RetrieveMultiple(query);

#endregion

#region Retrieve Duplicate HTML

if (resultCollection.BusinessEntities.Count > 0)
{
contact dupContact = resultCollection.BusinessEntities[0] as contact;

String linkStyle = "text-decoration:underline;color:blue;";

String contactUrl = String.Format(
"{3} {4}" ,
linkStyle,
context.OrganizationName,
dupContact.contactid.Value.ToString(),
firstName,
lastName
);

String errorMessage = String.Format("Duplicate Contact: {0}",contactUrl);

throw new InvalidPluginExecutionException(errorMessage);

}

#endregion
}

#endregion
}
}
}

Monday, January 19, 2009

CRM 4.0 State Level Security Wizard


Since the release of the FLS wizard I received a few enquiries about the FLS ability to control the change of an entity state and status codes.
Although the FLS does not control this type of behavior we have built a complete state manager wizard that allows us to control the entire application state.

The motivation which has driven me to develop this type of functionality is the need to control application workflows that span different user roles.
Consider a scenario where you have a project entity with logical statuses (e.g. Draft, Prepared, Ready to launch, Approved etc) and which represent the status that your project is in. You need to enable or disable a specific role from changing the project status depending on his function within that project.

Currently there is no way of doing that without specific plug-in development.
The wizard aims to solve two major problems:
1. Allowing you to control any type of entity status without the need to development.
2. Allowing the organization to shift from one paradigm to another by changing roles responsibility without the need for further develop or change your workflows.

The nice thing about this wizard is that its foundation is completely generic and allows an organization to completely control the change of state for any given entity. If you’re looking for a supported way to control who deactivates or activates an entity, want to manage whether a user can win or lose an opportunity, need to decide if a service rep can cancel or resolve a case or any other “SetState” behavior, this wizard will do the job.

Think about the possibilities that this type of functionality uncover. The SMW wizard has certainly solved many of our business problems and is an inseparable part our overall solution.

Similar to the FLS wizard, you can create a complete organization security hierarchy. This means you can set a setstate behavior at the business unit level , override those settings at the role level and create exceptions for individual users.


The following presentation displays 4 simple scenarios.
First Scenario: Control who activates and deactivates the account entity.

Second Scenario: Controls whether a user can cancel a case or set it state to waiting for details.

Third Scenario: Controls whether a user can close an opportunity as won.

Forth Scenario: Shows how to control custom status reasons added to a test entity.


I’m offering this wizard under the same sharing paradigm which I introduced a few weeks ago.
The State manager wizard and the entire set of wizards will be available in the next few days.

If you have questions or enquiries you may send them to support@gicrm.com.

If you need to rewind the presentation simply right click the flash movie and click rewind, then click play.

The proposed property (source code) price is 1000$ USD.



Here is a short description of how the SMW wizard affects CRM OOB entities and the type of control you can gain by using it:

Controlling activation and deactivation of any customizable and custom entities
Controlling publication of kb articles form draft to unapproved to published
Controlling case resolution
Controlling contract activation and cancelation
Controlling invoice cancelation and fulfillment
Controlling lead qualification
Controlling opportunity qualification (win, lose)
Controlling order fulfillment and cancelation
Controlling quote qualification (win, lose)
Controlling custom status reasons

Global Features:
Support for all languages
Supports Multi-tenancy
Supports IFD
Supports IE8