using _0_Framework.Domain; using _0_Framework.Domain.CustomizeCheckoutShared.Enums; using System; using Company.Domain.RollCallAgg.DomainService; using System.Linq; using _0_Framework.Exceptions; using Company.Domain.EmployeeAgg; using Company.Domain.WorkshopAgg; namespace Company.Domain.RollCallAgg { public class RollCall : EntityBase { private RollCall() { } public RollCall(long workshopId, long employeeId, string employeeFullName, DateTime startDate, DateTime? endDate, int year, int month, IRollCallDomainService service, RollCallModifyType rollCallModifyType = RollCallModifyType.None) { WorkshopId = workshopId; EmployeeId = employeeId; EmployeeFullName = employeeFullName; StartDate = startDate; EndDate = endDate; Year = year; Month = month; RollCallModifyType = rollCallModifyType; var shiftDetails = service.GetEmployeeShiftDetails(employeeId, workshopId); if (shiftDetails is { shiftType: WorkshopShiftStatus.Irregular, irregularShift: null } or { shiftType: WorkshopShiftStatus.Rotating, rotatingShifts: null }) { throw new NotFoundException("اطلاعات گروهبندی شخص نامعتبر است"); } SetBreakTime(service, employeeId, workshopId); //if (endDate.HasValue) //{ // Edit(StartDate.Value,endDate.Value,service); //} } public long WorkshopId { get; private set; } public long EmployeeId { get; private set; } public string EmployeeFullName { get; private set; } /// /// ورود /// private DateTime? _startDate; public DateTime? StartDate { get => _startDate; private set { if (value.HasValue) { _startDate = TruncateDateTime(value.Value); } else { _startDate = null; } } } /// /// خروج /// private DateTime? _endDate; public DateTime? EndDate { get => _endDate; private set { if (value.HasValue) { _endDate = TruncateDateTime(value.Value); } else { _endDate = null; } } } /// /// ماه /// public int Year { get; private set; } /// /// سال /// public int Month { get; private set; } /// /// نوع حضور غیاب /// public RollCallModifyType RollCallModifyType { get; private set; } /// /// روز کاری /// public DateTime ShiftDate { get; set; } private TimeSpan _shiftDurationTimeSpan; /// /// مقدار تایم شیفت (مدت زمان شیفت کاری) /// public TimeSpan ShiftDurationTimeSpan { get => _shiftDurationTimeSpan; set => _shiftDurationTimeSpan = TruncateTimeSpan(value); } private TimeSpan _breakTimeSpan; /// /// مقدار تایم استراحت (مدت زمان استراحت در شیفت کاری) /// public TimeSpan BreakTimeSpan { get => _breakTimeSpan; set => _breakTimeSpan = TruncateTimeSpan(value); } private TimeSpan _nightWorkTimeSpan; /// /// مقدار شب‌کاری (مدت زمان کار در شیفت شب) /// public TimeSpan NightWorkTimeSpan { get => _nightWorkTimeSpan; set => _nightWorkTimeSpan = TruncateTimeSpan(value); } private TimeSpan _fridayWorkTimeSpan; /// /// مقدار تایم جمعه (مدت زمان کار در روز جمعه) /// public TimeSpan FridayWorkTimeSpan { get => _fridayWorkTimeSpan; set => _fridayWorkTimeSpan = TruncateTimeSpan(value); } private TimeSpan _lateEntryDuration; /// /// تاخیر در ورود (مدت زمانی که کارمند با تأخیر وارد شده است) /// public TimeSpan LateEntryDuration { get => _lateEntryDuration; set => _lateEntryDuration = TruncateTimeSpan(value); } private TimeSpan _earlyEntryDuration; /// /// تعجیل در ورود (مدت زمانی که کارمند زودتر از زمان مشخص وارد شده است) /// public TimeSpan EarlyEntryDuration { get => _earlyEntryDuration; set => _earlyEntryDuration = TruncateTimeSpan(value); } private TimeSpan _lateExitDuration; /// /// تاخیر در خروج (مدت زمانی که کارمند با تأخیر از کار خارج شده است) /// public TimeSpan LateExitDuration { get => _lateExitDuration; set => _lateExitDuration = TruncateTimeSpan(value); } private TimeSpan _earlyExitDuration; /// /// تعجیل در خروج (مدت زمانی که کارمند زودتر از زمان مشخص از کار خارج شده است) /// public TimeSpan EarlyExitDuration { get => _earlyExitDuration; set => _earlyExitDuration = TruncateTimeSpan(value); } /// /// نوع شیفت /// public WorkshopShiftStatus ShiftType { get; set; } public void SetEndDateTime(DateTime endDate, IRollCallDomainService service) { EndDate = endDate; SetShiftDate(service); ShiftDurationTimeSpan = CalculateShiftDuration(StartDate!.Value, EndDate.Value, service); NightWorkTimeSpan = CalculateNightWorkDuration(StartDate.Value, endDate); FridayWorkTimeSpan = CalculateFridayWorkDuration(StartDate.Value, endDate); ////محاسبه اختلاف زمانی(تاخیر و تعجیل)ء service.CalculateTimeDifferences(this); SetBreakTime(service, EmployeeId, WorkshopId); } public void Edit(DateTime start, DateTime end, IRollCallDomainService service) { StartDate = start; EndDate = end; SetShiftDate(service); ShiftDurationTimeSpan = CalculateShiftDuration(StartDate.Value, EndDate.Value, service); NightWorkTimeSpan = CalculateNightWorkDuration(StartDate.Value, EndDate.Value); FridayWorkTimeSpan = CalculateFridayWorkDuration(StartDate.Value, EndDate.Value); //محاسبه اختلاف زمانی(تاخیر و تعجیل)ء service.CalculateTimeDifferences(this); SetBreakTime(service, EmployeeId, WorkshopId); } public void SetStartAgain(DateTime startDateTime) { StartDate = startDateTime; } public RollCall SetModifyType(RollCallModifyType modifyType) { RollCallModifyType = modifyType; return this; } public void SetShiftDate(IRollCallDomainService service) { ShiftDate = service.GetEmployeeShiftDateByRollCallStartDate(WorkshopId, EmployeeId, StartDate!.Value,EndDate.Value); } private TimeSpan CalculateShiftDuration(DateTime startRollCall, DateTime endRollCall, IRollCallDomainService service) { var shiftDetails = service.GetEmployeeShiftDetails(EmployeeId, WorkshopId); switch (shiftDetails.shiftType) { case WorkshopShiftStatus.Regular: var employeeShiftsSpans = shiftDetails.regularShifts.Select(x => { var start = new DateTime(new DateOnly(), x.StartTime); var end = new DateTime(new DateOnly(), x.EndTime); if (x.EndTime < x.StartTime) end = end.AddDays(1); var span = end - start; return new { Placement = x.Placement, ShiftSpan = span }; }).ToList(); return new TimeSpan(employeeShiftsSpans.Sum(x => (x.ShiftSpan).Ticks)); case WorkshopShiftStatus.Rotating: var rotatingShifts = shiftDetails.rotatingShifts; var res = service.FindRotatingShift(startRollCall, endRollCall, rotatingShifts); return res.end - res.start; break; case WorkshopShiftStatus.Irregular: return shiftDetails.irregularShift.WorkshopIrregularShifts switch { WorkshopIrregularShifts.TwelveThirtySix => TimeSpan.FromHours(6), WorkshopIrregularShifts.TwelveTwentyFour => TimeSpan.FromHours(8), WorkshopIrregularShifts.TwentyFourFortyEight => TimeSpan.FromHours(8), WorkshopIrregularShifts.TwentyFourTwentyFour => TimeSpan.FromHours(12), _ => new TimeSpan() }; break; default: throw new BadRequestException(string.Empty); } } private void SetBreakTime(IRollCallDomainService rollCallDomainService, long employeeId, long workshopId) { var breakTime = rollCallDomainService.GetBreakTime(employeeId, workshopId); if (breakTime.BreakTimeType == BreakTimeType.WithTime) BreakTimeSpan = breakTime.BreakTimeValue.ToTimeSpan(); } /// /// Truncates the TimeSpan to only include days, hours, and minutes. /// Removes seconds, milliseconds, and smaller units. /// /// The original TimeSpan value. /// A truncated TimeSpan with only days, hours, and minutes. private TimeSpan TruncateTimeSpan(TimeSpan time) { return new TimeSpan(time.Days, time.Hours, time.Minutes, 0); } /// /// Truncates the DateTime to only include Years,Month,days,Hours and Minutes. /// Removes seconds, milliseconds, and smaller units. /// /// The original DateTime value. /// A truncated DateTime with only days, hours, and minutes. private DateTime TruncateDateTime(DateTime dateTime) { return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, dateTime.Minute, 0); } //private static (DateTime start, DateTime end) FindRotatingShift(DateTime startRollCall, DateTime endRollCall, ICollection rotatingShifts) //{ // DateTime startDate = startRollCall.Date; // DateTime endDate = endRollCall.Date; // DateTime startEntryWithDate = startDate.Add(startDate.TimeOfDay); // DateTime endEntryWithDate = endDate.Add(endRollCall.TimeOfDay); // DateTime oneHourBeforeStart = startEntryWithDate.AddHours(-1); // DateTime oneHourAfterStart = startEntryWithDate.AddHours(1); // DateTime oneHourBeforeEnd = endEntryWithDate.AddHours(-1); // DateTime oneHourAfterEnd = endEntryWithDate.AddHours(1); // var shiftDateTimes = rotatingShifts.SelectMany(shift => // { // var shifts = new List<(DateTime Start, DateTime End)>(); // for (int i = -1; i <= 1; i++) // { // var shiftStart = startDate.AddDays(i).Date.Add(shift.StartTime.ToTimeSpan()); // var shiftEnd = shift.StartTime < shift.EndTime // ? startDate.AddDays(i).Date.Add(shift.EndTime.ToTimeSpan()) // : startDate.AddDays(i + 1).Date.Add(shift.EndTime.ToTimeSpan()); // shifts.Add((shiftStart, shiftEnd)); // } // return shifts; // }).ToList(); // #region مقایسه شروع حضور غیاب با شیفت // var startFilteredTimes = shiftDateTimes.Where(shift => // (oneHourBeforeStart <= shift.Start && oneHourAfterStart >= shift.Start) || // (oneHourBeforeStart <= shift.End && oneHourAfterStart >= shift.End)).ToList(); // if (startFilteredTimes.Count == 0) // { // startFilteredTimes = shiftDateTimes; // } // else if (startFilteredTimes.Count == 1) // { // var startChosenShift = startFilteredTimes.First(); // if (startChosenShift.End < startChosenShift.Start) // startChosenShift.End = startChosenShift.End.AddDays(1); // return startChosenShift; // } // #endregion // #region مقایسه پایان حضورغیاب با شیفت // var endFilteredTimes = shiftDateTimes.Where(shift => (oneHourBeforeEnd <= shift.Start && oneHourAfterEnd >= shift.Start) || // (oneHourBeforeEnd <= shift.End && oneHourAfterEnd >= shift.End)).ToList(); // if (endFilteredTimes.Count == 0) // { // endFilteredTimes = startFilteredTimes; // } // else if (endFilteredTimes.Count == 1) // { // var endChosenShift = endFilteredTimes.First(); // return endChosenShift; // } // #endregion // #region اشتراک حضور غیاب و شیفت // var overlapChosenShift = endFilteredTimes.Select(shift => new // { // Shift = shift, // Overlap = new TimeSpan(Math.Max(0, // Math.Min(shift.End.Ticks, oneHourAfterEnd.Ticks) - // Math.Max(shift.Start.Ticks, oneHourBeforeEnd.Ticks))) // }).MaxBy(s => s.Overlap); // var end = overlapChosenShift.Shift.End; // if (overlapChosenShift.Shift.End < overlapChosenShift.Shift.Start) // end = overlapChosenShift.Shift.End.AddDays(1); // return (overlapChosenShift.Shift.Start, end); // #endregion //} private static TimeSpan CalculateNightWorkDuration(DateTime start, DateTime end) { // مدت زمان کل را روی صفر تنظیم کنید TimeSpan totalDuration = TimeSpan.Zero; // تا زمانی که تاریخ شروع کمتر از تاریخ پایان است، حلقه اجرا شود while (start < end) { // محاسبه زمان شروع دوره شبانه بعدی (22:00) ء DateTime nextStart = new DateTime(start.Year, start.Month, start.Day, 22, 0, 0); // اگر زمان شروع فعلی قبل از دوره شبانه بعدی و زمان شروع بعدی درون تاریخ پایان باشد if (start < nextStart && nextStart < end) { // محاسبه زمان پایان دوره شبانه (6:00 روز بعد) DateTime nextEnd = nextStart.AddHours(8); // تنظیم زمان پایان بعدی در صورتی که بیشتر از تاریخ پایان باشد nextEnd = nextEnd > end ? end : nextEnd; // افزودن مدت زمان این دوره شبانه به مدت زمان کل totalDuration += nextEnd - nextStart; // جابه‌جایی زمان شروع به پایان دوره شبانه فعلی start = nextEnd; } else { // اگر هنوز زمان شروع دوره شبانه بعدی نرسیده، به روز بعد جابه‌جا شوید (6:00)ء start = start.Date.AddDays(1).AddHours(6); } } return totalDuration; } private static TimeSpan CalculateFridayWorkDuration(DateTime start, DateTime end) { if (start.DayOfWeek == DayOfWeek.Friday || end.DayOfWeek == DayOfWeek.Friday || (start.DayOfWeek == DayOfWeek.Thursday && end.DayOfWeek == DayOfWeek.Saturday)) { var startPeriod = start.DayOfWeek == DayOfWeek.Thursday ? start.AddDays(1).Date : start; var endPeriod = end.DayOfWeek == DayOfWeek.Saturday ? end.Date : end; return endPeriod - startPeriod; } return TimeSpan.Zero; } internal void SetEarlyEnter(TimeSpan earlyEntryDuration) { EarlyEntryDuration = earlyEntryDuration; LateEntryDuration = TimeSpan.Zero; } internal void SetLateEnter(TimeSpan lateEntryDuration) { LateEntryDuration = lateEntryDuration; EarlyEntryDuration = TimeSpan.Zero; } internal void SetEarlyExit(TimeSpan earlyExit) { EarlyExitDuration = earlyExit; LateExitDuration = TimeSpan.Zero; } internal void SetLateExit(TimeSpan lateExitDuration) { LateExitDuration = lateExitDuration; EarlyExitDuration = TimeSpan.Zero; } public void setStartAndEnd(DateTime start, DateTime end, IRollCallDomainService service) { StartDate = start; EndDate = end; SetShiftDate(service); ShiftDurationTimeSpan = CalculateShiftDuration(StartDate.Value, EndDate.Value, service); NightWorkTimeSpan = CalculateNightWorkDuration(StartDate.Value, EndDate.Value); FridayWorkTimeSpan = CalculateFridayWorkDuration(StartDate.Value, EndDate.Value); } public void SetStartDate(DateTime start) { StartDate = start; } /// /// جیزه /// public void ClearTimeDiff() { LateExitDuration = TimeSpan.Zero; EarlyExitDuration = TimeSpan.Zero; LateEntryDuration = TimeSpan.Zero; EarlyEntryDuration = TimeSpan.Zero; } } public enum RollCallModifyType { None, CutByBgService, EditByEmployer, Undefined } }