From 3c8f212825e44e78ed944a2ad8b8e04a170eeab5 Mon Sep 17 00:00:00 2001 From: MahanCh Date: Mon, 12 May 2025 15:12:20 +0330 Subject: [PATCH] CHANGE FIND ROTATING SHIFT FOR TIME DIFFERENCES --- .../DomainService/IRollCallDomainService.cs | 116 ++++++++++++++---- 1 file changed, 90 insertions(+), 26 deletions(-) diff --git a/Company.Domain/RollCallAgg/DomainService/IRollCallDomainService.cs b/Company.Domain/RollCallAgg/DomainService/IRollCallDomainService.cs index 90b53377..01f923c4 100644 --- a/Company.Domain/RollCallAgg/DomainService/IRollCallDomainService.cs +++ b/Company.Domain/RollCallAgg/DomainService/IRollCallDomainService.cs @@ -377,6 +377,7 @@ public class RollCallDomainService : IRollCallDomainService var earlyEntryRollCallRotating = rollCallsInRotatingShift.OrderBy(x => x.StartDate).FirstOrDefault(x => x.StartDate < shift.start); var lateEntryRollCallRotating = rollCallsInRotatingShift.OrderBy(x => x.StartDate).FirstOrDefault(x => x.StartDate > shift.start); + //برای خالی کردن اولیه حضور غیاب انتخاب شده earlyEntryRollCallRotating?.SetEarlyEnter(TimeSpan.Zero); if (earlyEntryRollCallRotating != null) @@ -406,6 +407,7 @@ public class RollCallDomainService : IRollCallDomainService var earlyExitRollCallRotating = rollCallsInRotatingShift.OrderByDescending(x => x.EndDate).FirstOrDefault(x => x.EndDate < shift.end); var lateExitRollCallRotating = rollCallsInRotatingShift.OrderBy(x => x.EndDate).FirstOrDefault(x => x.EndDate > shift.end); + //برای خالی کردن اولیه حضور غیاب انتخاب شده earlyExitRollCallRotating?.SetEarlyExit(TimeSpan.Zero); @@ -564,42 +566,104 @@ public class RollCallDomainService : IRollCallDomainService return shifts; }).ToList(); - var shiftScores = shiftDateTimes + //var shiftScores = shiftDateTimes + // .Select(shift => + // { + // var totalOverlap = TimeSpan.Zero; + + // var firstRollCall = rollCalls.MinBy(x => x.StartDate); + // var lastRollCall = rollCalls.MaxBy(x => x.EndDate); + + // long totalStartDistance = Math.Abs((shift.Start - firstRollCall.StartDate).Ticks); + // long totalEndDistance = Math.Abs((shift.End - lastRollCall.EndDate).Ticks); + + + // foreach (var rollCall in rollCalls) + // { + // var start = rollCall.StartDate; + // var end = rollCall.EndDate; + + // var overlapTicks = Math.Max(0, + // Math.Min(shift.End.Ticks, end.Ticks) - + // Math.Max(shift.Start.Ticks, start.Ticks)); + + // totalOverlap += new TimeSpan(overlapTicks); + // //totalStartDistance += Math.Abs((shift.Start - start).Ticks); + // //totalEndDistance += Math.Abs((shift.End - end).Ticks); + // } + + // return new + // { + // Shift = shift, + // TotalOverlap = totalOverlap, + // TotalDistance = totalStartDistance + totalEndDistance, + // StartDistance = totalStartDistance, + // EndDistance = totalEndDistance + // }; + // }) + // .OrderBy(s => s.StartDistance) + // .ThenBy(s => s.TotalDistance) + // .ThenByDescending(s => s.TotalOverlap) + // .ThenBy(s => s.EndDistance); + + + // مرحله 1: گروه‌بندی بر اساس نزدیکی زمان شروع به اولین حضور و غیاب + var groupedByStart = shiftDateTimes + .GroupBy(shift => + { + var firstRollCallStart = rollCalls.Min(x => x.StartDate); + var ticksDiff = Math.Abs((shift.Start - firstRollCallStart).Ticks); + return Math.Round(TimeSpan.FromTicks(ticksDiff).TotalMinutes / 30); // گروه‌بندی هر 30 دقیقه + }) + .OrderBy(g => g.Key) + .First(); // نزدیک‌ترین گروه به شروع + + // مرحله 2 (جایگزین مرحله ۴): گروه‌بندی بر اساس نزدیکی پایان شیفت به آخرین حضور و غیاب + var filteredByEnd = groupedByStart + .Select(shift => + { + var lastRollCallEnd = rollCalls.Max(x => x.EndDate); + var endDistance = Math.Abs((shift.End - lastRollCallEnd).Ticks); + return new { Shift = shift, EndDistance = endDistance }; + }) + .GroupBy(x => x.EndDistance / TimeSpan.FromMinutes(30).Ticks) // گروه‌بندی هر 30 دقیقه + .OrderBy(g => g.Key) + .First() // نزدیک‌ترین پایان + .ToList(); + + // مرحله 3: فیلتر بر اساس بیشترین همپوشانی با حضور و غیاب‌ها + var filteredByOverlap = filteredByEnd .Select(shift => { var totalOverlap = TimeSpan.Zero; - long totalStartDistance = 0; - long totalEndDistance = 0; - foreach (var rollCall in rollCalls) { - var start = rollCall.StartDate; - var end = rollCall.EndDate; - var overlapTicks = Math.Max(0, - Math.Min(shift.End.Ticks, end.Ticks) - - Math.Max(shift.Start.Ticks, start.Ticks)); - + Math.Min(shift.Shift.End.Ticks, rollCall.EndDate.Ticks) - + Math.Max(shift.Shift.Start.Ticks, rollCall.StartDate.Ticks)); totalOverlap += new TimeSpan(overlapTicks); - totalStartDistance += Math.Abs((shift.Start - start).Ticks); - totalEndDistance += Math.Abs((shift.End - end).Ticks); } - - return new - { - Shift = shift, - TotalOverlap = totalOverlap, - TotalDistance = totalStartDistance + totalEndDistance, - StartDistance = totalStartDistance, - EndDistance = totalEndDistance - }; + return new { Shift = shift.Shift, TotalOverlap = totalOverlap }; }) - .OrderByDescending(s => s.TotalOverlap) - .ThenBy(s => s.TotalDistance) - .ThenBy(s => s.StartDistance) - .ThenBy(s => s.EndDistance); + .GroupBy(x => Math.Round(x.TotalOverlap.TotalMinutes /5)) // گروه‌بندی همپوشانی + .OrderByDescending(g => g.Key) // بیشترین همپوشانی اول + .First() + .ToList(); - var overlapChosenShift = shiftScores.First(); + // مرحله 4 (جایگزین مرحله ۲): فیلتر نهایی بر اساس کمترین مجموع فاصله (TotalDistance) + var bestShift = filteredByOverlap + .Select(shift => + { + var firstRollCall = rollCalls.MinBy(x => x.StartDate); + var lastRollCall = rollCalls.MaxBy(x => x.EndDate); + var totalDistance = + Math.Abs((shift.Shift.Start - firstRollCall.StartDate).Ticks) + + Math.Abs((shift.Shift.End - lastRollCall.EndDate).Ticks); + return new { Shift = shift.Shift, TotalDistance = totalDistance }; + }) + .OrderBy(x => x.TotalDistance) // کمترین فاصله کلی + .First(); // بهترین شیفت نهایی + var overlapChosenShift = bestShift; var end = overlapChosenShift.Shift.End; if (overlapChosenShift.Shift.End < overlapChosenShift.Shift.Start) end = overlapChosenShift.Shift.End.AddDays(1);