Ejemplo n.º 1
0
        //Quy tắc phép bù của honda cập nhật trong file tài liệu 
        /// <summary>
        /// Hàm tính ra số phép bù của nhân viên hiện tại
        /// </summary>
        /// <param name="ProfileID">ID của nhân viên</param>
        /// <param name="lstTimeOff4Ago">Ds trong bảng Att_TimeOffInLieu của nhân viên từ 3 tháng trước cho đến hiện tại</param>
        /// <param name="lstTimeOffByMonth3Ago">Ds trong bảng Att_TimeOffInLieuMonth của nhân viên tính theo 3 tháng trước tháng hiện tại</param>
        /// <param name="monthYear">Tháng Hiện tại</param>
        /// <param name="lstTimeOffByMonthNEW">Ds sẽ phát sinh ra thi tính công thì sẽ lưu Ds này</param>
        /// <param name="isFromValidateLeaveDay">Nếu validate từ ngày nghỉ thì TRUE ngươc lại từ tính công thi FALSE</param>
        /// <param name="dateStartOfMonth">Ngày bắt đầu của Tháng, Honda là ngày 1</param>
        /// <returns></returns>
        public double? CalculateTotalHourTimeOff(Guid ProfileID, List<Att_TimeOffInLieu> lstTimeOff4Ago, List<Att_TimeOffInLieuMonth> lstTimeOffByMonth3Ago, DateTime monthYear, int dateStartOfMonth)
        {
            monthYear = new DateTime(monthYear.Year, monthYear.Month, 1);
            lstTimeOffByMonth3Ago = lstTimeOffByMonth3Ago.Where(m => m.Month != monthYear).ToList();
            if (lstTimeOffByMonth3Ago.Where(m => m.Month != null).ToList().Count == 0)
                return null;
            List<Att_TimeOffInLieuMonth> lstTimeOffByMonth_Auto_NEW = new List<Att_TimeOffInLieuMonth>();
            Att_TimeOffInLieuMonth TimeOffInLieuMonthNew = lstTimeOffByMonth3Ago.OrderByDescending(m => m.Month).FirstOrDefault();
            DateTime monthInLastTimeOff_inMonth = TimeOffInLieuMonthNew.Month ?? monthYear;
            for (DateTime MonthCheck = monthInLastTimeOff_inMonth.AddMonths(1); MonthCheck <= monthYear; MonthCheck = MonthCheck.AddMonths(1))
            {
                DateTime beginMonth = new DateTime(MonthCheck.Year, MonthCheck.Month, dateStartOfMonth);
                DateTime endMonth = beginMonth.AddMonths(1).AddMinutes(-1);
                //DK.m = IF(Giam(m-1)>=DK(m-1), CK(m-1), IF(Giam(m-1) < DK(m-1),Tang(m-1),CK(m-1))	
                DateTime monthTimeOff_Inmonth = MonthCheck.AddMonths(-1);
                Att_TimeOffInLieuMonth TimeOffInLieuLast = lstTimeOffByMonth3Ago.Where(m => m.Month == monthTimeOff_Inmonth).FirstOrDefault();
                if (TimeOffInLieuLast == null)
                {
                    TimeOffInLieuLast = lstTimeOffByMonth_Auto_NEW.Where(m => m.Month == monthTimeOff_Inmonth).FirstOrDefault();
                }
                if (TimeOffInLieuLast == null)
                    return null;

                double Balance = 0;
                if ((TimeOffInLieuLast.TakenLeaves ?? 0) >= (TimeOffInLieuLast.BalanceLeaves ?? 0))
                {
                    Balance = TimeOffInLieuLast.RemainLeaves ?? 0;
                }
                else
                {
                    Balance = TimeOffInLieuLast.UnusualLeaves ?? 0;
                }
                Att_TimeOffInLieuMonth LieuMonth_New = new Att_TimeOffInLieuMonth();
                LieuMonth_New.ProfileID = ProfileID;
                LieuMonth_New.Month = MonthCheck;
                LieuMonth_New.BalanceLeaves = Balance;
                LieuMonth_New.UnusualLeaves = lstTimeOff4Ago.Where(m => m.ProfileID == ProfileID && m.Date >= beginMonth && m.Date < endMonth).Sum(m => m.UnusualLeaves);
                LieuMonth_New.TakenLeaves = lstTimeOff4Ago.Where(m => m.ProfileID == ProfileID && m.Date >= beginMonth && m.Date < endMonth).Sum(m => m.TakenLeaves);
                LieuMonth_New.RemainLeaves = LieuMonth_New.BalanceLeaves + LieuMonth_New.UnusualLeaves - LieuMonth_New.TakenLeaves;
                lstTimeOffByMonth_Auto_NEW.Add(LieuMonth_New);
            }
            //if (!isFromValidateLeaveDay)
            //{
            //    lstTimeOffByMonthNEW = lstTimeOffByMonth_Auto_NEW;
            //}

            if (lstTimeOffByMonth_Auto_NEW.Where(m => m.Month == monthYear).ToList().Count > 0)
            {
                return lstTimeOffByMonth_Auto_NEW.Where(m => m.Month == monthYear).FirstOrDefault().RemainLeaves;
            }

            return null;
        }
Ejemplo n.º 2
0
        private int ComputeAttendance(Guid userID, Guid asynTaskID, DateTime monthYear, Guid cutOffDurationID,
            out DataErrorCode dataErrorCode, int totalProfile, int totalComputed, params Hre_ProfileEntity[] listProfile)
        {
            using (var context = new VnrHrmDataContext())
            {
                IUnitOfWork unitOfWork = new UnitOfWork(context);
                int attendanceTableCount = 0;

                List<Guid> listProfileID = listProfile.Select(s => s.ID).ToList();
                totalProfile = totalProfile <= 0 ? listProfileID.Count() : totalProfile;

                #region Xóa bảng công cũ đã tính trước đó

                dataErrorCode = DeleteAttendance(monthYear,
                    cutOffDurationID, listProfileID);

                if (dataErrorCode == DataErrorCode.Locked
                    || dataErrorCode == DataErrorCode.Error)
                {
                    return attendanceTableCount;
                }

                #endregion

                #region Tính khoảng thời gian theo cutOffDurationID

                DateTime attendanceFrom = monthYear.AddDays(1 - monthYear.Day).Date;
                DateTime attendanceTo = attendanceFrom.AddMonths(1).AddSeconds(-1);

                var cutOffDuration = unitOfWork.CreateQueryable<Att_CutOffDuration>(Guid.Empty,
                    d => d.ID == cutOffDurationID).Select(d => new
                    {
                        d.DateStart,
                        d.DateEnd,
                        d.OvertimeStart,
                        d.OvertimeEnd,
                        d.LeavedayStart,
                        d.LeavedayEnd,
                    }).FirstOrDefault();

                if (cutOffDuration != null)
                {
                    attendanceFrom = cutOffDuration.DateStart;
                    attendanceTo = cutOffDuration.DateEnd;
                }

                #endregion

                #region Tải các thông tin danh mục có liên quan

                string overTimeMethod = MethodOption.E_CASHOUT.ToString();
                string overTimeStatus = OverTimeStatus.E_APPROVED.ToString();
                string pregnancyType = PregnancyType.E_LEAVE_EARLY.ToString();
                string leaveStatus = LeaveDayStatus.E_APPROVED.ToString();
                string hdtJobStatus = HDTJobStatus.E_APPROVE.ToString();
                string leavedayTypeNOPAY = LeavedayTypeCode.NOPAY.ToString();
                string leavedayTypeABS = LeavedayTypeCode.ABS.ToString();
                string leavedayTypeHLD = LeavedayTypeCode.HLD.ToString();
                string rosterStatus = RosterStatus.E_APPROVED.ToString();

                string NOTAUTOREGISTERHOLIDAYLEAVE = AppConfig.HRM_ATT_NOTAUTOREGISTERHOLIDAYLEAVE.ToString();
                string OT_HOLIDAYSCOMPUTE400 = AppConfig.HRM_ATT_OT_HOLIDAYSCOMPUTE400.ToString();
                string MISSTAM_LEAVETYPE = AppConfig.HRM_ATT_MISSTAM_LEAVETYPE.ToString();
                string HRM_ATT_OT_OVERTIMESTATUS = AppConfig.HRM_ATT_OT_OVERTIMESTATUS.ToString();

                var standardWorkdayConfig = unitOfWork.CreateQueryable<Sys_AllSetting>(d => d.Name == NOTAUTOREGISTERHOLIDAYLEAVE
                    || d.Name == OT_HOLIDAYSCOMPUTE400 || d.Name == MISSTAM_LEAVETYPE || d.Name == HRM_ATT_OT_OVERTIMESTATUS).ToList();

                var notAutoRegHolidayLeave = standardWorkdayConfig.Where(s => s.Name == NOTAUTOREGISTERHOLIDAYLEAVE).FirstOrDefault();
                var otholidayscompute400 = standardWorkdayConfig.Where(s => s.Name == OT_HOLIDAYSCOMPUTE400).FirstOrDefault();
                var missTAM_LeaveType = standardWorkdayConfig.Where(s => s.Name == MISSTAM_LEAVETYPE).FirstOrDefault();
                var statusOT = standardWorkdayConfig.Where(s => s.Name == HRM_ATT_OT_OVERTIMESTATUS).FirstOrDefault();

                if (statusOT != null)
                {
                    overTimeStatus = statusOT.Value1;
                }

                DateTime startYear = new DateTime(monthYear.Year, 1, 1).AddMonths(-1);//đầu năm
                DateTime endYear = new DateTime(monthYear.Year, 12, 31).Date.AddDays(1).AddSeconds(-1);
                DateTime preMonthYear = monthYear.AddMonths(-1);

                List<Cat_DayOff> listHoliday = unitOfWork.CreateQueryable<Cat_DayOff>(d =>
                    d.DateOff >= startYear && d.DateOff <= endYear).ToList();

                //Tất cả roster từ đầu năm đến thời điểm tính công - cần cho mục tính tính phép năm còn lại cho từng nhân viên.
                var listRoster = unitOfWork.CreateQueryable<Att_Roster>(d => d.DateStart <= attendanceTo && d.DateEnd >= startYear
                    && d.Status == rosterStatus && listProfileID.Contains(d.ProfileID)).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 listRosterGroup = unitOfWork.CreateQueryable<Att_RosterGroup>(m => m.DateStart != null && m.DateEnd != null
                    && m.DateStart <= attendanceTo && m.DateEnd >= attendanceFrom).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();

                var listWorkHistory = unitOfWork.CreateQueryable<Hre_WorkHistory>(d => d.DateEffective <= attendanceTo
                    && listProfileID.Contains(d.ProfileID)).ToList();

                List<Att_Roster> lstRosterTypeGroup = new List<Att_Roster>();
                List<Att_RosterGroup> lstRosterGroup = new List<Att_RosterGroup>();

                GetRosterGroup(listProfileID, startYear, attendanceTo, out lstRosterTypeGroup, out lstRosterGroup);
                var listLateEarlyRule = unitOfWork.CreateQueryable<Cat_LateEarlyRule>().ToList<Cat_LateEarlyRule>();
                var listShift = unitOfWork.CreateQueryable<Cat_Shift>().ToList<Cat_Shift>();

                var currentYear = unitOfWork.CreateQueryable<Att_AnnualDetail>(d => monthYear == d.MonthYear).Select(d => d.Year).FirstOrDefault();
                var monthStart = unitOfWork.CreateQueryable<Att_AnnualDetail>(d => d.Year == currentYear).OrderBy(d => d.MonthYear).Select(d => d.MonthYear).FirstOrDefault();

                var listAnnualDetail = unitOfWork.CreateQueryable<Att_AnnualDetail>(d => d.MonthYear == monthStart
                    && d.ProfileID.HasValue && listProfileID.Contains(d.ProfileID.Value));

                var listPreAttendanceTable = unitOfWork.CreateQueryable<Att_AttendanceTable>(d => d.MonthYear.HasValue
                    && d.MonthYear == preMonthYear && listProfileID.Contains(d.ProfileID)).Select(d =>
                        new Att_AttendanceTableEntity
                        {
                            ID = d.ID,
                            AnlDayTaken = d.AnlDayTaken,
                            AnlDayAdjacent = d.AnlDayAdjacent,
                            SickDayTaken = d.SickDayTaken,
                            SickDayAdjacent = d.SickDayAdjacent,
                            AnlDayAvailable = d.AnlDayAvailable,
                            SickDayAvailable = d.SickDayAvailable,
                            ProfileID = d.ProfileID
                        }).ToList<Att_AttendanceTableEntity>();

                var listPregnancy = unitOfWork.CreateQueryable<Att_Pregnancy>(d => d.DateEnd >= attendanceFrom && d.DateStart <= attendanceTo
                    && d.Type == pregnancyType && listProfileID.Contains(d.ProfileID)).Select(d => new Att_PregnancyEntity
                    {
                        ID = d.ID,
                        ProfileID = d.ProfileID,
                        DateStart = d.DateStart,
                        DateEnd = d.DateEnd,
                        TypePregnancyEarly = d.TypePregnancyEarly
                    }).ToList<Att_PregnancyEntity>();

                var listOvertime = unitOfWork.CreateQueryable<Att_Overtime>(d => d.Status == overTimeStatus
                    && (d.MethodPayment == null || d.MethodPayment == overTimeMethod) && d.WorkDateRoot >= attendanceFrom
                    && d.WorkDateRoot <= attendanceTo && listProfileID.Contains(d.ProfileID)).Select(d => new Att_OvertimeEntity
                    {
                        ID = d.ID,
                        ProfileID = d.ProfileID,
                        OvertimeTypeID = d.OvertimeTypeID,
                        DurationType = d.DurationType,
                        WorkDateRoot = d.WorkDateRoot,
                        WorkDate = d.WorkDate,
                        ApproveHours = d.ApproveHours,
                        ConfirmHours = d.ConfirmHours,
                        RegisterHours = d.RegisterHours
                    }).ToList<Att_OvertimeEntity>();

                List<Guid> listOvertimeTypeID = listOvertime.Select(o => o.OvertimeTypeID).Distinct().ToList();
                var listOvertimeType = unitOfWork.CreateQueryable<Cat_OvertimeType>(d => listOvertimeTypeID.Contains(d.ID)).ToList();

                var listLeaveDay = unitOfWork.CreateQueryable<Att_LeaveDay>(d => d.Status == leaveStatus && ((d.DateStart <= attendanceTo
                    && d.DateEnd >= attendanceFrom) || d.DateOvertimeOff >= attendanceFrom && d.DateOvertimeOff <= attendanceTo)
                    && listProfileID.Contains(d.ProfileID)).Select(d => new Att_LeaveDayEntity
                    {
                        ID = d.ID,
                        ProfileID = d.ProfileID,
                        DateStart = d.DateStart,
                        DateEnd = d.DateEnd,
                        DateOvertimeOff = d.DateOvertimeOff,
                        LeaveDayTypeID = d.LeaveDayTypeID,
                        DurationType = d.DurationType,
                        LeaveHours = d.LeaveHours,
                        LeaveDays = d.LeaveDays
                    }).ToList<Att_LeaveDayEntity>();

                List<Guid> listLeaveDayTypeID = listLeaveDay.Select(o => o.LeaveDayTypeID).Distinct().ToList();
                var listLeaveDayType = unitOfWork.CreateQueryable<Cat_LeaveDayType>(d => listLeaveDayTypeID.Contains(d.ID)
                    || d.Code == leavedayTypeABS || d.Code == leavedayTypeNOPAY || d.Code == leavedayTypeHLD).ToList();

                List<Hre_HDTJob> listHDTJob = new List<Hre_HDTJob>();
                foreach (var templstProfileIds in listProfileID.Chunk(1000))
                {
                    listHDTJob.AddRange(unitOfWork.CreateQueryable<Hre_HDTJob>(d => d.Status == hdtJobStatus && ((d.DateFrom <= attendanceTo && d.DateTo == null)
                    || (d.DateTo != null && d.DateFrom <= attendanceTo && d.DateTo >= attendanceFrom)) && templstProfileIds.Contains(d.ProfileID.Value)).ToList());
                }
                //var listHDTJob = unitOfWork.CreateQueryable<Hre_HDTJob>(d => d.Status == hdtJobStatus && ((d.DateFrom <= attendanceTo && d.DateTo == null)
                //    || (d.DateTo != null && d.DateFrom <= attendanceTo && d.DateTo >= attendanceFrom)) && listProfileID.Contains(d.ProfileID.Value)).ToList();

                //Danh sách cấu hình grade theo danh sách nhân viên có trong danh sách mã thẻ
                var listGrade = unitOfWork.CreateQueryable<Att_Grade>(d => d.MonthStart.HasValue && d.MonthStart <= attendanceTo
                    && listProfileID.Contains(d.ProfileID.Value)).Select(d => new
                    {
                        d.ProfileID,
                        d.MonthStart,
                        d.GradeAttendanceID
                    }).ToList();

                listGrade = listGrade.GroupBy(d => d.ProfileID).Select(d =>
                    d.OrderByDescending(p => p.MonthStart).FirstOrDefault()).ToList();

                //Danh sách cấu hình gradeCfg theo danh sách grade tìm được ở trên
                var listGradeCfgID = listGrade.Select(d => d.GradeAttendanceID).Distinct().ToList();
                var listGradeCfg = unitOfWork.CreateQueryable<Cat_GradeAttendance>(d => listGradeCfgID.Contains(d.ID)).ToList();

                var lstTimeOffInLieu = unitOfWork.CreateQueryable<Att_TimeOffInLieu>(d => d.Date != null
                    && d.Date >= attendanceFrom && d.Date <= attendanceTo).Select(m => new
                    {
                        m.ProfileID,
                        m.UnusualLeaves,
                        m.TakenLeaves
                    }).ToList();

                DateTime month3Ago = new DateTime(attendanceTo.Year, attendanceTo.Month, 1);
                month3Ago = month3Ago.AddMonths(-3);

                List<Att_TimeOffInLieuMonth> lstTimeOffInLieu_ByMonth_3Month = unitOfWork.CreateQueryable<Att_TimeOffInLieuMonth>(d =>
                    d.Month != null && d.Month >= month3Ago && d.Month <= attendanceTo && listProfileID.Contains(d.ProfileID)).ToList();

                List<Att_TimeOffInLieuMonth> lstTimeOffInLieuMonth = lstTimeOffInLieu_ByMonth_3Month.Where(d =>
                    d.Month != null && d.Month >= attendanceFrom && d.Month <= attendanceTo).ToList<Att_TimeOffInLieuMonth>();

                List<Att_TimeOffInLieuMonth> lstTimeOffInLieuMonthInsert = new List<Att_TimeOffInLieuMonth>();
                DateTime beginYear = new DateTime(attendanceTo.Year, 1, 1);

                #endregion

                #region Bắt đầu tính công cho từng người

                var listWorkDay = unitOfWork.CreateQueryable<Att_Workday>(d => d.WorkDate >= attendanceFrom
                    && d.WorkDate <= attendanceTo && listProfileID.Contains(d.ProfileID)).ToList();

                List<Att_TimeOffInLieu> lstTimeOffInLieu_3Month = unitOfWork.CreateQueryable<Att_TimeOffInLieu>(d =>
                    d.Date >= month3Ago && d.Date <= attendanceTo && listProfileID.Contains(d.ProfileID)).ToList();

                var listTimeOffInLieu = lstTimeOffInLieu_3Month.Where(s => listProfileID.Contains(s.ProfileID)
                    && attendanceFrom <= s.Date && s.Date <= attendanceTo).Select(s => new Att_TimeOffInLieuEntity
                    {
                        ID = s.ID,
                        Date = s.Date,
                        ProfileID = s.ProfileID,
                        OvertimeID = s.OvertimeID,
                        LeaveDayID = s.LeaveDayID,
                        UnusualLeaves = s.UnusualLeaves,
                        LeaveHours = s.LeaveHours,
                        TakenLeaves = s.TakenLeaves
                    }).ToList<Att_TimeOffInLieuEntity>();

                using (var taskContext = new VnrHrmDataContext())
                {
                    IUnitOfWork taskUnitOfWork = new UnitOfWork(taskContext);
                    Sys_AsynTask asynTask = null;

                    if (asynTaskID != Guid.Empty)
                    {
                        asynTask = taskUnitOfWork.CreateQueryable<Sys_AsynTask>(s =>
                           s.ID == asynTaskID).FirstOrDefault();
                    }

                    int totalComputedProfileMustSubmitTask = 50;
                    int totalComputedProfileMustSubmit = 50;
                    int totalComputedProfileForSubmit = 0;
                    int totalComputedProfileForTask = 0;

                    totalComputedProfileMustSubmitTask = totalProfile * 5 / 100;

                    if (totalComputedProfileMustSubmitTask > listProfile.Count())
                    {
                        totalComputedProfileMustSubmitTask = listProfile.Count();
                    }

                    foreach (var profileId in listProfileID)
                    {
                        try
                        {
                            #region Những dữ liệu liên quan tính công theo từng nhân viên

                            var profile = listProfile.Where(d => d.ID == profileId).FirstOrDefault();
                            var listAnnualDetailByProfile = listAnnualDetail.Where(d => d.ProfileID == profileId).ToList();
                            var listPreAttendanceTableByProfile = listPreAttendanceTable.Where(d => d.ProfileID == profileId).ToList();
                            var listWorkDayByProfile = listWorkDay.Where(d => d.ProfileID == profileId).OrderBy(d => d.WorkDate).ToList();
                            var listTimeOffInLieuByProfile = listTimeOffInLieu.Where(d => d.ProfileID == profileId).ToList();

                            var listHDTJobByProfile = listHDTJob.Where(d => d.ProfileID == profileId).ToList();
                            var listPregnancyByProfile = listPregnancy.Where(prg => prg.ProfileID == profileId && prg.DateEnd >= attendanceFrom && prg.DateStart <= attendanceTo).ToList();
                            var listLeaveDayByProfile = listLeaveDay.Where(d => d.ProfileID == profileId && ((d.DateStart <= attendanceTo && d.DateEnd >= attendanceFrom)
                                || (d.DateOvertimeOff.HasValue && d.DateOvertimeOff >= attendanceFrom && d.DateOvertimeOff <= attendanceTo))).ToList();

                            var listOvertimeByProfile = listOvertime.Where(d => d.ProfileID == profileId && d.WorkDate >= attendanceFrom && d.WorkDate <= attendanceTo).ToList();
                            var gradeCfgIDByProfile = listGrade.Where(d => d.ProfileID == profileId && d.MonthStart <= attendanceTo).Select(d => d.GradeAttendanceID).FirstOrDefault();
                            var gradeCfgByProfile = listGradeCfg.Where(d => d.ID == gradeCfgIDByProfile).FirstOrDefault();

                            List<Hre_WorkHistory> listWorkHistoryByProfile = listWorkHistory.Where(d => d.ProfileID == profileId).ToList();
                            var listRosterByProfile = listRoster.Where(d => d.ProfileID == profileId && d.DateStart <= attendanceTo && d.DateEnd >= attendanceFrom).ToList();
                            var listMonthShifts = Att_AttendanceLib.GetDailyShifts(attendanceFrom, attendanceTo, profile.ID, listRosterByProfile, listRosterGroup);

                            #endregion

                            attendanceTableCount += ComputeAttendance(unitOfWork, userID, monthYear, cutOffDurationID, attendanceFrom, attendanceTo, profile,
                                gradeCfgByProfile, listShift, listAnnualDetailByProfile, listHDTJobByProfile, listLeaveDayByProfile, listLeaveDayType,
                                listOvertimeByProfile, listOvertimeType, listPregnancyByProfile, listLateEarlyRule, listWorkDayByProfile,
                                listPreAttendanceTableByProfile, listTimeOffInLieuByProfile, notAutoRegHolidayLeave, otholidayscompute400,
                                missTAM_LeaveType, listMonthShifts, listHoliday);

                            #region Cập Nhật Dữ Liệu Cho Việc Tính TimeOffInLieuMonth and Year

                            double? balanceLeaves = (new Att_LeavedayServices()).CalculateTotalHourTimeOff(profileId, lstTimeOffInLieu_3Month.Where(m =>
                                m.ProfileID == profileId).ToList(), lstTimeOffInLieu_ByMonth_3Month.Where(m => m.ProfileID == profileId).ToList(), monthYear, 1);

                            double UnusualLeaves = lstTimeOffInLieu.Where(m => m.ProfileID == profileId).Sum(m => m.UnusualLeaves ?? 0);
                            double TakenLeaves = lstTimeOffInLieu.Where(m => m.ProfileID == profileId).Sum(m => m.TakenLeaves ?? 0);
                            double RemainLeaves = UnusualLeaves - TakenLeaves + (balanceLeaves ?? 0);

                            var timeOffInLieuMonth_ByProfile = lstTimeOffInLieuMonth.Where(m =>
                                m.ProfileID == profileId).FirstOrDefault();

                            if (timeOffInLieuMonth_ByProfile == null)
                            {
                                //tạo mới
                                timeOffInLieuMonth_ByProfile = new Att_TimeOffInLieuMonth();
                                timeOffInLieuMonth_ByProfile.ID = Guid.NewGuid();
                                timeOffInLieuMonth_ByProfile.ProfileID = profileId;
                                timeOffInLieuMonth_ByProfile.BalanceLeaves = balanceLeaves ?? 0;
                                timeOffInLieuMonth_ByProfile.UnusualLeaves = UnusualLeaves;
                                timeOffInLieuMonth_ByProfile.TakenLeaves = TakenLeaves;
                                timeOffInLieuMonth_ByProfile.RemainLeaves = RemainLeaves;
                                timeOffInLieuMonth_ByProfile.Month = new DateTime(attendanceTo.Year, attendanceTo.Month, 1);
                                unitOfWork.AddObject(typeof(Att_TimeOffInLieuMonth), timeOffInLieuMonth_ByProfile);
                            }
                            else
                            {
                                //chinh sua
                                timeOffInLieuMonth_ByProfile.BalanceLeaves = balanceLeaves ?? 0;
                                timeOffInLieuMonth_ByProfile.UnusualLeaves = UnusualLeaves;
                                timeOffInLieuMonth_ByProfile.TakenLeaves = TakenLeaves;
                                timeOffInLieuMonth_ByProfile.RemainLeaves = RemainLeaves;
                            }

                            #endregion

                            #region Chia thành nhiều giai đoạn lưu bảng công

                            if (asynTask != null)
                            {
                                totalComputedProfileForTask++;
                                double percent = (double)totalComputedProfileForTask / (double)totalProfile;

                                if (totalComputedProfileForTask >= totalComputedProfileMustSubmitTask)
                                {
                                    asynTask.PercentComplete = asynTask.PercentComplete + percent;
                                    dataErrorCode = taskUnitOfWork.SaveChanges(userID);
                                    totalComputedProfileForTask = 0;

                                    if (dataErrorCode == DataErrorCode.Locked)
                                    {
                                        break;
                                    }
                                }
                            }

                            //Nên submit lần đầu tiên khi đã tính được 5 profile
                            bool firstSubmit = listProfileID.ToList().IndexOf(profileId) == 5;
                            firstSubmit = totalComputed >= 5 ? false : firstSubmit;//đã chạy 1 lần
                            totalComputedProfileForSubmit++;

                            if (firstSubmit || totalComputedProfileForSubmit >= totalComputedProfileMustSubmit)
                            {
                                totalComputedProfileForSubmit = firstSubmit ? totalComputedProfileForSubmit : 0;
                                dataErrorCode = unitOfWork.SaveChanges(userID);

                                if (dataErrorCode == DataErrorCode.Locked)
                                {
                                    break;
                                }
                            }

                            #endregion
                        }
                        catch
                        {
                            throw new Exception(profileId.ToString());
                        }
                    }
                }

                #endregion

                //Lưu tất cả kết quả tính công
                dataErrorCode = unitOfWork.SaveChanges(userID);
                return attendanceTableCount;
            }
        }