You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
345 lines
16 KiB
345 lines
16 KiB
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
|
|
{
|
|
|
|
/// <summary>
|
|
/// 彈性工時計算
|
|
/// </summary>
|
|
/// <param name="attendanceRule"></param>
|
|
/// <param name="SignIn"></param>
|
|
/// <returns>依序:工作起、工作迄、是否遲到</returns>
|
|
public Tuple<string, string, bool> 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<string, string,bool>(UseStartTime, UseEndTime, WorkDelay);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 計算工作時間。
|
|
/// 必須SignOut、SignIn有時間,SignOut晚於SignIn、TimeA(工作時間起)和TimeP(工作時間迄)
|
|
/// </summary>
|
|
/// <param name="sSignTime"></param>
|
|
/// <param name="info"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 計算考勤
|
|
/// </summary>
|
|
/// <param name="AllLineDatas">卡中資料</param>
|
|
/// <param name="AttendanceRules">出勤規則</param>
|
|
/// <param name="CardDate">打卡日期</param>
|
|
/// <returns></returns>
|
|
public List<OTB_EIP_Attendance> CalculateAttendance(string[] AllLineDatas, List<AttendanceRule> AttendanceRules, DateTime CardDate)
|
|
{
|
|
var saCardAttendanceInfo = new List<OTB_EIP_Attendance>();
|
|
|
|
//讀取打卡信息
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 取得考勤規則
|
|
/// </summary>
|
|
/// <param name="db"></param>
|
|
/// <param name="ConfigSettings">至少要4個</param>
|
|
/// <returns></returns>
|
|
public List<AttendanceRule> GetAttendanceRule(SqlSugarClient db, List<string> ConfigSettings)
|
|
{
|
|
var AttendanceRule = new List<AttendanceRule>();
|
|
try
|
|
{
|
|
do
|
|
{
|
|
//WebConfig依序:上班開始時間、上班結束時間、最晚上班時間(工作緩衝時間)、遲到緩衝時間(分)
|
|
//var ConfigSettings = new List<string>() { Common.ConfigGetValue("", "WorkTimePMKey"), Common.ConfigGetValue("", "WorkTimeAMKey")
|
|
// ,Common.ConfigGetValue("", "LatestShiftTimeKey"), Common.ConfigGetValue("", "DelayBufferTimeKey") };
|
|
var AllOrgIDs = db.Queryable<OTB_SYS_Organization>().Select(it => it.OrgID).ToList().Distinct();
|
|
|
|
if(!ConfigSettings.Any())
|
|
{
|
|
ConfigSettings = new List<string> { "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<OTB_SYS_SystemSetting>(@"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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 程序执行时间测试
|
|
/// </summary>
|
|
/// <param name="dateBegin">开始时间</param>
|
|
/// <param name="dateEnd">结束时间</param>
|
|
/// <returns>返回(秒)单位,比如: 0.00239秒</returns>
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
}
|