/// <summary> /// 获取某一天的打卡记录,无论排班是否开始或结束 /// </summary> /// <param name="nr"></param> /// <param name="datetime"></param> /// <returns></returns> public List <AttendanceRecordDetailView> GetDetailsViewByStaffAndDateWithExtrawork(string nr, DateTime datetime) { List <AttendanceRecordDetailView> records = new List <AttendanceRecordDetailView>(); SystemSetting setting = new SystemSettingService(this.DbString).Find(); DataContext dc = new DataContext(this.DbString); List <ShiftScheduleView> shifts = dc.Context.GetTable <ShiftScheduleView>().Where(s => s.staffNr.Equals(nr) && s.fullStartAt.Value.Date.Equals(datetime.Date)).OrderBy(s => s.fullStartAt).ToList(); if (shifts.Count > 0) { /// 找出在单个shift之间的 foreach (var s in shifts) { DateTime sq = s.fullStartAt.Value.AddMinutes(0 - setting.validAttendanceRecordTime.Value); DateTime eq = s.fullEndAt.Value.AddMinutes(setting.validAttendanceRecordTime.Value); List <AttendanceRecordDetailView> shiftAttendRecords = dc.Context.GetTable <AttendanceRecordDetailView>().Where(ss => ss.recordAt >= sq && ss.recordAt <= eq && ss.staffNr.Equals(nr)).OrderBy(ss => ss.recordAt).ToList();//new List<AttendanceRecordDetailView>(); // records.AddRange(shiftAttendRecords); foreach (var r in shiftAttendRecords) { if (records.FirstOrDefault(ss => s.id == r.id) == null) { records.Add(r); } } } /// 找出每两个shift之间的,及A的结束到B的开始,如果没有B,则A的开始到datetime的次日23:59:59 foreach (var firstShift in shifts) { ShiftScheduleView nextShift = dc.Context.GetTable <ShiftScheduleView>().Where(s => s.staffNr.Equals(nr) && s.fullStartAt > firstShift.fullEndAt).OrderBy(s => s.fullStartAt).FirstOrDefault(); DateTime sq = firstShift.fullEndAt.Value.AddMinutes(0 + setting.validAttendanceRecordTime.Value); DateTime eq = nextShift == null?datetime.Date.AddDays(1).Add(new TimeSpan(23, 59, 59)) : nextShift.fullStartAt.Value.AddMinutes(0 - setting.validAttendanceRecordTime.Value); List <AttendanceRecordDetailView> shiftAttendRecords = dc.Context.GetTable <AttendanceRecordDetailView>().Where(ss => ss.recordAt >= sq && ss.recordAt <= eq && ss.staffNr.Equals(nr)).OrderBy(ss => ss.recordAt).ToList(); //new List<AttendanceRecordDetailView>(); // records.AddRange(shiftAttendRecords); foreach (var r in shiftAttendRecords) { if (records.FirstOrDefault(ss => ss.id == r.id) == null) { records.Add(r); } } } } else { //ShiftScheduleView prevShift = dc.Context.GetTable<ShiftScheduleView>().Where(s => s.staffNr.Equals(nr) && s.fullEndAt < datetime).OrderByDescending(s => s.fullEndAt).FirstOrDefault(); //ShiftScheduleView nextShift= dc.Context.GetTable<ShiftScheduleView>().Where(s => s.staffNr.Equals(nr) && s.fullStartAt > datetime).OrderBy(s => s.fullStartAt).FirstOrDefault(); ///// 如果没有排班,则找出前一天开始,到次日的结束 //DateTime sq = prevShift== null? datetime.Date.AddDays(-1) : prevShift.fullEndAt.Value.AddMinutes(0 + setting.validAttendanceRecordTime.Value); //DateTime eq = nextShift == null ? datetime.Date.AddDays(1).Add(new TimeSpan(23, 59, 59)) : nextShift.fullStartAt.Value.AddMinutes(0 - setting.validAttendanceRecordTime.Value); //List<AttendanceRecordDetailView> shiftAttendRecords = dc.Context.GetTable<AttendanceRecordDetailView>().Where(ss => ss.recordAt >= sq && ss.recordAt <= eq && ss.staffNr.Equals(nr)).OrderBy(ss => ss.recordAt).ToList();//new List<AttendanceRecordDetailView>(); //records.AddRange(shiftAttendRecords); } List <AttendanceRecordDetailView> todayRecords = dc.Context.GetTable <AttendanceRecordDetailView>().Where(ss => ss.recordAt >= datetime.Date && ss.recordAt <= datetime.Date.Add(new TimeSpan(23, 59, 59)) && ss.staffNr.Equals(nr)).OrderBy(ss => ss.recordAt).ToList(); foreach (var r in todayRecords) { if (records.FirstOrDefault(s => s.id == r.id) == null) { records.Add(r); } } return(records.Distinct().OrderBy(ss => ss.recordAt).ToList());; }
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(); } } }