Tuesday 31 May 2016

How to customise the SLA in MS CRM

How to customise the SLA in MS CRM

How to Read Orgnisation Business Closure



Today we are going to learn how to customise your SLA.


Although MS has provided  Enhanced SLA which can full-fill most of the business requirements but when requirements are so complicate that can't be handled using system Enhanced SLA, developing a custom SLA functionality is the only solution.


In this post we'll not discuss anything regarding CRM System SLA because there are many posts out there on the internet for the same and if you are here reading this post, means you want your SLA to work beyond CRM System SLA.

Here i have created a hypothetical scenario on the basis of which your customer might want the SLA to run.


1.

a) As a training scenario, i have considered that for  your customer wants different SLA hours    for cases assigned to different teams which are working in different shifts (here we'll cal,l it SLA window). 


b) Lets suppose there are 20 different teams in an organisation for which different SLA needs to be set up, then such custom SLA solution are suitable.

b) We will take  care of Organisation Business Closure as well in calculating SLA.


2.  I have created a Custom entity named SLA Configurator in my organisation with following fields:

Field Name Data Type Validation  Purpose
Name Text NA A name for SLA record
SLA window Start whole number Range 0-24 Defines SLA start time
 or shift Start time
SLA window End whole number Range 0-24 Defines SLA end time
or shift end time
Team Lookup NA Team for which this SLA
 needs to be implemented
Resolution SLA in hrs whole number Range as required Total No of SLA hrs
for this scenario
Refer to image below:



3. 
a) Now what we need to do is that on creation  of case, needs to get the team for which the case has been created, and fetch the proper SLA configuration records according to the team.

b) We'll write this whole logic in a plugin which will fire on create of Case. I assume that you will be able to do that.

c) Below is the function to which we'll pass SLA Configuration Record and organisation service object as parameters. It'll return you the date to which your Resolve by needs to be set.


Calculation are as follows:
  • A Case is created for Team1
  • SLA Configuration Master have following data for Team1 


Let's say case created on 31 May,2016 01:00PM
Case assigned to Team1 
SLA hrs for Team1 : 24
SLA start window: 10 AM
SLA End Window: 07 PM
Business Closure have holiday on 1st June,2016
Then Resolve by:

31st May,2016         :    06 hrs     (1 PM- 7 PM)
1st June                     :    Holiday in Business Closure
2nd June                   :    09 hrs      (10 AM-07 PM)
3rd June                    :   09 hrs      (10 AM-07 PM)
Total Working hrs :    24 hrs

Resolve By                :   03 June,2016 07:00PM


Below is the code snippet:

 
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


 public static DateTime CalculateSla(Entity SLAConfigurator, IOrganizationService service)
        {

            int workstarttime = 0;
            int workendtime = 24;
            if (SLAConfigurator.Contains("new_slastartwindow") && SLAConfigurator.Contains("new_slaendwindow"))
            {
                int start = SLAConfigurator.GetAttributeValue<int>("new_slastartwindow");
                int end = SLAConfigurator.GetAttributeValue<int>("new_slaendwindow");
                if (end > start)
                {
                    workstarttime = start;
                    workendtime = end;
                }
            
            }

            int SLAInMin = 600;  //Default Value
            if(SLAConfigurator.Contains("new_resolvesla"))
            SLAInMin = SLAConfigurator.GetAttributeValue<int>("new_resolvesla") * 60;

            DateTime tempdate = DateTime.UtcNow.ToLocalTime();
            
            while (SLAInMin > 0)
            {
                if (tempdate.Hour >= workstarttime && tempdate.Hour < workendtime && lookinbusinessclosure(tempdate, service))
                {
                    tempdate = tempdate.AddMinutes(1);
                    SLAInMin--;
                }
                else
                {
                    while (!(tempdate.Hour >= workstarttime && tempdate.Hour < workendtime && lookinbusinessclosure(tempdate, service)))
                    {
                        tempdate = tempdate.AddMinutes(1);
                    }
                }
            }
            
            return tempdate;

        }
#region businessclosure
        private static IEnumerable<Entity> GetBusinessClosureCalendarRules(IOrganizationService service)
        {
            // Get Organization Business Closure Calendar Id
            Guid orgId = ((WhoAmIResponse)service.Execute(new WhoAmIRequest())).OrganizationId;
            var organization = service.Retrieve("organization", orgId, new ColumnSet("businessclosurecalendarid"));

            var query = new QueryExpression("calendar")
            {
                ColumnSet = new ColumnSet(true),
                Criteria = new FilterExpression()
            };

            // Add condition to get Get Calander where CalanderId is equal to Organization's businessclosurecalendarid
            query.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, organization["businessclosurecalendarid"].ToString()));

            // Get Calendar
            var businessClosureCalendar = service.RetrieveMultiple(query).Entities[0];

            // Return the Calendar rules
            return businessClosureCalendar != null ? businessClosureCalendar.GetAttributeValue<EntityCollection>("calendarrules").Entities : null;
        }
        public static bool lookinbusinessclosure(DateTime tempdate, IOrganizationService service)
        {
IEnumerable<Entity> businessClosures = null; //Define it static globally 
            if (businessClosures == null)
            { businessClosures = GetBusinessClosureCalendarRules(service); }
            foreach (var closure in businessClosures)
            {
                var startDate = (DateTime)closure["effectiveintervalstart"];
                var endDate = (DateTime)closure["effectiveintervalend"];
                if (tempdate >= startDate && tempdate <= endDate)
                    return false;
            }
            return true;  //true if not a holdiday
        }
        #endregion
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////




4. Here we have taken care of Business closure as well. So this is how you can set up your custom SLA. 

Your requirements might be different and based on that you can customise it as you want.

Comments are highly appreciated..!!!

Happy CRMing 











No comments:

Post a Comment