using _0_Framework.Application; using _0_Framework.InfraStructure; using Company.Domain.CustomizeWorkshopEmployeeSettingsAgg.Entities; using Company.Domain.CustomizeWorkshopSettingsAgg.Entities; using Company.Domain.LeaveAgg; using Company.Domain.LeftWorkAgg; using Company.Domain.RollCallAgg; using Company.Domain.YearlySalaryAgg; using CompanyManagment.App.Contracts.Contract; using CompanyManagment.App.Contracts.CustomizeCheckout; using CompanyManagment.App.Contracts.CustomizeWorkshopSettings; using CompanyManagment.App.Contracts.Leave; using CompanyManagment.App.Contracts.LeftWork; using CompanyManagment.App.Contracts.RollCall; using CompanyManagment.App.Contracts.WorkingHoursTemp; using System; using System.Collections.Generic; using System.Linq; using CompanyManagment.App.Contracts.Fine; using System.Globalization; using System.IO; using System.Threading.Tasks; using _0_Framework.Application.Enums; using _0_Framework.Domain.CustomizeCheckoutShared.Base; using _0_Framework.Domain.CustomizeCheckoutShared.Enums; using _0_Framework.Domain.CustomizeCheckoutShared.ValueObjects; using Microsoft.EntityFrameworkCore; using Company.Domain.EmployeeAgg; using CompanyManagment.App.Contracts.Loan; using CompanyManagment.App.Contracts.Reward; using CompanyManagment.App.Contracts.SalaryAid; using Company.Domain.RewardAgg; using CompanyManagment.App.Contracts.Reward.Enums; using static System.Runtime.InteropServices.JavaScript.JSType; using static Microsoft.EntityFrameworkCore.DbLoggerCategory.Database; using Company.Domain.HolidayItemAgg; using Company.Domain.RollCallEmployeeAgg; using OfficeOpenXml.ConditionalFormatting.Contracts; using PersianTools.Core; namespace CompanyManagment.EFCore.Repository; public class RollCallMandatoryRepository : RepositoryBase, IRollCallMandatoryRepository { private readonly CompanyContext _context; private readonly IYearlySalaryRepository _yearlySalaryRepository; private readonly ILeftWorkRepository _leftWorkRepository; private readonly ILeaveRepository _leaveRepository; private readonly IHolidayItemRepository _holidayItemRepository; private readonly TestDbContext _testDbContext; public RollCallMandatoryRepository(CompanyContext context, IYearlySalaryRepository yearlySalaryRepository, ILeftWorkRepository leftWorkRepository, ILeaveRepository leaveRepository, IHolidayItemRepository holidayItemRepository, TestDbContext testDbContext) : base(context) { _context = context; _yearlySalaryRepository = yearlySalaryRepository; _leftWorkRepository = leftWorkRepository; _leaveRepository = leaveRepository; _holidayItemRepository = holidayItemRepository; _testDbContext = testDbContext; } #region OfficialChckout public async Task MandatoryCompute(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd, CreateWorkingHoursTemp command, bool holidayWorking, bool isStaticCheckout, bool rotatingShiftCompute, double dailyWageUnAffected, bool totalLeaveCompute) { #region Entities string SumWorkeTime = string.Empty; var weeklyTime = new TimeSpan(); string shift1Hourse = "0"; string overMandatoryHours = "0"; string overMandatoryMinuts = "0"; string shiftOver22Hours = "0"; string shiftOver22Minuts = "0"; double ShiftPayResult = 0; int numberOfFridays = 0; #endregion int TotalContractDays = (int)(contractEnd - contractStart).TotalDays + 1; int fridays = 0; int holiday =await _context.HolidayItems.CountAsync(x => x.Holidaydate >= contractStart && x.Holidaydate <= contractEnd); ; for (var gDate = contractStart; gDate <= contractEnd; gDate = gDate.AddDays(1)) { if (gDate.DayOfWeek == DayOfWeek.Friday) { fridays += 1; } } int TotalDaysNoFriday = TotalContractDays - fridays; int mandatorDays = TotalContractDays - (fridays + holiday); if (command.ShiftWork != "4" && isStaticCheckout) mandatorDays = TotalDaysNoFriday; //if (holidayWorking) // mandatorDays = TotalContractDays - fridays; //***********************************// //This Time Mandatory Hourse double mandatoryHours = Math.Round((mandatorDays * 7.33), 2); //تبدیل عدد زیاضی موظفی به تایم اسپن int hoursConverted = (int)mandatoryHours; double minutesDecimalConverted = (mandatoryHours - hoursConverted) * 60; int minutesConverted = (int)minutesDecimalConverted; TimeSpan mandatoryHoursTimeSpan = new TimeSpan(hoursConverted, minutesConverted, 0); //گرفتن ساعت استراحت پرسنل از تنظیمات #region breakTime BaseCustomizeEntity settings =await _context.CustomizeWorkshopEmployeeSettings.AsSplitQuery() .Include(x => x.CustomizeWorkshopGroupSettings).FirstOrDefaultAsync(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); //اگر ساعت استراحت پرسنل وجود نداشت صفر است var breakTimeEntity = settings == null ? new BreakTime(false, new TimeOnly()) : settings.BreakTime; var endOfFarvardin = "1404/01/31".ToGeorgianDateTime(); #endregion List rollCallResult; List groupedRollCall; if (isStaticCheckout) { command.WorkshopId = workshopId; command.EmployeeId = employeeId; command.ContractStartGr = contractStart; command.ContractEndGr = contractEnd; rollCallResult = ConvertStaticHoursToRollCall(command, holidayWorking); //groupedRollCall = rollCallResult.GroupBy(x => x.ShiftDate.Date).Select(x => new GroupedRollCalls() //{ // CreationDate = x.Key, // ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value, EndWithOutResTime = s.ShiftEndWithoutRest.Value != null ? s.ShiftEndWithoutRest.Value : new DateTime() }).ToList(), // HasFriday = x.Any(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), // SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)), // BreakTime = x.First().BreakTimeSpan //}).OrderBy(x => x.CreationDate).ToList(); groupedRollCall = rollCallResult.GroupBy(x => x.ShiftDate.Date).Select(x => { DateTime friday = new DateTime(); if (x.Any(s => s.StartDate != null && s.EndDate != null && s.StartDate.Value.DayOfWeek == DayOfWeek.Friday)) { friday = x.FirstOrDefault(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday)) .StartDate.Value; } if (x.Any(s => s.StartDate != null && s.EndDate != null && s.EndDate.Value.DayOfWeek == DayOfWeek.Friday)) { friday = x.FirstOrDefault(s => s.StartDate != null && s.EndDate != null && (s.EndDate.Value.DayOfWeek == DayOfWeek.Friday)) .EndDate.Value; } return new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value, EndWithOutResTime = s.ShiftEndWithoutRest.Value != null ? s.ShiftEndWithoutRest.Value : new DateTime() }).ToList(), HasFriday = x.Any(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), //HasFriday = x.Any(s => // s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || // s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), Fridays = friday, SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)), BreakTime = x.First().BreakTimeSpan }; }).OrderBy(x => x.CreationDate).ToList(); } else { rollCallResult =await _context.RollCalls.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.StartDate.Value.Date >= contractStart.Date && x.StartDate.Value.Date <= contractEnd.Date && x.EndDate != null).Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.ShiftDate, BreakTimeSpan = x.BreakTimeSpan }).ToListAsync(); groupedRollCall = rollCallResult.GroupBy(x => x.CreationDate.Date).Select(x => { TimeSpan breakTime; if (contractStart > endOfFarvardin) { breakTime = CalculateBreakTime( x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))); } else { breakTime = CalculateBreakTime(breakTimeEntity, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))); } DateTime friday = new DateTime(); if (x.Any(s => s.StartDate != null && s.EndDate != null && s.StartDate.Value.DayOfWeek == DayOfWeek.Friday)) { friday = x.FirstOrDefault(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday)) .StartDate.Value; } if (x.Any(s => s.StartDate != null && s.EndDate != null && s.EndDate.Value.DayOfWeek == DayOfWeek.Friday)) { friday = x.FirstOrDefault(s => s.StartDate != null && s.EndDate != null && (s.EndDate.Value.DayOfWeek == DayOfWeek.Friday)) .EndDate.Value; } return new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value, EndWithOutResTime = s.EndDate!.Value }) .ToList(), //HasFriday = x.Any(s => // s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || // s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), Fridays = friday, SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) - breakTime, BreakTime = breakTime, }; }).OrderBy(x => x.CreationDate).ToList(); } var firdays = groupedRollCall.Where(x => x.Fridays != null && x.Fridays != new DateTime()) .DistinctBy(x => x.Fridays.Value.Date).ToList(); numberOfFridays = firdays.Count(); ////*****کسر ساعاعت استراحت پرسنل از ساعت کار //List rollCallSubtractSpan = groupedRollCall.Select(x => new GroupedRollCalls() //{ // CreationDate = x.CreationDate, // AfterSubtractRestSpan = AfterSubtract(command, x.SumOneDaySpan, x.CreationDate), //}).ToList(); TimeSpan sumSpans = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); TimeSpan sumSpansWhitOutleaves = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); //بدست آوردن مرخصی ساعتی LeaveSearchModel hoursleaveSearch = new LeaveSearchModel() { EmployeeId = employeeId, WorkshopId = workshopId, LeaveType = "استحقاقی", PaidLeaveType = "ساعتی", StartLeaveGr = contractStart, EndLeaveGr = contractEnd, IsAccepted = true, }; var hoursesleave = _leaveRepository.search(hoursleaveSearch); var hoursesleaveTimeSpansList = hoursesleave.Count > 0 ? hoursesleave.Select(x => TimeSpan.Parse(x.LeaveHourses)).ToList() : new List(); // مجموع مرخصی ساعتی var hoursesleaveTimeSpans = new TimeSpan(hoursesleaveTimeSpansList.Sum(x => x.Ticks)); //کسر مرخصی ساعتی از فیش استاتیک if (isStaticCheckout && command.ShiftWork != "4") { // کم کردن از مجموع ساعت کار پرسنل sumSpans = sumSpans.Subtract(hoursesleaveTimeSpans); } //****افزودن مرخصی پرسنل به مجموع ساعات کار*** #region AddEmployeeLeavs LeaveSearchModel leaveSearch = new LeaveSearchModel() { EmployeeId = employeeId, WorkshopId = workshopId, LeaveType = "استحقاقی", PaidLeaveType = "روزانه", StartLeaveGr = contractStart, EndLeaveGr = contractEnd, IsAccepted = true, }; var leaveSearchResult = _leaveRepository.search(leaveSearch); // {مقدار ساعت مجاز مرخصی در برای یک روز{کامل var leaveHoursesPerDay = 190.58 / 365; // {مقدار ساعت مجاز مرخصی در مدت این فیش حقوقی{کامل var starndardHoursesPerTotalDays = leaveHoursesPerDay * TotalContractDays; // جدا کردن ساعت و دقیقه int hours = (int)starndardHoursesPerTotalDays; double minutesDecimal = (starndardHoursesPerTotalDays - hours) * 60; int minutes = (int)minutesDecimal; TimeSpan totalLeaveSpan = TimeSpan.Zero; TimeSpan starndardHoursesPerTotalDaysSapn = new TimeSpan(hours, minutes, 0); //محموع تمام مرخصی های این ماه //TimeSpan totalLeaveOnThisCheckout = TimeSpan.Zero; if (leaveSearchResult.Count > 0 || hoursesleave.Count > 0) { if (leaveSearchResult.Any(x => x.HasShiftDuration)) { var sumSpansDouble = (sumSpans.TotalMinutes) / 60; if (sumSpansDouble < mandatoryHours) { starndardHoursesPerTotalDays = (sumSpansDouble * starndardHoursesPerTotalDays) / mandatoryHours; // جدا کردن ساعت و دقیقه hours = (int)starndardHoursesPerTotalDays; minutesDecimal = (starndardHoursesPerTotalDays - hours) * 60; minutes = (int)minutesDecimal; starndardHoursesPerTotalDaysSapn = new TimeSpan(hours, minutes, 0); } TimeSpan totalLeave = new TimeSpan(leaveSearchResult.Sum(x => x.ShiftDuration.Ticks)); totalLeave = totalLeave.Add(hoursesleaveTimeSpans); //totalLeaveOnThisCheckout = totalLeave; var totalLeaveDouble = (totalLeave.TotalMinutes) / 60; //اگر مدت مرخصی از مجاز بیشتر بود و مدل محاسبه کامل نبود if (totalLeaveDouble > starndardHoursesPerTotalDays && !totalLeaveCompute) { sumSpans = sumSpans.Add(starndardHoursesPerTotalDaysSapn); totalLeaveSpan = starndardHoursesPerTotalDaysSapn; } else { sumSpans = sumSpans.Add(totalLeave); totalLeaveSpan = totalLeave; } } else { int leavingDayCout = 0; //مرخصی های مابین List beatweenCheckout = leaveSearchResult .Where(x => x.StartLeaveGr >= contractStart && x.EndLeaveGr <= contractEnd).Select(x => new LeaveViewModel() { DayCounter = Convert.ToInt32(x.LeaveHourses), }).ToList(); leavingDayCout += beatweenCheckout.Sum(x => x.DayCounter); // مرخصی که شروعش قبل از شروع تصفیه حساب است List beforeCheckout = leaveSearchResult.Where(x => x.StartLeaveGr < contractStart) .Select(x => new LeaveViewModel() { DayCounter = (int)(contractStart - x.EndLeaveGr).TotalDays + 1, }).ToList(); leavingDayCout += beforeCheckout.Sum(x => x.DayCounter); // مرخصی که پایانش بعد از پایان تصفیه حساب است List afterCheckout = leaveSearchResult.Where(x => x.EndLeaveGr > contractEnd) .Select(x => new LeaveViewModel() { DayCounter = (int)(x.StartLeaveGr - contractEnd).TotalDays + 1, }).ToList(); leavingDayCout += afterCheckout.Sum(x => x.DayCounter); Console.WriteLine(leavingDayCout); TimeSpan workingPerDayAve = sumSpans / groupedRollCall.Count; //میانگین ساعت کار در روز TimeSpan sumLeave = new TimeSpan(); if (workingPerDayAve <= new TimeSpan(7, 20, 0)) { sumLeave = leavingDayCout * workingPerDayAve; sumLeave = sumLeave.Add(hoursesleaveTimeSpans); } else { var dayLeave = leavingDayCout * new TimeSpan(7, 20, 0); sumLeave = dayLeave.Add(hoursesleaveTimeSpans); } if (sumLeave > starndardHoursesPerTotalDaysSapn && !totalLeaveCompute) { sumSpans = sumSpans.Add(starndardHoursesPerTotalDaysSapn); totalLeaveSpan = starndardHoursesPerTotalDaysSapn; } else { sumSpans = sumSpans.Add(sumLeave); totalLeaveSpan = sumLeave; } //#region TotalLeaveOnThisCheckout //totalLeaveOnThisCheckout = (leavingDayCout * workingPerDayAve).Add(hoursesleaveTimeSpans); //#endregion } } //اگر مرخصی روزانه نداشت و فقط مرخصی ساعتی داشت //if (leaveSearchResult.Count == 0 && hoursesleave.Count > 0) //{ // if (hoursesleaveTimeSpans > starndardHoursesPerTotalDaysSapn) // { // sumSpans = sumSpans.Add(starndardHoursesPerTotalDaysSapn); // } // else // { // sumSpans = sumSpans.Add(hoursesleaveTimeSpans); // } //} Console.WriteLine(sumSpans); #endregion //***********************************// //ToTalHourse Employe eWorked double totalHourses = (sumSpans.TotalMinutes) / 60; int totalHolidaysAndNotH = (int)sumSpans.TotalHours; int totalHolidaysAndNotM = (int)(sumSpans.TotalMinutes % 60); //***********************************// //********** محاسبه مدت اضافه کاری ***********// #region ComputeMandatoryAtThisTime //***********************************// //var dailyFix = TimeSpan.Parse("07:20"); //TimeSpan mandatoryHoursTimeSpan = new TimeSpan(7, 20, 0).Multiply(mandatorDays); //TimeSpan Mandatory = sumSpansWhitOutleaves.Subtract(mandatoryHoursTimeSpan); double mandatoryWorkWithOutleaves = (sumSpans.TotalMinutes) / 60; double overTimeWork = 0; if (mandatoryWorkWithOutleaves > mandatoryHours) { overTimeWork = mandatoryWorkWithOutleaves - mandatoryHours; } #endregion //******* دستمزد روزانه *******// #region DailyFeeCompute var searchModel = new LeftWorkSearchModel() { EmployeeId = command.EmployeeId, WorkshopId = command.WorkshopId, }; var leftworkList = _leftWorkRepository.search(searchModel); var basic = "0"; double dayliFeeComplete = 0; var GetWorkStartDate = command.GetWorkDateHide.ToEnglishNumber(); var styear = Convert.ToInt32(GetWorkStartDate.Substring(0, 4)); var startDate = command.GetWorkDateHide.ToGeorgianDateTime(); var dayliFee = "خطای تاریخ"; double dayliFeeDouble = 0; double baseYearUnAffected = 0; double baseYearAffected = 0; double dailySalaryAffected = 0; if (styear >= 1370) { if (leftworkList == null) leftworkList = new List(); //var dayliFeeResult = _yearlySalaryRepository.DayliFeeComputing(startDate, contractStart, contractEnd, // command.EmployeeId, command.WorkshopId, leftworkList); //dayliFee = dayliFeeResult.DayliFee; //dayliFeeDouble = dayliFeeResult.DayliFeeDouble; //dayliFeeComplete = dayliFeeResult.DayliFee.MoneyToDouble(); //basic = dayliFeeResult.Basic; //dayliFee = dailyWageUnAffected; var baseYear = _yearlySalaryRepository.BaseYearCompute(contractStart, contractEnd, command.EmployeeId, command.WorkshopId, leftworkList).Result; dayliFee = (dailyWageUnAffected + baseYear.BaseYearResult).ToMoney(); baseYearUnAffected = baseYear.BaseYearResult; baseYearAffected = baseYearUnAffected; dailySalaryAffected = dailyWageUnAffected; } #endregion #region ConsumableItemsAndHousingAndFamily var ConsumableItems = _yearlySalaryRepository.ConsumableItems(contractEnd); var HousingAllowance = _yearlySalaryRepository.HousingAllowance(contractEnd); var familyAllowance = _yearlySalaryRepository.FamilyAllowance(command.EmployeeId, contractStart, contractEnd); var MarriedAllowance = _yearlySalaryRepository.MarriedAllowance(contractEnd, command.EmployeeId); // حق تاهل string MarriedAllowanceStr = MarriedAllowance > 0 ? MarriedAllowance.ToMoney() : "0"; #endregion var totalWeek = (int)(TotalContractDays / 6); #region Fix44Compute int TotalContractdaysUnder30 = TotalContractDays > 30 ? 30 : TotalContractDays; if (totalHourses < mandatoryHours) { if (!string.IsNullOrWhiteSpace(command.ShiftWork)) { var workedHoursePerDay = totalHourses / mandatorDays; //var result = (dayliFeeDouble / 7.33) * workedHoursePerDay; //dayliFee = result.ToMoney(); #region NeWdailyWage var da = dailyWageUnAffected / 7.33; dailySalaryAffected = da > 0 ? ((workedHoursePerDay * da).ToMoney()).MoneyToDouble() : 0; var ba = baseYearUnAffected / 7.33; baseYearAffected = ba > 0 ? ((workedHoursePerDay * ba).ToMoney()).MoneyToDouble() : 0; var fullDailySalary = dailySalaryAffected + baseYearAffected; dayliFee = fullDailySalary.ToMoney(); #endregion var HousingAllowonceNumberType = HousingAllowance.MoneyToDouble(); var HousingStep1 = HousingAllowonceNumberType / 30; var HousingStep2 = HousingStep1 / 7.33; var HousingStep3 = HousingStep2 * workedHoursePerDay; var HousingStep4 = HousingStep3 * TotalContractdaysUnder30; HousingAllowance = HousingStep4.ToMoney(); var ConsumableItemsNumberType = ConsumableItems.MoneyToDouble(); var consumableItemsStep1 = ConsumableItemsNumberType / 30; var consumableItemsStep2 = consumableItemsStep1 / 7.33; var consumableItemsStep3 = consumableItemsStep2 * workedHoursePerDay; var consumableItemsStep4 = consumableItemsStep3 * TotalContractdaysUnder30; ConsumableItems = consumableItemsStep4.ToMoney(); //حق تاهل if (MarriedAllowance > 0) { var MarriedStep1 = MarriedAllowance / 30; var MarriedStep2 = MarriedStep1 / 7.33; var MarriedStep3 = MarriedStep2 * workedHoursePerDay; var MarriedStep4 = MarriedStep3 * TotalContractdaysUnder30; MarriedAllowanceStr = MarriedStep4.ToMoney(); } if (familyAllowance != "0") { var familyAllowanceNumberType = familyAllowance.MoneyToDouble(); var familyAllowanceStep1 = familyAllowanceNumberType / 30; var familyAllowanceStep2 = familyAllowanceStep1 / 7.33; var familyAllowanceStep3 = familyAllowanceStep2 * workedHoursePerDay; var familyAllowanceStep4 = familyAllowanceStep3 * TotalContractdaysUnder30; familyAllowance = familyAllowanceStep4.ToMoney(); } if (totalWeek > 1) { double weekAvrage = 0; if (totalHourses < 44.00) { weekAvrage = (totalHourses * 6) / TotalContractDays; } else { weekAvrage = (totalHourses * 6) / TotalDaysNoFriday; } //var oneday = weekAvrage * 6; var totalShiftRound = Math.Round(weekAvrage, 2); SumWorkeTime = $"{totalShiftRound}"; } else if (totalWeek <= 1 && TotalDaysNoFriday <= 6) { var totalShiftRound = Math.Round(totalHourses, 2); SumWorkeTime = $"{totalShiftRound}"; } else if (totalWeek <= 1 && TotalDaysNoFriday > 6) { var perDyeWorked = totalHourses / TotalDaysNoFriday; var weekAvrage = perDyeWorked * 6; var totalShiftRound = Math.Round(weekAvrage, 2); SumWorkeTime = $"{totalShiftRound}"; } weeklyTime = sumSpans; } } else // اگر بیشتر از 44 بود { var HousingAllowonceNumberType = HousingAllowance.MoneyToDouble(); var ConsumableItemsNumberType = ConsumableItems.MoneyToDouble(); var familyAllowanceNumberType = familyAllowance.MoneyToDouble(); var HousingStep1 = HousingAllowonceNumberType / 30; var HousingStep4 = HousingStep1 * TotalContractdaysUnder30; HousingAllowance = HousingStep4.ToMoney(); var consumableItemsStep1 = ConsumableItemsNumberType / 30; var consumableItemsStep4 = consumableItemsStep1 * TotalContractdaysUnder30; ConsumableItems = consumableItemsStep4.ToMoney(); //حق تاهل if (MarriedAllowance > 0) { var MarriedStep1 = MarriedAllowance / 30; var MarriedStep4 = MarriedStep1 * TotalContractdaysUnder30; MarriedAllowanceStr = MarriedStep4.ToMoney(); } if (familyAllowance != "0") { var familyAllowanceStep1 = familyAllowanceNumberType / 30; var familyAllowanceStep4 = familyAllowanceStep1 * TotalContractdaysUnder30; familyAllowance = familyAllowanceStep4.ToMoney(); } SumWorkeTime = $"{44}"; //اضافه کار if (overTimeWork > 0) { //int mandatoryH = (int)Mandatory.TotalHours; //int mandatoryM = (int)(Mandatory.TotalMinutes % 60); int mandatoryH = (int)overTimeWork; int mandatoryM = (int)Math.Round((overTimeWork - mandatoryH) * 60); overMandatoryHours = mandatoryH.ToString(); overMandatoryMinuts = mandatoryM.ToString(); } } #endregion //****** نوبت کاری و شب کاری **** #region RotatingShiftCheckAndNightWorkOver22 string shiftPayValue = "0"; List rotatingResultList = RotatingShiftCheck(groupedRollCall); // شبکاری TimeSpan over22 = new TimeSpan(rotatingResultList.Sum(x => x.NightWorkSpan.Ticks)); var RotatingfaName = new List(); //if (command.ShiftWork != "1" && command.ShiftWork != "2" && command.ShiftWork != "4")//اگر چرخشی بود و منظم نبود //{ // if (moriningCount > 0) // RotatingfaName.Add("صبح"); // if (eveningCount > 0) // RotatingfaName.Add("عصر"); // if (nightCount > 0) // RotatingfaName.Add("شب"); //} //else// اگر منظم و شیفتی بود //{ // var totalDays = (int)(command.ContractEndGr - command.ContractStartGr).TotalDays + 1; // int validCount = 0; // if (totalDays <= 7) // زیر 7 روز باید حد اقل 2 تغییر شیفت داشته باشد // { // validCount = 2; // } // else if (totalDays >= 28) // بالای 28 روز حد اقل 8 تغییر شیفت // { // validCount = 8; // } // else // { // // تناسب گیری - اگر برای 28 روز 8 تغییر پس برای ایکس روز چند تغییر لازم است // validCount = (int)((totalDays * 8) / 28); // } // if (moriningCount >= validCount) // RotatingfaName.Add("صبح"); // if (eveningCount >= validCount) // RotatingfaName.Add("عصر"); // if (nightCount >= validCount) // RotatingfaName.Add("شب"); //} int moriningCount = 0; int eveningCount = 0; int nightCount = 0; int moriningWinRate = rotatingResultList.Where(x => x.IsMorningShift).Sum(x => x.WinRate); int eveningWinRate = rotatingResultList.Where(x => x.IsEveningShift).Sum(x => x.WinRate); int nightWinRate = rotatingResultList.Where(x => x.IsNightShift).Sum(x => x.WinRate); if (moriningWinRate > eveningWinRate && moriningWinRate > nightWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift); eveningCount = rotatingResultList.Count(x => x.IsEveningShift && x.WinRate > 55); nightCount = rotatingResultList.Count(x => x.IsNightShift && x.WinRate > 55); } if (eveningWinRate > moriningWinRate && eveningWinRate > nightWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift && x.WinRate > 55); eveningCount = rotatingResultList.Count(x => x.IsEveningShift); nightCount = rotatingResultList.Count(x => x.IsNightShift && x.WinRate > 55); } if (nightWinRate > moriningWinRate && nightWinRate > eveningWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift && x.WinRate > 55); eveningCount = rotatingResultList.Count(x => x.IsEveningShift && x.WinRate > 55); nightCount = rotatingResultList.Count(x => x.IsNightShift); } var totalDays = (int)(command.ContractEndGr - command.ContractStartGr).TotalDays + 1; int validCount = 0; if (totalDays <= 7) // زیر 7 روز باید حد اقل 2 تغییر شیفت داشته باشد { validCount = 2; } else if (totalDays >= 28) // بالای 28 روز حد اقل 8 تغییر شیفت { validCount = 6; } else { // تناسب گیری - اگر برای 28 روز 8 تغییر پس برای ایکس روز چند تغییر لازم است validCount = (int)((totalDays * 6) / 28); } string maxName; int maxValue = moriningCount; maxName = "moriningCount"; if (eveningCount > maxValue) { maxValue = eveningCount; maxName = "eveningCount"; } if (nightCount > maxValue) { maxValue = nightCount; maxName = "nightCount"; } int countOutOfRange = 0; switch (maxName) { case "moriningCount": countOutOfRange = eveningCount + nightCount; break; case "eveningCount": countOutOfRange = moriningCount + nightCount; break; case "nightCount": countOutOfRange = moriningCount + eveningCount; break; } var rotatingFaResult = ""; if (countOutOfRange >= validCount && rotatingShiftCompute) { shiftOver22Hours = "0"; shiftOver22Minuts = "0"; if (moriningCount >= 1) RotatingfaName.Add("صبح"); if (eveningCount >= 1) RotatingfaName.Add("عصر"); if (nightCount >= 1) RotatingfaName.Add("شب"); for (var rotateNumber = 0; rotateNumber < RotatingfaName.Count; rotateNumber++) { if (rotateNumber == 0) rotatingFaResult = $"{RotatingfaName[rotateNumber]}"; if (rotateNumber == 1) rotatingFaResult += $" و {RotatingfaName[rotateNumber]}"; if (rotateNumber == 2) rotatingFaResult += $" و {RotatingfaName[rotateNumber]}"; } } else { rotatingFaResult = "نوبت کاری ندارد"; var over22Hours = (int)over22.TotalHours; var over22Minuts = (int)(over22.TotalMinutes % 60); shiftOver22Hours = over22Hours.ToString(); shiftOver22Minuts = over22Minuts.ToString(); } #endregion //******* محاسبه مبلغ نوبت کاری ************* #region ShiftPayPercent if (rotatingFaResult != "نوبت کاری ندارد" || rotatingFaResult != "") { var TotalDays = (command.ContractEndGr - command.ContractStartGr).TotalDays + 1; var DailyFeeNumberType = dayliFee.MoneyToDouble(); if (rotatingFaResult == "صبح و عصر") { var shiftPyaPercent = DailyFeeNumberType * 10 / 100; ShiftPayResult = shiftPyaPercent * TotalDays; shiftPayValue = "10"; } else if (rotatingFaResult == "صبح و عصر و شب") { var shiftPyaPercent = DailyFeeNumberType * 15 / 100; ShiftPayResult = shiftPyaPercent * TotalDays; shiftPayValue = "15"; } else if (rotatingFaResult == "صبح و شب" || rotatingFaResult == "عصر و شب") { var shiftPyaPercent = DailyFeeNumberType * 22.5 / 100; ShiftPayResult = shiftPyaPercent * TotalDays; shiftPayValue = "22.5"; } } #endregion #region Result LeaveSearchModel sickLeaveSearch = new LeaveSearchModel() { EmployeeId = employeeId, WorkshopId = workshopId, LeaveType = "استعلاجی", PaidLeaveType = "روزانه", StartLeaveGr = contractStart, EndLeaveGr = contractEnd, IsAccepted = true, }; var sickLeaveSearchResult = _leaveRepository.search(sickLeaveSearch); var sickLeaveTimeSpans = sickLeaveSearchResult.Select(x => { var startLeave = contractStart > x.StartLeaveGr ? contractStart : x.StartLeaveGr; var endLeave = contractEnd < x.EndLeaveGr ? contractEnd : x.EndLeaveGr; return (endLeave - startLeave).Add(TimeSpan.FromDays(1)); }); var totalBreakTime = new TimeSpan(groupedRollCall.Sum(x => x.BreakTime.Ticks)); var res = new ComputingViewModel() { NumberOfWorkingDays = $"{groupedRollCall.Count}", NumberOfFriday = $"{numberOfFridays}", TotalHoursesH = totalHolidaysAndNotH.ToString(), TotalHoursesM = totalHolidaysAndNotM.ToString(), OverTimeWorkH = overMandatoryHours, OverTimeWorkM = overMandatoryMinuts, OverNightWorkH = shiftOver22Hours, OverNightWorkM = shiftOver22Minuts, ComplexNumberOfWorkingDays = $"{groupedRollCall.Count}", SalaryCompute = dayliFee, SumTime44 = SumWorkeTime, ConsumableItems = ConsumableItems, HousingAllowance = HousingAllowance, FamilyAllowance = familyAllowance, OfficialHoliday = holiday, weeklyTime = weeklyTime, RotatingResultList = rotatingResultList, RotatingStatus = rotatingFaResult, ShiftPay = ShiftPayResult, Basic = basic, FridayStartToEnd = fridays, TotalHolidayAndNotH = totalHolidaysAndNotH.ToString(), TotalHolidayAndNotM = totalHolidaysAndNotM.ToString(), DayliFeeComplete = dayliFeeComplete, MarriedAllowance = MarriedAllowanceStr, RotatingShiftValue = shiftPayValue, #region SaveRollCall GroupedRollCalls = groupedRollCall, //کارکرد واقعی - محاسبات شامل مرخصی افزوده شده TotalWorkingTimeSpan = sumSpans, // ساعت استراحت TotalBreakTimeSpan = totalBreakTime, // ساعت حضور - بدون مرخصی افزده شده TotalPresentTimeSpan = sumSpansWhitOutleaves, // مرخصی استحقاقی TotalPaidLeave = totalLeaveSpan, //// مجموع مرخصی های پرسنل در این فیش حقوقی //TotalLeaveOnThisCheckout = totalLeaveOnThisCheckout, //مرخصی استعلاجی TotalSickLeave = new TimeSpan(sickLeaveTimeSpans.Sum(x => x.Ticks)), //ساعت موظفی پرسنل در این ماه EmployeeMandatoryHours = mandatoryHoursTimeSpan, #endregion #region NewDailWage BaseYearAffected = baseYearAffected, DailySalaryAffected = dailySalaryAffected, #endregion }; #endregion return res; } /// /// محاسبه ساعات کارکرد پرسنل در صورت داشتن حضور غیاب /// /// /// /// /// /// public (bool hasRollCall, TimeSpan sumOfSpan) GetRollCallWorkingSpan(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { //bool hasRollcall = // _rollCallEmployeeRepository.HasRollCallRecord(employeeId, workshopId, contractStart, contractEnd); //if (!hasRollcall) // return (false, new TimeSpan()); List rollCallResult; List groupedRollCall; rollCallResult = _context.RollCalls.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.StartDate.Value.Date >= contractStart.Date && x.StartDate.Value.Date <= contractEnd.Date && x.EndDate != null).Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.ShiftDate, BreakTimeSpan = x.BreakTimeSpan }).ToList(); groupedRollCall = rollCallResult.GroupBy(x => x.CreationDate.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value }).ToList(), HasFriday = x.Any(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) - CalculateBreakTime( x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), BreakTime = CalculateBreakTime(x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), }).OrderBy(x => x.CreationDate).ToList(); TimeSpan sumSpans = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); return (true, sumSpans); } public async Task RotatingShiftReport(long workshopId, long employeeId, DateTime contractStart, DateTime contractEnd, string shiftwork, bool hasRollCall, CreateWorkingHoursTemp command, bool holidayWorking) { List rollCallResult = new List(); List groupedRollCall = new List(); if (hasRollCall) { rollCallResult = await _context.RollCalls.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.StartDate.Value.Date >= contractStart.Date && x.StartDate.Value.Date <= contractEnd.Date && x.EndDate != null).Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.ShiftDate, }).ToListAsync(); groupedRollCall = rollCallResult.GroupBy(x => x.CreationDate.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value }) .ToList(), HasFriday = x.Any(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), }).OrderBy(x => x.CreationDate).ToList(); } else { command.WorkshopId = workshopId; command.EmployeeId = employeeId; command.ContractStartGr = contractStart; command.ContractEndGr = contractEnd; rollCallResult = ConvertStaticHoursToRollCall(command, holidayWorking); groupedRollCall = rollCallResult.GroupBy(x => x.ShiftDate.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value }) .ToList(), HasFriday = x.Any(s => s.StartDate != null && s.EndDate != null && (s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value!.DayOfWeek == DayOfWeek.Friday)), SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) }).OrderBy(x => x.CreationDate).ToList(); } //****** نوبت کاری و شب کاری **** #region RotatingShiftCheckAndNightWorkOver22 string shiftPayValue = "0"; List rotatingResultList = RotatingShiftCheck(groupedRollCall); int moriningCount = 0; int eveningCount = 0; int nightCount = 0; int moriningWinRate = rotatingResultList.Where(x => x.IsMorningShift).Sum(x => x.WinRate); int eveningWinRate = rotatingResultList.Where(x => x.IsEveningShift).Sum(x => x.WinRate); int nightWinRate = rotatingResultList.Where(x => x.IsNightShift).Sum(x => x.WinRate); if (moriningWinRate > eveningWinRate && moriningWinRate > nightWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift); eveningCount = rotatingResultList.Count(x => x.IsEveningShift && x.WinRate > 55); nightCount = rotatingResultList.Count(x => x.IsNightShift && x.WinRate > 55); } if (eveningWinRate > moriningWinRate && eveningWinRate > nightWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift && x.WinRate > 55); eveningCount = rotatingResultList.Count(x => x.IsEveningShift); nightCount = rotatingResultList.Count(x => x.IsNightShift && x.WinRate > 55); } if (nightWinRate > moriningWinRate && nightWinRate > eveningWinRate) { moriningCount = rotatingResultList.Count(x => x.IsMorningShift && x.WinRate > 55); eveningCount = rotatingResultList.Count(x => x.IsEveningShift && x.WinRate > 55); nightCount = rotatingResultList.Count(x => x.IsNightShift); } // شبکاری TimeSpan over22 = new TimeSpan(rotatingResultList.Sum(x => x.NightWorkSpan.Ticks)); var RotatingfaName = new List(); var totalDays = (int)(contractEnd - contractStart).TotalDays + 1; int validCount = 0; if (totalDays <= 7) // زیر 7 روز باید حد اقل 2 تغییر شیفت داشته باشد { validCount = 2; } else if (totalDays >= 28) // بالای 28 روز حد اقل 8 تغییر شیفت { validCount = 6; } else { // تناسب گیری - اگر برای 28 روز 8 تغییر پس برای ایکس روز چند تغییر لازم است validCount = (int)((totalDays * 6) / 28); } string maxName; int maxValue = moriningCount; maxName = "moriningCount"; if (eveningCount > maxValue) { maxValue = eveningCount; maxName = "eveningCount"; } if (nightCount > maxValue) { maxValue = nightCount; maxName = "nightCount"; } int countOutOfRange = 0; switch (maxName) { case "moriningCount": countOutOfRange = eveningCount + nightCount; break; case "eveningCount": countOutOfRange = moriningCount + nightCount; break; case "nightCount": countOutOfRange = moriningCount + eveningCount; break; } var rotatingFaResult = ""; if (countOutOfRange >= validCount) { if (moriningCount >= 1) RotatingfaName.Add("صبح"); if (eveningCount >= 1) RotatingfaName.Add("عصر"); if (nightCount >= 1) RotatingfaName.Add("شب"); for (var rotateNumber = 0; rotateNumber < RotatingfaName.Count; rotateNumber++) { if (rotateNumber == 0) rotatingFaResult = $"{RotatingfaName[rotateNumber]}"; if (rotateNumber == 1) rotatingFaResult += $" و {RotatingfaName[rotateNumber]}"; if (rotateNumber == 2) rotatingFaResult += $" و {RotatingfaName[rotateNumber]}"; } } else { rotatingFaResult = "نوبت کاری ندارد"; } return new ComputingViewModel { RotatingStatus = rotatingFaResult, RotatingResultList = rotatingResultList }; #endregion } public static TimeSpan CalculateBreakTime(BreakTime breakTime, TimeSpan sumOneDaySpan) { if (breakTime.BreakTimeType != BreakTimeType.WithTime) return new TimeSpan(); var breakTimeSpan = breakTime.BreakTimeValue.ToTimeSpan(); if (breakTimeSpan * 2 >= sumOneDaySpan) return new TimeSpan(); return breakTimeSpan; ; } public static TimeSpan CalculateBreakTime(TimeSpan breakTimeSpan, TimeSpan sumOneDaySpan) { if (breakTimeSpan * 2 >= sumOneDaySpan) return new TimeSpan(); return breakTimeSpan; ; } public TimeSpan AfterSubtract(CreateWorkingHoursTemp command, TimeSpan sumOneDaySpan, DateTime creationDate) { #region RestTimes var rest0 = new TimeSpan(); var rest1 = new TimeSpan(); var rest2 = new TimeSpan(); var rest3 = new TimeSpan(); var rest4 = new TimeSpan(); var rest5 = new TimeSpan(); var rest6 = new TimeSpan(); switch (command.ShiftWork) { case "1": case "2": command.RestTime = command.RestTime == "0" ? "00" : command.RestTime; command.RestTimeYekshanbeh = command.RestTimeYekshanbeh == "0" ? "00" : command.RestTimeYekshanbeh; command.RestTimeDoshanbeh = command.RestTimeDoshanbeh == "0" ? "00" : command.RestTimeDoshanbeh; command.RestTimeSeshanbeh = command.RestTimeSeshanbeh == "0" ? "00" : command.RestTimeSeshanbeh; command.RestTimeCheharshanbeh = command.RestTimeCheharshanbeh == "0" ? "00" : command.RestTimeCheharshanbeh; command.RestTimePanjshanbeh = command.RestTimePanjshanbeh == "0" ? "00" : command.RestTimePanjshanbeh; command.RestTimeJomeh = command.RestTimeJomeh == "0" ? "00" : command.RestTimeJomeh; command.RestTimeMin = command.RestTimeMin == "0" ? "00" : command.RestTimeMin; command.RestTimeYekshanbehMin = command.RestTimeYekshanbehMin == "0" ? "00" : command.RestTimeYekshanbehMin; command.RestTimeDoshanbehMin = command.RestTimeDoshanbehMin == "0" ? "00" : command.RestTimeDoshanbehMin; command.RestTimeSeshanbehMin = command.RestTimeSeshanbehMin == "0" ? "00" : command.RestTimeSeshanbehMin; command.RestTimeCheharshanbehMin = command.RestTimeCheharshanbehMin == "0" ? "00" : command.RestTimeCheharshanbehMin; command.RestTimePanjshanbehMin = command.RestTimePanjshanbehMin == "0" ? "00" : command.RestTimePanjshanbehMin; command.RestTimeJomehMin = command.RestTimeJomehMin == "0" ? "00" : command.RestTimeJomehMin; rest0 = TimeSpan.Parse($"{command.RestTime}:{command.RestTimeMin}"); rest1 = TimeSpan.Parse($"{command.RestTimeYekshanbeh}:{command.RestTimeYekshanbehMin}"); rest2 = TimeSpan.Parse($"{command.RestTimeDoshanbeh}:{command.RestTimeDoshanbehMin}"); rest3 = TimeSpan.Parse($"{command.RestTimeSeshanbeh}:{command.RestTimeSeshanbehMin}"); rest4 = TimeSpan.Parse($"{command.RestTimeCheharshanbeh}:{command.RestTimeCheharshanbehMin}"); rest5 = TimeSpan.Parse($"{command.RestTimePanjshanbeh}:{command.RestTimePanjshanbehMin}"); rest6 = TimeSpan.Parse($"{command.RestTimeJomeh}:{command.RestTimeJomehMin}"); break; case "4": command.RestTimeShanbe1 = command.RestTimeShanbe1 == "0" ? "00" : command.RestTimeShanbe1; command.RestTimeShanbe1Min = command.RestTimeShanbe1Min == "0" ? "00" : command.RestTimeShanbe1Min; command.RestTimeYekShanbe1 = command.RestTimeYekShanbe1 == "0" ? "00" : command.RestTimeYekShanbe1; command.RestTimeYekShanbe1Min = command.RestTimeYekShanbe1Min == "0" ? "00" : command.RestTimeYekShanbe1Min; command.RestTimeDoShanbe1 = command.RestTimeDoShanbe1 == "0" ? "00" : command.RestTimeDoShanbe1; command.RestTimeDoShanbe1Min = command.RestTimeDoShanbe1Min == "0" ? "00" : command.RestTimeDoShanbe1Min; command.RestTimeSeShanbe1 = command.RestTimeSeShanbe1 == "0" ? "00" : command.RestTimeSeShanbe1; command.RestTimeSeShanbe1Min = command.RestTimeSeShanbe1Min == "0" ? "00" : command.RestTimeSeShanbe1Min; command.RestTimeCheharShanbe1 = command.RestTimeCheharShanbe1 == "0" ? "00" : command.RestTimeCheharShanbe1; command.RestTimeCheharShanbe1Min = command.RestTimeCheharShanbe1Min == "0" ? "00" : command.RestTimeCheharShanbe1Min; command.RestTimePanjShanbe1 = command.RestTimePanjShanbe1 == "0" ? "00" : command.RestTimePanjShanbe1; command.RestTimePanjShanbe1Min = command.RestTimePanjShanbe1Min == "0" ? "00" : command.RestTimePanjShanbe1Min; command.RestTimeJome1 = command.RestTimeJome1 == "0" ? "00" : command.RestTimeJome1; command.RestTimeJome1Min = command.RestTimeJome1Min == "0" ? "00" : command.RestTimeJome1Min; // sumrest week1 rest0 = TimeSpan.Parse($"{command.RestTimeShanbe1}:{command.RestTimeShanbe1Min}"); rest1 = TimeSpan.Parse($"{command.RestTimeYekShanbe1}:{command.RestTimeYekShanbe1Min}"); rest2 = TimeSpan.Parse($"{command.RestTimeDoShanbe1}:{command.RestTimeDoShanbe1Min}"); rest3 = TimeSpan.Parse($"{command.RestTimeSeShanbe1}:{command.RestTimeSeShanbe1Min}"); rest4 = TimeSpan.Parse($"{command.RestTimeCheharShanbe1}:{command.RestTimeCheharShanbe1Min}"); rest5 = TimeSpan.Parse($"{command.RestTimePanjShanbe1}:{command.RestTimePanjShanbe1Min}"); rest6 = TimeSpan.Parse($"{command.RestTimeJome1}:{command.RestTimeJome1Min}"); break; } //week1 #endregion var result = new TimeSpan(); switch (creationDate.DayOfWeek) { case DayOfWeek.Saturday: if (sumOneDaySpan >= rest0) result = sumOneDaySpan.Subtract(rest0); break; case DayOfWeek.Sunday: if (sumOneDaySpan >= rest1) result = sumOneDaySpan.Subtract(rest1); break; case DayOfWeek.Monday: if (sumOneDaySpan >= rest2) result = sumOneDaySpan.Subtract(rest2); break; case DayOfWeek.Tuesday: if (sumOneDaySpan >= rest3) result = sumOneDaySpan.Subtract(rest3); break; case DayOfWeek.Wednesday: if (sumOneDaySpan >= rest4) result = sumOneDaySpan.Subtract(rest4); break; case DayOfWeek.Thursday: if (sumOneDaySpan >= rest5) result = sumOneDaySpan.Subtract(rest5); break; case DayOfWeek.Friday: if (sumOneDaySpan >= rest6) result = sumOneDaySpan.Subtract(rest6); break; } return result; } public List RotatingShiftCheck(List rollCallList) { List finalResult = new List(); var nullDateTme = new DateTime(0001, 01, 01); foreach (var item in rollCallList) { #region Entityes var morningWorkingTime = new TimeSpan(); var eveningWorkingTime = new TimeSpan(); var nightWorkingTime = new TimeSpan(); #endregion foreach (var shift in item.ShiftList) { #region DatePeriod var shiftDate = item.CreationDate; if (shift.Start.Date < shiftDate.Date) shiftDate = shiftDate.AddDays(-1); DateTime midNight24 = new DateTime(shiftDate.Year, shiftDate.Month, shiftDate.Day, 0, 0, 0); DateTime morningStart = new DateTime(shiftDate.Year, shiftDate.Month, shiftDate.Day, 6, 0, 0); DateTime morningEnd = new DateTime(shiftDate.Year, shiftDate.Month, shiftDate.Day, 14, 0, 0); DateTime eveningStart = morningEnd; DateTime eveningEnd = new DateTime(shiftDate.Year, shiftDate.Month, shiftDate.Day, 22, 0, 0); DateTime nightStart = eveningEnd; DateTime nightEnd = morningStart; DateTime nightEndNextday = nightEnd.AddDays(1); DateTime morningEndNextday = morningEnd.AddDays(1); DateTime eveningEndNextday = eveningEnd.AddDays(1); #endregion #region MidNight Enter 00:00 ---> 6 if (shift.Start >= midNight24 // 00:00 >---> 6 && shift.End <= morningStart) { nightWorkingTime = nightWorkingTime.Add(shift.End - shift.Start); } else if (shift.Start >= midNight24 && shift.Start < morningStart // 00:00---6--->14 && shift.End > morningStart && shift.End <= morningEnd) { nightWorkingTime = nightWorkingTime.Add(morningStart - shift.Start); morningWorkingTime = morningWorkingTime.Add(shift.End - morningStart); } else if (shift.Start >= midNight24 && shift.Start < morningStart // 00:00---6---14--->22 && shift.End > morningEnd && shift.End <= eveningEnd) { nightWorkingTime = nightWorkingTime.Add(morningStart - shift.Start); morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); eveningWorkingTime = eveningWorkingTime.Add(shift.End - eveningStart); } else if (shift.Start >= midNight24 // 00:00---6---14----22---->6 && shift.Start < morningStart && shift.End > eveningEnd && shift.End <= nightEndNextday) { nightWorkingTime = nightWorkingTime.Add(morningStart - shift.Start); morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); eveningWorkingTime = eveningWorkingTime.Add(new TimeSpan(8, 0, 0)); nightWorkingTime = nightWorkingTime.Add(shift.End - eveningEnd); } #endregion #region morning enter 14 <- 6 if (shift.Start >= morningStart // 14<---<6 && shift.End <= morningEnd) { morningWorkingTime = morningWorkingTime.Add(shift.End - shift.Start); } else if (shift.Start >= morningStart && shift.Start < morningEnd // 22<---14---6 && shift.End > eveningStart && shift.End <= eveningEnd) { morningWorkingTime = morningWorkingTime.Add(morningEnd - shift.Start); eveningWorkingTime = eveningWorkingTime.Add(shift.End - eveningStart); } else if (shift.Start >= morningStart && shift.Start < morningEnd // // 6<---22---14---6 && shift.End > eveningEnd && shift.End <= nightEndNextday) { morningWorkingTime = morningWorkingTime.Add(morningEnd - shift.Start); eveningWorkingTime = eveningWorkingTime.Add(new TimeSpan(8, 0, 0)); nightWorkingTime = nightWorkingTime.Add(shift.End - eveningEnd); } else if (shift.Start >= morningStart // 14<---6<---22---14---6 && shift.Start < morningEnd && shift.End > nightEndNextday && shift.End <= morningEndNextday) { morningWorkingTime = morningWorkingTime.Add(morningEnd - shift.Start); eveningWorkingTime = eveningWorkingTime.Add(new TimeSpan(8, 0, 0)); nightWorkingTime = nightWorkingTime.Add(new TimeSpan(8, 0, 0)); TimeSpan nextDayMorningSpan = (shift.End - nightEndNextday); morningWorkingTime = morningWorkingTime.Add(nextDayMorningSpan); } else if (shift.Start >= morningStart // 22<---14<---6<---22---14---6 && shift.Start < morningEnd && shift.End > morningEndNextday && shift.End <= eveningEndNextday) { morningWorkingTime = morningWorkingTime.Add(morningEnd - shift.Start); eveningWorkingTime = eveningWorkingTime.Add(new TimeSpan(8, 0, 0)); nightWorkingTime = nightWorkingTime.Add(new TimeSpan(8, 0, 0)); morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); TimeSpan nextDayEveningSpan = (shift.End - morningEndNextday); eveningWorkingTime = eveningWorkingTime.Add(nextDayEveningSpan); } #endregion #region evening enter 22 <- 14 if (shift.Start >= eveningStart // 22<---<14 && shift.End <= eveningEnd) { eveningWorkingTime = eveningWorkingTime.Add(shift.End - shift.Start); } else if (shift.Start >= eveningStart && shift.Start < eveningEnd // 6<---22---14 && shift.End > nightStart && shift.End <= nightEndNextday) { eveningWorkingTime = eveningWorkingTime.Add(eveningEnd - shift.Start); nightWorkingTime = nightWorkingTime.Add(shift.End - eveningEnd); } else if (shift.Start >= eveningStart && shift.Start < eveningEnd // // 14<---6---22---14 && shift.End > nightEndNextday && shift.End <= morningEndNextday) { eveningWorkingTime = eveningWorkingTime.Add(eveningEnd - shift.Start); nightWorkingTime = nightWorkingTime.Add(new TimeSpan(8, 0, 0)); morningWorkingTime = morningWorkingTime.Add(shift.End - nightEndNextday); } else if (shift.Start >= eveningStart // 22<---14<---6---22---14 && shift.Start < eveningEnd && shift.End > morningEndNextday && shift.End <= eveningEndNextday) { eveningWorkingTime = eveningWorkingTime.Add(morningEnd - shift.Start); nightWorkingTime = nightWorkingTime.Add(new TimeSpan(8, 0, 0)); morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); TimeSpan nextDayEveningSpan = (shift.End - morningEndNextday); eveningWorkingTime = eveningWorkingTime.Add(nextDayEveningSpan); } #endregion #region night enter 6 <- 22 if (shift.Start >= nightStart // 6<---<22 && shift.End <= nightEndNextday) { nightWorkingTime = nightWorkingTime.Add(shift.End - shift.Start); } else if (shift.Start >= nightStart && shift.Start < nightEndNextday // 14<---6---22 && shift.End > nightEndNextday && shift.End <= morningEndNextday) { nightWorkingTime = nightWorkingTime.Add(nightEndNextday - shift.Start); morningWorkingTime = morningWorkingTime.Add(shift.End - nightEndNextday); } else if (shift.Start >= nightStart && shift.Start < nightEndNextday // // 22<---14---6---22 && shift.End > morningEndNextday && shift.End <= eveningEndNextday) { nightWorkingTime = nightWorkingTime.Add(nightEndNextday - shift.Start); ; morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); eveningWorkingTime = eveningWorkingTime.Add(shift.End - morningEndNextday); } else if (shift.Start >= nightStart // 6<---22<---14---6---22 && shift.Start < nightEndNextday && shift.End > eveningEndNextday) { nightWorkingTime = nightWorkingTime.Add(nightEndNextday - shift.Start); morningWorkingTime = morningWorkingTime.Add(new TimeSpan(8, 0, 0)); eveningWorkingTime = eveningWorkingTime.Add(new TimeSpan(8, 0, 0)); TimeSpan nextDayNightSpan = (shift.End - eveningEndNextday); nightWorkingTime = nightWorkingTime.Add(nextDayNightSpan); } #endregion } #region Result var result = new RotatingShiftViewModel(); result.RotatingDate = item.CreationDate.ToFarsi(); result.MorningWorkSpan = morningWorkingTime; result.EveningWorkSpan = eveningWorkingTime; result.NightWorkSpan = nightWorkingTime; var nullWorkspan = new TimeSpan(0, 0, 0); var totalTime = result.TotalWorkingTime.Add(result.MorningWorkSpan); totalTime = totalTime.Add(result.EveningWorkSpan); totalTime = totalTime.Add(result.NightWorkSpan); result.TotalWorkingTime = totalTime; var morningH = (int)result.MorningWorkSpan.TotalHours; var morningM = result.MorningWorkSpan.Minutes % 60; var morningMS = "00"; if (morningM < 10 && morningM > 0) morningMS = $"0{morningM}"; if (morningM > 10) morningMS = $"{morningM}"; result.MorningString = $"0{morningH}:{morningMS}"; var eveningH = (int)result.EveningWorkSpan.TotalHours; var eveningM = result.EveningWorkSpan.Minutes % 60; var eveningMS = "00"; if (eveningM < 10 && eveningM > 0) eveningMS = $"0{eveningM}"; if (eveningM > 10) eveningMS = $"{eveningM}"; result.EveningString = $"0{eveningH}:{eveningMS}"; var nightH = (int)result.NightWorkSpan.TotalHours; var nightM = result.NightWorkSpan.Minutes % 60; var nightMS = "00"; if (nightM < 10 && nightM > 0) nightMS = $"0{nightM}"; if (nightM > 10) nightMS = $"{nightM}"; result.NightString = $"0{nightH}:{nightMS}"; if (result.MorningWorkSpan > result.EveningWorkSpan || result.MorningWorkSpan == result.EveningWorkSpan) // if morning bigerThan evening or equal { if (result.MorningWorkSpan != nullWorkspan) { var sumSpan = result.MorningWorkSpan.Add(result.EveningWorkSpan); var sumSpanDouble = sumSpan.TotalMinutes; var winRate = (result.MorningWorkSpan.TotalMinutes * 100) / sumSpanDouble; result.WinRate = Convert.ToInt32(winRate); result.IsMorningShift = true; result.IsNightShift = false; result.IsEveningShift = false; result.RotatingShiftStatus = "صبح"; } if (result.MorningWorkSpan < result.NightWorkSpan || result.MorningWorkSpan == result.NightWorkSpan) // if night bigerThan morning or equal if (result.NightWorkSpan != nullWorkspan) { var sumSpan = result.MorningWorkSpan.Add(result.NightWorkSpan); var sumSpanDouble = sumSpan.TotalMinutes; var winRate = (result.NightWorkSpan.TotalMinutes * 100) / sumSpanDouble; result.WinRate = Convert.ToInt32(winRate); result.IsMorningShift = false; result.IsNightShift = true; result.IsEveningShift = false; result.RotatingShiftStatus = "شب"; } } else if (result.MorningWorkSpan < result.EveningWorkSpan) // if evening bigerThan morning { if (result.EveningWorkSpan != nullWorkspan) { var sumSpan = result.MorningWorkSpan.Add(result.EveningWorkSpan); var sumSpanDouble = sumSpan.TotalMinutes; var winRate = (result.EveningWorkSpan.TotalMinutes * 100) / sumSpanDouble; result.WinRate = Convert.ToInt32(winRate); result.IsEveningShift = true; result.IsMorningShift = false; result.IsNightShift = false; result.RotatingShiftStatus = "عصر"; } if (result.EveningWorkSpan < result.NightWorkSpan || result.EveningWorkSpan == result.NightWorkSpan) // if night bigerThan evening or equal if (result.NightWorkSpan != nullWorkspan) { var sumSpan = result.EveningWorkSpan.Add(result.NightWorkSpan); var sumSpanDouble = sumSpan.TotalMinutes; var winRate = (result.NightWorkSpan.TotalMinutes * 100) / sumSpanDouble; result.WinRate = Convert.ToInt32(winRate); result.IsMorningShift = false; result.IsEveningShift = false; result.IsNightShift = true; result.RotatingShiftStatus = "شب"; } } finalResult.Add(result); #endregion } return finalResult; } public List ConvertStaticHoursToRollCall(CreateWorkingHoursTemp command, bool workshopHolidyWorking) { var rollCallList = new List(); #region Entities if (string.IsNullOrWhiteSpace(command.ContarctStart) || string.IsNullOrWhiteSpace(command.ContractEnd)) { command.ContarctStart = command.ContractStartGr.ToFarsi(); command.ContractEnd = command.ContractEndGr.ToFarsi(); } var sdate = command.ContarctStart.ToEnglishNumber(); var edate = command.ContractEnd.ToEnglishNumber(); var syear = Convert.ToInt32(sdate.Substring(0, 4)); var smonth = Convert.ToInt32(sdate.Substring(5, 2)); var sday = Convert.ToInt32(sdate.Substring(8, 2)); var eyear = Convert.ToInt32(edate.Substring(0, 4)); var emonth = Convert.ToInt32(edate.Substring(5, 2)); var eday = Convert.ToInt32(edate.Substring(8, 2)); var d1 = new PersianDateTime(syear, smonth, sday); var d2 = new PersianDateTime(eyear, emonth, eday); //بدست آوردن مرخصی LeaveSearchModel leaveSearch = new LeaveSearchModel() { EmployeeId = command.EmployeeId, WorkshopId = command.WorkshopId, StartLeaveGr = command.ContractStartGr, EndLeaveGr = command.ContractEndGr, IsAccepted = true, }; var leaveSearchResult = _leaveRepository.search(leaveSearch); //بدس آوردن تعطیلات رسمی var holidayList = _holidayItemRepository.GetHolidayItem(sdate.Substring(0, 4)); bool isHoliday = false; #endregion #region SumRestTimesOneShift var rest0 = new TimeSpan(); var rest1 = new TimeSpan(); var rest2 = new TimeSpan(); var rest3 = new TimeSpan(); var rest4 = new TimeSpan(); var rest5 = new TimeSpan(); var rest6 = new TimeSpan(); var rest0w1 = new TimeSpan(); var rest1w1 = new TimeSpan(); var rest2w1 = new TimeSpan(); var rest3w1 = new TimeSpan(); var rest4w1 = new TimeSpan(); var rest5w1 = new TimeSpan(); var rest6w1 = new TimeSpan(); var rest0w2 = new TimeSpan(); var rest1w2 = new TimeSpan(); var rest2w2 = new TimeSpan(); var rest3w2 = new TimeSpan(); var rest4w2 = new TimeSpan(); var rest5w2 = new TimeSpan(); var rest6w2 = new TimeSpan(); var rest0w3 = new TimeSpan(); var rest1w3 = new TimeSpan(); var rest2w3 = new TimeSpan(); var rest3w3 = new TimeSpan(); var rest4w3 = new TimeSpan(); var rest5w3 = new TimeSpan(); var rest6w3 = new TimeSpan(); var rest0w4 = new TimeSpan(); var rest1w4 = new TimeSpan(); var rest2w4 = new TimeSpan(); var rest3w4 = new TimeSpan(); var rest4w4 = new TimeSpan(); var rest5w4 = new TimeSpan(); var rest6w4 = new TimeSpan(); if (command.ShiftWork == "4") { //week1 command.RestTimeShanbe1 = command.RestTimeShanbe1 == "0" ? "00" : command.RestTimeShanbe1; command.RestTimeShanbe1Min = command.RestTimeShanbe1Min == "0" ? "00" : command.RestTimeShanbe1Min; command.RestTimeYekShanbe1 = command.RestTimeYekShanbe1 == "0" ? "00" : command.RestTimeYekShanbe1; command.RestTimeYekShanbe1Min = command.RestTimeYekShanbe1Min == "0" ? "00" : command.RestTimeYekShanbe1Min; command.RestTimeDoShanbe1 = command.RestTimeDoShanbe1 == "0" ? "00" : command.RestTimeDoShanbe1; command.RestTimeDoShanbe1Min = command.RestTimeDoShanbe1Min == "0" ? "00" : command.RestTimeDoShanbe1Min; command.RestTimeSeShanbe1 = command.RestTimeSeShanbe1 == "0" ? "00" : command.RestTimeSeShanbe1; command.RestTimeSeShanbe1Min = command.RestTimeSeShanbe1Min == "0" ? "00" : command.RestTimeSeShanbe1Min; command.RestTimeCheharShanbe1 = command.RestTimeCheharShanbe1 == "0" ? "00" : command.RestTimeCheharShanbe1; command.RestTimeCheharShanbe1Min = command.RestTimeCheharShanbe1Min == "0" ? "00" : command.RestTimeCheharShanbe1Min; command.RestTimePanjShanbe1 = command.RestTimePanjShanbe1 == "0" ? "00" : command.RestTimePanjShanbe1; command.RestTimePanjShanbe1Min = command.RestTimePanjShanbe1Min == "0" ? "00" : command.RestTimePanjShanbe1Min; command.RestTimeJome1 = command.RestTimeJome1 == "0" ? "00" : command.RestTimeJome1; command.RestTimeJome1Min = command.RestTimeJome1Min == "0" ? "00" : command.RestTimeJome1Min; //week2 command.RestTimeShanbe2 = command.RestTimeShanbe2 == "0" ? "00" : command.RestTimeShanbe2; command.RestTimeShanbe2Min = command.RestTimeShanbe2Min == "0" ? "00" : command.RestTimeShanbe2Min; command.RestTimeYekShanbe2 = command.RestTimeYekShanbe2 == "0" ? "00" : command.RestTimeYekShanbe2; command.RestTimeYekShanbe2Min = command.RestTimeYekShanbe2Min == "0" ? "00" : command.RestTimeYekShanbe2Min; command.RestTimeDoShanbe2 = command.RestTimeDoShanbe2 == "0" ? "00" : command.RestTimeDoShanbe2; command.RestTimeDoShanbe2Min = command.RestTimeDoShanbe2Min == "0" ? "00" : command.RestTimeDoShanbe2Min; command.RestTimeSeShanbe2 = command.RestTimeSeShanbe2 == "0" ? "00" : command.RestTimeSeShanbe2; command.RestTimeSeShanbe2Min = command.RestTimeSeShanbe2Min == "0" ? "00" : command.RestTimeSeShanbe2Min; command.RestTimeCheharShanbe2 = command.RestTimeCheharShanbe2 == "0" ? "00" : command.RestTimeCheharShanbe2; command.RestTimeCheharShanbe2Min = command.RestTimeCheharShanbe2Min == "0" ? "00" : command.RestTimeCheharShanbe2Min; command.RestTimePanjShanbe2 = command.RestTimePanjShanbe2 == "0" ? "00" : command.RestTimePanjShanbe2; command.RestTimePanjShanbe2Min = command.RestTimePanjShanbe2Min == "0" ? "00" : command.RestTimePanjShanbe2Min; command.RestTimeJome2 = command.RestTimeJome2 == "0" ? "00" : command.RestTimeJome2; command.RestTimeJome2Min = command.RestTimeJome2Min == "0" ? "00" : command.RestTimeJome2Min; //week3 command.RestTimeShanbe3 = command.RestTimeShanbe3 == "0" ? "00" : command.RestTimeShanbe3; command.RestTimeShanbe3Min = command.RestTimeShanbe3Min == "0" ? "00" : command.RestTimeShanbe3Min; command.RestTimeYekShanbe3 = command.RestTimeYekShanbe3 == "0" ? "00" : command.RestTimeYekShanbe3; command.RestTimeYekShanbe3Min = command.RestTimeYekShanbe3Min == "0" ? "00" : command.RestTimeYekShanbe3Min; command.RestTimeDoShanbe3 = command.RestTimeDoShanbe3 == "0" ? "00" : command.RestTimeDoShanbe3; command.RestTimeDoShanbe3Min = command.RestTimeDoShanbe3Min == "0" ? "00" : command.RestTimeDoShanbe3Min; command.RestTimeSeShanbe3 = command.RestTimeSeShanbe3 == "0" ? "00" : command.RestTimeSeShanbe3; command.RestTimeSeShanbe3Min = command.RestTimeSeShanbe3Min == "0" ? "00" : command.RestTimeSeShanbe3Min; command.RestTimeCheharShanbe3 = command.RestTimeCheharShanbe3 == "0" ? "00" : command.RestTimeCheharShanbe3; command.RestTimeCheharShanbe3Min = command.RestTimeCheharShanbe3Min == "0" ? "00" : command.RestTimeCheharShanbe3Min; command.RestTimePanjShanbe3 = command.RestTimePanjShanbe3 == "0" ? "00" : command.RestTimePanjShanbe3; command.RestTimePanjShanbe3Min = command.RestTimePanjShanbe3Min == "0" ? "00" : command.RestTimePanjShanbe3Min; command.RestTimeJome3 = command.RestTimeJome3 == "0" ? "00" : command.RestTimeJome3; command.RestTimeJome3Min = command.RestTimeJome3Min == "0" ? "00" : command.RestTimeJome3Min; //week4 command.RestTimeShanbe4 = command.RestTimeShanbe4 == "0" ? "00" : command.RestTimeShanbe4; command.RestTimeShanbe4Min = command.RestTimeShanbe4Min == "0" ? "00" : command.RestTimeShanbe4Min; command.RestTimeYekShanbe4 = command.RestTimeYekShanbe4 == "0" ? "00" : command.RestTimeYekShanbe4; command.RestTimeYekShanbe4Min = command.RestTimeYekShanbe4Min == "0" ? "00" : command.RestTimeYekShanbe4Min; command.RestTimeDoShanbe4 = command.RestTimeDoShanbe4 == "0" ? "00" : command.RestTimeDoShanbe4; command.RestTimeDoShanbe4Min = command.RestTimeDoShanbe4Min == "0" ? "00" : command.RestTimeDoShanbe4Min; command.RestTimeSeShanbe4 = command.RestTimeSeShanbe4 == "0" ? "00" : command.RestTimeSeShanbe4; command.RestTimeSeShanbe4Min = command.RestTimeSeShanbe4Min == "0" ? "00" : command.RestTimeSeShanbe4Min; command.RestTimeCheharShanbe4 = command.RestTimeCheharShanbe4 == "0" ? "00" : command.RestTimeCheharShanbe4; command.RestTimeCheharShanbe4Min = command.RestTimeCheharShanbe4Min == "0" ? "00" : command.RestTimeCheharShanbe4Min; command.RestTimePanjShanbe4 = command.RestTimePanjShanbe4 == "0" ? "00" : command.RestTimePanjShanbe4; command.RestTimePanjShanbe4Min = command.RestTimePanjShanbe4Min == "0" ? "00" : command.RestTimePanjShanbe4Min; command.RestTimeJome4 = command.RestTimeJome4 == "0" ? "00" : command.RestTimeJome4; command.RestTimeJome4Min = command.RestTimeJome4Min == "0" ? "00" : command.RestTimeJome4Min; // sumrest week1 rest0w1 = TimeSpan.Parse($"{command.RestTimeShanbe1}:{command.RestTimeShanbe1Min}"); rest1w1 = TimeSpan.Parse($"{command.RestTimeYekShanbe1}:{command.RestTimeYekShanbe1Min}"); rest2w1 = TimeSpan.Parse($"{command.RestTimeDoShanbe1}:{command.RestTimeDoShanbe1Min}"); rest3w1 = TimeSpan.Parse($"{command.RestTimeSeShanbe1}:{command.RestTimeSeShanbe1Min}"); rest4w1 = TimeSpan.Parse($"{command.RestTimeCheharShanbe1}:{command.RestTimeCheharShanbe1Min}"); rest5w1 = TimeSpan.Parse($"{command.RestTimePanjShanbe1}:{command.RestTimePanjShanbe1Min}"); rest6w1 = TimeSpan.Parse($"{command.RestTimeJome1}:{command.RestTimeJome1Min}"); // sumrest week2 rest0w2 = TimeSpan.Parse($"{command.RestTimeShanbe2}:{command.RestTimeShanbe2Min}"); rest1w2 = TimeSpan.Parse($"{command.RestTimeYekShanbe2}:{command.RestTimeYekShanbe2Min}"); rest2w2 = TimeSpan.Parse($"{command.RestTimeDoShanbe2}:{command.RestTimeDoShanbe2Min}"); rest3w2 = TimeSpan.Parse($"{command.RestTimeSeShanbe2}:{command.RestTimeSeShanbe2Min}"); rest4w2 = TimeSpan.Parse($"{command.RestTimeCheharShanbe2}:{command.RestTimeCheharShanbe2Min}"); rest5w2 = TimeSpan.Parse($"{command.RestTimePanjShanbe2}:{command.RestTimePanjShanbe2Min}"); rest6w2 = TimeSpan.Parse($"{command.RestTimeJome2}:{command.RestTimeJome2Min}"); // sumrest week3 rest0w3 = TimeSpan.Parse($"{command.RestTimeShanbe3}:{command.RestTimeShanbe3Min}"); rest1w3 = TimeSpan.Parse($"{command.RestTimeYekShanbe3}:{command.RestTimeYekShanbe3Min}"); rest2w3 = TimeSpan.Parse($"{command.RestTimeDoShanbe3}:{command.RestTimeDoShanbe3Min}"); rest3w3 = TimeSpan.Parse($"{command.RestTimeSeShanbe3}:{command.RestTimeSeShanbe3Min}"); rest4w3 = TimeSpan.Parse($"{command.RestTimeCheharShanbe3}:{command.RestTimeCheharShanbe3Min}"); rest5w3 = TimeSpan.Parse($"{command.RestTimePanjShanbe3}:{command.RestTimePanjShanbe3Min}"); rest6w3 = TimeSpan.Parse($"{command.RestTimeJome3}:{command.RestTimeJome3Min}"); // sumrest week4 rest0w4 = TimeSpan.Parse($"{command.RestTimeShanbe4}:{command.RestTimeShanbe4Min}"); rest1w4 = TimeSpan.Parse($"{command.RestTimeYekShanbe4}:{command.RestTimeYekShanbe4Min}"); rest2w4 = TimeSpan.Parse($"{command.RestTimeDoShanbe4}:{command.RestTimeDoShanbe4Min}"); rest3w4 = TimeSpan.Parse($"{command.RestTimeSeShanbe4}:{command.RestTimeSeShanbe4Min}"); rest4w4 = TimeSpan.Parse($"{command.RestTimeCheharShanbe4}:{command.RestTimeCheharShanbe4Min}"); rest5w4 = TimeSpan.Parse($"{command.RestTimePanjShanbe4}:{command.RestTimePanjShanbe4Min}"); rest6w4 = TimeSpan.Parse($"{command.RestTimeJome4}:{command.RestTimeJome4Min}"); } #endregion #region Complex //[12-24 : 5] [24-24 : 6] [12-36 : 7] [24-48 : 8] if (command.ShiftWork is "5" or "6" or "7" or "8") { int addHours = command.ShiftWork switch { "5" => 36, "6" => 48, "7" => 48, "8" => 72, _ => 0 }; var start = Convert.ToDateTime(command.StartComplex); var end = Convert.ToDateTime(command.EndComplex); var startDateAndTime = new PersianDateTime(syear, smonth, sday, start.Hour, start.Minute); var startContract = new PersianDateTime(syear, smonth, sday, start.Hour, start.Minute); var endContract = new PersianDateTime(eyear, emonth, eday, 23, 59); var countLeves = leaveSearchResult.Where(x => x.PaidLeaveType == "روزانه").ToList(); //int totalLeaveDays = countLeves.Sum(x => int.Parse(x.LeaveHourses)); List affectedLeaves = new List(); DateTime contractStart = ($"{startContract}").ToGeorgianDateTime(); DateTime contractEnd = ($"{endContract}").ToGeorgianDateTime(); int leavingDayCout = 0; List thisCheckoutLeaves = new List(); if (leaveSearchResult.Count > 0) { foreach (var leave in leaveSearchResult) { //مرخصی های مابین if (leave.StartLeaveGr >= contractStart && leave.EndLeaveGr <= contractEnd) { var modifyleave = new LeaveViewModel() { Id = leave.Id, StartLeaveGr = leave.StartLeaveGr, EndLeaveGr = leave.EndLeaveGr }; thisCheckoutLeaves.Add(leave); } // مرخصی که شروعش قبل از شروع تصفیه حساب است if (leave.StartLeaveGr < contractStart && leave.EndLeaveGr <= contractEnd) { var modifyleave = new LeaveViewModel() { Id = leave.Id, StartLeaveGr = contractStart, EndLeaveGr = leave.EndLeaveGr }; thisCheckoutLeaves.Add(modifyleave); } // مرخصی که پایانش بعد از پایان تصفیه حساب است if (leave.EndLeaveGr > contractEnd && leave.StartLeaveGr >= contractStart) { var modifyleave = new LeaveViewModel() { Id = leave.Id, StartLeaveGr = leave.StartLeaveGr, EndLeaveGr = contractEnd, }; thisCheckoutLeaves.Add(modifyleave); } //مرخصی استثنا که تمام بازه فیش را پوشش میدهد if (leave.StartLeaveGr < contractStart && leave.EndLeaveGr > contractEnd) { var modifyleave = new LeaveViewModel() { Id = leave.Id, StartLeaveGr = leave.StartLeaveGr, EndLeaveGr = contractEnd, }; thisCheckoutLeaves.Add(modifyleave); } } } for (var da = startDateAndTime; da <= endContract; da = da.AddHours(addHours)) { var currentDateFa = $"{da}"; var currentDateGr = da.ToGregorianDateTime(); if (da == startContract) { start = new DateTime(currentDateGr.Year, currentDateGr.Month, currentDateGr.Day, start.Hour, start.Minute, 0); end = new DateTime(currentDateGr.Year, currentDateGr.Month, currentDateGr.Day, end.Hour, end.Minute, 0); if (start.Date == end.Date && start.TimeOfDay > end.TimeOfDay) end = end.AddDays(1); if ((command.ShiftWork is "6" or "8") && start == end) end = end.AddDays(1); } var startComplex = new DateTime(start.Year, start.Month, start.Day, start.Hour, start.Minute, start.Second); var endComplex = new DateTime(end.Year, end.Month, end.Day, end.Hour, end.Minute, end.Second); Console.WriteLine( $"{currentDateFa} - {currentDateGr.Date} - start : {startComplex} end : {endComplex}"); var hasLeave = thisCheckoutLeaves.Any(x => startComplex.Date <= x.EndLeaveGr.Date && endComplex.Date >= x.StartLeaveGr.Date); if (!hasLeave) { rollCallList.Add(new RollCallViewModel() { StartDate = startComplex, EndDate = endComplex, ShiftSpan = (endComplex - startComplex), ShiftDate = currentDateGr, ShiftEndWithoutRest = endComplex }); } else { var affected = thisCheckoutLeaves.FirstOrDefault(x => startComplex.Date <= x.EndLeaveGr.Date && endComplex.Date >= x.StartLeaveGr.Date); var modifyleave = new LeaveViewModel() { Id = affected.Id, StartLeaveGr = affected.StartLeaveGr, EndLeaveGr = affected.EndLeaveGr }; affectedLeaves.Add(modifyleave); } var endCal = end - start; start = startComplex.AddHours(addHours); end = start.Add(endCal); } affectedLeaves = affectedLeaves.DistinctBy(x => x.Id).ToList(); //مرخصی هایی که تاریخ آن ها بین رکورد های حضور پرسنل بوده و اعمال نشده var exceptionLeaves = thisCheckoutLeaves .Where(t => !affectedLeaves.Select(a => a.Id).Contains(t.Id)) .ToList(); //حذف رکورد های حضور به تعداد مرخصی های اعمال نشده if (exceptionLeaves.Count > 0) { int countRollCall = rollCallList.Count(); int takRollCall = exceptionLeaves.Count < countRollCall ? (countRollCall - exceptionLeaves.Count) : 0; rollCallList = rollCallList.Take(takRollCall).ToList(); } } #endregion #region ShiftWork4Compute if (command.ShiftWork == "4") { //DateTime currentDay = ($"{da}").ToGeorgianDateTime(); var hasSickLeave = false; for (var da = d1; da <= d2; da.AddDays(1)) { var FirstDayOfMonth = new PersianDateTime(da.Year, da.Month, 1); var w1 = 0; var w2 = 0; var w3 = 0; var w4 = 0; var w5 = 0; var w6 = 0; var currentDateFa = $"{da}"; DateTime currntDateGr = currentDateFa.ToGeorgianDateTime(); if (!workshopHolidyWorking) { isHoliday = holidayList.Any(x => x == currentDateFa); } switch (FirstDayOfMonth.DayOfWeek) { case "شنبه": w1 = 7; w2 = 14; w3 = 21; w4 = 28; w5 = 31; break; case "یکشنبه": w1 = 6; w2 = 13; w3 = 20; w4 = 27; w5 = 31; break; case "دوشنبه": w1 = 5; w2 = 12; w3 = 19; w4 = 26; w5 = 31; break; case "سه شنبه": w1 = 4; w2 = 11; w3 = 18; w4 = 25; w5 = 31; break; case "چهارشنبه": w1 = 3; w2 = 10; w3 = 17; w4 = 24; w5 = 31; break; case "پنج شنبه": w1 = 2; w2 = 9; w3 = 16; w4 = 23; w5 = 30; w6 = 31; break; case "جمعه": w1 = 1; w2 = 8; w3 = 15; w4 = 22; w5 = 29; w6 = 31; break; } switch (da.DayOfWeek) { case "شنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.Shanbe1 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1Shanbe1, command.SingleShift2Shanbe1, command.TowShifts1Shanbe1, command.TowShifts2Shanbe1, currntDateGr, rest0w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.Shanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1Shanbe2, command.SingleShift2Shanbe2, command.TowShifts1Shanbe2, command.TowShifts2Shanbe2, currntDateGr, rest0w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.Shanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1Shanbe3, command.SingleShift2Shanbe3, command.TowShifts1Shanbe3, command.TowShifts2Shanbe3, currntDateGr, rest0w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.Shanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1Shanbe4, command.SingleShift2Shanbe4, command.TowShifts1Shanbe4, command.TowShifts2Shanbe4, currntDateGr, rest0w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "یکشنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.YekShanbe1 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1YekShanbe1, command.SingleShift2YekShanbe1, command.TowShifts1YekShanbe1, command.TowShifts2YekShanbe1, currntDateGr, rest1w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.YekShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1YekShanbe2, command.SingleShift2YekShanbe2, command.TowShifts1YekShanbe2, command.TowShifts2YekShanbe2, currntDateGr, rest1w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.YekShanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1YekShanbe3, command.SingleShift2YekShanbe3, command.TowShifts1YekShanbe3, command.TowShifts2YekShanbe3, currntDateGr, rest1w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.YekShanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1YekShanbe4, command.SingleShift2YekShanbe4, command.TowShifts1YekShanbe4, command.TowShifts2YekShanbe4, currntDateGr, rest1w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "دوشنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.DoShanbe1 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1DoShanbe1, command.SingleShift2DoShanbe1, command.TowShifts1DoShanbe1, command.TowShifts2DoShanbe1, currntDateGr, rest2w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.DoShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1DoShanbe2, command.SingleShift2DoShanbe2, command.TowShifts1DoShanbe2, command.TowShifts2DoShanbe2, currntDateGr, rest2w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.DoShanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1DoShanbe3, command.SingleShift2DoShanbe3, command.TowShifts1DoShanbe3, command.TowShifts2DoShanbe3, currntDateGr, rest2w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.DoShanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1DoShanbe4, command.SingleShift2DoShanbe4, command.TowShifts1DoShanbe4, command.TowShifts2DoShanbe4, currntDateGr, rest2w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "سه شنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.SeShanbe1 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1SeShanbe1, command.SingleShift2SeShanbe1, command.TowShifts1SeShanbe1, command.TowShifts2SeShanbe1, currntDateGr, rest3w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.SeShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1SeShanbe2, command.SingleShift2SeShanbe2, command.TowShifts1SeShanbe2, command.TowShifts2SeShanbe2, currntDateGr, rest3w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.SeShanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1SeShanbe3, command.SingleShift2SeShanbe3, command.TowShifts1SeShanbe3, command.TowShifts2SeShanbe3, currntDateGr, rest3w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.SeShanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1SeShanbe4, command.SingleShift2SeShanbe4, command.TowShifts1SeShanbe4, command.TowShifts2SeShanbe4, currntDateGr, rest3w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "چهارشنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.CheharShanbe1 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1CheharShanbe1, command.SingleShift2CheharShanbe1, command.TowShifts1CheharShanbe1, command.TowShifts2CheharShanbe1, currntDateGr, rest4w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.CheharShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1CheharShanbe2, command.SingleShift2CheharShanbe2, command.TowShifts1CheharShanbe2, command.TowShifts2CheharShanbe2, currntDateGr, rest4w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.CheharShanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1CheharShanbe3, command.SingleShift2CheharShanbe3, command.TowShifts1CheharShanbe3, command.TowShifts2CheharShanbe3, currntDateGr, rest4w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.CheharShanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1CheharShanbe4, command.SingleShift2CheharShanbe4, command.TowShifts1CheharShanbe4, command.TowShifts2CheharShanbe4, currntDateGr, rest4w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "پنج شنبه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.PanjShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1PanjShanbe1, command.SingleShift2PanjShanbe1, command.TowShifts1PanjShanbe1, command.TowShifts2PanjShanbe1, currntDateGr, rest5w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.PanjShanbe2 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1PanjShanbe2, command.SingleShift2PanjShanbe2, command.TowShifts1PanjShanbe2, command.TowShifts2PanjShanbe2, currntDateGr, rest5w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.PanjShanbe3 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1PanjShanbe3, command.SingleShift2PanjShanbe3, command.TowShifts1PanjShanbe3, command.TowShifts2PanjShanbe3, currntDateGr, rest5w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.PanjShanbe4 && isHoliday == false) { var res = FindStaticShiftsStatus( command.SingleShift1PanjShanbe4, command.SingleShift2PanjShanbe4, command.TowShifts1PanjShanbe4, command.TowShifts2PanjShanbe4, currntDateGr, rest5w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; case "جمعه": if (((da.Day <= w1) || (da.Day > w4 && da.Day <= w5)) && command.Jome1) { var res = FindStaticShiftsStatus( command.SingleShift1Jome1, command.SingleShift2Jome1, command.TowShifts1Jome1, command.TowShifts2Jome1, currntDateGr, rest6w1, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (((da.Day > w1 && da.Day <= w2) || (da.Day > w5 && da.Day <= w6)) && command.Jome2) { var res = FindStaticShiftsStatus( command.SingleShift1Jome2, command.SingleShift2Jome2, command.TowShifts1Jome2, command.TowShifts2Jome2, currntDateGr, rest6w2, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w2 && da.Day <= w3 && command.Jome3) { var res = FindStaticShiftsStatus( command.SingleShift1Jome3, command.SingleShift2Jome3, command.TowShifts1Jome3, command.TowShifts2Jome3, currntDateGr, rest6w3, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } else if (da.Day > w3 && da.Day <= w4 && command.Jome4) { var res = FindStaticShiftsStatus( command.SingleShift1Jome4, command.SingleShift2Jome4, command.TowShifts1Jome4, command.TowShifts2Jome4, currntDateGr, rest6w4, leaveSearchResult); if (res.Count > 0) rollCallList.AddRange(res); } break; } } } #endregion return rollCallList; } /// /// جاگذاری شیفت های استاتیک در بازه تاریخ /// /// private List FindStaticShiftsStatus(string shift1Start, string shift1End, string shift2Start, string shift2End, DateTime cuurentDate, TimeSpan restTime, List leaveSearchResult) { var result = new List(); var shift1StartGr = new DateTime(); var shift1EndGr = new DateTime(); var shift2StartGr = new DateTime(); var shift2EndGr = new DateTime(); if (leaveSearchResult.Count > 0) { leaveSearchResult = leaveSearchResult.Select(x => new LeaveViewModel() { LeaveHourses = x.LeaveHourses, LeaveType = x.LeaveType, PaidLeaveType = x.PaidLeaveType, StartLeaveGr = x.StartLeaveGr, EndLeaveGr = x.PaidLeaveType == "روزانه" ? new DateTime(x.EndLeaveGr.Year, x.EndLeaveGr.Month, x.EndLeaveGr.Day, 23, 59, 59) : x.EndLeaveGr, }).ToList(); } #region Shift1 if (!string.IsNullOrWhiteSpace(shift1Start) && !string.IsNullOrWhiteSpace(shift1End)) { try { var starTimeSingel1 = Convert.ToDateTime(shift1Start); var endTimeSingel2 = Convert.ToDateTime(shift1End); bool hasRestTime = false; shift1StartGr = new DateTime(cuurentDate.Year, cuurentDate.Month, cuurentDate.Day, starTimeSingel1.Hour, starTimeSingel1.Minute, 0); shift1EndGr = new DateTime(cuurentDate.Year, cuurentDate.Month, cuurentDate.Day, endTimeSingel2.Hour, endTimeSingel2.Minute, 0); if (shift1EndGr.TimeOfDay < shift1StartGr.TimeOfDay) shift1EndGr = shift1EndGr.AddDays(1); var shiftEndWithoutRest = shift1EndGr; var shiftSpan = (shift1EndGr - shift1StartGr); if (restTime > TimeSpan.Zero && shiftSpan >= restTime) { hasRestTime = true; shift1EndGr = shift1EndGr.Subtract(restTime); shiftSpan = (shift1EndGr - shift1StartGr); } if (!leaveSearchResult.Any(x => x.StartLeaveGr < shift1EndGr && x.EndLeaveGr > shift1StartGr && x.PaidLeaveType == "روزانه")) { var hourseLeaveTypeResult = leaveSearchResult.FirstOrDefault(x => x.StartLeaveGr < shift1EndGr && x.EndLeaveGr > shift1StartGr && x.PaidLeaveType == "ساعتی"); if (hourseLeaveTypeResult == null) { result.Add(new RollCallViewModel() { BreakTimeSpan = hasRestTime ? restTime : TimeSpan.Zero, StartDate = shift1StartGr, EndDate = shift1EndGr, ShiftSpan = shiftSpan, ShiftDate = shift1StartGr, ShiftEndWithoutRest = shiftEndWithoutRest }); } else { if (hourseLeaveTypeResult.StartLeaveGr <= shift1StartGr && hourseLeaveTypeResult.EndLeaveGr < shift1EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { BreakTimeSpan = hasRestTime ? restTime : TimeSpan.Zero, StartDate = hourseLeaveTypeResult.EndLeaveGr, EndDate = shift1EndGr, ShiftSpan = (shift1EndGr - hourseLeaveTypeResult.EndLeaveGr), ShiftDate = shift1StartGr, ShiftEndWithoutRest = shiftEndWithoutRest }); } else if (hourseLeaveTypeResult.StartLeaveGr > shift1StartGr && hourseLeaveTypeResult.EndLeaveGr < shift1EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { BreakTimeSpan = hasRestTime ? restTime : TimeSpan.Zero, StartDate = shift1StartGr, EndDate = hourseLeaveTypeResult.StartLeaveGr, ShiftSpan = (hourseLeaveTypeResult.StartLeaveGr - shift1StartGr), ShiftDate = shift1StartGr, ShiftEndWithoutRest = hourseLeaveTypeResult.StartLeaveGr }); result.Add(new RollCallViewModel() { BreakTimeSpan = hasRestTime ? restTime : TimeSpan.Zero, StartDate = hourseLeaveTypeResult.EndLeaveGr, EndDate = shift1EndGr, ShiftSpan = (shift1EndGr - hourseLeaveTypeResult.EndLeaveGr), ShiftDate = shift1StartGr, ShiftEndWithoutRest = shiftEndWithoutRest }); } else if (hourseLeaveTypeResult.StartLeaveGr > shift1StartGr && hourseLeaveTypeResult.EndLeaveGr >= shift1EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { BreakTimeSpan = hasRestTime ? restTime : TimeSpan.Zero, StartDate = shift1StartGr, EndDate = hourseLeaveTypeResult.StartLeaveGr, ShiftSpan = (hourseLeaveTypeResult.StartLeaveGr - shift1StartGr), ShiftDate = shift1StartGr, ShiftEndWithoutRest = hourseLeaveTypeResult.StartLeaveGr }); } } } } catch (Exception e) { // ignored } } #endregion #region Shift2 if (!string.IsNullOrWhiteSpace(shift2Start) && !string.IsNullOrWhiteSpace(shift2End)) { try { var startTimeTowSh1 = Convert.ToDateTime(shift2Start); var endTimeTowSh2 = Convert.ToDateTime(shift2End); //اگر شیفت 1 وجود داشت تاریخ جاری را از شیف 1 میگیریم //زیرا ممکن پایان شیف 1 در روز بعد باشد var shift1 = result.MaxBy(x => x.EndDate); if (shift1 != null) if (shift1.EndDate != null) cuurentDate = shift1.EndDate.Value; shift2StartGr = new DateTime(cuurentDate.Year, cuurentDate.Month, cuurentDate.Day, startTimeTowSh1.Hour, startTimeTowSh1.Minute, 0); shift2EndGr = new DateTime(cuurentDate.Year, cuurentDate.Month, cuurentDate.Day, endTimeTowSh2.Hour, endTimeTowSh2.Minute, 0); if (shift2EndGr.TimeOfDay < shift2StartGr.TimeOfDay) shift2EndGr = shift2EndGr.AddDays(1); if (!leaveSearchResult.Any(x => x.StartLeaveGr < shift2EndGr && x.EndLeaveGr > shift2StartGr && x.PaidLeaveType == "روزانه")) { var hourseLeaveTypeResult = leaveSearchResult.FirstOrDefault(x => x.StartLeaveGr < shift2EndGr && x.EndLeaveGr > shift2StartGr && x.PaidLeaveType == "ساعتی"); if (hourseLeaveTypeResult == null) { result.Add(new RollCallViewModel() { StartDate = shift2StartGr, EndDate = shift2EndGr, ShiftSpan = (shift2EndGr - shift2StartGr), ShiftDate = shift1?.ShiftDate ?? shift2EndGr, ShiftEndWithoutRest = shift2EndGr, }); } else { if (hourseLeaveTypeResult.StartLeaveGr <= shift2StartGr && hourseLeaveTypeResult.EndLeaveGr < shift2EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { StartDate = hourseLeaveTypeResult.EndLeaveGr, EndDate = shift2EndGr, ShiftSpan = (shift2EndGr - hourseLeaveTypeResult.EndLeaveGr), ShiftDate = shift1?.EndDate ?? shift2EndGr, ShiftEndWithoutRest = shift2EndGr, }); } else if (hourseLeaveTypeResult.StartLeaveGr > shift2StartGr && hourseLeaveTypeResult.EndLeaveGr < shift2EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { StartDate = shift2StartGr, EndDate = hourseLeaveTypeResult.StartLeaveGr, ShiftSpan = (hourseLeaveTypeResult.StartLeaveGr - shift2StartGr), ShiftDate = shift1?.EndDate ?? shift2EndGr, ShiftEndWithoutRest = hourseLeaveTypeResult.StartLeaveGr, }); result.Add(new RollCallViewModel() { StartDate = hourseLeaveTypeResult.EndLeaveGr, EndDate = shift2EndGr, ShiftSpan = (shift2EndGr - hourseLeaveTypeResult.EndLeaveGr), ShiftDate = shift1?.EndDate ?? shift2EndGr, ShiftEndWithoutRest = shift2EndGr, }); } else if (hourseLeaveTypeResult.StartLeaveGr > shift2StartGr && hourseLeaveTypeResult.EndLeaveGr >= shift2EndGr) { //leave <--------------------> //shift <----------------------------------> result.Add(new RollCallViewModel() { StartDate = shift2StartGr, EndDate = hourseLeaveTypeResult.StartLeaveGr, ShiftSpan = (hourseLeaveTypeResult.StartLeaveGr - shift2StartGr), ShiftDate = shift1?.EndDate ?? shift2EndGr, ShiftEndWithoutRest = hourseLeaveTypeResult.StartLeaveGr, }); } } } } catch (Exception e) { // ignored } } #endregion return result; } #endregion #region CustomizeCheckout /// /// متد محاسبه فیش حقوقی دلخواه /// /// /// /// /// /// public CustomizeCheckoutMandatoryViewModel CustomizeCheckoutMandatoryCompute(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { var checkoutEnd = contractEnd; var checkoutStart = contractStart; if (workshopId == 170) return CustomizeCheckoutMandatoryComputeForKebabMahdi(employeeId, workshopId, contractStart, contractEnd); if (workshopId is 367 or 368) return CustomizeCheckoutMandatoryComputeForPizzaAmir(employeeId, workshopId, contractStart, contractEnd); var firstDayOfMonth = $"{(contractStart.ToFarsi())[..8]}/01".ToGeorgianDateTime(); #region LeftWork var leftWork = _leftWorkRepository.GetByWorkshopIdEmployeeIdInDates(workshopId, employeeId, contractStart, contractEnd); if (leftWork.StartWorkDateGr > contractStart) { contractStart = leftWork.StartWorkDateGr; } if (leftWork.LeftWorkDateGr.AddDays(-1) < contractEnd) { contractEnd = leftWork.LeftWorkDateGr.AddDays(-1); } TimeSpan leftWorkDurationTimeSpan = leftWork.HasLeft ? leftWork.LeftWorkDateGr.AddDays(-1) - leftWork.StartWorkDateGr : contractEnd - leftWork.StartWorkDateGr; #endregion #region Entities int numberOfFridays = 0; double monthySalary = 0; int monthDays = 0; double dailyWage = 0; int numberOfWorkingDay = 0; string endPersianDate = contractEnd.ToFarsi(); int monthOfCheckout = Convert.ToInt32(endPersianDate.Substring(5, 2)); int yearOfCheckout = Convert.ToInt32(endPersianDate.Substring(0, 4)); //روز هایی که پرسنل موظف بوده کار کند var mandatoryDays = 0; TimeSpan contractDuration = contractEnd - contractStart; var employee = _context.Employees.FirstOrDefault(x => x.id == employeeId); var personnelCode = _context.PersonnelCodeSet.FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId) ?.PersonnelCode ?? 0; var contract = _context.Contracts.Where(x => x.WorkshopIds == workshopId && x.EmployeeId == employeeId && x.ContractEnd.Date >= contractStart.Date && x.ContarctStart.Date <= contractEnd.Date).ToList() ?.MaxBy(x => x.ContarctStart); var totalDays = (int)(contractEnd - contractStart).TotalDays + 1; mandatoryDays = totalDays; #endregion #region CustomizeSettings CustomizeWorkshopEmployeeSettings customizeWorkshopEmployeeSettings = _context.CustomizeWorkshopEmployeeSettings .AsSplitQuery().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); CustomizeWorkshopSettings customizeWorkshopSettings = _context.CustomizeWorkshopSettings.FirstOrDefault(x => x.WorkshopId == workshopId); //ToDo handel exception if is null monthySalary = customizeWorkshopEmployeeSettings?.Salary ?? 0; monthDays = customizeWorkshopSettings.MaxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth ? 30 : firstDayOfMonth.CountMonthDays(); var shiftSettings = customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts; var employeeShiftsSpans = shiftSettings.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 EmployeeShiftResult { Placement = x.Placement, ShiftSpan = span }; }); var sumOfEmployeeShiftSpan = new TimeSpan(employeeShiftsSpans.Sum(x => x.ShiftSpan.Ticks)); if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Irregular) { sumOfEmployeeShiftSpan = CalculateIrregularShift(customizeWorkshopEmployeeSettings.IrregularShift); } if (customizeWorkshopEmployeeSettings.BreakTime.BreakTimeType == BreakTimeType.WithTime) { sumOfEmployeeShiftSpan -= customizeWorkshopEmployeeSettings.BreakTime.BreakTimeValue.ToTimeSpan(); } #endregion List rollCallResult = _context.RollCalls.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.StartDate.Value.Date >= contractStart.Date && x.StartDate.Value.Date <= contractEnd.Date && x.EndDate != null) .Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.CreationDate, BreakTimeSpan = x.BreakTimeSpan }).ToList(); List groupedRollCall = rollCallResult.GroupBy(x => x.StartDate!.Value.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value }) .ToList(), HasFriday = x.Any(s => s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value.DayOfWeek == DayOfWeek.Friday), SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) - CalculateBreakTime( x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), BreakTime = CalculateBreakTime(x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))) }).ToList(); TimeSpan sumSpans = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); numberOfFridays = groupedRollCall.Count(x => x.HasFriday); numberOfWorkingDay = groupedRollCall.Count(); //تعداد روز های قرارداد int contractDays = (int)contractDuration.TotalDays + 1; //روز های غیبت int fridays = 0; int holiday = _context.HolidayItems.Count(x => x.Holidaydate >= contractStart && x.Holidaydate <= contractEnd); for (var gDate = contractStart; gDate <= contractEnd; gDate = gDate.AddDays(1)) { if (gDate.DayOfWeek == DayOfWeek.Friday) { fridays += 1; } } if (customizeWorkshopEmployeeSettings.FridayWork == FridayWork.Default) { var fridayWorkingTotalDays = CalculateFridayWorkingTotalDays(rollCallResult); fridays = fridays - fridayWorkingTotalDays; mandatoryDays -= fridays; } if (customizeWorkshopEmployeeSettings.HolidayWork == HolidayWork.Default) { var groupStartDaysDates = groupedRollCall.Select(x => x.CreationDate.Date).ToList(); var holidayWorkingDays = _context.HolidayItems.Count(x => groupStartDaysDates.Any(r => r == x.Holidaydate.Date)); holiday = holiday - holidayWorkingDays; mandatoryDays -= holiday; } TimeSpan absentTimeSpans = new(); if ((mandatoryDays * sumOfEmployeeShiftSpan) > sumSpans) { absentTimeSpans = (mandatoryDays * sumOfEmployeeShiftSpan) - sumSpans; } dailyWage = monthySalary / monthDays; var minuteWage = sumOfEmployeeShiftSpan.TotalMinutes == 0 ? 0 : (dailyWage / sumOfEmployeeShiftSpan.TotalMinutes); // یافتن مرخصی ساعتی #region LeavHourse LeaveSearchModel leaveHourseSearch = new LeaveSearchModel() { EmployeeId = employeeId, WorkshopId = workshopId, LeaveType = "استحقاقی", StartLeaveGr = contractStart, EndLeaveGr = contractEnd, IsAccepted = true, }; List leaveList = _leaveRepository.search(leaveHourseSearch); #endregion //****افزودن مرخصی پرسنل به مجموع ساعات کار*** #region AddEmployeeLeaves //TimeSpan workingPerDayAve = sumSpans / numberOfWorkingDay;//میانگین ساعت کار در روز //if (workingPerDayAve <= new TimeSpan(7, 20, 0)) //{ // sumLeave = leavingDayCout * workingPerDayAve; //} //else //{ // sumLeave = leavingDayCout * new TimeSpan(7, 20, 0); //} double leavePayAmount = 0; double absentsDeductionAmount = 0; if (customizeWorkshopEmployeeSettings.LeavePay.LeavePayType != LeavePayType.None) { int permittedDays = customizeWorkshopEmployeeSettings.LeavePermittedDays; double leaveValue = customizeWorkshopEmployeeSettings.LeavePay.Value; sumSpans = CalculateLeavePay(sumOfEmployeeShiftSpan, absentTimeSpans, permittedDays, monthDays, contractDays, sumSpans , leaveValue, minuteWage, contractStart, contractEnd, out leavePayAmount, out absentsDeductionAmount); } else { absentsDeductionAmount = absentTimeSpans.TotalMinutes * minuteWage; } Console.WriteLine(sumSpans); #endregion //***********************************// //ToTal Hours Employee Worked double totalHours = (sumSpans.TotalMinutes) / 60; int totalHolidaysAndNotH = (int)sumSpans.TotalHours; int totalHolidaysAndNotM = (int)(sumSpans.TotalMinutes % 60); //***********************************// #region Deductions //غیبت //تاخیر و تعجیل //حق بیمه #region InsurancePay InsuranceDeduction insuranceDeduction = customizeWorkshopEmployeeSettings.InsuranceDeduction; //farokhiChange double insuranceDeductionAmount = InsurancePayCalculation(employeeId, contractStart, contractEnd, insuranceDeduction, monthySalary); #endregion #region SalaryAidDeduction var salaryAidViewModel = SalaryAidsForCheckout(employeeId, workshopId, checkoutStart, checkoutEnd); double salaryAidDeduction = salaryAidViewModel.Sum(x => x.AmountDouble); #endregion #region Loan var loanInstallments = LoanInstallmentForCheckout(employeeId, workshopId, contractStart, contractEnd); double loanDeduction = loanInstallments.Sum(x => x.AmountDouble); #endregion #region Fine var fineViewModels = FinesForCheckout(employeeId, workshopId, contractStart, contractEnd); double fineDeduction = fineViewModels.Sum(x => x.Amount.MoneyToDouble()); #endregion #endregion #region Payments //اضافه کاری #region OvertimePay double overtimePayAmount = 0; TimeSpan overtimeTimeSpan; if (customizeWorkshopSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular && customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { TimeOnly employeeOffSet = customizeWorkshopSettings.EndTimeOffSet; overtimeTimeSpan = CalculateOvertimeTimeSpan(rollCallResult, shiftSettings, employeeOffSet); } else if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { var date = new DateOnly(); var firstStartShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MinBy(x => x.Placement) .StartTime); var lastEndShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MaxBy(x => x.Placement) .EndTime); if (lastEndShift > firstStartShift) firstStartShift = firstStartShift.AddDays(1); var offSet = (firstStartShift - lastEndShift).Divide(2); var employeeOffSet = TimeOnly.FromDateTime(lastEndShift.Add(offSet)); overtimeTimeSpan = CalculateOvertimeTimeSpan(rollCallResult, shiftSettings, employeeOffSet); } else { var irregularShifts = customizeWorkshopEmployeeSettings.IrregularShift.WorkshopIrregularShifts; overtimeTimeSpan = CalculateIrregularOverTime(rollCallResult, sumOfEmployeeShiftSpan, irregularShifts, mandatoryDays); //Todo: fix for irregular and rotating shifts } overtimePayAmount = CalculateOvertimePay(overtimeTimeSpan, customizeWorkshopEmployeeSettings.OverTimePay, dailyWage); if (overtimePayAmount >= absentsDeductionAmount) { overtimePayAmount = overtimePayAmount - absentsDeductionAmount; absentsDeductionAmount = 0; } else { absentsDeductionAmount = absentsDeductionAmount - overtimePayAmount; overtimePayAmount = 0; } #endregion #region FridayPay double fridayPayAmount = 0; fridayPayAmount = FridayPayCalculation(customizeWorkshopEmployeeSettings, rollCallResult, dailyWage, shiftSettings, overtimePayAmount); #endregion //حق تاهل #region MaritalAllownace double maritalAllowancePay = 0; if (employee.MaritalStatus == "متاهل") { switch (customizeWorkshopEmployeeSettings.MarriedAllowance.MarriedAllowanceType) { case MarriedAllowanceType.Money: { maritalAllowancePay = customizeWorkshopEmployeeSettings.MarriedAllowance.Value; break; } //case MarriedAllowanceType.PercentageFromSalary: // { // double multiplier = customizeWorkshopEmployeeSettings.MarriedAllowance.Value / 100; // maritalAllowance = dailyWage * multiplier; // break; // } } } #endregion //شب کاری #region NightWorkPay double nightworkPayAmount = 0; List rotatingResultList = RotatingShiftCheck(groupedRollCall); // شبکاری TimeSpan nightWorks = new TimeSpan(rotatingResultList.Sum(x => x.NightWorkSpan.Ticks)); if (nightWorks > new TimeSpan()) { switch (customizeWorkshopEmployeeSettings.NightWorkPay.NightWorkingType) { case NightWorkType.MoneyPerHour: { var baseAmount = customizeWorkshopEmployeeSettings.NightWorkPay.Value; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += nightWorkMinutes * (baseAmount / 60); break; } case NightWorkType.PercentageFromSalary: { double multiplier = customizeWorkshopEmployeeSettings.NightWorkPay.Value / 100; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += ((dailyWage * multiplier) / 60) * nightWorkMinutes; break; } } } #endregion //سنوات #region BaseYearsPay double baseYearsPayAmount = CalculateYearsPayAmount(employeeId, workshopId, monthySalary, contractStart, contractEnd , customizeWorkshopEmployeeSettings.BaseYearsPay, customizeWorkshopSettings.BaseYearsPayInEndOfYear, customizeWorkshopSettings.MaxMonthDays); #endregion //حق اولاد #region FamilyAllowancePay double familyAllowancePay = 0; switch (customizeWorkshopEmployeeSettings.FamilyAllowance.FamilyAllowanceType) { case FamilyAllowanceType.Money: { double baseAmount = customizeWorkshopEmployeeSettings.FamilyAllowance.Value; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, baseAmount, contractEnd); break; } case FamilyAllowanceType.Percentage: { double multiplier = customizeWorkshopEmployeeSettings.FamilyAllowance.Value / 100; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, multiplier * monthySalary, contractEnd); break; } } #endregion #region Reward var rewardViewModels = RewardForCheckout(employeeId, workshopId, checkoutEnd, checkoutStart); double rewardPay = rewardViewModels.Sum(x => x.AmountDouble); #endregion #region LeavePay #endregion #region BonusesPay double bonusesPayAmount = 0; if (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType != BonusesType.None) { switch (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType) { case BonusesType.OneTimeOfSalary: bonusesPayAmount = monthySalary; break; case BonusesType.TwoTimeOfSalary: bonusesPayAmount = monthySalary * 2; break; case BonusesType.Money: bonusesPayAmount = customizeWorkshopEmployeeSettings.BonusesPay.Value; break; case BonusesType.PercentageOfSalary: bonusesPayAmount = (monthySalary * customizeWorkshopEmployeeSettings.BonusesPay.Value) / 100; break; } double bonusesPerMonth = bonusesPayAmount / 12; if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.YearlyPay) { var contractEndFarsi = Tools.FindeEndOfMonth(contractEnd.ToFarsi()); if (monthOfCheckout == 12 && (contractEndFarsi.EndsWith("29")) || contractEndFarsi.EndsWith("30")) { } else if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft) { TimeSpan bonusDuration; DateTime startOfYear = new PersianCalendar().ToDateTime(yearOfCheckout, 1, 1, 0, 0, 0, 0); if (startOfYear < leftWork.StartWorkDateGr) bonusDuration = leftWorkDurationTimeSpan; else bonusDuration = leftWork.LeftWorkDateGr - startOfYear; //ToDo: Check if should be absolute 365! bonusesPayAmount = (bonusesPayAmount / 365) * bonusDuration.TotalDays; } else { bonusesPayAmount = 0; } } else if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.MonthlyPay) { if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft && contractDays < monthDays) bonusesPayAmount = (bonusesPerMonth / contractEnd.CountPersianMonthDays()) * contractDuration.TotalDays + 1; bonusesPayAmount = bonusesPerMonth; } else { throw new InvalidDataException(); } } #endregion #endregion #region LateToWork & EarlyExit var lateToWorkEarlyExit = LateToWorkEarlyExit(groupedRollCall, shiftSettings, leaveList); foreach (var i in lateToWorkEarlyExit) { Console.WriteLine(" start : " + i.StartSpan + " end : " + i.EndSpan + " spaning : " + i.Spanning + " Type : " + i.TypeOfSapn); } var lateToWoks = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "LateToWork"); var earlyExits = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "EarlyExist"); var lateToWork = new TimeSpan(lateToWoks.Sum(x => x.Spanning.Ticks)); var earlyExist = new TimeSpan(earlyExits.Sum(x => x.Spanning.Ticks)); var totalSpaning = new TimeSpan(lateToWorkEarlyExit.Sum(x => x.Spanning.Ticks)); Console.ForegroundColor = ConsoleColor.Yellow; Console.WriteLine(" LateToWork H : " + (int)lateToWork.TotalHours + " M : " + (int)(lateToWork.TotalMinutes % 60)); Console.WriteLine(" EarlyExist H : " + (int)earlyExist.TotalHours + " M : " + (int)(earlyExist.TotalMinutes % 60)); Console.WriteLine(" TotalSpaning H : " + (int)totalSpaning.TotalHours + " M : " + (int)(totalSpaning.TotalMinutes % 60)); Console.ResetColor(); double earlyExitDeduction = 0; double lateToWorkDeduction = 0; ////محاسبه مزد روزانه به ازای هر دقیقه //double dailyWagePerMinute = // (customizeWorkshopEmployeeSettings.Salary / monthDays) / sumOfEmployeeShiftSpan.TotalMinutes; if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType != EarlyExitType.None && earlyExist > new TimeSpan()) { earlyExitDeduction = customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType switch { EarlyExitType.Default => earlyExist.TotalMinutes * minuteWage, EarlyExitType.MoneyPerMinute => earlyExist.TotalMinutes * customizeWorkshopEmployeeSettings.EarlyExit.Value, _ => 0 }; } if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType != LateToWorkType.None && lateToWork > new TimeSpan()) { lateToWorkDeduction = customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType switch { LateToWorkType.Default => lateToWork.TotalMinutes * minuteWage, LateToWorkType.MoneyPerMinute => lateToWork.TotalMinutes * customizeWorkshopEmployeeSettings.LateToWork.Value, _ => 0 }; } if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines.Any()) { lateToWorkDeduction += (from lateToWorkTimeFine in customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines let stepFine = lateToWoks.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(lateToWorkTimeFine.Minute)) select stepFine * lateToWorkTimeFine.FineMoney).Sum(); } if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines.Any()) { earlyExitDeduction += (from earlyExitFine in customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines let stepFine = earlyExits.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(earlyExitFine.Minute)) select stepFine * earlyExitFine.FineMoney).Sum(); } #endregion return new CustomizeCheckoutMandatoryViewModel { InsuranceDeduction = insuranceDeductionAmount, FridayPay = fridayPayAmount, OverTimePay = overtimePayAmount, BaseYearsPay = baseYearsPayAmount, NightWorkPay = nightworkPayAmount, MarriedAllowance = maritalAllowancePay, FamilyAllowance = familyAllowancePay, LeavePay = leavePayAmount, FineAbsenceDeduction = absentsDeductionAmount, BonusesPay = bonusesPayAmount, ContractEndFa = contractEnd.ToFarsi(), ContractStartFa = contractStart.ToFarsi(), EmployeeName = employee.FullName, InstallmentDeduction = loanDeduction, SalaryAidDeduction = salaryAidDeduction, FineDeduction = fineDeduction, RewardPay = rewardPay, Month = monthOfCheckout, Year = yearOfCheckout, LateToWorkDeduction = lateToWorkDeduction, EarlyExitDeduction = earlyExitDeduction, ShiftPay = 0, TaxDeduction = 0, EmployeeId = employeeId, SumOfWorkingDays = totalDays.ToString(), ContractNo = contract?.ContractNo ?? "-", MonthlySalary = dailyWage * mandatoryDays, PersonnelCode = personnelCode, FineViewModels = fineViewModels, InstallmentViewModels = loanInstallments, SalaryAidViewModels = salaryAidViewModel, RewardViewModels = rewardViewModels }; } public CustomizeCheckoutMandatoryViewModel CustomizeCheckoutMandatoryComputeForKebabMahdi(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { var checkoutEnd = contractEnd; var checkoutStart = contractStart; var exceptionEmployees = _context.CustomizeWorkshopGroupSettings.Where(x => x.id == 117) .Include(x => x.CustomizeWorkshopEmployeeSettingsCollection).AsSplitQuery().FirstOrDefault() ?.CustomizeWorkshopEmployeeSettingsCollection.Select(x => x.EmployeeId).ToList() ?? []; if (exceptionEmployees.Contains(employeeId)) { return CheckoutWithoutCalculationForKebabMahdi(workshopId, employeeId, contractStart, contractEnd); } var firstDayOfMonth = $"{(contractStart.ToFarsi())[..8]}/01".ToGeorgianDateTime(); #region LeftWork var leftWork = _leftWorkRepository.GetByWorkshopIdEmployeeIdInDates(workshopId, employeeId, contractStart, contractEnd); if (leftWork.StartWorkDateGr > contractStart) { contractStart = leftWork.StartWorkDateGr; } if (leftWork.LeftWorkDateGr.AddDays(-1) < contractEnd) { contractEnd = leftWork.LeftWorkDateGr.AddDays(-1); } TimeSpan leftWorkDurationTimeSpan = leftWork.HasLeft ? leftWork.LeftWorkDateGr.AddDays(-1) - leftWork.StartWorkDateGr : contractEnd - leftWork.StartWorkDateGr; #endregion #region Entities int numberOfFridays = 0; double monthySalary = 0; int monthDays = 0; double dailyWage = 0; int numberOfWorkingDay = 0; string endPersianDate = contractEnd.ToFarsi(); int monthOfCheckout = Convert.ToInt32(endPersianDate.Substring(5, 2)); int yearOfCheckout = Convert.ToInt32(endPersianDate.Substring(0, 4)); //روز هایی که پرسنل موظف بوده کار کند var mandatoryDays = 0; TimeSpan contractDuration = contractEnd - contractStart; var employee = _context.Employees.FirstOrDefault(x => x.id == employeeId); var personnelCode = _context.PersonnelCodeSet.FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId) ?.PersonnelCode ?? 0; var contract = _context.Contracts.Where(x => x.WorkshopIds == workshopId && x.EmployeeId == employeeId && x.ContractEnd.Date >= contractStart.Date && x.ContarctStart.Date <= contractEnd.Date).ToList() ?.MaxBy(x => x.ContarctStart); var totalDays = (int)(contractEnd - contractStart).TotalDays + 1; mandatoryDays = totalDays; #endregion #region CustomizeSettings CustomizeWorkshopEmployeeSettings customizeWorkshopEmployeeSettings; CustomizeWorkshopSettings customizeWorkshopSettings; var endFarvarding = new DateTime(2025, 4, 20); if (contractStart > endFarvarding) { customizeWorkshopEmployeeSettings = _context.CustomizeWorkshopEmployeeSettings .AsSplitQuery().AsNoTracking().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); customizeWorkshopSettings = _context.CustomizeWorkshopSettings.AsNoTracking() .FirstOrDefault(x => x.WorkshopId == workshopId); } else { customizeWorkshopEmployeeSettings = _testDbContext.CustomizeWorkshopEmployeeSettings .AsSplitQuery().AsNoTracking().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); customizeWorkshopSettings = _testDbContext.CustomizeWorkshopSettings.AsNoTracking() .FirstOrDefault(x => x.WorkshopId == workshopId); } //ToDo handel exception if is null monthySalary = customizeWorkshopEmployeeSettings?.Salary ?? 0; monthDays = customizeWorkshopSettings.MaxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth ? 30 : firstDayOfMonth.CountMonthDays(); var shiftSettings = customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts; var employeeShiftsSpans = shiftSettings.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 EmployeeShiftResult { Placement = x.Placement, ShiftSpan = span }; }); #endregion List rollCallResult = _context.RollCalls.AsNoTracking().Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.ShiftDate.Date >= contractStart.Date && x.ShiftDate.Date <= contractEnd.Date && x.EndDate != null) .Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.CreationDate, ShiftDate = x.ShiftDate, EarlyEntryDuration = x.EarlyEntryDuration, LateEntryDuration = x.LateEntryDuration, EarlyExitDuration = x.EarlyExitDuration, LateExitDuration = x.LateExitDuration, ShiftDurationTimeSpan = x.ShiftDurationTimeSpan, BreakTimeSpan = x.BreakTimeSpan }).ToList(); List groupedRollCall = rollCallResult.GroupBy(x => x.ShiftDate.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value, EarlyEntryDuration = s.EarlyEntryDuration, EarlyExitDuration = s.EarlyExitDuration, LateEntryDuration = s.LateEntryDuration, LateExitDuration = s.LateExitDuration, }).ToList(), HasFriday = x.Any(s => s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value.DayOfWeek == DayOfWeek.Friday), SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) - CalculateBreakTime( x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), BreakTime = CalculateBreakTime(x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), ShiftDate = x.Key, TotalEarlyEntryDuration = new TimeSpan(x.Sum(rollCall => rollCall.EarlyEntryDuration.Ticks)), TotalLateEntryDuration = new TimeSpan(x.Sum(rollCall => rollCall.LateEntryDuration.Ticks)), TotalEarlyExitDuration = new TimeSpan(x.Sum(rollCall => rollCall.EarlyExitDuration.Ticks)), TotalLateExitDuration = new TimeSpan(x.Sum(rollCall => rollCall.LateExitDuration.Ticks)), TotalShiftDurationTimeSpan = x.FirstOrDefault() == null ? TimeSpan.Zero : x.First().ShiftDurationTimeSpan }).ToList(); var sumOfEmployeeShiftSpan = groupedRollCall.Any() ? groupedRollCall.First().TotalShiftDurationTimeSpan : TimeSpan.Zero; if (customizeWorkshopEmployeeSettings.BreakTime.BreakTimeType == BreakTimeType.WithTime && sumOfEmployeeShiftSpan != TimeSpan.Zero) { sumOfEmployeeShiftSpan -= customizeWorkshopEmployeeSettings.BreakTime.BreakTimeValue.ToTimeSpan(); } // ساخت لیست همه تاریخ‌ها در بازه List allDates = Enumerable.Range(0, (contractEnd - contractStart).Days + 1) .Select(offset => contractStart.AddDays(offset)) .ToList(); // فیلتر تاریخ‌هایی که در لیست حضور نیستند List absentDates = allDates .Where(date => !groupedRollCall.Any(g => g.ShiftDate.Date == date.Date)) .ToList(); TimeSpan sumSpans = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); numberOfFridays = groupedRollCall.Count(x => x.HasFriday); numberOfWorkingDay = groupedRollCall.Count(); //تعداد روز های قرارداد int contractDays = (int)contractDuration.TotalDays + 1; //روز های غیبت var absenceDays = mandatoryDays - groupedRollCall.Count; int fridays = 0; int holiday = _context.HolidayItems.Count(x => x.Holidaydate >= contractStart && x.Holidaydate <= contractEnd); for (var gDate = contractStart; gDate <= contractEnd; gDate = gDate.AddDays(1)) { if (gDate.DayOfWeek == DayOfWeek.Friday) { fridays += 1; } } if (customizeWorkshopEmployeeSettings.FridayWork == FridayWork.Default) { var fridayWorkingTotalDays = groupedRollCall.Count(x => x.ShiftDate.DayOfWeek == DayOfWeek.Friday); var fridayWorking = fridays - fridayWorkingTotalDays; //mandatoryDays -= fridayWorking; } if (customizeWorkshopEmployeeSettings.HolidayWork == HolidayWork.Default) { var groupStartDaysDates = groupedRollCall.Select(x => x.CreationDate.Date).ToList(); var holidayWorkingDays = _context.HolidayItems.Count(x => groupStartDaysDates.Any(r => r == x.Holidaydate.Date)); holiday = holiday - holidayWorkingDays; mandatoryDays -= holiday; } TimeSpan absentTimeSpans = new(); if ((mandatoryDays * sumOfEmployeeShiftSpan) > sumSpans) { absentTimeSpans = (mandatoryDays * sumOfEmployeeShiftSpan) - sumSpans; } dailyWage = monthySalary / monthDays; var minuteWage = sumOfEmployeeShiftSpan.TotalMinutes == 0 ? 0 : (dailyWage / sumOfEmployeeShiftSpan.TotalMinutes); // یافتن مرخصی ساعتی #region LeavHourse LeaveSearchModel leaveHourseSearch = new LeaveSearchModel() { EmployeeId = employeeId, WorkshopId = workshopId, LeaveType = "استحقاقی", StartLeaveGr = contractStart, EndLeaveGr = contractEnd, IsAccepted = true, }; List leaveList = _leaveRepository.search(leaveHourseSearch); #endregion //****افزودن مرخصی پرسنل به مجموع ساعات کار*** #region AddEmployeeLeaves //TimeSpan workingPerDayAve = sumSpans / numberOfWorkingDay;//میانگین ساعت کار در روز //if (workingPerDayAve <= new TimeSpan(7, 20, 0)) //{ // sumLeave = leavingDayCout * workingPerDayAve; //} //else //{ // sumLeave = leavingDayCout * new TimeSpan(7, 20, 0); //} double leavePayAmount = 0; double absentsDeductionAmount = 0; int leavePermittedDays = customizeWorkshopEmployeeSettings.LeavePermittedDays; double leaveValue = customizeWorkshopEmployeeSettings.LeavePay.Value; if (customizeWorkshopEmployeeSettings.CustomizeWorkshopGroupSettingId == 77) { var startMonth = contractStart; var endMonth = contractStart.ToFarsi().FindeEndOfMonth().ToGeorgianDateTime(); int fridayInMonth = 0; // Ensure the dates are in the correct order if (startMonth > endMonth) { var temp = startMonth; startMonth = endMonth; endMonth = temp; } // Find the first Friday in the range int daysUntilFriday = ((int)DayOfWeek.Friday - (int)startMonth.DayOfWeek + 7) % 7; DateTime firstFriday = startMonth.AddDays(daysUntilFriday); // If the first Friday is outside the range, there are no Fridays if (firstFriday > endMonth) { fridayInMonth = 0; } // Calculate the total number of days between the first Friday and the end date int totalFridayPeriod = (endMonth - firstFriday).Days; // Count the Fridays by dividing the total days by 7 and adding 1 for the first Friday fridayInMonth = totalFridayPeriod / 7 + 1; leavePermittedDays = fridayInMonth; } sumSpans = CalculateLeavePay(sumOfEmployeeShiftSpan, absentTimeSpans, leavePermittedDays, monthDays, contractDays, sumSpans , leaveValue, minuteWage, contractStart, contractEnd, out leavePayAmount, out absentsDeductionAmount); if (customizeWorkshopEmployeeSettings.LeavePay.LeavePayType != LeavePayType.None) { } else { absentsDeductionAmount = absentTimeSpans.TotalMinutes * minuteWage; } leavePayAmount = 0; absenceDays = (absenceDays - leavePermittedDays) < 0 ? 0 : (absenceDays - leavePermittedDays); //اگر روز تولدش تاریخ فیش وجود داشت var monthOfBirthDay = employee!.DateOfBirth.ToFarsi().Substring(5, 2); var pc = new PersianCalendar(); var birthdayMonth = pc.GetMonth(employee.DateOfBirth); var birthdayDay = pc.GetDayOfMonth(employee.DateOfBirth); if (birthdayMonth == 12 && birthdayDay == 30) { //چک کن که آیا سال قرارداد کبیسه هست یا نه var leap = pc.IsLeapYear(pc.GetYear(contractStart)); if (!leap) { birthdayDay = 29; } } var employeeBirthDay = $"{yearOfCheckout:0000}/{birthdayMonth:00}/{birthdayDay:00}".ToGeorgianDateTime(); if (employeeBirthDay >= contractStart && employeeBirthDay <= contractEnd && absenceDays > 0) { CreateRewardForBirthDay(employeeId, workshopId, dailyWage, monthOfCheckout, yearOfCheckout, contractStart); } Console.WriteLine(sumSpans); #endregion //***********************************// //ToTal Hours Employee Worked double totalHours = (sumSpans.TotalMinutes) / 60; int totalHolidaysAndNotH = (int)sumSpans.TotalHours; int totalHolidaysAndNotM = (int)(sumSpans.TotalMinutes % 60); //***********************************// #region Deductions //غیبت //تاخیر و تعجیل //حق بیمه #region InsurancePay InsuranceDeduction insuranceDeduction = customizeWorkshopEmployeeSettings.InsuranceDeduction; //farokhiChange double insuranceDeductionAmount = InsurancePayCalculation(employeeId, contractStart, contractEnd, insuranceDeduction, monthySalary); #endregion #region SalaryAidDeduction var salaryAidViewModel = SalaryAidsForCheckout(employeeId, workshopId, checkoutStart, checkoutEnd); double salaryAidDeduction = salaryAidViewModel.Sum(x => x.AmountDouble); #endregion #region Loan var loanInstallments = LoanInstallmentForCheckout(employeeId, workshopId, contractStart, contractEnd); double loanDeduction = loanInstallments.Sum(x => x.AmountDouble); #endregion #region Fine var fineViewModels = FinesForCheckout(employeeId, workshopId, contractStart, contractEnd); double fineDeduction = fineViewModels.Sum(x => x.Amount.MoneyToDouble()); #endregion #endregion #region Payments //اضافه کاری #region OvertimePay double overtimePayAmount = 0; TimeSpan overtimeTimeSpan; if (customizeWorkshopSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular && customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { overtimeTimeSpan = CalculateOvertimeSpanWithSumSpan(sumSpans, mandatoryDays, shiftSettings); } else if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { //var date = new DateOnly(); //var firstStartShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MinBy(x => x.Placement).StartTime); //var lastEndShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MaxBy(x => x.Placement).EndTime); //if (lastEndShift > firstStartShift) // firstStartShift = firstStartShift.AddDays(1); //var offSet = (firstStartShift - lastEndShift).Divide(2); //var employeeOffSet = TimeOnly.FromDateTime(lastEndShift.Add(offSet)); overtimeTimeSpan = CalculateOvertimeSpanWithSumSpan(sumSpans, mandatoryDays, shiftSettings); } else { var irregularShifts = customizeWorkshopEmployeeSettings.IrregularShift.WorkshopIrregularShifts; overtimeTimeSpan = CalculateRotatingOvertime(customizeWorkshopEmployeeSettings.CustomizeRotatingShifts, groupedRollCall, mandatoryDays, sumSpans); } overtimePayAmount = CalculateOvertimePay(overtimeTimeSpan, customizeWorkshopEmployeeSettings.OverTimePay, dailyWage); if (overtimePayAmount >= absentsDeductionAmount) { overtimePayAmount = overtimePayAmount - absentsDeductionAmount; absentsDeductionAmount = 0; } else { absentsDeductionAmount = absentsDeductionAmount - overtimePayAmount; overtimePayAmount = 0; } overtimePayAmount = 0; #endregion #region KebabMahdiAbsentsCaclculation var rollCallDays = groupedRollCall.Count > mandatoryDays ? mandatoryDays : groupedRollCall.Count; absenceDays = mandatoryDays - rollCallDays; absenceDays = absenceDays - leavePermittedDays < 0 ? 0 : absenceDays - leavePermittedDays; absentsDeductionAmount = absenceDays * dailyWage; #endregion var createReward = absenceDays; if (monthOfCheckout == 1 && yearOfCheckout == 1404) { bool hasAbsents = _context.CustomizeCheckouts.Any(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.MonthInt == 12 && x.YearInt == 1403 && x.FineAbsenceDeduction > 0); bool absentInEid = !_context.RollCalls.Any(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.ShiftDate == new DateTime(2025, 3, 20)); if (hasAbsents && absentInEid) { CreateReward(employeeId, workshopId, dailyWage, monthOfCheckout, yearOfCheckout, new DateTime(2025, 3, 21), RewardType.Eid, "بابت تعطیلی آخر سال"); } if (absentDates.Any(x => x == new DateTime(2025, 4, 2) && createReward > 0)) { CreateReward(employeeId, workshopId, dailyWage, monthOfCheckout, yearOfCheckout, new DateTime(2025, 4, 2), RewardType.SinzdahBedar, "بابت تعطیلی روز 13 فروردین"); createReward--; } if (absentDates.Any(x => x == new DateTime(2025, 4, 3) && createReward > 0)) { CreateReward(employeeId, workshopId, dailyWage, monthOfCheckout, yearOfCheckout, new DateTime(2025, 4, 3), RewardType.ChahardahFarvardin, "بابت تعطیلی روز 14 فروردین"); createReward--; } } #region FridayPay double fridayPayAmount = 0; fridayPayAmount = FridayPayCalculation(customizeWorkshopEmployeeSettings, rollCallResult, dailyWage, shiftSettings, overtimePayAmount); #endregion //حق تاهل #region MaritalAllownace double maritalAllowancePay = 0; if (employee.MaritalStatus == "متاهل") { switch (customizeWorkshopEmployeeSettings.MarriedAllowance.MarriedAllowanceType) { case MarriedAllowanceType.Money: { maritalAllowancePay = customizeWorkshopEmployeeSettings.MarriedAllowance.Value; break; } //case MarriedAllowanceType.PercentageFromSalary: // { // double multiplier = customizeWorkshopEmployeeSettings.MarriedAllowance.Value / 100; // maritalAllowance = dailyWage * multiplier; // break; // } } } #endregion //شب کاری #region NightWorkPay double nightworkPayAmount = 0; List rotatingResultList = RotatingShiftCheck(groupedRollCall); // شبکاری TimeSpan nightWorks = new TimeSpan(rotatingResultList.Sum(x => x.NightWorkSpan.Ticks)); if (nightWorks > new TimeSpan()) { switch (customizeWorkshopEmployeeSettings.NightWorkPay.NightWorkingType) { case NightWorkType.MoneyPerHour: { var baseAmount = customizeWorkshopEmployeeSettings.NightWorkPay.Value; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += nightWorkMinutes * (baseAmount / 60); break; } case NightWorkType.PercentageFromSalary: { double multiplier = customizeWorkshopEmployeeSettings.NightWorkPay.Value / 100; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += ((dailyWage * multiplier) / 60) * nightWorkMinutes; break; } } } #endregion //سنوات #region BaseYearsPay double baseYearsPayAmount = CalculateYearsPayAmount(employeeId, workshopId, monthySalary, contractStart, contractEnd , customizeWorkshopEmployeeSettings.BaseYearsPay, customizeWorkshopSettings.BaseYearsPayInEndOfYear, customizeWorkshopSettings.MaxMonthDays); #endregion //حق اولاد #region FamilyAllowancePay double familyAllowancePay = 0; switch (customizeWorkshopEmployeeSettings.FamilyAllowance.FamilyAllowanceType) { case FamilyAllowanceType.Money: { double baseAmount = customizeWorkshopEmployeeSettings.FamilyAllowance.Value; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, baseAmount, contractEnd); break; } case FamilyAllowanceType.Percentage: { double multiplier = customizeWorkshopEmployeeSettings.FamilyAllowance.Value / 100; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, multiplier * monthySalary, contractEnd); break; } } #endregion #region Reward var rewardViewModels = RewardForCheckout(employeeId, workshopId, checkoutEnd, checkoutStart); double rewardPay = rewardViewModels.Sum(x => x.AmountDouble); #endregion #region LeavePay #endregion #region BonusesPay double bonusesPayAmount = 0; if (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType != BonusesType.None) { switch (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType) { case BonusesType.OneTimeOfSalary: bonusesPayAmount = monthySalary; break; case BonusesType.TwoTimeOfSalary: bonusesPayAmount = monthySalary * 2; break; case BonusesType.Money: bonusesPayAmount = customizeWorkshopEmployeeSettings.BonusesPay.Value; break; case BonusesType.PercentageOfSalary: bonusesPayAmount = (monthySalary * customizeWorkshopEmployeeSettings.BonusesPay.Value) / 100; break; } double bonusesPerMonth = bonusesPayAmount / 12; if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.YearlyPay) { var contractEndFarsi = Tools.FindeEndOfMonth(contractEnd.ToFarsi()); if (monthOfCheckout == 12 && (contractEndFarsi.EndsWith("29")) || contractEndFarsi.EndsWith("30")) { } else if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft) { TimeSpan bonusDuration; DateTime startOfYear = new PersianCalendar().ToDateTime(yearOfCheckout, 1, 1, 0, 0, 0, 0); if (startOfYear < leftWork.StartWorkDateGr) bonusDuration = leftWorkDurationTimeSpan; else bonusDuration = leftWork.LeftWorkDateGr - startOfYear; //ToDo: Check if should be absolute 365! bonusesPayAmount = (bonusesPayAmount / 365) * bonusDuration.TotalDays; } else { bonusesPayAmount = 0; } } else if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.MonthlyPay) { if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft && contractDays < monthDays) bonusesPayAmount = (bonusesPerMonth / contractEnd.CountPersianMonthDays()) * contractDuration.TotalDays + 1; bonusesPayAmount = bonusesPerMonth; } else { throw new InvalidDataException(); } } #endregion #endregion #region LateToWork & EarlyExit //var lateToWorkEarlyExit = LateToWorkEarlyExit(groupedRollCall, shiftSettings, leaveList); //foreach (var i in lateToWorkEarlyExit) //{ // Console.WriteLine(" start : " + i.StartSpan + " end : " + i.EndSpan + " spaning : " + i.Spanning + " Type : " + i.TypeOfSapn); //} //var lateToWoks = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "LateToWork"); //var earlyExits = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "EarlyExist"); //var lateToWork = new TimeSpan(lateToWoks.Sum(x => x.Spanning.Ticks)); //var earlyExist = new TimeSpan(earlyExits.Sum(x => x.Spanning.Ticks)); //var totalSpaning = new TimeSpan(lateToWorkEarlyExit.Sum(x => x.Spanning.Ticks)); //Console.ForegroundColor = ConsoleColor.Yellow; //Console.WriteLine(" LateToWork H : " + (int)lateToWork.TotalHours + " M : " + (int)(lateToWork.TotalMinutes % 60)); //Console.WriteLine(" EarlyExist H : " + (int)earlyExist.TotalHours + " M : " + (int)(earlyExist.TotalMinutes % 60)); //Console.WriteLine(" TotalSpaning H : " + (int)totalSpaning.TotalHours + " M : " + (int)(totalSpaning.TotalMinutes % 60)); //Console.ResetColor(); //double earlyExitDeduction = 0; //double lateToWorkDeduction = 0; //////محاسبه مزد روزانه به ازای هر دقیقه ////double dailyWagePerMinute = //// (customizeWorkshopEmployeeSettings.Salary / monthDays) / sumOfEmployeeShiftSpan.TotalMinutes; //if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType != EarlyExitType.None && earlyExist > new TimeSpan()) //{ // earlyExitDeduction = customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType switch // { // EarlyExitType.Default => earlyExist.TotalMinutes * minuteWage, // EarlyExitType.MoneyPerMinute => earlyExist.TotalMinutes * customizeWorkshopEmployeeSettings.EarlyExit.Value, // _ => 0 // }; //} //if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType != LateToWorkType.None && lateToWork > new TimeSpan()) //{ // lateToWorkDeduction = customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType switch // { // LateToWorkType.Default => lateToWork.TotalMinutes * minuteWage, // LateToWorkType.MoneyPerMinute => lateToWork.TotalMinutes * customizeWorkshopEmployeeSettings.LateToWork.Value, // _ => 0 // }; //} //if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines.Any()) //{ // lateToWorkDeduction += // (from lateToWorkTimeFine in customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines // let stepFine = lateToWoks.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(lateToWorkTimeFine.Minute)) // select stepFine * lateToWorkTimeFine.FineMoney).Sum(); //} //if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines.Any()) //{ // earlyExitDeduction += // (from earlyExitFine in customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines // let stepFine = earlyExits.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(earlyExitFine.Minute)) // select stepFine * earlyExitFine.FineMoney).Sum(); //} double lateToWorkDeduction = 0; TimeSpan totalLateToWorkSpan = TimeSpan.Zero; var beforeTir1404 = new DateTime(1404, 3, 31, new PersianCalendar()); if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Rotating) { foreach (var rollCall in groupedRollCall) { var rollCallShift = rollCall.TotalShiftDurationTimeSpan; var dayMinuteWage = rollCallShift.TotalMinutes == 0 ? 0 : (dailyWage / rollCallShift.TotalMinutes); (DateTime start, DateTime end)? firstShift = null; foreach (var rc in rollCall.ShiftList.OrderBy(x => x.Start)) { double minutes = 0; var shift = FindRotatingShift(rc.Start, rc.End, customizeWorkshopEmployeeSettings.CustomizeRotatingShifts); if (firstShift == null) { firstShift = shift; } if (shift.start == firstShift.Value.start && shift.end == firstShift.Value.end) { TimeSpan effectiveLate = rc.LateEntryDuration; if (contractStart > beforeTir1404) { // فقط اگر بیشتر از 5 دقیقه بود، محاسبه کنیم if (effectiveLate.TotalMinutes > 5) { effectiveLate = effectiveLate - TimeSpan.FromMinutes(5); } else { effectiveLate = TimeSpan.Zero; } } minutes += effectiveLate.TotalMinutes; totalLateToWorkSpan = totalLateToWorkSpan.Add(effectiveLate); lateToWorkDeduction += dayMinuteWage * minutes; } //if (contractStart>beforeTir1404) //{ //} //if (shift.start == firstShift.Value.start && shift.end == firstShift.Value.end) //{ // minutes += rc.LateEntryDuration.TotalMinutes; // totalLateToWorkSpan = totalLateToWorkSpan.Add(rc.LateEntryDuration); //} //lateToWorkDeduction += dayMinuteWage * minutes; } } } else { foreach (var rollCall in groupedRollCall) { var rollCallShift = rollCall.TotalShiftDurationTimeSpan; var dayMinuteWage = rollCallShift.TotalMinutes == 0 ? 0 : (dailyWage / rollCallShift.TotalMinutes); TimeSpan effectiveLate = rollCall.TotalLateEntryDuration; if (contractStart > beforeTir1404) { // اگر بیشتر از 5 دقیقه بود، فقط اضافه آن لحاظ شود if (effectiveLate.TotalMinutes > 5) { effectiveLate = effectiveLate - TimeSpan.FromMinutes(5); } else { effectiveLate = TimeSpan.Zero; } } var minutes = effectiveLate.TotalMinutes; lateToWorkDeduction += dayMinuteWage * minutes; totalLateToWorkSpan = totalLateToWorkSpan.Add(effectiveLate); } } if (mandatoryDays == 31) { mandatoryDays = 30; } #endregion return new CustomizeCheckoutMandatoryViewModel { InsuranceDeduction = Math.Truncate(insuranceDeductionAmount), FridayPay = Math.Truncate(fridayPayAmount), OverTimePay = Math.Truncate(overtimePayAmount), BaseYearsPay = Math.Truncate(baseYearsPayAmount), NightWorkPay = Math.Truncate(nightworkPayAmount), MarriedAllowance = Math.Truncate(maritalAllowancePay), FamilyAllowance = Math.Truncate(familyAllowancePay), LeavePay = Math.Truncate(leavePayAmount), FineAbsenceDeduction = Math.Truncate(absentsDeductionAmount), BonusesPay = Math.Truncate(bonusesPayAmount), ContractEndFa = contractEnd.ToFarsi(), ContractStartFa = contractStart.ToFarsi(), EmployeeName = employee.FullName, InstallmentDeduction = Math.Truncate(loanDeduction), SalaryAidDeduction = Math.Truncate(salaryAidDeduction), FineDeduction = Math.Truncate(fineDeduction), RewardPay = Math.Truncate(rewardPay), Month = monthOfCheckout, Year = yearOfCheckout, LateToWorkDeduction = Math.Truncate(lateToWorkDeduction), EarlyExitDeduction = 0, ShiftPay = 0, TaxDeduction = 0, EmployeeId = employeeId, SumOfWorkingDays = totalDays.ToString(), ContractNo = contract?.ContractNo ?? "-", MonthlySalary = dailyWage * mandatoryDays, PersonnelCode = personnelCode, FineViewModels = fineViewModels, InstallmentViewModels = loanInstallments, SalaryAidViewModels = salaryAidViewModel, RewardViewModels = rewardViewModels, LateToWorkValue = totalLateToWorkSpan, SettingSalary = customizeWorkshopEmployeeSettings.Salary, DailyWage = dailyWage, ShiftStatus = customizeWorkshopEmployeeSettings.WorkshopShiftStatus, IrregularShift = customizeWorkshopEmployeeSettings.IrregularShift, CustomizeRotatingShifts = customizeWorkshopEmployeeSettings.CustomizeRotatingShifts, EmployeeSettingsShifts = customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts .Select(x => (CustomizeSifts)x).ToList(), }; } private CustomizeCheckoutMandatoryViewModel CheckoutWithoutCalculationForKebabMahdi(long workshopId, long employeeId, DateTime contractStart, DateTime contractEnd) { var firstDayOfMonth = $"{(contractStart.ToFarsi())[..8]}/01".ToGeorgianDateTime(); CustomizeWorkshopEmployeeSettings customizeWorkshopEmployeeSettings; CustomizeWorkshopSettings customizeWorkshopSettings; var endFarvarding = new DateTime(2025, 4, 20); if (contractStart > endFarvarding) { customizeWorkshopEmployeeSettings = _context.CustomizeWorkshopEmployeeSettings .AsSplitQuery().AsNoTracking().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); customizeWorkshopSettings = _context.CustomizeWorkshopSettings.AsNoTracking() .FirstOrDefault(x => x.WorkshopId == workshopId); } else { customizeWorkshopEmployeeSettings = _testDbContext.CustomizeWorkshopEmployeeSettings .AsSplitQuery().AsNoTracking().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); customizeWorkshopSettings = _testDbContext.CustomizeWorkshopSettings.AsNoTracking() .FirstOrDefault(x => x.WorkshopId == workshopId); } //ToDo handel exception if is null var monthySalary = customizeWorkshopEmployeeSettings?.Salary ?? 0; var monthDays = customizeWorkshopSettings.MaxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth ? 30 : firstDayOfMonth.CountMonthDays(); double dailyWage = 0; dailyWage = monthySalary / monthDays; var totalDays = (int)(contractEnd - contractStart).TotalDays + 1; var mandatoryDays = totalDays; #region SalaryAidDeduction var salaryAidViewModel = SalaryAidsForCheckout(employeeId, workshopId, contractStart, contractEnd); double salaryAidDeduction = salaryAidViewModel.Sum(x => x.AmountDouble); #endregion #region Loan var loanInstallments = LoanInstallmentForCheckout(employeeId, workshopId, contractStart, contractEnd); double loanDeduction = loanInstallments.Sum(x => x.AmountDouble); #endregion #region Fine var fineViewModels = FinesForCheckout(employeeId, workshopId, contractStart, contractEnd); double fineDeduction = fineViewModels.Sum(x => x.Amount.MoneyToDouble()); #endregion #region Reward var rewardViewModels = RewardForCheckout(employeeId, workshopId, contractEnd, contractStart); double rewardPay = rewardViewModels.Sum(x => x.AmountDouble); #endregion if (mandatoryDays == 31) { mandatoryDays = 30; } return new CustomizeCheckoutMandatoryViewModel() { MonthlySalary = dailyWage * mandatoryDays, RewardPay = rewardPay, RewardViewModels = rewardViewModels, SalaryAidDeduction = salaryAidDeduction, SalaryAidViewModels = salaryAidViewModel, InstallmentDeduction = loanDeduction, InstallmentViewModels = loanInstallments, FineDeduction = fineDeduction, FineViewModels = fineViewModels }; } public CustomizeCheckoutMandatoryViewModel CustomizeCheckoutMandatoryComputeForPizzaAmir(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { var dynamicdeductions = new List(); //مقدار جریمه تاخیر ورود double lateEntryFine = 0; //مرز جریمه جداگانه تاخیر ورود int minuteThresholdForLateEntryFine = 16; //تعداد دفعاتی که پرسنل بیش از مرز تاخیر ورود داشته است int lateEntryFineTimes = 0; //مرز محاسبه تعجیل خروج int minuteThresholdForEarlyExitCalculation = 30; //مبلغ جریمه تاخیر ورود int lateEntryFineAmount = 400_000; //مقدار جریمه افرادی که دارای بیمه هستند ولی غیبت کرده اند int absenceForInsuranceEmployeesAmount = 1500_000; //جریمه غیبت برای پرسنل بیمه شده double absenceForInsuranceFine = 0; //تعداد روز غیبت پرسنل بیمه شده int absenceForInsuranceDays = 0; var checkoutEnd = contractEnd; var checkoutStart = contractStart; var firstDayOfMonth = $"{(contractStart.ToFarsi())[..8]}/01".ToGeorgianDateTime(); #region LeftWork var leftWork = _leftWorkRepository.GetByWorkshopIdEmployeeIdInDates(workshopId, employeeId, contractStart, contractEnd); if (leftWork.StartWorkDateGr > contractStart) { contractStart = leftWork.StartWorkDateGr; } if (leftWork.LeftWorkDateGr.AddDays(-1) < contractEnd) { contractEnd = leftWork.LeftWorkDateGr.AddDays(-1); } TimeSpan leftWorkDurationTimeSpan = leftWork.HasLeft ? leftWork.LeftWorkDateGr.AddDays(-1) - leftWork.StartWorkDateGr : contractEnd - leftWork.StartWorkDateGr; #endregion #region Entities int numberOfFridays = 0; double monthySalary = 0; int monthDays = 0; double dailyWage = 0; int numberOfWorkingDay = 0; string endPersianDate = contractEnd.ToFarsi(); int monthOfCheckout = Convert.ToInt32(endPersianDate.Substring(5, 2)); int yearOfCheckout = Convert.ToInt32(endPersianDate.Substring(0, 4)); //روز هایی که پرسنل موظف بوده کار کند var mandatoryDays = 0; TimeSpan contractDuration = contractEnd - contractStart; var employee = _context.Employees.FirstOrDefault(x => x.id == employeeId); var personnelCode = _context.PersonnelCodeSet.FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId) ?.PersonnelCode ?? 0; var contract = _context.Contracts.Where(x => x.WorkshopIds == workshopId && x.EmployeeId == employeeId && x.ContractEnd.Date >= contractStart.Date && x.ContarctStart.Date <= contractEnd.Date).ToList() ?.MaxBy(x => x.ContarctStart); var totalDays = (int)(contractEnd - contractStart).TotalDays + 1; mandatoryDays = totalDays; #endregion #region CustomizeSettings CustomizeWorkshopEmployeeSettings customizeWorkshopEmployeeSettings; CustomizeWorkshopSettings customizeWorkshopSettings; customizeWorkshopEmployeeSettings = _context.CustomizeWorkshopEmployeeSettings .AsSplitQuery().AsNoTracking().FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId); customizeWorkshopSettings = _context.CustomizeWorkshopSettings.AsNoTracking() .FirstOrDefault(x => x.WorkshopId == workshopId); //ToDo handel exception if is null monthySalary = customizeWorkshopEmployeeSettings?.Salary ?? 0; monthDays = customizeWorkshopSettings.MaxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth ? 30 : firstDayOfMonth.CountMonthDays(); var shiftSettings = customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts; var employeeShiftsSpans = shiftSettings.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 EmployeeShiftResult { Placement = x.Placement, ShiftSpan = span }; }); #endregion List rollCallResult = _context.RollCalls.AsNoTracking().Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.ShiftDate.Date >= contractStart.Date && x.ShiftDate.Date <= contractEnd.Date && x.EndDate != null) .Select(x => new RollCallViewModel() { StartDate = x.StartDate, EndDate = x.EndDate, ShiftSpan = (x.EndDate.Value - x.StartDate.Value), CreationDate = x.CreationDate, ShiftDate = x.ShiftDate, EarlyEntryDuration = x.EarlyEntryDuration, LateEntryDuration = x.LateEntryDuration, EarlyExitDuration = x.EarlyExitDuration, LateExitDuration = x.LateExitDuration, ShiftDurationTimeSpan = x.ShiftDurationTimeSpan, BreakTimeSpan = x.BreakTimeSpan }).ToList(); List groupedRollCall = rollCallResult.GroupBy(x => x.ShiftDate.Date).Select(x => new GroupedRollCalls() { CreationDate = x.Key, ShiftList = x.Select(s => new ShiftList() { Start = s.StartDate!.Value, End = s.EndDate!.Value, EarlyEntryDuration = s.EarlyEntryDuration, EarlyExitDuration = s.EarlyExitDuration, LateEntryDuration = s.LateEntryDuration, LateExitDuration = s.LateExitDuration, }).ToList(), HasFriday = x.Any(s => s.StartDate.Value.DayOfWeek == DayOfWeek.Friday || s.EndDate.Value.DayOfWeek == DayOfWeek.Friday), SumOneDaySpan = new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks)) - CalculateBreakTime( x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), BreakTime = CalculateBreakTime(x.First().BreakTimeSpan, new TimeSpan(x.Sum(shift => shift.ShiftSpan.Ticks))), ShiftDate = x.Key, TotalEarlyEntryDuration = new TimeSpan(x.Sum(rollCall => rollCall.EarlyEntryDuration.Ticks)), TotalLateEntryDuration = new TimeSpan(x.Sum(rollCall => rollCall.LateEntryDuration.Ticks)), TotalEarlyExitDuration = new TimeSpan(x.Sum(rollCall => rollCall.EarlyExitDuration.Ticks)), TotalLateExitDuration = new TimeSpan(x.Sum(rollCall => rollCall.LateExitDuration.Ticks)), TotalShiftDurationTimeSpan = x.FirstOrDefault() == null ? TimeSpan.Zero : x.First().ShiftDurationTimeSpan }).ToList(); var sumOfEmployeeShiftSpan = groupedRollCall.Any() ? groupedRollCall.First().TotalShiftDurationTimeSpan : TimeSpan.Zero; if (customizeWorkshopEmployeeSettings.BreakTime.BreakTimeType == BreakTimeType.WithTime && sumOfEmployeeShiftSpan != TimeSpan.Zero) { sumOfEmployeeShiftSpan -= customizeWorkshopEmployeeSettings.BreakTime.BreakTimeValue.ToTimeSpan(); } // ساخت لیست همه تاریخ‌ها در بازه List allDates = Enumerable.Range(0, (contractEnd - contractStart).Days + 1) .Select(offset => contractStart.AddDays(offset)) .ToList(); // فیلتر تاریخ‌هایی که در لیست حضور نیستند List absentDates = allDates .Where(date => !groupedRollCall.Any(g => g.ShiftDate.Date == date.Date)) .ToList(); TimeSpan sumSpans = new TimeSpan(groupedRollCall.Sum(x => x.SumOneDaySpan.Ticks)); numberOfFridays = groupedRollCall.Count(x => x.HasFriday); numberOfWorkingDay = groupedRollCall.Count(); //تعداد روز های قرارداد int contractDays = (int)contractDuration.TotalDays + 1; //روز های غیبت var absenceDays = mandatoryDays - groupedRollCall.Count; int fridays = 0; int holiday = _context.HolidayItems.Count(x => x.Holidaydate >= contractStart && x.Holidaydate <= contractEnd); for (var gDate = contractStart; gDate <= contractEnd; gDate = gDate.AddDays(1)) { if (gDate.DayOfWeek == DayOfWeek.Friday) { fridays += 1; } } if (customizeWorkshopEmployeeSettings.FridayWork == FridayWork.Default) { var fridayWorkingTotalDays = groupedRollCall.Count(x => x.ShiftDate.DayOfWeek == DayOfWeek.Friday); var fridayWorking = fridays - fridayWorkingTotalDays; //mandatoryDays -= fridayWorking; } if (customizeWorkshopEmployeeSettings.HolidayWork == HolidayWork.Default) { var groupStartDaysDates = groupedRollCall.Select(x => x.CreationDate.Date).ToList(); var holidayWorkingDays = _context.HolidayItems.Count(x => groupStartDaysDates.Any(r => r == x.Holidaydate.Date)); holiday = holiday - holidayWorkingDays; mandatoryDays -= holiday; } TimeSpan absentTimeSpans = new(); if ((mandatoryDays * sumOfEmployeeShiftSpan) > sumSpans) { absentTimeSpans = (mandatoryDays * sumOfEmployeeShiftSpan) - sumSpans; } dailyWage = monthySalary / monthDays; var minuteWage = sumOfEmployeeShiftSpan.TotalMinutes == 0 ? 0 : (dailyWage / sumOfEmployeeShiftSpan.TotalMinutes); // یافتن مرخصی ساعتی #region LeavHourse // LeaveSearchModel leaveHourseSearch = new LeaveSearchModel() // { // EmployeeId = employeeId, // WorkshopId = workshopId, // LeaveType = "استحقاقی", // // StartLeaveGr = contractStart, // EndLeaveGr = contractEnd, // IsAccepted = true, // // }; // List leaveList = _leaveRepository.search(leaveHourseSearch); #endregion //****افزودن مرخصی پرسنل به مجموع ساعات کار*** #region AddEmployeeLeaves //TimeSpan workingPerDayAve = sumSpans / numberOfWorkingDay;//میانگین ساعت کار در روز //if (workingPerDayAve <= new TimeSpan(7, 20, 0)) //{ // sumLeave = leavingDayCout * workingPerDayAve; //} //else //{ // sumLeave = leavingDayCout * new TimeSpan(7, 20, 0); //} double leavePayAmount = 0; double absentsDeductionAmount = 0; int leavePermittedDays = customizeWorkshopEmployeeSettings.LeavePermittedDays; double leaveValue = customizeWorkshopEmployeeSettings.LeavePay.Value; sumSpans = CalculateLeavePay(sumOfEmployeeShiftSpan, absentTimeSpans, leavePermittedDays, monthDays, contractDays, sumSpans , leaveValue, minuteWage, contractStart, contractEnd, out leavePayAmount, out absentsDeductionAmount); if (customizeWorkshopEmployeeSettings.LeavePay.LeavePayType != LeavePayType.None) { } else { absentsDeductionAmount = absentTimeSpans.TotalMinutes * minuteWage; } leavePayAmount = 0; absenceDays = (absenceDays - leavePermittedDays) < 0 ? 0 : (absenceDays - leavePermittedDays); //اگر روز تولدش تاریخ فیش وجود داشت Console.WriteLine(sumSpans); #endregion //***********************************// //ToTal Hours Employee Worked double totalHours = (sumSpans.TotalMinutes) / 60; int totalHolidaysAndNotH = (int)sumSpans.TotalHours; int totalHolidaysAndNotM = (int)(sumSpans.TotalMinutes % 60); //***********************************// #region Deductions //غیبت //تاخیر و تعجیل //حق بیمه #region InsurancePay InsuranceDeduction insuranceDeduction = customizeWorkshopEmployeeSettings.InsuranceDeduction; //farokhiChange double insuranceDeductionAmount = InsurancePayCalculation(employeeId, contractStart, contractEnd, insuranceDeduction, monthySalary); #endregion #region SalaryAidDeduction var salaryAidViewModel = SalaryAidsForCheckout(employeeId, workshopId, checkoutStart, checkoutEnd); double salaryAidDeduction = salaryAidViewModel.Sum(x => x.AmountDouble); #endregion #region Loan var loanInstallments = LoanInstallmentForCheckout(employeeId, workshopId, contractStart, contractEnd); double loanDeduction = loanInstallments.Sum(x => x.AmountDouble); #endregion #region Fine var fineViewModels = FinesForCheckout(employeeId, workshopId, contractStart, contractEnd); double fineDeduction = fineViewModels.Sum(x => x.Amount.MoneyToDouble()); #endregion #endregion #region Payments //اضافه کاری #region OvertimePay double overtimePayAmount = 0; TimeSpan overtimeTimeSpan; if (customizeWorkshopSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular && customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { overtimeTimeSpan = CalculateOvertimeSpanWithSumSpan(sumSpans, mandatoryDays, shiftSettings); } else if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Regular) { //var date = new DateOnly(); //var firstStartShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MinBy(x => x.Placement).StartTime); //var lastEndShift = new DateTime(date, customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts.MaxBy(x => x.Placement).EndTime); //if (lastEndShift > firstStartShift) // firstStartShift = firstStartShift.AddDays(1); //var offSet = (firstStartShift - lastEndShift).Divide(2); //var employeeOffSet = TimeOnly.FromDateTime(lastEndShift.Add(offSet)); overtimeTimeSpan = CalculateOvertimeSpanWithSumSpan(sumSpans, mandatoryDays, shiftSettings); } else { var irregularShifts = customizeWorkshopEmployeeSettings.IrregularShift.WorkshopIrregularShifts; overtimeTimeSpan = CalculateRotatingOvertime(customizeWorkshopEmployeeSettings.CustomizeRotatingShifts, groupedRollCall, mandatoryDays, sumSpans); } overtimePayAmount = CalculateOvertimePay(overtimeTimeSpan, customizeWorkshopEmployeeSettings.OverTimePay, dailyWage); if (overtimePayAmount >= absentsDeductionAmount) { overtimePayAmount = overtimePayAmount - absentsDeductionAmount; absentsDeductionAmount = 0; } else { absentsDeductionAmount = absentsDeductionAmount - overtimePayAmount; overtimePayAmount = 0; } overtimePayAmount = 0; #endregion #region KebabMahdiAbsentsCaclculation var rollCallDays = groupedRollCall.Count > mandatoryDays ? mandatoryDays : groupedRollCall.Count; absenceDays = mandatoryDays - rollCallDays; if (absenceDays - leavePermittedDays < 0) { leavePermittedDays -= absenceDays; leavePayAmount = leavePermittedDays * dailyWage; absentsDeductionAmount = 0; absenceDays = 0; } else { absenceDays -= leavePermittedDays; absentsDeductionAmount = absenceDays * dailyWage; leavePayAmount = 0; leavePermittedDays = 0; } #endregion #region FridayPay double fridayPayAmount = 0; fridayPayAmount = FridayPayCalculation(customizeWorkshopEmployeeSettings, rollCallResult, dailyWage, shiftSettings, overtimePayAmount); #endregion //حق تاهل #region MaritalAllownace double maritalAllowancePay = 0; if (employee.MaritalStatus == "متاهل") { switch (customizeWorkshopEmployeeSettings.MarriedAllowance.MarriedAllowanceType) { case MarriedAllowanceType.Money: { maritalAllowancePay = customizeWorkshopEmployeeSettings.MarriedAllowance.Value; break; } //case MarriedAllowanceType.PercentageFromSalary: // { // double multiplier = customizeWorkshopEmployeeSettings.MarriedAllowance.Value / 100; // maritalAllowance = dailyWage * multiplier; // break; // } } } #endregion //شب کاری #region NightWorkPay double nightworkPayAmount = 0; List rotatingResultList = RotatingShiftCheck(groupedRollCall); // شبکاری TimeSpan nightWorks = new TimeSpan(rotatingResultList.Sum(x => x.NightWorkSpan.Ticks)); if (nightWorks > new TimeSpan()) { switch (customizeWorkshopEmployeeSettings.NightWorkPay.NightWorkingType) { case NightWorkType.MoneyPerHour: { var baseAmount = customizeWorkshopEmployeeSettings.NightWorkPay.Value; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += nightWorkMinutes * (baseAmount / 60); break; } case NightWorkType.PercentageFromSalary: { double multiplier = customizeWorkshopEmployeeSettings.NightWorkPay.Value / 100; var nightWorkMinutes = (int)(nightWorks).TotalMinutes; nightworkPayAmount += ((dailyWage * multiplier) / 60) * nightWorkMinutes; break; } } } #endregion //سنوات #region BaseYearsPay double baseYearsPayAmount = CalculateYearsPayAmount(employeeId, workshopId, monthySalary, contractStart, contractEnd , customizeWorkshopEmployeeSettings.BaseYearsPay, customizeWorkshopSettings.BaseYearsPayInEndOfYear, customizeWorkshopSettings.MaxMonthDays); #endregion //حق اولاد #region FamilyAllowancePay double familyAllowancePay = 0; switch (customizeWorkshopEmployeeSettings.FamilyAllowance.FamilyAllowanceType) { case FamilyAllowanceType.Money: { double baseAmount = customizeWorkshopEmployeeSettings.FamilyAllowance.Value; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, baseAmount, contractEnd); break; } case FamilyAllowanceType.Percentage: { double multiplier = customizeWorkshopEmployeeSettings.FamilyAllowance.Value / 100; familyAllowancePay = CalculateFamilyAllowancePayAmount(employeeId, multiplier * monthySalary, contractEnd); break; } } #endregion #region Reward var rewardViewModels = RewardForCheckout(employeeId, workshopId, checkoutEnd, checkoutStart); double rewardPay = rewardViewModels.Sum(x => x.AmountDouble); #endregion #region LeavePay #endregion #region BonusesPay double bonusesPayAmount = 0; if (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType != BonusesType.None) { switch (customizeWorkshopEmployeeSettings.BonusesPay.BonusesPayType) { case BonusesType.OneTimeOfSalary: bonusesPayAmount = monthySalary; break; case BonusesType.TwoTimeOfSalary: bonusesPayAmount = monthySalary * 2; break; case BonusesType.Money: bonusesPayAmount = customizeWorkshopEmployeeSettings.BonusesPay.Value; break; case BonusesType.PercentageOfSalary: bonusesPayAmount = (monthySalary * customizeWorkshopEmployeeSettings.BonusesPay.Value) / 100; break; } double bonusesPerMonth = bonusesPayAmount / 12; if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.YearlyPay) { var contractEndFarsi = Tools.FindeEndOfMonth(contractEnd.ToFarsi()); if (monthOfCheckout == 12 && (contractEndFarsi.EndsWith("29")) || contractEndFarsi.EndsWith("30")) { } else if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft) { TimeSpan bonusDuration; DateTime startOfYear = new PersianCalendar().ToDateTime(yearOfCheckout, 1, 1, 0, 0, 0, 0); if (startOfYear < leftWork.StartWorkDateGr) bonusDuration = leftWorkDurationTimeSpan; else bonusDuration = leftWork.LeftWorkDateGr - startOfYear; //ToDo: Check if should be absolute 365! bonusesPayAmount = (bonusesPayAmount / 365) * bonusDuration.TotalDays; } else { bonusesPayAmount = 0; } } else if (customizeWorkshopEmployeeSettings.BonusesPay.PaymentType == BonusesPaymentType.MonthlyPay) { if (customizeWorkshopSettings.BonusesPaysInEndOfMonth == BonusesPaysInEndOfYear.WhenEverEmployeeLeftWork && leftWork.HasLeft && contractDays < monthDays) bonusesPayAmount = (bonusesPerMonth / contractEnd.CountPersianMonthDays()) * contractDuration.TotalDays + 1; bonusesPayAmount = bonusesPerMonth; } else { throw new InvalidDataException(); } } #endregion #endregion #region LateToWork & EarlyExit //var lateToWorkEarlyExit = LateToWorkEarlyExit(groupedRollCall, shiftSettings, leaveList); //foreach (var i in lateToWorkEarlyExit) //{ // Console.WriteLine(" start : " + i.StartSpan + " end : " + i.EndSpan + " spaning : " + i.Spanning + " Type : " + i.TypeOfSapn); //} //var lateToWoks = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "LateToWork"); //var earlyExits = lateToWorkEarlyExit.Where(x => x.TypeOfSapn == "EarlyExist"); //var lateToWork = new TimeSpan(lateToWoks.Sum(x => x.Spanning.Ticks)); //var earlyExist = new TimeSpan(earlyExits.Sum(x => x.Spanning.Ticks)); //var totalSpaning = new TimeSpan(lateToWorkEarlyExit.Sum(x => x.Spanning.Ticks)); //Console.ForegroundColor = ConsoleColor.Yellow; //Console.WriteLine(" LateToWork H : " + (int)lateToWork.TotalHours + " M : " + (int)(lateToWork.TotalMinutes % 60)); //Console.WriteLine(" EarlyExist H : " + (int)earlyExist.TotalHours + " M : " + (int)(earlyExist.TotalMinutes % 60)); //Console.WriteLine(" TotalSpaning H : " + (int)totalSpaning.TotalHours + " M : " + (int)(totalSpaning.TotalMinutes % 60)); //Console.ResetColor(); //double earlyExitDeduction = 0; //double lateToWorkDeduction = 0; //////محاسبه مزد روزانه به ازای هر دقیقه ////double dailyWagePerMinute = //// (customizeWorkshopEmployeeSettings.Salary / monthDays) / sumOfEmployeeShiftSpan.TotalMinutes; //if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType != EarlyExitType.None && earlyExist > new TimeSpan()) //{ // earlyExitDeduction = customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitType switch // { // EarlyExitType.Default => earlyExist.TotalMinutes * minuteWage, // EarlyExitType.MoneyPerMinute => earlyExist.TotalMinutes * customizeWorkshopEmployeeSettings.EarlyExit.Value, // _ => 0 // }; //} //if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType != LateToWorkType.None && lateToWork > new TimeSpan()) //{ // lateToWorkDeduction = customizeWorkshopEmployeeSettings.LateToWork.LateToWorkType switch // { // LateToWorkType.Default => lateToWork.TotalMinutes * minuteWage, // LateToWorkType.MoneyPerMinute => lateToWork.TotalMinutes * customizeWorkshopEmployeeSettings.LateToWork.Value, // _ => 0 // }; //} //if (customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines.Any()) //{ // lateToWorkDeduction += // (from lateToWorkTimeFine in customizeWorkshopEmployeeSettings.LateToWork.LateToWorkTimeFines // let stepFine = lateToWoks.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(lateToWorkTimeFine.Minute)) // select stepFine * lateToWorkTimeFine.FineMoney).Sum(); //} //if (customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines.Any()) //{ // earlyExitDeduction += // (from earlyExitFine in customizeWorkshopEmployeeSettings.EarlyExit.EarlyExitTimeFines // let stepFine = earlyExits.Count(x => x.Spanning.TotalMinutes >= Convert.ToInt32(earlyExitFine.Minute)) // select stepFine * earlyExitFine.FineMoney).Sum(); //} double lateToWorkDeduction = 0; double earlyExitDeduction = 0; TimeSpan totalLateToWorkSpan = TimeSpan.Zero; if (customizeWorkshopEmployeeSettings.WorkshopShiftStatus == WorkshopShiftStatus.Rotating) { foreach (var rollCall in groupedRollCall) { var rollCallShift = rollCall.TotalShiftDurationTimeSpan; var dayMinuteWage = rollCallShift.TotalMinutes == 0 ? 0 : (dailyWage / rollCallShift.TotalMinutes); (DateTime start, DateTime end)? firstShift = null; foreach (var rc in rollCall.ShiftList.OrderBy(x => x.Start)) { var shift = FindRotatingShift(rc.Start, rc.End, customizeWorkshopEmployeeSettings.CustomizeRotatingShifts); if (firstShift == null) { firstShift = shift; } TimeSpan effectiveLate = rc.LateEntryDuration; var minutes = effectiveLate.TotalMinutes; if (minutes >= minuteThresholdForLateEntryFine) { lateEntryFineTimes ++; lateEntryFine += lateEntryFineAmount; } totalLateToWorkSpan = totalLateToWorkSpan.Add(effectiveLate); lateToWorkDeduction += dayMinuteWage * minutes; TimeSpan effectiveEarlyExit = rollCall.TotalEarlyExitDuration; if (effectiveEarlyExit.TotalMinutes > minuteThresholdForEarlyExitCalculation) { earlyExitDeduction += dayMinuteWage * effectiveEarlyExit.TotalMinutes; } } } } else { foreach (var rollCall in groupedRollCall) { var rollCallShift = rollCall.TotalShiftDurationTimeSpan; var dayMinuteWage = rollCallShift.TotalMinutes == 0 ? 0 : (dailyWage / rollCallShift.TotalMinutes); TimeSpan effectiveLate = rollCall.TotalLateEntryDuration; var minutes = effectiveLate.TotalMinutes; if (minutes >= minuteThresholdForLateEntryFine) { lateEntryFineTimes ++; lateEntryFine += lateEntryFineAmount; } lateToWorkDeduction += dayMinuteWage * minutes; totalLateToWorkSpan = totalLateToWorkSpan.Add(effectiveLate); TimeSpan effectiveEarlyExit = rollCall.TotalEarlyExitDuration; if (effectiveEarlyExit.TotalMinutes > minuteThresholdForEarlyExitCalculation) { earlyExitDeduction += dayMinuteWage * effectiveEarlyExit.TotalMinutes; } } } dynamicdeductions.Add(new() { Amount = lateEntryFine.ToMoney(), Name = "جریمه 40 تومانی", Count = lateEntryFineTimes }); // if (mandatoryDays == 31) // { // mandatoryDays = 30; // } #endregion # region جریمه افراد غایبی که بیمه هستند var leftWorkInsurance = _context.LeftWorkInsuranceList .FirstOrDefault(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId &&(( x.StartWorkDate <= contractEnd && x.LeftWorkDate >= contractStart) || (x.LeftWorkDate == null && x.StartWorkDate <= contractEnd))); if (leftWorkInsurance != null && absenceDays >0) { absenceForInsuranceFine = absenceDays * absenceForInsuranceEmployeesAmount; absenceForInsuranceDays = absenceDays; dynamicdeductions.Add(new CheckoutDynamicDeductionItem { Amount = absenceForInsuranceFine.ToMoney(), Name = "جریمه بیمه", Count = absenceForInsuranceDays }); } #endregion #region اگر که پرسنل در روز های جمعه یا پنجشنبه غیبت داشت یک روز به غیبت اضافه شود //این منطق زمانی برقرار هست که مرخصی در اون روز نداشته باشه // ساخت لیست روزهای بین شروع و پایان قرارداد var contractDaysList = Enumerable.Range(0, (contractEnd - contractStart).Days + 1) .Select(offset => contractStart.AddDays(offset)) .ToList(); // کم کردن روزهایی که حضور دارند var absentDaysList = contractDaysList .Where(date => !groupedRollCall.Any(g => g.ShiftDate.Date == date.Date)) .ToList(); var absentFridaysOrThursdays = absentDaysList .Where(date => date.DayOfWeek is DayOfWeek.Friday or DayOfWeek.Thursday) .ToList(); var leaveList = _context.LeaveList .Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.IsAccepted == true && x.StartLeave <= contractEnd && x.EndLeave >= contractStart && x.LeaveType == "استحقاقی" && x.PaidLeaveType =="روزانه") .Select(x => new { x.StartLeave, x.EndLeave }) .ToList(); // بررسی کدام روزهای غایب جمعه/پنجشنبه در بازه مرخصی قرار ندارند var absentFridaysOrThursdaysWithoutLeave = absentFridaysOrThursdays .Where(date => !leaveList.Any(leave => date.Date >= leave.StartLeave.Date && date.Date <= leave.EndLeave.Date)) .ToList(); // تعداد روزهای غایب جمعه/پنجشنبه بدون مرخصی int absentFridaysOrThursdaysWithoutLeaveCount = absentFridaysOrThursdaysWithoutLeave.Count; absentsDeductionAmount += absentFridaysOrThursdaysWithoutLeaveCount * dailyWage; #endregion return new CustomizeCheckoutMandatoryViewModel { InsuranceDeduction = Math.Truncate(insuranceDeductionAmount), FridayPay = Math.Truncate(fridayPayAmount), OverTimePay = Math.Truncate(overtimePayAmount), BaseYearsPay = Math.Truncate(baseYearsPayAmount), NightWorkPay = Math.Truncate(nightworkPayAmount), MarriedAllowance = Math.Truncate(maritalAllowancePay), FamilyAllowance = Math.Truncate(familyAllowancePay), LeavePay = Math.Truncate(leavePayAmount), FineAbsenceDeduction = Math.Truncate(absentsDeductionAmount), BonusesPay = Math.Truncate(bonusesPayAmount), ContractEndFa = contractEnd.ToFarsi(), ContractStartFa = contractStart.ToFarsi(), EmployeeName = employee.FullName, InstallmentDeduction = Math.Truncate(loanDeduction), SalaryAidDeduction = Math.Truncate(salaryAidDeduction), FineDeduction = Math.Truncate(fineDeduction), RewardPay = Math.Truncate(rewardPay), Month = monthOfCheckout, Year = yearOfCheckout, LateToWorkDeduction = Math.Truncate(lateToWorkDeduction), EarlyExitDeduction = earlyExitDeduction, ShiftPay = 0, TaxDeduction = 0, EmployeeId = employeeId, SumOfWorkingDays = totalDays.ToString(), ContractNo = contract?.ContractNo ?? "-", MonthlySalary = dailyWage * mandatoryDays, PersonnelCode = personnelCode, FineViewModels = fineViewModels, InstallmentViewModels = loanInstallments, SalaryAidViewModels = salaryAidViewModel, RewardViewModels = rewardViewModels, LateToWorkValue = totalLateToWorkSpan, SettingSalary = customizeWorkshopEmployeeSettings.Salary, DailyWage = dailyWage, ShiftStatus = customizeWorkshopEmployeeSettings.WorkshopShiftStatus, IrregularShift = customizeWorkshopEmployeeSettings.IrregularShift, CustomizeRotatingShifts = customizeWorkshopEmployeeSettings.CustomizeRotatingShifts, EmployeeSettingsShifts = customizeWorkshopEmployeeSettings.CustomizeWorkshopEmployeeSettingsShifts .Select(x => (CustomizeSifts)x).ToList(), DynamicDeductions = dynamicdeductions, }; } public List RewardForCheckout(long employeeId, long workshopId, DateTime checkoutEnd, DateTime checkoutStart) { var result = _context.Rewards.Where(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId && x.GrantDate <= checkoutEnd && x.GrantDate >= checkoutStart).Select(x => new RewardViewModel { Title = x.Title, Amount = x.Amount.ToMoney(), AmountDouble = x.Amount, Description = x.Description, GrantDateGr = x.GrantDate, GrantDateFa = x.GrantDate.ToFarsi(), IsActive = x.IsActive, Id = x.id }).ToList(); return result; } private List FinesForCheckout(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { return _context.Fines.Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.FineDate >= contractStart && x.FineDate <= contractEnd && x.IsActive == IsActive.True).Select(x => new FineViewModel() { IsActive = x.IsActive, Amount = x.Amount.ToMoney(), FineDate = x.FineDate.ToFarsi(), Id = x.id, Title = x.Title, EmployeeId = x.EmployeeId, CreationDate = x.CreationDate.ToFarsi() }).ToList(); } public List LoanInstallmentForCheckout(long employeeId, long workshopId, DateTime contractStart, DateTime contractEnd) { return _context.Loans .Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId) .SelectMany(x => x.LoanInstallments) .Where(i => i.InstallmentDate >= contractStart && i.InstallmentDate <= contractEnd && i.IsActive == IsActive.True) .Select(x => new LoanInstallmentViewModel() { Id = x.Id, Month = x.Month, IsActive = x.IsActive, Amount = x.AmountForMonth.ToMoney(), Year = x.Year, AmountDouble = x.AmountForMonth, RemainingAmount = _context.Loans.SelectMany(l => l.LoanInstallments).Where(i => i.LoanId == x.LoanId && i.IsActive == IsActive.True && i.InstallmentDate > x.InstallmentDate) .Sum(i => i.AmountForMonth).ToMoney(), LoanAmount = _context.Loans.FirstOrDefault(l => l.id == x.LoanId).Amount.ToMoney() }).ToList(); } public List SalaryAidsForCheckout(long employeeId, long workshopId, DateTime checkoutStart, DateTime checkoutEnd) { return _context.SalaryAids .Where(x => x.CalculationDate >= checkoutStart && x.CalculationDate <= checkoutEnd && x.EmployeeId == employeeId && x.WorkshopId == workshopId).Select(x => new SalaryAidViewModel() { Amount = x.Amount.ToMoney(), AmountDouble = x.Amount, SalaryAidDateTimeFa = x.SalaryAidDateTime.ToFarsi(), SalaryAidDateTimeGe = x.SalaryAidDateTime, CalculationDateTimeGe = x.CalculationDate, CalculationDateTimeFa = x.CalculationDate.ToFarsi(), Id = x.id }).ToList(); } private void CreateRewardForBirthDay(long employeeId, long workshopId, double amount, int month, int year, DateTime contractStart) { var start = $"{year}/{month:00}/01".ToGeorgianDateTime(); var end = $"{year}/{month:00}/01".FindeEndOfMonth().ToGeorgianDateTime(); if (_context.Rewards.Any(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId && x.GrantDate >= start && x.GrantDate <= end && x.RewardType == RewardType.CreatedByCheckoutForBirthDay) == false) { var reward = new Reward(employeeId, workshopId, amount, "", 0, UserType.System, contractStart, "هدیه تولد", RewardType.CreatedByCheckoutForBirthDay); _context.Rewards.Add(reward); _context.SaveChanges(); } } private void CreateReward(long employeeId, long workshopId, double amount, int month, int year, DateTime contractStart, RewardType type, string title) { var start = $"{year}/{month:00}/01".ToGeorgianDateTime(); var end = $"{year}/{month:00}/01".FindeEndOfMonth().ToGeorgianDateTime(); if (_context.Rewards.Any(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId && x.GrantDate >= start && x.GrantDate <= end && x.RewardType == type) == false) { var reward = new Reward(employeeId, workshopId, amount, "", 0, UserType.System, contractStart, title, type); _context.Rewards.Add(reward); _context.SaveChanges(); } } //private void CreateRewardForChahardah(long employeeId, long workshopId, double amount, int month, int year, // DateTime contractStart) //{ // var start = $"{year}/{month:00}/01".ToGeorgianDateTime(); // var end = $"{year}/{month:00}/01".FindeEndOfMonth().ToGeorgianDateTime(); // if (_context.Rewards.Any(x => x.WorkshopId == workshopId && x.EmployeeId == employeeId // && x.GrantDate >= start && x.GrantDate <= end // && x.RewardType == RewardType.ChahardahFarvardin) == false) // { // var reward = new Reward(employeeId, workshopId, amount, "", 0, contractStart, "بابت تعطیلی روز 14 فروردین", // RewardType.ChahardahFarvardin); // _context.Rewards.Add(reward); // _context.SaveChanges(); // } //} private TimeSpan CalculateIrregularOverTime(List rollCalls, TimeSpan employeeShiftSpan, WorkshopIrregularShifts irregularShifts, int mandatoryDays) { var sumOfRollCallTicks = rollCalls.Sum(x => (x.EndDate.Value - x.StartDate.Value).Ticks); var sumRollCall = new TimeSpan(sumOfRollCallTicks); var sumOfShift = employeeShiftSpan * mandatoryDays; if (sumOfShift > sumRollCall) return TimeSpan.Zero; return sumRollCall - sumOfShift; } public static TimeSpan CalculateIrregularShiftSpans(int totalDays, IrregularShift irregularShift) { //مبنای تقسیم که بر اساس جمع مقدار ساعت استراحت و ساعت کاری بدست میاد double baseDivideTime = 0; //مقدار ساعت کارکرد در هر شیفت double workTime = 0; switch (irregularShift.WorkshopIrregularShifts) { case WorkshopIrregularShifts.TwelveThirtySix: baseDivideTime = 48; workTime = 12; break; case WorkshopIrregularShifts.TwelveTwentyFour: baseDivideTime = 36; workTime = 12; break; case WorkshopIrregularShifts.TwentyFourFortyEight: baseDivideTime = 72; workTime = 24; break; case WorkshopIrregularShifts.TwentyFourTwentyFour: baseDivideTime = 48; workTime = 24; break; } //کل ساعاتی داخلش ممکنه کار کرده باشه var workingHour = totalDays * 24; //مقدار تعداد خالصی که سر شیفت بوده است int countOfWorking = (int)(workingHour / baseDivideTime); //باقی مونده تعدادی که سر شیفت بوده است double fractionalPart = (workingHour / baseDivideTime) - countOfWorking; //مقدار ساعت خالصی که سر کار بوده است TimeSpan sumOfEmployeeWorkingHours = TimeSpan.FromHours(countOfWorking * workTime); //مقدار احتمال سر کار بودن بر حسب باقی مونده تقسیم var workingTimesDiff = fractionalPart * workTime; workingTimesDiff = workingTimesDiff >= workTime ? workTime : workingTimesDiff; //جمع ساعات خالصی و احتمالی sumOfEmployeeWorkingHours = sumOfEmployeeWorkingHours.Add(TimeSpan.FromHours(workingTimesDiff)); return sumOfEmployeeWorkingHours; } public static TimeSpan CalculateIrregularShift(IrregularShift irregularShift) { var workingTime = 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() }; return workingTime; } public static TimeSpan CalculateRotatingOvertime(ICollection rotatingShifts, List rollCalls, int mandatoryDays, TimeSpan sumSpan) { TimeSpan mandatorySpan = TimeSpan.Zero; foreach (var groupedRollCall in rollCalls) { var findRotatingShift = FindRotatingShift(groupedRollCall.ShiftList.Min(x => x.Start), groupedRollCall.ShiftList.Max(x => x.End), rotatingShifts); var span = findRotatingShift.end - findRotatingShift.start; mandatorySpan += span; } var leftDays = mandatoryDays - rollCalls.Count; if (leftDays > 0) { TimeSpan totalDuration = new TimeSpan(rotatingShifts.Sum(shift => Math.Abs(shift.EndTime.Ticks - shift.StartTime.Ticks))); var averageDuration = totalDuration / rotatingShifts.Count; mandatorySpan += averageDuration * leftDays; } if (mandatorySpan < sumSpan) { return sumSpan - mandatorySpan; } return TimeSpan.Zero; } #region CustomizeCheckoutCalculation public static double FridayPayCalculation(CustomizeWorkshopEmployeeSettings customizeWorkshopEmployeeSettings, List rollCallResult, double dailyWage, ICollection shiftSettings, double overtimePayAmount) { double fridayPayAmount = 0; switch (customizeWorkshopEmployeeSettings.FridayPay.FridayPayType) { case (FridayPayType.MoneyPerFridayForDay): { int workedFridaysCount = CalculateFridayWorkingTotalDays(rollCallResult); double baseAmount = customizeWorkshopEmployeeSettings.FridayPay.Value; fridayPayAmount = baseAmount * workedFridaysCount; break; } case (FridayPayType.MoneyPerFridayPerHour): { int workedFridaysMinutes = (int)CalculateFridayWorkingTimeSpan(rollCallResult).TotalMinutes; double baseAmount = customizeWorkshopEmployeeSettings.FridayPay.Value; fridayPayAmount = (baseAmount / 60) * workedFridaysMinutes; break; } case (FridayPayType.PercentageFromSalaryPerHour): { int workedFridaysMinutes = (int)CalculateFridayWorkingTimeSpan(rollCallResult).TotalMinutes; double percentageAmount = (customizeWorkshopEmployeeSettings.FridayPay.Value / 100 * dailyWage); fridayPayAmount = (percentageAmount / 60) * workedFridaysMinutes; break; } //case (FridayPayType.ExtraWorking): // { // var fridayOvertimeTimeSpan = CalculateFridayWorkingTimeSpanWithoutOvertime(rollCallResult, shiftSettings); // overtimePayAmount += CalculateOvertimePay(fridayOvertimeTimeSpan, customizeWorkshopEmployeeSettings.OverTimePay, dailyWage); // return overtimePayAmount; // break; // } default: break; } return fridayPayAmount; } public double InsurancePayCalculation(long employeeId, DateTime contractStart, DateTime contractEnd, InsuranceDeduction insuranceDeduction, double monthySalary) { double insurancePayAmount = 0; switch (insuranceDeduction.InsuranceDeductionType) { case InsuranceDeductionType.BasedOnLaborLaw: //farokhiChange double familyAllowance = _yearlySalaryRepository.FamilyAllowance(employeeId, contractStart, contractEnd) .MoneyToDouble(); double housingAllowance = _yearlySalaryRepository.HousingAllowance(contractEnd).MoneyToDouble(); double consumableItemsAllowance = _yearlySalaryRepository.ConsumableItems(contractEnd).MoneyToDouble(); double wage = _context.YearlySalaries.Include(x => x.YearlySalaryItemsList) .FirstOrDefault(x => x.StartDate <= contractEnd && x.EndDate <= contractEnd).YearlySalaryItemsList .FirstOrDefault(x => x.ItemName == "مزد روزانه").ItemValue; insurancePayAmount = (familyAllowance + housingAllowance + consumableItemsAllowance + wage) * 7 / 100; break; case InsuranceDeductionType.PercentageOfSalary: double multiplier = insuranceDeduction.Value / 100; insurancePayAmount = monthySalary * multiplier; break; case InsuranceDeductionType.Money: double baseAmount = insuranceDeduction.Value; insurancePayAmount = baseAmount; break; case InsuranceDeductionType.None: break; default: insurancePayAmount = 0; break; } return insurancePayAmount; } public static TimeSpan CalculateLeavePay(TimeSpan sumOfEmployeeShiftSpan, TimeSpan absentsTimeSpan, int permittedLeaveDay, int monthDays, int contractDays, TimeSpan sumSpans, double leaveValue, double minuteWage, DateTime startDate, DateTime endDate, out double leavePayAmount, out double absentsDeduction) { // زمان مجاز مرخصی TimeSpan permittedLeaveTimeSpan = sumOfEmployeeShiftSpan * permittedLeaveDay; // زمان مرخصی مجاز برای یک روز TimeSpan leaveTimePerDay = (permittedLeaveTimeSpan / monthDays); //اگر ترک کار کرده بود if (contractDays < monthDays) { permittedLeaveTimeSpan = leaveTimePerDay * contractDays; } //اگر قراردادش کامل بود else { } //اختلاف غیبت و مرخصی (TimeSpan Diffrence, AbsentOrLeave absentOrLeave) absentAndLeaveDifference; //مقدار مبلغ مرخصی leavePayAmount = 0; //مقدار مبلغ غیبت absentsDeduction = 0; //#region SumLeaves //var usedLeavesCheckout = new TimeSpan(); //foreach (var item in leaveList) //{ // var start = new DateTime(); // var end = new DateTime(); // start = item.StartLeaveGr < startDate ? startDate : item.StartLeaveGr; // end = item.EndLeaveGr > endDate ? endDate : item.EndLeaveGr; // if (item.PaidLeaveType == "روزانه") // { // var leaveSpan = (end - start); // usedLeavesCheckout = usedLeavesCheckout.Add(leaveSpan); // } // else // { // var leavingHourses = TimeSpan.Parse(item.LeaveHourses); // usedLeavesCheckout = usedLeavesCheckout.Add(leavingHourses); // } //} //#endregion //if (permittedLeaveTimeSpan >= usedLeavesCheckout) //{ // permittedLeaveTimeSpan = permittedLeaveTimeSpan - usedLeavesCheckout; // sumSpans += usedLeavesCheckout; // usedLeavesCheckout = new TimeSpan(); //} //else //{ // sumSpans += permittedLeaveTimeSpan; // absentsTimeSpan = (absentsTimeSpan - usedLeavesCheckout) - permittedLeaveTimeSpan; // permittedLeaveTimeSpan = new TimeSpan(); //} //اگر مقدار مجاز مرخصی بیشتر از غیبت یا مساوی باشد if (permittedLeaveTimeSpan >= absentsTimeSpan) { //محاسبه مقدار باقی مانده مزد مرخصی absentAndLeaveDifference.Diffrence = permittedLeaveTimeSpan - absentsTimeSpan; absentAndLeaveDifference.absentOrLeave = AbsentOrLeave.LeavePay; //صفر کردن مقدار غیبت absentsTimeSpan = new TimeSpan(0); ////برگرداندن ساعت کاری باقی مونده از مزد مرخصی به ساعت کاری //sumSpans += absentAndLeaveDifference.Diffrence; //مقدار مزد مرخصی برای هرروز استفاده نشده double leavePayPerDayWage = (leaveValue * (minuteWage * sumOfEmployeeShiftSpan.TotalMinutes)); if (permittedLeaveTimeSpan.TotalHours == 0) return sumSpans; leavePayAmount = (leavePayPerDayWage / permittedLeaveTimeSpan.TotalMinutes) * absentAndLeaveDifference.Diffrence.TotalMinutes; } //اگر مقدار غیبت بیشتر از مرخصی باشد else { //محاسبه مقدار باقی مانده از غیبت absentAndLeaveDifference.Diffrence = absentsTimeSpan - permittedLeaveTimeSpan; absentAndLeaveDifference.absentOrLeave = AbsentOrLeave.AbsentDeduction; //صفر کردن مقدار مزد مرخصی permittedLeaveTimeSpan = new TimeSpan(0); permittedLeaveDay = 0; ////برگرداندن ساعت کاری باقی مونده از مزد مرخصی به ساعت کاری //sumSpans += permittedLeaveTimeSpan; absentsDeduction = absentsTimeSpan.TotalMinutes * minuteWage; } return sumSpans; } /// /// محاسبه تاخیر در ورورد و تعجیل در خروج /// /// /// /// public List LateToWorkEarlyExit(List groupedRollCall, ICollection shiftSettings, List leavList) { List lateToWorkEarlyExistSpannig = new List(); foreach (var day in groupedRollCall) { foreach (var shift in shiftSettings) { //DateTime start = DateTime.Parse(shift.StartTime); //DateTime end = DateTime.Parse(shift.EndTime); DateTime startShift = new DateTime(day.CreationDate.Year, day.CreationDate.Month, day.CreationDate.Day, shift.StartTime.Hour, shift.StartTime.Minute, 0); DateTime endShift = new DateTime(day.CreationDate.Year, day.CreationDate.Month, day.CreationDate.Day, shift.EndTime.Hour, shift.EndTime.Minute, 0); if (shift.StartTime > shift.EndTime) endShift = endShift.AddDays(1); //اگر در بازه شیف تعیین شده حضور غیاب داشت var hasRollCall = day.ShiftList.Where(x => (x.Start <= startShift && x.End > startShift) || (x.Start >= startShift && x.End <= endShift) || (x.Start > startShift && x.End > endShift)).ToList(); if (!hasRollCall.Any()) // اگر در بازه شیفت هیچ حضور غیابی نداشت { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = startShift, EndSpan = endShift, Spanning = (endShift - startShift), TypeOfSapn = shift.Placement == ShiftPlacement.First ? "LateToWork" : "EarlyExist" }); } else if (hasRollCall.Count() == 1) { var singleHasRollCall = hasRollCall.FirstOrDefault(); if (singleHasRollCall != null && singleHasRollCall.Start > startShift && singleHasRollCall.End >= endShift) { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = startShift, EndSpan = singleHasRollCall.Start, Spanning = (singleHasRollCall.Start - startShift), TypeOfSapn = "LateToWork" }); } else if (singleHasRollCall != null && singleHasRollCall.Start <= startShift && singleHasRollCall.End < endShift) { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = singleHasRollCall.End, EndSpan = endShift, Spanning = (endShift - singleHasRollCall.End), TypeOfSapn = "EarlyExist" }); } else if (singleHasRollCall != null && singleHasRollCall.Start > startShift && singleHasRollCall.End < endShift) { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = startShift, EndSpan = singleHasRollCall.Start, Spanning = (singleHasRollCall.Start - startShift), TypeOfSapn = "LateToWork" }); lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = singleHasRollCall.End, EndSpan = endShift, Spanning = (endShift - singleHasRollCall.End), TypeOfSapn = "EarlyExist" }); } } else if (hasRollCall.Count() > 1) { var multiHasRollCall = hasRollCall.OrderBy(x => x.Start); var firstRollcall = multiHasRollCall.First(); var lastRollCall = multiHasRollCall.Last(); if (firstRollcall.Start > startShift && firstRollcall.End >= endShift) { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = startShift, EndSpan = firstRollcall.Start, Spanning = (firstRollcall.Start - startShift), TypeOfSapn = "LateToWork" }); } if (lastRollCall.Start <= startShift && lastRollCall.End < endShift) { lateToWorkEarlyExistSpannig.Add(new LateToWorkEarlyExistSpannig() { StartSpan = lastRollCall.End, EndSpan = endShift, Spanning = (endShift - lastRollCall.End), TypeOfSapn = "EarlyExist" }); } } } } leavList = leavList.Where(x => x.PaidLeaveType == "ساعتی").ToList(); // اگر تاخیر یا تعجیل به دلیل مرخصی ساعتی بود حساب نشود if (leavList.Count > 0 && lateToWorkEarlyExistSpannig.Count > 0) { foreach (var el in lateToWorkEarlyExistSpannig.ToList()) { var hasLeve = leavList.Any(x => (x.StartLeaveGr <= el.StartSpan && x.EndLeaveGr > el.StartSpan) || (x.StartLeaveGr >= el.StartSpan && x.EndLeaveGr <= el.EndSpan) || (x.StartLeaveGr > el.StartSpan && x.EndLeaveGr > el.EndSpan)); if (hasLeve) lateToWorkEarlyExistSpannig.Remove(el); } } return lateToWorkEarlyExistSpannig; } #region Pooya public double CalculateFamilyAllowancePayAmount(long employeeId, double basePay, DateTime contractEnd) { int underageChildrenCount = _context.EmployeeChildrenSet.Where(x => x.EmployeeId == employeeId && x.DateOfBirth.AddYears(18) > contractEnd) .Count(); return basePay * underageChildrenCount; } //Deprecated private TimeSpan CalculateOvertimeTimeSpanWithThreshold(List rollCalls, ICollection shiftSettings, int overtimeThresholdMinutes) { var mandatoryTotalTimeSpan = new TimeSpan(shiftSettings.Sum(x => (x.EndTime - x.StartTime).Ticks)); mandatoryTotalTimeSpan += new TimeSpan(0, overtimeThresholdMinutes, 0); var rollCallsTimeSpans = rollCalls.Select(x => x.EndDate.Value - x.StartDate.Value) .Where(x => x > mandatoryTotalTimeSpan).ToList(); var rollCallTotalTimeSpan = new TimeSpan(rollCallsTimeSpans.Sum(x => x.Ticks)); if (rollCallTotalTimeSpan < mandatoryTotalTimeSpan) return TimeSpan.Zero; return rollCallTotalTimeSpan - mandatoryTotalTimeSpan; } #region سنوات /// /// فرمول اصلی محاسبه سنوات برای پرسنل در بازه زمانی با تنظیمات پیشرفته /// /// حقوق ماهیانه پرسنل /// تنظیمات سنوات /// تنظیم مربوط به پرداخت هنگام ترک کار public double CalculateYearsPayAmount(long employeeId, long workshopId, double monthlySalary, DateTime contractStart, DateTime contractEnd, BaseYearsPay baseYearsSettings, BaseYearsPayInEndOfYear payOnLeave, MaxMonthDays maxMonthDays) { double baseYearPayAmount = 0; var leftWorks = _context.LeftWorkList .Where(x => x.EmployeeId == employeeId && x.WorkshopId == workshopId && x.LeftWorkDate.Date.AddDays(-1) >= contractStart && x.StartWorkDate.Date <= contractEnd) .ToList(); if (!leftWorks.Any()) return 0; int daysWorked = (int)new TimeSpan(leftWorks.Select(x => new { Start = x.StartWorkDate < contractStart ? contractStart : x.StartWorkDate, End = x.LeftWorkDate.AddDays(-1) > contractEnd ? contractEnd : x.LeftWorkDate.AddDays(-1) }).Sum(x => (x.End - x.Start).Ticks)).TotalDays + 1; bool hasLeftWork = leftWorks.MaxBy(x => x.LeftWorkDate).LeftWorkDate.AddDays(-1) < contractEnd; //محاسبه سنوات سالیانه switch (baseYearsSettings.BaseYearsPayType) { case BaseYearsPayType.PercentageOfSalary: { baseYearPayAmount = monthlySalary * baseYearsSettings.Value / 100; break; } case BaseYearsPayType.Money: { baseYearPayAmount = baseYearsSettings.Value; break; } case BaseYearsPayType.None: { return 0; } } //در صورت ترک کار if (hasLeftWork) { switch (payOnLeave) { //اگر سنوات در آخر سال تعلق می گیرد ترک کار قبل از پایان دوره موجب صفر شدن آن میشود case BaseYearsPayInEndOfYear.EndOfYear: return 0; //اگر هنگام ترک کار سنوات تعلق می گیرد case BaseYearsPayInEndOfYear.WhenEverEmployeeLeftWork: { //بر اساس نوع پرداخت سالیانه یا ماهیانه سنوات محاسبه می گردد switch (baseYearsSettings.PaymentType) { case BaseYearsPaymentType.MonthlyPay: { return CalculateYearsPayMonthlyByDays(baseYearPayAmount, daysWorked, contractStart.CountPersianMonthDays(), maxMonthDays); } case BaseYearsPaymentType.YearlyPay: { return CalculateYearsPayYearlyByDays(baseYearPayAmount, daysWorked); } default: return 0; } } } } //در صورت عدم ترک کار switch (baseYearsSettings.PaymentType) { case BaseYearsPaymentType.MonthlyPay: { return CalculateYearsPayMonthlyByDays(baseYearPayAmount, daysWorked, contractStart.CountPersianMonthDays(), maxMonthDays); } case BaseYearsPaymentType.YearlyPay: { string contractEndFa = contractEnd.ToFarsi(); bool isCheckoutForEsfand = contractEndFa.Substring(5, 2) == "12"; bool isContractEndOfMonth = contractEndFa.FindeEndOfMonth() == contractEndFa; //اگر آخر ماه نبود یا اسفند نبود سنوات سالیانه محاسبه نمی گردد if (isContractEndOfMonth == false || isCheckoutForEsfand == false) return 0; return CalculateYearsPayYearlyByDays(baseYearPayAmount, daysWorked); } default: return 0; } } /// /// محاسبه سنوات ماهیانه بر اساس روز های کارکرد /// /// سنوات در کل سال /// روز های کارکرد /// تعداد روز های ماه public static double CalculateYearsPayMonthlyByDays(double baseYears, int daysWorked, int totalDaysInMonth, MaxMonthDays maxMonthDays) { daysWorked = maxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth && daysWorked > 30 ? 30 : daysWorked; totalDaysInMonth = maxMonthDays == MaxMonthDays.ThirtyDaysForAllMonth ? 30 : totalDaysInMonth; return baseYears / 12 / totalDaysInMonth * daysWorked; } /// /// محاسبه سنوات سالیانه بر اساس روز های کارکرد /// /// سنوات در کل سال /// روز های کارکرد /// /// public static double CalculateYearsPayYearlyByDays(double baseYears, int daysWorked) { return baseYears / 365 * daysWorked; } #endregion //TODO: this must be updated with Mahan's method for leaves /// /// محاسبه مدت اضافه کاری /// public static TimeSpan CalculateOvertimeTimeSpan(List rollCalls, ICollection shiftSettings, TimeOnly employeeOffSet) { //for (DateTime offset = start; offset <= end; offset.AddDays(1)) //{ // DayOfWeek dayOfWeek = offset.DayOfWeek; // switch (dayOfWeek) // { // case DayOfWeek.Thursday: // shifts.Add(new ShiftViewModel { Start = offset.AddHours(9), End = offset.AddHours(14) }); // break; // case DayOfWeek.Friday: // break; // default: // shifts.Add(new ShiftViewModel { Start = offset.AddHours(8), End = offset.AddHours(16) }); // break; // } //} //if (!rollCalls.Any()) // return TimeSpan.Zero; //var startRollCall = rollCalls.MinBy(x => x.StartDate!.Value).StartDate!.Value; //var endRollCall = rollCalls.Max(x => x.EndDate)!.Value; //DateTime startDateTime = new DateTime(DateOnly.FromDateTime(startRollCall), employeeOffSet); //DateTime endDateTime = new DateTime(DateOnly.FromDateTime(endRollCall), employeeOffSet); //endDateTime = endDateTime == startDateTime ? endDateTime.AddDays(1) : endDateTime; var mandatoryPerDayTimeSpan = new TimeSpan(shiftSettings.Sum(x => (x.EndTime - x.StartTime).Ticks)); //bool isFirst = true; //var sumOfOverTime = TimeSpan.Zero; //for (var startDateOffset = startDateTime; startDateOffset <= endDateTime; startDateOffset = startDateOffset.AddDays(1)) //{ // IEnumerable rollCallViewModels; // var startPeriod = startDateOffset; // var endPeriod = startDateOffset.AddDays(1); // if (isFirst) // { // rollCallViewModels = rollCalls // .Where(x => x.StartDate.Value > startPeriod.Date && x.EndDate.Value <= endPeriod); // isFirst = false; // } // else // { // rollCallViewModels = rollCalls // .Where(x => x.StartDate.Value > startPeriod && x.EndDate.Value <= endPeriod); // } // var sum = rollCallViewModels.Sum(x => (x.EndDate.Value - x.StartDate.Value).Ticks); // var rollCallTimeSpan = new TimeSpan(sum); // if (rollCallTimeSpan > mandatoryPerDayTimeSpan) // { // var overTime = rollCallTimeSpan - mandatoryPerDayTimeSpan; // sumOfOverTime = sumOfOverTime.Add(overTime); // } //} //return sumOfOverTime; var groupedRollCalls = rollCalls.GroupBy(x => x.StartDate!.Value.Date); var rollCallsTimeSpans = groupedRollCalls.Where(x => x.Sum(y => (y.EndDate!.Value - y.StartDate!.Value).Ticks) > mandatoryPerDayTimeSpan.Ticks) .Select(x => x.Sum(y => (y.EndDate!.Value - y.StartDate!.Value).Ticks)).ToList(); var daysCount = rollCallsTimeSpans.Count(); var totalMandatoryTotalTimeSpan = mandatoryPerDayTimeSpan * daysCount; var rollCallTotalTimeSpan = new TimeSpan(rollCallsTimeSpans.Sum(x => x)); if (rollCallTotalTimeSpan < totalMandatoryTotalTimeSpan) return TimeSpan.Zero; return rollCallTotalTimeSpan - totalMandatoryTotalTimeSpan; } public static TimeSpan CalculateOvertimeSpanWithSumSpan(TimeSpan sumSpan, int mandatoryDays, ICollection shiftSettings) { var mandatoryPerDayTimeSpan = new TimeSpan(shiftSettings.Sum(x => (x.EndTime - x.StartTime).Ticks)); var mandatoryWorkingTimeSpan = mandatoryPerDayTimeSpan * mandatoryDays; if (mandatoryWorkingTimeSpan > sumSpan) return TimeSpan.Zero; return sumSpan - mandatoryWorkingTimeSpan; } /// /// محاسبه مبلغ اضافه کاری با استفاده از تنظیمات /// /// مدت اضافه کاری /// تنظیمات اضافه کاری /// مزد روزانه /// public static double CalculateOvertimePay(TimeSpan overtimeTimeSpan, OverTimePay overTimePaySettings, double dailyWage) { double baseAmount = overTimePaySettings.Value; double result = 0; switch (overTimePaySettings.OverTimePayType) { case OverTimePayType.None: break; case OverTimePayType.MoneyPerHour: { int totalMinutes = (int)overtimeTimeSpan.TotalMinutes; result = totalMinutes * (baseAmount / 60); break; } case OverTimePayType.PercentagePerHourOfSalary: { int totalMinutes = (int)overtimeTimeSpan.TotalMinutes; double multiplier = overTimePaySettings.Value / 100; result = ((dailyWage * multiplier) / 60) * totalMinutes; break; } } return result; } /// /// محاسبه مدت جمعه کاری بدون در نظر گرفتن اضافه کاری /// public static TimeSpan CalculateFridayWorkingTimeSpanWithoutOvertime(List rollCallsList, ICollection shiftSettings) { var _rollCallsList = rollCallsList; _rollCallsList = _rollCallsList.Where(x => x.StartDate.Value.DayOfWeek == DayOfWeek.Friday || x.EndDate.Value.DayOfWeek == DayOfWeek.Friday || (x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday && x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday)).ToList(); var preprocessedRollCalls = _rollCallsList.Select(x => new RollCallViewModel { StartDate = x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday ? x.StartDate.Value.AddDays(1).Date : x.StartDate.Value, EndDate = x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday ? x.EndDate.Value.Date : x.EndDate.Value }).ToList(); //var timeSpan = new TimeSpan(preprocessedRollCalls.Sum(x => (x.EndDate.Value - x.StartDate.Value).Ticks)); var extraWorkingTimeSpan = CalculateOvertimeTimeSpan(preprocessedRollCalls, shiftSettings, new TimeOnly()); var rollCallTimeSpan = CalculateFridayWorkingTimeSpan(preprocessedRollCalls); if (rollCallTimeSpan <= extraWorkingTimeSpan) return TimeSpan.Zero; return rollCallTimeSpan - extraWorkingTimeSpan; } /// /// محاسبه مدت جمعه کاری /// public static TimeSpan CalculateFridayWorkingTimeSpan(List rollCallsList) { var _rollCallsList = rollCallsList; _rollCallsList = _rollCallsList.Where(x => x.StartDate.Value.DayOfWeek == DayOfWeek.Friday || x.EndDate.Value.DayOfWeek == DayOfWeek.Friday || (x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday && x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday)).ToList(); var preprocessedRollCalls = _rollCallsList.Select(x => new { Start = x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday ? x.StartDate.Value.AddDays(1).Date : x.StartDate.Value, End = x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday ? x.EndDate.Value.Date : x.EndDate.Value }).ToList(); var timeSpan = new TimeSpan(preprocessedRollCalls.Sum(x => (x.End - x.Start).Ticks)); return timeSpan; } /// /// محاسبه روز های جمعه کاری /// public static int CalculateFridayWorkingTotalDays(List rollCallsList) { var _rollCallsList = rollCallsList; _rollCallsList = _rollCallsList.Where(x => x.StartDate.Value.DayOfWeek == DayOfWeek.Friday || x.EndDate.Value.DayOfWeek == DayOfWeek.Friday || (x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday && x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday)).ToList(); var preprocessedRollCalls = _rollCallsList.Select(x => new { Start = x.StartDate.Value.DayOfWeek == DayOfWeek.Thursday ? x.StartDate.Value.AddDays(1).Date : x.StartDate.Value, End = x.EndDate.Value.DayOfWeek == DayOfWeek.Saturday ? x.StartDate.Value.Date : x.EndDate.Value, ShiftDate = x.ShiftDate }).ToList(); int fridaysCount = preprocessedRollCalls.GroupBy(x => x.ShiftDate).Count(); return fridaysCount; } #endregion #endregion public static (DateTime start, DateTime end) FindRotatingShift(DateTime startRollCall, DateTime endRollCall, ICollection rotatingShifts) { DateTime startDate = startRollCall.Date; DateTime endDate = endRollCall.Date; DateTime startEntryWithDate = startDate.Add(startRollCall.TimeOfDay); DateTime endEntryWithDate = endDate.Add(endRollCall.TimeOfDay); DateTime twoHourBeforeStart = startEntryWithDate.AddHours(-2); DateTime twoHourAfterStart = startEntryWithDate.AddHours(2); DateTime twoHourBeforeEnd = endEntryWithDate.AddHours(-2); DateTime twoHourAfterEnd = endEntryWithDate.AddHours(2); 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; shiftStart = shiftStart.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 => // (twoHourBeforeStart <= shift.Start && twoHourAfterStart >= shift.Start) || // (twoHourBeforeStart <= shift.End && twoHourAfterStart >= 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 => // (twoHourBeforeEnd <= shift.Start && twoHourAfterEnd >= shift.Start) || // (twoHourBeforeEnd <= shift.End && twoHourAfterEnd >= shift.End)).ToList(); //if (endFilteredTimes.Count == 0) //{ // endFilteredTimes = startFilteredTimes; //} //else if (endFilteredTimes.Count == 1) //{ // var endChosenShift = endFilteredTimes.First(); // return endChosenShift; //} #endregion #region اشتراک حضور غیاب و شیفت var overlapShifts = shiftDateTimes .Select(shift => new { Shift = shift, Overlap = new TimeSpan(Math.Max(0, Math.Min(shift.End.Ticks, endRollCall.Ticks) - Math.Max(shift.Start.Ticks, startRollCall.Ticks))), // زمان حضور فرد در شیفت (مجموع Overlap با شیفت) TotalTimeInShift = new TimeSpan(Math.Max(0, Math.Min(shift.End.Ticks, endRollCall.Ticks) - Math.Max(shift.Start.Ticks, startRollCall.Ticks))), StartDistance = Math.Abs((shift.Start - startRollCall).Ticks), EndDistance = Math.Abs((shift.End - endRollCall).Ticks), TotalDistance = Math.Abs((shift.Start - startRollCall).Ticks) + Math.Abs((shift.End - endRollCall).Ticks) }) .OrderByDescending(s => s.TotalTimeInShift) // 1. بیشترین زمان حضور فرد .ThenByDescending(s => s.Overlap) // 2. بیشترین Overlap .ThenBy(s => s.TotalDistance) .ThenBy(s => s.StartDistance) .ThenBy(x => x.EndDistance); // 3. اگر برابر بود، Start نزدیک‌تر var overlapChosenShift = overlapShifts.First(); var end = overlapChosenShift.Shift.End; if (overlapChosenShift.Shift.End < overlapChosenShift.Shift.Start) end = overlapChosenShift.Shift.End.AddDays(1); return (overlapChosenShift.Shift.Start, end); #endregion } #endregion } enum AbsentOrLeave { LeavePay, AbsentDeduction } internal class EmployeeShiftResult { public ShiftPlacement Placement { get; set; } public TimeSpan ShiftSpan { get; set; } } internal class StaticShiftStartEnd { public DateTime StartShift { get; set; } public DateTime EndShift { get; set; } public TimeSpan ShiftSpanning { get; set; } public bool HasValue { get; set; } public string ShiftType { get; set; } }