diff --git a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/UtilService.java b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/UtilService.java index c148b07..b06ce6f 100644 --- a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/UtilService.java +++ b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/UtilService.java @@ -18,6 +18,8 @@ public interface UtilService { Map>> getScheduleInfoWithEmpId(List empIdList, String startDate, String endDate); + String getRqlxInScheduleInfo(String empId,String date); + /** * 获得指定天数的打卡时间集合 * 只支持一次工作时间段跨天,不支持多端工作时间段跨天。 diff --git a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java index ef958f8..882a507 100644 --- a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/AttendanceSummaryServiceImpl.java @@ -1459,7 +1459,7 @@ public class AttendanceSummaryServiceImpl extends Service implements AttendanceS String startDate = (String) forceTimeItem.get("startDate"); String endDate = (String) forceTimeItem.get("endDate"); return rq.compareTo(startDate) >= 0 && ("".equals(endDate) || rq.compareTo(endDate) <= 0); - } else if (listType.equals(PersonGroupListTypeEnum.CONDITION.getKey())) { + } else if (listType.equals(PersonGroupListTypeEnum.CONDITION.getKey()) || listType.equals(PersonGroupListTypeEnum.SQLCONDITION.getKey())) { List> forceTimeItemList = (List>) userManageInfo.get(empId); boolean forceTimeAllowSign; for (Map forceTimeItem : forceTimeItemList) { diff --git a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/UtilServiceImpl.java b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/UtilServiceImpl.java index 0396c3c..36ae2f7 100644 --- a/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/UtilServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/attendanceanalysis/service/impl/UtilServiceImpl.java @@ -66,7 +66,24 @@ public class UtilServiceImpl extends Service implements UtilService { } return scheduleInfo; } - + /** + * 获取人员在的目标日期排班结果中的日期类型 + */ + @Override + public String getRqlxInScheduleInfo(String empId,String date) { + Map params = new HashMap<>(); + params.put("tableName", "uf_pbjg"); + params.put("startDate", date); + params.put("endDate", date); + params.put("pblx", "0"); + params.put("current", "1"); + params.put("pageSize", "99"); + params.put("recurrence", "1"); + params.put("pbdx", empId); + Map schedulingResultsMap = schedulingResultsService.queryDataTableActualUse(params); + List> schedulingData = (List>) schedulingResultsMap.get("data"); + return schedulingData.size() > 0 ? Util.null2String(schedulingData.get(0).get("rqlx")) : ""; + } /** * 获得打卡数据 diff --git a/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java b/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java index 847c79e..e6f412e 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java +++ b/src/com/engine/jucailinkq/attendance/workflow/action/OvertimePlanCheckAction.java @@ -1,19 +1,26 @@ 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.workflow.service.MakeUpClockInService; import com.engine.jucailinkq.attendance.workflow.service.impl.MakeUpClockInServiceImpl; import com.engine.jucailinkq.common.util.CommonUtil; import com.engine.jucailinkq.common.util.DateUtil; import com.engine.common.util.ServiceUtil; +import com.engine.jucailinkq.common.util.DbTools; +import com.engine.jucailinkq.common.util.Utils; import com.google.common.collect.Maps; import lombok.extern.slf4j.Slf4j; +import weaver.general.TimeUtil; import weaver.general.Util; import weaver.interfaces.workflow.action.Action; import weaver.soa.workflow.request.RequestInfo; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; /** @@ -23,6 +30,7 @@ import java.util.stream.Collectors; public class OvertimePlanCheckAction implements Action { private MakeUpClockInService makeUpClockInService = ServiceUtil.getService(MakeUpClockInServiceImpl.class); + private UtilService utilService = ServiceUtil.getService(UtilServiceImpl.class); @Override public String execute(RequestInfo requestInfo) { @@ -34,15 +42,29 @@ public class OvertimePlanCheckAction implements Action { //加班人员 String jbry = mainTableData.get("jbry"); try { + //获取人员id和姓名信息 + List empIdList = Arrays.asList(jbry.split(",")); + Map empIdToNameInfo = CommonUtil.empIdToNameInfo(empIdList); + //获取作用时段包含计划加班的加班类型的考勤项目集合 + String sql = "select id,mc, bddrqlx, jbqsfzs, xzzjbsc, rzdjbxss, zzdjbxss, yzdjbxss, zysd, ccclfs from uf_jcl_kq_kqxm where xmlx = ?"; + List> jblxAttendanceList = DbTools.getSqlToList(sql, AttendanceItemTypeEnum.WORK_OVERTIME.getKey()); + 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>> detailGroupMap = detailTableData.stream().collect(Collectors.groupingBy(e->Util.null2String(e.get("jbry")))); - + List errorMessage = new ArrayList<>(); for (Map.Entry>> tableEntry :detailGroupMap.entrySet()){ List> detailGroupByUserList = tableEntry.getValue(); Map params = Maps.newHashMap(); - if ("".equals(tableEntry.getKey())){ - params.put("userId",jbry); + String empId = tableEntry.getKey(); + if ("".equals(empId)){ + log.error("明细表中存在缺少加班人员信息的数据!"); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent("明细表中存在缺少加班人员信息的数据!"); + return Action.FAILURE_AND_CONTINUE; }else { - params.put("userId",tableEntry.getKey()); + params.put("userId", empId); } params.put("submitDate",DateUtil.getCurrentDate()); params.put("submitStr","ksrq"); @@ -82,6 +104,105 @@ public class OvertimePlanCheckAction implements Action { requestInfo.getRequestManager().setMessagecontent(message); return Action.FAILURE_AND_CONTINUE; } + + //校验加班类型中最小加班分钟数、工作日最大加班小时数、周最大加班小时数、月最大加班小时数等限定值 + List> overtimeDetailList = tableEntry.getValue(); + Map matchItemInfo; + if (overtimeDetailList == null || overtimeDetailList.size() == 0) { + continue; + } + Map weekOvertimeInfo = new HashMap<>(); + Map monthOvertimeInfo = new HashMap<>(); + for (Map overtimeDetailItem : overtimeDetailList) { + String belongDate = overtimeDetailItem.get("gsrq"); + //从排班信息获取归属日日期类型 + String belongDateType = utilService.getRqlxInScheduleInfo(empId, belongDate); + //排班信息无法获取日期类型时,从日历信息获取 + belongDateType = "".equals(belongDateType) ? CommonUtil.getRqlx(empId, belongDate) : belongDateType; + //排班和日历都无法获取时,默认为工作日 + belongDateType = "".equals(belongDateType) ? DateTypeEnum.WORK_DAY.getKey() : belongDateType; + String startDate = overtimeDetailItem.get("ksrq"); + String jbsc = overtimeDetailItem.get("jbsc"); + double overtimeMinutes = Double.parseDouble(jbsc) * 60; + String jblxId = overtimeDetailItem.getOrDefault("jblx", ""); + matchItemInfo = jblxInfo.getOrDefault(jblxId, new HashMap<>()); + + String minMinutes = Util.null2String(matchItemInfo.get("jbqsfzs")); + if (!"".equals(minMinutes) && Integer.parseInt(minMinutes) > overtimeMinutes) { + //最小加班分钟数大于单条明细的加班时长分钟数 + String message = Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班分钟数小于加班类型-" + + Util.null2String(matchItemInfo.get("mc")) +"设置的最小加班分钟数!"; + log.error(message); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(message); + return Action.FAILURE_AND_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)) + "在日期" + startDate + "的加班时长累计后超过了加班类型-" + + 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)) + "在日期" + startDate + "的加班时长累计后超过了加班类型-" + + 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); + } + monthOvertimeInfo.put(yearMonth, monthOvertimeMinutes + overtimeMinutes); + if (maxMonthMinutes - monthOvertimeMinutes - overtimeMinutes < 0) { + //达到月加班最大小时数 + doLimitMonthHours = true; + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + startDate + "的加班时长累计后超过了加班类型-" + + Util.null2String(matchItemInfo.get("mc")) +"设置的月加班最大小时数!"); + } + } + //判断是否超出工作日、周、月最大小时数要求,在加班类型考勤项目中设置为“禁止提交时”,返回报错 + if ("1".equals(limitDealType) && (doLimitWorkDayHours || doLimitWeekHours || doLimitMonthHours)) { + log.error("超出加班类型工作日/周/月最大加班小时数限制!"); + requestInfo.getRequestManager().setMessageid("11111" + requestid + "22222"); + requestInfo.getRequestManager().setMessagecontent(String.valueOf(errorMessage)); + return Action.FAILURE_AND_CONTINUE; + } + } + } + } }catch (Exception e){ @@ -90,4 +211,63 @@ public class OvertimePlanCheckAction implements Action { } return Action.SUCCESS; } + + /** + * 获得一周加班分钟数 + * @param dataList + * @return + */ + public double getWeekTimeMinutes(List> dataList,String date){ + int day = TimeUtil.getDayOfWeek(date); + if (day ==0){ + day = 7; + } + String startDate = DateUtil.beforeDay(date,day-1); + String endDate = DateUtil.AfterDay(date,7-day); + List> list = dataList.stream().filter(e->{ + String sjksrq = Util.null2String(e.get("sjksrq")); + if (DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(startDate)) >=0 && + DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(endDate)) <=0 && + DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(date)) !=0){ + return true; + }else { + return false; + } + }).collect(Collectors.toList()); + + 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); + } + return totalMinutes; + } + + /** + * 获得一个月加班分钟数 + * @param dataList + * @return + */ + public double getMonthTimeMinutes(List> dataList,String date){ + String startDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-01"; + String endDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-31"; + List> list = dataList.stream().filter(e->DateUtil.getTime(e.get("sjksrq").toString()).compareTo(DateUtil.getTime(startDate))>=0 && + DateUtil.getTime(e.get("sjjsrq").toString()).compareTo(DateUtil.getTime(endDate))<=0).collect(Collectors.toList()); + 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); + } + + return totalMinutes; + } + + /** + * 获取目标人员时间区间内的加班结果 + */ + 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; + } } 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 1ec7ae6..91ce154 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/workflow/service/impl/OvertimePlanServiceImpl.java @@ -4,15 +4,14 @@ import com.engine.common.util.ServiceUtil; import com.engine.core.impl.Service; import com.engine.jucailinkq.attendance.attendanceanalysis.service.UtilService; import com.engine.jucailinkq.attendance.attendanceanalysis.service.impl.UtilServiceImpl; -import com.engine.jucailinkq.attendance.enums.AttendanceItemTypeEnum; -import com.engine.jucailinkq.attendance.enums.ClassSegmentTypeEnum; -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.OvertimePlanService; import com.engine.jucailinkq.common.util.CommonUtil; import com.engine.jucailinkq.common.util.DateUtil; import com.engine.jucailinkq.common.util.DbTools; +import com.engine.jucailinkq.common.util.Utils; import lombok.extern.slf4j.Slf4j; +import weaver.general.TimeUtil; import weaver.general.Util; import java.util.*; @@ -68,6 +67,8 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ Map dateToBcxxMap = scheduleInfoList == null ? new HashMap<>() : scheduleInfoList.stream().collect(Collectors.toMap(e->Util.null2String(e.get("bcrq")), e->Util.null2String(e.get("bcxx")))); Map dateTypeInfoFromBc = scheduleInfoList == null ? new HashMap<>() : scheduleInfoList.stream().collect(Collectors.toMap(e->Util.null2String(e.get("bcrq")), e->Util.null2String(e.get("rqlx")))); existOvertimePlanList = existOvertimePlanInfo.get(empId); + Map weekOvertimeInfo = new HashMap<>(); + Map monthOvertimeInfo = new HashMap<>(); for (String date : dateList) { String realEndDate = date; detailItem = new HashMap<>(); @@ -76,8 +77,8 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ detailItem.put("ksrq", date); detailItem.put("kssj", startTime); detailItem.put("jssj", endTime); - detailItem.put("jblx", null); - detailItem.put("jblxName", null); + detailItem.put("jblx", ""); + detailItem.put("jblxName", ""); //开始时时和结束时间存在跨天情况时,即开始时间大于等于结束时间 if (startTime.compareTo(endTime) >= 0) { realEndDate = DateUtil.AfterDay(date,1); @@ -157,23 +158,23 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ boolean currentDayOverLap = !"".equals(currentDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, currentDayStartTime, currentDayEndTime); boolean beforeDayOverLap = !"".equals(beforeDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, beforeDayStartTime, beforeDayEndTime); boolean nextDayOverLap = !"".equals(nextDayStartToEnd) && DateUtil.isOverlapping(date + " " + startTime, realEndDate + " " + endTime, nextDayStartTime, nextDayEndTime); + //20240814需求变更。非休息班次,出现重叠时间,自动调整加班开始或结束时间,并返回提示 + Map adjustInfo = new HashMap<>(); + adjustInfo.put("startWithAdjust", date + " " + startTime); + adjustInfo.put("endWithAdjust", realEndDate + " " + endTime); if ((!currentDayRestBc && currentDayOverLap) || (!beforeDayRestBc && beforeDayOverLap) || (!nextDayRestBc && nextDayOverLap)) { - //20240814需求变更。非休息班次,出现重叠时间,自动调整加班开始或结束时间,并返回提示 - Map adjustInfo = new HashMap<>(); - adjustInfo.put("startWithAdjust", date + " " + startTime); - adjustInfo.put("endWithAdjust", realEndDate + " " + endTime); //处理前一天 - if(beforeDayOverLap) { + if(!beforeDayRestBc && beforeDayOverLap) { belongDate = DateUtil.beforeDay(date, 1); adjustInfo = doAdjust(adjustInfo, beforeDayStartTime, beforeDayEndTime); } //处理当天 - if(currentDayOverLap) { + if(!currentDayRestBc && currentDayOverLap) { belongDate = "".equals(belongDate) ? date : belongDate; adjustInfo = doAdjust(adjustInfo, currentDayStartTime, currentDayEndTime); } //处理次日 - if(nextDayOverLap) { + if(!nextDayRestBc && nextDayOverLap) { belongDate = "".equals(belongDate) ? DateUtil.AfterDay(date, 1) : belongDate; adjustInfo = doAdjust(adjustInfo, nextDayStartTime, nextDayEndTime); } @@ -183,19 +184,27 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ detailItem.put("jssj", adjustInfo.get("endTime")); detailItem.put("jsrq", adjustInfo.get("endDate")); overtimeMinutes = DateUtil.getBetWeenMinutes(adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust")); - detailItem.put("jbsc", String.format("%.2f", overtimeMinutes / 60.0)); //4-非休息班次,出现重叠时间,属于不合理加班安排,返回提示”已自动调整开始和结束时间点“ errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班计划区间和非休息班次班段出现时间重叠,已自动调整开始和结束时间点!"); - - //5-加班区间和休息班次出现重叠,首次重叠的日期,即为归属日期 - } else if (beforeDayRestBc && beforeDayOverLap) { + } + //5-加班区间和休息班次出现重叠,首次重叠的日期,即为归属日期;如果已有归属日,则比较当前日期和归属日谁更早 + //20240816需求变更,需要去除重叠的休息班次中的休息时段时长 + int restOverLapMinutes = 0; + if (beforeDayRestBc && beforeDayOverLap) { belongDate = DateUtil.beforeDay(date, 1); + restOverLapMinutes = restOverLapMinutes + + countRestOverLapMinutes(beforeDayBcId, adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust"), DateUtil.beforeDay(date, 1)); } else if (currentDayRestBc && currentDayOverLap) { - belongDate = date; + belongDate = "".equals(belongDate) || date.compareTo(belongDate) < 0 ? date : belongDate; + restOverLapMinutes = restOverLapMinutes + + countRestOverLapMinutes(currentDayBcId, adjustInfo.get("startWithAdjust"), adjustInfo.get("endWithAdjust"), date); } else if (nextDayRestBc && nextDayOverLap) { - belongDate = DateUtil.AfterDay(date, 1); + belongDate = "".equals(belongDate) ? DateUtil.AfterDay(date, 1) : belongDate; + 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 belongDateType = dateTypeInfoFromBc.getOrDefault(belongDate, ""); @@ -208,6 +217,7 @@ 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); Map matchItemInfo = new HashMap<>(); for (Map attendanceItemInfo : jblxAttendanceList) { //判断该加班类型考勤项目是否被该人员使用,且考勤项目的绑定的日期类型是否包含归属日期类型 @@ -221,9 +231,11 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ detailItem.put("gsrq", belongDate); //20240814需求变更。增加单条明细的最小加班分钟数校验,工作日加班最大小时数、周加班最大小时数、月加班最大小时数 if (matchItemInfo.size() == 0) { + 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"))); String minMinutes = Util.null2String(matchItemInfo.get("jbqsfzs")); if (!"".equals(minMinutes) && Integer.parseInt(minMinutes) > overtimeMinutes) { //最小加班分钟数大于单条明细的加班时长分钟数 @@ -236,21 +248,61 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ 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) { - errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长加班类型-" + doLimitWorkDayHours = true; + errorMessage.add(Util.null2String(empIdToNameInfo.get(empId)) + "在日期" + date + "的加班时长累计后超过了加班类型-" + Util.null2String(matchItemInfo.get("mc")) +"设置的工作日加班最大小时数!"); - continue; } //判断是否满足周加班最大小时数 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); + } + 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; +// } } } overtimePlanDetailList.add(detailItem); @@ -258,12 +310,11 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ } if (errorMessage.size() == 0) { resultMap.put("status", true); - resultMap.put("data", overtimePlanDetailList); } else { resultMap.put("status", false); resultMap.put("errorInfo", errorMessage); - resultMap.put("data", null); } + resultMap.put("data", overtimePlanDetailList); } catch (Exception e) { log.info(e.getMessage()); @@ -274,6 +325,21 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ return resultMap; } + /** + * 目标区间和日期所在班次的休息时段重叠的分钟数 + */ + private int countRestOverLapMinutes(String nextDayBcId, String startTime, String endTime, String date) { + 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 = " + nextDayBcId; + List> bcDetailData = DbTools.getSqlToList(sql); + bcDetailData = bcDetailData.stream().filter(e -> countBdlxList.contains(Util.null2String(e.get("bdlx")))).collect(Collectors.toList()); + //获取需要累计的班段时长区间和目标区间存在交集的分钟数 + return Utils.removeTime(startTime, endTime, bcDetailData, date); + } + private Map doAdjust(Map adjustInfo, String bcStartTime, String bcEndTime) { String startWithAdjust = adjustInfo.get("startWithAdjust"); String endWithAdjust = adjustInfo.get("endWithAdjust"); @@ -366,4 +432,63 @@ public class OvertimePlanServiceImpl extends Service implements OvertimePlanServ } return startToEnd; } + + /** + * 获得一周加班分钟数 + * @param dataList + * @return + */ + public double getWeekTimeMinutes(List> dataList,String date){ + int day = TimeUtil.getDayOfWeek(date); + if (day ==0){ + day = 7; + } + String startDate = DateUtil.beforeDay(date,day-1); + String endDate = DateUtil.AfterDay(date,7-day); + List> list = dataList.stream().filter(e->{ + String sjksrq = Util.null2String(e.get("sjksrq")); + if (DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(startDate)) >=0 && + DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(endDate)) <=0 && + DateUtil.getTime(sjksrq).compareTo(DateUtil.getTime(date)) !=0){ + return true; + }else { + return false; + } + }).collect(Collectors.toList()); + + 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); + } + return totalMinutes; + } + + /** + * 获得一个月加班分钟数 + * @param dataList + * @return + */ + public double getMonthTimeMinutes(List> dataList,String date){ + String startDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-01"; + String endDate = date.split("-")[0]+"-"+ date.split("-")[1]+"-31"; + List> list = dataList.stream().filter(e->DateUtil.getTime(e.get("sjksrq").toString()).compareTo(DateUtil.getTime(startDate))>=0 && + DateUtil.getTime(e.get("sjjsrq").toString()).compareTo(DateUtil.getTime(endDate))<=0).collect(Collectors.toList()); + 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); + } + + return totalMinutes; + } + + /** + * 获取目标人员时间区间内的加班结果 + */ + 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; + } } diff --git a/src/com/engine/jucailinkq/common/util/CommonUtil.java b/src/com/engine/jucailinkq/common/util/CommonUtil.java index 2840068..d401aa4 100644 --- a/src/com/engine/jucailinkq/common/util/CommonUtil.java +++ b/src/com/engine/jucailinkq/common/util/CommonUtil.java @@ -591,6 +591,7 @@ public class CommonUtil { sqltj = Utils.converSQL(sqltj); log.info("getPersonnelGroupingByPerson sqltj : [{}]",sqltj); List> dataList = DbTools.getSqlToList(sqltj); + log.info("dataList_size :{}",dataList.size()); for (Map dataMap :dataList){ String hrmId = Util.null2String(dataMap.get("id")); if (empGroupUserInfo.get(hrmId) == null) { @@ -921,7 +922,7 @@ public class CommonUtil { if (dataIds.size() > 0){ sql = "select b.id keyid,b.mc kqxm,c.mc famc,b.* from uf_jcl_kq_kqfa_dt1 a left join uf_jcl_kq_kqxm b on a.kqxm=b.id left join uf_jcl_kq_kqfa c on a.mainid=c.id " + "where mainid in ("+String.join(",",dataIds)+") and (b.xmzt is null or b.xmzt <> '0') " + - "and c.zt = 0 and (c.sxrq0 is null or c.sxrq0 >= ?) and (c.sxrq1 is null or c.sxrq1 <= ?)"; + "and c.zt = 0 and (c.sxrq0 is null or c.sxrq0 <= ?) and (c.sxrq1 is null or c.sxrq1 >= ?)"; attendanceItems.addAll(DbTools.getSqlToList(sql, date, date)); } return attendanceItems; diff --git a/src/com/engine/jucailinkq/common/util/DateUtil.java b/src/com/engine/jucailinkq/common/util/DateUtil.java index 2c09721..c970f32 100644 --- a/src/com/engine/jucailinkq/common/util/DateUtil.java +++ b/src/com/engine/jucailinkq/common/util/DateUtil.java @@ -419,4 +419,16 @@ public class DateUtil { // 如果不重叠,返回0 return 0; } + + /** + * 获取日期在一年中属于第几周 + */ + public static int weekRank(String dateStr) throws Exception { + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd"); + Date date = formatter.parse(dateStr); + Calendar calendar = Calendar.getInstance(); + calendar.setTime(date); + calendar.setFirstDayOfWeek(Calendar.MONDAY);//设置星期一为一周开始的第一天 + return calendar.get(Calendar.WEEK_OF_YEAR); + } }