//正常打卡
        public int punchCardProcess(PunchCardLog logData, WorkTimeRule thisWorkTime, int action, int employeeID)
        {
            WorkDateTime wt = workTimeProcess(thisWorkTime);
            //需new一個出來 用原本的logData會等於context,一旦修改logData之後query後的context也會是修改後的(雖然沒儲存所以資料庫沒變)
            PunchCardLog newLogData;
            int          resultCount = 0; //0:操作異常 1:成功

            if (logData == null)          //今日皆未打卡
            {
                newLogData = new PunchCardLog()
                {
                    accountID      = employeeID, departmentID = (int)loginDepartmentID, logDate = wt.sWorkDt.Date,
                    lastOperaAccID = (int)loginID, onlineTime = definePara.dtNow(), createTime = definePara.dtNow()
                };
            }
            else   //今日有打過卡 or 電腦生成(跨日才有可能遇到)
            {
                newLogData              = new PunchCardLog();
                newLogData.ID           = logData.ID;
                newLogData.accountID    = logData.accountID;
                newLogData.departmentID = logData.departmentID;
                newLogData.logDate      = logData.logDate;
                newLogData.onlineTime   = logData.onlineTime;
                newLogData.offlineTime  = logData.offlineTime;
                newLogData.punchStatus  = logData.punchStatus;
                newLogData.createTime   = logData.createTime;

                newLogData.lastOperaAccID = (int)loginID;
                newLogData.updateTime     = definePara.dtNow();

                if (newLogData.onlineTime.Year == 1 && newLogData.offlineTime.Year == 1)
                {
                    newLogData.onlineTime = definePara.dtNow();
                }
                else
                {
                    newLogData.offlineTime = definePara.dtNow();
                }
            }
            newLogData.punchStatus = getStatusCode(wt, newLogData);
            resultCount            = newLogData.ID == 0? Repository.AddPunchCardLog(newLogData, true) : Repository.UpdatePunchCard(newLogData, true);
            if (resultCount == 1)     //一定要新增log成功 不然會沒logID
            {
                if (newLogData.punchStatus > psCode.normal && newLogData.punchStatus != psCode.takeLeave)
                {
                    Repository.AddPunchLogWarnAndMessage(newLogData);
                }
                else if (newLogData.punchStatus == psCode.normal)
                {
                    Repository.delPunchLogWarnAndMessage(newLogData);
                }
            }
            return(resultCount);
        }
        public void processPunchlogWarn(PunchCardLog log, WorkTimeRule thisWorkTime)    //排程用
        {
            WorkDateTime wt = workTimeProcess(thisWorkTime, log);

            if (definePara.dtNow() < wt.ePunchDT)
            {
                return;
            }
            log.punchStatus    = getStatusCode(wt, log);
            log.lastOperaAccID = 0;
            Repository.UpdatePunchCard(log, true);
            if (log.punchStatus > 1 && log.punchStatus != psCode.takeLeave)
            {
                Repository.AddPunchLogWarnAndMessage(log);
            }
        }
        //正常打卡
        public int punchCardProcess(PunchCardNeedParam logParam, int action, int employeeID)
        {
            WorkTimeRule thisWorkTime = logParam.thisWorkTime;
            PunchCardLog logData      = logParam.punchCardLog;
            WorkDateTime wt           = logParam.workDateTime;
            //需new一個出來 用原本的logData會等於context,一旦修改logData之後query後的context也會是修改後的(雖然沒儲存所以資料庫沒變)
            PunchCardLog newLogData;
            DateTime     dtNow       = definePara.dtNow();
            int          resultCount = 0; //0:操作異常 1:成功

            if (action == 1)              //action = 1 提早打上班卡
            {
                newLogData = new PunchCardLog()
                {
                    ID             = logData.ID,
                    accountID      = employeeID,
                    departmentID   = (int)loginDepartmentID,
                    logDate        = logData.logDate,
                    lastOperaAccID = (int)loginID,
                    onlineTime     = dtNow,
                    createTime     = dtNow
                };
            }
            else if (action == 0 && logData == null)    //action = 0  正常打卡或打下班卡
            //
            {
                newLogData = new PunchCardLog()
                {
                    accountID      = employeeID,
                    departmentID   = (int)loginDepartmentID,
                    logDate        = wt.sWorkDt.Date,
                    lastOperaAccID = (int)loginID,
                    createTime     = dtNow
                };
                if (dtNow >= wt.ePunchDT)    //在模糊區段 打下班卡
                {
                    newLogData.offlineTime = dtNow;
                }
                else    //非模糊區段 若上班卡沒打會先打上班卡 之後需要打一次下班卡
                {
                    newLogData.onlineTime = dtNow;
                }
            }
            else
            {
                newLogData                = new PunchCardLog();
                newLogData.ID             = logData.ID;
                newLogData.accountID      = logData.accountID;
                newLogData.departmentID   = logData.departmentID;
                newLogData.logDate        = logData.logDate;
                newLogData.onlineTime     = logData.onlineTime;
                newLogData.offlineTime    = logData.offlineTime;
                newLogData.punchStatus    = logData.punchStatus;
                newLogData.createTime     = logData.createTime;
                newLogData.lastOperaAccID = (int)loginID;
                newLogData.updateTime     = dtNow;
                if (dtNow >= wt.ePunchDT || logData.onlineTime.Year > 1)
                {
                    newLogData.offlineTime = dtNow;
                }
                else
                {
                    newLogData.onlineTime = dtNow;
                }
            }
            logParam.punchCardLog  = newLogData;
            logParam.workDateTime  = workTimeProcess(thisWorkTime, newLogData);
            newLogData.punchStatus = getStatusCode(logParam);
            resultCount            = newLogData.ID == 0? Repository.AddPunchCardLog(newLogData, true) : Repository.UpdatePunchCard(newLogData, true);
            if (resultCount == 1)     //一定要新增log成功 不然會沒logID
            {
                if (newLogData.punchStatus > psCode.normal && newLogData.punchStatus != psCode.takeLeave)
                {
                    Repository.AddPunchLogWarnAndMessage(newLogData);
                }
                else if (newLogData.punchStatus == psCode.normal)
                {
                    Repository.delPunchLogWarnAndMessage(newLogData);
                }
                if (action == 1)     //提早打上班卡 通知主管
                {
                    var accDetail = Repository.GetAccountDetail(newLogData.accountID);
                    var userName  = (string)accDetail.GetType().GetProperty("userName").GetValue(accDetail);
                    //obj.GetType().GetProperty(key).GetValue(obj);
                    Repository.systemSendMessage(userName, newLogData.accountID, "earlyPunch");
                }
            }
            return(resultCount);
        }
        public int getStatusCode(PunchCardNeedParam logParam, LeaveOfficeApply leave = null)
        {
            WorkDateTime wt          = logParam.workDateTime;
            PunchCardLog processLog  = logParam.punchCardLog;
            var          fullDayRest = false; //請整天假
            var          statusCode  = 0;     //statusCode:  0x01:正常 0x02:遲到 0x04:早退 0x08:加班 0x10:缺卡 0x20:曠職 0x40:請假

            if (wt.workAllTime)
            {
                return(psCode.normal);
            }
            var elasticityMin = wt.elasticityMin;   //彈性時間
            List <LeaveOfficeApply> thisLeave = new List <LeaveOfficeApply>();

            //if(leave == null){
            thisLeave = Repository.GetThisTakeLeave(processLog.accountID, wt.sWorkDt, wt.eWorkDt);
            //}else{
            //    thisLeave.Add(leave);
            //}
            if (thisLeave.Count > 0)
            {
                var allWorkLen = (wt.eWorkDt - wt.sWorkDt).TotalMinutes;
                var restLen    = (wt.eRestDt - wt.sRestDt).TotalMinutes;
                var workLen    = allWorkLen - restLen;
                var sum        = 0.0;
                foreach (var tmp in thisLeave)
                {
                    sum        += (tmp.endTime - tmp.startTime).TotalMinutes;
                    fullDayRest = (tmp.startTime <= wt.sWorkDt && tmp.endTime >= wt.eWorkDt)? true : false;
                }
                fullDayRest = sum >= workLen? true : fullDayRest;
                statusCode |= psCode.takeLeave;
            }

            if (processLog.onlineTime.Year == 1 && processLog.offlineTime.Year == 1)
            {
                if (definePara.dtNow() >= wt.ePunchDT)
                {
                    statusCode = fullDayRest? statusCode : (statusCode | psCode.noWork);
                }
                else
                {
                    if (definePara.dtNow() >= wt.eWorkDt)
                    {
                        statusCode = fullDayRest? statusCode : (statusCode | psCode.hadLost);
                    }
                }
            }
            else if (processLog.onlineTime.Year > 1 && processLog.offlineTime.Year > 1)
            {
                var newStartWt = wt.sWorkDt.AddMinutes(elasticityMin + 1);   //+1因遲到以時分為主 09:00:59 也不算遲到
                statusCode = processLog.onlineTime >= newStartWt? (statusCode | psCode.lateIn) : statusCode;
                var timeLen = (int)((processLog.onlineTime - wt.sWorkDt).TotalMinutes);
                timeLen    = (timeLen <0 || timeLen> elasticityMin)? 0: timeLen; //上班打卡超過彈性時間 下班就已下班時間為準
                statusCode = processLog.offlineTime < wt.eWorkDt.AddMinutes(timeLen)? (statusCode | psCode.earlyOut):statusCode;
                if (statusCode == psCode.takeLeave && (statusCode & psCode.lateIn) == 0 && (statusCode & psCode.earlyOut) == 0)
                {
                    statusCode = (statusCode | psCode.normal);
                }
            }
            else
            {
                if (processLog.onlineTime.Year > 1) //只有填上班
                {
                    var newStartWt = wt.sWorkDt.AddMinutes(elasticityMin + 1);
                    statusCode = processLog.onlineTime >= newStartWt? (statusCode | psCode.lateIn) : statusCode;
                    statusCode = definePara.dtNow() >= wt.ePunchDT ? (statusCode | psCode.hadLost) : statusCode; //打不到下班卡了
                }
                else                                                                                             //只有填下班
                {
                    statusCode |= psCode.hadLost;
                    statusCode  = processLog.offlineTime < wt.eWorkDt ? (statusCode | psCode.earlyOut) : statusCode;
                }
            }
            return(statusCode == 0? (psCode.normal) : statusCode);
        }
        public void countWorkTime(List <PunchCardLog> thisMonthAllLog, List <OvertimeApply> otApplies, WorkTimeRule thisWorkTime, DateTime startDT)
        {
            var totalTimeMinute        = 0.0;
            var totalOvertimeMinute    = 0;
            var restTimeMinute         = 0.0;
            var endStartWorkTimeMinute = 0.0;
            var noRestWorkTimeMinute   = 0.0;
            var sWorkTime     = thisWorkTime.startTime; //只取時間
            var eWorkTime     = thisWorkTime.endTime;
            var sRestTime     = thisWorkTime.sRestTime;
            var eRestTime     = thisWorkTime.eRestTime;
            var restlength    = TimeSpan.Zero;
            var thisAccLeaves = getThisAccLeaves(thisMonthAllLog, thisWorkTime, startDT);

            if (eRestTime < sRestTime)
            {
                restlength = eRestTime.Add(new TimeSpan(24, 0, 0)) - sRestTime;
            }
            else
            {
                restlength = eRestTime - sRestTime;
            }
            restTimeMinute = restlength.TotalMinutes;

            var endStartLength = TimeSpan.Zero;

            if (eWorkTime < sWorkTime)
            {
                endStartLength = eWorkTime.Add(new TimeSpan(24, 0, 0)) - sWorkTime;
            }
            else
            {
                endStartLength = eWorkTime - sWorkTime;
            }
            endStartWorkTimeMinute = endStartLength.TotalMinutes;
            noRestWorkTimeMinute   = (endStartWorkTimeMinute - restTimeMinute);

            foreach (var log in thisMonthAllLog)
            {
                if (log.onlineTime.Year == 1 || log.offlineTime.Year == 1 || log.onlineTime >= log.offlineTime)
                {
                    continue;
                }
                WorkDateTime workTime = workTimeProcess(thisWorkTime, log);

                //計算工作時間
                if (log.onlineTime <= workTime.sRestDt && log.offlineTime >= workTime.eRestDt)
                {
                    totalTimeMinute += (int)((log.offlineTime - log.onlineTime).TotalMinutes) - restTimeMinute;
                }
                else if (log.onlineTime < workTime.sRestDt && log.offlineTime <= workTime.eRestDt)
                {
                    if (log.offlineTime < workTime.sRestDt)
                    {
                        totalTimeMinute += (int)(log.offlineTime - log.onlineTime).TotalMinutes;
                    }
                    else
                    {
                        totalTimeMinute += (int)(workTime.sRestDt - log.onlineTime).TotalMinutes;
                    }
                }
                else if (log.onlineTime >= workTime.sRestDt && log.offlineTime > workTime.eRestDt)
                {
                    if (log.onlineTime > workTime.eRestDt)
                    {
                        totalTimeMinute += (int)(log.offlineTime - log.onlineTime).TotalMinutes;
                    }
                    else
                    {
                        totalTimeMinute += (int)(log.offlineTime - workTime.eRestDt).TotalMinutes;
                    }
                }

                foreach (var leave in thisAccLeaves)     //工作時間需會扣掉請假時間
                {
                    if (leave.startTime >= workTime.sWorkDt && leave.endTime <= workTime.eWorkDt &&
                        leave.unit == 3)    //只處理單位為小時的請假
                    {
                        if (leave.startTime > workTime.sWorkDt && leave.endTime < workTime.eWorkDt)
                        {
                            totalTimeMinute -= leave.unitVal * 60;
                        }
                    }
                }
            }

            foreach (var apply in otApplies)                //計算加班
            {
                totalOvertimeMinute += apply.timeLength;
            }

            if (thisMonthAllLog.Count > 0)
            {
                saveTotalTimeRecord(thisMonthAllLog[0].accountID, startDT, totalTimeMinute, totalOvertimeMinute);
            }
        }
        public int forcePunchLogProcess(PunchCardLog processLog, WorkTimeRule thisWorkTime, string action, string from = "")
        {
            WorkDateTime wt        = workTimeProcess(thisWorkTime, processLog);
            var          et_big_st = thisWorkTime.endTime >= thisWorkTime.startTime? true: false;

            processLog.logDate        = wt.sWorkDt.Date;
            processLog.lastOperaAccID = (int)loginID;
            if (action == "update")
            {
                processLog.updateTime = definePara.dtNow();
            }
            else
            {
                processLog.createTime = definePara.dtNow();
            }

            if (processLog.onlineTime.Year != 1)
            {
                if (processLog.onlineTime < wt.sPunchDT)     //2300-0800 if write 0000-0800
                {
                    processLog.onlineTime = processLog.onlineTime.AddDays(1);
                }
                if (processLog.onlineTime >= wt.ePunchDT)     //0000-0800 if write 2355-0800
                {
                    processLog.onlineTime = processLog.onlineTime.AddDays(-1);
                }
            }
            if (processLog.offlineTime.Year != 1)
            {
                if (processLog.offlineTime <= wt.sWorkDt)    //2300-0800 if write 2300-0800
                {
                    processLog.offlineTime = processLog.offlineTime.AddDays(1);
                }
            }
            if (et_big_st && processLog.onlineTime.Year != 1 && processLog.offlineTime.Year != 1)
            {
                if (processLog.onlineTime >= processLog.offlineTime)
                {
                    processLog.onlineTime = processLog.onlineTime.AddDays(-1);
                }
            }
            else if (!et_big_st && processLog.onlineTime.Year != 1 && processLog.offlineTime.Year != 1)
            {
                if (processLog.offlineTime <= processLog.onlineTime)
                {
                    processLog.offlineTime = processLog.offlineTime.AddDays(1);
                }
            }

            processLog.punchStatus = getStatusCode(wt, processLog);
            int result = action == "update"? Repository.UpdatePunchCard(processLog, false) : Repository.AddPunchCardLog(processLog, false);

            if (result == 1)
            {
                if (processLog.punchStatus > psCode.normal && processLog.punchStatus != psCode.takeLeave)
                {
                    Repository.AddPunchLogWarnAndMessage(processLog);
                }
                if (action == "update" && from == "applySign")
                {
                    Repository.UpdatePunchLogWarn(processLog.ID);
                }
            }
            return(result);
        }