Sunday, March 20, 2016

Round Robin Assignment Microsoft Dynamics CRM

What is Round Robin?

It is rotation of tasks through a group. A task could be a lead, case etc. Round Robin term frequently used when to assign tasks to team members. Leads and cases are commonly assigned through “Round Robin” implementation, but it can used for other entities too.

In this blog, I have discussed Round Robin assignment for leads in Microsoft Dynamics CRM, but the concept is same for other entities too.

In this example, we assign newly generated lead to a member of specific team (SalesTeam), instead of doing it manually we have done it through round robin. Here "SalesTeam" can have variable members, and team size  can change any time (member(s) can be added or deleted).

All this is achieved through a custom entity "counter", workflow and custom activity.

Custom Entity: "counter" entity will have integer value in a field "currentcounter" and 1:N relationship between "counter" and "lead" entity. This "currentcounter" will be pointer to a member of "SalesTeam" to whom new lead should get assigned. When "currentcounter" values reaches to threshold i.e. Count of Member of "SalesTeam", it will get reset. 

Custom Activity: It provides a user(member) entity record which belongs to "SalesTeam" based on "currentcounter" value of "counter" entity and also provides next "currentcounter" value calculated based on no of members in team ("SalesTeam").

Workflow: Assign lead to a user and update "currentcounter" value in "counter" entity by the value returned from custom activity.

Lead
Sales Team Member
CurentCounter
Remarks


1
“counter” and “lead” has 1:N relationship, a record has added in “counter” entity with “currentcounter” value set as 1, which is pointer to first member of “SalesTeam”
Lead1
USER1
2
Condition: CountofMembers(SalesTeam)!=currentcounter Action: INCREMENT currentcounter by 1
Lead2
USER2
3
Condition: CountofMembers(SalesTeam)==currentcounter Action: RESET currentcounter to 1
Lead3
USER3
1
Condition: CountofMembers(SalesTeam)!=currentcounter Action: INCREMENT currentcounter by 1
Lead4
USER1
2
Condition: CountofMembers(SalesTeam)!=currentcounter Action: INCREMENT currentcounter by 1
Lead5
USER2
3
One more member added to team (user4)
Condition: CountofMembers(SalesTeam)!=currentcounter Action: INCREMENT currentcounter by 1
Lead6
USER3
4
Condition: CountofMembers(SalesTeam)==currentcounter Action: RESET currentcounter to 1
Lead7
USER4
1
Condition: CountofMembers(SalesTeam)!=currentcounter Action: INCREMENT currentcounter by 1
Lead8
USER1
2
Two members are deleted from team (User2 and User3)
Condition: CountofMembers(SalesTeam)==currentcounter Action: RESET currentcounter to 1


Initially system will have one record inserted for counter entity and have value "1" for "currentcounter" field. Based on team size the "currentcounter" value will be updated.

*Note: Team name "SalesTeam" is hard coded  and case sensitive in this example. In case you are implementing it for a different team, change its name accordingly.

Implementation Round Robin

A. Customization

Create Custom Entity “Counter”



Add Field “currentcounter” to Custom Entity “counter”



Create 1:N relationship between “counter” and “lead” Entity



1.       Customize “lead” Entity Form




Add relational lookup to the lead entity form and change its visibility setting from field properties.



Save and Publish your changes, and add an entity record for counter entity




B. SDK - Custom Activity

Create custom activity and register it in Plug-in Registration Tool.


using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;
using System;
using System.Activities;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POC.AssignCounter
{
    public sealed partial class GetUseronCounter : CodeActivity
    {

        protected override void Execute(CodeActivityContext executionContext)
        {
            try
            {
                IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

                IOrganizationServiceFactory serviceFactory =
                  executionContext.GetExtension<IOrganizationServiceFactory>();

                IOrganizationService service =
                    serviceFactory.CreateOrganizationService(context.UserId);

                //Get entity from InArgument
                Entity counter = service.Retrieve("new_counter",
                   this.InputEntity.Get(executionContext).Id, new ColumnSet("new_currentcounter"));
                             
                if (counter.Contains("new_currentcounter"))
                {
                    //Fetch xml to get users of a team. Here one user will be returned per page and page position will be
                    //decided on current counter value.
                    string xmlquery = "<fetch version=\"1.0\"  mapping=\"logical\" distinct=\"true\" page=\"" + (int)counter["new_currentcounter"] + "\" count=\"1\" returntotalrecordcount=\"true\">" +
                                        "<entity name=\"systemuser\">" +
                                        "<attribute name=\"systemuserid\" />" +
                                        "<order attribute=\"fullname\" descending=\"false\" />" +
                                        "<link-entity name=\"teammembership\" from=\"systemuserid\" to=\"systemuserid\" visible=\"false\" intersect=\"true\">" +
                                        "<link-entity name=\"team\" from=\"teamid\" to=\"teamid\" alias=\"aa\">" +
                                        "<filter type=\"and\">" +
                                        "<condition attribute=\"name\" operator=\"eq\" value=\"SalesTeam\" />" +
                                        "</filter>" +
                                        "</link-entity>" +
                                        "</link-entity>" +
                                        "</entity>" +
                                        "</fetch>";

                    FetchExpression query = new FetchExpression(xmlquery);
                    EntityCollection users = service.RetrieveMultiple(query);

                    //Set out argument OutputEntity- first user entity of resultset.
                   this.OutputEntity.Set(executionContext, new EntityReference("systemuser", new Guid(users[0].Attributes["systemuserid"].ToString())));

                    int newcounter = 1;
                    //Counter value should not exceed to total member count of team, in case if it exceeds
                    //that means user has been deleted from team.
                    if ((int)counter["new_currentcounter"] >= users.TotalRecordCount)
                    {
                        //Set default value 1
                        newcounter = 1;                                          
                    }
                    else
                    {
                        //Increment by 1 current counter value
                        newcounter = (int)counter["new_currentcounter"] + 1;
                    }

                    //Set out argument OutputCounter- new counter value, that will be further
                    //used by workflow to update counter entity.
                    this.OutputCounter.Set(executionContext, newcounter);

                }            

            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException("GetUseronCounter ERROR>>>>>: " + ex.StackTrace.ToString(), ex);
            }
        }

        [RequiredArgument]
        [Input("Counter")]
        [ReferenceTarget("new_counter")]
        public InArgument<EntityReference> InputEntity { get; set; }

        [Output("user")]
        [ReferenceTarget("systemuser")]
        public OutArgument<EntityReference> OutputEntity { get; set; }

        [Output("NewCounter")]   
        public OutArgument<int> OutputCounter { get; set; }

    }
}


C. Workflow Creation
     

Create a synchronous workflow 




     When a new lead is created in system, this real time workflow will get triggered. And all the steps defined will execute in order.

Step 1: Set a counter value for newly created lead. A lead can be created from web forms or through SDK calls. We don't want user to select counter entity every time whenever a new lead is created in system. Also there is a relationship between counter and leads, therefore a counter record needs to be set for lead and round robin implementation.




Step 2: Custom activity will be called, it takes the counter entity assigned to the lead.







The above activity will be returning two parameter, one will be the user to whom leads should be assigned and the other will the next "currentcounter" value

Step 3
: Update the "counter" entity's  "currentcounter" field value by the updated value returned from Step2.




Step 4: Assign lead to the returned system user from custom workflow activity Step 2. 






Step 5
: Stop the workflow with "Success"


Step 6
: Save and Activate workflow.

Test - Implementation Round Robin

Create Sales Team and add members




Create leads in system it will be auto assigned to Sale’s team members.





You can add or delete members to team, round robin will assign leads to a member of team.





Friday, March 18, 2016

Configuring Shared Mailbox Microsoft Dynamics CRM Online and Exchange Online

Many of us have sent emails to support team for any issue related to any product, services etc. Business has their dedicated or shared customer support that respond to the customer queries through emails, phone, fax etc. 


Business asks you to design customer support for their product and services. Business will provide a support email to all there valuable customers. Customers will send queries and concerns on this support email. That will be queued in Microsoft Dynamics CRM and assigned to dedicated members of a team (round robin) for handling requests and respond to customer's email with a solution or escalate the issue further. In the entire process the employee/members can send email through their individual mailbox or by support mailbox.




Mailbox and CRM Queue




Configure Shared Mailbox

Administrators can configure or create shared mailboxes in exchange on-line.


Shared Mailbox - Exchange On-line


Enter name, email address and Members (who monitor and send email from this shared mailbox).


Configure Queue Microsoft Dynamics CRM

Create a queue in Microsoft Dynamics CRM.
Shared Queue Configuration


Shared mailbox and Incoming email id should be same. "Convert Incoming Email to Activities" option will convert the incoming emails to email activity in CRM system.

Configure Queue Mailbox Microsoft Dynamics CRM

Configure queue mailbox for incoming emails



Shared Mailbox Configuration


Both Incoming and Outgoing Email synchronization method should be "Server Side".

Click Save, Approve Email and Test and Enable Mailboxes.

Send Email To Shared Mailbox

Email send to Shared Mailbox

Track Send Email In Shared Queue

Email will be synchronized in Shared Queue. 

Receive email added as Queue item

Open email activity from shared queue, here user has can reply to that email by their email id or they can select Shared Queue email address in "From" look up field.

Reply from User Mailbox



Reply from Shared Mailbox

Incoming emails are converted to activities in CRM system. Activities can be assigned to user(s)/member(s) either manually or through any automated process. 


Thursday, March 17, 2016

Configuring Forward Mailbox in Microsoft Dynamics CRM and Exchange Online


For incoming emails you can use either of mailbox configuration.

  • Individual Mailbox - Each CRM user has its own incoming and outgoing server synchronization set up.
  • Forward Mailbox- A centralized mailbox at exchange, CRM monitors this mailbox for incoming messages. And all CRM user's mailbox monitors this Forward mailbox.
Forward mailbox reduces administrative effort. To configure forward mailbox, adminstrators would require to do configuration (Create rules to send incoming emails to Centralized mailbox) both at Exchange and CRM end.


Configuration Exchange On-line





In the above diagram, Mailbox 1, Mailbox 2 and Mailbox 3 have rules on incoming emails, if rule condition matches then incoming email is forwarded as attachment to Mailbox 4.


Rule - Exchange Online



Configuration Microsoft Dynamics CRM

Add Forward Mailbox

Go to Settings, Email configuration.then click mailboxes. Click Add new forward mailbox. 




*Note: 

  • Email address will be your exchange email address (Mailbox that receives all the forwarded emails)
  • Server Profile should be Microsoft Exchange Online (If exchange is hosted in office 365)
  • Incoming Email should have server side synchronization. 
  • Forward mailboxes does not have Outgoing email synchronization. It should be set "None"

Click Save, Approve Email and Test and Enable Mailboxes.



Update User Mailbox - Change Synchronization Method (Incoming Email)

Open any existing user mailbox and change incoming synchronization from "server side synchronization" to "forward mailbox".






Click Save and Test and Enable Mailboxes.

Now you are all set to receive emails from forward mailbox in MS CRM. 


Monday, March 14, 2016

Microsoft Dynamics Event Execution Pipeline

Every action in Microsoft Dynamics CRM subscribes to an event. Every action perform on CRM client are handled by Organization web service, which is part of CRM server. There are ways to extract data from dynamics CRM. Example

1. Web API
2. Organization Data Services (Deprecated in 2016)
3.  Organization Service - SOAP endpoints

Each of these methods are wrapper to fetch CRM data which internally linked to the CRM server organization web service. 



When any event is raised in CRM system, Server generates Organization web service request message which is then passed to series of stages. Stage 10 Pre-Validation, stage 20 Pre-Operation and stage 40 Post-Operation are only available for the Plug-in registration.

Any WEB API HTTP request to update a property of an entity will be internally catered by Organization web service. 





In the above flow, organization request passes from stage 10 to stage 40, each of the stage has significance and can update the organization message accordingly.

Stage 10: Pre-Validation: Use this stage when to perform any task prior to any security check. An example, transaction amount should be greater than $500. If user has entered any  value in transaction amount field which is less than expected value then the whole execution process should be aborted. Also Stage 10 is not part of database transaction, any create, update or delete operation perform on any entity will not roll back in case any exception raised in stage 20, 30 and 40. 

Stage 20: Pre-Operation: Use this stage when you want to perform any operation before the main operation in database transaction. An example, you want to log some analytic data in custom entity before main operation performs. However you want any exception in Main operation will also roll-back custom entity record. 

Plug-in code in pre-operation runs under the security context of the user (Calling, Adminstrator, System etc). In case user does not have permission on entity, properties or entity images, then the process will be aborted and exception will thrown by system.

Stage 30: Main Operation: You cannot register Plugins in this stage, this is reserved for system core operation. Main operation executes in the context of impersonated user. In case impersonated user doesn't have sufficient privileges, the core system operation will be aborted and exception will be thrown.

On successful execution, an organization response message will be generated and passed to the next stage.

Stage 40: Use this stage when to perfom any operation after the main operation. An example, whenever an account is created it must be assigned to some agent. So account has been created in stage 30, and response message will be having GUID value populated in ID field. You can use this id value and assign it to some agent.

*Stage 20, 30 and 40 executes in database transaction. Any exception in either of stage will roll-back the whole transaction i.e. error in stage 40 will roll back stage 30 and stage 20 operations. However any operation performed in stage 10 will not roll back.

The final response message is send back to the client.