As developers, we are often asked to write plugins to calculate durations. A common example would be that the business wants to calculate how long an Opportunity was opened for. From a business perspective, it makes more sense to count only the business days, which is easy to do in C# (there are plenty of algorithms out there to filter out the weekends from a time interval). It makes even more sense to also exclude the holidays which are defined in the Business Closures calendar in CRM.
It is a nice feature and it integrates well with the out of the box Service module in the sense that you can configure it to prevent users from scheduling service activities on holidays.
From a development perspective however, it’s not that easy to deal with the Business Closures calendar for a few different reasons:
- There is no clear documentation how to deal with them programmatically
- In the Business Closures Calendar, we know they are stored in the related list of Calendar Rules, but the calendar rule entity doesn’t support Retrieve Multiple queries which makes the dates uneasy to retrieve
- You can only retrieve the business closures by getting the business closure calendar, the latter supports Retrieve Multiple
You may get confused with the ExpandCalendarRequest that is out there. It is used to retrieve the calendar rules from a user’s calendar. The idea being to retrieve a set of time blocks with appointment information for a specific user (these are also CalendarRules). If you try to retrieve the rules for the business closures calendar, you get a rather obscure error: “Invalid time zone code”.
After spending some time on that route, I reverted back to the original recommendation by many on forums and blogs and I managed to make it work with the code below. The idea is to retrieve the business closure calendar ID of the organization and then return its list of CalendarRule. From there, it’s easy to use to result to do what you need.
private IEnumerable<Entity> GetBusinessClosureCalendarRules(IExecutionContext context, IOrganizationService service) { // Get Organization Business Closure Calendar Id Entity org = service.Retrieve("organization", context.OrganizationId, new Microsoft.Xrm.Sdk.Query.ColumnSet("businessclosurecalendarid")); QueryExpression q = new QueryExpression("calendar"); q.ColumnSet = new ColumnSet(true); q.Criteria = new FilterExpression(); q.Criteria.AddCondition(new ConditionExpression("calendarid", ConditionOperator.Equal, org["businessclosurecalendarid"].ToString())); Entity businessClosureCalendar = service.RetrieveMultiple(q).Entities[0]; if (businessClosureCalendar != null) { return businessClosureCalendar.GetAttributeValue<EntityCollection>;("calendarrules").Entities; } return null; }
With all this in place, you now know how to retrieve your business closures dates. My next step is to see if it is possible to restrict dates on the calendar rules that are retrieved. In the code above, the calendar is retrieved with all its business closure dates regardless of the year. If your CRM has been running a few years, it’s possible you have a lot of records in there and you may want to optimize your code by doing some fine tuning (get business closure dates from a specific date range). I’ll update this post after I get it to work if it ever happens J.
*This post is locked for comments