diff --git a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowArchivingAction.java b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowArchivingAction.java index a7af270..034aadd 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowArchivingAction.java +++ b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowArchivingAction.java @@ -10,6 +10,9 @@ import weaver.general.Util; import weaver.interfaces.workflow.action.Action; import weaver.soa.workflow.request.RequestInfo; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -25,7 +28,7 @@ import java.util.stream.Collectors; public class BatchAskForLeaveWorkFlowArchivingAction implements Action { @Override public String execute(RequestInfo requestInfo) { - + String requestid = requestInfo.getRequestid(); // 流程表单主表数据 HashMap mainTableData = CommonUtil.getMainTableInfo(requestInfo); log.info("mainTableData : [{}]",mainTableData); @@ -53,7 +56,7 @@ public class BatchAskForLeaveWorkFlowArchivingAction implements Action { String jqye = Util.null2String(data.get("jqye")); double sysc = Double.valueOf(data.get("sysc").toString()); double havedSysc= balanceMap.get(jqye) ==null?0:Double.valueOf(balanceMap.get(jqye).toString()); - sysc = Utils.add(sysc,havedSysc); + sysc = new BigDecimal(String.valueOf(sysc)).add(new BigDecimal(String.valueOf(havedSysc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); balanceMap.put(jqye,sysc); } @@ -65,11 +68,14 @@ public class BatchAskForLeaveWorkFlowArchivingAction implements Action { double havedztsc = Util.null2String(map.get("ztsc")).equals("") ? 0 : Double.valueOf(map.get("ztsc").toString()); double havedyxsc = Util.null2String(map.get("yxsc")).equals("") ? 0 : Double.valueOf(map.get("yxsc").toString()); - double updatedztsc = Utils.subtract(havedztsc,ztsc); - double updatedwxsc = Utils.add(havedyxsc,ztsc); +// double updatedztsc = Utils.subtract(havedztsc,ztsc); +// double updatedyxsc = Utils.add(havedyxsc,ztsc); + double updatedztsc = new BigDecimal(String.valueOf(havedztsc)).subtract(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); + double updatedyxsc = new BigDecimal(String.valueOf(havedyxsc)).add(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); String updateSql = "update uf_jcl_kq_jqye set yxsc=?,ztsc=? where id=?"; - if (!DbTools.update(updateSql,updatedwxsc,updatedztsc,id)){ + log.info(requestid + "-updateSql : {}", updateSql); + if (!DbTools.update(updateSql,updatedyxsc,updatedztsc,id)){ //更新假期余额失败 String message = "更新假期余额失败"; log.error(message); diff --git a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowBackAction.java b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowBackAction.java index a097e62..c90d62c 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowBackAction.java +++ b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowBackAction.java @@ -10,6 +10,9 @@ import weaver.general.Util; import weaver.interfaces.workflow.action.Action; import weaver.soa.workflow.request.RequestInfo; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -63,7 +66,7 @@ public class BatchAskForLeaveWorkFlowBackAction implements Action { String jqye = Util.null2String(data.get("jqye")); double sysc = Double.valueOf(data.get("sysc").toString()); double havedSysc= balanceMap.get(jqye) ==null?0:Double.valueOf(balanceMap.get(jqye).toString()); - sysc = Utils.add(sysc,havedSysc); + sysc = new BigDecimal(String.valueOf(sysc)).add(new BigDecimal(String.valueOf(havedSysc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); balanceMap.put(jqye,sysc); } log.info("balanceMap : [{}]",balanceMap); @@ -76,8 +79,10 @@ public class BatchAskForLeaveWorkFlowBackAction implements Action { if ("1".equals(jlzt)) { double havedyxsc = Util.null2String(map.get("yxsc")).equals("") ? 0 : Double.valueOf(map.get("yxsc").toString()); double havedwxsc = Util.null2String(map.get("wxsc")).equals("") ? 0 : Double.valueOf(map.get("wxsc").toString()); - double updatedyxsc = Utils.subtract(havedyxsc,ztsc); - double updatedwxsc = Utils.add(havedwxsc,ztsc); +// double updatedyxsc = Utils.subtract(havedyxsc,ztsc); +// double updatedwxsc = Utils.add(havedwxsc,ztsc); + double updatedyxsc = new BigDecimal(String.valueOf(havedyxsc)).subtract(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); + double updatedwxsc = new BigDecimal(String.valueOf(havedwxsc)).add(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); log.info("updatedyxsc : [{}],id:[{}]",updatedyxsc,id); String updateSql = "update uf_jcl_kq_jqye set wxsc=?,yxsc=? where id=?"; @@ -86,8 +91,10 @@ public class BatchAskForLeaveWorkFlowBackAction implements Action { double havedztsc = Util.null2String(map.get("ztsc")).equals("") ? 0 : Double.valueOf(map.get("ztsc").toString()); double havedwxsc = Util.null2String(map.get("wxsc")).equals("") ? 0 : Double.valueOf(map.get("wxsc").toString()); - double updatedztsc = Utils.subtract(havedztsc,ztsc); - double updatedwxsc = Utils.add(havedwxsc,ztsc); +// double updatedztsc = Utils.subtract(havedztsc,ztsc); +// double updatedwxsc = Utils.add(havedwxsc,ztsc); + double updatedztsc = new BigDecimal(String.valueOf(havedztsc)).subtract(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); + double updatedwxsc = new BigDecimal(String.valueOf(havedwxsc)).add(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); log.info("updatedwxsc : [{}],updatedztsc:[{}],id:[{}]",updatedwxsc,updatedztsc,id); String updateSql = "update uf_jcl_kq_jqye set wxsc=?,ztsc=? where id=?"; diff --git a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowSubmitAction.java b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowSubmitAction.java index ac2f540..65e6050 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowSubmitAction.java +++ b/src/com/engine/jucailinkq/attendance/workflow/action/askforleave/BatchAskForLeaveWorkFlowSubmitAction.java @@ -11,6 +11,9 @@ import weaver.general.Util; import weaver.interfaces.workflow.action.Action; import weaver.soa.workflow.request.RequestInfo; +import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.*; import java.util.stream.Collectors; @@ -95,7 +98,7 @@ public class BatchAskForLeaveWorkFlowSubmitAction implements Action { String jqye = Util.null2String(data.get("jqye")); double sysc = Double.valueOf(data.get("sysc").toString()); double havedSysc = balanceMap.get(jqye) == null ? 0 : Double.valueOf(balanceMap.get(jqye).toString()); - sysc = Utils.add(sysc, havedSysc); + sysc = new BigDecimal(String.valueOf(sysc)).add(new BigDecimal(String.valueOf(havedSysc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); balanceMap.put(jqye, sysc); } log.info("balanceMap : [{}]",balanceMap); @@ -107,8 +110,10 @@ public class BatchAskForLeaveWorkFlowSubmitAction implements Action { double havedztsc = Util.null2String(map.get("ztsc")).equals("") ? 0 : Double.valueOf(map.get("ztsc").toString()); double havedwxsc = Util.null2String(map.get("wxsc")).equals("") ? 0 : Double.valueOf(map.get("wxsc").toString()); - double updatedztsc = Utils.add(havedztsc, ztsc); - double updatedwxsc = Utils.subtract(havedwxsc, ztsc); +// double updatedztsc = Utils.add(havedztsc, ztsc); +// double updatedwxsc = Utils.subtract(havedwxsc, ztsc); + double updatedztsc = new BigDecimal(String.valueOf(havedztsc)).add(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); + double updatedwxsc = new BigDecimal(String.valueOf(havedwxsc)).subtract(new BigDecimal(String.valueOf(ztsc)),new MathContext(5, RoundingMode.HALF_UP)).doubleValue(); String updateSql = "update uf_jcl_kq_jqye set wxsc=?,ztsc=? where id=?"; if (!DbTools.update(updateSql, updatedwxsc, updatedztsc, id)) { diff --git a/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java b/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java index 77f7d3e..728193f 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java @@ -14,6 +14,7 @@ import lombok.extern.slf4j.Slf4j; import weaver.general.TimeUtil; import weaver.general.Util; +import java.time.ZoneOffset; import java.util.*; import java.util.stream.Collectors; @@ -54,7 +55,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ Map detailItem; String sql = ""; //获取作用时段包含计划加班的加班类型的考勤项目集合 - sql = "select id,mc, bddrqlx, jbqsfzs, xzzjbsc, rzdjbxss, zzdjbxss, yzdjbxss, zysd, ccclfs,zdkcjcxxsc from uf_jcl_kq_kqxm where xmlx = ?"; + sql = "select id,mc, bddrqlx, jbqsfzs, xzzjbsc, rzdjbxss, zzdjbxss, yzdjbxss, zysd, ccclfs,zdkcjcxxsc,sfkcxxdsc from uf_jcl_kq_kqxm where xmlx = ?"; List> jblxAttendanceList = DbTools.getSqlToList(sql, AttendanceItemTypeEnum.WORK_OVERTIME.getKey()); jblxAttendanceList = jblxAttendanceList.stream().filter(f -> Util.null2String(f.get("zysd")).contains(WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey())).collect(Collectors.toList()); //获取人员id和姓名信息 @@ -95,10 +96,11 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ int overtimeMinutes = DateUtil.getBetWeenMinutes(date + " " + startTime, realEndDate + " " + endTime); detailItem.put("jbsc", String.format("%.2f", overtimeMinutes / 60.0)); //根据班次数据,设置归属日期 + Map>> bcDetailListToDateMap = new HashMap<>(); //获取当天班次id String currentDayBcId = Util.null2String(dateToBcxxMap.get(date)).split("-")[0]; //获取当天班次开始时间和结束时间 - String currentDayStartToEnd = getBcStartAndEndTime(date, currentDayBcId, workBdlxList); + String currentDayStartToEnd = getBcStartAndEndTime(date, currentDayBcId, workBdlxList, bcDetailListToDateMap); String currentDayStartTime = !"".equals(currentDayStartToEnd) ? currentDayStartToEnd.split(",")[0] : ""; String currentDayEndTime = !"".equals(currentDayStartToEnd) ? currentDayStartToEnd.split(",")[1] : ""; //判断当天班次是否为休息班次、且“休息班打卡自动加班”未勾选 @@ -107,7 +109,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ //获取前1天班次id String beforeDayBcId = Util.null2String(dateToBcxxMap.get(DateUtil.beforeDay(date, 1))).split("-")[0]; //获取前1天班次开始时间和结束时间 - String beforeDayStartToEnd = getBcStartAndEndTime(DateUtil.beforeDay(date, 1), beforeDayBcId, workBdlxList); + String beforeDayStartToEnd = getBcStartAndEndTime(DateUtil.beforeDay(date, 1), beforeDayBcId, workBdlxList, bcDetailListToDateMap); String beforeDayStartTime = !"".equals(beforeDayStartToEnd) ? beforeDayStartToEnd.split(",")[0] : ""; String beforeDayEndTime = !"".equals(beforeDayStartToEnd) ? beforeDayStartToEnd.split(",")[1] : ""; //判断前1天班次是否为休息班次、且“休息班打卡自动加班”未勾选 @@ -116,7 +118,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ //获取次日班次id String nextDayBcId = Util.null2String(dateToBcxxMap.get(DateUtil.AfterDay(date, 1))).split("-")[0]; //获取次日班次开始时间和结束时间 - String nextDayStartToEnd = getBcStartAndEndTime(DateUtil.AfterDay(date, 1), nextDayBcId, workBdlxList); + String nextDayStartToEnd = getBcStartAndEndTime(DateUtil.AfterDay(date, 1), nextDayBcId, workBdlxList, bcDetailListToDateMap); String nextDayStartTime = !"".equals(nextDayStartToEnd) ? nextDayStartToEnd.split(",")[0] : ""; String nextDayEndTime = !"".equals(nextDayStartToEnd) ? nextDayStartToEnd.split(",")[1] : ""; //判断次日班次是否为休息班次、且“休息班打卡自动加班”未勾选 @@ -133,8 +135,25 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ boolean nextDayOverLap = false; //20240820需求变更,非休息班次,加班区间完全处于休息班段内时,允许申请加班计划,并在匹配加班类型时避开勾选了去除休息时段的加班类型 boolean onlyInRestPeriod = false; + //20240924需求变更,区分“休息”、“就餐”、“休息和就餐”三类时段的时长和要求,并且对加班区间的首尾如果有不许累计时长的以上三类区间,要灵活修改加班区间的首尾时间点 + boolean onlyInDinePeriod = false; + boolean onlyInRestAndDinePeriod = false; + boolean borderHaveRest = false; + boolean allowOvertimeSign = true; + Map overtimeBorderInfo = new HashMap<>(); + overtimeBorderInfo.put("onlyInRestPeriod", false); + overtimeBorderInfo.put("onlyInDinePeriod", false); + overtimeBorderInfo.put("onlyInRestAndDinePeriod", false); + overtimeBorderInfo.put("borderHaveRest", false); + overtimeBorderInfo.put("allowOvertimeSign", true); //20240814需求变更。非休息班次,出现重叠时间,自动调整加班开始或结束时间,并返回提示 Map adjustInfo = new HashMap<>(); + adjustInfo.put("startWithAdjust", date + " " + startTime); + adjustInfo.put("endWithAdjust", realEndDate + " " + endTime); + adjustInfo.put("startDate", date); + adjustInfo.put("startTime", startTime); + adjustInfo.put("endDate", realEndDate); + adjustInfo.put("endTime", endTime); if (!"".equals(currentDayStartToEnd)) { //1-加班时间段处于前一日下班后和当日上班前 beforeToCurrentDay = ("".equals(beforeDayEndTime) || beforeDayEndTime.compareTo(date + " " + startTime) <= 0) && currentDayStartTime.compareTo(realEndDate + " " + endTime) >=0; @@ -149,10 +168,16 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ int beforeDayDiffMinutes = !"".equals(beforeDayEndTime) ? DateUtil.getBetWeenMinutes(beforeDayEndTime, date + " " + startTime) : 9999; int currentDayDiffMinutes = DateUtil.getBetWeenMinutes(realEndDate + " " + endTime, currentDayStartTime); belongDate = currentDayDiffMinutes < beforeDayDiffMinutes ? date : DateUtil.beforeDay(date, 1); + //20240924需求变更,判断加班区间是否与班次的休息或就餐班段有交集 + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + DateUtil.beforeDay(date, 1), date, null, false); } else if (currentToNextDay) { int nextDayDiffMinutes = !"".equals(nextDayStartTime) ? DateUtil.getBetWeenMinutes(realEndDate + " " + endTime, nextDayStartTime) : 9999; int currentDayDiffMinutes = DateUtil.getBetWeenMinutes(currentDayEndTime, date + " " + startTime); belongDate = currentDayDiffMinutes <= nextDayDiffMinutes ? date : DateUtil.AfterDay(date, 1); + //20240924需求变更,判断加班区间是否与班次的休息或就餐班段有交集 + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + date, DateUtil.AfterDay(date, 1), null, false); } else if (beforeToNextDay) { int beforeDayDiffMinutes = !"".equals(beforeDayEndTime) ? DateUtil.getBetWeenMinutes(beforeDayEndTime, date + " " + startTime) : 9999; int nextDayDiffMinutes = !"".equals(nextDayStartTime) ? DateUtil.getBetWeenMinutes(realEndDate + " " + endTime, nextDayStartTime) : 9999; @@ -162,58 +187,73 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ } else { belongDate = beforeDayDiffMinutes <= nextDayDiffMinutes ? DateUtil.beforeDay(date, 1) : DateUtil.AfterDay(date, 1); } + //20240924需求变更,判断加班区间是否与班次的休息或就餐班段有交集 + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + DateUtil.beforeDay(date, 1), DateUtil.AfterDay(date, 1), null, false); } else { //20240812需求变更,休息班次,允许加班计划区间和班次班段区间有重叠 currentDayOverLap = !"".equals(currentDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, currentDayStartTime, currentDayEndTime); beforeDayOverLap = !"".equals(beforeDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, beforeDayStartTime, beforeDayEndTime); nextDayOverLap = !"".equals(nextDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, nextDayStartTime, nextDayEndTime); - //20240814需求变更。非休息班次,出现重叠时间,自动调整加班开始或结束时间,并返回提示 - adjustInfo.put("startWithAdjust", date + " " + startTime); - adjustInfo.put("endWithAdjust", realEndDate + " " + endTime); - adjustInfo.put("startDate", date); - adjustInfo.put("startTime", startTime); - adjustInfo.put("endDate", realEndDate); - adjustInfo.put("endTime", endTime); - if ((!currentDayRestBc && currentDayOverLap) || (!beforeDayRestBc && beforeDayOverLap) || (!nextDayRestBc && nextDayOverLap)) { - //处理前一天 - if(!beforeDayRestBc && beforeDayOverLap) { - belongDate = DateUtil.beforeDay(date, 1); - if (overtimeOnlyInRestRange(beforeDayBcId, date + " " + startTime, realEndDate + " " + endTime, DateUtil.beforeDay(date, 1))) { - onlyInRestPeriod = true; - } else { + //20240924需求变更,区分“休息”、“就餐”、“休息和就餐”三类时段的时长和要求,并且对加班区间的首尾如果有不许累计时长的以上三类区间,要灵活修改加班区间的首尾时间点 + //处理前一天 + if (beforeDayOverLap) { + belongDate = DateUtil.beforeDay(date, 1); + if (!beforeDayRestBc) { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, false); + onlyInRestPeriod = (boolean) overtimeBorderInfo.get("onlyInRestPeriod"); + onlyInDinePeriod = (boolean) overtimeBorderInfo.get("onlyInDinePeriod"); + onlyInRestAndDinePeriod = (boolean) overtimeBorderInfo.get("onlyInRestAndDinePeriod"); + if (!onlyInRestPeriod && !onlyInDinePeriod && !onlyInRestAndDinePeriod) { adjustInfo = doAdjust(adjustInfo, beforeDayStartTime, beforeDayEndTime); } + } else { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, true); } - //处理当天 - if(!currentDayRestBc && currentDayOverLap) { - belongDate = "".equals(belongDate) ? date : belongDate; - if (overtimeOnlyInRestRange(currentDayBcId, date + " " + startTime, realEndDate + " " + endTime, date)) { - onlyInRestPeriod = true; - } else { + } + //处理当天 + if (currentDayOverLap) { + belongDate = "".equals(belongDate) ? date : belongDate; + if (!currentDayRestBc) { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, false); + onlyInRestPeriod = (boolean) overtimeBorderInfo.get("onlyInRestPeriod"); + onlyInDinePeriod = (boolean) overtimeBorderInfo.get("onlyInDinePeriod"); + onlyInRestAndDinePeriod = (boolean) overtimeBorderInfo.get("onlyInRestAndDinePeriod"); + if (!onlyInRestPeriod && !onlyInDinePeriod && !onlyInRestAndDinePeriod) { adjustInfo = doAdjust(adjustInfo, currentDayStartTime, currentDayEndTime); } + } else { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, true); } - //处理次日 - if(!nextDayRestBc && nextDayOverLap) { - belongDate = "".equals(belongDate) ? DateUtil.AfterDay(date, 1) : belongDate; - if (overtimeOnlyInRestRange(nextDayBcId, date + " " + startTime, realEndDate + " " + endTime, DateUtil.AfterDay(date, 1))) { - onlyInRestPeriod = true; - } else { + } + //处理次日 + if (nextDayOverLap) { + belongDate = "".equals(belongDate) ? DateUtil.AfterDay(date, 1) : belongDate; + if (!nextDayRestBc) { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, false); + onlyInRestPeriod = (boolean) overtimeBorderInfo.get("onlyInRestPeriod"); + onlyInDinePeriod = (boolean) overtimeBorderInfo.get("onlyInDinePeriod"); + onlyInRestAndDinePeriod = (boolean) overtimeBorderInfo.get("onlyInRestAndDinePeriod"); + if (!onlyInRestPeriod && !onlyInDinePeriod && !onlyInRestAndDinePeriod) { adjustInfo = doAdjust(adjustInfo, nextDayStartTime, nextDayEndTime); } + } else { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, date + " " + startTime, realEndDate + " " + endTime, + null, null, belongDate, true); } - //重置加班开始和结束时间、加班时长 - detailItem.put("ksrq", adjustInfo.get("startDate")); - detailItem.put("kssj", adjustInfo.get("startTime")); - detailItem.put("jssj", adjustInfo.get("endTime")); - detailItem.put("jsrq", adjustInfo.get("endDate")); - overtimeMinutes = DateUtil.getBetWeenMinutes(adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust")); - //4-非休息班次,出现重叠时间,属于不合理加班安排,返回提示”已自动调整开始和结束时间点“ - if (!onlyInRestPeriod) { - errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划区间和非休息班次班段出现时间重叠,已自动调整开始和结束时间点!"); - } - } + //以上三天处理过后,还要考虑调整过加班起始时间后的区间,处于两天之间的情况,此处仅考虑非休息班次自动调整过加班开始、结束时间后处于两班次之间的情况 + if ((beforeDayOverLap && !beforeDayRestBc) || (currentDayOverLap && !currentDayRestBc) || (nextDayOverLap && !nextDayRestBc)) { + overtimeBorderCheck(overtimeBorderInfo, bcDetailListToDateMap, adjustInfo.get("startDate") + " " + adjustInfo.get("startTime"), + adjustInfo.get("endDate") + " " + adjustInfo.get("endTime"), + belongDate, DateUtil.AfterDay(belongDate, 1), null, false); + } + overtimeMinutes = DateUtil.getBetWeenMinutes(adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust")); //5-加班区间和休息班次出现重叠,首次重叠的日期,即为归属日期;如果已有归属日,则比较当前日期和归属日谁更早 if (beforeDayRestBc && beforeDayOverLap) { belongDate = DateUtil.beforeDay(date, 1); @@ -235,13 +275,19 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ List> attendanceItemSetList = CommonUtil.getAttendanceItemsByEmpIdDate(empId, belongDate); List kqxmSetIds = attendanceItemSetList.stream().map(f->f.get("keyid").toString()).collect(Collectors.toList()); // log.info(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的可用考勤项目:" + kqxmSetIds); + onlyInRestPeriod = (boolean) overtimeBorderInfo.get("onlyInRestPeriod"); + onlyInDinePeriod = (boolean) overtimeBorderInfo.get("onlyInDinePeriod"); + onlyInRestAndDinePeriod = (boolean) overtimeBorderInfo.get("onlyInRestAndDinePeriod"); Map matchItemInfo = new HashMap<>(); for (Map attendanceItemInfo : jblxAttendanceList) { //判断该加班类型考勤项目是否被该人员使用,且考勤项目的绑定的日期类型是否包含归属日期类型 if (kqxmSetIds.contains(Util.null2String(attendanceItemInfo.get("id"))) && Util.null2String(attendanceItemInfo.get("bddrqlx")).contains(belongDateType)) { - //非休息班次,加班区间完全处于休息班段内时,在匹配加班类型时避开勾选了“是否扣除时间区间内的就餐时长”的加班类型 - if (onlyInRestPeriod && "1".equals(Util.null2String(attendanceItemInfo.get("zdkcjcxxsc")))) { + //非休息班次,加班区间完全处于“就餐”或“休息和就餐”班段内时,在匹配加班类型时避开勾选了“是否扣除时间区间内的就餐时长”的加班类型 + if ((onlyInDinePeriod || onlyInRestAndDinePeriod) && "1".equals(Util.null2String(attendanceItemInfo.get("zdkcjcxxsc")))) { + continue; + //非休息班次,加班区间完全处于“休息”或“休息和就餐”班段内时,在匹配加班类型时避开勾选了“是否扣除时间区间内的休息时长”的加班类型 + } else if ((onlyInRestPeriod || onlyInRestAndDinePeriod) && "1".equals(Util.null2String(attendanceItemInfo.get("sfkcxxdsc")))) { continue; } detailItem.put("jblx", Util.null2String(attendanceItemInfo.get("id"))); @@ -255,92 +301,107 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ log.info(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划未匹配到合适的加班类型!"); errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划未匹配到合适的加班类型!"); continue; - } else { - log.info(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划匹配到:" + Util.null2String(matchItemInfo.get("mc"))); - //20240816需求变更,根据zdkcjcxxsc字段设置,即“是否扣除时间区间内的就餐时长”需要去除重叠的休息班次中的休息时段时长 - String removeRestSc = Util.null2String(matchItemInfo.get("zdkcjcxxsc")); - int restOverLapMinutes = 0; - if (beforeDayRestBc && beforeDayOverLap && "1".equals(removeRestSc)) { - restOverLapMinutes = restOverLapMinutes - + countRestOverLapMinutes(beforeDayBcId, adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust"), DateUtil.beforeDay(date, 1)); - } else if (currentDayRestBc && currentDayOverLap && "1".equals(removeRestSc)) { - restOverLapMinutes = restOverLapMinutes - + countRestOverLapMinutes(currentDayBcId, adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust"), date); - } else if (nextDayRestBc && nextDayOverLap && "1".equals(removeRestSc)) { - restOverLapMinutes = restOverLapMinutes - + countRestOverLapMinutes(nextDayBcId, adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust"), DateUtil.AfterDay(date, 1)); - } - overtimeMinutes = overtimeMinutes - restOverLapMinutes; - detailItem.put("jbsc", String.format("%.2f", overtimeMinutes / 60.0)); - //单条明细的最小加班分钟数校验 - String minMinutes = Util.null2String(matchItemInfo.get("jbqsfzs")); - if (!"".equals(minMinutes) && Integer.parseInt(minMinutes) > overtimeMinutes) { - //最小加班分钟数大于单条明细的加班时长分钟数 - errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班分钟数小于加班类型-" - + Util.null2String(matchItemInfo.get("mc")) +"设置的最小加班分钟数!"); - continue; + } + log.info(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划匹配到:" + Util.null2String(matchItemInfo.get("mc"))); + //20240924需求变更,区分“休息”、“就餐”、“休息和就餐”三类时段的时长和要求,并且对加班区间的首尾如果有不许累计时长的以上三类区间,要灵活修改加班区间的首尾时间点 + //根据sfkcxxdsc字段设置,即“是否扣除时间区间内的休息时长”需要去除重叠的休息班次中的休息时段时长 + String removeRestSc = Util.null2String(matchItemInfo.get("sfkcxxdsc")); + //20240816需求变更,根据zdkcjcxxsc字段设置,即“是否扣除时间区间内的就餐时长”需要去除重叠的休息班次中的就餐时段时长 + String removeDineSc = Util.null2String(matchItemInfo.get("zdkcjcxxsc")); + //根据匹配的加班类型中的sfkcxxdsc字段和zdkcjcxxsc字段设置再次处理加班时长和加班区间 + List> borderOverlapBcDetails = (List>) overtimeBorderInfo.get("borderOverlapBcDetails"); + int restOverLapMinutes = 0; + if (borderOverlapBcDetails != null && borderOverlapBcDetails.size() > 0) { + restOverLapMinutes = countDineOrRestOverLapMinutes(borderOverlapBcDetails, adjustInfo, removeRestSc, removeDineSc); + } + overtimeMinutes = overtimeMinutes - restOverLapMinutes; + detailItem.put("jbsc", String.format("%.2f", overtimeMinutes / 60.0)); + //重置加班开始和结束时间、加班时长 + detailItem.put("ksrq", adjustInfo.get("startDate")); + detailItem.put("kssj", adjustInfo.get("startTime")); + detailItem.put("jssj", adjustInfo.get("endTime")); + detailItem.put("jsrq", adjustInfo.get("endDate")); + //对于不允许加班的情况,此处指非休息班次中,和非休息、就餐班段有重叠时 + allowOvertimeSign = (boolean) overtimeBorderInfo.get("allowOvertimeSign"); + if (!allowOvertimeSign) { + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班区间和工作班次的非休息/就餐班段有重叠!"); + continue; + } + //单条明细的最小加班分钟数校验 + String minMinutes = Util.null2String(matchItemInfo.get("jbqsfzs")); + if (!"".equals(minMinutes) && Integer.parseInt(minMinutes) > overtimeMinutes) { + //最小加班分钟数大于单条明细的加班时长分钟数 + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班分钟数小于加班类型-" + + Util.null2String(matchItemInfo.get("mc")) +"设置的最小加班分钟数!"); + continue; + } + String limitTotalOvertimeSc = Util.null2String(matchItemInfo.get("xzzjbsc")); + if ("1".equals(limitTotalOvertimeSc)) { + String limitWorkDayHours = Util.null2String(matchItemInfo.get("rzdjbxss")); + String limitWeekHours = Util.null2String(matchItemInfo.get("zzdjbxss")); + String limitMonthHours = Util.null2String(matchItemInfo.get("yzdjbxss")); + String limitDealType = Util.null2String(matchItemInfo.get("ccclfs")); + boolean doLimitWorkDayHours = false; + boolean doLimitWeekHours = false; + boolean doLimitMonthHours = false; + //判断是否满足工作日加班最大小时数 + boolean needCheckWorkDayHours = !"".equals(limitWorkDayHours) && (belongDateType.equals(DateTypeEnum.WORK_DAY.getKey()) || belongDateType.equals(DateTypeEnum.CHANGECLASS.getKey())); + if (needCheckWorkDayHours && Double.compare(Double.parseDouble(limitWorkDayHours), overtimeMinutes / 60.0) < 0) { + doLimitWorkDayHours = true; + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" + + Util.null2String(matchItemInfo.get("mc")) +"设置的工作日加班最大小时数!"); } - String limitTotalOvertimeSc = Util.null2String(matchItemInfo.get("xzzjbsc")); - if ("1".equals(limitTotalOvertimeSc)) { - String limitWorkDayHours = Util.null2String(matchItemInfo.get("rzdjbxss")); - String limitWeekHours = Util.null2String(matchItemInfo.get("zzdjbxss")); - String limitMonthHours = Util.null2String(matchItemInfo.get("yzdjbxss")); - String limitDealType = Util.null2String(matchItemInfo.get("ccclfs")); - boolean doLimitWorkDayHours = false; - boolean doLimitWeekHours = false; - boolean doLimitMonthHours = false; - //判断是否满足工作日加班最大小时数 - boolean needCheckWorkDayHours = !"".equals(limitWorkDayHours) && (belongDateType.equals(DateTypeEnum.WORK_DAY.getKey()) || belongDateType.equals(DateTypeEnum.CHANGECLASS.getKey())); - if (needCheckWorkDayHours && Double.compare(Double.parseDouble(limitWorkDayHours), overtimeMinutes / 60.0) < 0) { - doLimitWorkDayHours = true; + //判断是否满足周加班最大小时数 + if (!"".equals(limitWeekHours)) { + int weekRank = DateUtil.weekRank(belongDate); + double maxWeekMinutes = Double.parseDouble(limitWeekHours) *60; + double weekOvertimeMinutes; + if (weekOvertimeInfo.get(belongDate.split("-")[0] + "" + weekRank) == null) { + String countStartDate = DateUtil.beforeDay(belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-01", 6); + String countEndDate = DateUtil.AfterDay(belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-28", 9); + weekOvertimeMinutes = getWeekTimeMinutes(getWorkOverTimeResults(countStartDate, countEndDate, empId), belongDate); + } else { + weekOvertimeMinutes = weekOvertimeInfo.get(belongDate.split("-")[0] + "" + weekRank); + } + weekOvertimeInfo.put(belongDate.split("-")[0] + "" + weekRank, weekOvertimeMinutes + overtimeMinutes); + if (maxWeekMinutes - weekOvertimeMinutes - overtimeMinutes < 0) { + //达到周加班最大小时数 + doLimitWeekHours = true; errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" - + Util.null2String(matchItemInfo.get("mc")) +"设置的工作日加班最大小时数!"); + + Util.null2String(matchItemInfo.get("mc")) +"设置的周加班最大小时数!"); } - //判断是否满足周加班最大小时数 - if (!"".equals(limitWeekHours)) { - int weekRank = DateUtil.weekRank(belongDate); - double maxWeekMinutes = Double.parseDouble(limitWeekHours) *60; - double weekOvertimeMinutes; - if (weekOvertimeInfo.get(belongDate.split("-")[0] + "" + weekRank) == null) { - String countStartDate = DateUtil.beforeDay(belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-01", 6); - String countEndDate = DateUtil.AfterDay(belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-28", 9); - weekOvertimeMinutes = getWeekTimeMinutes(getWorkOverTimeResults(countStartDate, countEndDate, empId), belongDate); - } else { - weekOvertimeMinutes = weekOvertimeInfo.get(belongDate.split("-")[0] + "" + weekRank); - } - weekOvertimeInfo.put(belongDate.split("-")[0] + "" + weekRank, weekOvertimeMinutes + overtimeMinutes); - if (maxWeekMinutes - weekOvertimeMinutes - overtimeMinutes < 0) { - //达到周加班最大小时数 - doLimitWeekHours = true; - errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" - + Util.null2String(matchItemInfo.get("mc")) +"设置的周加班最大小时数!"); - } + } + //判断是否满足月加班最大小时数 + if (!"".equals(limitMonthHours)) { + String yearMonth = belongDate.substring(0, 7); + double maxMonthMinutes = Double.parseDouble(limitMonthHours) *60; + double monthOvertimeMinutes; + if (monthOvertimeInfo.get(yearMonth) == null) { + String countStartDate = belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-01"; + String countEndDate = belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-31"; + monthOvertimeMinutes = getMonthTimeMinutes(getWorkOverTimeResults(countStartDate, countEndDate, empId), belongDate); + } else { + monthOvertimeMinutes = monthOvertimeInfo.get(yearMonth); } - //判断是否满足月加班最大小时数 - if (!"".equals(limitMonthHours)) { - String yearMonth = belongDate.substring(0, 7); - double maxMonthMinutes = Double.parseDouble(limitMonthHours) *60; - double monthOvertimeMinutes; - if (monthOvertimeInfo.get(yearMonth) == null) { - String countStartDate = belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-01"; - String countEndDate = belongDate.split("-")[0]+"-"+ belongDate.split("-")[1]+"-31"; - monthOvertimeMinutes = getMonthTimeMinutes(getWorkOverTimeResults(countStartDate, countEndDate, empId), belongDate); - } else { - monthOvertimeMinutes = monthOvertimeInfo.get(yearMonth); - } - monthOvertimeInfo.put(yearMonth, monthOvertimeMinutes + overtimeMinutes); - if (maxMonthMinutes - monthOvertimeMinutes - overtimeMinutes < 0) { - //达到月加班最大小时数 - doLimitMonthHours = true; - errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" - + Util.null2String(matchItemInfo.get("mc")) +"设置的月加班最大小时数!"); - } + monthOvertimeInfo.put(yearMonth, monthOvertimeMinutes + overtimeMinutes); + if (maxMonthMinutes - monthOvertimeMinutes - overtimeMinutes < 0) { + //达到月加班最大小时数 + doLimitMonthHours = true; + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" + + Util.null2String(matchItemInfo.get("mc")) +"设置的月加班最大小时数!"); } + } // //判断是否超出工作日、周、月最大小时数要求 // if ("1".equals(limitDealType) && (doLimitWorkDayHours || doLimitWeekHours || doLimitMonthHours)) { // continue; // } - } + } + //如果实际加班时长为0,加班开始时间和结束时间置为初始值 + if (overtimeMinutes == 0) { + detailItem.put("ksrq", date); + detailItem.put("kssj", startTime); + detailItem.put("jssj", endTime); + detailItem.put("jsrq", realEndDate); } overtimePlanDetailList.add(detailItem); } @@ -377,6 +438,90 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ return Utils.removeTime(startTime, endTime, bcDetailData, date); } + /** + * 目标区间和日期所在班次中需要扣除的“就餐”、“休息”、“就餐和休息”时段重叠的分钟数 + * @param borderOverlapBcDetails + * @param adjustInfo + * @param removeRestSc + * @param removeDineSc + */ + private int countDineOrRestOverLapMinutes(List> borderOverlapBcDetails, Map adjustInfo, String removeRestSc, String removeDineSc) { + List countBdlxList = new ArrayList<>(); + if ("1".equals(removeRestSc) && "1".equals(removeDineSc)) { + countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + } else if ("1".equals(removeRestSc)) { + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + } else if ("1".equals(removeDineSc)) { + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + } else { + return 0; + } + + for (Map bcDetailItem : borderOverlapBcDetails) { + if (!countBdlxList.contains(bcDetailItem.get("bdlx").toString())) { + continue; + } + String dtkssj = Utils.getkssjTime(bcDetailItem, (String) bcDetailItem.get("bcBelongDate")); + String dtjssj = Utils.getjssjTime(bcDetailItem, (String) bcDetailItem.get("bcBelongDate")); + bcDetailItem.put("bdStartTime", dtkssj); + bcDetailItem.put("bdEndTime", dtjssj); + } + //筛选出处理过的班次明细数据,并根据开始时间排序 + List> countBcDetails = borderOverlapBcDetails.stream().filter(f -> f.get("bdStartTime") != null).collect(Collectors.toList()); + if (countBcDetails.size() == 0) { + return 0; + } + countBcDetails = countBcDetails.stream().sorted(Comparator.comparing(e->DateUtil.getTime(e.get("bdStartTime").toString()).toInstant(ZoneOffset.of("+8")).toEpochMilli())).collect(Collectors.toList()); + //合并相邻休息、就餐时段 + List> finalCountBcDetails = new ArrayList<>(); + for (Map bcDetailItem : countBcDetails) { + if (finalCountBcDetails.size() == 0) { + finalCountBcDetails.add(bcDetailItem); + continue; + } + Map finalCountItem = finalCountBcDetails.get(finalCountBcDetails.size() - 1); + if (finalCountItem.get("bdEndTime").toString().equals(bcDetailItem.get("bdStartTime").toString())) { + finalCountItem.put("bdEndTime", bcDetailItem.get("bdEndTime")); + } else { + finalCountBcDetails.add(bcDetailItem); + } + } + //累计时间,并且调整加班区间 + int countMinutes = 0; + String overtimeStartTime = adjustInfo.get("startWithAdjust"); + String overtimeEndTime = adjustInfo.get("endWithAdjust"); + String bdStartTime = ""; + String bdEndTime = ""; + for (Map bcDetailItem : finalCountBcDetails) { + if (overtimeStartTime.compareTo(overtimeEndTime) == 0) { + break; + } + bdStartTime = (String) bcDetailItem.get("bdStartTime"); + bdEndTime = (String) bcDetailItem.get("bdEndTime"); + countMinutes = countMinutes + DateUtil.getOverlappedMinutes(overtimeStartTime, overtimeEndTime, bdStartTime, bdEndTime); + //调整加班开始和结束时间 + if (overtimeStartTime.compareTo(bdStartTime) >= 0 && overtimeStartTime.compareTo(bdEndTime) < 0) { + overtimeStartTime = bdEndTime; + } + if (overtimeEndTime.compareTo(bdStartTime) > 0 && overtimeEndTime.compareTo(bdEndTime) <= 0) { + overtimeEndTime = bdStartTime; + } + if (overtimeStartTime.compareTo(overtimeEndTime) > 0) { + overtimeEndTime = overtimeStartTime; + } + } + adjustInfo.put("startWithAdjust", overtimeStartTime); + adjustInfo.put("endWithAdjust", overtimeEndTime); + adjustInfo.put("startDate", overtimeStartTime.split(" ")[0]); + adjustInfo.put("startTime", overtimeStartTime.split(" ")[1]); + adjustInfo.put("endDate", overtimeEndTime.split(" ")[0]); + adjustInfo.put("endTime", overtimeEndTime.split(" ")[1]); + + return countMinutes; + } + /** * 加班区间和非休息班次出现重叠时,自动调整加班区间的开始/结束时间 */ @@ -406,7 +551,92 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ } /** - * 判断请假区间是否完全处于班次中的休息时段内 + * 判断加班区间与班次中非工作时段的关系 + */ + private void overtimeBorderCheck(Map overtimeBorderInfo, Map>> bcDetailListToDateMap, + String startTime, String endTime, String beforeDate, String afterDate, String overlapDate, boolean overlapRestBc) { + List countBdlxList = new ArrayList<>(); + countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + List> overlapBcDetailList = new ArrayList<>(); + if (overlapDate == null) { + //如果重叠日期为null,只需判断加班区间的首尾是否和班次的非工作时段有重叠 + //处理加班区间首部的附近的班次数据 + List> beforeOvertimeBcDetailList = bcDetailListToDateMap.get(beforeDate); + if (beforeOvertimeBcDetailList != null && beforeOvertimeBcDetailList.size() > 0) { + beforeOvertimeBcDetailList = beforeOvertimeBcDetailList.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); + for (Map bcDetailItem : beforeOvertimeBcDetailList) { + int overlapMinutes = Utils.removeTime(startTime, endTime, Collections.singletonList(bcDetailItem), beforeDate); + if (overlapMinutes > 0) { + bcDetailItem.put("bcBelongDate", beforeDate); + overlapBcDetailList.add(bcDetailItem); + } + } + } + //处理加班区间尾部的附近的班次数据 + List> afterOvertimeBcDetailList = bcDetailListToDateMap.get(afterDate); + if (afterOvertimeBcDetailList != null && afterOvertimeBcDetailList.size() > 0) { + afterOvertimeBcDetailList = afterOvertimeBcDetailList.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); + for (Map bcDetailItem : afterOvertimeBcDetailList) { + int overlapMinutes = Utils.removeTime(startTime, endTime, Collections.singletonList(bcDetailItem), afterDate); + if (overlapMinutes > 0) { + bcDetailItem.put("bcBelongDate", afterDate); + overlapBcDetailList.add(bcDetailItem); + } + } + } + //处理重叠班段数据 + if (overlapBcDetailList.size() > 0) { + overtimeBorderInfo.put("borderHaveRest", true); + overtimeBorderInfo.put("borderOverlapBcDetails", overlapBcDetailList); + } + } else { + //如果重叠日期不为null,还需要区分重叠的班次是否为休息班次 + List> overlapOvertimeBcDetailList = bcDetailListToDateMap.get(overlapDate); + if (overlapOvertimeBcDetailList == null || overlapOvertimeBcDetailList.size() == 0) { + return; + } + overlapOvertimeBcDetailList = overlapOvertimeBcDetailList.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); + //处理加班区间重叠的班次数据 + for (Map bcDetailItem : overlapOvertimeBcDetailList) { + int overlapMinutes = Utils.removeTime(startTime, endTime, Collections.singletonList(bcDetailItem), overlapDate); + if (overlapMinutes > 0) { + bcDetailItem.put("bcBelongDate", overlapDate); + overlapBcDetailList.add(bcDetailItem); + } + } + if (overlapBcDetailList.size() == 0) { + return; + } + List> existOverlapBcDetailList = (List>) overtimeBorderInfo.getOrDefault("borderOverlapBcDetails", new ArrayList<>()); + existOverlapBcDetailList.addAll(overlapBcDetailList); + if (overlapRestBc) { + //休息班次时,需要判断开始或者结束是否处于班次的非工作时段 + overtimeBorderInfo.put("overlapRestBcRest", true); + overtimeBorderInfo.put("borderOverlapBcDetails", existOverlapBcDetailList); + } else { + //非休息班次时,只需判断是不是只在就餐/休息班段内加班 + int overRangeMinutes = DateUtil.getBetWeenMinutes(startTime, endTime); + if (overRangeMinutes != Utils.removeTime(startTime, endTime, overlapBcDetailList, overlapDate)) { + overtimeBorderInfo.put("allowOvertimeSign", false); + return; + } + List bdlxList = overlapBcDetailList.stream().map(e->e.get("bdlx").toString()).collect(Collectors.toList()); + if ((bdlxList.contains(ClassSegmentTypeEnum.REST_PERIOD.getKey()) && bdlxList.contains(ClassSegmentTypeEnum.DINING_PERIOD.getKey())) + || bdlxList.contains(ClassSegmentTypeEnum.REST_AND_DINE.getKey())) { + overtimeBorderInfo.put("onlyInRestAndDinePeriod", true); + } else if (bdlxList.contains(ClassSegmentTypeEnum.REST_PERIOD.getKey())) { + overtimeBorderInfo.put("onlyInRestPeriod", true); + } else if (bdlxList.contains(ClassSegmentTypeEnum.DINING_PERIOD.getKey())) { + overtimeBorderInfo.put("onlyInDinePeriod", true); + } + } + } + } + + /** + * 判断加班区间是否完全处于班次中的休息时段内 */ private boolean overtimeOnlyInRestRange(String bcId, String startTime, String endTime, String date) { int overRangeMinutes = DateUtil.getBetWeenMinutes(startTime, endTime); @@ -468,22 +698,23 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ return result; } - public String getBcStartAndEndTime(String date, String currentDayBcId, List workBdlxList) { + public String getBcStartAndEndTime(String date, String currentDayBcId, List workBdlxList, Map>> bcDetailListToDateMap) { String startToEnd = ""; if (!"".equals(currentDayBcId)) { //查询当天班次明细 - String sql = "select id, bdlx, gsrq, kssj, jssj from uf_jcl_kq_bcxx_dt1 where mainid = " + currentDayBcId + " order by gsrq desc, kssj desc"; + String sql = "select id, bdlx, gsrq, kssj as dtkssj, jssj as dtjssj from uf_jcl_kq_bcxx_dt1 where mainid = " + currentDayBcId + " order by gsrq desc, dtkssj desc"; List> bcDetailData = DbTools.getSqlToList(sql); + bcDetailListToDateMap.put(date, new ArrayList<>(bcDetailData)); bcDetailData = bcDetailData.stream().filter(e -> workBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); if (bcDetailData.size() > 0) { String endGsrqValue = Util.null2String(bcDetailData.get(0).get("gsrq")); - String lastJssj = Util.null2String(bcDetailData.get(0).get("jssj")); - String lastKssj = Util.null2String(bcDetailData.get(0).get("kssj")); + String lastJssj = Util.null2String(bcDetailData.get(0).get("dtjssj")); + String lastKssj = Util.null2String(bcDetailData.get(0).get("dtkssj")); String bdEndDate = "2".equals(endGsrqValue) ? DateUtil.AfterDay(date,1) : ("0".equals(endGsrqValue) ? DateUtil.beforeDay(date,1) : date); bdEndDate = lastKssj.compareTo(lastJssj) >= 0 ? DateUtil.AfterDay(bdEndDate,1) : bdEndDate; String startGsrqValue = Util.null2String(bcDetailData.get(bcDetailData.size() - 1).get("gsrq")); - String firstKssj = Util.null2String(bcDetailData.get(bcDetailData.size() - 1).get("kssj")); + String firstKssj = Util.null2String(bcDetailData.get(bcDetailData.size() - 1).get("dtkssj")); String bdStartDate = "2".equals(startGsrqValue) ? DateUtil.AfterDay(date,1) : ("0".equals(startGsrqValue) ? DateUtil.beforeDay(date,1) : date); startToEnd = bdStartDate + " " + firstKssj + "," + bdEndDate + " " + lastJssj; @@ -518,7 +749,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ double totalMinutes = 0; for (Map data:list){ String hsdw = data.get("hsdw").toString(); - totalMinutes += Utils.getItemduration(1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8); + totalMinutes += Utils.getItemduration(0.1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8); } return totalMinutes; } @@ -536,7 +767,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ double totalMinutes = 0; for (Map data:list){ String hsdw = data.get("hsdw").toString(); - totalMinutes += Utils.getItemduration(1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8); + totalMinutes += Utils.getItemduration(0.1,AccountingUnitEnum.MINUTES.getKey(), Double.valueOf(data.get("sjjbsc").toString()),AccountingUnitEnum.getEnum(hsdw),8); } return totalMinutes; diff --git a/src/com/engine/jucailinkq/common/cmd/GetPersonDateBySuitOrganzation.java b/src/com/engine/jucailinkq/common/cmd/GetPersonDateBySuitOrganzation.java index 1fa8383..816523b 100644 --- a/src/com/engine/jucailinkq/common/cmd/GetPersonDateBySuitOrganzation.java +++ b/src/com/engine/jucailinkq/common/cmd/GetPersonDateBySuitOrganzation.java @@ -10,6 +10,8 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import lombok.extern.slf4j.Slf4j; import weaver.general.Util; + +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; @@ -131,6 +133,9 @@ public class GetPersonDateBySuitOrganzation extends AbstractCommonCommand personGroupHolidayMap = (Map)entry.getValue(); Set userIds = personGroupUserIds.get(personGroupId); + if (userIds == null || userIds.size() == 0) { + continue; + } for (String userId :userIds){ //人力资源原本已有的假期,(假别,规则id) Map psersonSet = personMap.get(userId) == null?null:(Map)personMap.get(userId); @@ -156,6 +161,9 @@ public class GetPersonDateBySuitOrganzation extends AbstractCommonCommand departMentHolidayMap = (Map)entry.getValue(); List> userIds = hrmListGroupByDepart.get(departMentId); + if (userIds == null || userIds.size() == 0) { + continue; + } for (Map userIdMap :userIds){ //人力资源原本已有的假期,(假别,规则id) String userId = Util.null2String(userIdMap.get("id")); @@ -179,6 +187,9 @@ public class GetPersonDateBySuitOrganzation extends AbstractCommonCommand subCompanyHolidayMap = (Map)entry.getValue(); List> userIds = hrmListGroupBySubCompany.get(subCompanyId); + if (userIds == null || userIds.size() == 0) { + continue; + } for (Map userIdMap :userIds){ //人力资源原本已有的假期,(假别,规则id) String userId = Util.null2String(userIdMap.get("id")); diff --git a/src/com/engine/jucailinkq/common/util/Utils.java b/src/com/engine/jucailinkq/common/util/Utils.java index 26767fd..bb10844 100644 --- a/src/com/engine/jucailinkq/common/util/Utils.java +++ b/src/com/engine/jucailinkq/common/util/Utils.java @@ -506,20 +506,25 @@ public class Utils { */ public static int removeTimeWithOvertimePlan(String kssj,String jssj,List> overtimePlanList, Map dateToBcxxMap){ //获取作用时段包含计划加班的加班类型、并且勾选了“是否扣除时间区间内的就餐时长”的考勤项目集合 - String sql = "select id, mc, zysd, zdkcjcxxsc from uf_jcl_kq_kqxm where xmlx = ?"; + //20241008逻辑变更,区分休息、就餐时段,增加字段“是否扣除时间区间内的休息段时长” + String sql = "select id, mc, zysd, zdkcjcxxsc, sfkcxxdsc from uf_jcl_kq_kqxm where xmlx = ?"; List> jblxAttendanceList = DbTools.getSqlToList(sql, AttendanceItemTypeEnum.WORK_OVERTIME.getKey()); - List needDealJblxIdList = jblxAttendanceList.stream() +// List needDealJblxIdList = jblxAttendanceList.stream() +// .filter(f -> Util.null2String(f.get("zysd")).contains(WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey()) +// && ("1".equals(Util.null2String(f.get("zdkcjcxxsc"))) || "1".equals(Util.null2String(f.get("sfkcxxdsc"))))) +// .map(e->e.get("id").toString()) +// .collect(Collectors.toList()); + Map> needDealJblxMap = jblxAttendanceList.stream() .filter(f -> Util.null2String(f.get("zysd")).contains(WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey()) - && "1".equals(Util.null2String(f.get("zdkcjcxxsc")))) - .map(e->e.get("id").toString()) - .collect(Collectors.toList()); + && ("1".equals(Util.null2String(f.get("zdkcjcxxsc"))) || "1".equals(Util.null2String(f.get("sfkcxxdsc"))))) + .collect(Collectors.toMap(e->e.get("id").toString(), e->e)); //对加班计划数据逐条判断是否已经去除休息、就餐时长 List> newOvertimePlanList = new ArrayList<>(); if (dateToBcxxMap != null && dateToBcxxMap.size() > 0) { for (Map overtimePlanItem : overtimePlanList) { - if (needDealJblxIdList.contains(Util.null2String(overtimePlanItem.get("jblx")))) { - List> overtimePlanWithNoRest = removeRestRange(overtimePlanItem, dateToBcxxMap); + if (!"".equals(Util.null2String(overtimePlanItem.get("jblx"))) && needDealJblxMap.get(overtimePlanItem.get("jblx").toString()) != null) { + List> overtimePlanWithNoRest = removeRestRange(overtimePlanItem, dateToBcxxMap, needDealJblxMap.get(overtimePlanItem.get("jblx").toString())); if (overtimePlanWithNoRest.size() > 0) { newOvertimePlanList.addAll(overtimePlanWithNoRest); } @@ -559,17 +564,21 @@ public class Utils { /** * 去除加班计划中的休息/就餐时段,即将加班计划时段拆分为不含休息/就餐时段的多组加班计划数据 + * 20241008,需要区分就餐、休息时段 * @param overtimePlanItem 加班计划信息 * @param dateToBcxxMap 日期-班次信息映射 + * @param jblxInfo * @return */ - private static List> removeRestRange(Map overtimePlanItem, Map dateToBcxxMap) { + private static List> removeRestRange(Map overtimePlanItem, Map dateToBcxxMap, Map jblxInfo) { List> result = new ArrayList<>(); String startDate = Util.null2String(overtimePlanItem.get("ksrq")); String startTimePoint = Util.null2String(overtimePlanItem.get("kssj")); String endDate = Util.null2String(overtimePlanItem.get("jsrq")); String endTimePoint = Util.null2String(overtimePlanItem.get("jssj")); + String removeRestSc = Util.null2String(jblxInfo.get("sfkcxxdsc")); + String removeDineSc = Util.null2String(jblxInfo.get("zdkcjcxxsc")); try { //获取需要比较的班次中的休息/就餐时段 @@ -578,7 +587,7 @@ public class Utils { for (String date : dateList) { String bcId = dateToBcxxMap.getOrDefault(date, ""); bcId = "".equals(bcId) ? "" : bcId.split("-")[0]; - List> bcRestRangeInfoItem = getBcRestRangeInfo(bcId, date); + List> bcRestRangeInfoItem = getBcRestRangeInfo(bcId, date, removeRestSc, removeDineSc); if (bcRestRangeInfoItem.size() > 0) { restRangeInfo.addAll(bcRestRangeInfoItem); } @@ -602,7 +611,7 @@ public class Utils { //1-加班区间完全处于休息时段内 overtimeStart = overtimeEnd; break; - } else if (overtimeStart.compareTo(restRangeStart) < 0 && overtimeEnd.compareTo(restRangeEnd) > 0) { + } else if (overtimeStart.compareTo(restRangeStart) <= 0 && overtimeEnd.compareTo(restRangeEnd) >= 0) { //2-休息时段完全处于加班区间内 splitRangeItem = new HashMap<>(); splitRangeItem.put("startTime", overtimeStart); @@ -653,18 +662,28 @@ public class Utils { * 获取对应日期班次中的休息/就餐时段信息 * @param bcId 班次id * @param date 日期 + * @param removeRestSc + * @param removeDineSc * @return */ - private static List> getBcRestRangeInfo(String bcId, String date) { + private static List> getBcRestRangeInfo(String bcId, String date, String removeRestSc, String removeDineSc) { + List> result = new ArrayList<>(); List countBdlxList = new ArrayList<>(); - countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey()); - countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); - countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + if ("1".equals(removeRestSc) && "1".equals(removeDineSc)) { + countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + } else if ("1".equals(removeRestSc)) { + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + } else if ("1".equals(removeDineSc)) { + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + } else { + return result; + } String sql = "select id, bdlx, gsrq, kssj as dtkssj, jssj as dtjssj from uf_jcl_kq_bcxx_dt1 where mainid = " + bcId; List> bcDetailData = DbTools.getSqlToList(sql); bcDetailData = bcDetailData.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); - List> result = new ArrayList<>(); Map itemMap; for (Map bcDetailItem : bcDetailData){ String dtkssj = Utils.getkssjTime(bcDetailItem, date);