Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

Dynamics CRM: How to Add working days by calculating business closure and weekends


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;
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);
}
}
}

Happy Coding

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 first appeared on Dynamics CRM, please read the originial post: here

Share the post

Dynamics CRM: How to Add working days by calculating business closure and weekends

×

Subscribe to Dynamics Crm

Get updates delivered right to your inbox!

Thank you for your subscription

×