Introduction:
Microsoft Dynamics CRM has comprehensive Calendar management capabilities to manage work schedules.
You are allowed to not only specify the work hours but also the break times when the resource would be unavailable.
Here we are demonstrating how to add breaks to daily work schedule programmatically.
Calendar and Calendar rules entities in CRM are always tricky to deal with, when it comes to handle them through program.
In the below code we will Add a break on 6th April 2015 from 12:30 to 1:00 PM:
//First read the UserId for whom you need to add break Guid userid = ((WhoAmIResponse)service.Execute(new WhoAmIRequest())).UserId; //Next we need to get the Calendar associated with the user. Every user has a calendar associated with it. Entity userEntity = service.Retrieve("systemuser", userid, new ColumnSet(new String[] { "calendarid" })); //Get the calendar for the user Entity userCalendarEntity = service.Retrieve("calendar", userEntity.GetAttributeValue<EntityReference>("calendarid").Id, new ColumnSet(true)); //The daily schedule of the user is stored in the form of calendar rules. //Here we are retrieving all the calendar rules related to the particular User Calendar found earlier. EntityCollection calendarRules = (EntityCollection)userCalendarEntity.Attributes["calendarrules"];
What is Inner Calendar?
Inner Calendars are created so that they can be used by other calendars to build different time slots or rules in the System.
// Create a new inner calendar Entity newInnerCalendar = new Entity("calendar"); newInnerCalendar.Attributes["businessunitid"] = new EntityReference("businessunit", ((Microsoft.Xrm.Sdk.EntityReference)(userCalendarEntity["businessunitid"])).Id); //create newInnerCalendar Guid innerCalendarId = service.Create(newInnerCalendar);
First we are creating a calendar rule specifying the duration to be 1440 minutes i.e. 24 hours as we want to create this rule for one day only.
// Create a new calendar rule and assign the inner calendar id to it Entity calendarRule = new Entity("calendarrule"); calendarRule.Attributes["duration"] = 1440; // 24hrs in minutes //It specifies the extent of the Calendar rule,generally an Integer value. calendarRule.Attributes["extentcode"] = 1;
//Pattern of the rule recurrence. As we have given FREQ=DAILY it will create a calendar rule on daily basis. We can even create on Weekly basis by specifying FREQ=WEEKLY.
INTERVAL=1; – This means how many days interval between the next same schedule. For e.g if the date was 6th April and interval was 2, it would create a schedule for 8th april, 10th april and so on…
COUNT=1; This means how many recurring records should be created, if in the above example the count was given as 2, it would create schedule for 6th and 8th and then stop. If the count was 3, it would go on until 10th and then stop
calendarRule.Attributes["pattern"] = "FREQ=DAILY;INTERVAL=1;COUNT=1"; //Rank is an Integer value which specifies the Rank value of the Calendar rule calendarRule.Attributes["rank"] = 0; // Timezone code to be set which the calendar rule will follow calendarRule.Attributes["timezonecode"] = 035; //Specifying the InnerCalendar Id calendarRule.Attributes["innercalendarid"] = new EntityReference("calendar", innerCalendarId); //Start time for the created Calendar rule calendarRule.Attributes["starttime"] = new DateTime(2015, 04, 06, 0, 0, 0, DateTimeKind.Utc);
Now we will add this rule to the earlier retrieved calendar rules
calendarRules.Entities.Add(calendarRule); // assign all the calendar rule back to the user calendar userCalendarEntity.Attributes["calendarrules"] = calendarRules; //update the user calendar entity that has the new rule service.Update(userCalendarEntity); //Above we created a Calendar rule, now below we are creating two more Calendar rules one specifying the Working hour in the day (i.e. on 6th April 2015) and other for specifying the Break time (30 minutes) in a day.
Calendar rule for Working Day :
Entity workingHourcalendarRule = new Entity("calendarrule"); //Duration of Working hours in minutes (9 hours i.e. 540 minutes) workingHourcalendarRule.Attributes["duration"] = 540; //total work hours duration //Effort available for a resource (User) during the time described by the calendar rule i.e. Capacity part in the Calendar rule workingHourcalendarRule.Attributes["effort"] = 1.0; // It is a Flag used in vary-by-day calendar rules. workingHourcalendarRule.Attributes["issimple"] = true; // offset 480 i.e. 8 hours from start time (12:00) i.e. Working hour start from 8 am
Now, what actually this “offset” mean?
In the earlier Calendar rule which we updated in CRM we had set the start time by default to 12 am by setting the below attribute:
“calendarRule.Attributes["starttime"] = new DateTime(2015, 04, 06, 0, 0, 0, DateTimeKind.Utc);” workingHourcalendarRule.Attributes["offset"] = 480; //to indicate start time is 8 AM //Rank of the Calendar Rule workingHourcalendarRule.Attributes["rank"] = 0; //Sub Type of the Calendar rule.For setting Work hours it is 1. workingHourcalendarRule.Attributes["subcode"] = 1; //Type of calendar rule such as working hours, break, holiday, or time off. 0 for working hours workingHourcalendarRule.Attributes["timecode"] = 0; // Local time zone for the calendar rule. workingHourcalendarRule.Attributes["timezonecode"] = -1; //Specifying the InnerCalendar Id workingHourcalendarRule.Attributes["calendarid"] = new EntityReference("calendar", innerCalendarId);
Calendar rule for Setting Break in the Day from 12:30pm – 1pm
Entity calendarRulebreak = new Entity("calendarrule"); //Duration of Break: 30 minutes calendarRulebreak.Attributes["duration"] = 30; calendarRulebreak.Attributes["effort"] = 1.0; calendarRulebreak.Attributes["issimple"] = true; //We setting the offset to 750minutes (i.e. 12.5 hours) .As explained for above part here we are specifying when this rule will start. (I.e. when the break starts) In our case it will be 12 am + 12.5 hours = 12:30 pm //Duration of Break: 30 minutes calendarRulebreak.Attributes["offset"] = 750; calendarRulebreak.Attributes["rank"] = 0; //SubCode=4 for Specifying Break calendarRulebreak.Attributes["subcode"] = 4; //TimeCode=2 for Specifying Break rule calendarRulebreak.Attributes["timecode"] = 2; // Local time zone for the calendar rule calendarRulebreak.Attributes["timezonecode"] = -1; calendarRulebreak.Attributes["calendarid"] = new EntityReference("calendar", innerCalendarId); //Add working hour rule to InnerCalendar Rules innerCalendarRules.Entities.Add(workingHourcalendarRule); //Add Break Hour rule to InnerCalendar Rules innerCalendarRules.Entities.Add(calendarRulebreak); newInnerCalendar.Attributes["calendarrules"] = innerCalendarRules; newInnerCalendar.Attributes["calendarid"] = innerCalendarId; service.Update(newInnerCalendar);
In the new Inner Calendar which we created we will add the above two calendar rules and update the Inner calendar.
After successfully running the code you may see a record is created for the specified date with a Break added as seen below:
Conclusion:
The steps to get the calendar is
- Read the user calendar
- Create the inner calendar
- Create the calendar rule for the day
- Create the calendar rule for the work duration
- Create the calendar rule for the break duration.
Get more from your Dynamics CRM..Start monitoring User Adoption today!
Hello
I am trying to create an entrance in the Calendar if someone could give me an idea:
I created an entity A which has some fields to define the periodicity and I need to save this in the Calendar, for example:
Periodicity: Monthly Range: 01-March-2016 to 01-March-2017 Day of month: 10
so I will need to create in the Calendar a entrance for each month since March 2016 till March 2017 the day 10
Similar to periodicity Weekly, daily
I have created an plugin in C# and my idea is create the logic here and save in the calendar with the information obtained. Is this possible?
could you give me the whole class if this example in this post? I have error with service class
Thank you
Hi,
You have a custom entity A which will store the details for creating Workhours i.e. Month and day for which you want to create the workhour.
Yes you can achieve this through a plugin provided you have all the data required to create the Calendar rules as shown in the blog.
Also as you said you’re having issue with the service class.
We are using the IOrganizationService object which you can obtain in the Plugin using below code in case you have missed it.
public void Execute(IServiceProvider serviceProvider)
{
// object Organization service factory object
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
// object organization object
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
}
Still if you are facing any errors then please copy paste your error here, so that we can look into it detail.
Hi Inogic,
First of all this post is simple awesome! coz it helped me alot and i am sure it will help many others too!
I has a small doubt i am able to create a facility with some work hours (say 8 to 5) for weekly schedule. The concern is when i go to CRM and change the timings (say 9 to 6) it gets changed for all the days in the weeks.
I wanted to know how to set different timings for different days in the weeks with break (say 12 PM: to 1 PM) through code!
It would be great if it is possible to share the code, because have used the same code which you have given above.
Thanks in advance!
Hi,
Thanks for your comment.
Regarding your query it seems you want to set the work Hours for a Week.
Let us consider you want to set the Work hours for the Week from 10th April 2016 to 16 April 2016.
Below is the code:
Call the CreateCalendarRulesForWeekDay() Method from your function and make sure you have the below code:
///
///
private void CreateCalendarRulesForWeekDay()
{
DateTime weekStartDate = DateTime.MinValue;
DateTime weekEndDate = DateTime.MinValue;
Entity systemUserEntity = null;
Entity userCalendarEntity = null;
EntityCollection calendarRules = null;
string[] weekPatternSet = null;
try
{
string weekPattern = “SU,MO,TU,WE,TH,FR,SA”;
weekStartDate = Convert.ToDateTime(“04/10/2016”);
weekEndDate = Convert.ToDateTime(“04/16/2016”);
//Get the calendar id of the user
systemUserEntity = _service.Retrieve(“systemuser”, new Guid(_userId), new ColumnSet(new String[] { “calendarid” }));
// Retrieve the calendar of the user
userCalendarEntity = _service.Retrieve(“calendar”, ((Microsoft.Xrm.Sdk.EntityReference)(systemUserEntity.Attributes[“calendarid”])).Id, new ColumnSet(true));
//Here we are retrieving all the calendar rules related to the particular User Calendar found earlier.
calendarRules = (EntityCollection)userCalendarEntity.Attributes[“calendarrules”];
//To Store SU,Mo,TU,WE,TH,FR,SA
weekPatternSet = weekPattern.Split(‘,’);
//Iterate for each day in a Week
foreach (var dayInWeek in weekPatternSet)
{
Entity newInnerCalendar = null;
Guid innerCalendarId = Guid.Empty;
//When the workhour will start for particular day in a Week
int workOffSet = GetOffSetValue(dayInWeek);
//When the Break will start for particular day in a Week
int breakOffSet = GetBreakOffSet(dayInWeek);
//Working Work Hour duration in Minutes for particular day in a Week
int workDuration = GetWorkDuration(dayInWeek);
//Break Duration : 1 Hour
int breakDuration = 60;
newInnerCalendar = new Entity(“calendar”);
newInnerCalendar.Attributes[“businessunitid”] = new EntityReference(“businessunit”, ((Microsoft.Xrm.Sdk.EntityReference)(userCalendarEntity[“businessunitid”])).Id);
innerCalendarId = _service.Create(newInnerCalendar);
// Create a new calendar rule and assign the inner calendar id to it
Entity calendarRule = new Entity(“calendarrule”);
calendarRule.Attributes[“pattern”] = “FREQ=WEEKLY;INTERVAL=1;BYDAY=” + dayInWeek + “”;
//Set Create Calendar Rule record attributes referring Blog above
//MonthDays
int monDays = GetDaysInMonth(weekEndDate.Year, weekEndDate.Month);
if (monDays == weekEndDate.Day)
{
if (weekEndDate.Month == 12)
{
calendarRule.Attributes[“effectiveintervalend”] = new DateTime(weekEndDate.Year, 1, 1, 0, 0, 0, DateTimeKind.Utc);
}
else
{
calendarRule.Attributes[“effectiveintervalend”] = new DateTime(weekEndDate.Year, weekEndDate.Month + 1, 1, 0, 0, 0, DateTimeKind.Utc);
}
}
else
{
calendarRule.Attributes[“effectiveintervalend”] = new DateTime(weekEndDate.Year, weekEndDate.Month, weekEndDate.Day + 1, 0, 0, 0, DateTimeKind.Utc);
}
calendarRules.Entities.Add(calendarRule);
// assign all the calendar rule back to the user calendar
userCalendarEntity.Attributes[“calendarrules”] = calendarRules;
// update the user calendar entity that has the new rule
_service.Update(userCalendarEntity);
//Create Working Calendar Rules record referring Blog above
Entity workingHourcalendarRule = new Entity(“calendarrule”);
workingHourcalendarRule.Attributes[“duration”] = workDuration;
// offset 120 i.e. 2 hours from start time (12:00)
workingHourcalendarRule.Attributes[“offset”] = workOffSet;
//Set the rest of the attributes referring the blog above
EntityCollection innerCalendarRules = new EntityCollection();
innerCalendarRules.EntityName = “calendarrule”;
Entity calendarRulebreak = new Entity(“calendarrule”);
// Break Duration
calendarRulebreak.Attributes[“duration”] = breakDuration;
calendarRulebreak.Attributes[“offset”] = breakOffSet;
//Set rest of the Attributes referring the blog above
innerCalendarRules.Entities.Add(calendarRulebreak);
innerCalendarRules.Entities.Add(workingHourcalendarRule);
newInnerCalendar.Attributes[“calendarrules”] = innerCalendarRules;
newInnerCalendar.Attributes[“calendarid”] = innerCalendarId;
_service.Update(newInnerCalendar);
}
}
catch (Exception err)
{
throw new Exception(err.Message);
}
}
Also, you will need below functions along with this:
///
///
/// ///
private int GetWorkDuration(string dayInWeek)
{
try
{
int duration = 0;
switch (dayInWeek.ToLower())
{
case “su”:
duration = 540;
break;
case “mo”:
duration = 600;
break;
case “tu”:
duration = 600;
break;
case “we”:
duration = 600;
break;
case “th”:
duration = 540;
break;
case “fr”:
duration = 540;
break;
case “sa”:
duration = 540;
break;
default:
duration = 0;
break;
}
return duration;
}
catch (Exception err)
{
throw new Exception(err.Message);
}
}
///
///
/// ///
private int GetBreakOffSet(string dayInWeek)
{
try
{
int offSetVal = 0;
switch (dayInWeek.ToLower())
{
case “su”:
offSetVal = 720;
break;
case “mo”:
offSetVal = 780;
break;
case “tu”:
offSetVal = 780;
break;
case “we”:
offSetVal = 780;
break;
case “th”:
offSetVal = 780;
break;
case “fr”:
offSetVal = 780;
break;
case “sa”:
offSetVal = 780;
break;
default:
offSetVal = 0;
break;
}
return offSetVal;
}
catch (Exception err)
{
throw new Exception(err.Message);
}
}
///
///
/// ///
private int GetOffSetValue(string dayInWeek)
{
try
{
int offSetVal = 0;
switch (dayInWeek.ToLower())
{
case “su”:
offSetVal = 480;
break;
case “mo”:
offSetVal = 540;
break;
case “tu”:
offSetVal = 540;
break;
case “we”:
offSetVal = 540;
break;
case “th”:
offSetVal = 540;
break;
case “fr”:
offSetVal = 540;
break;
case “sa”:
offSetVal = 540;
break;
default:
offSetVal = 0;
break;
}
return offSetVal;
}
catch (Exception err)
{
throw new Exception(err.Message);
}
}
///
///
/// /// ///
private int GetDaysInMonth(int year, int month)
{
int monDays = 0;
DateTime dt1 = new DateTime(year, month, 1);
DateTime dt2 = dt1.AddMonths(1);
TimeSpan ts = dt2 – dt1;
monDays = Convert.ToInt32(ts.TotalDays);
return monDays;
}
In this code we are using a global variable “_service” which is an Object of IOrganizationService.
Using this code we have set the workhours from 10th April 2016 to 16th April 2016.
Hope this helps.