Блог

Расчет рабочего времени в Dynamics CRM 2016/365

В данной статье представлен класс, который позволит производить операции с рабочим временем в Microsoft Dynamics CRM.  С его помощью к заданной дате можно прибавить рабочие дни, часы и минуты.

Для использования класса необходимо создать его экземпляр, в качестве параметров передаем ссылку на сервис и сущность календаря обслуживания клиентов. Далее можно будет использовать методы AddWorkDays, AddWorkHours и AddWorkMinutes в качестве параметров они принимают дату, к которой нужно применить операцию и соответственно дни, часы и минуты, которые мы хотим прибавить к этой дате.

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;

namespace Yandex.Money.CRM.Actions.Helpers.BusinessCalendarLogic
{
    public class BusinessCalendarLogic
    {
        private readonly Entity _calendarWorkDay;
        private readonly Entity _calendarHoliday;

        /// <summary>
        /// Инициализирует новый объект для работы с рабочими днями, в качестве параметром принимает сервис CRM и календарь обслуживания клиентов
        /// </summary>
        /// <param name="service">Сервис CRM</param>
        /// <param name="calendar">Календарь обслуживания клиентов</param>
        public BusinessCalendarLogic(IOrganizationService service, Entity calendar)
        {
            var holidayschedulecalendarRef = calendar.GetAttributeValue<EntityReference>("holidayschedulecalendarid");
            if (holidayschedulecalendarRef != null)
                _calendarHoliday = service.Retrieve(holidayschedulecalendarRef.LogicalName, holidayschedulecalendarRef.Id, new ColumnSet(true));
            var calendarRules = calendar.GetAttributeValue<EntityCollection>("calendarrules");
            var innercalendarRef = calendarRules[0].GetAttributeValue<EntityReference>("innercalendarid");
            _calendarWorkDay = service.Retrieve(innercalendarRef.LogicalName, innercalendarRef.Id, new ColumnSet(true));
        }

        public DateTime AddWorkDays(DateTime date, int days)
        {
            while (days > 0)
            {
                if (IsBusinessTime(date))
                    days--;
                date = date.AddDays(1);
            }
            return date;
        }

        public DateTime AddWorkHours(DateTime date, int hours)
        {
            int minutes = hours * 60;
            return AddWorkMinutes(date, minutes);
        }

        public DateTime AddWorkMinutes(DateTime date, int minutes)
        {
            while (minutes > 0)
            {
                if (IsBusinessTime(date))
                    minutes--;
                date = date.AddMinutes(1);
            }
            return date;
        }

        public bool IsBusinessTime(DateTime dateToCheck)
        {
            return dateToCheck.IsBusinessTime(_calendarWorkDay, _calendarHoliday);
        }
    }

    public static class BusinessCalendarLogicExtension
    {
        public static bool IsBusinessTime(this DateTime dateToCheck, Entity calendarWorkDay, Entity calendarHoliday)
        {
            return dateToCheck.IsBusinessTimeWorkDay(calendarWorkDay) && dateToCheck.IsBusinessTimeHoliday(calendarHoliday);
        }

        public static bool IsBusinessTimeHoliday(this DateTime dateToCheck, Entity calendar)
        {
            if (calendar == null)
                return true;
            var calendarRules = calendar.GetAttributeValue<EntityCollection>("calendarrules");
            foreach (var calendarRule in calendarRules.Entities)
            {
                var startTime = calendarRule.GetAttributeValue<DateTime>("starttime");
                var duration = calendarRule.GetAttributeValue<int>("duration") - 1;
                var endTime = startTime.AddMinutes(duration);
                if (dateToCheck.IsBetween(startTime, endTime))
                    return false;
            }
            return true;
        }
		public static bool IsBusinessTimeWorkDay(this DateTime dateToCheck, Entity calendar)
        {
            var calendarRules = calendar.GetAttributeValue<EntityCollection>("calendarrules");
            foreach (var calendarRule in calendarRules.Entities)
            {
                var startTime = new DateTime(dateToCheck.Year, dateToCheck.Month, dateToCheck.Day).AddMinutes(calendarRule.GetAttributeValue<int>("offset"));
                var duration = calendarRule.GetAttributeValue<int>("duration");
                var endTime = startTime.AddMinutes(duration);
                if (dateToCheck.IsBetween(startTime, endTime))
                    return true;
            }
            return false;
        }

        private static bool IsBetween(this DateTime input, DateTime date1, DateTime date2)
        {
            return input >= date1 && input <= date2;
        }
    }
}

Класс хорошо работает при следующих настройках (в календаре выходных дней хранятся все выходные дни, включая праздники и собственно обычные выходные):

Но при необходимости можно будет его модернизировать и для работы в иных ситуациях.

Комментариев нет

Ваш комментарий