Сценарии для изменения календарей

Примечание
Перед началом работы со сценариями рекомендуется ознакомиться со стандартами написания программного кода на языке C#.

Получение календарей

Базовым классом календаря с рабочим расписанием является справочник Календарь объекта (ResourceCalendar). В нем хранится расписание для глобального производственного календаря, который всегда присутствует в системе с Id = 1. Также в данном справочнике хранятся расписания общих календарей системы, которые можно получить, например, по наименованию. Ниже приведены примеры кода для получения календарей разными способами.

Пример без использования Public API

Пространство имен:

using EleWise.ELMA.Projects.Models.Resources; //здесь класс ResourceCalendar
using EleWise.ELMA.Model.Managers; //здесь класс EntityManager
using EleWise.ELMA.Model.Services; //здесь класс InterfaceActivator

Текст сценария

            var scheduleGlobal = EntityManager<ResourceCalendar>.Instance.Load(1L); //Получение глобального производственного календаря
            var manager = EntityManager<ResourceCalendar, long>.Instance;
            var filter = InterfaceActivator.Create<ResourceCalendarFilter>();
            filter.SearchString = "809";
            var scheduleShared1 = EntityManager<ResourceCalendar, long>.Instance.Find(filter, new FetchOptions(0,1)).FirstOrDefault();//Получение общего календаря с наванием "809" через фильтр объекта по строке поиска
            var scheduleShared2 = EntityManager<ResourceCalendar, long>.Instance.Find("Name like '809'").FirstOrDefault();//Получение общего календаря с названием "809" через EQL-запрос 

Пример с использованием Public API

Примечание
Актуальная информация по Public API доступна по ссылке.

Пространство имен:

using EleWise.ELMA.API;

Текст сценария:

            var scheduleGlobal = PublicAPI.Projects.Objects.Resources.ResourceCalendar.Load(1L);
            var filter = PublicAPI.Projects.Objects.Resources.ResourceCalendar.Filter().SearchString("809").Filter;
            var scheduleShared1 = EntityManager<ResourceCalendar, long>.Instance.Find(filter, new FetchOptions(0,1)).FirstOrDefault();//Получение общего календаря с наванием "809" через фильтр объекта по строке поиска
            var scheduleShared2 =  PublicAPI.Projects.Objects.Resources.ResourceCalendar.Find("Name like '809'").FirstOrDefault();//Получение общего календаря с названием "809" через EQL-запрос

После получения календаря можно проводить настройку интервалов рабочего времени, отмечать рабочие и выходные дни. Основными настраиваемыми параметрами календаря являются:

  • BaseIntervals – задает базовые интервалы рабочего времени. Один интервал, если обеденный перерыв не определен, и два, если указан обед. Данный параметр влияет только на вновь создаваемые в календаре рабочие дни и исключительные рабочие дни. По умолчанию их расписание будет взято из базовых интервалов. Изменение базовых интервалов не изменяет уже существующее расписание;
  • WorkIntervals – задает интервалы рабочего времени в каждый день рабочей недели, а также определяет исключительные рабочие дни (например, рабочие предпраздничные субботы);
  • HolidayIntervals – определяет праздничные дни, которые выпадают на рабочие дни календаря.

Изменения в расписании глобального производственного календаря

Рассмотрим некоторые примеры по изменению расписания в глобальном производственном календаре.

Пример 1

Изменение на предприятии интервалов рабочего времени на 8:30 – 17:30 с обедом в 12:30 – 13:30.

//Задаем базовое временя работы до обеда (дата в данном случае совершенно не важна и может быть любой, важно только время)
            scheduleGlobal.BaseIntervals.ElementAt(0).Start = new DateTime(2000, 1, 1, 8, 30, 0);
            scheduleGlobal.BaseIntervals.ElementAt(0).Finish = new DateTime(2000, 1, 1, 12, 30, 0);
            //Задаем базовое временя работы после обеда. При этом проверяем, что в календаре прописан обед и сущесвует второй интервал рабочего времени
            if (scheduleGlobal.BaseIntervals.Count > 1)
            {
                scheduleGlobal.BaseIntervals.ElementAt(1).Start = new DateTime(2000, 1, 1, 13, 30, 0);
                scheduleGlobal.BaseIntervals.ElementAt(1).Finish = new DateTime(2000, 1, 1, 17, 30, 0);
            }
            //Если второй интервал не прописан, то создаем его
            else
            {
                //Или с помощью менеджера или с помощью PublicAPI
                var newInterval = EntityManager<EleWise.ELMA.Calendar.Models.BaseTimeInterval>.Instance.Create();
                //var newInterval = PublicAPI.Portal.Objects.Calendar.BaseTimeInterval.Create();
                newInterval.Calendar = scheduleGlobal;
                newInterval.Start = new DateTime(2000, 1, 1, 13, 30, 0);
                newInterval.Finish = new DateTime(2000, 1, 1, 17, 30, 0);
                newInterval.Save();
            }
            //Теперь переопределяем интервалы рабочего времени, попробуем, например, сдвинуть рабочую неделю на 1 день вперед (вт-сб)
            //Удаляем записи о работе в понедельник и воскресенье
            var removeInterval = scheduleGlobal.WorkIntervals.Where(c => c.DayOfWeek == 1 || c.DayOfWeek == 7).FirstOrDefault();
            while (removeInterval != null)
            {
                scheduleGlobal.WorkIntervals.Remove(removeInterval);
                removeInterval.Delete();
                removeInterval = scheduleGlobal.WorkIntervals.Where(c => c.DayOfWeek == 1 || c.DayOfWeek == 7).FirstOrDefault();
            }
            //Правим или добавляем записи о работе со вторника по субботу
            for (int day = 2; day <= 6; day++)
            {
                var workIntervals = scheduleGlobal.WorkIntervals.Where(c => c.DayOfWeek == day);
                var interval1 = workIntervals.ElementAtOrDefault(0);
                if (interval1 == null)
                {
                    //Создаем интервал с помощью менеджера или же PublicAPI
                    interval1 = EntityManager<WorkTimeInterval>.Instance.Create();
                    //interval1 = PublicAPI.Projects.Objects.Resources.WorkTimeInterval.Create();
                }
                interval1.Calendar = scheduleGlobal;
                interval1.DayOfWeek = day;
                interval1.Start = new DateTime(2000, 1, 1, 8, 30, 0);
                interval1.Finish = new DateTime(2000, 1, 1, 12, 30, 0);
                interval1.Save();
                
                var interval2 = workIntervals.ElementAtOrDefault(1);
                if (interval2 == null)
                {
                    //Создаем интервал с помощью менеджера или же PublicAPI
                    interval2 = EntityManager<WorkTimeInterval>.Instance.Create();
                    //interval2 = PublicAPI.Projects.Objects.Resources.WorkTimeInterval.Create();
                }
                interval2.Calendar = scheduleGlobal;
                interval2.DayOfWeek = day;
                interval2.Start = new DateTime(2000, 1, 1, 13, 30, 0);
                interval2.Finish = new DateTime(2000, 1, 1, 17, 30, 0);
                interval2.Save();
            }
            scheduleGlobal.Save();

Пример 2

Пусть у нас существует какой-то процесс/интеграция, через которые мы хотим задавать праздничные дни и рабочие дни-исключения. Опишем соответствующие функции:

        //Функция добавления праздничного дня
        public virtual bool AddHoliday(DateTime newHoliday)
        {
            //Отсекаем время на случай, если оно есть
            DateTime newHolidayDate = newHoliday.Date;
            var scheduleGlobal = EntityManager<ResourceCalendar>.Instance.Load(1L);
            //var scheduleGlobal = PublicAPI.Projects.Objects.Resources.ResourceCalendar.Load(1L);
            
            //Если указанный праздничный день уже есть в календаре, то ничего не делаем
            if (scheduleGlobal.HolidayIntervals.Where(c => c.DateStart == newHolidayDate).Any())
                return false;
            var newCalendarHoliday = EntityManager<HolidayInterval>.Instance.Create();
            //var newCalendarHoliday = PublicAPI.Projects.Objects.Resources.HolidayInterval.Create();
            newCalendarHoliday.Calendar = scheduleGlobal;
            newCalendarHoliday.DateStart = newHolidayDate;
            newCalendarHoliday.DateFinish = newHolidayDate;
            newCalendarHoliday.Save();
            return true;
        }
        
        //Функция добавления исключительного рабочего дня
        public virtual bool AddExceptionWorkDay(DateTime newExceptionWorkDay)
        {
            //Отсекаем время на случай, если оно есть
            DateTime newExceptionWorkDayDate = newExceptionWorkDay.Date;
            var scheduleGlobal = EntityManager<ResourceCalendar>.Instance.Load(1L);
            //var scheduleGlobal = PublicAPI.Projects.Objects.Resources.ResourceCalendar.Load(1L);
            
            //Если указанный исключительный день уже есть в календаре, то ничего не делаем
            if (scheduleGlobal.WorkIntervals.Where(c => c.DateExceptionStart == newExceptionWorkDayDate).Any())
                return false;
            //Создаем рабочий интервал исключительного дня на каждый базовый интервал
            foreach (var baseInterval in scheduleGlobal.BaseIntervals)
            {
                var newCalendarException = EntityManager<WorkTimeInterval>.Instance.Create();
                //var newCalendarException = PublicAPI.Projects.Objects.Resources.WorkTimeInterval.Create();
                newCalendarException.Calendar = scheduleGlobal;
                newCalendarException.DateExceptionStart = newExceptionWorkDayDate;
                newCalendarException.DateExceptionFinish = newExceptionWorkDayDate;
                newCalendarException.Start = baseInterval.Start;
                newCalendarException.Finish = baseInterval.Finish;
                newCalendarException.Save();
            }
            return true;
        }

Рассмотрим, как можно использовать эти функции для нашего примера компании, в которой рабочая неделя идет со вторника по субботу. Зададим праздничными днями 23 февраля, 8 и 9 марта. А за 9 марта установим рабочий день 11 марта:

            AddHoliday(new DateTime(2019, 2, 23));
            AddHoliday(new DateTime(2019, 3, 8));
            AddHoliday(new DateTime(2019, 3, 9));
            AddExceptionWorkDay(new DateTime(2019, 3, 11));

Вычисления с учетом рабочего календаря

Для проверки, является ли какой-либо день рабочим в производственном календаре, а также для вычислений с учетом производственного календаря предусмотрен сервис IProductionCalendarService.

Пример без использования Public API

Пространства имен:

using EleWise.ELMA.Services;
using EleWise.ELMA.Scheduling;

Текст сценария:

            var productionCalendar = Locator.GetServiceNotNull<IProductionCalendarService>();
            if (productionCalendar.IsWorkDay(context.StartDate.Value))
            {
                Console.WriteLine(context.Data + " - работаем");
            }
            else
            {
                Console.WriteLine(context.Data + " - отдыхаем");
            }            

Пример с использованием Public API

Примечание
Актуальная информация по Public API доступна по ссылке.

Пространство имен:

using EleWise.ELMA.API;

Текст сценария:

            if (PublicAPI.Services.ProductionCalendar.IsWorkDay(context.StartDate.Value))
            {
                Console.WriteLine(context.Data + " - работаем");
            }
            else
            {
                Console.WriteLine(context.Data + " - отдыхаем");
            }

Более подробно с функциями для вычислений с учетом производственного календаря можно ознакомится в статье https://www.elma-bpm.ru/KB/article-5494.html.