CRM 4 Incremental Numbering for any Entity
UPDATE 08/01/2009
- Project is now on CodePlex (http://www.codeplex.com/crmnumbering/)
MYOB can only take 8 characters and accountants don't like seeing cryptic Invoice Numbers that CRM generate, so we ended up writing a custom plugin that automatically incremented each invoice. Keeping extensibility in mind we made it work with any customizable entity. Here is how we did it.
We created a simple organization owned entity that held the type of entity you wanted to increment, the property/field you wanted to increment and the current/starting position.
The field to increment must be of type integer.
Next we wrote a plugin that hooked into the Pre-Create event synchronously, check the target, get the incremental settings for this entity, make sure the property specified is not in the property bag, increment the current number and update our custom entity with the newest number.
public void Execute(IPluginExecutionContext context)
{
if (context.InputParameters.Properties.Contains("Target") &&
context.InputParameters.Properties["Target"] is DynamicEntity)
{
DynamicEntity entity = context.InputParameters.Properties["Target"] as DynamicEntity;
// simple query to get incremental settings for this entity
IncrementalNumbering setting = GetSettings(context, entity.Name);
// system generated, if its assigned ignore this record
if (setting != null && !entity.Properties.Contains(setting.PropertyName))
{
int next = setting.CurrentPosition + 1;
CrmNumberProperty increment = new CrmNumberProperty(setting.PropertyName, new CrmNumber(next));
entity.Properties.Add(increment);
// keep track of the latest id inside the custom entity
setting.Increment(context, next);
}
}
}
GetSettings call above finds the matching setting, if it finds one it calls overloaded constructor below passing it the Dynamic Entity which then convert the CRM specific types into basic .NET types.
Here is the IncrementalNumbering class.
public class IncrementalNumbering
{
public class Fields
{
public const string Id = "mag_incrementalnumberingid";
public const string EntityName = "mag_entity_schema_name";
public const string PropertyName = "mag_property_schema_name";
public const string CurrentPosition = "mag_currentposition";
}
public IncrementalNumbering() { }
public IncrementalNumbering(DynamicEntity entity)
{
this.Id = (entity.Properties[Fields.Id] as Key).Value;
this.EntityName = entity.Properties[Fields.EntityName].ToString();
this.PropertyName = entity.Properties[Fields.PropertyName].ToString();
this.CurrentPosition = (entity.Properties[Fields.CurrentPosition] as CrmNumber).Value;
}
public void Increment(IPluginExecutionContext context, int next)
{
using (ICrmService service = context.CreateCrmService(true))
{
this.CurrentPosition = next; // set before calling ToDynamic
TargetUpdateDynamic target = new TargetUpdateDynamic();
target.Entity = this.ToDynamic();
UpdateRequest request = new UpdateRequest();
request.Target = target;
service.Execute(request);
}
}
// include rest of the fields, but leave it for now
public DynamicEntity ToDynamic()
{
DynamicEntity entity = new DynamicEntity(IncrementalNumbering.SchemaName);
PropertyCollection properties = new PropertyCollection();
properties.Add(new KeyProperty(Fields.Id, new Key(this.Id)));
properties.Add(new CrmNumberProperty(Fields.CurrentPosition, new CrmNumber(this.CurrentPosition)));
entity.Properties = properties;
return entity;
}
}
Here is the result

Bit of a hack with converting between CRM and .NET types, keep an eye out for another post where I'll be showing you how to wrap CRM entities so that you're only working with .NET types. If you want the full sample including code; send me an email.
Enjoy!