Thursday, November 20, 2008

Queues in MS CRM

There are a lot of misconceptions about queues. They only apply to cases and activities.  While the terminology is the same, assigning a case or activity to a queue is not the same as assigning an entity to a CRM user or team. Programmatically what is being used is a RouteRequest rather than an AssignRequest.

To get a better idea how this works we'll look at database. There are two entities storing queue information, the Queue and the QueueItem. These are not customizable.

Queue – (table) contains all queues

  • There are two queues automatically created for each CRM user. 
    • Assigned
    • In Progress
  • Any user defined queues that you create are also stored here.
    • example:  My New Public Queue

QueueItem – (link table)  Contains an entry for each entity assigned to a queue.

  • An item can only belong to one Queue at a time,
  • The only entities that can below to a Queue are:
    • Activities ( email, tasks, etc. )
    • Cases

An activity or case retains its owner and is not modified in any way when it is assigned to a queue. It is just added to the QueueItem list.  An entity can ONLY belong to one queue at a time.

Normal Lifecycle

When created a case or activity is added to the Assigned queue of the owner and it will stay there until it is completed/closed/canceled.

Sometimes a workflow will assign an entity to a user defined queue. (Below is an example that just puts all created Cases into a Support queue.) You might want logic with timers to move Cases around, or you might have different queues by subject, or related account territory. The important thing is that the queue is used as a natural part of the customer's business process.

image

When someone selects an entity in the queue and clicks  Accept... that entity it is then moved into that person's "In Progress" queue.

image

Example code working with Queues

Creating a Queue

var newQueue = new queue
{
    name = "My New Public Queue",
    businessunitid = new Lookup { Value = BusinessUnitId, type = EntityName.businessunit.ToString() },
    primaryuserid = new Lookup { Value = UserId, type = EntityName.systemuser.ToString() },
    queuetypecode = new Picklist { name = "Public", Value = 1 }
};

service.Create(newQueue);

Assigning an incident to a Queue

// Target the incident var target = new TargetQueuedIncident { EntityId = incidentId }; // Create a RouteRequest ( you would need to query for your Queue Id's ) var route = new RouteRequest { Target = target, RouteType = RouteType.Queue,
SourceQueueId = currentQueueId.Value EndpointId = finalQueueId, }; // Execute the route var routed = (RouteResponse)service.Execute(route);

Tracking Queue Assignment in a Plugin

One of the related improvements to MS CRM 4.0 is the inclusion of the Route Message for Plug-ins.  For example, you can now trigger based on a Case being routed to a queue even though the case entity is not modified in any way.

Your code can inspect the SourceQueueId to see what queue it is coming from and the EndpointId to see the destination queue.

This link shows a complete list of the Plug-in Message Input Parameters. You can see that the Route Message has 3 input parameters, two which I mentioned (SourceQueueId and EndpointId) as well as RouteType which has three values ( Auto = 0 ( automatic route) , User = 1 (route to a user's private queue), Queue =  2 (route to a public queue) ) You could use the RouteType to filter out a chunk of queue routes that wish to ignore.

The fact that the dynamic entity of an incident contains no information about the queue it is assigned to means that you need to examine the context.InputParameters.Properties to find out which queue the case is coming from and which queue it will finally call home.

public void Execute(IPluginExecutionContext context)
   {
      DynamicEntity entity = null;

    if (context.InputParameters.Properties.Contains(ParameterName.Target) &&
       context.InputParameters.Properties[ParameterName.Target] is DynamicEntity)
    {
        entity = (DynamicEntity)context.InputParameters.Properties[ParameterName.Target];
        
        if (entity.Name != EntityName.incident.ToString()) { return; }
        if (context.MessageName != MessageName.Route.ToString()) { return; }
        
        Guid SourceQueueId = ((Moniker)context.InputParameters.Properties["SourceQueueId"]).Id;
        Guid EndpointId = ((Moniker)context.InputParameters.Properties["EndpointId"]).Id;
    }

7 comments:

Ashish Garg said...

Hi,

I need to assing a incident from one queue to another queue using a workflow.
In a workflow when we use Assing record step there we can hard code the Queue Name to which The incident ll get assigned to.
Now what i need to do is Assign the case to a queue dynamically i.e. Based on some if condition the incident should to a particular queue.
I dont want to make multiple if conditions, instead i need to dynamically assign them to respective queues.
I know i need to write a custom workflow assembly for that. Can you please guide me on how to go about it.

Er.ashishgarg@gmail.com

Mark Kovalcson said...

This article shows how to create a custom workflow.

http://crmscape.blogspot.com/2009/01/crm-40-custom-workflows.html

Between this Queues article and that article I think you have most of what you need.

Syed Akif Kamal said...

Hi,

Nice article. A small question. I need to remove an email queue item from In-progress queue whenever it is converted a case or lead. How can it be achieved?? Any idea.

Regards,

Anonymous said...

Hi Mark,

Your article was very helpful for me. I need to move the case into the 'in progress' queue.

May I know why the case that I create by code go to 'in progress' queue? The queue should go to 'assigned' queue first I think.

After the case go to a queue, the case is only visible for the user who create the queue.

In my case, the case in queue is only visible for the user that is used as default credential when create case by code.

Could you please advise, Mark?

Thank you in advance.

Syed Akif Kamal said...

Nice Article.....

I have a small issue. I have queue configured to receive emails but whenever a new email is received, it is also showed in the "in progress" queue of the queue owner, means it is visible in public queue and "in progress" queue of queue owner.

So why it started happening :S Any help will be highly appreciated

kenn said...

Can a plugin be triggered by a new activity (like an email) got inserted into a queue?

Thanks!

Mark Kovalcson said...

Ken if you look at the bottom of the article is talks about tracking queue assignment and there is a link to a list of all of the queue related methods availble.

Anonymous, when you create a case (incident entity), if you specify the owner it most likely considers it in progress, because it would be owned by the user the webservice is running as by default. You can find the case in the queue and always programatically route it to the assigned queue.

Ashish,
I have a post on creating a custom workflow, this article combined with that should get you on your way.
http://crmscape.blogspot.com/2009/01/crm-40-custom-workflows.html