|
@@ -2,12 +2,11 @@ package com.malk.kaiyue.service.impl;
|
|
|
|
|
|
import cn.hutool.core.date.DateTime;
|
|
|
import cn.hutool.core.date.DateUtil;
|
|
|
-import cn.hutool.core.util.StrUtil;
|
|
|
-import cn.hutool.http.HttpUtil;
|
|
|
import com.malk.kaiyue.service.KYService;
|
|
|
import com.malk.server.common.McR;
|
|
|
import com.malk.server.dingtalk.DDConf;
|
|
|
import com.malk.server.dingtalk.DDR;
|
|
|
+import com.malk.server.dingtalk.DDR_New;
|
|
|
import com.malk.service.dingtalk.DDClient;
|
|
|
import com.malk.utils.UtilHttp;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
@@ -15,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
|
import java.util.*;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Slf4j
|
|
@@ -59,12 +59,16 @@ public class KYServiceImpl implements KYService {
|
|
|
return (Map)ddr.getResult();
|
|
|
}
|
|
|
|
|
|
+ //保存5s内已处理的更新假期余额事件
|
|
|
+ private Map<String, Long> bodyList = new HashMap<>();
|
|
|
|
|
|
public McR getEmployeeAnnualLeaveNum(Map<String, Object> map) {
|
|
|
//获取accessToken
|
|
|
String access_token = ddClient.getAccessToken();
|
|
|
//获取agentId
|
|
|
String agentId = ddConf.getAgentId().toString();
|
|
|
+ //获取OA管理员账号
|
|
|
+ String opUserId = ddConf.getOperator();
|
|
|
//查询接口body添加参数
|
|
|
//field_filter_list:要查询字段(花名册字段信息参考:https://open.dingtalk.com/document/orgapp/roster-custom-field-business-code)
|
|
|
//agentid:企业内部应用AgentId
|
|
@@ -110,15 +114,23 @@ public class KYServiceImpl implements KYService {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+ //假期有效开始日期为当年1月1日
|
|
|
+ DateTime beginDate = DateUtil.beginOfYear(new Date());
|
|
|
+ //假期有效截至日期为当年12月31日
|
|
|
+ DateTime endDate = DateUtil.endOfYear(new Date());
|
|
|
//工龄(年) 计算规则:首次工作时间至当年一月一日 数值向下取整
|
|
|
- int workAge =(int) (DateUtil.betweenDay(DateUtil.parse(joinWorkingTime), DateUtil.beginOfYear(new Date()), true) / 365);
|
|
|
- System.out.println(workAge + "年");
|
|
|
+ int workAge =(int) (DateUtil.betweenYear(DateUtil.parse(joinWorkingTime), beginDate, true));
|
|
|
+ if (DateUtil.dayOfYear(DateUtil.parse(joinWorkingTime)) != 1){
|
|
|
+ workAge --;
|
|
|
+ }
|
|
|
+
|
|
|
+ System.out.println("截至今年1月1日,工龄为:"+workAge + "年");
|
|
|
//法定年假
|
|
|
int legalAnnualLeave = 0;
|
|
|
//福利年假
|
|
|
int welfareAnnualLeave = 0;
|
|
|
//根据职级、工龄和合同续签数计算年假基数
|
|
|
- if (positionLevel.equals("5")){
|
|
|
+ if (positionLevel.equals("5") || positionLevel.equals("副主任医师")){
|
|
|
if (workAge < 10){
|
|
|
legalAnnualLeave = 5;
|
|
|
welfareAnnualLeave = 15;
|
|
@@ -129,35 +141,35 @@ public class KYServiceImpl implements KYService {
|
|
|
legalAnnualLeave = 15;
|
|
|
welfareAnnualLeave = 5;
|
|
|
}
|
|
|
- }else if (positionLevel.equals("4") || positionLevel.equals("3")){
|
|
|
+ }else if (positionLevel.equals("4") || positionLevel.equals("3") || positionLevel.equals("技术专员")){
|
|
|
if (workAge < 10){
|
|
|
legalAnnualLeave = 5;
|
|
|
- welfareAnnualLeave = 7 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 7 + 2 * (Math.min(contractRenewCount, 2));
|
|
|
}else if (workAge >= 10 && workAge < 20){
|
|
|
legalAnnualLeave = 10;
|
|
|
- welfareAnnualLeave = 2 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 2 + 2 * (Math.min(contractRenewCount, 2));
|
|
|
}else if (workAge >= 20){
|
|
|
legalAnnualLeave = 15;
|
|
|
welfareAnnualLeave = 1;
|
|
|
}
|
|
|
- }else if (positionLevel.equals("2")){
|
|
|
+ }else if (positionLevel.equals("2") || positionLevel.equals("高级管理员")){
|
|
|
if (workAge < 10){
|
|
|
legalAnnualLeave = 5;
|
|
|
- welfareAnnualLeave = 5 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 5 + 2 * (Math.min(contractRenewCount, 2));
|
|
|
}else if (workAge >= 10 && workAge < 20){
|
|
|
legalAnnualLeave = 10;
|
|
|
- welfareAnnualLeave = 0 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 0 + 2 * (Math.min(contractRenewCount, 2));
|
|
|
}else if (workAge >= 20){
|
|
|
legalAnnualLeave = 15;
|
|
|
welfareAnnualLeave = 0;
|
|
|
}
|
|
|
- }else if (positionLevel.equals("1")){
|
|
|
+ }else if (positionLevel.equals("1") || positionLevel.equals("技术专家")){
|
|
|
if (workAge < 10){
|
|
|
legalAnnualLeave = 5;
|
|
|
- welfareAnnualLeave = 3 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 3 + 2 * (Math.min(contractRenewCount, 2));
|
|
|
}else if (workAge >= 10 && workAge < 20){
|
|
|
legalAnnualLeave = 10;
|
|
|
- welfareAnnualLeave = 0 + 2 * contractRenewCount;
|
|
|
+ welfareAnnualLeave = 0 + 2 * (Math.min(contractRenewCount, 1));
|
|
|
}else if (workAge >= 20){
|
|
|
legalAnnualLeave = 15;
|
|
|
welfareAnnualLeave = 0;
|
|
@@ -166,10 +178,9 @@ public class KYServiceImpl implements KYService {
|
|
|
legalAnnualLeave = 0;
|
|
|
welfareAnnualLeave = 0;
|
|
|
}
|
|
|
- //开始日期为当年1月1日
|
|
|
- DateTime beginDate = DateUtil.beginOfYear(new Date());
|
|
|
- //有效日期至当年12月31日
|
|
|
- DateTime endDate = DateUtil.offsetDay(DateUtil.endOfYear(new Date()),-1);
|
|
|
+
|
|
|
+ //当年天数
|
|
|
+ int yearDays = DateUtil.dayOfYear(endDate);
|
|
|
|
|
|
result.add("姓名:"+name+",职级:"+positionLevel+",工龄:"+workAge+"年,合同续签数"+contractRenewCount+",法定年假:" + legalAnnualLeave + "天,福利年假:" + welfareAnnualLeave + "天"+",截止日期:"+endDate);
|
|
|
//年假基数
|
|
@@ -177,8 +188,8 @@ public class KYServiceImpl implements KYService {
|
|
|
double yearLeaveDecimalPart = 0;
|
|
|
//判断员工是否当年新入职
|
|
|
if (DateUtil.year(DateUtil.parse(confirmJoinTime)) == DateUtil.year(new Date())){
|
|
|
- int workDay = (int) DateUtil.betweenDay(DateUtil.parse(confirmJoinTime),endDate,true);
|
|
|
- yearLeave = workDay * yearLeave / 365.0;
|
|
|
+ int workDay = (int) DateUtil.betweenDay(DateUtil.parse(confirmJoinTime),endDate,true) + 1;
|
|
|
+ yearLeave = workDay * yearLeave / yearDays;
|
|
|
yearLeaveDecimalPart = yearLeave - (int) yearLeave;
|
|
|
if (yearLeaveDecimalPart < 0.25){
|
|
|
yearLeave = (int) yearLeave;
|
|
@@ -188,6 +199,34 @@ public class KYServiceImpl implements KYService {
|
|
|
yearLeave = (int) yearLeave + 1;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ //查询出用户消费年假记录 当返回leaveRecords中calType为null或不返回该字段则为请假消耗 将计算出的年假数减去请假消耗的数量
|
|
|
+ Map body = new HashMap();
|
|
|
+ body.put("opUserId",opUserId);
|
|
|
+ body.put("leaveCode","f9240c02-8fe7-4535-af2c-ca6740e1c654");//测试年假wzy
|
|
|
+ body.put("userIds",new String[]{userId});
|
|
|
+ body.put("pageNumber",0);
|
|
|
+ body.put("pageSize",50);
|
|
|
+ DDR_New useDdr = (DDR_New) UtilHttp.doPost("https://api.dingtalk.com/v1.0/attendance/vacations/records/query", DDConf.initTokenHeader(access_token), null, body, DDR_New.class);
|
|
|
+ Map useResult = (Map) useDdr.getResult();
|
|
|
+ List<Map> useList = (List<Map>) useResult.get("leaveRecords");
|
|
|
+ Double useLeaveNum = 0d;
|
|
|
+ for (Map use : useList) {
|
|
|
+ //判断是否为今年请假
|
|
|
+ DateTime gmtCreate = DateUtil.date((long) use.get("gmtCreate"));
|
|
|
+ if (DateUtil.year(gmtCreate) == DateUtil.year(new Date())){
|
|
|
+ //判断是否为请假消耗
|
|
|
+ if (!use.containsKey("calType") || Objects.isNull(use.get("calType"))){
|
|
|
+ //判断是否为正常请假而不是接口测试
|
|
|
+ if (!"接口测试修改".equals(use.get("leaveReason").toString())){
|
|
|
+ useLeaveNum += (int) use.get("recordNumPerDay") / 100;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //实际年假数
|
|
|
+ double realYearLeave = (yearLeave - useLeaveNum) < 0 ? 0 : (yearLeave - useLeaveNum);
|
|
|
+
|
|
|
//更新假期余额接口的body
|
|
|
Map<String,Object> updateBody = new HashMap<>();
|
|
|
Map<String,Object> leave_quotas = new HashMap<>();
|
|
@@ -198,19 +237,33 @@ public class KYServiceImpl implements KYService {
|
|
|
//操作原因
|
|
|
leave_quotas.put("reason","接口测试修改");
|
|
|
//以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
|
|
|
- leave_quotas.put("quota_num_per_day",(int) (yearLeave * 100) );
|
|
|
+ leave_quotas.put("quota_num_per_day",(int) (realYearLeave * 100) );
|
|
|
//以小时计算的额度总数 假期类型按小时,计算该值不为空且按百分之一小时折算。例如:1000=10小时。
|
|
|
leave_quotas.put("quota_num_per_hour",0);
|
|
|
//额度所对应的周期,格式必须是"yyyy",例如"2021"
|
|
|
leave_quotas.put("quota_cycle",DateUtil.year(new Date())+"");
|
|
|
//自定义添加的假期类型:年假开发测试的leave_code
|
|
|
- leave_quotas.put("leave_code","28abb7bf-e1b6-4387-9e2a-e1b2ae983e7a");
|
|
|
+ //leave_quotas.put("leave_code","28abb7bf-e1b6-4387-9e2a-e1b2ae983e7a");
|
|
|
+ leave_quotas.put("leave_code","f9240c02-8fe7-4535-af2c-ca6740e1c654");//测试
|
|
|
//要更新的员工的userId
|
|
|
leave_quotas.put("userid",userId);
|
|
|
|
|
|
updateBody.put("leave_quotas",leave_quotas);
|
|
|
- //当前企业内拥有OA审批应用权限的管理员的userId(飞超)
|
|
|
- updateBody.put("op_userid","02421908021891243060");
|
|
|
+ //当前企业内拥有OA审批应用权限的管理员的userId
|
|
|
+ updateBody.put("op_userid",opUserId);
|
|
|
+
|
|
|
+ String bodyStr = yearLeave + userId;
|
|
|
+
|
|
|
+ // 检查更新事件是否已经处理过,如果是,则忽略该更新
|
|
|
+ if (isUpdateLeave(bodyStr)) {
|
|
|
+ log.info("更新事件已处理,忽略该回调...");
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 将更新和当前时间戳添加到已处理集合中
|
|
|
+ long currentTime = System.currentTimeMillis();
|
|
|
+ bodyList.put(bodyStr, currentTime);
|
|
|
|
|
|
//更新假期余额
|
|
|
UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody, DDR.class);
|
|
@@ -219,4 +272,20 @@ public class KYServiceImpl implements KYService {
|
|
|
log.info(result.stream().collect(Collectors.joining(",")));
|
|
|
return McR.success(result);
|
|
|
}
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查该更新事件在5s内是否处理过,应对钉钉瞬间重复回调
|
|
|
+ *
|
|
|
+ * @param msg 回调事件
|
|
|
+ * @return 是否处理过
|
|
|
+ */
|
|
|
+ private boolean isUpdateLeave(String msg) {
|
|
|
+ // 清理超过10s的回调事件
|
|
|
+ long currentTime = System.currentTimeMillis();
|
|
|
+ long expirationTime = currentTime - TimeUnit.SECONDS.toMillis(5);
|
|
|
+ bodyList.entrySet().removeIf(entry -> entry.getValue() < expirationTime);
|
|
|
+
|
|
|
+ return bodyList.containsKey(msg);
|
|
|
+ }
|
|
|
+
|
|
|
}
|