Files
Backend-Api/Company.Domain/RollCallAgg/RollCall.cs
2026-01-29 11:29:03 +03:30

561 lines
19 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;
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; }
/// <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; }
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();
}
/// <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);
}
//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);
}
public void SetStartDate(DateTime start)
{
StartDate = start;
}
/// <summary>
/// جیزه
/// </summary>
public void ClearTimeDiff()
{
LateExitDuration = TimeSpan.Zero;
EarlyExitDuration = TimeSpan.Zero;
LateEntryDuration = TimeSpan.Zero;
EarlyEntryDuration = TimeSpan.Zero;
}
}
public enum RollCallModifyType
{
None,
CutByBgService,
EditByEmployer,
Undefined
}
}