846 lines
38 KiB
C#
846 lines
38 KiB
C#
using _0_Framework.Application;
|
||
using _0_Framework.Domain.CustomizeCheckoutShared.Enums;
|
||
using Company.Domain.RollCallAgg.DomainService;
|
||
using Company.Domain.WorkshopAgg;
|
||
using CompanyManagment.App.Contracts.EmployeeDocuments;
|
||
using WorkFlow.Application.Contracts.RollCallConfirmedAbsence;
|
||
using WorkFlow.Application.Contracts.RollCallConfirmedWithoutLunchBreak;
|
||
using WorkFlow.Application.Contracts.Shared;
|
||
using WorkFlow.Application.Contracts.WorkFlow;
|
||
using WorkFlow.Domain.RollCallConfirmedAbsenceAgg;
|
||
using WorkFlow.Domain.RollCallConfirmedWithoutLunchBreakAgg;
|
||
using WorkFlow.Infrastructure.ACL.Checkout;
|
||
using WorkFlow.Infrastructure.ACL.CustomizedWorkshopSettings;
|
||
using WorkFlow.Infrastructure.ACL.RollCall;
|
||
|
||
namespace WorkFlow.Application;
|
||
|
||
public class WorkFlowApplication : IWorkFlowApplication
|
||
{
|
||
private readonly IRollCallConfirmedAbsenceRepository _absenceRepository;
|
||
private readonly IWorkFlowRollCallACL _rollCallACL;
|
||
private readonly IWorkFlowCheckoutACL _checkoutACL;
|
||
private readonly IWorkFlowCustomizedWorkshopSettingsACL _customizedWorkshopSettingsACL;
|
||
private readonly IRollCallDomainService _rollCallDomainService;
|
||
private readonly IRollCallConfirmedWithoutLunchBreakRepository _rollCallConfirmedWithoutLunchBreakRepository;
|
||
private readonly IEmployeeDocumentsApplication _employeeDocumentsApplication;
|
||
private readonly IWorkshopRepository _workshopRepository;
|
||
|
||
public WorkFlowApplication(IRollCallConfirmedAbsenceRepository absenceRepository, IWorkFlowRollCallACL rollCallACL, IWorkFlowCheckoutACL checkoutACL, IWorkFlowCustomizedWorkshopSettingsACL customizedWorkshopSettingsACL, IRollCallConfirmedWithoutLunchBreakRepository rollCallConfirmedWithoutLunchBreakRepository, IRollCallDomainService rollCallDomainService, IEmployeeDocumentsApplication employeeDocumentsApplication, IWorkshopRepository workshopRepository)
|
||
{
|
||
_absenceRepository = absenceRepository;
|
||
_rollCallACL = rollCallACL;
|
||
_checkoutACL = checkoutACL;
|
||
_customizedWorkshopSettingsACL = customizedWorkshopSettingsACL;
|
||
_rollCallConfirmedWithoutLunchBreakRepository = rollCallConfirmedWithoutLunchBreakRepository;
|
||
_rollCallDomainService = rollCallDomainService;
|
||
_employeeDocumentsApplication = employeeDocumentsApplication;
|
||
_workshopRepository = workshopRepository;
|
||
}
|
||
|
||
public async Task<OperationResult> CreateRollCallConfirmedAbsence(CreateRollCallConfirmedAbsence command)
|
||
{
|
||
OperationResult op = new OperationResult();
|
||
if (!command.AbsenceDate.TryToGeorgianDateTime(out var absenceDateGe))
|
||
{
|
||
throw new InvalidDataException("تاریخ را به درستی وارد کنید");
|
||
}
|
||
var entity = new RollCallConfirmedAbsence(command.WorkshopId, command.EmployeeId, absenceDateGe,
|
||
command.ConfirmedByAccountId);
|
||
|
||
_absenceRepository.Create(entity);
|
||
await _absenceRepository.SaveChangesAsync();
|
||
|
||
return op.Succcedded();
|
||
}
|
||
public async Task<OperationResult> CreateRollCallConfirmedWithoutLunchBreak(CreateRollCallConfirmedWithoutLunchBreak command)
|
||
{
|
||
OperationResult op = new();
|
||
var entity = _rollCallACL.GetDetails(command.RollCallId);
|
||
|
||
if (entity == null)
|
||
return op.Failed("خطای سیستمی");
|
||
|
||
var newEntity = new RollCallConfirmedWithoutLunchBreak(command.RollCallId, entity.EmployeeId, entity.WorkshopId, entity.RollCallDate);
|
||
|
||
await _rollCallConfirmedWithoutLunchBreakRepository.CreateAsync(newEntity);
|
||
await _rollCallConfirmedWithoutLunchBreakRepository.SaveChangesAsync();
|
||
|
||
return op.Succcedded();
|
||
}
|
||
|
||
public async Task<int> GetCountAllWorkFlows(long workshopId, long accountId)
|
||
{
|
||
int count = 0;
|
||
count += await GetAllWorkFlowCount(workshopId, accountId);
|
||
return count;
|
||
}
|
||
public Task<int> GetRollCallAbsentsWorkFlows(long workshopId)
|
||
{
|
||
var now = DateTime.Now;
|
||
|
||
DateTime.Now.Date.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
return Task.FromResult(_rollCallACL.GetRollCallAbsentsWorkFlowsCount(workshopId, now, twoMonthsAgo));
|
||
}
|
||
public async Task<int> GetCountCutRollCallByBgService(long workshopId)
|
||
{
|
||
return (await GetRollCallWorkFlowsCutByBgService(workshopId)).Count;
|
||
}
|
||
|
||
|
||
|
||
public async Task<int> GetAllWorkFlowCount(long workshopId, long accountId)
|
||
{
|
||
var count = 0;
|
||
// RollCall
|
||
|
||
count += await GetAllRollCallCount(workshopId);
|
||
|
||
count += await GetAllEmployeeDocuments(workshopId, accountId);
|
||
|
||
// Employee Documents
|
||
|
||
|
||
return count;
|
||
}
|
||
|
||
public async Task<int> GetAllEmployeeDocuments(long workshopId, long accountId)
|
||
{
|
||
int count = 0;
|
||
count += (await _employeeDocumentsApplication.GetClientRejectedDocumentForClient(workshopId, accountId)).Count;
|
||
return count;
|
||
}
|
||
|
||
public Task<int> GetAllWorkFlowCountAsync(long workshopId)
|
||
{
|
||
return Task.FromResult(20);
|
||
}
|
||
|
||
public async Task<int> GetAllRollCallCount(long workshopId)
|
||
{
|
||
int count = 0;
|
||
var activeServiceByWorkshopId = _rollCallACL.GetActiveServiceByWorkshopId(workshopId);
|
||
if (activeServiceByWorkshopId == null)
|
||
{
|
||
return count;
|
||
}
|
||
//count += _rollCallACL.GetRollCallAbsentsWorkFlows(accId, workshopId);
|
||
count += (await GetAbsentRollCallWorkFlows(workshopId))?.Count ?? 0;
|
||
count += (await GetRollCallWorkFlowsCutByBgService(workshopId))?.Count ?? 0;
|
||
count += (await GetEmployeesWithoutLunchBreak(workshopId))?.Count ?? 0;
|
||
//count += (await GetRollCallsOverlappingLeaves(workshopId))?.Count ?? 0;
|
||
count += (await GetUndefinedRollCalls(workshopId))?.Count ?? 0;
|
||
return count;
|
||
}
|
||
|
||
#region Methods For Ajax
|
||
|
||
/// <summary>
|
||
///غیبت ها
|
||
/// </summary>
|
||
public async Task<DailyRollCallWorkFlowViewModel> GetAbsentRollCallWorkFlowsByDate(long workshopId, DateTime date)
|
||
{
|
||
|
||
var startOfDay = date.Date;
|
||
var endOfDay = startOfDay.AddDays(1).Date.AddTicks(-1);
|
||
|
||
startOfDay.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, DateTime.Now);
|
||
|
||
var absences = _rollCallACL.GetAbsentRollCallWorkFlows(workshopId, startOfDay, endOfDay);
|
||
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, startOfDay, endOfDay);
|
||
|
||
var confirmedAbssences = await GetConfirmAbsencesBy(workshopId, startOfDay, endOfDay);
|
||
|
||
|
||
//var groupedConfirmedAbssencesByDate = confirmedAbssences.GroupBy(x => x.AbsenceDate.Date).ToList();
|
||
|
||
//List<DailyRollCallWorkFlowViewModel> result = new();
|
||
|
||
////iterating day by day in absences
|
||
//foreach (var item in absences)
|
||
//{
|
||
|
||
|
||
var allAbsencesInDate = absences.FirstOrDefault();
|
||
if (allAbsencesInDate == null)
|
||
return await Task.FromResult(new DailyRollCallWorkFlowViewModel());
|
||
|
||
|
||
var newItem = new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = date.Date,
|
||
DateTimeFa = date.ToFarsi(),
|
||
|
||
};
|
||
|
||
//dont count absences before the last checkout
|
||
var absencesWithoutCheckout = allAbsencesInDate.RollCallWorkFlowPerDayViewModels
|
||
.Where(x => !lastCheckouts.Any(y => x.EmployeeId == y.EmployeeId && y.CheckoutStart <= date && y.CheckoutEnd >= date) &&
|
||
activeEmployees.Any(y => y.EmployeeId == x.EmployeeId));
|
||
|
||
|
||
if (confirmedAbssences != null)
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = absencesWithoutCheckout
|
||
.Where(x => confirmedAbssences.All(y => x.EmployeeId != y.EmployeeId))
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = absencesWithoutCheckout.ToList();
|
||
|
||
}
|
||
|
||
|
||
|
||
FilterWithOffset(workshopId, date, ref newItem);
|
||
|
||
newItem.DayOfWeekFa = newItem.DateTime.DayOfWeek.DayOfWeeKToPersian();
|
||
|
||
|
||
return newItem;
|
||
}
|
||
|
||
private void FilterWithOffset(long workshopId, DateTime date, ref DailyRollCallWorkFlowViewModel dailyRollCall)
|
||
{
|
||
if (date.Date == DateTime.Now.Date.AddDays(-1))
|
||
{
|
||
foreach (var item in dailyRollCall.RollCallWorkFlowPerDayViewModels.ToList())
|
||
{
|
||
var employeeOffset = _rollCallDomainService.GetEmployeeOffSetForRegularSettings(item.EmployeeId, workshopId);
|
||
if (DateTime.Now < DateTime.Today + employeeOffset.ToTimeSpan())
|
||
dailyRollCall.RollCallWorkFlowPerDayViewModels.Remove(item);
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// بدون ثبت استراحت
|
||
/// </summary>
|
||
public async Task<DailyRollCallConfirmedWithoutLunchBreakViewModel> GetEmployeesWithoutLunchBreakByDate(long workshopId, DateTime date)
|
||
{
|
||
var startOfDay = date.Date;
|
||
var endOfDay = startOfDay.AddDays(1).Date.AddTicks(-1);
|
||
|
||
startOfDay.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, DateTime.Now);
|
||
var notSlicedRollCalls = _rollCallACL.GetNotSlicedRollCallsByWorkshopId(workshopId, startOfDay, endOfDay);
|
||
var employeesWithoutBreakTime = _customizedWorkshopSettingsACL.GetEmployeesWithoutBreakTime(workshopId);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, startOfDay, endOfDay);
|
||
notSlicedRollCalls = notSlicedRollCalls
|
||
.Where(x => !lastCheckouts.Any(y => y.EmployeeId == x.EmployeeId && y.CheckoutStart.Date <= x.RollCallDate.Date &&
|
||
y.CheckoutEnd.Date >= x.RollCallDate.Date) && activeEmployees.Any(y => y.EmployeeId == x.EmployeeId)).ToList();
|
||
|
||
var employeeWithoutBreakTimeAndNotSliced = notSlicedRollCalls
|
||
.Join(employeesWithoutBreakTime, x => x.EmployeeId, y => y.EmployeeId, (x, y) =>
|
||
new { x.EmployeeId, x.EmployeeName, x.RollCallId, x.RollCallDate }).ToList();
|
||
|
||
|
||
var confirmed = _rollCallConfirmedWithoutLunchBreakRepository.GetByWorkshopId(workshopId, startOfDay, endOfDay).ToList();
|
||
|
||
return new DailyRollCallConfirmedWithoutLunchBreakViewModel()
|
||
{
|
||
DateFa = date.ToFarsi(),
|
||
DateGr = date.Date,
|
||
DayOfWeekFa = date.DayOfWeek.DayOfWeeKToPersian(),
|
||
RollCallConfirmedWithoutLunchList = employeeWithoutBreakTimeAndNotSliced
|
||
.Where(x => confirmed.All(y => y.RollCallId != x.RollCallId)).Select(y => new RollCallConfirmedWithoutLunchBreakViewModel
|
||
{
|
||
EmployeeId = y.EmployeeId,
|
||
EmployeeName = y.EmployeeName,
|
||
RollCallId = y.RollCallId
|
||
}).ToList()
|
||
};
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// قطع شده توسط سیستم
|
||
/// </summary>
|
||
public async Task<DailyRollCallWorkFlowViewModel> GetRollCallWorkFlowsCutByBgServiceByDate(long workshopId, DateTime date)
|
||
{
|
||
var startOfDay = date.Date;
|
||
var endOfDay = startOfDay.AddDays(1).Date.AddTicks(-1);
|
||
|
||
startOfDay.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, DateTime.Now.Date);
|
||
var rollCalls = _rollCallACL.GetRollCallWorkFlowsCutByBgService(workshopId, startOfDay, endOfDay);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, startOfDay, endOfDay);
|
||
|
||
var rollCallsForDate = rollCalls.FirstOrDefault();
|
||
if (rollCallsForDate == null)
|
||
return new();
|
||
var result = new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = date.Date,
|
||
DateTimeFa = date.ToFarsi(),
|
||
RollCallWorkFlowPerDayViewModels = rollCallsForDate.RollCallWorkFlowPerDayViewModels
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= rollCallsForDate.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= rollCallsForDate.DateTime.Date) && activeEmployees.Any(z => y.EmployeeId == z.EmployeeId))
|
||
.ToList(),
|
||
DayOfWeekFa = date.DayOfWeek.DayOfWeeKToPersian()
|
||
};
|
||
return result;
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// تعیین وضعیت تردد پرسنل
|
||
/// </summary>
|
||
public async Task<DailyRollCallWorkFlowViewModel> GetUndefinedRollCallsByDate(long workshopId, DateTime date)
|
||
{
|
||
var startOfDay = date.Date;
|
||
var endOfDay = startOfDay.AddDays(1).Date.AddTicks(-1);
|
||
|
||
startOfDay.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, DateTime.Now.Date);
|
||
var rollCalls = _rollCallACL.GetUndefinedRollCalls(workshopId, startOfDay, endOfDay);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, startOfDay, endOfDay);
|
||
|
||
var rollCallsForDate = rollCalls.FirstOrDefault();
|
||
if (rollCallsForDate == null)
|
||
return new();
|
||
var result = new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = date.Date,
|
||
DateTimeFa = date.ToFarsi(),
|
||
RollCallWorkFlowPerDayViewModels = rollCallsForDate.RollCallWorkFlowPerDayViewModels
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= rollCallsForDate.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= rollCallsForDate.DateTime.Date) && activeEmployees.Any(z => y.EmployeeId == z.EmployeeId))
|
||
.ToList(),
|
||
DayOfWeekFa = date.DayOfWeek.DayOfWeeKToPersian()
|
||
};
|
||
return result;
|
||
}
|
||
|
||
/// <summary>
|
||
/// تداخل مرخصی و حضور
|
||
/// </summary>
|
||
public async Task<DailyWorkFlowEmployeesWithRollCallOnLeaveViewModel> GetRollCallsOverlappingLeaveByDate(long workshopId, DateTime date)
|
||
{
|
||
var startOfDay = date.Date;
|
||
var endOfDay = startOfDay.AddDays(1).Date.AddTicks(-1);
|
||
|
||
startOfDay.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, DateTime.Now.Date);
|
||
var rollCalls = _rollCallACL.GetRollCallsOverlappingLeaves(workshopId, startOfDay, endOfDay);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, startOfDay, endOfDay);
|
||
|
||
var rollCallsForDate = rollCalls.FirstOrDefault(x => x.Date == date);
|
||
if (rollCallsForDate == null)
|
||
return new();
|
||
|
||
var result = new DailyWorkFlowEmployeesWithRollCallOnLeaveViewModel()
|
||
{
|
||
Date = date.Date,
|
||
DateFa = date.ToFarsi(),
|
||
EmployeesList = rollCallsForDate.EmployeesList
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId &&
|
||
z.CheckoutStart.Date <= rollCallsForDate.Date.Date &&
|
||
z.CheckoutEnd.Date >= rollCallsForDate.Date.Date) && activeEmployees.Any(z => y.EmployeeId == z.EmployeeId))
|
||
.Select(e => new WorkFlowEmployeeWithRollCallOnLeaveViewModel()
|
||
{
|
||
EmployeeId = e.EmployeeId,
|
||
EmployeeFullName = e.EmployeeFullName,
|
||
LeaveId = e.LeaveId,
|
||
EndOfOverlapTime = e.EndOfOverlapTime,
|
||
StartOfOverlapTime = e.StartOfOverlapTime,
|
||
RollCallId = e.RollCallId,
|
||
EndOfOverlapDateFa = e.EndOfOverlapDateFa,
|
||
EndOfOverlapDateTime = e.EndOfOverlapDateTime,
|
||
StartOfOverlapDateFa = e.StartOfOverlapDateFa,
|
||
StartOfOverlapDateTime = e.StartOfOverlapDateTime
|
||
}).ToList(),
|
||
DayOfWeek = date.DayOfWeek.DayOfWeeKToPersian()
|
||
};
|
||
return result;
|
||
}
|
||
|
||
#endregion
|
||
|
||
public async Task<List<RollCallConfirmAbsenceViewModel>> GetConfirmAbsencesBy(long workshopId, DateTime start, DateTime end)
|
||
{
|
||
return _absenceRepository.GetConfirmAbsencesBy(workshopId, start, end);
|
||
}
|
||
|
||
|
||
#region Methods For OnGet
|
||
|
||
|
||
/// <summary>
|
||
/// لیست تداخل مرخصی و حضور
|
||
/// </summary>
|
||
public async Task<List<DailyWorkFlowEmployeesWithRollCallOnLeaveViewModel>> GetRollCallsOverlappingLeaves(long workshopId)
|
||
{
|
||
var now = DateTime.Now;
|
||
DateTime.Now.Date.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
var rollCalls = _rollCallACL.GetRollCallsOverlappingLeaves(workshopId, twoMonthsAgo, now);
|
||
return rollCalls
|
||
.Select(x => new DailyWorkFlowEmployeesWithRollCallOnLeaveViewModel()
|
||
{
|
||
Date = x.Date,
|
||
DateFa = x.DateFa,
|
||
EmployeesList = x.EmployeesList
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId &&
|
||
z.CheckoutStart.Date <= x.Date.Date &&
|
||
z.CheckoutEnd.Date >= x.Date.Date) && activeEmployees.Any(z => y.EmployeeId == z.EmployeeId))
|
||
.Select(e => new WorkFlowEmployeeWithRollCallOnLeaveViewModel()
|
||
{
|
||
EmployeeId = e.EmployeeId,
|
||
EmployeeFullName = e.EmployeeFullName,
|
||
LeaveId = e.LeaveId,
|
||
EndOfOverlapTime = e.EndOfOverlapTime,
|
||
StartOfOverlapTime = e.StartOfOverlapTime,
|
||
RollCallId = e.RollCallId,
|
||
EndOfOverlapDateFa = e.EndOfOverlapDateFa,
|
||
EndOfOverlapDateTime = e.EndOfOverlapDateTime,
|
||
StartOfOverlapDateFa = e.StartOfOverlapDateFa,
|
||
StartOfOverlapDateTime = e.StartOfOverlapDateTime
|
||
}).ToList(),
|
||
DayOfWeek = x.DayOfWeek
|
||
})
|
||
.Where(y => y.EmployeesList != null && y.EmployeesList.Any())
|
||
.OrderBy(x => x.Date).ToList();
|
||
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// لیست وضعیت تردد پرسنل
|
||
/// </summary>
|
||
public async Task<List<DailyRollCallWorkFlowViewModel>> GetUndefinedRollCalls(long workshopId)
|
||
{
|
||
|
||
var now = DateTime.Now;
|
||
|
||
DateTime.Now.Date.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
//استثنا برای کارگاه پیتزا امیر برای برای نمایش ندادن کارپوشه قبل از 1 آبان 1404
|
||
if(workshopId == 367 && twoMonthsAgo< new DateTime(2025,10,23))
|
||
{
|
||
twoMonthsAgo = new DateTime(2025,10,23);
|
||
}
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
List<DailyRollCallWorkFlowViewModel> rollCalls = _rollCallACL.GetUndefinedRollCalls(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
return rollCalls.Select(x => new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = x.DateTime,
|
||
DateTimeFa = x.DateTimeFa,
|
||
RollCallWorkFlowPerDayViewModels = x.RollCallWorkFlowPerDayViewModels
|
||
.Where(y =>
|
||
!lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= x.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= x.DateTime.Date) &&
|
||
activeEmployees.Any(z => z.EmployeeId == y.EmployeeId && x.DateTime.Date >= z.startActive &&
|
||
x.DateTime.Date <= z.endActive))
|
||
.ToList(),
|
||
DayOfWeekFa = x.DateTime.DayOfWeek.DayOfWeeKToPersian()
|
||
}).Where(y => y.RollCallWorkFlowPerDayViewModels != null && y.RollCallWorkFlowPerDayViewModels.Any()).OrderBy(x => x.DateTime).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// لیست قطع شده توسط سیستم
|
||
/// </summary>
|
||
public async Task<List<DailyRollCallWorkFlowViewModel>> GetRollCallWorkFlowsCutByBgService(long workshopId)
|
||
{
|
||
|
||
var now = DateTime.Now;
|
||
|
||
DateTime.Now.Date.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
//استثنا برای کارگاه پیتزا امیر برای برای نمایش ندادن کارپوشه قبل از 1 آبان 1404
|
||
if(workshopId == 367 && twoMonthsAgo< new DateTime(2025,10,23))
|
||
{
|
||
twoMonthsAgo = new DateTime(2025,10,23);
|
||
}
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
var rollCalls = _rollCallACL.GetRollCallWorkFlowsCutByBgService(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
return rollCalls.Select(x => new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = x.DateTime,
|
||
DateTimeFa = x.DateTimeFa,
|
||
RollCallWorkFlowPerDayViewModels = x.RollCallWorkFlowPerDayViewModels
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= x.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= x.DateTime.Date) && activeEmployees.Any(z => z.EmployeeId == y.EmployeeId && x.DateTime.Date >= z.startActive &&
|
||
x.DateTime.Date <= z.endActive))
|
||
.ToList(),
|
||
DayOfWeekFa = x.DateTime.DayOfWeek.DayOfWeeKToPersian()
|
||
}).Where(y => y.RollCallWorkFlowPerDayViewModels != null && y.RollCallWorkFlowPerDayViewModels.Any())
|
||
.OrderBy(x => x.DateTime).ToList();
|
||
}
|
||
|
||
#region CountForCreateCheckout
|
||
|
||
public async Task<int> CountCutByBgServiceLastMonth(long workshopId)
|
||
{
|
||
var workshop = _workshopRepository.Get(workshopId);
|
||
|
||
if (workshop == null || workshop.IsStaticCheckout)
|
||
return 0;
|
||
|
||
DateTime lastMonthEnd = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1);
|
||
var now = lastMonthEnd;
|
||
var twoMonthsAgo = ($"{lastMonthEnd.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
||
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
var rollCalls = _rollCallACL.GetRollCallWorkFlowsCutByBgService(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
return rollCalls.Select(x => new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = x.DateTime,
|
||
DateTimeFa = x.DateTimeFa,
|
||
RollCallWorkFlowPerDayViewModels = x.RollCallWorkFlowPerDayViewModels
|
||
.Where(y => !lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= x.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= x.DateTime.Date) && activeEmployees.Any(z => z.EmployeeId == y.EmployeeId && x.DateTime.Date >= z.startActive &&
|
||
x.DateTime.Date <= z.endActive))
|
||
.ToList(),
|
||
DayOfWeekFa = x.DateTime.DayOfWeek.DayOfWeeKToPersian()
|
||
}).Where(y => y.RollCallWorkFlowPerDayViewModels != null && y.RollCallWorkFlowPerDayViewModels.Any())
|
||
.OrderBy(x => x.DateTime).Count();
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// لیست غیبت ها
|
||
/// </summary>
|
||
public async Task<int> CountAbsentRollCallLastMonth(long workshopId)
|
||
{
|
||
var workshop = _workshopRepository.Get(workshopId);
|
||
|
||
if (workshop == null || workshop.IsStaticCheckout)
|
||
return 0;
|
||
|
||
DateTime lastMonthEnd = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1);
|
||
var now = lastMonthEnd;
|
||
var twoMonthsAgo = ($"{lastMonthEnd.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
||
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
|
||
var absences = _rollCallACL.GetAbsentRollCallWorkFlows(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
|
||
var confirmedAbssences = await GetConfirmAbsencesBy(workshopId, twoMonthsAgo,
|
||
now);
|
||
|
||
|
||
var groupedConfirmedAbssencesByDate = confirmedAbssences.GroupBy(x => x.AbsenceDate.Date).ToList();
|
||
|
||
List<DailyRollCallWorkFlowViewModel> result = new();
|
||
|
||
//iterating day by day in absences
|
||
foreach (var item in absences)
|
||
{
|
||
|
||
var allAbsencesInDate = item.RollCallWorkFlowPerDayViewModels;
|
||
var confirmedAbssencesInDate = groupedConfirmedAbssencesByDate.FirstOrDefault(x => x.Key == item.DateTime.Date);
|
||
//set the date of new item
|
||
var newItem = new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = item.DateTime,
|
||
DateTimeFa = item.DateTime.ToFarsi()
|
||
};
|
||
|
||
//dont count absences before the last checkout
|
||
allAbsencesInDate = allAbsencesInDate.Where(x => !lastCheckouts.Any(y =>
|
||
x.EmployeeId == y.EmployeeId && y.CheckoutStart <= item.DateTime.Date && y.CheckoutEnd >= item.DateTime.Date) && activeEmployees.Any(y =>
|
||
item.DateTime.Date >= y.startActive && item.DateTime.Date <= y.endActive)).ToList();
|
||
|
||
|
||
if (confirmedAbssencesInDate != null)
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = allAbsencesInDate
|
||
.Where(x => confirmedAbssencesInDate.All(y => x.EmployeeId != y.EmployeeId))
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = allAbsencesInDate.ToList();
|
||
|
||
}
|
||
|
||
newItem.DayOfWeekFa = newItem.DateTime.DayOfWeek.DayOfWeeKToPersian();
|
||
FilterWithOffset(workshopId, item.DateTime, ref newItem);
|
||
if (newItem.RollCallWorkFlowPerDayViewModels.Count > 0)
|
||
result.Add(newItem);
|
||
|
||
}
|
||
return result.OrderByDescending(x => x.DateTime).Count();
|
||
}
|
||
|
||
|
||
public async Task<int> CountEmployeesWithoutLunchBreakLastMonth(long workshopId)
|
||
{
|
||
var workshop = _workshopRepository.Get(workshopId);
|
||
|
||
if (workshop == null || workshop.IsStaticCheckout)
|
||
return 0;
|
||
|
||
DateTime lastMonthEnd = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1);
|
||
var now = lastMonthEnd;
|
||
var twoMonthsAgo = ($"{lastMonthEnd.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
var notSlicedRollCalls = _rollCallACL.GetNotSlicedRollCallsByWorkshopId(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var employeesWithoutBreakTime = _customizedWorkshopSettingsACL.GetEmployeesWithoutBreakTime(workshopId);
|
||
|
||
notSlicedRollCalls = notSlicedRollCalls
|
||
.Where(x => !lastCheckouts.Any(y => y.EmployeeId == x.EmployeeId && y.CheckoutStart.Date <= x.RollCallDate.Date && y.CheckoutEnd.Date >= x.RollCallDate.Date)).ToList();
|
||
|
||
var employeeWithoutBreakTimeAndNotSliced = notSlicedRollCalls
|
||
.Join(employeesWithoutBreakTime, x => x.EmployeeId,
|
||
y => y.EmployeeId, (x, y) =>
|
||
new { y.EmployeeId, x.EmployeeName, x.RollCallId, x.RollCallDate }).ToList();
|
||
|
||
|
||
var entites = _rollCallConfirmedWithoutLunchBreakRepository.GetByWorkshopId(workshopId, twoMonthsAgo, now).ToList();
|
||
|
||
return employeeWithoutBreakTimeAndNotSliced.Where(x => !entites.Any(y => y.RollCallId == x.RollCallId))
|
||
.GroupBy(x => x.RollCallDate.Date).OrderBy(x => x.Key).Select(x => new DailyRollCallConfirmedWithoutLunchBreakViewModel
|
||
{
|
||
DateGr = x.Key.Date,
|
||
DateFa = x.Key.Date.ToFarsi(),
|
||
DayOfWeekFa = x.Key.DayOfWeek.DayOfWeeKToPersian(),
|
||
RollCallConfirmedWithoutLunchList = x.Select(y => new RollCallConfirmedWithoutLunchBreakViewModel
|
||
{
|
||
EmployeeId = y.EmployeeId,
|
||
EmployeeName = y.EmployeeName,
|
||
RollCallId = y.RollCallId,
|
||
}).ToList()
|
||
}).Count();
|
||
|
||
}
|
||
|
||
|
||
public async Task<int> CountUndefinedLastMonth(long workshopId)
|
||
{
|
||
var workshop = _workshopRepository.Get(workshopId);
|
||
|
||
if (workshop == null || workshop.IsStaticCheckout)
|
||
return 0;
|
||
|
||
DateTime lastMonthEnd = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1);
|
||
var now = lastMonthEnd;
|
||
var twoMonthsAgo = ($"{lastMonthEnd.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime();
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
List<DailyRollCallWorkFlowViewModel> rollCalls = _rollCallACL.GetUndefinedRollCalls(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
return rollCalls.Select(x => new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = x.DateTime,
|
||
DateTimeFa = x.DateTimeFa,
|
||
RollCallWorkFlowPerDayViewModels = x.RollCallWorkFlowPerDayViewModels
|
||
.Where(y =>
|
||
!lastCheckouts.Any(z => z.EmployeeId == y.EmployeeId && z.CheckoutStart.Date <= x.DateTime.Date &&
|
||
z.CheckoutEnd.Date >= x.DateTime.Date) &&
|
||
activeEmployees.Any(z => z.EmployeeId == y.EmployeeId && x.DateTime.Date >= z.startActive &&
|
||
x.DateTime.Date <= z.endActive))
|
||
.ToList(),
|
||
DayOfWeekFa = x.DateTime.DayOfWeek.DayOfWeeKToPersian()
|
||
}).Where(y => y.RollCallWorkFlowPerDayViewModels != null && y.RollCallWorkFlowPerDayViewModels.Any()).OrderBy(x => x.DateTime).Count();
|
||
}
|
||
#endregion
|
||
|
||
|
||
/// <summary>
|
||
/// لیست غیبت ها
|
||
/// </summary>
|
||
public async Task<List<DailyRollCallWorkFlowViewModel>> GetAbsentRollCallWorkFlows(long workshopId)
|
||
{
|
||
|
||
var now = DateTime.Now;
|
||
|
||
|
||
DateTime.Now.Date.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
//استثنا برای کارگاه پیتزا امیر برای برای نمایش ندادن کارپوشه قبل از 1 آبان 1404
|
||
if(workshopId == 367 && twoMonthsAgo< new DateTime(2025,10,23))
|
||
{
|
||
twoMonthsAgo = new DateTime(2025,10,23);
|
||
}
|
||
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
|
||
var absences = _rollCallACL.GetAbsentRollCallWorkFlows(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var activeEmployees = _rollCallACL.GetActiveWorkshopRollCallEmployees(workshopId, twoMonthsAgo, now);
|
||
|
||
var confirmedAbssences = await GetConfirmAbsencesBy(workshopId, twoMonthsAgo,
|
||
now);
|
||
|
||
|
||
var groupedConfirmedAbssencesByDate = confirmedAbssences.GroupBy(x => x.AbsenceDate.Date).ToList();
|
||
|
||
List<DailyRollCallWorkFlowViewModel> result = new();
|
||
|
||
//iterating day by day in absences
|
||
foreach (var item in absences)
|
||
{
|
||
|
||
var allAbsencesInDate = item.RollCallWorkFlowPerDayViewModels;
|
||
var confirmedAbssencesInDate = groupedConfirmedAbssencesByDate.FirstOrDefault(x => x.Key == item.DateTime.Date);
|
||
//set the date of new item
|
||
var newItem = new DailyRollCallWorkFlowViewModel()
|
||
{
|
||
DateTime = item.DateTime,
|
||
DateTimeFa = item.DateTime.ToFarsi()
|
||
};
|
||
|
||
//dont count absences before the last checkout
|
||
allAbsencesInDate = allAbsencesInDate.Where(x => !lastCheckouts.Any(y =>
|
||
x.EmployeeId == y.EmployeeId && y.CheckoutStart <= item.DateTime.Date && y.CheckoutEnd >= item.DateTime.Date) && activeEmployees.Any(y =>
|
||
item.DateTime.Date >= y.startActive && item.DateTime.Date <= y.endActive)).ToList();
|
||
|
||
|
||
if (confirmedAbssencesInDate != null)
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = allAbsencesInDate
|
||
.Where(x => confirmedAbssencesInDate.All(y => x.EmployeeId != y.EmployeeId))
|
||
.ToList();
|
||
}
|
||
else
|
||
{
|
||
newItem.RollCallWorkFlowPerDayViewModels = allAbsencesInDate.ToList();
|
||
|
||
}
|
||
|
||
newItem.DayOfWeekFa = newItem.DateTime.DayOfWeek.DayOfWeeKToPersian();
|
||
FilterWithOffset(workshopId, item.DateTime, ref newItem);
|
||
if (newItem.RollCallWorkFlowPerDayViewModels.Count > 0)
|
||
result.Add(newItem);
|
||
|
||
}
|
||
return result.OrderByDescending(x => x.DateTime).ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// لیست بدون ثبت استرحت
|
||
/// </summary>
|
||
public async Task<List<DailyRollCallConfirmedWithoutLunchBreakViewModel>> GetEmployeesWithoutLunchBreak(long workshopId)
|
||
{
|
||
|
||
var now = DateTime.Now.Date;
|
||
|
||
now.AddMonthsFa(-2, out var twoMonthsAgo);
|
||
|
||
//استثنا برای کارگاه پیتزا امیر برای برای نمایش ندادن کارپوشه قبل از 1 آبان 1404
|
||
if(workshopId == 367 && twoMonthsAgo< new DateTime(2025,10,23))
|
||
{
|
||
twoMonthsAgo = new DateTime(2025,10,23);
|
||
}
|
||
var lastCheckouts = _checkoutACL.GetLastCheckoutsByWorkshopIdForWorkFlow(workshopId, twoMonthsAgo, now);
|
||
var notSlicedRollCalls = _rollCallACL.GetNotSlicedRollCallsByWorkshopId(workshopId, twoMonthsAgo, now.AddDays(-1).Date);
|
||
var employeesWithoutBreakTime = _customizedWorkshopSettingsACL.GetEmployeesWithoutBreakTime(workshopId);
|
||
|
||
notSlicedRollCalls = notSlicedRollCalls
|
||
.Where(x => !lastCheckouts.Any(y => y.EmployeeId == x.EmployeeId && y.CheckoutStart.Date <= x.RollCallDate.Date && y.CheckoutEnd.Date >= x.RollCallDate.Date)).ToList();
|
||
|
||
var employeeWithoutBreakTimeAndNotSliced = notSlicedRollCalls
|
||
.Join(employeesWithoutBreakTime, x => x.EmployeeId,
|
||
y => y.EmployeeId, (x, y) =>
|
||
new { y.EmployeeId, x.EmployeeName, x.RollCallId, x.RollCallDate }).ToList();
|
||
|
||
|
||
var entites = _rollCallConfirmedWithoutLunchBreakRepository.GetByWorkshopId(workshopId, twoMonthsAgo, now).ToList();
|
||
|
||
return employeeWithoutBreakTimeAndNotSliced.Where(x => !entites.Any(y => y.RollCallId == x.RollCallId))
|
||
.GroupBy(x => x.RollCallDate.Date).OrderBy(x => x.Key).Select(x => new DailyRollCallConfirmedWithoutLunchBreakViewModel
|
||
{
|
||
DateGr = x.Key.Date,
|
||
DateFa = x.Key.Date.ToFarsi(),
|
||
DayOfWeekFa = x.Key.DayOfWeek.DayOfWeeKToPersian(),
|
||
RollCallConfirmedWithoutLunchList = x.Select(y => new RollCallConfirmedWithoutLunchBreakViewModel
|
||
{
|
||
EmployeeId = y.EmployeeId,
|
||
EmployeeName = y.EmployeeName,
|
||
RollCallId = y.RollCallId,
|
||
}).ToList()
|
||
}).ToList();
|
||
|
||
}
|
||
|
||
#endregion
|
||
|
||
|
||
public async Task<List<(long Id, string Name)>> GetEmployeesWithoutGroup(long workshopId)
|
||
{
|
||
return _customizedWorkshopSettingsACL.GetEmployeesWithoutGroup(workshopId);
|
||
}
|
||
|
||
#region ForApi
|
||
|
||
|
||
public async Task<bool> HasWorkFlow(long workshopId, string year, string month)
|
||
{
|
||
var workshop = _workshopRepository.GetDetails(workshopId);
|
||
bool hasWorkFlow = false;
|
||
|
||
var skipRollCallByWorkshopId = workshopId is 368 or 610;
|
||
if (workshop.HasRollCallFreeVip == "true" && !skipRollCallByWorkshopId)
|
||
{
|
||
DateTime startSreach;
|
||
DateTime endSearch;
|
||
|
||
if (month == "0" && year == "0")
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
string startStr = $"{now.ToFarsi().Substring(0, 8)}01";
|
||
startSreach = startStr.ToGeorgianDateTime();
|
||
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
||
}
|
||
else if (month == "0" && year != "0")
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
|
||
string startStr = $"{year}/{now.ToFarsi().Substring(5, 2)}/01";
|
||
startSreach = startStr.ToGeorgianDateTime();
|
||
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
||
}
|
||
else if (month != "0" && year == "0")
|
||
{
|
||
DateTime now = DateTime.Now;
|
||
|
||
string startStr = $"{now.ToFarsi().Substring(0, 4)}/{month}/01";
|
||
startSreach = startStr.ToGeorgianDateTime();
|
||
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
||
}
|
||
else
|
||
{
|
||
string startStr = $"{year}/{month}/01";
|
||
startSreach = startStr.ToGeorgianDateTime();
|
||
endSearch = (startStr.FindeEndOfMonth()).ToGeorgianDateTime();
|
||
}
|
||
|
||
|
||
DateTime lastMonthEnd = ($"{DateTime.Now.ToFarsi().Substring(0, 8)}01").ToGeorgianDateTime().AddDays(-1);
|
||
if (lastMonthEnd == endSearch)
|
||
{
|
||
var countWorkFlowCut = await CountCutByBgServiceLastMonth(workshopId);
|
||
var countWorkFlowAbsent = await CountAbsentRollCallLastMonth(workshopId);
|
||
var countWorkFlowLunchBreak = await CountEmployeesWithoutLunchBreakLastMonth(workshopId);
|
||
var countUndefinedRollCalls = await CountUndefinedLastMonth(workshopId);
|
||
|
||
hasWorkFlow = countWorkFlowCut > 0 || countWorkFlowAbsent > 0 || countWorkFlowLunchBreak > 0 ||
|
||
countUndefinedRollCalls > 0;
|
||
}
|
||
}
|
||
|
||
return hasWorkFlow;
|
||
}
|
||
#endregion
|
||
|
||
} |