diff --git a/src/com/engine/jucailinkq/attendance/workflow/service/impl/AskForLeaveServiceImpl.java b/src/com/engine/jucailinkq/attendance/workflow/service/impl/AskForLeaveServiceImpl.java index d88ec39..f55280a 100644 --- a/src/com/engine/jucailinkq/attendance/workflow/service/impl/AskForLeaveServiceImpl.java +++ b/src/com/engine/jucailinkq/attendance/workflow/service/impl/AskForLeaveServiceImpl.java @@ -157,6 +157,11 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic String leaveType = Util.null2String(mainTableData.get("jqlx")); String leaveDuration = Util.null2String(mainTableData.get("qjsc")); String dailyRepeat = Util.null2String(mainTableData.get("mtcfsdjq")); + //假期余额使用规则,0-假别优先,1-失效日期优先,默认0 + String jqyeUsePriority = Util.null2String(mainTableData.get("yesygz")); + if ("".equals(jqyeUsePriority)) { + jqyeUsePriority = "0"; + } //获取请假日期集合 List leaveDateList = DateUtil.getDatesBetween(startDate, endDate); //已编辑内容中的假期额度使用信息 @@ -277,11 +282,37 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic // } //20241021逻辑变更,根据考勤项目的“优先使用项目”信息,获取所有可使用假期余额信息 Map>> canUseJqyeInfo = new HashMap<>(); + //20241107需求变更,获取所有可使用假期余额信息列表,并按照失效期+级联优先级排序 + List> canUseJqyeList = new ArrayList<>(); + //记录假别优先级 + int jbPriorityValue = 1; + List> canUseJqyeItem; for (Map item : holidayPriorityItemList) { - canUseJqyeInfo.put(item.get("id").toString(), collectUsableHolidayBalance(unableUseJqyeIdList, editedUseJqed, item, startDate, entry.getKey(), empIdToName.get(entry.getKey()), modeId, errorMessage)); + if (!checkAmountJqIdList.contains(item.get("id").toString())) { + continue; + } + //20241107需求变更,根据流程中设置的假期额度使用优先规则,收集假期余额数据 + canUseJqyeItem = collectUsableHolidayBalance(unableUseJqyeIdList, editedUseJqed, item, startDate, entry.getKey(), empIdToName.get(entry.getKey()), modeId, errorMessage, jbPriorityValue); + if ("0".equals(jqyeUsePriority)) { + canUseJqyeInfo.put(item.get("id").toString(), canUseJqyeItem); + } else if ("1".equals(jqyeUsePriority)) { + canUseJqyeList.addAll(canUseJqyeItem); + } + } + if (canUseJqyeList.size() > 0) { + //按照延期失效日期早+级联优先级高(优先数字小)规则排序 + canUseJqyeList.sort(Comparator.comparing((Map h) -> (String) h.get("yqsxrq")) + .thenComparing(h -> (Integer) h.get("jbPriorityValue"))); + } + + List> detailListItem = new ArrayList<>(); + if ("0".equals(jqyeUsePriority)) { + detailListItem = matchHolidayWithPriority(editedLeaveInfo, checkAmountJqIdList, errorMessage, entry.getKey(), + empIdToName.get(entry.getKey()), canUseJqyeInfo, holidayPriorityItemList, editedUseJqed, editedUseJqlxWithEmp, entry.getValue(), editedEmpLeaveInfo.get(entry.getKey())); + } else if ("1".equals(jqyeUsePriority)) { + detailListItem = matchHolidayWithDatePriority(editedLeaveInfo, checkAmountJqIdList, errorMessage, entry.getKey(), + empIdToName.get(entry.getKey()), canUseJqyeList, holidayPriorityItemList, editedUseJqed, editedUseJqlxWithEmp, entry.getValue(), editedEmpLeaveInfo.get(entry.getKey())); } - List> detailListItem = matchHolidayWithPriority(editedLeaveInfo, checkAmountJqIdList, errorMessage, entry.getKey(), - empIdToName.get(entry.getKey()), canUseJqyeInfo, holidayPriorityItemList, editedUseJqed, editedUseJqlxWithEmp, entry.getValue(), editedEmpLeaveInfo.get(entry.getKey())); if (detailListItem.size() > 0) { completeLeaveDetailList.addAll(detailListItem); } @@ -876,6 +907,7 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic jqlxEdited = editedLeaveInfo.get(empId + "_" + jqlxId + "_" + ksrq) != null; //本次请假日期范围内,已存在该请假类型开始日期相同的请假明细,则不使用该请假类型 if (jqlxEditedUseSc > 0 || jqlxEdited) { + jqlxEdited = true; continue; } leaveDuration = leaveDurationMap.get("leaveDuration"); @@ -934,6 +966,118 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic return matchResultSign ? result : new ArrayList<>(); } + + /** + * @param editedLeaveInfo 触发接口前已编辑的请假明细信息 + * @param checkAmountJqIdList 需要校验假期额度的假期类型id集合 + * @param errorMessage 错误信息记录集合 + * @param empId 请假人员id + * @param empName 请假人员姓名 + * @param canUseJqyeList 可使用的假期余额列表,且已经按照“延期失效时间”+“级联优先值”排序后的列表 + * @param editedUseJqed 触发接口前已编辑的假期额度使用信息 + * @param editedUseJqlxWithEmp 触发接口前,本次提交的日期集合中已编辑的假期类型id_人员id条件下已使用的时长 + * @param leaveDetailList 请假明细集合 + * @return 给请假明细中请假时长分配应扣的假期余额id及时长 + */ + private List> matchHolidayWithDatePriority(Map editedLeaveInfo, List checkAmountJqIdList, List errorMessage, String empId, String empName, + List> canUseJqyeList, List> holidayPriorityItemList, Map editedUseJqed, + Map editedUseJqlxWithEmp, List> leaveDetailList, List> editedLeaveInfoList) { + List> result = new ArrayList<>(); + //记录分配假期余额的结果 + boolean matchResultSign = true; + //此次遍历请假总时长 + double totalLeaveDuration = 0; + for (Map detailData : leaveDetailList) { + String qtj = Util.null2String(detailData.get("qtj")); + String btj = Util.null2String(detailData.get("btj")); + //请假时间 + double leaveDuration; + if (qtj.equals(CheckBoxEnum.CHECKED.getKey())) { + //全天默认8小时 + leaveDuration = 8; + } else if (btj.equals(CheckBoxEnum.CHECKED.getKey())) { + //半天默认4小时 + leaveDuration = 4; + } else { + leaveDuration = Double.parseDouble(Util.null2String(detailData.get("qjsc"))); + } + totalLeaveDuration = totalLeaveDuration + leaveDuration; + } + Map leaveDurationMap = new HashMap<>(); + leaveDurationMap.put("totalLeaveDuration", totalLeaveDuration); + //遍历关联请假余额id和假期类型id + for (Map detailData : leaveDetailList) { + String ksrq = Util.null2String(detailData.get("ksrq")); + String qtj = Util.null2String(detailData.get("qtj")); + String btj = Util.null2String(detailData.get("btj")); + detailData.put("qjrName", empName); + //请假时间 + double leaveDuration; + if (qtj.equals(CheckBoxEnum.CHECKED.getKey())) { + //全天默认8小时 + leaveDuration = 8; + } else if (btj.equals(CheckBoxEnum.CHECKED.getKey())) { + //半天默认4小时 + leaveDuration = 4; + } else{ + leaveDuration = Double.parseDouble(Util.null2String(detailData.get("qjsc"))); + } + //单日假期“全局唯一性”约束校验 + boolean dailyCheckSign = checkDailyLeaveLicense(empId, empName, detailData, editedLeaveInfoList, leaveDuration, errorMessage); + if (!dailyCheckSign) { + leaveDurationMap.put("totalLeaveDuration", Utils.subtract(leaveDurationMap.get("totalLeaveDuration"), leaveDuration)); + continue; + } + + log.info("leaveDuration : [{}]", leaveDuration); + leaveDurationMap.put("leaveDuration", leaveDuration); + //20241107逻辑变更,按照假期余额延长失效日期+假期项目级联优先级,(失效日期越早+优先级越高)依次分配请假时长 + Map jqlxIdToNameInfo = holidayPriorityItemList.stream().collect(Collectors.toMap(e->Util.null2String(e.get("id")),e->Util.null2String(e.get("mc")))); + dealLeaveDetailWithAllJqye(detailData, canUseJqyeList, editedUseJqed, leaveDurationMap, ksrq, result, jqlxIdToNameInfo, editedLeaveInfo, editedUseJqlxWithEmp, empId); + //额度假匹配结束,如果还有请假时长未分配,筛选出假期中非额度假的假期类型来分配请假时长 + leaveDuration = leaveDurationMap.get("leaveDuration"); + if (leaveDuration > 0) { + holidayPriorityItemList = holidayPriorityItemList.stream().filter(f -> !checkAmountJqIdList.contains(f.get("id").toString())).collect(Collectors.toList()); + if (holidayPriorityItemList.size() == 0) { + errorMessage.add(empName + "_" + ksrq + "假期余额不足!"); + matchResultSign = false; + } + boolean jqlxEdited = false; + for (Map holidayItem : holidayPriorityItemList) { + Double jqlxEditedUseSc = editedUseJqlxWithEmp.getOrDefault(holidayItem.get("id") + "_" + empId, (double) 0); + //使用的的请假项目是否已被编辑 + jqlxEdited = editedLeaveInfo.get(empId + "_" + holidayItem.get("id") + "_" + ksrq) != null; + //本次请假日期范围内,已存在该请假类型开始日期相同的请假明细,则不使用该请假类型 + if (jqlxEditedUseSc > 0 || jqlxEdited) { + jqlxEdited = true; + continue; + } + detailData.put("qjlx", holidayPriorityItemList.get(0).get("id").toString()); + detailData.put("qjlxName", jqlxIdToNameInfo.get(holidayPriorityItemList.get(0).get("id").toString())); + detailData.put("qjsc", leaveDurationMap.get("leaveDuration").toString()); + detailData.put("jqye", ""); + result.add(detailData); + leaveDuration = 0; + } + if (leaveDuration > 0) { + String message = empName; + if (jqlxEdited) { + //人员id+日期+假期类型三种条件约束唯一性 + message = message + "_" + ksrq + "本流程中已存在一笔该请假类型的请假明细!"; + } else { + //假期余额不足 + message = message + "_" + ksrq + "假期余额不足!"; + } + errorMessage.add(message); + matchResultSign = false; + } + } + + } + return matchResultSign ? result : new ArrayList<>(); + } + + private boolean checkDailyLeaveLicense(String empId, String empName, Map detailData, List> editedLeaveInfoList, double leaveDuration, List errorMessage) { //判断当前请假信息属于哪一种请假方式(全天、半天、指定时长、指定区间) @@ -1121,8 +1265,10 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic return false; } //使用的假期类型的额度单位 - String eddw = Util.null2String(holidayBalancefilterList.get(0).get("eddw")); - int multipleNum = eddw.equals(AccountingUnitEnum.DAY.getKey()) ? 8 : 1; +// String eddw = Util.null2String(holidayBalancefilterList.get(0).get("eddw")); +// int multipleNum = eddw.equals(AccountingUnitEnum.DAY.getKey()) ? 8 : 1; + String hsdw = Util.null2String(holidayBalancefilterList.get(0).get("hsdw")); + int multipleNum = hsdw.equals(AccountingUnitEnum.DAY.getKey()) ? 8 : 1; for (Map holidayBalance : holidayBalancefilterList) { //1-如果已编辑的请假明细中已有该假期余额id的记录,则满足最小使用时长;如果result的请假明细中已有该假期余额id的记录,则满足最小使用时长 boolean minLeaveDurationSign = editedUseJqed.get(holidayBalance.get("id").toString()) != null || result.stream().anyMatch(map -> itemId.equals(map.get("qjlx"))); @@ -1182,6 +1328,94 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic } + private void dealLeaveDetailWithAllJqye(Map detailData, List> canUseJqyeList, Map editedUseJqed, + Map leaveDurationMap, String ksrq, List> result, Map jqlxIdToNameInfo, + Map editedLeaveInfo, Map editedUseJqlxWithEmp, String empId) { + double totalLeaveDuration = leaveDurationMap.get("totalLeaveDuration"); + double leaveDuration = leaveDurationMap.get("leaveDuration"); + List> simpleResult = new ArrayList<>(); + //假期余额记录 + List> holidayBalancefilterList = new ArrayList<>(); + for (Map map : canUseJqyeList){ + if (DateUtil.getTime(map.get("yqsxrq").toString()).compareTo(DateUtil.getTime(ksrq)) >= 0){ + holidayBalancefilterList.add(map); + } + } + if (holidayBalancefilterList.size() == 0) { + return; + } + //使用的假期类型的额度单位 + String hsdw = Util.null2String(holidayBalancefilterList.get(0).get("hsdw")); + int multipleNum = hsdw.equals(AccountingUnitEnum.DAY.getKey()) ? 8 : 1; + boolean jqlxEdited; + for (Map holidayBalance : holidayBalancefilterList) { + String jqlxId = holidayBalance.get("jqid").toString(); + Double jqlxEditedUseSc = editedUseJqlxWithEmp.getOrDefault(jqlxId + "_" + empId, (double) 0); + //使用的的请假项目是否已被编辑 + jqlxEdited = editedLeaveInfo.get(empId + "_" + jqlxId + "_" + ksrq) != null; + //本次请假日期范围内,已存在该请假类型开始日期相同的请假明细,则不使用该请假类型 + if (jqlxEditedUseSc > 0 || jqlxEdited) { + continue; + } + //1-如果已编辑的请假明细中已有该假期余额id的记录,则满足最小使用时长;如果result的请假明细中已有该假期余额id的记录,则满足最小使用时长 + boolean minLeaveDurationSign = editedUseJqed.get(holidayBalance.get("id").toString()) != null || result.stream().anyMatch(map -> jqlxId.equals(map.get("qjlx"))); + //2-如果编辑记录中不存在,则需要判断是否满足最小使用时长 + if (!minLeaveDurationSign) { + String minLeaveDuration = Util.null2String(holidayBalance.get("minLeaveDuration")); + minLeaveDurationSign = "".equals(minLeaveDuration) || totalLeaveDuration >= Double.parseDouble(minLeaveDuration) * multipleNum; + } + //不满足最小使用时长,直接执行下一条 + if (!minLeaveDurationSign) { + continue; + } + //额定未休时长 + double wxsc = "".equals(Util.null2String(holidayBalance.get("wxsc"))) ? 0 : Double.parseDouble(holidayBalance.get("wxsc").toString()); + wxsc = multipleNum * wxsc; + if (leaveDuration > 0 && wxsc > 0) { + detailData.put("qjlx", jqlxId); + detailData.put("qjlxName", jqlxIdToNameInfo.get(jqlxId)); + + if (leaveDuration > wxsc) { + detailData.put("qjsc", String.valueOf(wxsc)); + leaveDuration = Utils.subtract(leaveDuration, wxsc); + totalLeaveDuration = Utils.subtract(totalLeaveDuration, wxsc); + detailData.put("jqye", holidayBalance.get("id").toString() + "_" + wxsc); + wxsc = 0; + simpleResult.add(new HashMap<>(detailData)); + + } else { + detailData.put("qjsc", String.valueOf(leaveDuration)); + wxsc = Utils.subtract(wxsc, leaveDuration); + //可能存在倍数转换 + wxsc = Utils.divide(wxsc, multipleNum); + totalLeaveDuration = Utils.subtract(totalLeaveDuration, leaveDuration); + detailData.put("jqye", holidayBalance.get("id").toString() + "_" + leaveDuration); + leaveDuration = 0; + simpleResult.add(detailData); + } + + holidayBalance.put("wxsc", wxsc); + } + } + //合并同一假期类型的明细 + if (simpleResult.size() > 0) { + Map>> simpleResultGroup = simpleResult.stream().collect(Collectors.groupingBy(m -> m.get("qjlx"))); + for (Map.Entry>> entry : simpleResultGroup.entrySet()) { + double qjscSum = entry.getValue().stream().mapToDouble(f->Double.parseDouble(f.get("qjsc"))).sum(); + String jqyeUseInfo = entry.getValue().stream().map(map -> map.get("jqye")).collect(Collectors.joining(",")); + Map resultItem = entry.getValue().get(0); + resultItem.put("qjsc", String.valueOf(qjscSum)); + resultItem.put("jqye", jqyeUseInfo); + result.add(resultItem); + } + } + + + leaveDurationMap.put("totalLeaveDuration", totalLeaveDuration); + leaveDurationMap.put("leaveDuration", leaveDuration); + + } + /** * 收集假期类型关联的可使用的假期余额 * @param unableUseJqyeIdList 不可使用的假期余额id集合 @@ -1189,9 +1423,10 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic * @param holidayItem 假期类型对应的考勤项目信息 * @param startDate 开始日期 * @param leaveEmpId 请假人id + * @param jbPriorityValue */ - private List> collectUsableHolidayBalance(List unableUseJqyeIdList, Map editedUseJqed, Map holidayItem, - String startDate, String leaveEmpId, String empName, String modeId, List errorMessage) { + private List> collectUsableHolidayBalance(List unableUseJqyeIdList, Map editedUseJqed, Map holidayItem, + String startDate, String leaveEmpId, String empName, String modeId, List errorMessage, int jbPriorityValue) { String itemId = Util.null2String(holidayItem.get("id")); String sql = "select id,jqid,sxrq,ktsc,yxsc,wxsc,yqsxrq,ztsc from uf_jcl_kq_jqye where ygid=? and jqid=? and sxrq<=? and yqsxrq>=? order by yqsxrq, modedatacreatedate, modedatacreatetime"; @@ -1228,6 +1463,8 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic errorMessage.add(message); return new ArrayList<>(); } + //假期的核算单位,0-天、1-小时 + String hsdw = Util.null2String(holidayItem.get("hsdw")); //假期额度的额度单位,0-天、1-小时 String eddw = Util.null2String(jqedInfo.get("eddw")); int multiple = 1; @@ -1289,6 +1526,8 @@ public class AskForLeaveServiceImpl extends Service implements AskForLeaveServic holidayBalance.put("wxsc", Utils.divide(realWxsc, multiple)); holidayBalance.put("minLeaveDuration", minLeaveDuration == null ? null : Utils.divide(minLeaveDuration, multiple)); holidayBalance.put("eddw", eddw); + holidayBalance.put("hsdw", hsdw); + holidayBalance.put("jbPriorityValue", jbPriorityValue); canUseHolidayBalanceList.add(holidayBalance); } } diff --git a/workflow/request/hrmattendance/HrmjucailAskForLeave_e9.jsp b/workflow/request/hrmattendance/HrmjucailAskForLeave_e9.jsp index 136853b..5ab40bc 100644 --- a/workflow/request/hrmattendance/HrmjucailAskForLeave_e9.jsp +++ b/workflow/request/hrmattendance/HrmjucailAskForLeave_e9.jsp @@ -18,6 +18,7 @@ kssj: WfForm.getFieldValue(WfForm.convertFieldNameToId("kssj")), jssj: WfForm.getFieldValue(WfForm.convertFieldNameToId("jssj")), cxjqj: WfForm.getFieldValue(WfForm.convertFieldNameToId("cxjqj")), + yesygz: WfForm.getFieldValue(WfForm.convertFieldNameToId("yesygz")), qjsc: WfForm.getFieldValue(WfForm.convertFieldNameToId("qjsc")) } diff --git a/workflow/request/hrmattendance/HrmjucailBatchAskForLeave_e9.jsp b/workflow/request/hrmattendance/HrmjucailBatchAskForLeave_e9.jsp index b1747ac..05a1997 100644 --- a/workflow/request/hrmattendance/HrmjucailBatchAskForLeave_e9.jsp +++ b/workflow/request/hrmattendance/HrmjucailBatchAskForLeave_e9.jsp @@ -19,6 +19,7 @@ kssj: WfForm.getFieldValue(WfForm.convertFieldNameToId("kssj")), jssj: WfForm.getFieldValue(WfForm.convertFieldNameToId("jssj")), cxjqj: WfForm.getFieldValue(WfForm.convertFieldNameToId("cxjqj")), + yesygz: WfForm.getFieldValue(WfForm.convertFieldNameToId("yesygz")), qjsc: WfForm.getFieldValue(WfForm.convertFieldNameToId("qjsc")) }