541 lines
18 KiB
C#
541 lines
18 KiB
C#
using _0_Framework.Domain;
|
|
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
|
|
using System;
|
|
using Company.Domain.RollCallAgg.DomainService;
|
|
using System.Linq;
|
|
using _0_Framework.Exceptions;
|
|
|
|
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("اطلاعات گروهبندی شخص نامعتبر است");
|
|
}
|
|
|
|
//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; }
|
|
|
|
/// <summary>
|
|
/// ورود
|
|
/// </summary>
|
|
private DateTime? _startDate;
|
|
|
|
public DateTime? StartDate
|
|
{
|
|
get => _startDate;
|
|
private set
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
_startDate = TruncateDateTime(value.Value);
|
|
}
|
|
else
|
|
{
|
|
_startDate = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// خروج
|
|
/// </summary>
|
|
private DateTime? _endDate;
|
|
|
|
public DateTime? EndDate
|
|
{
|
|
get => _endDate;
|
|
private set
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
_endDate = TruncateDateTime(value.Value);
|
|
}
|
|
else
|
|
{
|
|
_endDate = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ماه
|
|
/// </summary>
|
|
public int Year { get; private set; }
|
|
|
|
/// <summary>
|
|
/// سال
|
|
/// </summary>
|
|
public int Month { get; private set; }
|
|
|
|
/// <summary>
|
|
/// نوع حضور غیاب
|
|
/// </summary>
|
|
public RollCallModifyType RollCallModifyType { get; private set; }
|
|
|
|
/// <summary>
|
|
/// روز کاری
|
|
/// </summary>
|
|
public DateTime ShiftDate { get; set; }
|
|
|
|
private TimeSpan _shiftDurationTimeSpan;
|
|
/// <summary>
|
|
/// مقدار تایم شیفت (مدت زمان شیفت کاری)
|
|
/// </summary>
|
|
public TimeSpan ShiftDurationTimeSpan
|
|
{
|
|
get => _shiftDurationTimeSpan;
|
|
set => _shiftDurationTimeSpan = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _breakTimeSpan;
|
|
/// <summary>
|
|
/// مقدار تایم استراحت (مدت زمان استراحت در شیفت کاری)
|
|
/// </summary>
|
|
public TimeSpan BreakTimeSpan
|
|
{
|
|
get => _breakTimeSpan;
|
|
set => _breakTimeSpan = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _nightWorkTimeSpan;
|
|
/// <summary>
|
|
/// مقدار شبکاری (مدت زمان کار در شیفت شب)
|
|
/// </summary>
|
|
public TimeSpan NightWorkTimeSpan
|
|
{
|
|
get => _nightWorkTimeSpan;
|
|
set => _nightWorkTimeSpan = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _fridayWorkTimeSpan;
|
|
/// <summary>
|
|
/// مقدار تایم جمعه (مدت زمان کار در روز جمعه)
|
|
/// </summary>
|
|
public TimeSpan FridayWorkTimeSpan
|
|
{
|
|
get => _fridayWorkTimeSpan;
|
|
set => _fridayWorkTimeSpan = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _lateEntryDuration;
|
|
/// <summary>
|
|
/// تاخیر در ورود (مدت زمانی که کارمند با تأخیر وارد شده است)
|
|
/// </summary>
|
|
public TimeSpan LateEntryDuration
|
|
{
|
|
get => _lateEntryDuration;
|
|
set => _lateEntryDuration = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _earlyEntryDuration;
|
|
/// <summary>
|
|
/// تعجیل در ورود (مدت زمانی که کارمند زودتر از زمان مشخص وارد شده است)
|
|
/// </summary>
|
|
public TimeSpan EarlyEntryDuration
|
|
{
|
|
get => _earlyEntryDuration;
|
|
set => _earlyEntryDuration = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _lateExitDuration;
|
|
/// <summary>
|
|
/// تاخیر در خروج (مدت زمانی که کارمند با تأخیر از کار خارج شده است)
|
|
/// </summary>
|
|
public TimeSpan LateExitDuration
|
|
{
|
|
get => _lateExitDuration;
|
|
set => _lateExitDuration = TruncateTimeSpan(value);
|
|
}
|
|
|
|
private TimeSpan _earlyExitDuration;
|
|
/// <summary>
|
|
/// تعجیل در خروج (مدت زمانی که کارمند زودتر از زمان مشخص از کار خارج شده است)
|
|
/// </summary>
|
|
public TimeSpan EarlyExitDuration
|
|
{
|
|
get => _earlyExitDuration;
|
|
set => _earlyExitDuration = TruncateTimeSpan(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// نوع شیفت
|
|
/// </summary>
|
|
public WorkshopShiftStatus ShiftType { get; set; }
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Truncates the TimeSpan to only include days, hours, and minutes.
|
|
/// Removes seconds, milliseconds, and smaller units.
|
|
/// </summary>
|
|
/// <param name="time">The original TimeSpan value.</param>
|
|
/// <returns>A truncated TimeSpan with only days, hours, and minutes.</returns>
|
|
private TimeSpan TruncateTimeSpan(TimeSpan time)
|
|
{
|
|
return new TimeSpan(time.Days, time.Hours, time.Minutes, 0);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Truncates the DateTime to only include Years,Month,days,Hours and Minutes.
|
|
/// Removes seconds, milliseconds, and smaller units.
|
|
/// </summary>
|
|
/// <param name="dateTime">The original DateTime value.</param>
|
|
/// <returns>A truncated DateTime with only days, hours, and minutes.</returns>
|
|
private DateTime TruncateDateTime(DateTime dateTime)
|
|
{
|
|
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour,
|
|
dateTime.Minute, 0);
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
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 static (DateTime start, DateTime end) FindRotatingShift(DateTime startRollCall, DateTime endRollCall, ICollection<CustomizeRotatingShift> 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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// جیزه
|
|
/// </summary>
|
|
public void ClearTimeDiff()
|
|
{
|
|
LateExitDuration = TimeSpan.Zero;
|
|
EarlyExitDuration = TimeSpan.Zero;
|
|
LateEntryDuration = TimeSpan.Zero;
|
|
EarlyEntryDuration = TimeSpan.Zero;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
public enum RollCallModifyType
|
|
{
|
|
None,
|
|
CutByBgService,
|
|
EditByEmployer,
|
|
Undefined
|
|
}
|
|
}
|