Exemple #1
0
        /// <summary>
        /// Tính số ngày phép năm tích lũy được đến thời điểm currentMonth.
        /// </summary>
        /// <param name="currentMonth">Tháng đang xét</param>
        /// <param name="gradeCfg"></param>
        /// <param name="dateHire">Ngày vào làm của nhân viên.</param>
        /// <param name="dateEndProbation">Ngày kết thúc thử việc</param>
        /// <param name="dateQuit">Ngày nghỉ làm của nhân viên</param>
        /// <param name="monthStartAnnualLeave">Tháng bắt đầu tính phép năm.</param>
        /// <param name="initAnnualValue">Phép năm có sẵn từ trước</param>
        /// <param name="lstLeaveDay">DS nghỉ phép theo loại trong cấu hình từ đầu năm tới giờ</param>
        /// <returns></returns>
        public static Double GetAnnualLeaveReceive(int Year, DateTime currentMonth, Cat_GradeAttendance gradeCfg, DateTime? dateHire,
            DateTime? dateEndProbation, DateTime? dateQuit, int? monthStartAnnualLeave, double? initAnnualValue, Cat_Position pos, Hre_ProfileMultiField profile
            , List<Att_LeaveDayInfo> lstLeaveDay, List<Sys_AllSetting> lstAllSetting, List<Hre_HDTJob> lstHDTJob_ByProfile, List<DateTime> lstDayOff, List<Att_LeaveDayInfo> lstLeaveDayAllYear,string userLogin)
        {
            double result = 0;
            int Month = currentMonth.Month;
            Cat_JobTitle CatJobTitle = new Cat_JobTitle();
            if (profile.JobTitleID != null && profile.JobTitleID != Guid.Empty)
            {
                CatJobTitle = lstCatJobTitle.Where(s => s.ID == profile.JobTitleID).FirstOrDefault();
            }

            if (gradeCfg == null)
            {
                return result;
            }

            if (string.IsNullOrWhiteSpace(gradeCfg.FormulaAnnualLeave))
            {
                throw new Exception("Formula Annual Leave not found.");
            }

            //Lấy khoảng thời gian của kỳ lương
            DateTime dtStart, dtEnd;
            Att_AttendanceServices.GetSalaryDateRange(gradeCfg, null, null, currentMonth, out dtStart, out dtEnd);

            double totalDayAnnualLeaveOnYear = gradeCfg.TotalDayAnnualLeaveOnYear.Get_Integer();
            double seniority = GetAnnualBySeniority(currentMonth, dateHire, gradeCfg);
            string formulaAnnualLeave = gradeCfg.FormulaAnnualLeave;
            Formula formula = new Formula(formulaAnnualLeave);

            //đâsdasd



            #region abc
            #region Param
            lstHDTJob_ByProfile = lstHDTJob_ByProfile.Where(m => m.DateFrom != null && m.Type != null).OrderBy(m => m.DateFrom).ToList();
            ParamGetConfigANL paramConfig = new ParamGetConfigANL();
            //set du lieu
            GetConfigANL(lstAllSetting, out paramConfig);
            int monthBeginYear = paramConfig.monthBeginYear; //Tháng bắt đầu tính phép năm
            int dayBeginFullMonth = paramConfig.dayBeginFullMonth; //Ngày bắt đầu tính tròn ANL cho tháng
            int seniorMonth = paramConfig.seniorMonth; // Số tháng để có 1 level cho thâm niên
            int dayPerMonth = paramConfig.dayPerMonth; // Số ngày cho 1 tháng
            double anlRoundUp = paramConfig.anlRoundUp; //Số làm tròn Lên xuống
            string typeProfileBegin = paramConfig.typeProfileBegin; //Loại lấy theo DateHire hay DateQuit
            int maxInMonthToGetAct = paramConfig.maxInMonthToGetAct; //Ngày chuẩn để xét là DT4 và DT5 đc tính cho tháng àno
            double anlFullYear = paramConfig.anlFullYear; // Số ngày phép bình thường cho 1 năm (tính theo tháng)
            double anlSeniorMoreThanNormal = paramConfig.anlSeniorMoreThanNormal; // Số ngày phép Được cộng thêm do thâm niên so với bình thường (tính theo tháng)
            double anlHDT4MoreThanNormal = paramConfig.anlHDT4MoreThanNormal; // Số ngày phép được cộng thêm do HDT4 so với bình thường (tính theo tháng)
            double anlHDT5MoreThanNormal = paramConfig.anlHDT5MoreThanNormal; // Số ngày phép được cộng thêm do HDT5 so với bình thường (tính theo tháng)
            List<string> lstCodeLeaveNonANL = paramConfig.lstCodeLeaveNonANL;
            int monthInYearSenior = paramConfig.monthInYearSenior;
            int monthRoundUp = paramConfig.monthRoundUp;
            #endregion
            #region Data
            //gan du lieu can thiet
            DateTime BeginYear = new DateTime(Year, monthBeginYear, 1);
            DateTime EndYear = BeginYear.AddYears(1).AddMinutes(-1);
            DateTime? DateCheckByMonth = null;
            if (Month != null)
            {
                DateCheckByMonth = new DateTime(Year, Month, 1);
                if (Month < monthBeginYear)
                {
                    DateCheckByMonth = new DateTime(Year + 1, Month, 1);
                }
            }
            DateTime? DateStartProfile = null;
            DateTime DateEndProfile = EndYear;
            if (typeProfileBegin == AnlProfileTypeBegin.E_DATE_ENDPROBATION.ToString())
            {
                DateStartProfile = dateEndProbation;
            }
            else
            {
                DateStartProfile = dateHire;
            }
            if (DateStartProfile == null)
                return 0;

            if (dateQuit != null && dateQuit < EndYear)
            {
                DateEndProfile = dateQuit.Value.Date.AddDays(1).AddMinutes(-1);
            }

            if (DateStartProfile.Value.Day > dayBeginFullMonth)
            {
                DateTime beginMonthOfDateTime = new DateTime(DateStartProfile.Value.Year, DateStartProfile.Value.Month, dayBeginFullMonth);
                bool IsAdd1Month = false;
                for (DateTime dateCheck = beginMonthOfDateTime; dateCheck < DateStartProfile.Value.Date; dateCheck = dateCheck.AddDays(1))
                {
                    if (!lstDayOff.Any(m => m == dateCheck))
                    {
                        IsAdd1Month = true;
                        break;
                    }
                }
                if (IsAdd1Month)
                {
                    DateStartProfile = new DateTime(DateStartProfile.Value.AddMonths(1).Year, DateStartProfile.Value.AddMonths(1).Month, 1);
                }
                else
                {
                    DateStartProfile = new DateTime(DateStartProfile.Value.Year, DateStartProfile.Value.Month, dayBeginFullMonth);

                }
            }
            DateTime DateStartInYear = BeginYear > DateStartProfile.Value ? BeginYear : DateStartProfile.Value;
            DateTime DateEndInYear = EndYear < DateEndProfile ? EndYear : DateEndProfile;
            List<HDTJobTypeRange> lstHDTJobContaint = new List<HDTJobTypeRange>();
            foreach (var item in lstHDTJob_ByProfile)
            {
                HDTJobTypeRange hdtJob = new HDTJobTypeRange();
                hdtJob.Type = item.Type;
                hdtJob.DateStart = item.DateFrom.Value;
                hdtJob.DateEnd = item.DateTo;
                lstHDTJobContaint.Add(hdtJob);
            }
            lstHDTJobContaint = lstHDTJobContaint.OrderByDescending(m => m.DateStart).ToList();
            DateTime DateBeFore = DateTime.MaxValue;
            foreach (var item in lstHDTJobContaint)
            {
                if (item.DateEnd == null)
                {
                    item.DateEnd = DateBeFore;
                }
                DateBeFore = item.DateStart;
            }
            #endregion
            //ANL_WORK_HDT4,
            //ANL_WORK_HDT5,
            if (DateCheckByMonth == null)
            {
                #region ANL and Leave
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_NORMAL.ToString()))
                {
                    double value = 0;
                    double monthWorkingNormalInYear = 0;

                    for (int i = 0; i < 12; i++)
                    {
                        if (DateStartInYear.AddMonths(i) < DateEndInYear)
                        {
                            monthWorkingNormalInYear++;
                        }
                        else
                        {
                            break;
                        }
                    }
                    value = anlFullYear * monthWorkingNormalInYear;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_NORMAL.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_SENIOR.ToString()))
                {
                    double value = 0;
                    int MonBegin = monthInYearSenior == 0 ? 1 : monthInYearSenior;
                    //--DateStartProfile
                    DateTime Monthyear = new DateTime(Year, MonBegin, 1);

                    double dateLeave = lstLeaveDayAllYear.Where(m => m.TotalDuration != null).Sum(m => m.TotalDuration.Value);
                    dateLeave += (lstLeaveDayAllYear.Where(m => m.TotalDuration == null).Sum(m => m.Duration) / 8);

                    DateTime dateRoundProfileStart = DateStartProfile.Value.AddMonths(-monthRoundUp);

                    double Days = (Monthyear - dateRoundProfileStart).TotalDays - dateLeave;
                    double YearSenior = Math.Round(Days / 365, MidpointRounding.AwayFromZero);
                    int level = (int)(YearSenior / (seniorMonth / 12));
                    value = level * anlSeniorMoreThanNormal * 12;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_SENIOR.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_LEAVE_NON_HAVEANL.ToString()))
                {
                    double value = 0;
                    //Logic: Vướng cai đầu năm cuối năm nên phải cắt cái ngày đó ra cho chính xác
                    double numLeave = 0;
                    foreach (var item in lstLeaveDay)
                    {
                        if (item.DateStart < DateStartInYear && item.DateEnd > DateStartInYear)
                        {
                            DateTime FirstSunday = DateTime.MinValue;
                            for (DateTime DateCheck = DateStartInYear; DateCheck < item.DateEnd; DateCheck = DateCheck.AddDays(1))
                            {
                                if (DateCheck.DayOfWeek == DayOfWeek.Sunday)
                                {
                                    FirstSunday = DateCheck;
                                    break;
                                }
                            }
                            int sundayCount = 0;
                            if (FirstSunday != DateTime.MinValue)
                            {
                                sundayCount = (int)((item.DateEnd - FirstSunday).TotalDays / 7) + 1;
                            }
                            int dayOffCount = lstDayOff.Select(m => m.Date >= DateStartInYear && m.Date < item.DateEnd).Count();
                            numLeave += (item.DateEnd - DateStartInYear).TotalDays - sundayCount - dayOffCount;

                        }
                        else if (item.DateStart < DateEndInYear && item.DateEnd > DateEndInYear)
                        {

                            DateTime FirstSunday = DateTime.MinValue;
                            for (DateTime DateCheck = item.DateStart; DateCheck < DateEndInYear; DateCheck = DateCheck.AddDays(1))
                            {
                                if (DateCheck.DayOfWeek == DayOfWeek.Sunday)
                                {
                                    FirstSunday = DateCheck;
                                    break;
                                }
                            }
                            int sundayCount = 0;
                            if (FirstSunday != DateTime.MinValue)
                            {
                                sundayCount = (int)((DateEndInYear - FirstSunday).TotalDays / 7) + 1;
                            }
                            int dayOffCount = lstDayOff.Select(m => m.Date >= item.DateStart && m.Date < DateEndInYear).Count();
                            numLeave += (item.DateEnd - DateStartInYear).TotalDays - sundayCount - dayOffCount;
                        }
                        else
                        {
                            numLeave += item.LeaveDays ?? 0;
                        }

                    }
                    value = ((int)(numLeave / dayPerMonth)) + ((numLeave % dayPerMonth) >= anlRoundUp ? 1 : 0);
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_LEAVE_NON_HAVEANL.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_WORK_HDT4.ToString()))
                {
                    double value = 0;
                    double monthCount = 0;
                    double dayCount = 0;
                    //thuat: 1. lây cái mới nhất so với ngày bắt đầu năm
                    //Lấy cái moi nhất nhỏ hơn ngày bắt đầu năm
                    string Lv4 = HDTJobType.E_Four.ToString();

                    List<HDTJobTypeRange> lstHDTJobContaintLV4 = lstHDTJobContaint.Where(m => m.Type == Lv4).ToList();
                    //Lấy ra 3 khoảng
                    //Đầu Năm
                    HDTJobTypeRange lstHDTJobContaintLV4_BeginYear = lstHDTJobContaintLV4.Where(m => m.DateStart < DateStartInYear && m.DateEnd != null && m.DateEnd.Value > DateStartInYear).FirstOrDefault();
                    //Trong Năm
                    List<HDTJobTypeRange> lstHDTJobContaintLV4_InYear = lstHDTJobContaintLV4.Where(m => m.DateStart >= DateStartInYear && m.DateEnd != null && m.DateEnd.Value <= DateEndInYear).ToList();
                    //Cuối Năm
                    HDTJobTypeRange lstHDTJobContaintLV4_EndYear = lstHDTJobContaintLV4.Where(m => m.DateStart < DateEndInYear && m.DateEnd != null && m.DateEnd.Value > DateEndInYear).FirstOrDefault();
                    bool isFullYear = false;
                    if (lstHDTJobContaintLV4_BeginYear != null && !isFullYear)
                    {
                        if (lstHDTJobContaintLV4_BeginYear.DateEnd.Value > DateEndInYear)
                        {
                            dayCount = (DateEndInYear - DateStartInYear).TotalDays;
                            isFullYear = true;
                        }
                        else
                        {
                            dayCount += (lstHDTJobContaintLV4_BeginYear.DateEnd.Value - DateStartInYear).TotalDays;
                        }
                    }
                    if (lstHDTJobContaintLV4_EndYear != null && !isFullYear)
                    {
                        if (lstHDTJobContaintLV4_EndYear.DateStart < DateStartInYear)
                        {
                            dayCount = (DateEndInYear - DateStartInYear).TotalDays;
                            isFullYear = true;
                        }
                        else
                        {
                            dayCount += (DateEndInYear - lstHDTJobContaintLV4_EndYear.DateStart).TotalDays;
                        }
                    }
                    if (!isFullYear)
                    {
                        foreach (var item in lstHDTJobContaintLV4_InYear)
                        {
                            dayCount += (item.DateEnd.Value - item.DateStart).TotalDays;
                        }
                    }
                    monthCount = ((int)(dayCount / dayPerMonth)) + (((dayCount % dayPerMonth) / dayPerMonth) >= anlRoundUp ? 1 : 0);
                    value = monthCount * anlHDT4MoreThanNormal;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_WORK_HDT4.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_WORK_HDT5.ToString()))
                {
                    double value = 0;
                    double monthCount = 0;
                    double dayCount = 0;
                    //thuat: 1. lây cái mới nhất so với ngày bắt đầu năm
                    //Lấy cái moi nhất nhỏ hơn ngày bắt đầu năm
                    string Lv5 = HDTJobType.E_Five.ToString();

                    List<HDTJobTypeRange> lstHDTJobContaintLV5 = lstHDTJobContaint.Where(m => m.Type == Lv5).ToList();
                    //Lấy ra 3 khoảng
                    //Đầu Năm
                    HDTJobTypeRange lstHDTJobContaintLV5_BeginYear = lstHDTJobContaintLV5.Where(m => m.DateStart < DateStartInYear && m.DateEnd != null && m.DateEnd.Value > DateStartInYear).FirstOrDefault();
                    //Trong Năm
                    List<HDTJobTypeRange> lstHDTJobContaintLV5_InYear = lstHDTJobContaintLV5.Where(m => m.DateStart >= DateStartInYear && m.DateEnd != null && m.DateEnd.Value <= DateEndInYear).ToList();
                    //Cuối Năm
                    HDTJobTypeRange lstHDTJobContaintLV5_EndYear = lstHDTJobContaintLV5.Where(m => m.DateStart < DateEndInYear && m.DateEnd != null && m.DateEnd.Value > DateEndInYear).FirstOrDefault();
                    bool isFullYear = false;
                    if (lstHDTJobContaintLV5_BeginYear != null && !isFullYear)
                    {
                        if (lstHDTJobContaintLV5_BeginYear.DateEnd.Value > DateEndInYear)
                        {
                            dayCount = (DateEndInYear - DateStartInYear).TotalDays;
                            isFullYear = true;
                        }
                        else
                        {
                            dayCount += (lstHDTJobContaintLV5_BeginYear.DateEnd.Value - DateStartInYear).TotalDays;
                        }
                    }
                    if (lstHDTJobContaintLV5_EndYear != null && !isFullYear)
                    {
                        if (lstHDTJobContaintLV5_EndYear.DateStart < DateStartInYear)
                        {
                            dayCount = (DateEndInYear - DateStartInYear).TotalDays;
                            isFullYear = true;
                        }
                        else
                        {
                            dayCount += (DateEndInYear - lstHDTJobContaintLV5_EndYear.DateStart).TotalDays;
                        }
                    }
                    if (!isFullYear)
                    {
                        foreach (var item in lstHDTJobContaintLV5_InYear)
                        {
                            dayCount += (item.DateEnd.Value - item.DateStart).TotalDays;
                        }
                    }

                    monthCount = ((int)(dayCount / dayPerMonth)) + (((dayCount % dayPerMonth) / dayPerMonth) >= anlRoundUp ? 1 : 0);
                    value = monthCount * anlHDT5MoreThanNormal;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_WORK_HDT5.ToString(), value);
                }
                #endregion
            }
            else
            {
                #region BHXH
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_NORMAL.ToString()))
                {
                    double value = 0;
                    if (DateStartInYear <= DateCheckByMonth)
                    {
                        value = anlFullYear;
                    }
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_NORMAL.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_SENIOR.ToString()))
                {
                    double value = 0;
                    int level = 0;

                    DateTime DateSenior = DateTime.MinValue;
                    for (int i = 0; i < 20; i++)
                    {
                        DateSenior = DateStartProfile.Value.AddMonths(seniorMonth);
                        if (DateSenior <= DateCheckByMonth)
                        {
                            level++;
                            continue;
                        }
                        else
                        {
                            break;
                        }
                    }
                    value = (level * anlSeniorMoreThanNormal);
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_SENIOR.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_WORK_HDT4.ToString()))
                {
                    double value = 0;
                    double monthCount = 0;
                    double dayCount = 0;
                    //thuat: 1. lây cái mới nhất so với ngày bắt đầu năm
                    //Lấy cái moi nhất nhỏ hơn ngày bắt đầu năm
                    string Lv4 = HDTJobType.E_Four.ToString();

                    DateTime DateStartMonth = DateCheckByMonth.Value;
                    DateTime DateEndMonth = DateStartMonth.AddMonths(1).AddMinutes(-1);

                    List<HDTJobTypeRange> lstHDTJobContaintLV4 = lstHDTJobContaint.Where(m => m.Type == Lv4).ToList();
                    //Lấy ra 3 khoảng
                    //Đầu Năm
                    HDTJobTypeRange lstHDTJobContaintLV4_BeginMonth = lstHDTJobContaintLV4.Where(m => m.DateStart < DateStartMonth && m.DateEnd != null && m.DateEnd.Value > DateStartMonth).FirstOrDefault();
                    //Trong Năm
                    List<HDTJobTypeRange> lstHDTJobContaintLV4_InMonth = lstHDTJobContaintLV4.Where(m => m.DateStart >= DateStartMonth && m.DateEnd != null && m.DateEnd.Value <= DateEndMonth).ToList();
                    //Cuối Năm
                    HDTJobTypeRange lstHDTJobContaintLV4_EndMonth = lstHDTJobContaintLV4.Where(m => m.DateStart < DateEndMonth && m.DateEnd != null && m.DateEnd.Value > DateEndMonth).FirstOrDefault();
                    bool isFullMonth = false;
                    if (lstHDTJobContaintLV4_BeginMonth != null && !isFullMonth)
                    {
                        if (lstHDTJobContaintLV4_BeginMonth.DateEnd.Value > DateEndMonth)
                        {
                            dayCount = (DateEndMonth - DateStartMonth).TotalDays;
                            isFullMonth = true;
                        }
                        else
                        {
                            dayCount += (lstHDTJobContaintLV4_BeginMonth.DateEnd.Value - DateStartMonth).TotalDays;
                        }
                    }
                    if (lstHDTJobContaintLV4_EndMonth != null && !isFullMonth)
                    {
                        if (lstHDTJobContaintLV4_EndMonth.DateStart < DateStartMonth)
                        {
                            dayCount = (DateEndMonth - DateStartMonth).TotalDays;
                            isFullMonth = true;
                        }
                        else
                        {
                            dayCount += (DateEndMonth - lstHDTJobContaintLV4_EndMonth.DateStart).TotalDays;
                        }
                    }
                    if (!isFullMonth)
                    {
                        foreach (var item in lstHDTJobContaintLV4_InMonth)
                        {
                            dayCount += (item.DateEnd.Value - item.DateStart).TotalDays;
                        }
                    }

                    monthCount = ((dayCount % dayPerMonth) >= anlRoundUp ? 1 : 0);
                    value = monthCount * anlHDT4MoreThanNormal;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_WORK_HDT4.ToString(), value);
                }
                if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ANL_WORK_HDT5.ToString()))
                {
                    double value = 0;
                    double monthCount = 0;
                    double dayCount = 0;
                    //thuat: 1. lây cái mới nhất so với ngày bắt đầu năm
                    //Lấy cái moi nhất nhỏ hơn ngày bắt đầu năm
                    string Lv5 = HDTJobType.E_Five.ToString();
                    DateTime DateStartMonth = DateCheckByMonth.Value;
                    DateTime DateEndMonth = DateStartMonth.AddMonths(1).AddMinutes(-1);
                    List<HDTJobTypeRange> lstHDTJobContaintLV5 = lstHDTJobContaint.Where(m => m.Type == Lv5).ToList();
                    //Lấy ra 3 khoảng
                    //Đầu Năm
                    HDTJobTypeRange lstHDTJobContaintLV5_BeginMonth = lstHDTJobContaintLV5.Where(m => m.DateStart < DateStartMonth && m.DateEnd != null && m.DateEnd.Value > DateStartMonth).FirstOrDefault();
                    //Trong Năm
                    List<HDTJobTypeRange> lstHDTJobContaintLV5_InMonth = lstHDTJobContaintLV5.Where(m => m.DateStart >= DateStartMonth && m.DateEnd != null && m.DateEnd.Value <= DateEndMonth).ToList();
                    //Cuối Năm
                    HDTJobTypeRange lstHDTJobContaintLV5_EndMonth = lstHDTJobContaintLV5.Where(m => m.DateStart < DateEndMonth && m.DateEnd != null && m.DateEnd.Value > DateEndMonth).FirstOrDefault();
                    bool isFullMonth = false;
                    if (lstHDTJobContaintLV5_BeginMonth != null && !isFullMonth)
                    {
                        if (lstHDTJobContaintLV5_BeginMonth.DateEnd.Value > DateEndMonth)
                        {
                            dayCount = (DateEndMonth - DateStartMonth).TotalDays;
                            isFullMonth = true;
                        }
                        else
                        {
                            dayCount += (lstHDTJobContaintLV5_BeginMonth.DateEnd.Value - DateStartMonth).TotalDays;
                        }
                    }
                    if (lstHDTJobContaintLV5_EndMonth != null && !isFullMonth)
                    {
                        if (lstHDTJobContaintLV5_EndMonth.DateStart < DateStartMonth)
                        {
                            dayCount = (DateEndMonth - DateStartMonth).TotalDays;
                            isFullMonth = true;
                        }
                        else
                        {
                            dayCount += (DateEndMonth - lstHDTJobContaintLV5_EndMonth.DateStart).TotalDays;
                        }
                    }
                    if (!isFullMonth)
                    {
                        foreach (var item in lstHDTJobContaintLV5_InMonth)
                        {
                            dayCount += (item.DateEnd.Value - item.DateStart).TotalDays;
                        }
                    }

                    monthCount = ((dayCount % dayPerMonth) >= anlRoundUp ? 1 : 0);
                    value = monthCount * anlHDT5MoreThanNormal;
                    formula.Parameters.Add(Formula.FormulaConstant.ANL_WORK_HDT5.ToString(), value);
                }
                #endregion
            }
            #endregion


            double AnnualDays = 0;
            if (profile != null && CatJobTitle != null)
            {
                AnnualDays = CatJobTitle.AnnualDays ?? 0;
            }

            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.INS_PROBATION.ToString()))
            {
                DateTime midDate = new DateTime(currentMonth.Year, currentMonth.Month, 15);
                bool isProbation = dateEndProbation.HasValue && dateEndProbation.Value > midDate;
                formula.Parameters.Add(Formula.FormulaConstant.INS_PROBATION.ToString(), isProbation.ToString());
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.TOTAL.ToString()))
            {
                formula.Parameters.Add(Formula.FormulaConstant.TOTAL.ToString(), totalDayAnnualLeaveOnYear);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.CURRENTYEAR.ToString()))
            {
                formula.Parameters.Add(Formula.FormulaConstant.CURRENTYEAR.ToString(), currentMonth.Year);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.TOTAL_LEAVE_BY_TYPE_IN_MONTH.ToString()))
            {

                if (ProfileCurrentID != profile.ID || dtEnd.Month == 1)
                {
                    _Num_TOTAL_LEAVE_BY_TYPE_IN_MONTH = 0;
                    ProfileCurrentID = profile.ID;
                }


                DateTime DateBeginMonth = dtStart;
                DateTime DateEndMonth = dtEnd;
                string E_FULLSHIFT = LeaveDayDurationType.E_FULLSHIFT.ToString();
                List<string> lstCodeLeave = lstCodeLeaveNonAnl;
                double Sum = 0;
                if (lstCodeLeave.Count > 0)
                {
                    Guid guidNewRelease = Guid.NewGuid();

                    string status = string.Empty;
                    BaseService baseService = new BaseService();
                    List<object> lst3ParamFT = new List<object>();
                    lst3ParamFT.Add(null);
                    lst3ParamFT.Add(DateBeginMonth);
                    lst3ParamFT.Add(DateEndMonth);
                    var dataAtt_LeaveDay = baseService.GetData<Att_LeaveDay>(lst3ParamFT, ConstantSql.hrm_att_getdata_LeaveDay_Inner, userLogin, ref status).ToList();
                    var lstLeaveTotalDuration = dataAtt_LeaveDay.Where(m => m.ProfileID == profile.ID
                        //&& m.DateStart <= DateEndMonth
                        //&& m.DateEnd >= DateBeginMonth
                         && m.DurationType == E_FULLSHIFT
                         && m.TotalDuration != null
                         && m.Cat_LeaveDayType != null
                         && lstCodeLeave.Contains(m.Cat_LeaveDayType.Code))
                        .Select(m => m.TotalDuration);
                    foreach (var item in lstLeaveTotalDuration)
                    {
                        if (item != null)
                        {
                            Sum += item.Value;
                        }
                    }
                    if (Sum > 13)
                        _Num_TOTAL_LEAVE_BY_TYPE_IN_MONTH = _Num_TOTAL_LEAVE_BY_TYPE_IN_MONTH + 1;
                    //EntityService.Instance.ReleaseContext(guidNewRelease);
                }
                formula.Parameters.Add(Formula.FormulaConstant.TOTAL_LEAVE_BY_TYPE_IN_MONTH.ToString(), _Num_TOTAL_LEAVE_BY_TYPE_IN_MONTH);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHHIRE.ToString()))
            {
                double monthHire = dateHire == null ? 1 : dateHire.Value.Month;
                formula.Parameters.Add(Formula.FormulaConstant.MONTHHIRE.ToString(), monthHire);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.YEARHIRE.ToString()))
            {
                int yearHire = dateHire != null ? dateHire.Value.Year : 0;
                formula.Parameters.Add(Formula.FormulaConstant.YEARHIRE.ToString(), yearHire);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.ADDITIONAL_ANNUAL.ToString()))
            {
                initAnnualValue = initAnnualValue.HasValue ? initAnnualValue.Value : 0;
                formula.Parameters.Add(Formula.FormulaConstant.ADDITIONAL_ANNUAL.ToString(), initAnnualValue.Value);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHENDPRO.ToString()))
            {
                #region Tháng kết thúc thử việc

                if (dateEndProbation.HasValue)
                {
                    DateTime fromDate = currentMonth.Date.AddDays(1 - currentMonth.Day);
                    DateTime toDate = fromDate.Date.AddMonths(1).AddSeconds(-1);
                    GetDuration(gradeCfg, currentMonth, out fromDate, out toDate);

                    int monthstart = dateEndProbation.Value.Month;
                    if (currentMonth.Year > dateEndProbation.Value.Year)
                    {
                        monthstart = monthStartAnnualLeave == null ? 1 : monthStartAnnualLeave.Value;
                    }
                    else if (currentMonth.Year == dateEndProbation.Value.Year)
                    {
                        monthstart = dateEndProbation.Value.Month;

                        if (dateEndProbation.Value.Day > 15)
                        {
                            monthstart++;
                        }

                        //Tháng đang xét nhỏ hơn tháng vào cty
                        if (currentMonth.Month < monthstart)
                        {
                            return 0;
                        }
                    }
                    else if (currentMonth.Year < dateEndProbation.Value.Year)
                    {
                        return 0;
                    }

                    formula.Parameters.Add(Formula.FormulaConstant.MONTHENDPRO.ToString(), monthstart);
                }

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHSTART_PROB.FormulaToString()))
            {
                #region Tháng bắt đầu thử việc

                DateTime dateTemp = DateTime.Now;
                if (dateEndProbation.HasValue)
                {
                    dateTemp = dateEndProbation.Value;
                }
                else if (dateHire.HasValue)
                {
                    dateTemp = dateHire.Value;
                }

                int monthstart = dateTemp.Month;
                if (currentMonth.Year > dateTemp.Year)
                {
                    monthstart = monthStartAnnualLeave == null ? 1 : monthStartAnnualLeave.Value;
                }
                else if (currentMonth.Year == dateTemp.Year)
                {
                    monthstart = dateTemp.Month;
                    if (dateTemp.Day > 15)
                    {
                        monthstart++;
                    }

                    //Trường hợp tháng vào cty nhỏn hơn tháng bắt đầu tính phép năm
                    if (monthStartAnnualLeave != null && monthstart < monthStartAnnualLeave.Value)
                    {
                        monthstart = monthStartAnnualLeave.Value;
                    }

                    //Tháng đang xét nhỏ hơn tháng vào cty
                    if (currentMonth.Month < monthstart)
                    {
                        return 0;
                    }
                }
                else if (currentMonth.Year < dateTemp.Year)
                {
                    return 0;
                }

                formula.Parameters.Add(Formula.FormulaConstant.MONTHSTART_PROB.ToString(), monthstart);

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHSTART2.FormulaToString()))
            {
                #region MONTHSTART2

                if (!dateHire.HasValue)
                {
                    return 0;
                }

                double monthstart = dateHire.Value.Month;
                if (currentMonth.Year > dateHire.Value.Year)
                {
                    monthstart = monthStartAnnualLeave == null ? 1 : monthStartAnnualLeave.Value;
                }
                else if (currentMonth.Year == dateHire.Value.Year)
                {
                    DateTime monthHirePro = dateHire.Value;
                    DateTime fromDate = currentMonth.Date.AddDays(1 - currentMonth.Day);
                    DateTime toDate = fromDate.Date.AddMonths(1).AddSeconds(-1);

                    Att_AttendanceServices.GetMonthSalary(gradeCfg, dateHire.Value, out monthHirePro);
                    Att_AttendanceLib.GetDuration(gradeCfg, monthHirePro, out fromDate, out toDate);
                    Double countDay = toDate.Date.Subtract(dateHire.Value.Date).TotalDays;

                    if (countDay <= 20 && countDay >= 10)
                    {
                        monthstart += 0.5;
                    }
                    else if (countDay < 10)
                    {
                        monthstart += 1;
                    }

                    //cung nam nhung thang dang xet nho hon thang vao cty
                    if (currentMonth.Month < dateHire.Value.Month)
                    {
                        return 0;
                    }
                }
                else if (currentMonth.Year < dateHire.Value.Year)
                {
                    return 0;
                }

                formula.Parameters.Add(Formula.FormulaConstant.MONTHSTART2.ToString(), monthstart);

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHSTART.FormulaToString()))
            {
                #region MONTHSTART

                if (dateHire != null)
                {
                    int monthstart = dateHire.Value.Month;
                    if (currentMonth.Year > dateHire.Value.Year)
                    {
                        monthstart = monthStartAnnualLeave == null ? 1 : monthStartAnnualLeave.Value;
                    }
                    else if (currentMonth.Year == dateHire.Value.Year)
                    {
                        monthstart = dateHire.Value.Month;
                        if (dateHire.Value.Day > 15)
                        {
                            monthstart++;
                        }

                        //cung nam nhung thang dang xet nho hon thang vao cty
                        if (currentMonth.Month < monthstart)
                        {
                            return 0;
                        }
                    }
                    else if (currentMonth.Year < dateHire.Value.Year)
                    {
                        return 0;
                    }

                    formula.Parameters.Add(Formula.FormulaConstant.MONTHSTART.ToString(), monthstart);
                }

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.TERMINATION.ToString()))
            {
                #region TERMINATION

                bool isTermination = dateQuit.HasValue && dateQuit.Value.Year == currentMonth.Year && dateQuit.Value.Month == currentMonth.Month;
                formula.Parameters.Add(Formula.FormulaConstant.TERMINATION.ToString(), isTermination);

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHEND.ToString()))
            {
                #region MONTHEND

                int monthEnd = 0;

                if (dateQuit.HasValue && dateQuit.Value.Year == currentMonth.Year)
                {
                    if (dateQuit.Value.Day > 15)
                    {
                        monthEnd = dateQuit.Value.Month;
                    }
                    else
                    {
                        monthEnd = dateQuit.Value.Month - 1;
                    }
                }

                formula.Parameters.Add(Formula.FormulaConstant.MONTHEND.ToString(), monthEnd);

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.CURRENTMONTH.ToString()))
            {
                #region CURRENTMONTH

                int month = 0;
                month = currentMonth.Month;

                if (dateQuit.HasValue && dateQuit.Value.Year == currentMonth.Year
                    && dateQuit.Value.Month == currentMonth.Month)
                {
                    if (dateQuit.Value.Day > 15)
                    {
                        month = currentMonth.Month;
                    }
                    else
                    {
                        month = currentMonth.Month - 1;
                    }
                }

                formula.Parameters.Add(Formula.FormulaConstant.CURRENTMONTH.ToString(), month);

                #endregion
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.SENIOR_BONUS_LEAVE.ToString()))
            {
                formula.Parameters.Add(Formula.FormulaConstant.SENIOR_BONUS_LEAVE.ToString(), seniority);
            }
            if (formulaAnnualLeave.Contains(Formula.FormulaConstant.SENIOR_BONUS_LEAVE_FROM_.ToString()))
            {
                #region SENIOR_BONUS_LEAVE_FROM

                Double hourOnWorkDate = 8;

                if (gradeCfg.HourOnWorkDate.HasValue)
                {
                    hourOnWorkDate = gradeCfg.HourOnWorkDate.Value;
                }

                int idx = formulaAnnualLeave.IndexOf(Formula.FormulaConstant.SENIOR_BONUS_LEAVE_FROM_.ToString());

                while (idx != -1)
                {
                    int idx2 = formulaAnnualLeave.IndexOf(@"]", idx) - 1;
                    int lengh = Formula.FormulaConstant.SENIOR_BONUS_LEAVE_FROM_.ToString().Length;
                    string monthYearString = formulaAnnualLeave.Substring(idx + lengh, idx2 - idx - lengh + 1);
                    string year = monthYearString.Substring(4);
                    string month = monthYearString.Substring(2, 2);

                    string fullParamString = Formula.FormulaConstant.SENIOR_BONUS_LEAVE_FROM_.ToString() + monthYearString;
                    if (!formula.Parameters.ContainsKey(fullParamString))
                    {
                        DateTime monthYearEffect = new DateTime(int.Parse(year), int.Parse(month), 1);
                        seniority = GetAnnualBySeniority(currentMonth, monthYearEffect, dateHire, gradeCfg);
                        formula.Parameters.Add(fullParamString, seniority);
                    }
                    idx = formulaAnnualLeave.IndexOf(Formula.FormulaConstant.SENIOR_BONUS_LEAVE_FROM_.ToString(), idx2);
                }

                #endregion
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.MONTHENDPRO.ToString()))
            {
                #region MONTHENDPRO
                DateTime fromDate = new DateTime(currentMonth.Year, currentMonth.Month, 1);
                DateTime toDate = fromDate.AddMonths(1).AddMinutes(-1);
                Att_AttendanceServices.GetSalaryDateRange(gradeCfg, null, null, currentMonth, out fromDate, out toDate);

                int monthstart = 0;
                if (dateEndProbation != null)
                {
                    monthstart = dateEndProbation.Value.Month;
                }
                if (dateEndProbation != null && currentMonth.Year > dateEndProbation.Value.Year)
                {
                    monthstart = 1;
                    monthstart = monthStartAnnualLeave ?? 1;
                }
                else if (dateEndProbation != null && currentMonth.Year == dateEndProbation.Value.Year)
                {
                    if (dateEndProbation != null)
                    {
                        if (dateEndProbation.Value.Day > 15)
                            monthstart = dateEndProbation.Value.Month;
                    }
                    monthstart++;
                    // cung nam nhung thang dang xet nho hon thang vao cty
                    if (currentMonth.Month < monthstart)
                        return 0;
                }
                else if (dateEndProbation != null && currentMonth.Year < dateEndProbation.Value.Year)
                {
                    return 0;
                }
                formula.Parameters.Add(Formula.FormulaConstant.MONTHENDPRO.ToString(), monthstart);
                #endregion
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.POSITION_CODE.ToString()))
            {
                string PositionCode = string.Empty;
                if (pos != null && pos.Code != null)
                {
                    PositionCode = pos.Code;
                }
                formula.Parameters.Add(Formula.FormulaConstant.POSITION_CODE.ToString(), PositionCode);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.CURRENTMONTH_INSALARY.ToString()))
            {
                int month = 0;
                month = currentMonth.Month;
                formula.Parameters.Add(Formula.FormulaConstant.CURRENTMONTH_INSALARY.ToString(), month);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.IS_PROBATION.ToString()))
            {
                int flag = 0;

                if ((dateHire != null && dateHire >= dtStart && dateHire <= dtEnd) ||
                    (dateEndProbation != null && dateEndProbation >= dtStart && dateEndProbation <= dtEnd) ||
                    (dateHire != null && dateHire <= dtEnd && dateEndProbation != null && dateEndProbation >= dtStart))
                {
                    flag = 1;
                }
                formula.Parameters.Add(Formula.FormulaConstant.IS_PROBATION.ToString(), flag);
            }

            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.YEAR_OF_DATEHIRE.ToString()))
            {
                int year = 0;
                if (dateHire != null && dateHire >= dtStart && dateHire <= dtEnd)
                {
                    year = dateHire.Value.Year;
                }
                formula.Parameters.Add(Formula.FormulaConstant.YEAR_OF_DATEHIRE.ToString(), year);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.MONTH_OF_DATEHIRE.ToString()))
            {
                int month = 0;
                if (dateHire != null && dateHire >= dtStart && dateHire <= dtEnd)
                {
                    month = dateHire.Value.Month;
                }
                formula.Parameters.Add(Formula.FormulaConstant.MONTH_OF_DATEHIRE.ToString(), month);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.YEAR_OF_DATEENDPROBATION.ToString()))
            {
                int year = 0;
                if (dateEndProbation != null && dateEndProbation >= dtStart && dateEndProbation <= dtEnd)
                {
                    year = dateEndProbation.Value.Year;
                }
                formula.Parameters.Add(Formula.FormulaConstant.YEAR_OF_DATEENDPROBATION.ToString(), year);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.MONTH_OF_DATEENDPROBATION.ToString()))
            {
                int month = 0;
                if (dateEndProbation != null && dateEndProbation >= dtStart && dateEndProbation <= dtEnd)
                {
                    month = dateEndProbation.Value.Month;
                }
                formula.Parameters.Add(Formula.FormulaConstant.MONTH_OF_DATEENDPROBATION.ToString(), month);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.DAYOFDATEHIRE.ToString()))
            {
                int Day = 0;
                if (dateHire != null)
                    Day = dateHire.Value.Day;
                formula.Parameters.Add(Formula.FormulaConstant.DAYOFDATEHIRE.ToString(), Day);
            }

            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.DAYOFDATEQUIT.ToString()))
            {
                int Day = 0;
                if (dateQuit != null)
                    Day = dateQuit.Value.Day;
                formula.Parameters.Add(Formula.FormulaConstant.DAYOFDATEQUIT.ToString(), Day);
            }
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.JOBTITLE_ANNUAL.ToString()))
            {
                formula.Parameters.Add(Formula.FormulaConstant.JOBTITLE_ANNUAL.ToString(), AnnualDays);
            }
            //Lấy tháng của DateHire, lấy kỳ lương theo tháng đó (tháng của DateHire), sau đó xuất ra Năm của kỳ lương đó.
            //vd: DateHire là 26/08/2014 ==>kỳ lương T8 là 25/07/2014-24/08/2014, ktra DateHire có thuộc kỳ T8 ko, nếu ko thì ktra trong kỳ lương T9.
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.YEAR_OF_SALARY_IF_DATEHIRE_BELONG.ToString()))
            {
                int year = 0;
                DateTime dateStart, dateEnd;
                if (dateHire != null)
                {
                    DateTime dtmonthCheck = new DateTime(dateHire.Value.Year, dateHire.Value.Month, 1);
                    //Lấy khoảng thời gian của kỳ lương
                    Att_AttendanceServices.GetSalaryDateRange(gradeCfg, null, null, dtmonthCheck, out dateStart, out dateEnd);
                    if (dateHire >= dateStart && dateHire <= dateEnd)
                    {
                        year = dateEnd.Year;
                    }
                    else
                    {
                        DateTime dateStartAdd = dateStart.AddMonths(1);
                        DateTime dateEndAdd = dateEnd.AddMonths(1);
                        if (dateHire >= dateStartAdd && dateHire <= dateEndAdd)
                        {
                            year = dateEndAdd.Year;
                        }
                    }
                }
                formula.Parameters.Add(Formula.FormulaConstant.YEAR_OF_SALARY_IF_DATEHIRE_BELONG.ToString(), year);
            }
            //Lấy tháng của DateHire, lấy kỳ lương theo tháng đó (tháng của DateHire), sau đó xuất ra Tháng của kỳ lương đó.
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.MONTH_OF_SALARY_IF_DATEHIRE_BELONG.ToString()))
            {
                int month = 0;
                DateTime dateStart, dateEnd;
                if (dateHire != null)
                {
                    DateTime dtmonthCheck = new DateTime(dateHire.Value.Year, dateHire.Value.Month, 1);
                    //Lấy khoảng thời gian của kỳ lương
                    Att_AttendanceServices.GetSalaryDateRange(gradeCfg, null, null, dtmonthCheck, out dateStart, out dateEnd);
                    if (dateHire >= dateStart && dateHire <= dateEnd)
                    {
                        month = dateEnd.Month;
                    }
                    else
                    {
                        DateTime dateStartAdd = dateStart.AddMonths(1);
                        DateTime dateEndAdd = dateEnd.AddMonths(1);
                        if (dateHire >= dateStartAdd && dateHire <= dateEndAdd)
                        {
                            month = dateEndAdd.Month;
                        }
                    }
                }
                formula.Parameters.Add(Formula.FormulaConstant.MONTH_OF_SALARY_IF_DATEHIRE_BELONG.ToString(), month);
            }
            //XuChi..Phần tử lấy số ngày thâm niên (theo đk của Danieli)
            if (gradeCfg.FormulaAnnualLeave.Contains(Formula.FormulaConstant.THAMNIEN_DANIELI.ToString()))
            {
                int thamnien = 0;
                DateTime dayRule = new DateTime(2014, 10, 4);  //Ngày quy định fixed của Danieli
                DateTime currentDay = DateTime.Now.Date;       //Ngày hiện tại lúc kiểm tra
                if (dateHire != null)
                {
                    DateTime dayHire = dateHire.Value.Date;
                    //Nếu ngày vào làm vào sau ngày quy định (logic: thâm niên 5 năm thì cộng 1)
                    if (dayHire >= dayRule)
                    {
                        while (dayHire.AddYears(5) <= currentDay)
                        {
                            dayHire = dayHire.AddYears(5);
                            thamnien++;
                        }
                    }
                    else //Nếu ngày vào làm trước ngày quy định 
                    {
                        //logic 1: thâm niêm 3 năm thì cộng 1
                        while (dayHire.AddYears(3) <= dayRule)
                        {
                            dayHire = dayHire.AddYears(3);
                            thamnien++;
                        }
                        //logic 2: sau logic 1, sẽ có ngày dayHire gần với ngày dayRule nhất, 
                        //khi đó dayHire sẽ đc so sánh với currentDay, sau đó tính thâm niên 5 năm thì cộng 1
                        while (dayHire.AddYears(5) <= currentDay)
                        {
                            dayHire = dayHire.AddYears(5);
                            thamnien++;
                        }
                    }
                }
                formula.Parameters.Add(Formula.FormulaConstant.THAMNIEN_DANIELI.ToString(), thamnien);
            }

            result = Convert.ToDouble(formula.Evaluate());
            if ((result - (int)result) > 0)
            {
                double dental = result - (int)result;
                result = dental >= 0.5 ? (int)result + 1 : (int)result;
            }
            return result;
            return result;
        }
        /// <summary>
        /// Hàm tính toán Phép năm dành cho từng nhân viên
        /// </summary>
        /// <param name="Profile">Nhân Viên</param>
        /// <param name="lstGradeCfg">Ds Chế Độ lương</param>
        /// <param name="lstGrade">Ds Grade của Nhân viên</param>
        /// <param name="BeginYear">Ngày bắt đầu của năm</param>
        /// <param name="EndYear">Ngày Kết Thúc Của Năm</param>
        /// <param name="lstLeaveAnl">Ds nghỉ phép năm</param>
        /// <param name="lstAnnualDetailInDB">Ds AnnualDetail trong DB</param>
        /// <param name="AnnualLeave">AnnualLeave</param>
        /// <param name="lstRosterInYear">Ds Roster</param>
        /// <param name="lstRosterGroup">Ds RosterGroup</param>
        /// <param name="lstWorkHistory">Ds WorkingHistory</param>
        /// <param name="lstDayOff">Ds Ngày Nghỉ Lễ </param>
        /// <returns></returns>
        private List<Att_AnnualDetail> AnalyzeAnnualDetailPerProfile(Hre_ProfileMultiField Profile, List<Cat_GradeAttendance>
            lstGradeCfg, List<Att_Grade> lstGrade, DateTime BeginYear, DateTime EndYear, List<Att_LeaveDayInfo> lstLeaveAnl,
            List<Att_AnnualDetail> lstAnnualDetailInDB, Att_AnnualLeave AnnualLeave, List<Att_RosterInfo> lstRosterInYearIn,
            List<Att_RosterGroup> lstRosterGroup, List<Cat_DayOff> lstDayOff,
            bool IsFrom1To31, Cat_Position Position, List<Sys_AllSetting> lstAllSetting, List<Hre_HDTJob> lstHDTJob, out List<Att_AnnualDetail> AnalyzeAnnualDetailPerProfile_Update, string userLogin)
        {
            AnalyzeAnnualDetailPerProfile_Update = new List<Att_AnnualDetail>();
            using (var context = new VnrHrmDataContext())
            {
                var unitOfWork = (IUnitOfWork)(new UnitOfWork(context));
                var repoAtt_Roster = new CustomBaseRepository<Att_Roster>(unitOfWork);
                var repoCat_Shift = new Cat_ShiftRepository(unitOfWork);
                var shifts = repoCat_Shift.FindBy(s => s.IsDelete == null).ToList();

                var lstRosterID = lstRosterInYearIn.Select(s => s.ID).ToList();
                var lstRosterInYear = repoAtt_Roster.FindBy(s => lstRosterID.Contains(s.ID)).ToList();

                List<Att_AnnualDetail> lstResult = new List<Att_AnnualDetail>();
                double leaveBeginYearToMonth = 0;
                double leaveBeginYearToMonth_Init = 0;
                string E_ROSTERGROUP = RosterType.E_ROSTERGROUP.ToString();
                List<Att_Roster> lstRoster_byProfile = lstRosterInYear.Where(m => m.ProfileID == Profile.ID && m.Type != E_ROSTERGROUP).ToList();
                List<Att_Roster> lstRosterTypeGroup = lstRosterInYear.Where(m => m.ProfileID == Profile.ID && m.Type == E_ROSTERGROUP).ToList();

                for (DateTime Month = BeginYear; Month <= EndYear; Month = Month.AddMonths(1))
                {
                    var gradeByProfileByTime = lstGrade.Where(m => m.ProfileID == Profile.ID && m.MonthStart <= Month).OrderByDescending(m => m.MonthStart).FirstOrDefault();
                    if (gradeByProfileByTime == null)
                        continue;
                    var GradeCfg = lstGradeCfg.Where(m => m.ID == gradeByProfileByTime.GradeAttendanceID).FirstOrDefault();
                    if (GradeCfg == null)
                        continue;

                    DateTime BeginMonth = Month;
                    DateTime EndMonth = BeginMonth.AddMonths(1).AddMinutes(-1);
                    if (!IsFrom1To31)
                    {
                        Att_AttendanceServices.GetRangeMaxMinGrade(new List<Cat_GradeAttendance>() { GradeCfg }, Month, out BeginMonth, out EndMonth);
                    }

                    int AnnualLeaveMonthStart = AnnualLeave != null ? AnnualLeave.MonthStart : 1;
                    double AnnualLeaveInitAnlValue = AnnualLeave != null ? AnnualLeave.InitAnlValue : 0;

                    double Availale = Att_AttendanceLib.GetAnnualLeaveReceive(BeginYear.Year, Month, GradeCfg, Profile.DateHire,
                        Profile.DateEndProbation, Profile.DateQuit, AnnualLeaveMonthStart, AnnualLeaveInitAnlValue, Position, Profile,
                        lstLeaveAnl, lstAllSetting, lstHDTJob, lstDayOff.Select(m => m.DateOff).ToList(), lstLeaveAnl, userLogin);
                    double LeaveInMonth = 0;
                    List<Att_LeaveDayInfo> lstAnlInMonth = lstLeaveAnl.Where(m => m.ProfileID == Profile.ID && m.DateStart <= EndMonth && m.DateEnd >= BeginMonth).ToList();
                    foreach (var item in lstAnlInMonth)
                    {
                        var listRosterEntity = lstRoster_byProfile.Select(d => new Att_RosterEntity
                        {
                            ID = d.ID,
                            ProfileID = d.ProfileID,
                            RosterGroupName = d.RosterGroupName,
                            Type = d.Type,
                            Status = d.Status,
                            DateEnd = d.DateEnd,
                            DateStart = d.DateStart,
                            MonShiftID = d.MonShiftID,
                            TueShiftID = d.TueShiftID,
                            WedShiftID = d.WedShiftID,
                            ThuShiftID = d.ThuShiftID,
                            FriShiftID = d.FriShiftID,
                            SatShiftID = d.SatShiftID,
                            SunShiftID = d.SunShiftID,
                            MonShift2ID = d.MonShiftID,
                            TueShift2ID = d.TueShift2ID,
                            WedShift2ID = d.WedShift2ID,
                            ThuShift2ID = d.ThuShift2ID,
                            FriShift2ID = d.FriShift2ID,
                            SatShift2ID = d.SatShift2ID,
                            SunShift2ID = d.SunShift2ID
                        }).ToList();

                        var listRosterGroupEntity = lstRosterGroup.Select(d => new Att_RosterGroupEntity
                        {
                            ID = d.ID,
                            DateEnd = d.DateEnd,
                            DateStart = d.DateStart,
                            MonShiftID = d.MonShiftID,
                            TueShiftID = d.TueShiftID,
                            WedShiftID = d.WedShiftID,
                            ThuShiftID = d.ThuShiftID,
                            FriShiftID = d.FriShiftID,
                            SatShiftID = d.SatShiftID,
                            SunShiftID = d.SunShiftID,
                            RosterGroupName = d.RosterGroupName
                        }).ToList();

                        if (item.DateStart >= BeginMonth && item.DateEnd <= EndMonth)
                        {
                            //Chi cần lấy TotalDuration hoặc lấy giờ rồi lấy ca
                            if (item.DurationType == LeaveDayDurationType.E_FULLSHIFT.ToString())
                            {
                                LeaveInMonth += item.LeaveDays ?? 0;
                            }
                            else
                            {
                                //Lấy ra ca làm việc 
                                DateTime DateBeginLeave = item.DateStart.Date;
                                DateTime DateEndLeave = item.DateEnd.Date;

                                Dictionary<DateTime, Cat_Shift> dicShift = Att_AttendanceLib.GetDailyShifts(Profile != null ? Profile.ID : Guid.Empty, DateBeginLeave, DateEndLeave, listRosterEntity, listRosterGroupEntity, shifts);

                                if (dicShift != null && dicShift.ContainsKey(DateBeginLeave))
                                {
                                    Cat_Shift shift = dicShift[DateBeginLeave];
                                    if (shift != null)
                                    {
                                        double HourWorkday = shift.udStandardWorkHours > 0 ? shift.udStandardWorkHours : 8.0;

                                        LeaveInMonth += item.LeaveHours.Value / HourWorkday;
                                    }
                                }
                            }
                        }
                        else
                        {
                            DateTime DateBegin = BeginMonth > item.DateStart ? BeginMonth : item.DateStart;
                            DateTime DateEnd = EndMonth < item.DateEnd ? BeginMonth : item.DateEnd;
                            Dictionary<DateTime, Cat_Shift> dicShift = Att_AttendanceLib.GetDailyShifts(Profile != null ? Profile.ID : Guid.Empty, DateBegin, DateEnd, listRosterEntity, listRosterGroupEntity, shifts);
                            for (DateTime dateCheck = DateBegin; dateCheck <= DateEnd; dateCheck = dateCheck.AddDays(1))
                            {
                                if (Att_WorkDayHelper.IsWorkDay(dateCheck, GradeCfg, dicShift, lstDayOff) && !lstDayOff.Any(m => m.DateOff == dateCheck))
                                {
                                    LeaveInMonth++;
                                }
                            }
                        }
                    }
                    Att_AnnualDetail AnnualDetail = lstAnnualDetailInDB.Where(m => m.ProfileID == Profile.ID && m.MonthYear == Month).FirstOrDefault();
                    bool isNew = false;
                    if (AnnualDetail == null)
                    {
                        isNew = true;
                        AnnualDetail = new Att_AnnualDetail();
                    }
                    else
                    {
                        AnalyzeAnnualDetailPerProfile_Update.Add(AnnualDetail);
                    }


                    if (Profile.DateQuit != null)
                    {
                        DateTime MonthQuit = Profile.DateQuit.Value.Day >= 15 ? Profile.DateQuit.Value.AddMonths(1) : Profile.DateQuit.Value;
                        MonthQuit = new DateTime(MonthQuit.Year, MonthQuit.Month, 1);
                        if (Month >= MonthQuit)
                        {
                            AnnualDetail.IsDelete = true;
                        }
                    }
                    AnnualDetail.Available = Availale;
                    AnnualDetail.InitAvailable = AnnualLeave == null ? 0 : AnnualLeave.InitAnlValue;
                    AnnualDetail.ProfileID = Profile.ID;
                    //AnnualDetail.Hre_Profile = Profile.CopyData<Hre_Profile>();
                    AnnualDetail.Year = BeginYear.Year;
                    AnnualDetail.MonthYear = Month;
                    AnnualDetail.MonthBeginInYear = MonthStartAnl; //todo: Phần tử này để trong cấu hình chung
                    if (AnnualLeave != null && AnnualLeave.MonthResetAnlOfBeforeYear != null)
                    {
                        AnnualDetail.MonthResetInitAvailable = AnnualLeave.MonthResetAnlOfBeforeYear.Value;//todo: MonthReset Này để trong chế độ lương
                    }
                    else
                    {
                        AnnualDetail.MonthResetInitAvailable = 12;//todo: MonthReset Này để trong chế độ lương
                    }
                    AnnualDetail.MonthStartProfile = AnnualLeave == null ? 1 : AnnualLeave.MonthStart;
                    if (AnnualDetail.MonthResetInitAvailable != null && AnnualDetail.MonthResetInitAvailable != 12 && AnnualDetail.Year != null)
                    {
                        DateTime MonthReset = new DateTime(AnnualDetail.Year.Value, AnnualDetail.MonthResetInitAvailable.Value, 1);
                        AnnualDetail.IsHaveResetInitAvailable = true;
                        if (Month <= MonthReset) //Trong những tháng có
                        {
                            double delta = leaveBeginYearToMonth_Init + LeaveInMonth - AnnualDetail.InitAvailable.Value;
                            if (delta > 0)
                            {
                                AnnualDetail.TotalLeaveBefFromInitAvailable = leaveBeginYearToMonth_Init;
                                AnnualDetail.LeaveInMonthFromInitAvailable = LeaveInMonth - delta;
                                AnnualDetail.LeaveInMonth = delta;
                                AnnualDetail.TotalLeaveBef = leaveBeginYearToMonth;
                                leaveBeginYearToMonth += delta;
                                leaveBeginYearToMonth_Init += LeaveInMonth - delta;
                            }
                            else
                            {
                                AnnualDetail.TotalLeaveBefFromInitAvailable = leaveBeginYearToMonth_Init;
                                AnnualDetail.LeaveInMonthFromInitAvailable = LeaveInMonth;
                                AnnualDetail.TotalLeaveBef = leaveBeginYearToMonth;
                                AnnualDetail.LeaveInMonth = 0;
                                leaveBeginYearToMonth_Init += LeaveInMonth;
                            }
                        }
                        else //sau những tháng kho có
                        {
                            AnnualDetail.InitAvailable = 0;
                            AnnualDetail.TotalLeaveBef = leaveBeginYearToMonth;
                            AnnualDetail.LeaveInMonth = LeaveInMonth;
                            leaveBeginYearToMonth += LeaveInMonth;
                        }
                    }
                    else //Bình thường
                    {
                        AnnualDetail.IsHaveResetInitAvailable = false;
                        AnnualDetail.TotalLeaveBef = leaveBeginYearToMonth;
                        AnnualDetail.LeaveInMonth = LeaveInMonth;
                        leaveBeginYearToMonth += LeaveInMonth;
                    }
                    double remain = (AnnualDetail.Available ?? 0) + (AnnualDetail.InitAvailable ?? 0) - (AnnualDetail.TotalLeaveBefFromInitAvailable ?? 0) - (AnnualDetail.LeaveInMonthFromInitAvailable ?? 0) - (AnnualDetail.TotalLeaveBef ?? 0) - (AnnualDetail.LeaveInMonth ?? 0);
                    AnnualDetail.Remain = remain;
                    AnnualDetail.Type = AnnualLeaveDetailType.E_ANNUAL_LEAVE.ToString();
                    if (isNew)
                    {
                        lstResult.Add(AnnualDetail);
                    }
                }
                return lstResult;
            }
        }