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.
- 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.
When someone selects an entity in the queue and clicks Accept... that entity it is then moved into that person's "In Progress" queue.
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;
}