Example #1
0
        public JsonResult Create([Bind(Include = "staffNr,attendanceDate, actWorkingHour, remark, actExtraWorkingHour, extraWorkType")] AttendanceRecordCal arc)
        {
            ResultMessage msg = new ResultMessage();

            try
            {
                msg = DoValidation(arc);

                if (!msg.Success)
                {
                    return(Json(msg, JsonRequestBehavior.AllowGet));
                }
                else
                {
                    IAttendanceRecordCalService arcs = new AttendanceRecordCalService(Settings.Default.db);
                    bool isSucceed = arcs.Create(arc);

                    msg.Success = isSucceed;
                    msg.Content = isSucceed ? "" : "创建失败";

                    return(Json(msg, JsonRequestBehavior.AllowGet));
                }
            }
            catch (Exception ex)
            {
                return(Json(new ResultMessage()
                {
                    Success = false, Content = ex.Message
                }, JsonRequestBehavior.AllowGet));
            }
        }
Example #2
0
        public ActionResult UpdateActHour(int id)
        {
            ResultMessage msg          = new ResultMessage();
            double        actHour      = 0;
            double        actExtraHour = 0;

            if (!double.TryParse(Request.Form["actWorkingHourRound"], out actHour))
            {
                msg.Content = "工作日工时必须是数字";
                return(Json(msg));
            }

            // 加班时间可以为空
            // 如果加班为空, 直接写入0
            // 如果不为空, 则所填必须为数字
            if (!string.IsNullOrWhiteSpace(Request.Form["actExtraWorkingHourRound"]) && !double.TryParse(Request.Form["actExtraWorkingHourRound"], out actExtraHour))
            {
                msg.Content = "加班工时必须是数字";
                return(Json(msg));
            }

            bool handled = false;

            if (!bool.TryParse(Request.Form["isExceptionHandled"], out handled))
            {
                msg.Content = "是否处理值非法,请刷新页面重新填写";
                return(Json(msg));
            }

            IAttendanceRecordCalService ss     = new AttendanceRecordCalService(Settings.Default.db);
            AttendanceRecordCal         record = ss.FindById(id);

            string oldHour    = record.actWorkingHour.ToString();
            string oldActHour = record.actExtraWorkingHour.ToString();

            //判断加班类型是否为空, 如果为空, 就返回null
            // 如果做判断,直接使用int.Parse转,会报异常

            int?ExtraWorkType = null;

            if (!string.IsNullOrWhiteSpace(Request.Form["extraWorkType"]))
            {
                ExtraWorkType = int.Parse(Request.Form["extraWorkType"]);
            }

            msg = ss.UpdateActHourById(id, actHour, actExtraHour, handled, Request.Form["remark"], ExtraWorkType);

            string newHour    = actHour.ToString();
            string newActHour = actExtraHour.ToString();

            // 创建调整考勤记录##User##
            try
            {
                IMessageRecordService mrs = new MessageRecordService(Settings.Default.db);
                mrs.CreateStaffUpdateAttHourMessage(record.staffNr, (Session["user"] as User).id, oldHour, newHour, oldActHour, newActHour);
            }
            catch { }

            return(Json(msg));
        }
Example #3
0
        // GET: AttendanceRecordCal/Delete/5
        public ActionResult Delete(int id)
        {
            IAttendanceRecordCalService arcs = new AttendanceRecordCalService(Settings.Default.db);

            AttendanceRecordCal record = arcs.FindById(id);

            SetExtraWorkTypeList(record.extraworkType);



            if (record != null)
            {
                AbsenceRecordView   absenceRecord   = new AbsenceRecordService(Settings.Default.db).FindViewByStaffNrAndDate(record.staffNr, record.attendanceDate);
                ExtraWorkRecordView extraWorkRecord = new ExtraWorkRecordService(Settings.Default.db).FindViewByStaffNrAndDate(record.staffNr, record.attendanceDate);

                List <AttendanceRecordDetailView> records = new List <AttendanceRecordDetailView>();
                IAttendanceRecordDetailService    s       = new AttendanceRecordDetailService(Settings.Default.db);
                records = s.GetDetailsViewByStaffAndDateWithExtrawork(record.staffNr, record.attendanceDate);
                ViewData["attendRecords"]   = records;
                ViewData["absenceRecord"]   = absenceRecord;
                ViewData["extraWorkRecord"] = extraWorkRecord;
            }
            else
            {
                SetExtraWorkTypeList(null);
            }


            return(View(record));
        }
Example #4
0
        private ResultMessage DoValidation(AttendanceRecordCal model)
        {
            ResultMessage msg          = new ResultMessage();
            double        actHour      = 0;
            double        actExtraHour = 0;

            if (string.IsNullOrEmpty(model.staffNr))
            {
                msg.Success = false;
                msg.Content = "员工号不能为空";

                return(msg);
            }

            if (string.IsNullOrWhiteSpace(model.attendanceDate.ToString()))
            {
                msg.Success = false;
                msg.Content = "日期不能为空";

                return(msg);
            }

            if (!double.TryParse(model.actWorkingHour.ToString(), out actHour))
            {
                msg.Success = false;
                msg.Content = "工作时长必须是数字";

                return(msg);
            }

            //可以为空
            //不为空的时候检查是否是数字

            if (!string.IsNullOrWhiteSpace(model.actExtraWorkingHour.ToString()) && !double.TryParse(model.actExtraWorkingHour.ToString(), out actExtraHour))
            {
                msg.Success = false;
                msg.Content = "加班时长必须是数字";

                return(msg);
            }

            IStaffService ss          = new StaffService(Settings.Default.db);
            bool          staffResult = ss.IsStaffExist(model.staffNr);

            if (!staffResult)
            {
                msg.Success = false;
                msg.Content = "员工不存在,请先创建员工";

                return(msg);
            }

            return(new ResultMessage()
            {
                Success = true, Content = ""
            });
        }
Example #5
0
        public bool DeleteById(int id)
        {
            AttendanceRecordCal arc = this.context.GetTable <AttendanceRecordCal>().FirstOrDefault(c => c.id.Equals(id));

            if (arc != null)
            {
                this.context.GetTable <AttendanceRecordCal>().DeleteOnSubmit(arc);
                this.context.SubmitChanges();
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #6
0
 public bool Create(AttendanceRecordCal attendanceRecordCal)
 {
     return(attendanceRecordCalRepo.Create(attendanceRecordCal));
 }
Example #7
0
        /// <summary>
        /// 将Detail的数据计算到Cal中
        /// 将班次结束点日期等于date日期,结束点时间小于等于date时间的班次考勤进行计算
        /// </summary>
        /// <param name="dateTime">计算的时间</param>
        /// <param name="shiftCodes">班次代码</param>
        /// <param name="searchModel">需要计算的员工的查询条件, **NOT IMPLEMENT**</param>
        public void CalculateAttendRecord(DateTime dateTime, List <string> shiftCodes = null, StaffSearchModel searchModel = null)
        {
            DataContext dc = new DataContext(this.DbString);
            /// 判断配置
            SystemSetting setting = dc.Context.GetTable <SystemSetting>().FirstOrDefault();

            if (setting == null)
            {
                throw new SystemSettingNotSetException();
            }

            /// 查找员工的需要被计算的排班
            //IStaffService staffService = new StaffService(this.DbString);
            //List<Staff> staffs = staffService.Search(searchModel).ToList();
            var allShiftShedulesQ = dc.Context.GetTable <ShiftScheduleView>().Where(s => s.fullEndAt.Value <= dateTime && s.fullEndAt.Value.Date.Equals(dateTime.Date));

            if (shiftCodes != null && shiftCodes.Count > 0)
            {
                if (shiftCodes.Count > 1)
                {
                    allShiftShedulesQ = allShiftShedulesQ.Where(s => shiftCodes.Contains(s.code));
                }
                else
                {
                    allShiftShedulesQ = allShiftShedulesQ.Where(s => s.code.Equals(shiftCodes.First()));
                }
            }
            List <ShiftScheduleView> allShiftShedules = allShiftShedulesQ.ToList();
            Dictionary <string, List <ShiftScheduleView> > allStaffShitSchedules = new Dictionary <string, List <ShiftScheduleView> >();

            foreach (var ssv in allShiftShedules)
            {
                if (!allStaffShitSchedules.ContainsKey(ssv.staffNr))
                {
                    allStaffShitSchedules.Add(ssv.staffNr, new List <ShiftScheduleView>());
                }
                allStaffShitSchedules[ssv.staffNr].Add(ssv);
            }
            Dictionary <string, List <AttendanceRecordCal> > staffAttendCals = new Dictionary <string, List <AttendanceRecordCal> >();

            /// 循环每一个员工
            foreach (var staffShiftShedule in allStaffShitSchedules)
            {
                Dictionary <DateTime, double> totalWorkingHours = new Dictionary <DateTime, double>();
                Dictionary <DateTime, List <AttendanceExceptionType> > exceptions = new Dictionary <DateTime, List <AttendanceExceptionType> >();
                // 获取今日、昨日的所有排班
                List <ShiftScheduleView> staffShitSchedules = staffShiftShedule.Value; // dc.Context.GetTable<ShiftScheduleView>()
                                                                                       // .Where(s => s.staffNr.Equals(staff.nr) && (s.scheduleAt.Date.Equals(date.Date) || (s.scheduleAt.Equals(date.Date.AddDays(-1)) && s.shiftType.Equals((int)ShiftType.Tommorrow)))).ToList();

                if (staffShitSchedules.Count == 0)
                {
                    //TODO UPDATE OR CREATE
                    //AttendanceRecordCal recordCal = new AttendanceRecordCal() { staffNr = staff.nr, actWorkingHour = 0, oriWorkingHour = 0, attendanceDate = date, createdAt = DateTime.Now, isManualCal = false, remark = "没有排班" };
                    //recordCal.actWorkingHour = recordCal.oriWorkingHour = 0;

                    /// 如果没有排班则跳过, 写入出勤时间为0 ?
                    break;
                }

                foreach (var shift in staffShitSchedules)
                {
                    DateTime shiftDate = shift.fullStartAt.Value.Date;// dateTime.Date.AddDays(shift.shiftType.Equals((int)ShiftType.Today) ? 0 : -1);
                    if (!totalWorkingHours.ContainsKey(shiftDate))
                    {
                        totalWorkingHours.Add(shiftDate, 0);
                    }
                    exceptions[shiftDate] = new List <AttendanceExceptionType>();


                    //  DateTime shiftStart = shift.scheduleAt.AddDays(shift.shiftType.Equals((int)ShiftType.Today) ? 0 : -1).Add(shift.startAt);

                    DateTime shiftStart = shift.fullStartAt.Value; //shift.scheduleAt.Add(shift.startAt);
                    DateTime shiftEnd   = shift.fullEndAt.Value;   //shift.scheduleAt.AddDays(shift.shiftType.Equals((int)ShiftType.Today) ? 0 : 1).Add(shift.endAt);

                    DateTime sq = shiftStart.AddMinutes(0 - setting.validAttendanceRecordTime.Value);
                    DateTime eq = shiftEnd.AddMinutes(setting.validAttendanceRecordTime.Value);

                    List <AttendanceRecordDetail> records = dc.Context.GetTable <AttendanceRecordDetail>().Where(s => s.staffNr.Equals(staffShiftShedule.Key) && s.recordAt >= sq && s.recordAt <= eq).OrderBy(s => s.recordAt).ToList();
                    //staff.AttendanceRecordDetail.Where(s => s.recordAt >= sq && s.recordAt <= eq).ToList().OrderBy(s => s.recordAt).ToList();

                    if (records.Count == 0)
                    {
                        /// TODO UPDATE OR CREATE
                        /// 创建异常,班次旷工,考勤的时间为 0
                        exceptions[shiftDate].Add(AttendanceExceptionType.ShiftAbsence);
                    }
                    else
                    {
                        /// 清洗短时间内的重复打卡数据
                        MarkRepeatRecord(records, (float)setting.repeatAttendanceRecordTime.Value);
                        List <AttendanceRecordDetail> validRecrods = records.Where(s => s.isRepeatedData == false).ToList();
                        if (validRecrods.Count == 1)
                        {
                            /// TODO UPDATE OR CREATE
                            /// 创建异常,考勤记录不完整,考勤的时间为 0
                            exceptions[shiftDate].Add(AttendanceExceptionType.MessRecord);
                        }
                        else
                        {
                            // 判断迟到
                            DateTime firstAt = validRecrods.First().recordAt;
                            if (firstAt.AddMinutes(0 - setting.lateExceptionTime.Value) > shiftStart)
                            {
                                /// TODO UPDATE OR CREATE
                                /// 创建异常,迟到
                                exceptions[shiftDate].Add(AttendanceExceptionType.Late);
                            }

                            DateTime lastAt = validRecrods.Last().recordAt;
                            if (lastAt.AddMinutes(setting.earlyLeaveExceptionTime.Value) < shiftEnd)
                            {
                                /// TODO UPDATE OR CREATE
                                /// 创建早退,迟到
                                exceptions[shiftDate].Add(AttendanceExceptionType.EarlyLeave);
                            }

                            if (validRecrods.Count % 2 == 1)
                            {
                                /// TODO UPDATE OR CREATE
                                /// 创建异常,考勤记录不完整,考勤的时间为 0
                                exceptions[shiftDate].Add(AttendanceExceptionType.MessRecord);
                            }

                            for (int i = 0; i < validRecrods.Count - 1; i += 2)
                            {
                                totalWorkingHours[shiftDate] += (validRecrods[i + 1].recordAt - validRecrods[i].recordAt).TotalHours;
                            }
                        }
                    }
                }
                staffAttendCals.Add(staffShiftShedule.Key, new List <AttendanceRecordCal>());
                // 创建, 计算过的出勤时间
                foreach (var dic in totalWorkingHours)
                {
                    AttendanceRecordCal cal = new AttendanceRecordCal()
                    {
                        attendanceExceptions = exceptions[dic.Key],
                        createdAt            = DateTime.Now,
                        oriWorkingHour       = Math.Round(dic.Value, 2),
                        actWorkingHour       = Math.Round(dic.Value, 2),
                        staffNr        = staffShiftShedule.Key,
                        attendanceDate = dic.Key
                    };
                    staffAttendCals[staffShiftShedule.Key].Add(cal);
                }
            }

            //using (TransactionScope scope = new TransactionScope())
            //{
            DataContext subDc = new DataContext(this.DbString);
            List <AttendanceRecordCal> insertCals = new List <AttendanceRecordCal>();

            foreach (var dic in staffAttendCals)
            {
                // string nrsq = string.Format(",{0},", string.Join(",", staffAttendCals.Keys));
                // string dateq = string.Format(",{0},", string.Join(",", staffAttendCals[dic.Key].Select(ss => ss.attendanceDate.ToString("yyyy-MM-dd")).ToList()));
                /// 手动修改的不会被修改实际值
                //List<AttendanceRecordCal> _updateCals = subDc.Context.GetTable<AttendanceRecordCal>()
                //    .Where(s => staffAttendCals.Keys.Contains(s.staffNr)
                //    && (staffAttendCals[dic.Key].Select(ss => ss.attendanceDate).ToList()
                //    .Contains(s.attendanceDate))).ToList();
                //List<AttendanceRecordCal> _updateCals = subDc.Context.GetTable<AttendanceRecordCal>()
                // .AsEnumerable()
                //.Join(staffAttendCals.Keys,s=>s.staffNr,ci=>ci, (s,ci)=> s)
                //.Join(staffAttendCals[dic.Key].Select(ss => ss.attendanceDate).ToList(),sss=>sss.attendanceDate,cci=>cci,(sss,cci)=>sss).ToList();

                List <AttendanceRecordCal> _updateCals = new List <AttendanceRecordCal>();
                //   IQueryable<AttendanceRecordCal> _updateCalsQ = dc.Context.GetTable<AttendanceRecordCal>()
                //.Where(s => nrsq.IndexOf("," + s.staffNr + ",") != -1);
                IQueryable <AttendanceRecordCal> _updateCalsQ = dc.Context.GetTable <AttendanceRecordCal>()
                                                                .Where(s => s.staffNr.Equals(dic.Key));
                if (staffAttendCals[dic.Key].Count == 0)
                {
                }
                else if (staffAttendCals[dic.Key].Count == 1)
                {
                    _updateCals = _updateCalsQ.Where(s => s.attendanceDate.Equals(staffAttendCals[dic.Key].First().attendanceDate)).ToList();
                }
                else
                {
                    _updateCals = _updateCalsQ.Where(s => staffAttendCals[dic.Key].Select(ss => ss.attendanceDate).ToList().Contains(s.attendanceDate)).ToList();
                }

                //.Where(ss => dateq.IndexOf("," + ss.attendanceDate.ToString("yyyy-MM-dd") + ",") != -1).ToList();


                foreach (var u in _updateCals)
                {
                    var c = dic.Value.Where(d => d.attendanceDate.Equals(u.attendanceDate)).FirstOrDefault();

                    if (c != null)
                    {
                        u.oriWorkingHour = u.actWorkingHour = c.oriWorkingHour;
                        u.isManualCal    = false;
                        if (c != null)
                        {
                            u.oriWorkingHour = c.oriWorkingHour;
                            if (u.isManualCal == false)
                            {
                                u.actWorkingHour = c.oriWorkingHour;
                                u.isManualCal    = false;
                            }
                            u.createdAt      = DateTime.Now;
                            u.isException    = c.isException;
                            u.exceptionCodes = c.exceptionCodes;
                        }
                    }
                }
                List <AttendanceRecordCal> _insertCals = dic.Value.Where(s => !_updateCals.Select(ss => ss.attendanceDate).Contains(s.attendanceDate)).ToList();
                insertCals.AddRange(_insertCals);

                /// scope 完成
                //  scope.Complete();
                // }
            }

            subDc.Context.GetTable <AttendanceRecordCal>().InsertAllOnSubmit(insertCals);

            subDc.Context.SubmitChanges();
        }
Example #8
0
        public void CalculateAttendRecordWithExtrawork(DateTime datetime, List <string> shiftCodes = null, StaffSearchModel searchModel = null)
        {
            // 是否是休息日
            IWorkAndRestService wars = new WorkAndRestService(this.DbString);
            WorkAndRest         wr   = wars.FindByDate(datetime);
            bool          isRestDay  = wars.IsRestDay(wr);
            SystemSetting setting    = new SystemSettingService(this.DbString).Find();


            DataContext dc = new DataContext(this.DbString);



            // 计算在职人员的考勤
            List <Staff> staffs = dc.Context.GetTable <Staff>().Where(s => (s.workStatus == (int)WorkStatus.OnWork) || (s.workStatus == (int)WorkStatus.OffWork && s.resignAt >= datetime)).ToList();

            foreach (Staff staff in staffs)
            {
                double workdayHour = 0;

                double extraHour = 0;
                // 异常情况
                List <AttendanceExceptionType> exceptions = new List <AttendanceExceptionType>();
                if (staff.nr.Equals("201471"))
                {
                    string s = "201471";
                }
                // 获取已经结束的排班
                List <ShiftScheduleView> shifts = dc.Context.GetTable <ShiftScheduleView>().Where(s => s.staffNr.Equals(staff.nr) && s.fullStartAt.Value.Date == datetime.Date && s.fullEndAt <= DateTime.Now).ToList();
                if (shifts.Count > 0)
                {
                    foreach (var shift in shifts)
                    {
                        DateTime validSQ = shift.fullStartAt.Value.AddMinutes(0 - setting.validAttendanceRecordTime.Value);
                        DateTime validEQ = shift.fullEndAt.Value.AddMinutes(0 + setting.validAttendanceRecordTime.Value);
                        DateTime sq      = validSQ;
                        DateTime eq      = shift.shiftType == (int)ShiftType.Today ? datetime.Date.AddDays(1).AddHours(8) : datetime.Date.AddDays(1).AddHours(23);

                        ShiftScheduleView nextShift = new ShiftSheduleService(this.DbString).GetNextShiftScheduleView(staff.nr, shift.fullEndAt.Value);

                        if (nextShift != null)
                        {
                            if ((nextShift.fullStartAt.Value.Date - shift.fullStartAt.Value.Date).TotalDays < 2)
                            {
                                eq = nextShift.fullStartAt.Value.AddMinutes(0 - setting.validAttendanceRecordTime.Value);
                            }
                        }

                        List <AttendanceRecordDetail> records = new AttendanceRecordDetailService(this.DbString).GetByStaffAndTimespan(staff.nr, sq, eq);
                        if (records.Count == 0)
                        {
                            // 旷工,可能他有请假。。。
                            exceptions.Add(AttendanceExceptionType.Absence);
                        }
                        else
                        {
                            /// 清洗数据
                            MarkRepeatRecordByMinute(records, (float)setting.repeatAttendanceRecordTime.Value);
                            records = records.Where(s => s.isRepeatedData == false).ToList();

                            // 如果考勤记录不配对,如 进-出 的偶数被,则是打开记录不完整
                            // 但是这不影响计算
                            if (records.Count % 2 != 0)
                            {
                                exceptions.Add(AttendanceExceptionType.MessRecord);
                            }

                            /// 开始计算
                            /// 早到的使用排班开始时间,晚到的算迟到,提早走的算早退
                            /// 此处不涉及到多次进出-计算目前只能算出大概,很难精确
                            /// 打卡迟了肯定算迟到
                            /// 如果早退了一般不会来加班了
                            // 是否有早打卡?
                            // int hasEarlyCount= records.Where(s => s.recordAt < shift.fullStartAt.Value).Count();

                            if (records.Count == 1)
                            {
                                exceptions.Add(AttendanceExceptionType.MessRecord);
                                /// 以下都是推测,都是要人为的调整的
                                DateTime recordAt = records[0].recordAt;
                                // 如果是早来,迟走,可能是忘记打卡了
                                if (recordAt < shift.fullStartAt.Value || (records.Last().recordAt >= shift.fullEndAt.Value && recordAt <= validEQ))
                                {
                                    /// 如果早来超过一个小时,可能是加班
                                    if (recordAt <= shift.fullStartAt.Value.AddHours(-1))
                                    {
                                        extraHour = (shift.fullStartAt.Value - recordAt).TotalHours;
                                    }
                                    workdayHour = (shift.fullEndAt.Value - shift.fullStartAt.Value).TotalHours;
                                }// 如果迟走超过一个小时,可能是加班,即使此处误判,也需要加班单存在的
                                else if (recordAt >= shift.fullEndAt.Value.AddHours(1))
                                {
                                    exceptions.Add(AttendanceExceptionType.ExtraWork);
                                    workdayHour = (shift.fullEndAt.Value - shift.fullStartAt.Value).TotalHours;
                                    extraHour   = (recordAt - shift.fullEndAt.Value).TotalHours;
                                }
                                else
                                {
                                    // 如果只有一次打卡记录在应该的工作区间内,则需要人工手动调整了!
                                }
                            }
                            else
                            {
                                DateTime firstD = records.First().recordAt;
                                DateTime lastD  = records.Last().recordAt;
                                // 正常上班,无加班
                                // 1. 如果走时间在排班结束范围外内,则算整个排班时间
                                if (lastD >= shift.fullEndAt.Value &&
                                    lastD <= validEQ)
                                {
                                    if (firstD <= shift.fullStartAt)
                                    {
                                        /// 如果早来超过一个小时,可能是加班
                                        if (firstD <= shift.fullStartAt.Value.AddHours(-1))
                                        {
                                            extraHour = (shift.fullStartAt.Value - firstD).TotalHours;
                                        }
                                        // 正常
                                        workdayHour = (shift.fullEndAt.Value - shift.fullStartAt.Value).TotalHours;
                                    }
                                    else
                                    {
                                        // 迟到
                                        exceptions.Add(AttendanceExceptionType.Late);
                                        workdayHour = (shift.fullEndAt.Value - firstD).TotalHours;
                                    }
                                }
                                else
                                {
                                    if (lastD < shift.fullEndAt.Value)
                                    {
                                        // 早退
                                        exceptions.Add(AttendanceExceptionType.EarlyLeave);
                                        if (firstD < shift.fullStartAt)
                                        {
                                            /// 如果早来超过一个小时,可能是加班
                                            if (firstD <= shift.fullStartAt.Value.AddHours(-1))
                                            {
                                                extraHour = (shift.fullStartAt.Value - firstD).TotalHours;
                                            }
                                            workdayHour = (lastD - shift.fullStartAt.Value).TotalHours;
                                        }
                                        else
                                        {
                                            // 迟到+早退
                                            exceptions.Add(AttendanceExceptionType.Late);
                                            workdayHour = (lastD - firstD).TotalHours;
                                        }
                                    }
                                    else
                                    {
                                        if (lastD >= shift.fullEndAt.Value.AddHours(1))
                                        {
                                            exceptions.Add(AttendanceExceptionType.ExtraWork);

                                            workdayHour = (shift.fullEndAt.Value - shift.fullStartAt.Value).TotalHours;
                                            extraHour   = (lastD - shift.fullEndAt.Value).TotalHours;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    // 如果没有排班怎么计算?
                    // 如果没有排班,应该都是加班
                    // TODO, 根据目前和德晋HR了解情况,会排班,所以这种情况暂时不考虑
                }
                /// 暂时对没有排班的不处理
                if (shifts.Count > 0)
                {
                    // 基本工时都是 8 小时,不分部门和职称
                    if (workdayHour > 8)
                    {
                        workdayHour = 8;
                    }

                    /// 如果是双休或节假日都算加班!无论是否有排班
                    if (isRestDay)
                    {
                        extraHour  += workdayHour;
                        workdayHour = 0;
                    }
                    extraHour   = Math.Round(extraHour, 1);
                    workdayHour = Math.Round(workdayHour, 1);

                    // 如果是成型课 或者 行政课的司机,则加班不减0.5h,其它的都减
                    if (extraHour > 0)
                    {
                        exceptions.Add(AttendanceExceptionType.ExtraWork);
                        if (staff.IsMinusExtraWorkHour)
                        {
                            extraHour -= 0.5;
                            if (extraHour < 0)
                            {
                                extraHour = 0;
                            }
                        }
                        ExtraWorkRecord extraRecord = new ExtraWorkRecordService(this.DbString).FindByStaffNrAndDete(staff.nr, datetime.Date);
                        if (extraRecord == null)
                        {
                            exceptions.Add(AttendanceExceptionType.ExtraWorkNoRecord);
                        }
                        else
                        {
                            if (extraHour != extraRecord.duration)
                            {
                                exceptions.Add(AttendanceExceptionType.ExtraWorkHourNotMatch);
                            }

                            if (wr.dateType != extraRecord.ExtraWorkType.systemCode)
                            {
                                exceptions.Add(AttendanceExceptionType.ExtraWorkTypeNotMatch);
                            }
                        }
                    }

                    DataContext         comitDC   = new DataContext(this.DbString);
                    AttendanceRecordCal calRecord = comitDC.Context.GetTable <AttendanceRecordCal>().FirstOrDefault(s => s.staffNr.Equals(staff.nr) && s.attendanceDate.Equals(datetime.Date));

                    exceptions = exceptions.Distinct().ToList();
                    int?extraType = extraHour == 0 ? null : wr.dateType;
                    if (calRecord == null)
                    {
                        comitDC.Context.GetTable <AttendanceRecordCal>().InsertOnSubmit(new AttendanceRecordCal()
                        {
                            staffNr              = staff.nr,
                            attendanceDate       = datetime.Date,
                            oriWorkingHour       = workdayHour,
                            actWorkingHour       = workdayHour,
                            oriExtraWorkingHour  = extraHour,
                            actExtraWorkingHour  = extraHour,
                            extraworkType        = extraType,
                            attendanceExceptions = exceptions.Distinct().ToList(),
                            createdAt            = DateTime.Now
                        });
                    }
                    else
                    {
                        calRecord.extraworkType        = extraType;
                        calRecord.oriWorkingHour       = calRecord.actWorkingHour = workdayHour;
                        calRecord.oriExtraWorkingHour  = calRecord.actExtraWorkingHour = extraHour;
                        calRecord.createdAt            = DateTime.Now;
                        calRecord.attendanceExceptions = exceptions;
                    }
                    comitDC.Context.SubmitChanges();
                }
            }
        }