diff --git a/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java b/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java index 521195e..db6e128 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java +++ b/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java @@ -2,10 +2,7 @@ package com.engine.jucailinkq.attendance.workflow.action; import com.engine.jucailinkq.attendance.attendanceanalysis.service.UtilService; import com.engine.jucailinkq.attendance.attendanceanalysis.service.impl.UtilServiceImpl; -import com.engine.jucailinkq.attendance.enums.AccountingUnitEnum; -import com.engine.jucailinkq.attendance.enums.AttendanceItemTypeEnum; -import com.engine.jucailinkq.attendance.enums.DateTypeEnum; -import com.engine.jucailinkq.attendance.enums.WorkForTimeEnum; +import com.engine.jucailinkq.attendance.enums.*; import com.engine.jucailinkq.attendance.workflow.service.MakeUpClockInService; import com.engine.jucailinkq.attendance.workflow.service.impl.MakeUpClockInServiceImpl; import com.engine.jucailinkq.common.util.CommonUtil; @@ -42,6 +39,8 @@ public class OvertimePlanCheckAction implements Action { log.info("OvertimePlanCheckAction_start, detailTableData_size : {}",detailTableData.size()); //加班人员 String jbry = mainTableData.get("jbry"); + String mainStartDate = Util.null2String(mainTableData.get("ksrq")); + String mainEndDate = Util.null2String(mainTableData.get("jsrq")); try { //获取人员id和姓名信息 List empIdList = Arrays.asList(jbry.split(",")); @@ -52,6 +51,14 @@ public class OvertimePlanCheckAction implements Action { Map> jblxInfo = jblxAttendanceList.stream() .filter(f -> Util.null2String(f.get("zysd")).contains(WorkForTimeEnum.PLAN_WORK_OVERTIME.getKey())) .collect(Collectors.toMap(e->e.get("id").toString(), e->e)); + //获取目标人员列表已存在的加班计划 + Map>> existOvertimePlanInfo = getOvertimePlanInfo(empIdList, DateUtil.beforeDay(mainStartDate, 1)); + List> existOvertimePlanList = new ArrayList<>(); + //获取人员列表在日期区间的班次数据 + Map>> scheduleInfoMap = utilService.getScheduleInfoWithEmpId(empIdList, DateUtil.beforeDay(mainStartDate, 1), DateUtil.AfterDay(mainEndDate,1)); + List workBdlxList = new ArrayList<>(); + workBdlxList.add(ClassSegmentTypeEnum.WORK_TIME.getKey());workBdlxList.add(ClassSegmentTypeEnum.EXTENDED_OVERTIME.getKey()); + workBdlxList.add(ClassSegmentTypeEnum.EARLY_OVERTIME.getKey());workBdlxList.add(ClassSegmentTypeEnum.OVERTIME_IN_CLASS.getKey()); //明细数据按照人员分组 Map>> detailGroupMap = detailTableData.stream().collect(Collectors.groupingBy(e->Util.null2String(e.get("jbry")))); List errorMessage = new ArrayList<>(); @@ -70,7 +77,6 @@ public class OvertimePlanCheckAction implements Action { params.put("submitDate",DateUtil.getCurrentDate()); params.put("submitStr","ksrq"); params.put("submitDataList",detailGroupByUserList); - /** * 考勤周期校验 */ @@ -105,7 +111,11 @@ public class OvertimePlanCheckAction implements Action { requestInfo.getRequestManager().setMessagecontent(message); return Action.FAILURE_AND_CONTINUE; } - + //获取人员已存在的加班计划信息 + existOvertimePlanList = existOvertimePlanInfo.get(empId); + //获取该人员的日期与班次id的映射 + List> scheduleInfoList = scheduleInfoMap.get(empId); + Map dateToBcxxMap = scheduleInfoList == null ? new HashMap<>() : scheduleInfoList.stream().collect(Collectors.toMap(e->Util.null2String(e.get("bcrq")), e->Util.null2String(e.get("bcxx")))); //校验加班类型中最小加班分钟数、工作日最大加班小时数、周最大加班小时数、月最大加班小时数等限定值 List> overtimeDetailList = tableEntry.getValue(); Map matchItemInfo; @@ -123,11 +133,66 @@ public class OvertimePlanCheckAction implements Action { //排班和日历都无法获取时,默认为工作日 belongDateType = "".equals(belongDateType) ? DateTypeEnum.WORK_DAY.getKey() : belongDateType; String startDate = overtimeDetailItem.get("ksrq"); + String startTime = overtimeDetailItem.get("ksrq"); + String endDate = overtimeDetailItem.get("jsrq"); + String endTime = overtimeDetailItem.get("jssj"); String jbsc = overtimeDetailItem.get("jbsc"); double overtimeMinutes = Double.parseDouble(jbsc) * 60; String jblxId = overtimeDetailItem.getOrDefault("jblx", ""); matchItemInfo = jblxInfo.getOrDefault(jblxId, new HashMap<>()); - + //判断改组明细是否与已存在的加班计划有重叠 + boolean overLappingSign = checkOverlapping(existOvertimePlanList, startDate + " " +startTime, endDate + " " + endTime); + if (overLappingSign) { + String message = Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班计划区间和已申请的加班计划(已审核/待审核)出现时间重叠,不允许申请加班!"; + log.error(message); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(message); + return Action.FAILURE_AND_CONTINUE; + } + //判断是否与临近班次班段重叠,重叠班次是否为非休息班次的非休息时段 + //获取当天班次id + String currentDayBcId = Util.null2String(dateToBcxxMap.get(startDate)).split("-")[0]; + //判断当天班次是否为休息班次、且“休息班打卡自动加班”未勾选 + boolean currentDayRestBc = checkRestBc(currentDayBcId); + if (!currentDayRestBc) { + String overlapInfo = checkBcOverlap(startDate, currentDayBcId, workBdlxList, startDate + " " + startTime, endDate + " " + endTime); + if (!"".equals(overlapInfo)) { + String message = Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班计划区间" + overlapInfo; + log.error(message); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(message); + return Action.FAILURE_AND_CONTINUE; + } + } + //获取前1天班次id + String beforeDayBcId = Util.null2String(dateToBcxxMap.get(DateUtil.beforeDay(startDate, 1))).split("-")[0]; + //判断前1天班次是否为休息班次、且“休息班打卡自动加班”未勾选 + boolean beforeDayRestBc = checkRestBc(beforeDayBcId); + if (!beforeDayRestBc) { + String overlapInfo = checkBcOverlap(DateUtil.beforeDay(startDate, 1), beforeDayBcId, workBdlxList, startDate + " " + startTime, endDate + " " + endTime); + if (!"".equals(overlapInfo)) { + String message = Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班计划区间" + overlapInfo; + log.error(message); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(message); + return Action.FAILURE_AND_CONTINUE; + } + } + //获取次日班次id + String nextDayBcId = Util.null2String(dateToBcxxMap.get(DateUtil.AfterDay(startDate, 1))).split("-")[0]; + //判断次日班次是否为休息班次、且“休息班打卡自动加班”未勾选 + boolean nextDayRestBc = checkRestBc(nextDayBcId); + if (!nextDayRestBc) { + String overlapInfo = checkBcOverlap(DateUtil.AfterDay(startDate, 1), nextDayBcId, workBdlxList, startDate + " " + startTime, endDate + " " + endTime); + if (!"".equals(overlapInfo)) { + String message = Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班计划区间" + overlapInfo; + log.error(message); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(message); + return Action.FAILURE_AND_CONTINUE; + } + } + //判断是否满足最小加班分钟数 String minMinutes = Util.null2String(matchItemInfo.get("jbqsfzs")); if (!"".equals(minMinutes) && Integer.parseInt(minMinutes) > overtimeMinutes) { //最小加班分钟数大于单条明细的加班时长分钟数 @@ -267,8 +332,124 @@ public class OvertimePlanCheckAction implements Action { * 获取目标人员时间区间内的加班结果 */ public List> getWorkOverTimeResults(String startDate,String endDate,String userId){ - String sql = "select a.sjjbsc, a.sjksrq, a.sjjsrq, a.jblx, b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx = b.id where a.jbry=? and a.sjksrq>=? and a.sjjsrq<=?"; - List> dataList = DbTools.getSqlToList(sql,userId,startDate,endDate); - return dataList; + String sql = "select a.sjjbsc, a.sjksrq, a.sjjsrq, a.jbjhid, a.jblx, b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx = b.id where a.zt != 2 and a.jbry=? and a.sjksrq>=? and a.sjjsrq<=?"; + List> jbjgDataList = DbTools.getSqlToList(sql,userId,startDate,endDate); + sql = "select b.jbsc as sjjbsc, b.ksrq as sjksrq, b.jsrq as sjjsrq, a.id as jbjhid, b.jblx, c.hsdw from uf_jcl_kq_jbjh a " + + "left join uf_jcl_kq_jbjh_dt1 b on a.id = b.mainid left join uf_jcl_kq_kqxm c on b.jblx = c.id where a.jlzt != 2 and b.jbry = ? and b.ksrq >= ? and b.jsrq <= ?"; + List> jbjhDataList = DbTools.getSqlToList(sql,userId,startDate,endDate); + //去除加班计划中数据已转换为加班结果的数据 + Set jbjhIds = jbjgDataList.stream().filter(f -> !"".equals(Util.null2String(f.get("jbjhid")))).map(e->e.get("jbjhid").toString()).collect(Collectors.toSet()); + jbjhDataList = jbjhDataList.stream().filter(f -> !jbjhIds.contains(f.get("jbjhid").toString())).collect(Collectors.toList()); + if (jbjhDataList.size() > 0) { + jbjgDataList.addAll(jbjhDataList); + } + return jbjgDataList; + } + + private boolean checkOverlapping(List> existOvertimePlanList, String startTimePoint, String endTimePoint) { + boolean overlappingSign = false; + if (existOvertimePlanList != null && existOvertimePlanList.size() > 0) { + String contrastStartPoint = ""; + String contrastEndPoint = ""; + for (Map item : existOvertimePlanList) { + contrastStartPoint = item.get("ksrq") + " " + item.get("kssj"); + contrastEndPoint = item.get("jsrq") + " " + item.get("jssj"); + overlappingSign = DateUtil.isOverlapping(contrastStartPoint, contrastEndPoint, startTimePoint, endTimePoint); + if (overlappingSign) { + break; + } + } + } + return overlappingSign; + } + + /** + * 获取目标人员在加班计划表中结束日期大于等于匹配日期的数据记录 + * @param empIdList 人员id列表 + * @param matchDate 匹配日期 + * @returnd + */ + private Map>> getOvertimePlanInfo(List empIdList, String matchDate) { + Map>> result = new HashMap<>(); + if (empIdList.size() > 0 && !"".equals(matchDate)) { + String sql = "select b.id, b.jbry, b.ksrq, b.jsrq, b.kssj, b.jssj from uf_jcl_kq_jbjh a left join uf_jcl_kq_jbjh_dt1 b on b.mainid = a.id where a.jlzt != 2 and b.jsrq >= '" + + matchDate + "' and b.jbry in (" + String.join(",",empIdList) + ")"; + List> data = DbTools.getSqlToList(sql); + result = data.stream().collect(Collectors.groupingBy(e->e.get("jbry").toString())); + } + return result; + } + + private boolean checkRestBc(String bcId) { + boolean restSign = false; + if (!"".equals(bcId)) { + //查询当天班次明细 + String sql = "select id, sfxx, xxbdkzdjb from uf_jcl_kq_bcxx where id = " + bcId; + Map data = DbTools.getSqlToMap(sql); + if ("1".equals(Util.null2String(data.get("sfxx"))) && !"1".equals(Util.null2String(data.get("xxbdkzdjb")))) { + restSign = true; + } + } + return restSign; + } + + public String getBcStartAndEndTime(String date, String currentDayBcId, List workBdlxList) { + 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"; + List> bcDetailData = DbTools.getSqlToList(sql); + 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 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 bdStartDate = "2".equals(startGsrqValue) ? DateUtil.AfterDay(date,1) : ("0".equals(startGsrqValue) ? DateUtil.beforeDay(date,1) : date); + + startToEnd = bdStartDate + " " + firstKssj + "," + bdEndDate + " " + lastJssj; + } + } + return startToEnd; + } + + private String checkBcOverlap(String startDate, String currentDayBcId, List workBdlxList, String overtimePlanStart, String overtimePlanEnd) { + //获取当前日期班次开始时间和结束时间 + String currentDayStartToEnd = getBcStartAndEndTime(startDate, currentDayBcId, workBdlxList); + String currentDayStartTime = !"".equals(currentDayStartToEnd) ? currentDayStartToEnd.split(",")[0] : ""; + String currentDayEndTime = !"".equals(currentDayStartToEnd) ? currentDayStartToEnd.split(",")[1] : ""; + //如果加班计划区间和班次区间有交集 + boolean noOverlapSign = overtimePlanStart.compareTo(currentDayEndTime) >= 0 || overtimePlanEnd.compareTo(currentDayStartTime) <= 0; + if (!noOverlapSign) { + //判断交集部分是否完全属于班次的休息、就餐时段 + boolean onlyInRestPeriod = overtimeOnlyInRestRange(currentDayBcId, overtimePlanStart, overtimePlanEnd, startDate); + if (!onlyInRestPeriod) { + return "与" + startDate + "班次中的非休息、就餐时段存在交集!"; + } else { + return ""; + } + } else { + return ""; + } + } + + /** + * 判断请假区间是否完全处于班次中的休息时段内 + */ + private boolean overtimeOnlyInRestRange(String bcId, String startTime, String endTime, String date) { + int overRangeMinutes = DateUtil.getBetWeenMinutes(startTime, endTime); + List countBdlxList = new ArrayList<>(); + countBdlxList.add(ClassSegmentTypeEnum.REST_AND_DINE.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.REST_PERIOD.getKey()); + countBdlxList.add(ClassSegmentTypeEnum.DINING_PERIOD.getKey()); + 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()); + //获取需要累计的班段时长区间和目标区间存在交集的分钟数,并与请假区间内的分钟数最比较 + return overRangeMinutes == Utils.removeTime(startTime, endTime, bcDetailData, date); } } 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 395b484..77f7d3e 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java @@ -60,7 +60,7 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ //获取人员id和姓名信息 Map empIdToNameInfo = CommonUtil.empIdToNameInfo(empIdList); //获取目标人员列表已存在的加班计划 - Map>> existOvertimePlanInfo = getOvertimePlanInfo(empIdList, startDate); + Map>> existOvertimePlanInfo = getOvertimePlanInfo(empIdList, DateUtil.beforeDay(startDate, 1)); List> existOvertimePlanList = new ArrayList<>(); for (String empId : empIdList) { @@ -543,11 +543,20 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ } /** - * 获取目标人员时间区间内的加班结果 + * 获取目标人员时间区间内的加班结果,20240830需求变更,还需要考虑加班计划中数据 */ public List> getWorkOverTimeResults(String startDate,String endDate,String userId){ - String sql = "select a.sjjbsc, a.sjksrq, a.sjjsrq, a.jblx, b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx = b.id where a.jbry=? and a.sjksrq>=? and a.sjjsrq<=?"; - List> dataList = DbTools.getSqlToList(sql,userId,startDate,endDate); - return dataList; + String sql = "select a.sjjbsc, a.sjksrq, a.sjjsrq, a.jbjhid, a.jblx, b.hsdw from uf_jcl_kq_jbjg a left join uf_jcl_kq_kqxm b on a.jblx = b.id where a.zt != 2 and a.jbry=? and a.sjksrq>=? and a.sjjsrq<=?"; + List> jbjgDataList = DbTools.getSqlToList(sql,userId,startDate,endDate); + sql = "select b.jbsc as sjjbsc, b.ksrq as sjksrq, b.jsrq as sjjsrq, a.id as jbjhid, b.jblx, c.hsdw from uf_jcl_kq_jbjh a " + + "left join uf_jcl_kq_jbjh_dt1 b on a.id = b.mainid left join uf_jcl_kq_kqxm c on b.jblx = c.id where a.jlzt != 2 and b.jbry = ? and b.ksrq >= ? and b.jsrq <= ?"; + List> jbjhDataList = DbTools.getSqlToList(sql,userId,startDate,endDate); + //去除加班计划中数据已转换为加班结果的数据 + Set jbjhIds = jbjgDataList.stream().filter(f -> !"".equals(Util.null2String(f.get("jbjhid")))).map(e->e.get("jbjhid").toString()).collect(Collectors.toSet()); + jbjhDataList = jbjhDataList.stream().filter(f -> !jbjhIds.contains(f.get("jbjhid").toString())).collect(Collectors.toList()); + if (jbjhDataList.size() > 0) { + jbjgDataList.addAll(jbjhDataList); + } + return jbjgDataList; } }