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

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

Описание сценариев работы с рабочим календарем без примеров можно прочитать в этой статье.

В рабочем календаре задаются выходные и праздничные дни и режим работы. Подробнее об этом можно прочитать в этой статье.

В нормативно-правовых актах и договорах сроки часто отсчитываются в рабочих днях, например: " ...в течение 14 рабочих дней с момента оплаты." Для автоматизации учета этого срока необходимо использовать вычисление с учетом рабочего календаря.

Второй случай, когда может потребоваться использовать учет рабочего календаря – автоматическое определение времени выполнения задачи. Простое вычитание даты начала из даты завершения даст некорректный результат, так как будет учтено ночное и нерабочее время, выходные дни, обеденный перерыв.

Вычисление даты "через 14 рабочих дней"

Рассмотрим ситуацию, когда заказчик обязан оплатить стоимость услуги в течение четырнадцати рабочих дней с момента подписания договора.

Упрощенная схема бизнес-процесса при этом выглядит следующим образом:

Если деньги не поступили, система ожидает 14 рабочих дней.

Сценарий расчета даты через 14 рабочих дней записывает дату в переменную NextDate и выглядит следующим образом:

Пример сценария с использованием PublicAPI

Примечание
Актуальная документация по PublicAPI доступна по ссылке.
Внимание!
Сценарий, указанный ниже, актуален для версий системы ELMA с 3.8 включительно до 3.12.1 включительно.

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

using EleWise.ELMA.API;

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

context.NextDate = PublicAPI.Services.ProductionCalendar.EvalTargetTime(context.NachaloPerioda.Value, TimeSpan.FromDays(14));

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

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

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

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

var calendar = Locator.GetServiceNotNull<IProductionCalendarService>();
context.NextDate = calendar.EvalTargetTime(context.NachaloPerioda.Value, TimeSpan.FromDays(14));

Определение рабочего времени выполнения задачи

Рассмотрим процесс «Экстренный вызов», в котором оператор принимает заявку и передает ее на исполнение сотруднику технической поддержки. Сотрудник принимает заявку в виде задачи и начинает работу. Когда работа выполнена, сотрудник закрывает задачу и система автоматически рассчитывает время, затраченное на исполнение заявки и добавляет соответствующую запись в реестр выполненных заявок.

Сценарий расчета рабочего времени, потребовавшегося на исполнение заявки, выглядит следующим образом:

Пример сценария с использованием PublicAPI

Примечание
Актуальная документация по PublicAPI доступна по ссылке.
Внимание!
Сценарий, указанный ниже, актуален для версий системы ELMA с 3.8 включительно до 3.12.1 включительно.

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

using EleWise.ELMA.API;

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

public void WorkDays(Context context)
{
    //получим дату и время начала и окончания работ
    DateTime startTime = context.Task.StartDate.Value;
    DateTime endTime = context.Task.EndWorkDate.Value;
    //получим службу производственного календаря
    //подсчитаем интервал методом EvalWorkTimeDifference()
    context.VremyaIspolneniya= PublicAPI.Services.ProductionCalendar.EvalWorkTimeDifference(startTime, endTime);
}

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

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

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

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

public void WorkDays(Context context)
{
    //получим дату и время начала и окончания работ
    DateTime startTime = context.Task.StartDate.Value;
    DateTime endTime = context.Task.EndWorkDate.Value;
    //получим службу производственного календаря
    var calendar = Locator.GetServiceNotNull<IProductionCalendarService>();
    //подсчитаем интервал методом EvalWorkTimeDifference()
    context.VremyaIspolneniya= calendar.EvalWorkTimeDifference(startTime, endTime);
}

Для простого обращения к задаче «Исполнение заявки», используется скрипт, выполняющийся при создании задачи в процессе и записывающий нужную задачу в контекстную переменную Task.

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

using EleWise.ELMA.Tasks.Models;

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

public override void OnTaskCreate(ITaskBase task, Context context)
{
    //выбираем только нужную задачу по имени операции
    if (task.Subject == "Исполнение заявки")
    {
        //записываем задачу в контекстную переменную
        context.Task=(TaskBase)task;
    }
}

Подробнее о подобных скриптах можно прочитать в этой статье.

Внимание!
При работе с датами-исключениями в функции EvalTargetTime не рекомендуется использовать TimeSpan. С учетом того, что 24 часа - это одни сутки, но обычно 3 рабочих дня, возникает неоднозначность. Поэтому лучше пользоваться функцией, которая прибавляет именно рабочие часы, минуты и т.д. (передавать не TimeSpan, а long).

Примеры сценариев с использованием PublicAPI

Примечание
Актуальная документация по PublicAPI доступна по ссылке.
Внимание!
Сценарии, указанные ниже, актуальны для версий системы ELMA с 3.8 включительно до 3.12.1 включительно.
1. Сценарий вычисления предыдущего рабочего дня:
private DateTime GetPrevWorkDay(Context context, DateTime selectedDay)
{
	return PublicAPI.Services.ProductionCalendar.EvalTargetTime(selectedDay.Date.AddMinutes(1), -1).Date;
}
2. Сценарий вычисления следующего рабочего дня:
private DateTime GetNextWorkDay(Context context, DateTime selectedDay)
{
	return PublicAPI.Services.ProductionCalendar.EvalTargetTime(selectedDay.Date.AddHours(23).AddMinutes(59), 1).Date;
}

Примеры сценариев без использования PublicAPI

1. Сценарий вычисления предыдущего рабочего дня:
private DateTime GetPrevWorkDay(Context context, DateTime selectedDay)
{
	var calendar = Locator.GetServiceNotNull<IProductionCalendarService>();
	return calendar.EvalTargetTime(selectedDay.Date.AddMinutes(1), -1).Date;
}
2. Сценарий вычисления следующего рабочего дня:
private DateTime GetNextWorkDay(Context context, DateTime selectedDay)
{
	var calendar = Locator.GetServiceNotNull<IProductionCalendarService>();
	return calendar.EvalTargetTime(selectedDay.Date.AddHours(23).AddMinutes(59), 1).Date;
}