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!

8 Comments

  • This is great, bu are you sure that concurrent access will not issue the occasional duplicate number?

    Perhaps a Mutex would help by ensuring that only one thread executes the code at a time?

    Cheers
    Si

  • It doesn't work with lock(). Plugin could be ran by more than one process. use mutex instead.

  • Thanks grega, you are correct, Mutex will protect the plugin against multiple processes. I have updated codeplex.

  • may I know how to implement in CRM4.0 ?
    I have just registerd the .dll but don't know how to continue ...
    Please ..

  • Hey Ben

    Once you register the dll, create a step
    Message: Update
    Entity:
    Stage: Pre
    Pipeline: Synchronous

    Then go into the crm settings section, you'll see 'Incremental Numbering', create a record for your incremental numbering entity.

  • Hi Austin, I'm not sure if that's required since the logic part is wrapped in a try catch

  • I do not think mutex will work in a load balanced front end situation (with more than one front end server)

  • Hi Bob

    You're correct, for load balanced servers you'll need to modify the code so that it checks if the number is available just before updating, this done in a loop with some millisecond sleeper works. (not reliable very high load, you might want to look at other possibilities like external db with a stored proc)

Comments have been disabled for this content.