Учет календаря в жизненном цикле обращения
Добрый день!
В жизненном цикле количество часов в определенном статусе идет без расчета производственного календаря (рабочий день с 9:00 до 18:00, т.е. должно быть 12 минут, а не 15 часов)
Нашла в конфигураторе, где именно происходит расчет:
var previousIntervalESQ = new EntitySchemaQuery(UserConnection.EntitySchemaManager, "CaseLifecycle");
previousIntervalESQ.AddAllSchemaColumns();
previousIntervalESQ.AddColumn("StartDate").OrderByDesc();
previousIntervalESQ.Filters.Add(previousIntervalESQ.CreateFilterWithParameters(
FilterComparisonType.Equal, "Case", CaseId));
previousIntervalESQ.Filters.Add(previousIntervalESQ.CreateIsNullFilter("EndDate"));
var previousIntervals = previousIntervalESQ.GetEntityCollection(UserConnection);
if (previousIntervals.Count == 0) {
return false;
}
var lastInterval = previousIntervals[0];
lastInterval.UseAdminRights = false;
DateTime startDate = lastInterval.GetTypedColumnValue("StartDate");
TimeSpan difference = (TimeSpan)(Date-startDate);
lastInterval.SetColumnValue("EndDate", Date);
lastInterval.SetColumnValue("StateDurationInMinutes", difference.TotalMinutes);
lastInterval.SetColumnValue("StateDurationInHours", difference.TotalHours);
lastInterval.SetColumnValue("StateDurationInDays", difference.TotalDays);
lastInterval.Save();
return true;
Подскажите, что прописать в данном методе для корректного расчета с учетом календаря?
Заранее спасибо за ответ!
Нравится
var lastInterval = previousIntervals[0]; TimeSpan workingS = new TimeSpan(9, 0, 0); TimeSpan workingL = new TimeSpan(18, 0, 0); lastInterval.UseAdminRights = false; DateTime startDate = lastInterval.GetTypedColumnValue<DateTime>("StartDate"); //TimeSpan difference = (TimeSpan)(Date-startDate); TimeSpan difference = ((TimeSpan)(workingL - finishDate.TimeOfDay)) + ((TimeSpan)(startDate.TimeOfDay - workingS)); lastInterval.SetColumnValue("EndDate", Date); lastInterval.SetColumnValue("StateDurationInMinutes", difference.TotalMinutes); lastInterval.SetColumnValue("StateDurationInHours", difference.TotalHours); lastInterval.SetColumnValue("StateDurationInDays", difference.TotalDays); lastInterval.Save(); return true;
Если нужно будет учитывать выходные дни, если задачи могут длиться большего чем один рабочий день, то придется дорабатывать логику, а если исключительно как в примере, то тогда так.
var lastInterval = previousIntervals[0]; TimeSpan workingS = new TimeSpan(9, 0, 0); TimeSpan workingL = new TimeSpan(18, 0, 0); lastInterval.UseAdminRights = false; DateTime startDate = lastInterval.GetTypedColumnValue<DateTime>("StartDate"); //TimeSpan difference = (TimeSpan)(Date-startDate); TimeSpan difference = ((TimeSpan)(workingL - finishDate.TimeOfDay)) + ((TimeSpan)(startDate.TimeOfDay - workingS)); lastInterval.SetColumnValue("EndDate", Date); lastInterval.SetColumnValue("StateDurationInMinutes", difference.TotalMinutes); lastInterval.SetColumnValue("StateDurationInHours", difference.TotalHours); lastInterval.SetColumnValue("StateDurationInDays", difference.TotalDays); lastInterval.Save(); return true;
Если нужно будет учитывать выходные дни, если задачи могут длиться большего чем один рабочий день, то придется дорабатывать логику, а если исключительно как в примере, то тогда так.
Литвинко Павел,
Спасибо большое за комментарий, не могли бы вы ещё подсказать, хотя бы схематично, пути доработки логики, так как выходные действительно нужно учитывать?
Васильева Светлана Александровна,
(Немного обновил код) Ну, если на вскидку, то к той логике, что у вас уже есть, поле расчета переменной difference убираем, добавляем примерно такую логику:
Получаем разницу в днях и циклом пробегаемся по каждому дню, первый и последний проверяем отдельно, а все остальные если это не выходные, то прибавляем 9 рабочих часов,
difference указываем разницу между первым и последним днем, и добавляем полученное кол-во часов, к этой разнице.
TimeSpan difference = new TimeSpan(); //((TimeSpan)(workingL - finishDate.TimeOfDay)) + ((TimeSpan)(startDate.TimeOfDay - workingS)); TimeSpan span = finishDate - startDate; int relative = span.Days; int workHours = 0; int HoursFL = 0; int MinutesFL = 0; for (int i = 0; i <= relative; i++) { DateTime temp = new DateTime(); temp = startDate.AddDays(i); if (startDate.Date == temp.Date) { var tempHour = workingL - temp.TimeOfDay; HoursFL += tempHour.Hours; MinutesFL += tempHour.Minutes; } else if (finishDate.Date == temp.Date) { var tempHour = workingL - finishDate.TimeOfDay; HoursFL += tempHour.Hours; MinutesFL += tempHour.Minutes; } else { string tempDay = temp.DayOfWeek.ToString(); if (tempDay != "Saturday" && tempDay != "Sunday") { workHours += 9; } } } difference = new TimeSpan(workHours + HoursFL, MinutesFL, 0);
Ну и туда же можно добавить еще проверку на государственные праздники, которые можно например в детали хранить, заполняя раз в год
Васильева Светлана Александровна,
здравствуйте, возникла похожая задача, не могли бы вы написать название сервиса в котором рассчитываются значения ?
t.vladislav,
Владислав, решила не трогать базовую логику, поэтому для своей задачи создала объект в виде представления в БД, и создала VIEW с расчетной колонкой. Календарь взяла из сервисного договора.
Предварительно создала функцию
CREATE FUNCTION [dbo].[WorkTime]
(
@StartDate DATETIME,
@FinishDate DATETIME,
@CalendarId UNIQUEIDENTIFIER = 'F0FF1F0E-F46B-1410-1787-0026185BFCD3' --Типовой календарь
)
RETURNS BIGINT
AS
BEGIN
DECLARE @Temp BIGINT = 0
DECLARE @FirstDay DATE = CONVERT(DATE, @StartDate, 112)
DECLARE @LastDay DATE = CONVERT(DATE, @FinishDate, 112)
DECLARE @StartTime TIME = CONVERT(TIME, @StartDate)
DECLARE @FinishTime TIME = CONVERT(TIME, @FinishDate)
DECLARE @WorkStart TIME = '09:00'
DECLARE @WorkFinish TIME = '18:00'
-- получаем рабочее время по случайному дню в выбранном календаре
SELECT @WorkStart=From, @WorkFinish=To FROM [WorkingTimeInterval] WHERE [DayInCalendarId] = (
SELECT TOP 1 [Id] FROM [DayInCalendar] WHERE [CalendarId] = @CalendarId
)
DECLARE @DailyWorkTime BIGINT = DATEDIFF(MINUTE, @WorkStart, @WorkFinish)
DECLARE @DayOff TABLE (
[Date] date
)
INSERT INTO @DayOff
SELECT [Date] FROM DayOff WHERE CalendarId = @CalendarId AND DayTypeId = '078c9b1e-9312-43ef-b890-e5298db62827' -- выходной
--TODO: calc short days too
IF (@StartTime<@WorkStart)
BEGIN
SET @StartTime = @WorkStart
END
IF (@FinishTime>@WorkFinish)
BEGIN
SET @FinishTime=@WorkFinish
END
IF (@FinishTime<@WorkStart)
BEGIN
SET @FinishTime=@WorkStart
END
IF (@StartTime>@WorkFinish)
BEGIN
SET @StartTime = @WorkFinish
END
DECLARE @CurrentDate DATE
SET @CurrentDate = @FirstDay
DECLARE @LastDate DATE
SET @LastDate = @LastDay
WHILE(@CurrentDate<=@LastDate)
BEGIN
IF (DATEPART(dw, @CurrentDate)!=1 AND DATEPART(dw, @CurrentDate)!=7) AND NOT EXISTS (SELECT 1 FROM @DayOff WHERE [Date] = @CurrentDate)
BEGIN
IF (@CurrentDate!=@FirstDay) AND (@CurrentDate!=@LastDay)
BEGIN
SET @Temp = @Temp + @DailyWorkTime
END
--IF it starts at startdate and it finishes not this date find diff between work finish and start as minutes
ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate!=@LastDay)
BEGIN
SET @Temp = @Temp + DATEDIFF(MINUTE, @StartTime, @WorkFinish)
END
ELSE IF (@CurrentDate!=@FirstDay) AND (@CurrentDate=@LastDay)
BEGIN
SET @Temp = @Temp + DATEDIFF(MINUTE, @WorkStart, @FinishTime)
END
--IF it starts and finishes in the same date
ELSE IF (@CurrentDate=@FirstDay) AND (@CurrentDate=@LastDay)
BEGIN
SET @Temp = DATEDIFF(MINUTE, @StartTime, @FinishTime)
END
END
SET @CurrentDate = DATEADD(day, 1, @CurrentDate)
END
-- Return the result of the function
IF @Temp<0
BEGIN
SET @Temp=0
END
RETURN @Temp
END
_____________________________________
create view ITdsVwCaseLifecycle as
SELECT
NEWID() as [Id]
,[CaseLifecycle].[CreatedOn] as [CreatedOn]
,[CaseLifecycle].[CreatedById] as [CreatedById]
,[CaseLifecycle].[ModifiedOn] as [ModifiedOn]
,[CaseLifecycle].[ModifiedById] as [ModifiedById]
,null as [ProcessListeners]
,[dbo].[WorkTime]([CaseLifecycle].[StartDate], [CaseLifecycle].[EndDate], [ServicePact].[CalendarId]) as [ITdsTiming] -- рассчитывает время в минутах
,([dbo].[WorkTime] ([CaseLifecycle].[StartDate], [CaseLifecycle].[EndDate], [ServicePact].[CalendarId]) / 60.0) as [ITdsTimingInHour] -- рассчитывает время в часах
,[Case].[ID] as [ITdsCaseId]
,[CaseLifecycle].[Id] as [ITdsCaseLIfeCycleId]
,[ServicePact].[Id] as [ServicePactId]
FROM [DEV].[dbo].[CaseLifecycle] -- жизненный цикл обращения
left join [Case] on [Case].[ID] = [CaseLifecycle].[CaseId] -- обращения
left join [ServicePact] on [Case].[ServicePactId] = [ServicePact].[Id] -- сервисный договор