Dynamics CRM: How to Add working days by calculating business closure and weekends
Hayer
802
Recently I received a requirement to set the Incident Auto Closure date to 'CreatedOn' + 7 working days. To add working days to 'CreatedOn' date, we need to exclude all the weekend and business closures. I came up with the following solution to achieve the required outcome.
Add the following Class to your project to calculate working day and business closures.
using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace HayerCrmPackage.Plugins
{
public class AddWorkingDaysClass
{
///
/// Add working days to a specific date by calculating Business Closure and weekends
///
public static DateTime AddWorkingAndBusinessClosureDays(DateTime specificDate, int workingDaysToAdd,
IOrganizationService service, IPluginExecutionContext context)
{
var currentDate = specificDate;
var businessClosures = GetBusinessClosureCalendarRules(context, service);
// Calculate the working days by taking out the weekends
int completeWeeks = workingDaysToAdd / 5;
DateTime date = specificDate.AddDays(completeWeeks * 7);
workingDaysToAdd = workingDaysToAdd % 5;
for (int i = 0; i < workingDaysToAdd; i++)
{
date = date.AddDays(1);
while (!IsWorkingDayOfWeek(date))
{
date = date.AddDays(1);
}
}
// Calculate the working days by taking out Business Closures
for (var i = currentDate; i <= date; i = i.AddDays(1))
{
if (i.DayOfWeek == DayOfWeek.Saturday || i.DayOfWeek == DayOfWeek.Sunday)
continue;
foreach (var closure in businessClosures)
{
var startDate = (DateTime)closure["effectiveintervalstart"];
var endDate = (DateTime)closure["effectiveintervalend"];
var range = new DateRange(startDate, endDate);
if (range.Includes(i))
{
date = date.AddDays(1);
if (date.DayOfWeek == DayOfWeek.Saturday)
{
date = date.AddDays(2);
i = i.AddDays(1);
}
else if (date.DayOfWeek == DayOfWeek.Sunday)
{
date = date.AddDays(1);
}
}
}
}
return date;
}
///
/// Get Business Closure Calendar Rules
///
private static IEnumerable<Entity> GetBusinessClosureCalendarRules(IPluginExecutionContext context,
IOrganizationService service)
{
// Get Organization Business Closure Calendar Id
var organization = service.Retrieve("organization", context.OrganizationId, 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;
}
private static bool IsWorkingDayOfWeek(DateTime date)
{
var day = date.DayOfWeek;
return day != DayOfWeek.Saturday && day != DayOfWeek.Sunday;
}
public interface IRange<T>
{
T Start { get; }
T End { get; }
bool Includes(T value);
}
public class DateRange : IRange<DateTime>
{
public DateRange(DateTime start, DateTime end)
{
Start = start;
End = end;
}
public DateTime Start { get; private set; }
public DateTime End { get; private set; }
public bool Includes(DateTime value)
{
return (Start <= value) && (value < End);
}
}
}
}
To consume above class in your plugin, use the following code:
using System;Happy Coding
using System.Linq;
using HayerCrmPackage.Plugins.Entities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
namespace HayerCrmPackage.Plugins
{
public class PreCaseCreate : Plugin
{
public PreCaseCreate()
: base(typeof(PreCaseCreate))
{
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Create", "incident", new Action<LocalPluginContext>(ExecutePreCaseCreate)));
}
protected void ExecutePreCaseCreate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}
var pluginContext = localContext.PluginExecutionContext;
var service = localContext.OrganizationService;
var context = new OrganizationServiceContext(service);
var targetEntity = (pluginContext.InputParameters != null && pluginContext.InputParameters.Contains("Target"))
? (Entity)pluginContext.InputParameters["Target"]
: null;
// Converting Entity to Incident
var incident = (targetEntity != null && targetEntity.LogicalName == Incident.EntityLogicalName) ? targetEntity.ToEntity<Incident>() : null;
// If you want to update the number of working days to add, change the value of 2nd parameter below
incident.new_AutoClosureDate = AddWorkingDaysClass.AddWorkingAndBusinessClosureDays(DateTime.Now, 7, service,
pluginContext);
}
}
}
P. S. Hayer
(ਪ੍ਰੇਮਜੀਤ ਸਿੰਘ ਹੇਰ)
Ref:
1. Adding Working Week Days to a Specific Date
2. Check if Date Time is in Date Range
Please check my other (non-CRM) blog here: Programming Blogs
*This post is locked for comments