diff --git a/src/com/engine/kq/biz/KQFormatData.java b/src/com/engine/kq/biz/KQFormatData.java index 3f6eed7..92620bf 100644 --- a/src/com/engine/kq/biz/KQFormatData.java +++ b/src/com/engine/kq/biz/KQFormatData.java @@ -4,24 +4,32 @@ import cn.hutool.core.convert.Convert; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.engine.jc.kq.AbnormalOvertimeRemind; +import com.engine.kq.bean.KQRepeatBean; import com.engine.kq.biz.chain.shiftinfo.ShiftInfoBean; import com.engine.kq.entity.KQShiftRuleEntity; import com.engine.kq.entity.TimeScopeEntity; import com.engine.kq.entity.WorkTimeEntity; import com.engine.kq.enums.FlowReportTypeEnum; +import com.engine.kq.jucailin.genid.IdGenerator; import com.engine.kq.log.KQLog; +import com.engine.kq.util.KQLockAttendaUtil; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.googlecode.aviator.AviatorEvaluator; import com.googlecode.aviator.Expression; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import weaver.common.DateUtil; import weaver.conn.BatchRecordSet; import weaver.conn.RecordSet; +import weaver.file.Prop; import weaver.general.BaseBean; import weaver.general.InitServer; import weaver.general.Util; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.sql.Timestamp; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -35,6 +43,28 @@ public class KQFormatData extends BaseBean { private boolean writeLog = false; private LinkedHashMap logInfo = new LinkedHashMap<>(); + private static final String LOCK_DEGREE = Util.null2String(Prop.getPropValue("kqLockAttenda", "LOCK_DEGREE")); + + public Map formatKqDateByLock(String userId, String kqDate, int formatType) { + Map resultMap = new HashMap<>(); + + //-1: 其他; 11:右键重新计算考勤数据; 12: 考勤自动和手动同步;13:钉钉同步或者导入; 14:云桥考勤同步 15: 考勤导入;16:排班更新 + //17:考勤流程;18testkq.jsp直接触发的;19:考勤设置升级;20:计划任务执行。 + //①在途的考勤流程可以正常提交归档报表能统计,管理员干预归档的流程报表能统计。 + //②关账不影响考勤导入打卡数据,正常的打卡数据进入报表,导入、同步。 + //③其他操作报表更新控制不生效,比如重新计算考勤,自动计算考勤。 + +// if (LOCK_DEGREE.equals("0")&&new KQLockAttendaUtil().checkLockStatus(userId, kqDate)) { +// kqLog.info("锁定程度强控:人员考勤数据已被锁定,"+"userId:"+userId+":kqDate:"+kqDate+";formatType="+formatType); +// if(formatType==12||formatType==13||formatType==14||formatType==15||formatType==17){ +// return formatKqDate(userId, kqDate); +// } +// return resultMap; +// } + //最新确认逻辑:弱控只控制流程在锁定范围内不能提交,其他都可以重新计算考勤报表。 + return formatKqDate(userId, kqDate); + } + /*** * 该方法不允许直接调用 * @param userId @@ -42,7 +72,12 @@ public class KQFormatData extends BaseBean { * @return */ public Map formatKqDate(String userId, String kqDate) { + //考勤报表增加锁定功能:弱控 + //1、考勤流程控制,请假、出差、公出、补卡、加班、销假、考勤变更新建的流程不能提交,在途的流程可以正常提交归档报表能统计,管理员干预归档的流程报表能统计。 + //2、关账不影响考勤导入打卡数据,正常的打卡数据进入报表。 + //3、强控就是前2点锁定日期后也不能进入报表了 List> lsParam = new ArrayList<>(); + boolean isKqReportHalfOpen = "1".equals(new KQSettingsComInfo().getMain_val("kq_report_half")); //非工作日处理 List nonlsParam = null; Map resultMap = new HashMap<>(); @@ -56,6 +91,11 @@ public class KQFormatData extends BaseBean { kqLog.info("今天之后的无需处理的数据:resourceid=="+userId+"kqdate=="+kqDate+"today=="+today); return resultMap; } + // 强控 + if (LOCK_DEGREE.equals("1")&&new KQLockAttendaUtil().checkLockStatus(userId, kqDate)) { + kqLog.info("锁定程度强控:人员考勤数据已被锁定,"+"userId:"+userId+":kqDate:"+kqDate); + return resultMap; + } String uuid = UUID.randomUUID().toString(); KQFormatFreeData kqFormatFreeData = new KQFormatFreeData(); KQWorkTime kqWorkTime = new KQWorkTime(); @@ -89,18 +129,29 @@ public class KQFormatData extends BaseBean { //没有考勤组不需格式化 return resultMap; } - if (workTime == null || workTime.getWorkMins() == 0) { + if (workTime == null || (workTime != null && workTime.getWorkMins() == 0 && workTime.getNonWorkShift() != 1)) { kqLog.info("workTime == null || workTime.getWorkMins() == 0 插入空记录"); nonlsParam = new ArrayList<>(); formatNonWork(userId, kqDate,nonlsParam,workTime, workFlowInfo); if(!nonlsParam.isEmpty()){ - sql = " insert into kq_format_detail(resourceid,kqdate,groupid,serialnumber,signindate,signintime,signinid,signoutdate,signouttime,signoutid,leaveMins,leaveinfo,evectionMins,outMins)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?) "; + sql = " insert into kq_format_detail(resourceid,kqdate,groupid,serialnumber,signindate,signintime,signinid,signoutdate,signouttime,signoutid,leaveMins,leaveinfo,evectionMins,outMins,day_type,create_time,update_time,id,flowinfo)values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) "; rs.executeUpdate(sql, nonlsParam); + Long id = IdGenerator.generate(); + String baseField = ""; + if ("mysql".equalsIgnoreCase(rs.getDBType())){ + baseField = "sysdate(),sysdate(),"+id; + }else if ("oracle".equalsIgnoreCase(rs.getDBType())){ + baseField = "SYSDATE,SYSDATE,"+id; + }else if ("postgresql".equalsIgnoreCase(rs.getDBType())){ + baseField = "now(),now(),"+id; + }else{ + baseField = "GETDATE(),GETDATE(),"+id; + } sql = " insert into kq_format_total(resourceid,kqdate,subcompanyid,departmentid,jobtitle,groupid,serialid,workdays," + " workmins,attendancedays,attendancemins,signdays,signmins,belate,belatemins,gravebelate,gravebelatemins,leaveeearly,leaveearlymins," + - " graveleaveearly,graveleaveearlymins,absenteeism,absenteeismmins,forgotcheck, forgotcheckMins,leaveMins,evectionMins,outMins)" + + " graveleaveearly,graveleaveearlymins,absenteeism,absenteeismmins,forgotcheck, forgotcheckMins,leaveMins,evectionMins,outMins,create_time,update_time,id)" + " select a.resourceid,kqdate,b.subcompanyid1,b.departmentid,b.jobtitle,groupid,serialid," + " case when sum(workmins)>0 then 1 end as workdays, sum(workmins) as workmins," + " 0 as attendancedays, sum(attendanceMins) as attendanceMins," + @@ -108,10 +159,14 @@ public class KQFormatData extends BaseBean { " sum(case when belatemins> 0 then 1 else 0 end) as belate,sum(belatemins) as belatemins," + " sum(case when graveBeLateMins> 0 then 1 else 0 end) as graveBeLate,sum(graveBeLateMins) as graveBeLateMins," + " sum(case when leaveearlymins> 0 then 1 else 0 end) as leaveearly,sum(leaveearlymins) as leaveearlymins," + - " sum(case when graveLeaveEarlyMins> 0 then 1 else 0 end) as graveLeaveEarly,sum(graveLeaveEarlyMins) as graveLeaveEarlyMins," + - " sum(case when absenteeismmins> 0 then 1 else 0 end) as absenteeism,sum(absenteeismmins) as absenteeismmins," + - " sum(case when forgotcheckmins> 0 then 1 else 0 end) as forgotcheck,sum(forgotcheckmins) as forgotcheckmins, " + - " sum(leaveMins) as leaveMins, sum(evectionMins) as evectionMins, sum(outMins) as outMins" + + " sum(case when graveLeaveEarlyMins> 0 then 1 else 0 end) as graveLeaveEarly,sum(graveLeaveEarlyMins) as graveLeaveEarlyMins,"; +// if(isKqReportHalfOpen) { +// sql+=" sum((on_absenteeismmins+off_absenteeismmins)) as absenteeism,sum(absenteeismmins) as absenteeismmins,"; +// } else { + sql+=" sum(case when absenteeismmins> 0 then 1 else 0 end) as absenteeism,sum(absenteeismmins) as absenteeismmins,"; +// } + sql+=" sum(case when forgotcheckmins> 0 then 1 else 0 end) as forgotcheck,sum(forgotcheckmins) as forgotcheckmins, " + + " sum(leaveMins) as leaveMins, sum(evectionMins) as evectionMins, sum(outMins) as outMins," +baseField+ " from kq_format_detail a, hrmresource b" + " where a.resourceid = b.id and resourceid =? and kqdate=?" + " group by resourceid,kqdate,b.subcompanyid1,b.departmentid,b.jobtitle,groupid,serialid,workmins"; @@ -122,6 +177,7 @@ public class KQFormatData extends BaseBean { String definedField = ""; String definedParam = ""; String definedParamSum = ""; + String convertAttendDay = workTime != null ? Util.null2s(workTime.getConvertAttendDay(),"1.0") : "1.0"; if (workTime.getKQType().equals("3")) {//自由工时 lsParam.addAll(kqFormatFreeData.format(userId, kqDate, workFlowInfo)); } else { @@ -132,46 +188,95 @@ public class KQFormatData extends BaseBean { } if (lsParam.size() > 0) { - sql = " insert into kq_format_detail( " + - " resourceid,kqdate,groupid,serialid,serialnumber,workbegindate,workbegintime,workenddate,workendtime,workmins," + - " signindate,signintime,signinid,signoutdate,signouttime,signoutid,signMins," + - " attendanceMins,belatemins,graveBeLateMins,leaveearlymins,graveLeaveEarlyMins,absenteeismmins,forgotcheckMins," + - " leaveMins,leaveinfo,evectionMins,outMins,forgotbeginworkcheckmins,otherinfo"+(definedField.length()>0?","+definedField+"":"")+") " + - " values(?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?,?,?,?"+(definedField.length()>0?","+definedParam+"":"")+")"; + if (rs.getDBType().equals("postgresql")) { + sql = " insert into kq_format_detail( " + + " resourceid,kqdate,groupid,serialid,serialnumber,workbegindate,workbegintime,workenddate,workendtime,workmins," + + " signindate,signintime,signinid,signoutdate,signouttime,signoutid,signMins," + + " attendanceMins,belatemins,graveBeLateMins,leaveearlymins,graveLeaveEarlyMins,absenteeismmins,forgotcheckMins," + + " leaveMins,leaveinfo,evectionMins,outMins,forgotbeginworkcheckmins,otherinfo"+(definedField.length()>0?","+definedField+"":"")+",day_type,create_time,update_time,id,flowinfo,on_absenteeismmins,off_absenteeismmins) " + + " values(?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?,?,?,?"+(definedField.length()>0?","+definedParam+"":"")+",?,?::timestamp,?::timestamp,?,?,?,?)"; + + }else{ + sql = " insert into kq_format_detail( " + + " resourceid,kqdate,groupid,serialid,serialnumber,workbegindate,workbegintime,workenddate,workendtime,workmins," + + " signindate,signintime,signinid,signoutdate,signouttime,signoutid,signMins," + + " attendanceMins,belatemins,graveBeLateMins,leaveearlymins,graveLeaveEarlyMins,absenteeismmins,forgotcheckMins," + + " leaveMins,leaveinfo,evectionMins,outMins,forgotbeginworkcheckmins,otherinfo"+(definedField.length()>0?","+definedField+"":"")+",day_type,create_time,update_time,id,flowinfo,on_absenteeismmins,off_absenteeismmins) " + + " values(?,?,?,?,?,?,?,?,?,?, ?,?,?,?,?,?,?, ?,?,?,?,?,?,?,?,?,?,?,?,?"+(definedField.length()>0?","+definedParam+"":"")+",?,?,?,?,?,?,?)"; + } for (int i = 0; i < lsParam.size(); i++) { List param = lsParam.get(i); boolean isok = rs.executeUpdate(sql, param); kqLog.info("插入记录:userId:"+userId+":kqDate:"+kqDate+":param:"+JSON.toJSONString(param)+":isok:"+isok+"::uuid::"+uuid); } + String attendancedaysF = " (cast(sum(attendanceMins)AS decimal(10, 2))*"+Util.getDoubleValue(convertAttendDay)+")/sum(workmins) as attendancedays, sum(attendanceMins) as attendanceMins, "; + String workF = " case when sum(workmins)>0 then "+convertAttendDay+" end as workdays, sum(workmins) as workmins,"; + String belateminsF = " sum(case when belatemins> 0 then 1 else 0 end) as belate,sum(belatemins) as belatemins,"; + String graveBeLateMinsF = " sum(case when graveBeLateMins> 0 then 1 else 0 end) as graveBeLate,sum(graveBeLateMins) as graveBeLateMins,"; + String leaveearlyminsF = " sum(case when leaveearlymins> 0 then 1 else 0 end) as leaveearly,sum(leaveearlymins) as leaveearlymins,"; + String graveLeaveEarlyMinsF = " sum(case when graveLeaveEarlyMins> 0 then 1 else 0 end) as graveLeaveEarly,sum(graveLeaveEarlyMins) as graveLeaveEarlyMins, "; + String absenteeismminsF = " sum(case when absenteeismmins> 0 then 1 else 0 end) as absenteeism,sum(absenteeismmins) as absenteeismmins, "; + String forgotcheckminsF = " sum(case when forgotcheckmins> 0 then 1 else 0 end) as forgotcheck,sum(forgotcheckmins) as forgotcheckmins,"; + String forgotbeginworkcheckminsF = " sum(case when forgotbeginworkcheckmins> 0 then 1 else 0 end) as forgotbeginworkcheck,sum(forgotbeginworkcheckmins) as forgotbeginworkcheckmins "; + String signF = " cast(sum(signmins)AS decimal(10, 2))/sum(workmins) as signdays, sum(signmins) as signmins,"; + String onoffAbsenteeismminsF= " sum(case when on_absenteeismmins> 0 then 1 else 0 end) as on_absenteeismmins,sum(case when off_absenteeismmins> 0 then 1 else 0 end) as off_absenteeismmins "; + if(1 == workTime.getNonWorkShift()){ + attendancedaysF = " 0 as attendancedays, 0 as attendanceMins, "; + workF = " 0 as workdays, 0 as workmins,"; + belateminsF = " 0 as belate,0 as belatemins,"; + graveBeLateMinsF = " 0 as graveBeLate,0 as graveBeLateMins,"; + leaveearlyminsF = " 0 as leaveearly,0 as leaveearlymins,"; + graveLeaveEarlyMinsF = " 0 as graveLeaveEarly,0 as graveLeaveEarlyMins, "; + absenteeismminsF = " 0 as absenteeism,0 as absenteeismmins,"; + forgotcheckminsF = " 0 as forgotcheck,0 as forgotcheckmins,"; + forgotbeginworkcheckminsF = " 0 as forgotbeginworkcheck,0 as forgotbeginworkcheckmins "; + signF = " 0 as signdays, 0 as signmins,"; + onoffAbsenteeismminsF = " 0 as on_absenteeismmins, 0 as off_absenteeismmins "; + } + + Long id = IdGenerator.generate(); + String baseField = ""; + if ("mysql".equalsIgnoreCase(rs.getDBType())){ + baseField = " now(),now(),"+id; + }else if ("oracle".equalsIgnoreCase(rs.getDBType())){ + baseField = " sysdate,sysdate,"+id; + }else if ("postgresql".equalsIgnoreCase(rs.getDBType())){ + baseField = " now(),now(),"+id; + }else{ + baseField = " getdate(),getdate(),"+id; + } sql = " insert into kq_format_total(resourceid,kqdate,subcompanyid,departmentid,jobtitle,groupid,serialid,workdays,workmins," + " attendancedays,attendancemins,signdays,signmins,belate,belatemins,gravebelate,gravebelatemins,leaveeearly,leaveearlymins,graveleaveearly," + " graveleaveearlymins,absenteeism,absenteeismmins,forgotcheck,forgotcheckmins," + - " leaveMins,evectionMins,outMins,forgotbeginworkcheck,forgotbeginworkcheckmins"+(definedField.length()>0?","+definedField+"":"")+") " + + " leaveMins,evectionMins,outMins,forgotbeginworkcheck,forgotbeginworkcheckmins"+(definedField.length()>0?","+definedField+"":"")+",create_time,update_time,id,on_absenteeismmins,off_absenteeismmins) " + " select a.resourceid,kqdate,b.subcompanyid1,b.departmentid,b.jobtitle,groupid,serialid," + - " case when sum(workmins)>0 then 1 end as workdays, sum(workmins) as workmins," + - " cast(sum(attendanceMins)AS decimal(10, 2))/sum(workmins) as attendancedays, sum(attendanceMins) as attendanceMins," + - " cast(sum(signmins)AS decimal(10, 2))/sum(workmins) as signdays, sum(signmins) as signmins," + - " sum(case when belatemins> 0 then 1 else 0 end) as belate,sum(belatemins) as belatemins," + - " sum(case when graveBeLateMins> 0 then 1 else 0 end) as graveBeLate,sum(graveBeLateMins) as graveBeLateMins," + - " sum(case when leaveearlymins> 0 then 1 else 0 end) as leaveearly,sum(leaveearlymins) as leaveearlymins," + - " sum(case when graveLeaveEarlyMins> 0 then 1 else 0 end) as graveLeaveEarly,sum(graveLeaveEarlyMins) as graveLeaveEarlyMins, " + - " sum(case when absenteeismmins> 0 then 1 else 0 end) as absenteeism,sum(absenteeismmins) as absenteeismmins," + - " sum(case when forgotcheckmins> 0 then 1 else 0 end) as forgotcheck,sum(forgotcheckmins) as forgotcheckmins,sum(leaveMins) as leaveMins," + + workF + + attendancedaysF + + signF + + belateminsF + + graveBeLateMinsF + + leaveearlyminsF + + graveLeaveEarlyMinsF + + absenteeismminsF + + forgotcheckminsF+ + " sum(leaveMins) as leaveMins," + " sum(evectionMins) as evectionMins,sum(outMins) as outMins, " + - " sum(case when forgotbeginworkcheckmins> 0 then 1 else 0 end) as forgotbeginworkcheck,sum(forgotbeginworkcheckmins) as forgotbeginworkcheckmins " + - (definedField.length()>0?","+definedParamSum+"":"")+ + forgotbeginworkcheckminsF + + (definedField.length()>0?","+definedParamSum+"":"")+","+baseField+","+onoffAbsenteeismminsF+ " from kq_format_detail a, hrmresource b" + " where a.resourceid = b.id and resourceid = ? and kqdate=?" + " group by resourceid,kqdate,b.subcompanyid1,b.departmentid,b.jobtitle,groupid,serialid"; rs.executeUpdate(sql, userId, kqDate); - } + } } // 晶测考勤二开 判断加班异常 AbnormalOvertimeRemind.remind(Convert.toInt(userId, 0), kqDate); }catch (Exception e) { - writeLog(e); - kqLog.info(e); + kqLog.info("考勤重算报错:KQFormatData.Exception:"); + StringWriter errorsWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(errorsWriter)); + kqLog.info(errorsWriter.toString()); } return resultMap; } @@ -180,9 +285,17 @@ public class KQFormatData extends BaseBean { Map workFlowInfo, String uuid) { List> lsParam = new ArrayList<>(); List params = null; + HashMap middleMap = new HashMap<>(); try { + KQRepeatLengthContext.clear(); + KQRepeatLengthContext.removeRepeatBeanLink(); + KQRepeatLengthContext.removeRepeatBeanLinkRange(); + Timestamp date = new Timestamp(System.currentTimeMillis()); KQSettingsComInfo kqSettingsComInfo = new KQSettingsComInfo(); String nosign_is_absent = Util.null2String(kqSettingsComInfo.getMain_val("nosign_is_absent"),"1"); + //默认不开启半天的特殊规则,如果开启,那么只要是半天的单位,并且申请考勤流程半天,那么实际出勤就是0.5天,不考虑迟到和早退。当天旷工的情况需要考虑,即如果另外半天是旷工,那么实际出勤自然也是0 + String is_half = Util.null2String(kqSettingsComInfo.getMain_val("is_half"),"0"); + String early_one_mins = Util.null2String(kqSettingsComInfo.getMain_val("early_one_mins"),"0"); KQTimesArrayComInfo kqTimesArrayComInfo = new KQTimesArrayComInfo(); KQFormatShiftRule kqFormatShiftRule = new KQFormatShiftRule(); String preDate = DateUtil.addDate(kqDate, -1);//上一天日期 @@ -190,22 +303,48 @@ public class KQFormatData extends BaseBean { String dateKey = userId + "|" + kqDate; String nextDateKey = userId + "|" + nextDate; ArrayList hostIps = InitServer.getRealIp(); - kqLog.info("format in >>>>>userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); boolean oneSign = false; List lsSignTime = new ArrayList<>(); List lsWorkTime = new ArrayList<>(); List lsRestTime = new ArrayList<>(); List workFlow = null; - + int restShift = 0; + int signoutOnlyoff = 0; if (workTime != null) { lsSignTime = workTime.getSignTime();//允许打卡时间 lsWorkTime = workTime.getWorkTime();//工作时间 lsRestTime = workTime.getRestTime();//休息时段时间 oneSign = lsWorkTime!=null&&lsWorkTime.size()==1; + restShift = workTime.getNonWorkShift(); + signoutOnlyoff = workTime.getSignoutOnlyoff(); + } + kqLog.info("format in >>>>>userId" + userId + "kqDate==" + kqDate+":restShift:"+restShift+":signoutOnlyoff:"+signoutOnlyoff+":hostIps:"+hostIps+":uuid::"+uuid); + + if(this.writeLog) { + logInfo.put("signoutOnlyoff",signoutOnlyoff); + } + //哺乳假 请假时长 + int repeatLeaveMins = 0; + //所有的请假时长 + int allLeaveMins = 0; + String repeatKey = userId+"_"+kqDate; + String keyRepeat = userId + "|" + kqDate+"|repeat"; + if (workFlowInfo.get(keyRepeat) != null) { + List workFlowRepeat = (List) workFlowInfo.get(keyRepeat); + repeatLeaveMins = handleRepeatWorkFlowInfo(workFlowRepeat,repeatKey); } int[] dayMins = new int[2880];//一天所有分钟数 Arrays.fill(dayMins, -1); + + //处理半天班次冲销问题 + int[] dayMinsNew = new int[2880];//一天所有分钟数 + Arrays.fill(dayMinsNew, -1); + int workMins4leave = 0; + int middleMins = 0;//班次的半天时长 + int middleMins_final = 0;//班次的半天时长 + int shiftNums = lsWorkTime == null ? 0 : lsWorkTime.size(); + // 一天4次打卡单独做判断,如果是上午下班打卡和下午上班打卡时间重叠,那么上午的下班卡取最早的,下午的上班卡取最晚的。用shiftCount是否等于-1判断,-1就走标准不重叠。2就表示重叠走新的逻辑 int shiftCount = lsWorkTime == null ? 0 : lsWorkTime.size(); int shiftI = 0; @@ -227,7 +366,50 @@ public class KQFormatData extends BaseBean { if (shiftCount == 2 && shiftI == 1) { shiftCount = signBeginDateTime.compareTo(signEndDateTimeZero) <= 0 ? shiftCount : -1; } + + String workBeginTime = Util.null2String(workTimeScope.getBeginTime()); + String ori_workBeginTime = workBeginTime; + int workBeginIdx = kqTimesArrayComInfo.getArrayindexByTimes(workBeginTime); + boolean workBenginTimeAcross = workTimeScope.getBeginTimeAcross(); + String workEndTime = Util.null2String(workTimeScope.getEndTime()); + String ori_workEndTime = workEndTime; + int workEndIdx = kqTimesArrayComInfo.getArrayindexByTimes(workEndTime); + boolean workEndTimeAcross = workTimeScope.getEndTimeAcross(); + int workMins = workTimeScope.getWorkMins(); + + String workBeginDate = workBenginTimeAcross ? nextDate : kqDate; + String workEndDate = workEndTimeAcross ? nextDate : kqDate; + if(lsRestTime != null && !lsRestTime.isEmpty()){ + for(int k = 0 ; k < lsRestTime.size(); k++){ + TimeScopeEntity restTimeScope = lsRestTime.get(k); + if (restTimeScope!=null) { + String restBeginTime = Util.null2String(restTimeScope.getBeginTime()); + String restEndTime = Util.null2String(restTimeScope.getEndTime()); + int beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(restBeginTime); + int endIdx = kqTimesArrayComInfo.getArrayindexByTimes(restEndTime); + if (endIdx > beginIdx) { + Arrays.fill(dayMinsNew, beginIdx, endIdx, -11);//休息时间 + } + } + } + int all_rest_cnt = kqTimesArrayComInfo.getCnt(dayMinsNew, workBeginIdx, workEndIdx, -11); + if(all_rest_cnt >= 0){ + workMins = workMins-(all_rest_cnt); + } + } + workMins4leave += workMins; } + middleMins = workMins4leave>0?workMins4leave/2:0; + middleMins_final = middleMins; + int split_time_index = middleMins_final; // 半天时间index,用于考勤汇总报表区分上下午 + if(oneSign) { + List halfWorkIndex = workTime.getHalfWorkIndex(); + if(halfWorkIndex != null && !halfWorkIndex.isEmpty()) { + int[] halfWorkIndexs = halfWorkIndex.get(0); + split_time_index = halfWorkIndexs[1];//半天的时间 + } + } + for (int i = 0; lsWorkTime != null && i < lsWorkTime.size(); i++) { shiftI = i; params = new ArrayList<>(); @@ -269,9 +451,12 @@ public class KQFormatData extends BaseBean { int leaveEarlyMins = 0; int graveLeaveEarlyMins = 0; int absenteeismMins = 0; + int on_absenteeismMins = 0; + int off_absenteeismMins = 0; int leaveMins = 0;//请假时长 Map leaveInfo = new HashMap<>();//请假信息 Map otherinfo = new HashMap<>();//存一些用得到的信息 + Map flowinfo = new HashMap<>();//流程信息 int evectionMins = 0;//出差时长 int outMins = 0;//公出时长 int otherMins = 0;//异常流程时长 @@ -302,46 +487,56 @@ public class KQFormatData extends BaseBean { kqLog.info("workEndDateTime" + workEndDateTime+"::userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); Map shifRuleMap = Maps.newHashMap(); - if(oneSign){ - //个性化设置只支持一天一次上下班 - ShiftInfoBean shiftInfoBean = new ShiftInfoBean(); - shiftInfoBean.setSplitDate(kqDate); - shiftInfoBean.setShiftRuleMap(workTime.getShiftRuleInfo()); - shiftInfoBean.setSignTime(lsSignTime); - shiftInfoBean.setWorkTime(lsWorkTime); - List logList = Lists.newArrayList(); - KQShiftRuleInfoBiz.getShiftRuleInfo(shiftInfoBean, userId, shifRuleMap,logList); - if(!shifRuleMap.isEmpty()){ - if(!logList.isEmpty()){ - otherinfo.put("logList", logList); - } - otherinfo.put("shiftRule", shifRuleMap); - if(shifRuleMap.containsKey("shift_beginworktime")){ - String shift_beginworktime = Util.null2String(shifRuleMap.get("shift_beginworktime")); - if(shift_beginworktime.length() > 0){ - workBeginTime = Util.null2String(shift_beginworktime); - workBeginIdx = kqTimesArrayComInfo.getArrayindexByTimes(workBeginTime); - workTimeScope.setBeginTime(workBeginTime); - workTimeScope.setBeginTimeAcross(workBeginIdx>=1440?true:false); - } - } - if(shifRuleMap.containsKey("shift_endworktime")){ - String shift_endworktime = Util.null2String(shifRuleMap.get("shift_endworktime")); - if(shift_endworktime.length() > 0){ - workEndTime = Util.null2String(shift_endworktime); - workEndIdx = kqTimesArrayComInfo.getArrayindexByTimes(workEndTime); - workTimeScope.setEndTime(workEndTime); - workTimeScope.setEndTimeAcross(workEndIdx>=1440?true:false); + if (1 != restShift) { + if(oneSign){ + //个性化设置只支持一天一次上下班 + ShiftInfoBean shiftInfoBean = new ShiftInfoBean(); + shiftInfoBean.setSplitDate(kqDate); + shiftInfoBean.setShiftRuleMap(workTime.getShiftRuleInfo()); + shiftInfoBean.setSignTime(lsSignTime); + shiftInfoBean.setWorkTime(lsWorkTime); + shiftInfoBean.setSignoutOnlyoff(signoutOnlyoff); + List logList = Lists.newArrayList(); + KQShiftRuleInfoBiz.getShiftRuleInfo(shiftInfoBean, userId, shifRuleMap,logList); + if(!shifRuleMap.isEmpty()){ + if(!logList.isEmpty()){ + otherinfo.put("logList", logList); + } + + otherinfo.put("shiftRule", shifRuleMap); + if(shifRuleMap.containsKey("shift_beginworktime")){ + String shift_beginworktime = Util.null2String(shifRuleMap.get("shift_beginworktime")); + if(shift_beginworktime.length() > 0){ + workBeginTime = Util.null2String(shift_beginworktime); + workBeginIdx = kqTimesArrayComInfo.getArrayindexByTimes(workBeginTime); + workTimeScope.setBeginTime(workBeginTime); + workTimeScope.setBeginTimeAcross(workBeginIdx>=1440?true:false); + } + } + if(this.writeLog) { + logInfo.put("before.workEndIdx",workEndIdx); + } + if(shifRuleMap.containsKey("shift_endworktime")){ + String shift_endworktime = Util.null2String(shifRuleMap.get("shift_endworktime")); + if(shift_endworktime.length() > 0){ + workEndTime = Util.null2String(shift_endworktime); + workEndIdx = kqTimesArrayComInfo.getArrayindexByTimes(workEndTime); + workTimeScope.setEndTime(workEndTime); + workTimeScope.setEndTimeAcross(workEndIdx>=1440?true:false); + } } } + kqLog.info("个性化之后 signBeginDateTime" + signBeginDateTime); + kqLog.info("个性化之后 signEndDateTime" + signEndDateTime); + kqLog.info("个性化之后 workBeginDateTime" + workBeginDateTime); + kqLog.info("个性化之后 workEndDateTime" + workEndDateTime); } - kqLog.info("个性化之后 signBeginDateTime" + signBeginDateTime); - kqLog.info("个性化之后 signEndDateTime" + signEndDateTime); - kqLog.info("个性化之后 workBeginDateTime" + workBeginDateTime); - kqLog.info("个性化之后 workEndDateTime" + workEndDateTime); + } + if(this.writeLog) { + logInfo.put("after.workEndIdx",workEndIdx); } - List lsCheckInfo = new KQFormatSignData().getSignInfo(userId,signTimeScope,workTimeScope,kqDate,preDate,nextDate,kqTimesArrayComInfo,hostIps,uuid,shiftCount,shiftI); + List lsCheckInfo = new KQFormatSignData().getSignInfo(userId,signTimeScope,workTimeScope,kqDate,preDate,nextDate,kqTimesArrayComInfo,hostIps,uuid,shiftCount,shiftI,signoutOnlyoff); kqLog.info("lsCheckInfo" + JSONObject.toJSONString(lsCheckInfo)+"::userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); if(this.writeLog) { logInfo.put(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10005297,weaver.general.ThreadVarLanguage.getLang())+"",signBeginDateTime); @@ -374,6 +569,11 @@ public class KQFormatData extends BaseBean { signInDate = signDate; signInTime = signTime; signInTimeIndx = kqTimesArrayComInfo.getArrayindexByTimes(signInTime); + if(this.writeLog) { + logInfo.put(j+">>>signInTime",signInTime); + logInfo.put(j+">>>signInTimeIndx",signInTimeIndx); + logInfo.put(j+">>>kqDate",kqDate+"|"+signDate); + } if(deduct_signintime.length() > 0){ if(signTime.length() > 0){ if(deduct_signintime.compareTo(signTime) < 0){ @@ -395,11 +595,6 @@ public class KQFormatData extends BaseBean { flowSignInTimeIndx -= 1440; flowSignInTimeIndx = flowSignInTimeIndx < 0 ? 0 : flowSignInTimeIndx; } - if(oneSign){ - if(workBeginIdx>signInTimeIndx) { - earlyInMins = workBeginIdx-signInTimeIndx; - } - } } else if (checkInfo.get("signType").equals("2")) {//签退 checkOut++; //如果流程抵扣存在,打卡时长也存在,那么相互比较得到出勤时长和打卡时长 暂不这样处理,还是按照漏签的逻辑来处理 @@ -463,6 +658,11 @@ public class KQFormatData extends BaseBean { } else if (checkInfo.get("signType").equals("2")) {//签退 if(signTime.length() > 0){ beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(signTime); + if(this.writeLog) { + logInfo.put(j+".signTime",signDate+"|"+signTime); + logInfo.put(j+".beginIdx",beginIdx); + logInfo.put(j+".workEndIdx",workEndIdx); + } if(StringUtils.isNotBlank(signDate) && signDate.compareTo(kqDate) > 0){ beginIdx+=1440; }else if(kqDate.compareTo(signDate) > 0){ @@ -548,24 +748,76 @@ public class KQFormatData extends BaseBean { workFlow = (List) workFlowInfo.get(dateKey); } + boolean isHandle1 = false; + boolean isHandle2 = false; + List flowList = Lists.newArrayList(); for (int j = 0; workFlow != null && j < workFlow.size(); j++) { Map data = (Map) workFlow.get(j); String flowType = Util.null2String(data.get("flowtype")); String newLeaveType = Util.null2String(data.get("newleavetype")); String signtype = Util.null2String(data.get("signtype")); + String durationrule = Util.null2String(data.get("durationrule")); + String ishalf = Util.null2String(data.get("ishalf")); + double duration = Util.getDoubleValue(Util.null2String(data.get("duration"))); + if(flowType.equalsIgnoreCase(FlowReportTypeEnum.LEAVE.getFlowType())){ + duration = Util.getDoubleValue(Util.null2String(data.get(newLeaveType))); + } String serial = Util.null2String(data.get("serial")); String requestId = Util.null2String(data.get("requestId")); - beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("begintime"))); - endIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("endtime"))); + String begintime = Util.null2String(data.get("begintime")); + String endtime = Util.null2String(data.get("endtime")); + beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(begintime); + endIdx = kqTimesArrayComInfo.getArrayindexByTimes(endtime); + String leavetypeKey = repeatKey+"_"+newLeaveType; + List kqRepeatBeans = KQRepeatLengthContext.getKQRepeatBean(leavetypeKey); + if(CollectionUtils.isNotEmpty(kqRepeatBeans)){ + Long allCnt = 0L; + for (int k = 0; k < kqRepeatBeans.size(); k++) { + KQRepeatBean kqRepeatBean = kqRepeatBeans.get(k); + Long repeatLate = kqRepeatBean.getRepeatLate(); + Long repeatEarly = kqRepeatBean.getRepeatEarly(); + allCnt += ((repeatLate != null && repeatLate > 0) ? repeatLate : 0L)+ ((repeatEarly != null && repeatEarly > 0) ? repeatEarly : 0L); + } + if(leaveInfo.get(newLeaveType)==null){ + leaveInfo.put(newLeaveType,allCnt.intValue()); + }else{ + Integer val = (Integer) leaveInfo.get(newLeaveType); + leaveInfo.put(newLeaveType,val+allCnt); + } + continue; + } if (beginIdx >= endIdx) { continue; } + Map flowMap = Maps.newHashMap(); + flowMap.put("newLeaveType", newLeaveType); + flowMap.put("begintime", begintime); + flowMap.put("endtime", endtime); + List> flowMapList = Lists.newArrayList(); + if(flowinfo.containsKey(flowType)){ + List> tmpFlowMapList = (List>) flowinfo.get(flowType); + tmpFlowMapList.add(flowMap); + }else{ + flowMapList.add(flowMap); + flowinfo.put(flowType, flowMapList); + } + int middleIdx = (workBeginIdx+workEndIdx)/2;//工作时段标识 1 + if(flowType.equals(FlowReportTypeEnum.EVECTION.getFlowType())){ + if("2".equals(durationrule) && "true".equals(ishalf)){ + isHandle2 = true; + } Arrays.fill(dayMins, beginIdx, endIdx, 7);//出差抵扣时段标识 7 }else if(flowType.equals(FlowReportTypeEnum.OUT.getFlowType())){ + if("2".equals(durationrule) && "true".equals(ishalf)){ + isHandle2 = true; + } Arrays.fill(dayMins, beginIdx, endIdx, 8);//公出抵扣时段标识 8 }else if(flowType.equalsIgnoreCase(FlowReportTypeEnum.LEAVE.getFlowType())){ + if("2".equals(durationrule) && "true".equals(ishalf)){ + isHandle1 = true; + } if (endIdx > beginIdx) { Arrays.fill(dayMins, beginIdx, endIdx, 5);//流程抵扣时段标识 5 int tmpBeginIdx = beginIdx; @@ -599,37 +851,6 @@ public class KQFormatData extends BaseBean { } - if (workEndTimeAcross && false) {//跨天需要加入一天的流程 - workFlow = null; - if (workFlowInfo.get(nextDateKey) != null) { - workFlow = (List) workFlowInfo.get(nextDateKey); - } - - for (int j = 0; workFlow != null && j < workFlow.size(); j++) { - Map data = (Map) workFlow.get(j); - String flowType = Util.null2String(data.get("flowtype")); - beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("begintime")))+1440; - endIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("endtime")))+1440; - if(endIdx>=2880){ - endIdx = 2880; - } - if(flowType.equals(FlowReportTypeEnum.EVECTION.getFlowType())){ - Arrays.fill(dayMins, beginIdx, endIdx, 7);//出差抵扣时段标识 7 - }else if(flowType.equals(FlowReportTypeEnum.OUT.getFlowType())){ - Arrays.fill(dayMins, beginIdx, endIdx, 8);//公出抵扣时段标识 8 - }else if(flowType.equalsIgnoreCase(FlowReportTypeEnum.LEAVE.getFlowType())){ - if (endIdx > beginIdx) { - Arrays.fill(dayMins, beginIdx, endIdx, 5);//流程抵扣时段标识 5 - - } - }else{ - if (endIdx > beginIdx) { - Arrays.fill(dayMins, beginIdx, endIdx, 99);//异常流程抵扣时段标识99 - } - } - } - } - if(lsRestTime != null && !lsRestTime.isEmpty()){ for(int k = 0 ; k < lsRestTime.size(); k++){ TimeScopeEntity restTimeScope = lsRestTime.get(k); @@ -661,6 +882,11 @@ public class KQFormatData extends BaseBean { leaveEarlyMins++; break; case 4: + if(j attendRepeatBeans = KQRepeatLengthContext.getKQRepeatBean(repeatKey); + + if(beLateMins > 0){ + beLateMins = (int) handleRepeatLength(attendRepeatBeans, beLateMins, "late"); + } + if(leaveEarlyMins > 0){ + leaveEarlyMins = (int) handleRepeatLength(attendRepeatBeans, leaveEarlyMins, "early"); + } + + boolean isAmAbsent = false; + boolean isPmAbsent = false; + if(on_absenteeismMins > 0){ + //如果没有个性化的旷工,那就是全天旷工 + isAmAbsent = true; + } + if(off_absenteeismMins > 0) { + isPmAbsent = true; + } + KQShiftRuleEntity kqShiftRuleEntity = new KQShiftRuleEntity(); kqShiftRuleEntity.setUserId(userId); kqShiftRuleEntity.setKqDate(kqDate); @@ -700,6 +945,12 @@ public class KQFormatData extends BaseBean { kqShiftRuleEntity.setForgotBeginWorkCheckMins(forgotBeginWorkCheckMins); kqShiftRuleEntity.setEarlyInMins(earlyInMins); kqShiftRuleEntity.setLateOutMins(lateOutMins); + kqShiftRuleEntity.setAMAbsent(isAmAbsent); + kqShiftRuleEntity.setPMAbsent(isPmAbsent); + kqShiftRuleEntity.setNosign_is_absent(nosign_is_absent); + kqShiftRuleEntity.setSignInTime(signInTime); + kqShiftRuleEntity.setSignOutTime(signOutTime); + kqShiftRuleEntity.setEarly_one_mins(early_one_mins); kqLog.info("人性化规则处理前数据" + JSONObject.toJSONString(kqShiftRuleEntity)); if(this.writeLog) { logInfo.put(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10005301,weaver.general.ThreadVarLanguage.getLang())+"",kqShiftRuleEntity); @@ -717,6 +968,14 @@ public class KQFormatData extends BaseBean { absenteeismMins = kqShiftRuleEntity.getAbsenteeismmins(); forgotCheckMins = kqShiftRuleEntity.getForgotcheckmins(); forgotBeginWorkCheckMins = kqShiftRuleEntity.getForgotBeginWorkCheckMins(); + int shiftOn_absenteeismMins = Util.getIntValue(kqShiftRuleEntity.getOn_absenteeismMins()); + if(shiftOn_absenteeismMins > 0) { + on_absenteeismMins = shiftOn_absenteeismMins; + } + int shiftOff_absenteeismMins = Util.getIntValue(kqShiftRuleEntity.getOff_absenteeismMins()); + if(shiftOff_absenteeismMins > 0) { + off_absenteeismMins = shiftOff_absenteeismMins; + } boolean isondutyfreecheck =false; boolean isoffdutyfreecheck =false; @@ -743,14 +1002,20 @@ public class KQFormatData extends BaseBean { absenteeismMins = 0; forgotCheckMins = 0; forgotBeginWorkCheckMins = 0; + isAmAbsent = false; + isPmAbsent = false; + on_absenteeismMins = 0; + off_absenteeismMins = 0; }else if(!new KQFormatBiz().needCal(workEndDate,workEndTime)) {//还未到下班时间 kqLog.writeLog("还未到上班时间"); leaveEarlyMins = 0; graveLeaveEarlyMins = 0; forgotCheckMins = 0; + isPmAbsent = false; + off_absenteeismMins = 0; } - if (workTime.getIsExclude()) {//无需考勤人员没有异常状态 + if (1 == restShift || workTime.getIsExclude()) {//休息日班次或者无需考勤人员没有异常状态 beLateMins = 0; graveBeLateMins = 0; leaveEarlyMins = 0; @@ -758,6 +1023,18 @@ public class KQFormatData extends BaseBean { absenteeismMins = 0; forgotCheckMins = 0; forgotBeginWorkCheckMins = 0; + isAmAbsent = false; + isPmAbsent = false; + on_absenteeismMins = 0; + off_absenteeismMins = 0; + } + if (1 == restShift) {//非工作日班次連打卡時長和出勤时长也不給了 + workMins = 0; + signMins = 0; + isAmAbsent = false; + isPmAbsent = false; + on_absenteeismMins = 0; + off_absenteeismMins = 0; } //允许下班不打卡 ,如果上班也没有打卡,那么算上班旷工0.5天 if (isoffdutyfreecheck) { @@ -768,6 +1045,7 @@ public class KQFormatData extends BaseBean { } absenteeismMins = 0; forgotCheckMins = 0; + off_absenteeismMins = 0; } //允许上班不打卡,如果下班也没有打卡,那么算漏签 if(isondutyfreecheck){ @@ -778,14 +1056,134 @@ public class KQFormatData extends BaseBean { } absenteeismMins = 0; forgotBeginWorkCheckMins = 0; + on_absenteeismMins = 0; } if(isondutyfreecheck&&isoffdutyfreecheck){ absenteeismMins = 0; forgotCheckMins = 0; forgotBeginWorkCheckMins = 0; + on_absenteeismMins = 0; + off_absenteeismMins = 0; + } + int repeatLeaveTime = (int) getRepeatLeaveTime(); + if(repeatLeaveTime > 0){ + leaveMins = leaveMins+repeatLeaveTime; } //计算实际出勤时间(出差公出算出勤)=应出勤-旷工-请假-迟到-早退 attendanceMins = workMins - absenteeismMins-leaveMins-beLateMins-graveBeLateMins-leaveEarlyMins-graveLeaveEarlyMins; + + if(this.writeLog) { + logInfo.put("is_half",is_half); + logInfo.put("shiftNums",shiftNums); + logInfo.put("isHandle2",isHandle2); + logInfo.put("isHandle1",isHandle1); + logInfo.put("workMins"+i,workMins); + logInfo.put("absenteeismMins"+i,absenteeismMins); + logInfo.put("middleMins"+i,middleMins); + } + //如果开启半天特殊处理的,请假是需要扣除0.5天 + //说明没有打卡的情况,因为有打卡肯定是有迟到、早退、漏签这些异常的,不考虑迟到算旷工,早退算旷工的情况 + //只处理1天1次,和1天2次的情况,因为1天3次的中间点可能在第二段,需要考虑有没有打卡,以及有打卡第三次是否需要处理等情况,和上下午半天的概念不太适用 + if("1".equals(is_half)){ + boolean absentFlag_1 = false;//请假, + boolean absentFlag_2 = false;//公出或出差 + if(isHandle1 || isHandle2){ + if(absenteeismMins>0 && !(beLateMins >0||graveBeLateMins > 0||leaveEarlyMins > 0||graveLeaveEarlyMins > 0||forgotCheckMins > 0||forgotBeginWorkCheckMins >0)){ + if(isHandle1){ + absentFlag_1 = true;//可以理解为是1天3次和1天1次的情况,因为1天2次的情况,如果有旷工,那么另外半天才是有请假, + } + if(isHandle2){ + absentFlag_2 = true;//可以理解为是1天3次和1天1次的情况,因为1天2次的情况,如果有旷工,那么另外半天才是有公出或者出差 + } + } + } + if(this.writeLog) { + logInfo.put("tmp_absenteeismMins"+i,absenteeismMins); + logInfo.put("absentFlag_1"+i,absentFlag_1); + logInfo.put("absentFlag_2"+i,absentFlag_2); + } + /*1次---上午3小时,下午5小时 + 上午公出,下午旷工 + 上午公出,下午打卡 + 上午旷工,下午公出 + 上午打卡,下午公出 + + 2次---上午3小时,下午5小时 + 上午公出,下午旷工--需处理实际出勤、旷工时长 + 上午公出,下午打卡--需处理实际出勤 + 上午旷工,下午公出--需处理实际出勤、旷工时长 + 上午打卡,下午公出--需处理实际出勤 + */ + if(isHandle2){ + if(shiftNums ==1){ + absenteeismMins = absentFlag_2?middleMins_final:0; + attendanceMins = workMins - absenteeismMins; + }else if(shiftNums == 2){ + if(workMins>middleMins_final && middleMins_final>0){ + absenteeismMins = (absenteeismMins > middleMins_final)?middleMins_final:((absentFlag_2||outMins>0||evectionMins>0)?Math.abs(workMins - middleMins_final):0); + absenteeismMins = (i==1 && middleMap.get("attendanceMins0")>0)?(absentFlag_2?absenteeismMins:0):absenteeismMins;//上午打卡3小时,下午公出5小时,下午的就不要显示旷工1小时了 + } + attendanceMins = workMins - absenteeismMins; + } + } + if(this.writeLog) { + logInfo.put("absenteeismMins_1"+i,absenteeismMins); + logInfo.put("attendanceMins_1"+i,attendanceMins); + } + + /*1次---上午3小时,下午5小时 + 上午请假,下午旷工 + 上午请假,下午打卡 + 上午旷工,下午请假 + 上午打卡,下午请假 + + 2次---上午3小时,下午5小时 + 上午请假,下午旷工--需处理实际出勤、旷工时长 + 上午请假,下午打卡--需处理实际出勤 + 上午旷工,下午请假--需处理实际出勤、旷工时长 + 上午打卡,下午请假--需处理实际出勤 + */ + + if(isHandle1){ + if(shiftNums == 1){ + absenteeismMins = absentFlag_1?middleMins_final:0; + attendanceMins = workMins - absenteeismMins - (leaveMins>0?middleMins_final:(absentFlag_1?(workMins - middleMins_final):0)); + }else if(shiftNums == 2){ + if(workMins>middleMins_final && middleMins_final>0){ + absenteeismMins = (absenteeismMins > middleMins_final)?middleMins_final:((absentFlag_1||leaveMins>0)?Math.abs(workMins - middleMins_final):0); + absenteeismMins = (i==1 && middleMap.get("attendanceMins0")>0)?0:absenteeismMins;//上午打卡3小时,下午请假5小时,下午的就不要显示旷工1小时了 + } + attendanceMins = workMins - absenteeismMins - (leaveMins>0?middleMins_final:(absentFlag_1?Math.abs(workMins - middleMins_final):0)); + attendanceMins = attendanceMins>middleMins_final?middleMins_final:attendanceMins;//上午请假3小时,下午打卡5小时 + }else if(shiftNums == 3){//比如一天三次上下班,那么中间点在第二次上下班区间 +// if(workMins>middleMins && middleMins>0){ +// absenteeismMins = (absenteeismMins > middleMins_final)?middleMins_final:((absentFlag_1||leaveMins>0)?(workMins - middleMins):0); +// absenteeismMins = (i>=1 && middleMap.get("attendanceMins"+(i-1))>0)?0:absenteeismMins; +// } +// attendanceMins = workMins - absenteeismMins - (leaveMins>0?middleMins_final:(absentFlag_1?Math.abs(workMins - middleMins_final):0)); +// attendanceMins = attendanceMins>middleMins_final?middleMins_final:attendanceMins;//上午请假3小时,下午打卡5小时 +// if(workMins < middleMins){//客户可能是一天2次,或者3次,那么workmins有可能是小于半天的请假时间 +// middleMins = middleMins-workMins; +// }else { +// middleMins = 0; +// } + } + if(absenteeismMins > middleMins_final){//客户可能是一天2次,或者3次 + absenteeismMins = middleMins_final; + } + } + middleMap.put("attendanceMins"+i,attendanceMins); + middleMap.put("absenteeismMins"+i,absenteeismMins); + middleMap.put("workMins"+i,workMins); + middleMap.put("leaveMins"+i,leaveMins); + middleMap.put("outMins"+i,outMins); + middleMap.put("evectionMins"+i,evectionMins); + middleMap.put("isHandle1"+i,isHandle1?1:0); + middleMap.put("isHandle2"+i,isHandle2?1:0); + middleMap.put("absentFlag_1"+i,absentFlag_1?1:0);//1表示有旷工 + middleMap.put("absentFlag_2"+i,absentFlag_2?1:0);//1表示有旷工 + } + // 如果没有开启"漏签是否算实际出勤"开关,则漏签不算实际出勤时长 if("0".equals(nosign_is_absent)) { attendanceMins = attendanceMins-forgotCheckMins-forgotBeginWorkCheckMins; @@ -793,11 +1191,24 @@ public class KQFormatData extends BaseBean { if(beforeBegin || attendanceMins < 0) {//还未到上班时间,不用计算任何状体 attendanceMins = 0; } + + /** + * 汇总报表的日历显示是有旷工就不显示漏签了,如果这里还统计漏签,张总表示日历也需要修改,改不动了 + * 在处理完实际出勤之后,将漏签还原 + */ + String nosign_ishandle = Util.null2String(kqShiftRuleEntity.getNosign_ishandle()); + if("1".equals(nosign_ishandle)){ + forgotCheckMins = 0; + }else if("2".equals(nosign_ishandle)){ + forgotCheckMins = 0; + forgotBeginWorkCheckMins = 0; + } + kqLog.info("实际出勤计算公式" + "实际出勤=应出勤- 旷工-请假-迟到-早退 userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); - kqLog.info("实际出勤计算结果" + attendanceMins + "=" + workMins + "- " + absenteeismMins + "-" + leaveMins + "-" + (beLateMins + graveBeLateMins) + "-" + (leaveEarlyMins - graveLeaveEarlyMins)+" userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); + kqLog.info("实际出勤计算结果" + attendanceMins + "=" + workMins + "- " + absenteeismMins + "-" + leaveMins + "-" + (beLateMins + graveBeLateMins) + "-" + (leaveEarlyMins - graveLeaveEarlyMins)+ "-" + (repeatLeaveTime)+" userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid); if(this.writeLog) { logInfo.put(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10005303,weaver.general.ThreadVarLanguage.getLang())+"",""+weaver.systeminfo.SystemEnv.getHtmlLabelName(130566,weaver.general.ThreadVarLanguage.getLang())+"="+weaver.systeminfo.SystemEnv.getHtmlLabelName(132056,weaver.general.ThreadVarLanguage.getLang())+"- "+weaver.systeminfo.SystemEnv.getHtmlLabelName(20085,weaver.general.ThreadVarLanguage.getLang())+"-"+weaver.systeminfo.SystemEnv.getHtmlLabelName(670,weaver.general.ThreadVarLanguage.getLang())+"-"+weaver.systeminfo.SystemEnv.getHtmlLabelName(20081,weaver.general.ThreadVarLanguage.getLang())+"-"+weaver.systeminfo.SystemEnv.getHtmlLabelName(20082,weaver.general.ThreadVarLanguage.getLang())+""); - logInfo.put(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10005304,weaver.general.ThreadVarLanguage.getLang())+"",attendanceMins+"="+workMins+"- "+absenteeismMins+"-"+leaveMins+"-"+(beLateMins+graveBeLateMins)+"-"+(leaveEarlyMins-graveLeaveEarlyMins)); + logInfo.put(""+weaver.systeminfo.SystemEnv.getHtmlLabelName(10005304,weaver.general.ThreadVarLanguage.getLang())+"",attendanceMins+"="+workMins+"- "+absenteeismMins+"-"+leaveMins+"-"+(beLateMins+graveBeLateMins)+"-"+(leaveEarlyMins-graveLeaveEarlyMins)+"-"+(repeatLeaveTime)); } //判断当天考勤状态 // if (beLateMins > 0) { @@ -879,15 +1290,265 @@ public class KQFormatData extends BaseBean { } kqLog.info("format in >>>>>userId" + userId + "kqDate==" + kqDate+":hostIps:"+hostIps+":uuid::"+uuid +":params:"+JSON.toJSONString(params)); + Long id = IdGenerator.generate(); + params.add(workTime.getDayType()); + params.add(date); + params.add(date); + params.add(id); + params.add(JSONObject.toJSONString(flowinfo)); +// if(isAmAbsent){ +// params.add(1); +// }else { +// params.add(0); +// } +// if(isPmAbsent){ +// params.add(1); +// }else { +// params.add(0); +// } + params.add(on_absenteeismMins); + params.add(off_absenteeismMins); lsParam.add(params); + + resetAttendRepeatBeans(attendRepeatBeans); + //这个只是记录每个时段消耗的哺乳假,用完就清掉 + KQRepeatLengthContext.removeRepeatBeanLinkRange(); + //把每一段的请假时长记录一下 + allLeaveMins += leaveMins; + } + KQRepeatLengthContext.removeRepeatBean(); + KQRepeatLengthContext.clear(); + KQRepeatLengthContext.removeRepeatBeanLinkRange(); + + if(repeatLeaveMins > 0){ + if(allLeaveMins == 0){ + //哺乳假 有这种情况,没有迟到,也没有早退,allLeaveMins未0的情况 + if(CollectionUtils.isNotEmpty(lsParam)){ + List tmp = lsParam.get(0); + //目前请假时长是24位,以后有新增调整列一定要记得改这里的 + tmp.set(24, repeatLeaveMins); + } + } } } catch (Exception e) { - writeLog(e); - kqLog.info(e); + kqLog.info("考勤格式化生成数据报错:KQFormatData:"); + StringWriter errorsWriter = new StringWriter(); + e.printStackTrace(new PrintWriter(errorsWriter)); + kqLog.info(errorsWriter.toString()); } return lsParam; } + /** + * 哺乳假被当前规则用完了之后,需要把late和early的已休时长重置一下 + * 为什么要在这里搞,因为前面迟到,严重迟到在判断的时候都需要用到原始数据,只有前面的判断都用完了,最后才能去更新 + * @param attendRepeatBeans + */ + private void resetAttendRepeatBeans(List attendRepeatBeans) { + if(CollectionUtils.isEmpty(attendRepeatBeans)){ + return ; + } + KQRepeatBean attendRepeatBeanLink = KQRepeatLengthContext.getRepeatBeanLink(); + if(attendRepeatBeanLink == null){ + return ; + } + Long repeatLateLink = attendRepeatBeanLink.getRepeatLateLink(); + Long repeatEarlyLink = attendRepeatBeanLink.getRepeatEarlyLink(); + for (int i = 0; i < attendRepeatBeans.size(); i++) { + KQRepeatBean attendRepeatBean = attendRepeatBeans.get(i); + Long repeatEarly = attendRepeatBean.getRepeatEarly(); + Long repeatLate = attendRepeatBean.getRepeatLate(); + if(repeatLateLink != null && repeatLateLink > 0 && repeatLate != null && repeatLate > 0){ + if(repeatLateLink > repeatLate){ + repeatLateLink = repeatLateLink - repeatLate; + attendRepeatBean.setRepeatLateLink(repeatLate); + }else{ + attendRepeatBean.setRepeatLateLink(repeatLateLink); + repeatLateLink= 0L; + } + } + if(repeatEarlyLink != null && repeatEarlyLink > 0 && repeatEarly != null && repeatEarly > 0){ + if(repeatEarlyLink > repeatEarly){ + repeatEarlyLink = repeatEarlyLink - repeatEarly; + attendRepeatBean.setRepeatEarlyLink(repeatEarly); + }else{ + attendRepeatBean.setRepeatEarlyLink(repeatEarlyLink); + repeatEarlyLink = 0L; + } + } + } + } + + /** + * 实际出勤里也要去除哺乳假的时长 + * @return + */ + private long getRepeatLeaveTime() { + long repeatLeaveTime = 0L; + KQRepeatBean attendRepeatBeanLink = KQRepeatLengthContext.getRepeatBeanLinkRange(); + if(attendRepeatBeanLink == null){ + return repeatLeaveTime; + } + Long repeatLateLink = attendRepeatBeanLink.getRepeatLateLink(); + Long repeatEarlyLink = attendRepeatBeanLink.getRepeatEarlyLink(); + if(repeatLateLink > 0){ + repeatLeaveTime = repeatLateLink; + } + if(repeatEarlyLink > 0){ + if(repeatLeaveTime > 0){ + repeatLeaveTime += repeatEarlyLink; + }else{ + repeatLeaveTime = repeatEarlyLink; + } + } + return repeatLeaveTime; + } + + /** + * 哺乳假针对异常时长部分的处理 + * @param attendRepeatBeans + * @param repeatLength + * @param type + * @return + */ + private long handleRepeatLength(List attendRepeatBeans, long repeatLength, String type) { + if(repeatLength <= 0){ + return repeatLength; + } + Long oriLength = repeatLength; + try{ +// 当天总消耗哺乳假 用于当天迟到早退 + KQRepeatBean attendRepeatBeanLink = KQRepeatLengthContext.getRepeatBeanLink(); +// 当前时段消耗哺乳假,用于计算缺勤 + KQRepeatBean attendRepeatBeanLinkRange = KQRepeatLengthContext.getRepeatBeanLinkRange(); + if(attendRepeatBeanLink == null){ + attendRepeatBeanLink = new KQRepeatBean(); + } + if(attendRepeatBeanLinkRange == null){ + attendRepeatBeanLinkRange = new KQRepeatBean(); + } + Long repeatLateLink = attendRepeatBeanLink.getRepeatLateLink(); + if(repeatLateLink == null){ + repeatLateLink = 0L; + } + Long repeatEarlyLink = attendRepeatBeanLink.getRepeatEarlyLink(); + if(repeatEarlyLink == null){ + repeatEarlyLink = 0L; + } + Long repeatLateLinkRange = attendRepeatBeanLinkRange.getRepeatLateLink(); + if(repeatLateLinkRange == null){ + repeatLateLinkRange = 0L; + } + Long repeatEarlyLinkRange = attendRepeatBeanLinkRange.getRepeatEarlyLink(); + if(repeatEarlyLinkRange == null){ + repeatEarlyLinkRange = 0L; + } + if(CollectionUtils.isNotEmpty(attendRepeatBeans)){ + for (int i = 0; i < attendRepeatBeans.size(); i++) { + KQRepeatBean attendRepeatBean = attendRepeatBeans.get(i); + if(oriLength <= 0){ + attendRepeatBeanLink.setRepeatLateLink(repeatLateLink); + attendRepeatBeanLink.setRepeatEarlyLink(repeatEarlyLink); + KQRepeatLengthContext.setRepeatBeanLink(attendRepeatBeanLink); + attendRepeatBeanLinkRange.setRepeatLateLink(repeatLateLinkRange); + attendRepeatBeanLinkRange.setRepeatEarlyLink(repeatEarlyLinkRange); + KQRepeatLengthContext.setRepeatBeanLinkRange(attendRepeatBeanLinkRange); + return oriLength; + } + if("late".equals(type)){ + Long repeatLate = attendRepeatBean.getRepeatLate(); + Long repeatLatTmp = attendRepeatBean.getRepeatLateLink(); + if(repeatLate != null){ + if(repeatLatTmp != null && repeatLatTmp > 0){ + repeatLate = repeatLate - repeatLatTmp; + repeatLate = repeatLate < 0 ? 0 : repeatLate; + } + oriLength = oriLength - repeatLate; + oriLength = oriLength < 0 ? 0 : oriLength; + if(oriLength == 0){ + //如果异常已经被每天重复时长完全抵扣了,那么需要更新下AttendRepeatBeanLink + repeatLateLink += repeatLength; + repeatLateLinkRange += repeatLength; + }else{ + repeatLateLink += repeatLate; + repeatLateLinkRange += repeatLate; + } + } + } + if("early".equals(type)){ + Long repeatEarly = attendRepeatBean.getRepeatEarly(); + Long repeatEarTmp = attendRepeatBean.getRepeatEarlyLink(); + if(repeatEarly != null){ + if(repeatEarTmp != null && repeatEarTmp > 0){ + repeatEarly = repeatEarly - repeatEarTmp; + repeatEarly = repeatEarly < 0 ? 0 : repeatEarly; + } + oriLength = oriLength - repeatEarly; + oriLength = oriLength < 0 ? 0 : oriLength; + if(oriLength == 0){ + //如果异常已经被每天重复时长完全抵扣了,那么需要更新下AttendRepeatBean + repeatEarlyLink += repeatLength; + repeatEarlyLinkRange += repeatLength; + }else{ + repeatEarlyLink += repeatEarly; + repeatEarlyLinkRange += repeatEarly; + } + } + } + } + } + + attendRepeatBeanLink.setRepeatLateLink(repeatLateLink); + attendRepeatBeanLink.setRepeatEarlyLink(repeatEarlyLink); + KQRepeatLengthContext.setRepeatBeanLink(attendRepeatBeanLink); + attendRepeatBeanLinkRange.setRepeatLateLink(repeatLateLinkRange); + attendRepeatBeanLinkRange.setRepeatEarlyLink(repeatEarlyLinkRange); + KQRepeatLengthContext.setRepeatBeanLinkRange(attendRepeatBeanLinkRange); + }catch (Exception e){ + kqLog.error("handleRepeatLength",e); + } + return oriLength; + } + + public int handleRepeatWorkFlowInfo(List workFlowRepeat, String repeatKey) { + int repeatLeaveMins = 0; + for (int j = 0; workFlowRepeat != null && j < workFlowRepeat.size(); j++) { + Map data = (Map) workFlowRepeat.get(j); + String repeatType = Util.null2String(data.get("repeatType")); + String repeatLate = Util.null2String(data.get("repeatLate")); + String repeatEarly = Util.null2String(data.get("repeatEarly")); + String newleavetype = Util.null2String(data.get("newleavetype")); + String leavetypeKey = repeatKey+"_"+newleavetype; + KQRepeatBean repeatBean = new KQRepeatBean(); + repeatBean.setRepeatType(repeatType); + if("0".equals(repeatType)){ + if(repeatLate.length() > 0){ + repeatBean.setRepeatLate(new Double(Double.valueOf(repeatLate)).longValue()); + repeatLeaveMins += new Double(Double.valueOf(repeatLate)).longValue(); + } + } + if("1".equals(repeatType)){ + if(repeatEarly.length() > 0){ + repeatBean.setRepeatEarly(new Double(Double.valueOf(repeatEarly)).longValue()); + repeatLeaveMins += new Double(Double.valueOf(repeatEarly)).longValue(); + } + } + if("2".equals(repeatType)){ + if(repeatLate.length() > 0){ + repeatBean.setRepeatLate(new Double(Double.valueOf(repeatLate)).longValue()); + repeatLeaveMins += new Double(Double.valueOf(repeatLate)).longValue(); + } + if(repeatEarly.length() > 0){ + repeatBean.setRepeatEarly(new Double(Double.valueOf(repeatEarly)).longValue()); + repeatLeaveMins += new Double(Double.valueOf(repeatEarly)).longValue(); + } + } + KQRepeatLengthContext.setKQRepeatBean(repeatKey,repeatBean); + KQRepeatLengthContext.setKQRepeatBean(leavetypeKey,repeatBean); + } + return repeatLeaveMins; + } + public void setWriteLog(boolean writeLog) { this.writeLog = writeLog; } @@ -934,6 +1595,7 @@ public class KQFormatData extends BaseBean { int beginIdx = 0; int endIdx = 0; int leaveMins = 0;//请假时长 + Map flowinfo = new HashMap<>();//流程信息 Map leaveInfo = new HashMap<>();//请假信息 int evectionMins = 0;//出差时长 int outMins = 0;//公出时长 @@ -987,8 +1649,26 @@ public class KQFormatData extends BaseBean { Map data = (Map) workFlow.get(j); String flowType = Util.null2String(data.get("flowtype")); String newLeaveType = Util.null2String(data.get("newleavetype")); - beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("begintime"))); - endIdx = kqTimesArrayComInfo.getArrayindexByTimes(Util.null2String(data.get("endtime"))); + String begintime = Util.null2String(data.get("begintime")); + String endtime = Util.null2String(data.get("endtime")); + beginIdx = kqTimesArrayComInfo.getArrayindexByTimes(begintime); + endIdx = kqTimesArrayComInfo.getArrayindexByTimes(endtime); + + if (beginIdx > endIdx) { + continue; + } + Map flowMap = Maps.newHashMap(); + flowMap.put("newLeaveType", newLeaveType); + flowMap.put("begintime", begintime); + flowMap.put("endtime", endtime); + List> flowMapList = Lists.newArrayList(); + if(flowinfo.containsKey(flowType)){ + List> tmpFlowMapList = (List>) flowinfo.get(flowType); + tmpFlowMapList.add(flowMap); + }else{ + flowMapList.add(flowMap); + flowinfo.put(flowType, flowMapList); + } if(flowType.equals(FlowReportTypeEnum.EVECTION.getFlowType())){ Arrays.fill(dayMins, beginIdx, endIdx, 7);//出差抵扣时段标识 7 }else if(flowType.equals(FlowReportTypeEnum.OUT.getFlowType())){ @@ -1048,5 +1728,12 @@ public class KQFormatData extends BaseBean { nonlsParam.add(JSONObject.toJSONString(leaveInfo)); nonlsParam.add(evectionMins); nonlsParam.add(outMins); + nonlsParam.add(workTime.getDayType()); + Timestamp date = new Timestamp(System.currentTimeMillis()); + Long id = IdGenerator.generate(); + nonlsParam.add(date); + nonlsParam.add(date); + nonlsParam.add(id); + nonlsParam.add(JSONObject.toJSONString(flowinfo)); } }