using Entity.Sugar; using SqlSugar; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace EasyBL { public class AttendanceMethods { /// /// 彈性工時計算 /// /// /// /// 依序:工作起、工作迄、是否遲到 public Tuple GetFlexTime(AttendanceRule attendanceRule, string SignIn) { var UseStartTime = @""; //實際使用上班時間。 var UseEndTime = @""; //實際使用上班時間。 var AnyBuffer = true; var WorkDelay = false; if (string.IsNullOrWhiteSpace(attendanceRule.WorkStartBuffer)) { AnyBuffer = false; } //檢查有無buffer if (AnyBuffer) { var SignInTime = Convert.ToDateTime(SignIn); var StandardWorkStart = Convert.ToDateTime(attendanceRule.WorkStart); var StandardWorkEnd = Convert.ToDateTime(attendanceRule.WorkEnd); var BufferedWorkStart = Convert.ToDateTime(attendanceRule.WorkStartBuffer + ":59"); //-1: t1 早於 t2。 0: t1 與 t2 相同。 1: t1 晚於 t2。 var CheckStandardThreadhold = DateTime.Compare(SignInTime, StandardWorkStart) > 0; if (CheckStandardThreadhold) { var CheckBufferThreadhold = DateTime.Compare(SignInTime, BufferedWorkStart); switch (CheckBufferThreadhold) { case 1: WorkDelay = true; var TotalBufferHour = ExecDateDiff(StandardWorkStart, BufferedWorkStart); StandardWorkEnd = StandardWorkEnd.AddHours(TotalBufferHour); if (attendanceRule.DelayBuffer > 0) { BufferedWorkStart = BufferedWorkStart.AddMinutes(-1 * attendanceRule.DelayBuffer); StandardWorkEnd = StandardWorkEnd.AddMinutes(-1 * attendanceRule.DelayBuffer); } UseEndTime = StandardWorkEnd.ToString("HH:mm"); UseStartTime = BufferedWorkStart.ToString("HH:mm"); break; case 0: case -1: var WorkStartBuffer = ExecDateDiff(StandardWorkStart, SignInTime); WorkDelay = false; UseEndTime = StandardWorkEnd.AddHours(WorkStartBuffer).ToString("HH:mm"); UseStartTime = StandardWorkStart.AddHours(WorkStartBuffer).ToString("HH:mm"); break; default: break; } } else { WorkDelay = false; UseEndTime = attendanceRule.WorkEnd; UseStartTime = attendanceRule.WorkStart; } } //無緩衝 else { WorkDelay = DateTime.Compare(Convert.ToDateTime(SignIn), Convert.ToDateTime(attendanceRule.WorkStart)) > 0; UseStartTime = attendanceRule.WorkStart; UseEndTime = attendanceRule.WorkEnd; } return new Tuple(UseStartTime, UseEndTime, WorkDelay); } /// /// 計算工作時間。 /// 必須SignOut、SignIn有時間,SignOut晚於SignIn、TimeA(工作時間起)和TimeP(工作時間迄) /// /// /// /// public double GetWorkingHour(string sSignTime, OTB_EIP_Attendance info) { var WorkingHour = 0.0; var CheckAvaliableTime = !string.IsNullOrWhiteSpace(info.SignOut) && !string.IsNullOrWhiteSpace(info.SignIn); var HasDiffTime = ExecDateDiff(Convert.ToDateTime(info.SignIn), Convert.ToDateTime(info.SignOut)) > 0; var HasWorkTime = !string.IsNullOrWhiteSpace(info.TimeA) && !string.IsNullOrWhiteSpace(info.TimeP); if (CheckAvaliableTime && HasDiffTime && HasWorkTime) { var StandardWorkStart = Convert.ToDateTime(info.TimeA); var StandardWorkEnd = Convert.ToDateTime(info.TimeP); var SignInTime = Convert.ToDateTime(info.SignIn); if (SignInTime.Second > 0) //取最小量 SignInTime = SignInTime.AddSeconds(-1 * SignInTime.Second); var SignOutTime = Convert.ToDateTime(sSignTime); if (SignOutTime.Second > 0) //取最大量 SignOutTime = SignOutTime.AddSeconds(-1 * SignOutTime.Second); var ActualStartTime = new DateTime(); var ActualEndTime = new DateTime(); //實際認列開始工作時間。過早一律認列上班時間 var WorkStartThreadhold = DateTime.Compare(SignInTime, StandardWorkStart); //實際認列結束工作時間。 var WorkEndThreadhold = DateTime.Compare(SignOutTime, StandardWorkEnd); switch (WorkStartThreadhold) { //刷進時間 晚於 變動上班時間 case 1: ActualStartTime = SignInTime; break; //刷進時間 早於(等於) 變動上班時間 case 0: case -1: ActualStartTime = StandardWorkStart; break; default: break; } switch (WorkEndThreadhold) { case 1: case 0: ActualEndTime = StandardWorkEnd; break; case -1: ActualEndTime = SignOutTime; break; default: break; } //實際工作起 早於 實際工作迄(前面條件會變更) var TotalWorkTimeThreadhold = DateTime.Compare(ActualStartTime, ActualEndTime); switch (TotalWorkTimeThreadhold) { case 1: case 0: WorkingHour = 0; break; case -1: WorkingHour = Math.Round(ExecDateDiff(ActualStartTime, ActualEndTime), 2, MidpointRounding.AwayFromZero); break; default: break; } } return WorkingHour; } /// /// 計算考勤 /// /// 卡中資料 /// 出勤規則 /// 打卡日期 /// public List CalculateAttendance(string[] AllLineDatas, List AttendanceRules, DateTime CardDate) { var saCardAttendanceInfo = new List(); //讀取打卡信息 foreach (string str in AllLineDatas) { //打卡日期,卡號 , 刷卡時間,姓名 ,組織 //20190701,0410164401,14:03:39,陳OO ,TE var strInfo = str.Split(','); var sOrgID = strInfo[4].ToString().Trim(); if (string.IsNullOrEmpty(sOrgID)) { continue; } var sCardDate = strInfo[0].ToString().Trim(); var sCardId = strInfo[1].ToString().Trim(); var sSignTime = strInfo[2].ToString().Trim(); var sCardUserName = strInfo[3].ToString().Trim(); var sTimeA = @"09:00"; //標準上班時間 var sTimeP = @"17:30"; //標準下班時間 var sTimeAE = ""; //允許最彈性下班時間 var UseStartTime = @""; //實際使用上班時間。 var UseEndTime = @""; //實際使用上班時間。 var AnyBuffer = true; var ApplyRule = AttendanceRules.Where(ar => ar.OrgID == sOrgID).FirstOrDefault(); if (ApplyRule != null) { sTimeA = ApplyRule.WorkStart; sTimeP = ApplyRule.WorkEnd; sTimeAE = ApplyRule.WorkStartBuffer; } if (string.IsNullOrWhiteSpace(sTimeAE)) { AnyBuffer = false; sTimeAE = sTimeP; } if (saCardAttendanceInfo.Any(x => x.CardId == sCardId)) { //如果存在則更新打卡信息 foreach (OTB_EIP_Attendance info in saCardAttendanceInfo) { if (info.CardId == sCardId) { info.SignOut = sSignTime; var TotalWorkingHours = GetWorkingHour(sSignTime, info); var bStatusP = DateTime.Compare(Convert.ToDateTime(info.TimeP), Convert.ToDateTime(sSignTime)) > 0; info.Hours = TotalWorkingHours.ToString(); info.StatusP = bStatusP; break; } } } //不存在則新增 else { var FlexTime = GetFlexTime(ApplyRule, sSignTime); var oAttendanceInfo = new OTB_EIP_Attendance { OrgID = sOrgID, CardDate = CardDate, CardId = sCardId, TimeA = FlexTime.Item1, TimeP = FlexTime.Item2, CardUserName = sCardUserName, Hours = "0", SignIn = sSignTime, SignOut = "" }; oAttendanceInfo.StatusA = FlexTime.Item3; oAttendanceInfo.StatusP = false; oAttendanceInfo.Memo = ""; oAttendanceInfo.CreateDate = DateTime.Now; saCardAttendanceInfo.Add(oAttendanceInfo); } } return saCardAttendanceInfo; } /// /// 取得考勤規則 /// /// /// 至少要4個 /// public List GetAttendanceRule(SqlSugarClient db, List ConfigSettings) { var AttendanceRule = new List(); try { do { //WebConfig依序:上班開始時間、上班結束時間、最晚上班時間(工作緩衝時間)、遲到緩衝時間(分) //var ConfigSettings = new List() { Common.ConfigGetValue("", "WorkTimePMKey"), Common.ConfigGetValue("", "WorkTimeAMKey") // ,Common.ConfigGetValue("", "LatestShiftTimeKey"), Common.ConfigGetValue("", "DelayBufferTimeKey") }; var AllOrgIDs = db.Queryable().Select(it => it.OrgID).ToList().Distinct(); if(!ConfigSettings.Any()) { ConfigSettings = new List { "WorkTimePM", "WorkTimeAM", "LatestShiftTime", "DelayBufferTime" }; } var spWorkTimePMKey = new SugarParameter("@WorkTimePM", ConfigSettings[0]); var spDWorkTimeAMKey = new SugarParameter("@WorkTimeAM", ConfigSettings[1]); var spLatestShiftTimeKey = new SugarParameter("@LatestShiftTime", ConfigSettings[2]); var spDelayBufferKey = new SugarParameter("@DelayBuffer", ConfigSettings[3]); var AllOfSystemSettings = db.Ado.SqlQuery(@"select *from OTB_SYS_SystemSetting where Effective ='Y' and SettingItem in (@WorkTimePM, @WorkTimeAM, @LatestShiftTime, @DelayBuffer )", spWorkTimePMKey, spDWorkTimeAMKey, spLatestShiftTimeKey, spDelayBufferKey).ToArray(); // foreach (var OrgID in AllOrgIDs) { var attendanceRule = new AttendanceRule() { OrgID = OrgID }; foreach (var Key in ConfigSettings) { var MatchedRule = AllOfSystemSettings.Where(s => s.OrgID == OrgID && s.SettingItem == Key).FirstOrDefault(); if (MatchedRule != null && !string.IsNullOrWhiteSpace(MatchedRule.SettingValue)) { var SplittedTime = MatchedRule.SettingValue.Split(new char[] { '~' }, StringSplitOptions.RemoveEmptyEntries); switch (Key) { case "WorkTimePM": attendanceRule.WorkStart = SplittedTime[0].PadLeft(5, '0');//開始時間 attendanceRule.WorkTimePMDeadLine = MatchedRule.SettingValue; break; case "WorkTimeAM": attendanceRule.WorkEnd = SplittedTime[1].PadLeft(5, '0');//結束時間 attendanceRule.WorkTimeAMDeadLine = MatchedRule.SettingValue; break; case "LatestShiftTime": attendanceRule.WorkStartBuffer = SplittedTime[0].PadLeft(5, '0'); break; case "DelayBufferTime": var DelayBuffer = 0; var CheckIntValue = int.TryParse(MatchedRule.SettingValue, out DelayBuffer); attendanceRule.DelayBuffer = DelayBuffer; break; default: break; } } } AttendanceRule.Add(attendanceRule); } } while (false); } catch (Exception error) { throw error; } return AttendanceRule; } /// /// 程序执行时间测试 /// /// 开始时间 /// 结束时间 /// 返回(秒)单位,比如: 0.00239秒 private double ExecDateDiff(DateTime dateBegin, DateTime dateEnd) { var ts1 = new TimeSpan(dateBegin.Ticks); var ts2 = new TimeSpan(dateEnd.Ticks); var ts3 = ts1.Subtract(ts2).Duration(); //你想转的格式 return ts3.TotalHours; } } }