Thursday 28 July 2011

CRM 2011 - Creating Service Restrictions

To create a service restriction within CRM 2011 using the Organisation service is not a trivial task.  It appears as though the addition of the restriction is at a significantly lower level then, for example, adding an Account. It has taken quite a bit of investigation to get to this point so here goes.
A typical service restriction will consist of the following:
  1. A "CalendarRule" attached to the calendar of the user (daily calendar rule).
  2. An inner calendar or sub calendar attached to this calendar rule.
  3. At a minimum 2 calendar rules attached to the inner calendar.
The user you are trying to add the restriction for should already have a Calendar assigned to them. If they don't, the best way to initialise this is to create their work hours within CRM and CRM will automatically create it for you, then all you need to do is access the SystemUser.CalendarId value of the user. See below:

    SystemUser user = OrgService.Retrieve(SystemUser.EntityLogicalName, UserId, new ColumnSet("calendarid")).ToEntity<SystemUser>();
    Calendar userCalendar = OrgService.Retrieve(Calendar.EntityLogicalName, user.CalendarId.Id, new ColumnSet(true)).ToEntity<Calendar>();

Once you have the calendar loaded you will find a field (Calendar.CalendarRules) that will contain all the rules for the user's calendar.  This is where you will need to add the daily calendar rule. The standard daily calendar rule for a service restriction will also contain a reference to an Inner Calendar (CalendarRule.InnerCalendar) which is the calendar you must add the other 2 calendar rules to. The following outlines the default settings for a daily calendar rule and its associated inner calendar:

    //create the inner calendar
    Calendar newInnerCalendar = new Calendar
                                    {
                                        BusinessUnitId = new EntityReference(BusinessUnit.EntityLogicalName, userSettings.BusinessUnitId.Value)
                                    };
    Guid innerCalendarId = OrgService.Create(newInnerCalendar);
 
    //create the base rule
    baseRule = new CalendarRule
                    {
                        Duration = 1440,
                        ExtentCode = 1,
                        Pattern = "FREQ=DAILY;COUNT=1",
                        Rank = 0,
                        StartTime = ScheduleDate.ToLocalTime(),
                        TimeZoneCode = userSettings.TimeZoneCode,
                        InnerCalendarId = new EntityReference(Calendar.EntityLogicalName, innerCalendarId)
                    };
                
    // update the users calendar with the new rule
    List<CalendarRule> userRules = userCalendar.CalendarRules.ToList();
    userRules.Add(baseRule);
    userCalendar.CalendarRules = userRules;
 
    OrgService.Update(userCalendar);

NOTE: These are the settings that must be used, a change to these settings will most likely cause the rule and calendar to be ignored by CRM or worse cause an un-handled exception.

NOTE: Using "ToLocalTime()" is required when talking to CRM.  This is because CRM accepts a local time but returns a UTC time. Further Details

Once you have created the daily calendar rule (#1) and the inner calendar associated with the rule (#2) then you must add the 2 calendar rules to the inner calendar. These 2 rules are what defines the service restriction.  The first Calendar Rule below outlines the users availability for that particular day, the second outlines the service restriction:

    // load the inner calendar from CRM
    Calendar innerCalendar = OrgService.Retrieve(Calendar.EntityLogicalName, innerCalendarId, new ColumnSet(true)).ToEntity<Calendar>();
    //daily work rule
    CalendarRule dailyWorkRule = new CalendarRule
                                        {
                                            Duration = 540,
                                            Effort = 1.0,
                                            IsSimple = true,
                                            Offset = 480,
                                            Rank = 1,
                                            SubCode = (intSubCode.Schedulable,
                                            TimeCode = (intTimeCode.Available,
                                            TimeZoneCode = -1
                                        };
 
    //create restriction rule
    CalendarRule restrictionRule = new CalendarRule
                                        {
                                            Duration = 540,
                                            IsSimple = true,
                                            Offset = 480,
                                            Rank = 1,
                                            SubCode = (intSubCode.ResourceServiceRestriction,
                                            TimeCode = (intTimeCode.Filter,
                                            TimeZoneCode = -1,
                                            ServiceId = new EntityReference(Service.EntityLogicalName, ServiceId)
                                        };
 
    List<CalendarRule> rules = innerCalendar.CalendarRules.ToList();
    rules.Add(restrictionRule);
    rules.Add(dailyWorkRule);
 
    innerCalendar.CalendarRules = rules;
    OrgService.Update(innerCalendar);

Of these 2 Calendar Rules the are a couple of fields that may be modified, they include:
  1. Duration - This is the time in minutes the rule is scheduled to last.
  2. Offset - This is the time in minutes from 12:00AM (00:00) until the rule is scheduled to start. (ie. 480 = 7hours. Therefore start time would be 7:00AM)
  3. Service id - This is the service the user is restricted from undertaking during the time period.
This is simply a starting point, when modifying the calendar using the web service, as i said earlier, it is at quite a low level.  This means you must be wise about what you do, take into account existing work daily work hours, vacations, breaks, appointments, etc.  If you take your time to get it right you will be rewarded but beware if you make a mistake it will "break" the calendar and you be required to manually remove records using either the Organisation service or direct access to the tables to get it to display again.

No comments:

Post a Comment