Browse Source

凯悦日志记录 成都年初发放假期调整 南通绍兴发放年假调整

wzy 5 months ago
parent
commit
973efbf8bd

+ 8 - 16
mjava-kaiyue/src/main/java/com/malk/kaiyue/controller/KYCDController.java

@@ -15,6 +15,7 @@ import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 import org.springframework.web.bind.annotation.*;
 
+import java.text.ParseException;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 
@@ -75,22 +76,13 @@ public class KYCDController extends DDCallbackController {
         return McR.success(result);
     }
 
-
-    //每年1月1日 00:00定时更新员工旧职级
-    /*@Scheduled(cron = "0 0 0 1 1 ? ")
-    @GetMapping("/cronUpdateEmployeeOldPositionLevel")
-    McR cronUpdateEmployeeOldPositionLevel(){
-        System.out.println("定时更新员工旧职级开始执行"+new Date());
-        return kycdService.updateEmployeeOldPositionLevel();
-    }*/
-
-    //每年1月1日 01:00定时更新员工年假数
-    /*@Scheduled(cron = "0 0 1 1 1 ? ")
-    @GetMapping("/cronUpdateEmployeeAnnualLeaveNum")
-    McR cronUpdateEmployeeAnnualLeaveNum(){
-        System.out.println("定时更新员工年假数开始执行"+new Date());
-        return kycdService.updateEmployeeAnnualLeaveNum();
-    }*/
+    //每年1月1日 00:00定时更新员工年假数
+    @Scheduled(cron = "0 0 0 1 1 ? ")
+    @GetMapping("/grantEmployeeAnnualLeave")
+    McR grantEmployeeAnnualLeave() {
+        System.out.println("年初发放员工年假开始执行"+new Date());
+        return kycdService.grantEmployeeAnnualLeave();
+    }
 
     //保存十分钟内已处理的回调事件
     private Map<String, Long> eventList = new HashMap<>();

+ 4 - 3
mjava-kaiyue/src/main/java/com/malk/kaiyue/controller/KYNTController.java

@@ -62,16 +62,17 @@ public class KYNTController extends DDCallbackController {
     //计算并设置员工年假数
     @PostMapping("/getEmployeeAnnualLeaveNum")
     McR getEmployeeAnnualLeaveNum(@RequestBody Map<String, Object> map) {
-        return kyntService.getEmployeeAnnualLeaveNum(map);
+        kyntService.getEmployeeAnnualLeaveNum(map);
+        return McR.success();
     }
 
     //每年1月1日 01:00定时更新员工年假数
-    /*@Scheduled(cron = "0 0 1 1 1 ? ")
+    @Scheduled(cron = "0 0 1 1 1 ? ")
     @GetMapping("/cronUpdateEmployeeAnnualLeaveNum")
     McR cronUpdateEmployeeAnnualLeaveNum(){
         System.out.println("定时更新员工年假数开始执行"+new Date());
         return kyntService.updateEmployeeAnnualLeaveNum();
-    }*/
+    }
 
 
     @PostMapping("/getUserLeaveInfo")

+ 2 - 2
mjava-kaiyue/src/main/java/com/malk/kaiyue/controller/KYSXController.java

@@ -59,8 +59,8 @@ public class KYSXController extends DDCallbackController {
         return McR.success(result);
     }
 
-    //每年1月1日 01:00定时更新员工年假数
-    @Scheduled(cron = "0 0 1 1 1 ? ")
+    //每年1月1日 02:00定时更新员工年假数
+    @Scheduled(cron = "0 10 1 1 1 ? ")
     @GetMapping("/cronUpdateEmployeeAnnualLeaveNum")
     McR cronUpdateEmployeeAnnualLeaveNum(){
         System.out.println("定时更新员工年假数开始执行"+new Date());

+ 31 - 0
mjava-kaiyue/src/main/java/com/malk/kaiyue/entity/KaiyueLog.java

@@ -0,0 +1,31 @@
+package com.malk.kaiyue.entity;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+@TableName(value = "kaiyue_log")
+@Data
+public class KaiyueLog {
+    @TableId(value = "id", type = IdType.AUTO)
+    private int id;
+
+    //员工id
+    private String userId;
+
+    //信息
+    private String msg;
+
+    //更新假期状态
+    private String state;
+
+    //预支假期年份
+    private String year;
+
+    //城市
+    private String city;
+
+    //有效位 1:正常  0:删除
+    private String validFlag;
+
+}

+ 11 - 0
mjava-kaiyue/src/main/java/com/malk/kaiyue/mapper/KaiyueLogMapper.java

@@ -0,0 +1,11 @@
+package com.malk.kaiyue.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.malk.kaiyue.entity.AdvancedLeave;
+import com.malk.kaiyue.entity.KaiyueLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface KaiyueLogMapper extends BaseMapper<KaiyueLog> {
+
+}

+ 2 - 0
mjava-kaiyue/src/main/java/com/malk/kaiyue/service/KYCDService.java

@@ -5,6 +5,7 @@ import com.malk.kaiyue.entity.AdvancedLeave;
 import com.malk.server.common.McR;
 import org.springframework.scheduling.annotation.Async;
 
+import java.text.ParseException;
 import java.util.List;
 import java.util.Map;
 
@@ -36,4 +37,5 @@ public interface KYCDService extends IService<AdvancedLeave> {
      */
     Map getUserLeaveInfo(String userId);
 
+    McR grantEmployeeAnnualLeave();
 }

+ 1 - 1
mjava-kaiyue/src/main/java/com/malk/kaiyue/service/KYSXService.java

@@ -26,7 +26,7 @@ public interface KYSXService {
      * @return
      */
     @Async
-    Map getEmployeeAnnualLeaveNum(Map<String, Object> map);
+    McR getEmployeeAnnualLeaveNum(Map<String, Object> map);
 
     /**
      * 每年1月1日 01:00定时更新员工年假数

+ 571 - 221
mjava-kaiyue/src/main/java/com/malk/kaiyue/service/impl/KYCDServiceImpl.java

@@ -3,10 +3,13 @@ package com.malk.kaiyue.service.impl;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.util.NumberUtil;
+import com.alibaba.fastjson.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.malk.kaiyue.entity.AdvancedLeave;
+import com.malk.kaiyue.entity.KaiyueLog;
 import com.malk.kaiyue.mapper.AdvancedLeaveMapper;
+import com.malk.kaiyue.mapper.KaiyueLogMapper;
 import com.malk.kaiyue.service.KYCDService;
 import com.malk.server.common.McR;
 import com.malk.server.dingtalk.DDConf;
@@ -21,6 +24,8 @@ import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -36,6 +41,9 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
     @Autowired
     private AdvancedLeaveMapper advancedLeaveMapper;
 
+    @Autowired
+    private KaiyueLogMapper kaiyueLogMapper;
+
     @Value("${dingtalk_cd.appKey}")
     private String appKey;
 
@@ -58,6 +66,9 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
     //体验社-成都年假测试
 //    private static final String LEAVE_CODE = "609a84ed-54d4-4ecd-a44f-4c55b04c37ea";
 
+    //预支年假
+    private static final double ADVANCE_LEAVE = 8.0;
+
     @Override
     public List<String> getEmployeeUserId() {
         Map<String,Object> map = new HashMap<>();
@@ -118,7 +129,7 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
         //查询接口body添加参数
         //field_filter_list:要查询字段(花名册字段信息参考:https://open.dingtalk.com/document/orgapp/roster-custom-field-business-code)
         //agentid:企业内部应用AgentId
-        map.put("field_filter_list","sys00-name,sys01-positionLevel,sys00-confirmJoinTime,b433c687-c3b3-4f97-8498-d23944f3316b,80292628-1c88-4c25-9c40-3e91283552e7");
+        map.put("field_filter_list","sys00-name,sys01-positionLevel,sys00-confirmJoinTime,b433c687-c3b3-4f97-8498-d23944f3316b,80292628-1c88-4c25-9c40-3e91283552e7,sys01-employeeType");
         map.put("agentid",agentId);
 
         List<String> result = new ArrayList<>();
@@ -126,123 +137,148 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
         if (Objects.nonNull(map)){
             DDR ddr = (DDR) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list", null, DDConf.initTokenParams(access_token), map, DDR.class);
             List<Map> employeeData = (List<Map>) ddr.getResult();
-
+            String year = DateUtil.year(new Date()) + "";
             //遍历员工信息
             for (Map data : employeeData) {
                 String userId = data.get("userid").toString();
-                //入职日期
-                String confirmJoinTime = "";
-                //职级
-                String positionLevel = "";
-                //姓名
-                String name = "";
-                //原职级
-                String oldPositionLevel = "";
-                //升职日期
-                String promotionTime = "";
-
-                List<Map> fieldDataList = (List<Map>) data.get("field_data_list");
-                for (Map fieldData : fieldDataList) {
-                    String fieldCode = fieldData.get("field_code").toString();
-                    List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
-
-                    if (Objects.nonNull(fieldValueList.get(0).get("value"))){
-                        String value = fieldValueList.get(0).get("value").toString();
-                        switch (fieldCode){
-                            case "sys00-confirmJoinTime": confirmJoinTime = value;break;
-                            case "sys01-positionLevel": positionLevel = value;break;
-                            case "sys00-name": name = value;break;
-                            case "b433c687-c3b3-4f97-8498-d23944f3316b": oldPositionLevel = value;break;//成都原职级
+
+                KaiyueLog kaiyueLog = new KaiyueLog();
+                kaiyueLog.setCity("cd");
+                kaiyueLog.setUserId(userId);
+
+                kaiyueLog.setYear(year);
+
+                try{
+                    //入职日期
+                    String confirmJoinTime = "";
+                    //职级
+                    String positionLevel = "";
+                    //姓名
+                    String name = "";
+                    //原职级
+                    String oldPositionLevel = "";
+                    //升职日期
+                    String promotionTime = "";
+                    //员工类型
+                    String employeeType = "";
+
+                    List<Map> fieldDataList = (List<Map>) data.get("field_data_list");
+                    for (Map fieldData : fieldDataList) {
+                        String fieldCode = fieldData.get("field_code").toString();
+                        List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
+
+                        if (Objects.nonNull(fieldValueList.get(0).get("value"))){
+                            String value = getString(fieldValueList.get(0).get("value"));
+                            String label = getString(fieldValueList.get(0).get("label"));
+                            switch (fieldCode){
+                                case "sys00-confirmJoinTime": confirmJoinTime = value;break;
+                                case "sys01-positionLevel": positionLevel = value;break;
+                                case "sys00-name": name = value;break;
+                                case "b433c687-c3b3-4f97-8498-d23944f3316b": oldPositionLevel = value;break;//成都原职级
 //                            case "7482b192-9f1d-49fa-adab-6f33f7d0951e": oldPositionLevel = value;break;//高级假期原职级
-                            case "80292628-1c88-4c25-9c40-3e91283552e7": promotionTime = value;break;//升职日期
-                            default:break;
+                                case "80292628-1c88-4c25-9c40-3e91283552e7": promotionTime = value;break;//升职日期
+                                case "sys01-employeeType": employeeType = label;break;
+                                default:break;
+                            }
                         }
                     }
-                }
-                //若没有原职级 则默认原职级是现职级
-                if ("".equals(oldPositionLevel)){
-                    oldPositionLevel = positionLevel;
-                }
-                //若没有升职日期 则默认升职日期是入职日期
-                if ("".equals(promotionTime)){
-                    promotionTime = confirmJoinTime;
-                }
 
-                if ("".equals(confirmJoinTime) || "".equals(positionLevel) || "".equals(name) || "".equals(oldPositionLevel)){
-                    log.info("更新员工年假余额:参数缺啦!");
-                    return McR.errorParam("参数缺啦!");
-                }
+                    //若员工类型为劳务外包或实习 不发放年假
+                    if (!employeeType.equals("全职")) {
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("员工类型不为全职 不发放年假");
+                        kaiyueLogMapper.insert(kaiyueLog);
+
+                        continue;
+                    }
 
 
-                //假期有效开始日期为当年1月1日
-                DateTime beginDate = DateUtil.beginOfYear(new Date());
-                //假期有效截至日期为当年12月31日
-                DateTime endDate = DateUtil.endOfYear(new Date());
-                //今天
-                DateTime today = DateUtil.date();
-                //当年天数
-                int yearDays = DateUtil.dayOfYear(endDate);
-                //年假
-                double yearLeave = 0.0;
-                //预支年假
-                double advanceLeave = 8.0;
-
-
-                //获取原职级年假基数
-                int oldPositionLevelBaseNum = getAnnualLeaveBaseNum(oldPositionLevel);
-                //获取现职级年假基数
-                int positionLevelBaseNum = getAnnualLeaveBaseNum(positionLevel);
-
-                //获取入职日期的月日
-                String confirmJoinMonthAndDay = confirmJoinTime.substring(5);
-                String year = DateUtil.year(new Date()) + "";
-                //今年入职周年日
-                DateTime anniversaryOfEmployment = DateUtil.parse(year + "-" + confirmJoinMonthAndDay);
-
-                //计算今天是入职第几周年
-                long anniversary = DateUtil.betweenYear(DateUtil.parse(confirmJoinTime), anniversaryOfEmployment, true) - 1;
-                //判断员工是否当年新入职
-                if (DateUtil.year(DateUtil.parse(confirmJoinTime)) == DateUtil.year(new Date())){
-                    //分两段计算:入职日到升职日,升职日到年底
-                    long day1 = DateUtil.betweenDay(DateUtil.parse(confirmJoinTime), DateUtil.parse(promotionTime), true);
-                    long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endDate, true);
-                    yearLeave = (double) (day1 * oldPositionLevelBaseNum + day2 * positionLevelBaseNum ) / yearDays;
-                }else {
-                    //升职日期在今年入职周年日之前
-                    if (DateUtil.compare(anniversaryOfEmployment, DateUtil.parse(promotionTime)) >= 0){
-                        //升职日期在今年
-                        if (DateUtil.compare(DateUtil.parse(promotionTime),today) >= 0){
-                            //获取年初到升职日的天数
-                            int day1 = DateUtil.dayOfYear(DateUtil.parse(promotionTime));
-                            //获升职值日到入职周年日的天数
-                            long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), anniversaryOfEmployment, true);
-                            //获取入职周年日到年底的天数
-                            long day3 = DateUtil.betweenDay(anniversaryOfEmployment, endDate, true);
-                            //分三段计算:年初-升职日,升职日到入职周年日,入职周年日到年底
-                            yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays ;
-                        }else{
+                    //若没有原职级 则默认原职级是现职级
+                    if ("".equals(oldPositionLevel)){
+                        oldPositionLevel = positionLevel;
+                    }
+                    //若没有升职日期 则默认升职日期是入职日期
+                    if ("".equals(promotionTime)){
+                        promotionTime = confirmJoinTime;
+                    }
+
+                    if ("".equals(confirmJoinTime) || "".equals(positionLevel) || "".equals(name) || "".equals(oldPositionLevel)){
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("更新员工年假余额:参数缺啦!");
+                        kaiyueLogMapper.insert(kaiyueLog);
+                        continue;
+                    }
+
+
+                    //假期有效开始日期为当年1月1日
+                    DateTime beginDate = DateUtil.beginOfYear(new Date());
+                    //假期有效截至日期为当年12月31日
+                    DateTime endDate = DateUtil.endOfYear(new Date());
+                    //今天
+                    DateTime today = DateUtil.date();
+                    //当年天数
+                    int yearDays = DateUtil.dayOfYear(endDate);
+                    //年假
+                    double yearLeave = 0.0;
+                    //预支年假
+                    double advanceLeave = 8.0;
+
+
+                    //获取原职级年假基数
+                    int oldPositionLevelBaseNum = getAnnualLeaveBaseNum(oldPositionLevel);
+                    //获取现职级年假基数
+                    int positionLevelBaseNum = getAnnualLeaveBaseNum(positionLevel);
+
+                    //获取入职日期的月日
+                    String confirmJoinMonthAndDay = confirmJoinTime.substring(5);
+
+                    //今年入职周年日
+                    DateTime anniversaryOfEmployment = DateUtil.parse(year + "-" + confirmJoinMonthAndDay);
+
+                    //计算今天是入职第几周年
+                    long anniversary = DateUtil.betweenYear(DateUtil.parse(confirmJoinTime), anniversaryOfEmployment, true) - 1;
+                    //判断员工是否当年新入职
+                    if (DateUtil.year(DateUtil.parse(confirmJoinTime)) == DateUtil.year(new Date())){
+                        //分两段计算:入职日到升职日,升职日到年底
+                        long day1 = DateUtil.betweenDay(DateUtil.parse(confirmJoinTime), DateUtil.parse(promotionTime), true);
+                        long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endDate, true);
+                        yearLeave = (double) (day1 * oldPositionLevelBaseNum + day2 * positionLevelBaseNum ) / yearDays;
+                    }else {
+                        //升职日期在今年入职周年日之前
+                        if (DateUtil.compare(anniversaryOfEmployment, DateUtil.parse(promotionTime)) >= 0){
+                            //升职日期在今年
+                            if (DateUtil.compare(DateUtil.parse(promotionTime),today) >= 0){
+                                //获取年初到升职日的天数
+                                int day1 = DateUtil.dayOfYear(DateUtil.parse(promotionTime));
+                                //获升职值日到入职周年日的天数
+                                long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), anniversaryOfEmployment, true);
+                                //获取入职周年日到年底的天数
+                                long day3 = DateUtil.betweenDay(anniversaryOfEmployment, endDate, true);
+                                //分三段计算:年初-升职日,升职日到入职周年日,入职周年日到年底
+                                yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays ;
+                            }else{
+                                //获取年初到入职周年日的天数
+                                int day1 = DateUtil.dayOfYear(anniversaryOfEmployment);
+                                //获取入职周年日到年底的天数
+                                long day2 = DateUtil.betweenDay(anniversaryOfEmployment, endDate, true);
+                                //分两段计算:年初到入职周年日,入职周年日到年底
+                                yearLeave = (double) (day1 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays ;
+                            }
+                        }else {
+                            //升职日在今年入职周年日之后
                             //获取年初到入职周年日的天数
                             int day1 = DateUtil.dayOfYear(anniversaryOfEmployment);
-                            //获取入职周年日到年底的天数
-                            long day2 = DateUtil.betweenDay(anniversaryOfEmployment, endDate, true);
-                            //分两段计算:年初到入职周年日,入职周年日到年底
-                            yearLeave = (double) (day1 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays ;
+                            //获取入职周年日到升职日的天数
+                            long day2 = DateUtil.betweenDay(anniversaryOfEmployment, DateUtil.parse(promotionTime), true);
+                            //获取升职日到年底的天数
+                            long day3 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endDate, true);
+                            //分三段计算:年初-入职周年日,入职周年日到升职日,升职日到年底
+                            yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (oldPositionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays;
                         }
-                    }else {
-                        //升职日在今年入职周年日之后
-                        //获取年初到入职周年日的天数
-                        int day1 = DateUtil.dayOfYear(anniversaryOfEmployment);
-                        //获取入职周年日到升职日的天数
-                        long day2 = DateUtil.betweenDay(anniversaryOfEmployment, DateUtil.parse(promotionTime), true);
-                        //获取升职日到年底的天数
-                        long day3 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endDate, true);
-                        //分三段计算:年初-入职周年日,入职周年日到升职日,升职日到年底
-                        yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (oldPositionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays;
                     }
-                }
 
 
-                //年假小数
+                    //年假小数
                 /*double yearLeaveDecimalPart = yearLeave - (int) yearLeave;
                 if (yearLeaveDecimalPart < 0.25){
                     yearLeave = (int) yearLeave;
@@ -251,39 +287,40 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
                 }else if (yearLeaveDecimalPart < 1){
                     yearLeave = (int) yearLeave + 1;
                 }*/
-                yearLeave = Math.round(yearLeave * 100.0) / 100.0;
-
-                //查询出用户消费年假记录 当返回leaveRecords中calType为null或不返回该字段则为请假消耗 将计算出的年假数减去请假消耗的数量
-                Map body = new HashMap();
-                body.put("opUserId",opUserId);
-                body.put("leaveCode",LEAVE_CODE);
-                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;
-                if (Objects.nonNull(useList) && !useList.isEmpty()){
-                    for (Map use : useList) {
-                        DateTime gmtCreate = DateUtil.date((long) use.get("gmtCreate"));
-                        //获取今年请假记录
-                        if (DateUtil.year(gmtCreate) == DateUtil.year(new Date())){
-                            //判断是否为正常请假而不是接口测试或期初假期发放
-                            if (!"接口测试修改".equals(use.get("leaveReason").toString()) && !"期初假期发放".equals(use.get("leaveReason").toString())){
-                                //若是请假消耗或管理员手动减少
-                                if (!use.containsKey("calType") || Objects.isNull(use.get("calType")) || "delete".equals(use.get("calType").toString())){
-                                    useLeaveNum += (int) use.get("recordNumPerDay") / 100;
+                    yearLeave = Math.round(yearLeave * 100.0) / 100.0;
+
+                    //查询出用户消费年假记录 当返回leaveRecords中calType为null或不返回该字段则为请假消耗 将计算出的年假数减去请假消耗的数量
+                    Map body = new HashMap();
+                    body.put("opUserId",opUserId);
+                    body.put("leaveCode",LEAVE_CODE);
+                    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;
+                    if (Objects.nonNull(useList) && !useList.isEmpty()){
+                        for (Map use : useList) {
+                            DateTime gmtCreate = DateUtil.date((long) use.get("gmtCreate"));
+                            //获取今年请假记录
+                            if (DateUtil.year(gmtCreate) == DateUtil.year(new Date())){
+                                //判断是否为正常请假而不是接口测试或期初假期发放
+                                String leaveReason = getString(use.get("leaveReason"));
+                                if (Arrays.asList("期初年假发放","去年预支扣除","去年预支假清空").contains(leaveReason)){
+                                    //若是请假消耗或管理员手动减少
+                                    if (!use.containsKey("calType") || Objects.isNull(use.get("calType")) || "delete".equals(use.get("calType").toString())){
+                                        useLeaveNum += ((int) use.get("recordNumPerDay"))/100.0;
+                                    }
+                                    //注:若是管理员手动增加 则假期余额会多出一个BCXsunNm记录增加的假期天数  最终会在设置的假期余额的基础上加上这些天数
+                                    //故此处手动新增的假期余额不做处理
                                 }
-                                //注:若是管理员手动增加 则假期余额会多出一个BCXsunNm记录增加的假期天数  最终会在设置的假期余额的基础上加上这些天数
-                                //故此处手动新增的假期余额不做处理
                             }
                         }
                     }
-                }
 
 
-                //年假余额
+                /*//年假余额
                 BigDecimal annualLeaveNum = new BigDecimal(0.00);
 
                 //查询员工年假余额
@@ -303,69 +340,34 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
                             }
                         }
                     }
-                }
+                }*/
 
-                LambdaQueryWrapper<AdvancedLeave> advancedLeaveLambdaQueryWrapper = new LambdaQueryWrapper<>();;
-                advancedLeaveLambdaQueryWrapper.eq(AdvancedLeave::getUserId,userId)
-                        .eq(AdvancedLeave::getYear,year)
-                        .eq(AdvancedLeave::getValidFlag,"1")
-                        .eq(AdvancedLeave::getCity,"cd");
-                AdvancedLeave advancedLeave = advancedLeaveMapper.selectOne(advancedLeaveLambdaQueryWrapper);
-
-                if (Objects.nonNull(advancedLeave)){
-                    advanceLeave = Double.valueOf(advancedLeave.getLeaveNum());
-                }else {
-                    advancedLeave = new AdvancedLeave();
-
-                    //1月1日 则根据年假余额计算当年预支假
-                    if (DateUtil.beginOfYear(new Date()).equals(today)){
-                        //年假余额小于8时
-                        if (annualLeaveNum.compareTo(new BigDecimal(8)) < 0){
-                            advanceLeave = Double.parseDouble(annualLeaveNum.subtract(annualLeaveNum.remainder(new BigDecimal(0.5))).toString());
-                        }
+                    LambdaQueryWrapper<AdvancedLeave> advancedLeaveLambdaQueryWrapper = new LambdaQueryWrapper<>();;
+                    advancedLeaveLambdaQueryWrapper.eq(AdvancedLeave::getUserId,userId)
+                            .eq(AdvancedLeave::getYear,year)
+                            .eq(AdvancedLeave::getValidFlag,"1")
+                            .eq(AdvancedLeave::getCity,"cd");
+                    AdvancedLeave advancedLeave = advancedLeaveMapper.selectOne(advancedLeaveLambdaQueryWrapper);
 
-                        advancedLeave.setLeaveNum(advanceLeave + "");
-                        advancedLeave.setUserId(userId);
-                        advancedLeave.setYear(String.valueOf(DateUtil.year(new Date())));
-                        advancedLeave.setCity("hq");
-                        advancedLeaveMapper.insert(advancedLeave);
+                    if (Objects.nonNull(advancedLeave)){
+                        advanceLeave = Double.valueOf(advancedLeave.getLeaveNum());
                     }else {
-                        //若当天不是1月1日且表中没有预支假记录 则默认预支假为8天
+                        advancedLeave = new AdvancedLeave();
                         advancedLeave.setLeaveNum(advanceLeave + "");
                         advancedLeave.setUserId(userId);
-                        advancedLeave.setYear(String.valueOf(DateUtil.year(new Date())));
+                        advancedLeave.setYear(year);
                         advancedLeave.setCity("cd");
                         advancedLeaveMapper.insert(advancedLeave);
                     }
-                }
 
-                /*LambdaQueryWrapper<AdvancedLeave> advancedLeaveLambdaQueryWrapper = new LambdaQueryWrapper<>();;
-                advancedLeaveLambdaQueryWrapper.eq(AdvancedLeave::getUserId,userId)
-                        .eq(AdvancedLeave::getCity,"cd")
-                        .eq(AdvancedLeave::getValidFlag,"1");
-                AdvancedLeave advancedLeave = advancedLeaveMapper.selectOne(advancedLeaveLambdaQueryWrapper);
-                if (Objects.nonNull(advancedLeave)){
-                    advanceLeave = Double.valueOf(advancedLeave.getLeaveNum());
-                }else {
-                    advanceLeave = NumberUtil.sub(yearLeave - useLeaveNum).doubleValue() >= 8 ? 8 : NumberUtil.sub(yearLeave - useLeaveNum).intValue();
-                    advancedLeave = new AdvancedLeave();
-                    advancedLeave.setLeaveNum(advanceLeave + "");
-                    advancedLeave.setUserId(userId);
-                    advancedLeave.setYear(String.valueOf(DateUtil.year(new Date())));
-                    advancedLeave.setCity("cd");
-                    advancedLeaveMapper.insert(advancedLeave);
-                }*/
-
-
-                //年假总数
-                int realYearLeave =  NumberUtil.sub(yearLeave, useLeaveNum, -advanceLeave).doubleValue() < 0 ? 0 : NumberUtil.sub(yearLeave, useLeaveNum, -advanceLeave).multiply(new BigDecimal(100)).intValue();
+                    //年假总数
+                    int realYearLeave =  NumberUtil.sub(yearLeave, useLeaveNum, -advanceLeave).doubleValue() < 0 ? 0 : NumberUtil.sub(yearLeave, useLeaveNum, -advanceLeave).multiply(new BigDecimal(100)).intValue();
 
 
-
-                //获取员工原年假余额 取较大值
-                if (annualLeaveNum.multiply(new BigDecimal(100)).intValue() > realYearLeave){
+                    //获取员工原年假余额 取较大值
+                /*if (annualLeaveNum.multiply(new BigDecimal(100)).intValue() > realYearLeave){
                     realYearLeave = annualLeaveNum.multiply(new BigDecimal(100)).intValue();
-                }
+                }*/
                 /*Map balanceMap = new HashMap();
                 balanceMap.put("leave_code",LEAVE_CODE);
                 balanceMap.put("op_userid",opUserId);
@@ -387,51 +389,63 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
                 }*/
 
 
-                //更新假期余额接口的body
-                DateTime deadline = DateUtil.parse((DateUtil.year(new Date()) + 1) + "-03-31");
-                Map<String,Object> updateBody = new HashMap<>();
-                Map<String,Object> leave_quotas = new HashMap<>();
-                //额度有效期开始时间,毫秒级时间戳
-                leave_quotas.put("start_time",beginDate.getTime());
-                //额度有效期结束时间,毫秒级时间戳。
-                leave_quotas.put("end_time",deadline.getTime());
-                //操作原因
-                leave_quotas.put("reason","接口测试修改");
-                //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
-                leave_quotas.put("quota_num_per_day",realYearLeave);
-                //以小时计算的额度总数 假期类型按小时,计算该值不为空且按百分之一小时折算。例如: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",LEAVE_CODE);
-                //要更新的员工的userId
-                leave_quotas.put("userid",userId);
-
-                updateBody.put("leave_quotas",leave_quotas);
-                //当前企业内拥有OA审批应用权限的管理员的userId
-                updateBody.put("op_userid",opUserId);
-
-                String bodyStr = realYearLeave + userId;
-
-                // 检查更新事件是否已经处理过,如果是,则忽略该更新
-                if (isUpdateLeave(bodyStr)) {
-                    log.info("更新事件已处理,忽略该回调...");
-                    return null;
-                }
+                    //更新假期余额接口的body
+                    DateTime deadline = DateUtil.parse((DateUtil.year(new Date()) + 1) + "-03-31");
+                    Map<String,Object> updateBody = new HashMap<>();
+                    Map<String,Object> leave_quotas = new HashMap<>();
+                    //额度有效期开始时间,毫秒级时间戳
+                    leave_quotas.put("start_time",beginDate.getTime());
+                    //额度有效期结束时间,毫秒级时间戳。
+                    leave_quotas.put("end_time",deadline.getTime());
+                    //操作原因
+                    leave_quotas.put("reason","接口测试修改");
+                    //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
+                    leave_quotas.put("quota_num_per_day",realYearLeave);
+                    //以小时计算的额度总数 假期类型按小时,计算该值不为空且按百分之一小时折算。例如: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",LEAVE_CODE);
+                    //要更新的员工的userId
+                    leave_quotas.put("userid",userId);
+
+                    updateBody.put("leave_quotas",leave_quotas);
+                    //当前企业内拥有OA审批应用权限的管理员的userId
+                    updateBody.put("op_userid",opUserId);
+
+/*                    String bodyStr = realYearLeave + userId;
+
+                    // 检查更新事件是否已经处理过,如果是,则忽略该更新
+                    if (isUpdateLeave(bodyStr)) {
+                        log.info("更新事件已处理,忽略该回调...");
+                        return null;
+                    }
 
-                // 将更新和当前时间戳添加到已处理集合中
-                long currentTime = System.currentTimeMillis();
-                bodyList.put(bodyStr, currentTime);
+                    // 将更新和当前时间戳添加到已处理集合中
+                    long currentTime = System.currentTimeMillis();
+                    bodyList.put(bodyStr, currentTime);*/
 
-                result.add("姓名:"+name+",职级:" + positionLevel+",原职级:" + oldPositionLevel+ ",年假基数:" + yearLeave + "天,入职日期:" + confirmJoinTime + ",升职日期:" + promotionTime + ",开始日期:" + beginDate+",截止日期:" + deadline);
+                    result.add("姓名:"+name+",职级:" + positionLevel+",原职级:" + oldPositionLevel+ ",年假基数:" + yearLeave + "天,入职日期:" + confirmJoinTime + ",升职日期:" + promotionTime + ",开始日期:" + beginDate+",截止日期:" + deadline);
 
-                //更新假期余额
-                UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody, DDR.class);
+                    //更新假期余额
+                    Map map3 = JSON.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody));
+                    kaiyueLog.setMsg(getString(map3.get("errmsg")));
+                    if ((boolean)map3.get("success")){
+                        kaiyueLog.setState("1");
+                    }else {
+                        kaiyueLog.setState("0");
+                    }
+                    kaiyueLogMapper.insert(kaiyueLog);
+                }catch (Exception e){
+                    kaiyueLog.setState("0");
+                    kaiyueLog.setMsg("接口异常:"+e.getMessage());
+                    kaiyueLogMapper.insert(kaiyueLog);
+                }
             }
         }
-        log.info(result.stream().collect(Collectors.joining(",")));
-        return McR.success(result);
+
+        return McR.success();
     }
 
     @Override
@@ -532,6 +546,342 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
         return leaveMap;
     }
 
+    @Override
+    public McR grantEmployeeAnnualLeave() {
+        //获取accessToken
+        String access_token = ddClient.getAccessToken(appKey,appSecret);
+
+        //获取员工userId集合
+        List<String> userIdList = getEmployeeUserId();
+//        List<String> userIdList = Arrays.asList("253434204020308091");
+
+
+        //遍历集合给所有员工更新年假余额
+        if (Objects.nonNull(userIdList) && !userIdList.isEmpty()) {
+            Map map = new HashMap();
+            //查询接口body添加参数
+            //field_filter_list:要查询字段(花名册字段信息参考:https://open.dingtalk.com/document/orgapp/roster-custom-field-business-code)
+            //agentid:企业内部应用AgentId
+            map.put("field_filter_list", "sys00-name,sys01-positionLevel,sys00-confirmJoinTime,b433c687-c3b3-4f97-8498-d23944f3316b,80292628-1c88-4c25-9c40-3e91283552e7,sys01-employeeType");
+            map.put("agentid", agentId);
+
+            String year = DateUtil.year(new Date()) + "";
+
+            for (String userId : userIdList) {
+                KaiyueLog kaiyueLog = new KaiyueLog();
+                kaiyueLog.setCity("cd");
+                kaiyueLog.setUserId(userId);
+                kaiyueLog.setYear(year+"");
+                try{
+                    map.put("userid_list", userId);
+                    //获取员工花名册字段信息
+                    DDR ddr = (DDR) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list", null, DDConf.initTokenParams(access_token), map, DDR.class);
+                    List<Map> employeeData = (List<Map>) ddr.getResult();
+
+                    //遍历员工信息
+                    for (Map data : employeeData) {
+                        //入职日期
+                        String confirmJoinTime = "";
+                        //职级
+                        String positionLevel = "";
+                        //姓名
+                        String name = "";
+                        //原职级
+                        String oldPositionLevel = "";
+                        //升职日期
+                        String promotionTime = "";
+                        //员工类型
+                        String employeeType = "";
+
+                        List<Map> fieldDataList = (List<Map>) data.get("field_data_list");
+                        for (Map fieldData : fieldDataList) {
+                            String fieldCode = fieldData.get("field_code").toString();
+                            List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
+
+                            if (Objects.nonNull(fieldValueList.get(0).get("value"))) {
+                                String value = getString(fieldValueList.get(0).get("value"));
+                                String label = getString(fieldValueList.get(0).get("label"));
+                                switch (fieldCode) {
+                                    case "sys00-confirmJoinTime":
+                                        confirmJoinTime = value;
+                                        break;
+                                    case "sys01-positionLevel":
+                                        positionLevel = value;
+                                        break;
+                                    case "sys00-name":
+                                        name = value;
+                                        break;
+                                    case "b433c687-c3b3-4f97-8498-d23944f3316b":
+                                        oldPositionLevel = value;
+                                        break;//成都原职级
+                                    case "80292628-1c88-4c25-9c40-3e91283552e7":
+                                        promotionTime = value;
+                                        break;//升职日期
+                                    case "sys01-employeeType":
+                                        employeeType = label;
+                                        break;
+                                    default:
+                                        break;
+                                }
+                            }
+                        }
+
+                        //若员工类型不为全职 不发放年假
+                        if (!employeeType.equals("全职")) {
+                            kaiyueLog.setState("0");
+                            kaiyueLog.setMsg("员工类型不为全职 不发放年假");
+                            kaiyueLogMapper.insert(kaiyueLog);
+
+                            continue;
+                        }
+
+                        //若没有原职级 则默认原职级是现职级
+                        if ("".equals(oldPositionLevel)) {
+                            oldPositionLevel = positionLevel;
+                        }
+                        //若没有升职日期 则默认升职日期是入职日期
+                        if ("".equals(promotionTime)) {
+                            promotionTime = confirmJoinTime;
+                        }
+
+                        if ("".equals(confirmJoinTime) || "".equals(positionLevel) || "".equals(name) || "".equals(oldPositionLevel)) {
+                            kaiyueLog.setState("0");
+                            kaiyueLog.setMsg("更新员工年假余额:参数缺啦!");
+                            kaiyueLogMapper.insert(kaiyueLog);
+                            continue;
+                        }
+                    /*String dateString = "2025-01-01";
+                    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+                    Date now = dateFormat.parse(dateString);*/
+
+                        Date now = new Date();
+
+                        //获取入职日期的月日
+                        String confirmJoinMonthAndDay = confirmJoinTime.substring(5);
+
+                        //获取去年年份
+                        String lastYear = DateUtil.year(now) - 1 + "";
+                        //今年入职周年日
+                        DateTime anniversaryOfEmployment = DateUtil.parse(year + "-" + confirmJoinMonthAndDay);
+                        //假期有效开始日期为当年1月1日
+                        DateTime beginDate = DateUtil.beginOfYear(now);
+                        //假期有效截至日期为次年3月31日
+                        DateTime deadline = DateUtil.parse((DateUtil.year(now) + 1) + "-03-31");
+
+                        DateTime endYearDate = DateUtil.endOfYear(now);
+                        //今天
+                        DateTime today = DateUtil.date();
+                        //当年天数
+                        int yearDays = DateUtil.dayOfYear(endYearDate);
+                        //年假
+                        double yearLeave = 0.0;
+
+                        //获取原职级年假基数
+                        int oldPositionLevelBaseNum = getAnnualLeaveBaseNum(oldPositionLevel);
+                        //获取现职级年假基数
+                        int positionLevelBaseNum = getAnnualLeaveBaseNum(positionLevel);
+
+
+                        //新增今年预支假+今年实有年假----------------------------------------------------------------------------------------------
+                        //计算今天是入职第几周年
+                        long anniversary = DateUtil.betweenYear(DateUtil.parse(confirmJoinTime), anniversaryOfEmployment, true) - 1;
+                        //判断员工是否当年新入职
+                        if (DateUtil.year(DateUtil.parse(confirmJoinTime)) == DateUtil.year(now)) {
+                            //分两段计算:入职日到升职日,升职日到年底
+                            long day1 = DateUtil.betweenDay(DateUtil.parse(confirmJoinTime), DateUtil.parse(promotionTime), true);
+                            long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endYearDate, true);
+                            yearLeave = (double) (day1 * oldPositionLevelBaseNum + day2 * positionLevelBaseNum) / yearDays;
+                        } else {
+                            //升职日期在今年入职周年日之前
+                            if (DateUtil.compare(anniversaryOfEmployment, DateUtil.parse(promotionTime)) >= 0) {
+                                //升职日期在今年
+                                if (DateUtil.compare(DateUtil.parse(promotionTime), today) >= 0) {
+                                    //获取年初到升职日的天数
+                                    int day1 = DateUtil.dayOfYear(DateUtil.parse(promotionTime));
+                                    //获升职值日到入职周年日的天数
+                                    long day2 = DateUtil.betweenDay(DateUtil.parse(promotionTime), anniversaryOfEmployment, true);
+                                    //获取入职周年日到年底的天数
+                                    long day3 = DateUtil.betweenDay(anniversaryOfEmployment, endYearDate, true);
+                                    //分三段计算:年初-升职日,升职日到入职周年日,入职周年日到年底
+                                    yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays;
+                                } else {
+                                    //获取年初到入职周年日的天数
+                                    int day1 = DateUtil.dayOfYear(anniversaryOfEmployment);
+                                    //获取入职周年日到年底的天数
+                                    long day2 = DateUtil.betweenDay(anniversaryOfEmployment, endYearDate, true);
+                                    //分两段计算:年初到入职周年日,入职周年日到年底
+                                    yearLeave = (double) (day1 * (positionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays;
+                                }
+                            } else {
+                                //升职日在今年入职周年日之后
+                                //获取年初到入职周年日的天数
+                                int day1 = DateUtil.dayOfYear(anniversaryOfEmployment);
+                                //获取入职周年日到升职日的天数
+                                long day2 = DateUtil.betweenDay(anniversaryOfEmployment, DateUtil.parse(promotionTime), true);
+                                //获取升职日到年底的天数
+                                long day3 = DateUtil.betweenDay(DateUtil.parse(promotionTime), endYearDate, true);
+                                //分三段计算:年初-入职周年日,入职周年日到升职日,升职日到年底
+                                yearLeave = (double) (day1 * (oldPositionLevelBaseNum + (anniversary > 4 ? 4 : anniversary)) + day2 * (oldPositionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1)) + day3 * (positionLevelBaseNum + (anniversary + 1 > 4 ? 4 : anniversary + 1))) / yearDays;
+                            }
+                        }
+
+                        yearLeave = Math.round(yearLeave * 100.0) / 100.0;
+
+                        //今年年假总数
+                        int realYearLeave = (int) ((yearLeave + ADVANCE_LEAVE) * 100);
+
+                        //更新假期余额接口的body
+                        Map<String, Object> updateBody = new HashMap<>();
+                        Map<String, Object> leave_quotas = new HashMap<>();
+                        //额度有效期开始时间,毫秒级时间戳
+                        leave_quotas.put("start_time", beginDate.getTime());
+                        //额度有效期结束时间,毫秒级时间戳。
+                        leave_quotas.put("end_time", deadline.getTime());
+                        //操作原因
+                        leave_quotas.put("reason", "期初年假发放");
+                        //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
+                        leave_quotas.put("quota_num_per_day", realYearLeave);
+                        //以小时计算的额度总数 假期类型按小时,计算该值不为空且按百分之一小时折算。例如:1000=10小时。
+                        leave_quotas.put("quota_num_per_hour", 0);
+                        //额度所对应的周期,格式必须是"yyyy",例如"2021"
+                        leave_quotas.put("quota_cycle", DateUtil.year(now) + "");
+                        //自定义添加的假期类型:年假开发测试的leave_code
+                        leave_quotas.put("leave_code", LEAVE_CODE);
+                        //要更新的员工的userId
+                        leave_quotas.put("userid", userId);
+
+                        updateBody.put("leave_quotas", leave_quotas);
+                        //当前企业内拥有OA审批应用权限的管理员的userId
+                        updateBody.put("op_userid", opUserId);
+
+                        //更新假期余额
+                        Map map1 = JSON.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody));
+
+                        kaiyueLog.setMsg(getString(map1.get("errmsg")));
+                        if ((boolean)map1.get("success")){
+                            kaiyueLog.setState("1");
+                        }else {
+                            kaiyueLog.setState("0");
+                        }
+                        //休眠一分钟 一个员工一分钟内只能更新一次假期余额
+                        Thread.sleep(6000);
+
+                        //查询员工次年结余年假----------------------------------------------------------------------------------------------
+                        List<Map> leaveQuotasList = new ArrayList<>();
+                        getLeaveNum(LEAVE_CODE, userId, 0, 50, leaveQuotasList);
+
+
+                        if (Objects.nonNull(leaveQuotasList)) {
+                            //假期有效开始日期为去年1月1日
+                            String dateString2 = lastYear + "-01-01";
+                            SimpleDateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd");
+                            DateTime lastYearBeginDate = DateUtil.beginOfYear(dateFormat2.parse(dateString2));
+                            //假期有效截至日期为今年3月31日
+                            DateTime lastYearDeadline = DateUtil.parse(DateUtil.year(now) + "-03-31");
+                            //更新假期余额接口的body
+                            Map<String, Object> lastUpdateBody = new HashMap<>();
+                            Map<String, Object> lastLeaveQuotas = new HashMap<>();
+                            //额度有效期开始时间,毫秒级时间戳
+                            lastLeaveQuotas.put("start_time", lastYearBeginDate.getTime());
+                            //额度有效期结束时间,毫秒级时间戳。
+                            lastLeaveQuotas.put("end_time", lastYearDeadline.getTime());
+                            //操作原因
+                            lastLeaveQuotas.put("reason", "去年预支假清空");
+                            lastLeaveQuotas.put("leave_code", LEAVE_CODE);
+                            //要更新的员工的userId
+                            lastLeaveQuotas.put("userid", userId);
+
+                            lastUpdateBody.put("leave_quotas", lastLeaveQuotas);
+                            //当前企业内拥有OA审批应用权限的管理员的userId
+                            lastUpdateBody.put("op_userid", opUserId);
+
+                            //记录剩余清空的假期数
+                            int remainedClearLeaveNum = 800;
+
+                            for (Map leaveQuotas : leaveQuotasList) {
+                                String quotaCycle = leaveQuotas.get("quota_cycle").toString();
+                                if (quotaCycle.contains(lastYear)) {
+                                    int usedNum = 0;
+                                    int quotaNum = 0;
+
+                                    if (Objects.isNull(leaveQuotas.get("quota_num_per_hour")) && Objects.nonNull(leaveQuotas.get("quota_num_per_day"))) {
+                                        quotaNum = (int) leaveQuotas.get("quota_num_per_day");
+                                    }
+                                    if (Objects.nonNull(leaveQuotas.get("used_num_per_day"))) {
+                                        usedNum = (int) leaveQuotas.get("used_num_per_day");
+                                    }
+
+                                    //若此周期年假余额>0
+                                    if (quotaNum - usedNum > 0 && remainedClearLeaveNum > 0) {
+                                        lastLeaveQuotas.put("quota_cycle", quotaCycle);
+                                        if (quotaNum - usedNum >= remainedClearLeaveNum) {
+                                            lastLeaveQuotas.put("quota_num_per_day", quotaNum - remainedClearLeaveNum);
+                                            break;
+                                        } else {
+                                            lastLeaveQuotas.put("quota_num_per_day", usedNum);
+                                            remainedClearLeaveNum -= quotaNum - usedNum;
+                                        }
+                                        Map map2 = JSON.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), lastUpdateBody));
+
+                                        kaiyueLog.setMsg(getString(map2.get("errmsg")));
+                                        if ((boolean)map2.get("success")){
+                                            kaiyueLog.setState("1");
+                                        }else {
+                                            kaiyueLog.setState("0");
+                                        }
+                                        kaiyueLogMapper.insert(kaiyueLog);
+
+                                        //休眠一分钟 一个员工一分钟内只能更新一次假期余额
+                                        Thread.sleep(6000);
+                                    }
+                                }
+                            }
+
+                            AdvancedLeave advancedLeave = new AdvancedLeave();
+                            advancedLeave.setUserId(userId);
+                            advancedLeave.setCity("cd");
+                            advancedLeave.setYear(year);
+
+                            if (remainedClearLeaveNum > 0) {
+                                //去年预支假期今年扣除
+                                leave_quotas.put("quota_num_per_day", realYearLeave - remainedClearLeaveNum);
+                                leave_quotas.put("reason", "去年预支扣除");
+                                updateBody.put("leave_quotas", leave_quotas);
+
+                                Map map3 =JSON.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody));
+
+                                kaiyueLog.setMsg(getString(map3.get("errmsg")));
+                                if ((boolean)map3.get("success")){
+                                    kaiyueLog.setState("1");
+                                }else {
+                                    kaiyueLog.setState("0");
+                                }
+                                kaiyueLogMapper.insert(kaiyueLog);
+
+                                advancedLeave.setLeaveNum((800 - remainedClearLeaveNum) / 100.0 + "");
+                            } else {
+                                advancedLeave.setLeaveNum("8.0");
+                            }
+                            advancedLeaveMapper.insert(advancedLeave);
+                        }
+
+
+                    }
+                }catch (Exception e){
+                    kaiyueLog.setState("0");
+                    kaiyueLog.setMsg("接口异常:"+e.getMessage());
+                    kaiyueLogMapper.insert(kaiyueLog);
+                }
+            }
+        }
+
+        return McR.success();
+    }
+
+    private String getString(Object label) {
+        return Objects.isNull(label) ? "" : label.toString();
+    }
+
     private List<Map> getLeaveNum(String leave_code,String userId,int offset,int size,List<Map> leaveQuotasList) {
         String access_token = ddClient.getAccessToken(appKey,appSecret);
 

+ 215 - 154
mjava-kaiyue/src/main/java/com/malk/kaiyue/service/impl/KYNTServiceImpl.java

@@ -1,7 +1,11 @@
 package com.malk.kaiyue.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.kaiyue.entity.KaiyueLog;
+import com.malk.kaiyue.mapper.KaiyueLogMapper;
 import com.malk.kaiyue.service.KYNTService;
 import com.malk.server.common.McR;
 import com.malk.server.dingtalk.DDConf;
@@ -41,10 +45,13 @@ public class KYNTServiceImpl implements KYNTService {
     @Value("${dingtalk_nt.operator}")
     private String opUserId;
 
+    @Autowired
+    private KaiyueLogMapper kaiyueLogMapper;
+
     //南通凯悦-年假测试3
-    private static final String LEAVE_CODE = "42a0db4f-2929-4c59-8683-67ecacc73b7c";
-    //体验社-年假测试wzy
-//    private static final String LEAVE_CODE = "f9240c02-8fe7-4535-af2c-ca6740e1c654";
+//    private static final String LEAVE_CODE = "42a0db4f-2929-4c59-8683-67ecacc73b7c";
+    //南通凯悦-年假
+    private static final String LEAVE_CODE = "db3deaeb-36c9-4798-8395-0f61d006949d";
 
     @Override
     public List<Map> getEmployeeRosterInfo(Map<String, Object> map) {
@@ -100,13 +107,15 @@ public class KYNTServiceImpl implements KYNTService {
 
     @Async
     public McR getEmployeeAnnualLeaveNum(Map<String, Object> map) {
+
+
         //获取accessToken
         String access_token = ddClient.getAccessToken(appKey,appSecret);
 
         //查询接口body添加参数
         //field_filter_list:要查询字段(花名册字段信息参考:https://open.dingtalk.com/document/orgapp/roster-custom-field-business-code)
         //agentid:企业内部应用AgentId
-        map.put("field_filter_list","sys00-name,sys01-positionLevel,6ef81fb9-e178-4395-8a7f-6f33b3263bb2,52b25106-d588-43d7-a048-7661e3f90189,sys00-confirmJoinTime,sys02-joinWorkingTime,sys05-nowContractStartTime,sys05-contractRenewCount");
+        map.put("field_filter_list","sys00-name,sys01-positionLevel,6ef81fb9-e178-4395-8a7f-6f33b3263bb2,52b25106-d588-43d7-a048-7661e3f90189,sys00-confirmJoinTime,sys02-joinWorkingTime,sys05-nowContractStartTime,sys05-contractRenewCount,sys01-employeeType");
         map.put("agentid",agentId);
 
         List<String> result = new ArrayList<>();
@@ -118,156 +127,195 @@ public class KYNTServiceImpl implements KYNTService {
             //遍历员工信息
             for (Map data : employeeData) {
                 String userId = data.get("userid").toString();
-                //首次参加工作日期(计算工龄)
-                String joinWorkingTime = "";
-                //入职日期
-                String confirmJoinTime = "";
-                //职级
-                String positionLevel = "";
-                //原职级
-                String oldPositionLevel = "";
-                //升职日期
-                String promotionTime = "";
-                //姓名
-                String name = "";
-                //现合同开始日期
-                String owContractStartTime = "";
-                //合同续签次数
-                int contractRenewCount = 0;
-                List<Map> fieldDataList = (List<Map>) data.get("field_data_list");
-                for (Map fieldData : fieldDataList) {
-                    String fieldCode = fieldData.get("field_code").toString();
-                    List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
-                    if (Objects.nonNull(fieldValueList.get(0).get("value"))){
-                        String value = fieldValueList.get(0).get("value").toString();
-                        switch (fieldCode){
-                            case "sys02-joinWorkingTime": joinWorkingTime = value;break;
-                            case "sys00-confirmJoinTime": confirmJoinTime = value;break;
-                            case "sys01-positionLevel": positionLevel = value;break;
-                            case "6ef81fb9-e178-4395-8a7f-6f33b3263bb2": oldPositionLevel = fieldValueList.get(0).get("label").toString();break;
-                            case "52b25106-d588-43d7-a048-7661e3f90189": promotionTime = value;break;
-                            case "sys00-name": name = value;break;
-                            case "sys05-nowContractStartTime": owContractStartTime = value;break;
-                            case "sys05-contractRenewCount": contractRenewCount = Integer.valueOf(value);break;
-                            default:break;
+
+                KaiyueLog kaiyueLog = new KaiyueLog();
+                kaiyueLog.setCity("nt");
+                kaiyueLog.setUserId(userId);
+                int year = DateUtil.year(new Date());
+                kaiyueLog.setYear(year+"");
+
+                try{
+                    //首次参加工作日期(计算工龄)
+                    String joinWorkingTime = "";
+                    //入职日期
+                    String confirmJoinTime = "";
+                    //职级
+                    String positionLevel = "";
+                    //原职级
+                    String oldPositionLevel = "";
+                    //升职日期
+                    String promotionTime = "";
+                    //姓名
+                    String name = "";
+                    //现合同开始日期
+                    String owContractStartTime = "";
+                    //员工类型
+                    String employeeType = "";
+
+                    //合同续签次数
+                    int contractRenewCount = 0;
+                    List<Map> fieldDataList = (List<Map>) data.get("field_data_list");
+                    for (Map fieldData : fieldDataList) {
+                        String fieldCode = fieldData.get("field_code").toString();
+                        List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
+                        if (Objects.nonNull(fieldValueList.get(0).get("value"))){
+                            String value = getString(fieldValueList.get(0).get("value"));
+                            String label = getString(fieldValueList.get(0).get("label"));
+                            switch (fieldCode){
+                                case "sys02-joinWorkingTime": joinWorkingTime = value;break;
+                                case "sys00-confirmJoinTime": confirmJoinTime = value;break;
+                                case "sys01-positionLevel": positionLevel = value;break;
+                                case "6ef81fb9-e178-4395-8a7f-6f33b3263bb2": oldPositionLevel = fieldValueList.get(0).get("label").toString();break;
+                                case "52b25106-d588-43d7-a048-7661e3f90189": promotionTime = value;break;
+                                case "sys00-name": name = value;break;
+                                case "sys05-nowContractStartTime": owContractStartTime = value;break;
+                                case "sys05-contractRenewCount": contractRenewCount = Integer.valueOf(value);break;
+                                case "sys01-employeeType": employeeType = label;break;
+                                default:break;
+                            }
                         }
-                    }else {
-                        log.info("更新员工年假余额:参数缺啦!");
-                        return McR.errorParam("参数缺啦!");
                     }
 
-                }
-                //若没有原职级 则默认原职级是现职级
-                if ("".equals(oldPositionLevel)){
-                    oldPositionLevel = positionLevel;
-                }
-                //若没有升职日期 则默认当天是升职日期
-                if ("".equals(promotionTime)){
-                    promotionTime = confirmJoinTime;
-                }
-                //若没有现合同开始日期
-                if ("".equals(owContractStartTime)){
-                    //若合同续签次数为0 则默认合同开始日期为入职日期
-                    if (contractRenewCount == 0){
-                        owContractStartTime = confirmJoinTime;
-                    }else {
-                        //若合同续签次数不为0 则默认合同开始日期为当天
-                        owContractStartTime = DateUtil.today();
+
+                    //若员工类型为不为全职 不发放年假
+                    if (!employeeType.equals("全职")) {
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("员工类型不为全职 不发放年假");
+                        kaiyueLogMapper.insert(kaiyueLog);
+                        continue;
                     }
 
-                }
-                //旧合同续签次数等于合同续签数-1 最小为0
-                int oldContractRenewCount = Math.max(0, contractRenewCount - 1);
-
-                //假期有效开始日期为当年1月1日
-                DateTime beginDate = DateUtil.beginOfYear(new Date());
-                //假期有效截至日期为当年12月31日
-                DateTime endDate = DateUtil.endOfYear(new Date());
-                //当年天数
-                int yearDays = DateUtil.dayOfYear(endDate);
-
-                //工龄(年) 计算规则:首次工作时间至当年一月一日 数值向下取整
-                int workAge =(int) (DateUtil.betweenYear(DateUtil.parse(joinWorkingTime), beginDate, true));
-                if (DateUtil.dayOfYear(DateUtil.parse(joinWorkingTime)) != 1){
-                    workAge --;
-                }
+                    //若没有原职级 则默认原职级是现职级
+                    if ("".equals(oldPositionLevel)){
+                        oldPositionLevel = positionLevel;
+                    }
+                    //若没有升职日期 则默认当天是升职日期
+                    if ("".equals(promotionTime)){
+                        promotionTime = confirmJoinTime;
+                    }
+                    //若没有首次工作时间 则默认当天是首次工作时间
+                    if ("".equals(joinWorkingTime)){
+                        joinWorkingTime = confirmJoinTime;
+                    }
+                    //若没有现合同开始日期
+                    if ("".equals(owContractStartTime)){
+                        //若合同续签次数为0 则默认合同开始日期为入职日期
+                        if (contractRenewCount == 0){
+                            owContractStartTime = confirmJoinTime;
+                        }else {
+                            //若合同续签次数不为0 则默认合同开始日期为当天
+                            owContractStartTime = DateUtil.today();
+                        }
+                    }
 
-                System.out.println("截至今年1月1日,工龄为:"+workAge + "年");
-                //年假数
-                double yearLeave = getLeaveNum(confirmJoinTime,beginDate,endDate,promotionTime,owContractStartTime,oldPositionLevel,positionLevel,workAge,oldContractRenewCount,contractRenewCount,yearDays);
+                    if ("".equals(joinWorkingTime) || "".equals(confirmJoinTime) || "".equals(positionLevel) || "".equals(name)) {
+                        log.info("更新员工年假余额:参数缺啦!");
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("更新员工年假余额:参数缺啦!");
+                        kaiyueLogMapper.insert(kaiyueLog);
+                        continue;
+                    }
 
-                //年假小数
-                double yearLeaveDecimalPart = yearLeave - (int) yearLeave;
 
-                result.add("姓名:"+name+",职级:"+positionLevel+",工龄:"+workAge+"年,合同续签数"+contractRenewCount+",年假数:" + yearLeave + "天"+",截止日期:"+endDate);
+                    //旧合同续签次数等于合同续签数-1 最小为0
+                    int oldContractRenewCount = Math.max(0, contractRenewCount - 1);
 
-                if (yearLeaveDecimalPart < 0.25){
-                    yearLeave = (int) yearLeave;
-                }else if (yearLeaveDecimalPart < 0.75){
-                    yearLeave = (int) yearLeave + 0.5;
-                }else if (yearLeaveDecimalPart < 1){
-                    yearLeave = (int) yearLeave + 1;
-                }
+                    //假期有效开始日期为当年1月1日
+                    DateTime beginDate = DateUtil.beginOfYear(new Date());
+                    //年底
+                    DateTime endDate = DateUtil.endOfYear(new Date());
+
+
+                    //假期有效截至日期为次年3月31日
+                    DateTime deadline = DateUtil.parse((year + 1) + "-03-31");
 
-                //查询出用户消费年假记录 当返回leaveRecords中calType为null或不返回该字段则为请假消耗 将计算出的年假数减去请假消耗的数量
-                Map body = new HashMap();
-                body.put("opUserId",opUserId);
-                body.put("leaveCode",LEAVE_CODE);
-                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;
-                if (Objects.nonNull(useList) && !useList.isEmpty()){
-                    for (Map use : useList) {
-                        //判断是否为今年请假
-                        DateTime gmtCreate = DateUtil.date((long) use.get("gmtCreate"));
-                        if (DateUtil.year(gmtCreate) == DateUtil.year(new Date())){
-                            //判断是否为正常请假而不是接口测试或期初假期发放
-                            if (Objects.nonNull(use.get("leaveReason"))){
-                                if (!"接口测试修改".equals(use.get("leaveReason").toString()) && !"期初假期发放".equals(use.get("leaveReason").toString())){
-                                    //若是请假消耗或管理员手动减少
-                                    if (!use.containsKey("calType") || Objects.isNull(use.get("calType")) || "delete".equals(use.get("calType").toString())){
-                                        useLeaveNum += (int) use.get("recordNumPerDay") / 100;
+
+                    //当年天数
+                    int yearDays = DateUtil.dayOfYear(endDate);
+
+                    //工龄(年) 计算规则:首次工作时间至当年一月一日 数值向下取整
+                    int workAge =(int) (DateUtil.betweenYear(DateUtil.parse(joinWorkingTime), beginDate, true));
+                    if (DateUtil.dayOfYear(DateUtil.parse(joinWorkingTime)) != 1){
+                        workAge --;
+                    }
+
+                    System.out.println("截至今年1月1日,工龄为:"+workAge + "年");
+                    //年假数
+                    double yearLeave = getLeaveNum(confirmJoinTime,beginDate,endDate,promotionTime,owContractStartTime,oldPositionLevel,positionLevel,workAge,oldContractRenewCount,contractRenewCount,yearDays);
+
+                    //年假小数
+                    double yearLeaveDecimalPart = yearLeave - (int) yearLeave;
+
+                    result.add("姓名:"+name+",职级:"+positionLevel+",工龄:"+workAge+"年,合同续签数"+contractRenewCount+",年假数:" + yearLeave + "天"+",截止日期:"+endDate);
+
+                    if (yearLeaveDecimalPart < 0.25){
+                        yearLeave = (int) yearLeave;
+                    }else if (yearLeaveDecimalPart < 0.75){
+                        yearLeave = (int) yearLeave + 0.5;
+                    }else if (yearLeaveDecimalPart < 1){
+                        yearLeave = (int) yearLeave + 1;
+                    }
+
+                    //查询出用户消费年假记录 当返回leaveRecords中calType为null或不返回该字段则为请假消耗 将计算出的年假数减去请假消耗的数量
+                    Map body = new HashMap();
+                    body.put("opUserId",opUserId);
+                    body.put("leaveCode",LEAVE_CODE);
+                    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;
+                    if (Objects.nonNull(useList) && !useList.isEmpty()){
+                        for (Map use : useList) {
+                            //判断是否为今年请假
+                            DateTime gmtCreate = DateUtil.date((long) use.get("gmtCreate"));
+                            if (DateUtil.year(gmtCreate) == DateUtil.year(new Date())){
+                                //判断是否为正常请假而不是接口测试或期初假期发放
+                                if (Objects.nonNull(use.get("leaveReason"))){
+                                    String leaveReason = getString(use.get("leaveReason"));
+                                    if (!"接口测试修改".equals(leaveReason) && !"期初假期发放".equals(leaveReason) && !"年假发放".equals(leaveReason)){
+                                        //若是请假消耗或管理员手动减少
+                                        if (!use.containsKey("calType") || Objects.isNull(use.get("calType")) || "delete".equals(use.get("calType").toString())){
+                                            useLeaveNum += ((int) use.get("recordNumPerDay")) / 100.0;
+                                        }
+                                        //注:若是管理员手动增加 则假期余额会多出一个BCXsunNm记录增加的假期天数  最终会在设置的假期余额的基础上加上这些天数
+                                        //故此处手动新增的假期余额不做处理
                                     }
-                                    //注:若是管理员手动增加 则假期余额会多出一个BCXsunNm记录增加的假期天数  最终会在设置的假期余额的基础上加上这些天数
-                                    //故此处手动新增的假期余额不做处理
                                 }
                             }
                         }
                     }
-                }
 
-                //实际年假数
-                double realYearLeave = (yearLeave - useLeaveNum) < 0 ? 0 : (yearLeave - useLeaveNum);
-
-                //更新假期余额接口的body
-                Map<String,Object> updateBody = new HashMap<>();
-                Map<String,Object> leave_quotas = new HashMap<>();
-                //额度有效期开始时间,毫秒级时间戳
-                leave_quotas.put("start_time",beginDate.getTime());
-                //额度有效期结束时间,毫秒级时间戳。
-                leave_quotas.put("end_time",endDate.getTime());
-                //操作原因
-                leave_quotas.put("reason","接口测试修改");
-                //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
-                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",LEAVE_CODE);
-                //要更新的员工的userId
-                leave_quotas.put("userid",userId);
-
-                updateBody.put("leave_quotas",leave_quotas);
-                //当前企业内拥有OA审批应用权限的管理员的userId
-                updateBody.put("op_userid",opUserId);
-
-                String bodyStr = yearLeave + userId;
+                    //实际年假数
+                    double realYearLeave = (yearLeave - useLeaveNum) < 0 ? 0 : (yearLeave - useLeaveNum);
+
+                    //更新假期余额接口的body
+                    Map<String,Object> updateBody = new HashMap<>();
+                    Map<String,Object> leave_quotas = new HashMap<>();
+                    //额度有效期开始时间,毫秒级时间戳
+                    leave_quotas.put("start_time",beginDate.getTime());
+                    //额度有效期结束时间,毫秒级时间戳。
+                    leave_quotas.put("end_time",deadline.getTime());
+                    //操作原因
+                    leave_quotas.put("reason","年假发放");
+                    //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
+                    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",LEAVE_CODE);
+                    //要更新的员工的userId
+                    leave_quotas.put("userid",userId);
+
+                    updateBody.put("leave_quotas",leave_quotas);
+                    //当前企业内拥有OA审批应用权限的管理员的userId
+                    updateBody.put("op_userid",opUserId);
+
+/*                String bodyStr = yearLeave + userId;
 
                 // 检查更新事件是否已经处理过,如果是,则忽略该更新
                 if (isUpdateLeave(bodyStr)) {
@@ -275,17 +323,34 @@ public class KYNTServiceImpl implements KYNTService {
                     return null;
                 }
 
-
                 // 将更新和当前时间戳添加到已处理集合中
                 long currentTime = System.currentTimeMillis();
-                bodyList.put(bodyStr, currentTime);
+                bodyList.put(bodyStr, currentTime);*/
 
-                //更新假期余额
-                UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody, DDR.class);
+                    //更新假期余额
+                    Map map3 = JSONObject.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody));
+                    kaiyueLog.setMsg(getString(map3.get("errmsg")));
+                    if ((boolean)map3.get("success")){
+                        kaiyueLog.setState("1");
+                    }else {
+                        kaiyueLog.setState("0");
+                    }
+                    kaiyueLogMapper.insert(kaiyueLog);
+
+                    //休眠3秒
+                    Thread.sleep(3000);
+                }catch (Exception e){
+                    kaiyueLog.setState("0");
+                    kaiyueLog.setMsg("接口异常:"+e.getMessage());
+                    kaiyueLogMapper.insert(kaiyueLog);
+                }
             }
         }
-        log.info(result.stream().collect(Collectors.joining(",")));
-        return McR.success(result);
+        return McR.success();
+    }
+
+    private String getString(Object label) {
+        return Objects.isNull(label) ? "" : label.toString();
     }
 
     private double getLeaveNum(String confirmJoinTime,Date beginDate,Date endDate,String promotionTime,String owContractStartTime,String oldPositionLevel,String positionLevel,int workAge,int oldContractRenewCount,int contractRenewCount,int yearDays) {
@@ -396,19 +461,15 @@ public class KYNTServiceImpl implements KYNTService {
     public McR updateEmployeeAnnualLeaveNum() {
         //获取员工userId集合
         List<String> userIdList = getEmployeeUserId();
+//        List<String> userIdList = Arrays.asList("02212658405620308091");
         //遍历集合给所有员工更新年假余额
         if (Objects.nonNull(userIdList) && !userIdList.isEmpty()){
-            for (String userId : userIdList) {
-                Map map = new HashMap();
-                map.put("userid_list",userId);
+            Map map = new HashMap();
+            //将userIdList拆分成50长度的多个数组
+            List<List<String>> userIdListList = CollectionUtil.splitList(userIdList,50);
+            for (List<String> userIdList1 : userIdListList) {
+                map.put("userid_list",String.join(",",userIdList1));
                 getEmployeeAnnualLeaveNum(map);
-                //线程等待10s
-                try {
-                    log.info("线程睡眠10s");
-                    Thread.sleep(10000);
-                } catch (InterruptedException e) {
-                    e.printStackTrace();
-                }
             }
         }
         return McR.success();

+ 45 - 34
mjava-kaiyue/src/main/java/com/malk/kaiyue/service/impl/KYSXServiceImpl.java

@@ -3,6 +3,9 @@ package com.malk.kaiyue.service.impl;
 import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.date.DateTime;
 import cn.hutool.core.date.DateUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.malk.kaiyue.entity.KaiyueLog;
+import com.malk.kaiyue.mapper.KaiyueLogMapper;
 import com.malk.kaiyue.service.KYNTService;
 import com.malk.kaiyue.service.KYSXService;
 import com.malk.server.common.McR;
@@ -43,6 +46,9 @@ public class KYSXServiceImpl implements KYSXService {
     @Value("${dingtalk_sx.operator}")
     private String opUserId;
 
+    @Autowired
+    private KaiyueLogMapper kaiyueLogMapper;
+
     //绍兴凯悦-年假(测)
 //    private static final String LEAVE_CODE = "1eecac0a-18b3-4596-b696-ba60d71c8306";
 
@@ -104,7 +110,7 @@ public class KYSXServiceImpl implements KYSXService {
     private Map<String, Long> bodyList = new HashMap<>();
 
     @Async
-    public Map getEmployeeAnnualLeaveNum(Map<String, Object> map) {
+    public McR getEmployeeAnnualLeaveNum(Map<String, Object> map) {
         //获取accessToken
         String access_token = ddClient.getAccessToken(appKey,appSecret);
 
@@ -114,9 +120,6 @@ public class KYSXServiceImpl implements KYSXService {
         map.put("field_filter_list","sys00-name,sys01-positionLevel,sys01-employeeType,9bd53d78-3008-4927-aef8-152a1b44f29b,434d3cd0-3b02-4250-9e7d-7748c31efa84,sys00-confirmJoinTime,sys02-joinWorkingTime,sys05-nowContractStartTime,sys05-contractRenewCount");
         map.put("agentid",agentId);
 
-        List<Map> errorList = new ArrayList<>();
-        List<Map> successList = new ArrayList<>();
-
         //获取员工花名册字段信息
         if (Objects.nonNull(map)){
             DDR ddr = (DDR) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list", null, DDConf.initTokenParams(access_token), map, DDR.class);
@@ -125,6 +128,13 @@ public class KYSXServiceImpl implements KYSXService {
             //遍历员工信息
             for (Map data : employeeData) {
                 String userId = data.get("userid").toString();
+
+                KaiyueLog kaiyueLog = new KaiyueLog();
+                kaiyueLog.setCity("sx");
+                kaiyueLog.setUserId(userId);
+                int year = DateUtil.year(new Date());
+                kaiyueLog.setYear(year+"");
+
                 try {
                     //首次参加工作日期(计算工龄)
                     String joinWorkingTime = "";
@@ -166,10 +176,10 @@ public class KYSXServiceImpl implements KYSXService {
                         }
                     }
 
-                    if (employeeType.equals("劳务外包") || employeeType.equals("实习") || employeeType.equals("兼职")){
-                        Map successMap = new HashMap();
-                        successMap.put(userId,"姓名:"+name+",劳务外包、实习、兼职员工不发放年假");
-                        successList.add(successMap);
+                    if (!employeeType.equals("全职")){
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("员工类型不为全职 不发放年假");
+                        kaiyueLogMapper.insert(kaiyueLog);
 
                         continue;
                     }
@@ -193,10 +203,9 @@ public class KYSXServiceImpl implements KYSXService {
                     }
 
                     if ("".equals(confirmJoinTime) || "".equals(positionLevel) || "".equals(name)){
-                        Map errorMap = new HashMap();
-                        errorMap.put(userId,"参数缺失!");
-                        errorList.add(errorMap);
-//                        log.info("更新员工userid:{} 参数缺失!", userId);
+                        kaiyueLog.setState("0");
+                        kaiyueLog.setMsg("更新员工年假余额:参数缺啦!");
+                        kaiyueLogMapper.insert(kaiyueLog);
                         continue;
                     }
 
@@ -205,8 +214,12 @@ public class KYSXServiceImpl implements KYSXService {
 
                     //假期有效开始日期为当年1月1日
                     DateTime beginDate = DateUtil.beginOfYear(new Date());
-                    //假期有效截至日期为当年12月31日
+                    //年底
                     DateTime endDate = DateUtil.endOfYear(new Date());
+
+                    //假期有效截至日期为次年3月31日
+                    DateTime deadline = DateUtil.parse((year + 1) + "-03-31");
+
                     //当年天数
                     int yearDays = DateUtil.dayOfYear(endDate);
 
@@ -270,14 +283,13 @@ public class KYSXServiceImpl implements KYSXService {
 
                     //实际年假数
                     double realYearLeave = (yearLeave * 100 - useLeaveNum) < 0 ? 0 : (yearLeave * 100 - useLeaveNum);
-
                     //更新假期余额接口的body
                     Map<String,Object> updateBody = new HashMap<>();
                     Map<String,Object> leave_quotas = new HashMap<>();
                     //额度有效期开始时间,毫秒级时间戳
                     leave_quotas.put("start_time",beginDate.getTime());
                     //额度有效期结束时间,毫秒级时间戳。
-                    leave_quotas.put("end_time",endDate.getTime());
+                    leave_quotas.put("end_time",deadline.getTime());
                     //操作原因
                     leave_quotas.put("reason","接口年假发放");
                     //以天计算的额度总数 假期类型按天计算时,该值不为空且按百分之一天折算。 例如:1000=10天。
@@ -285,7 +297,7 @@ public class KYSXServiceImpl implements KYSXService {
                     //以小时计算的额度总数 假期类型按小时,计算该值不为空且按百分之一小时折算。例如:1000=10小时。
                     leave_quotas.put("quota_num_per_hour",0);
                     //额度所对应的周期,格式必须是"yyyy",例如"2021"
-                    leave_quotas.put("quota_cycle",DateUtil.year(new Date())+"");
+                    leave_quotas.put("quota_cycle",year+"");
                     //自定义添加的假期类型:年假开发测试的leave_code
                     leave_quotas.put("leave_code",LEAVE_CODE);
                     //要更新的员工的userId
@@ -308,25 +320,26 @@ public class KYSXServiceImpl implements KYSXService {
                     bodyList.put(bodyStr, currentTime);
 
                     //更新假期余额
-                    UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody, DDR.class);
+                    Map map3 = JSONObject.parseObject(UtilHttp.doPost("https://oapi.dingtalk.com/topapi/attendance/vacation/quota/update", null, DDConf.initTokenParams(access_token), updateBody));
+                    kaiyueLog.setMsg(getString(map3.get("errmsg")));
+                    if ((boolean)map3.get("success")){
+                        kaiyueLog.setState("1");
+                    }else {
+                        kaiyueLog.setState("0");
+                    }
+                    kaiyueLogMapper.insert(kaiyueLog);
 
-                    Map successMap = new HashMap();
-                    successMap.put(userId,"姓名:"+name+",职级:" + positionLevel+",原职级:" + oldPositionLevel+",入职日期:" + confirmJoinTime + ",升职日期:" + promotionTime + ",年假数:"+ realYearLeave + ",开始日期:" + beginDate+",截止日期:" + endDate);
-                    successList.add(successMap);
+                    //休眠3秒
+                    Thread.sleep(3000);
                 }catch (Exception e){
-                    log.info("更新员工年假失败:{}",e);
-                    Map errorMap = new HashMap();
-                    errorMap.put(userId,e.getMessage());
-                    errorList.add(errorMap);
+                    kaiyueLog.setState("0");
+                    kaiyueLog.setMsg("接口异常:"+e.getMessage());
+                    kaiyueLogMapper.insert(kaiyueLog);
                 }
             }
         }
-        log.info("更新失败列表:{}",errorList);
-        log.info("更新成功列表:{}",successList);
-        Map result = new HashMap();
-        result.put("errorList",errorList);
-        result.put("successList",successList);
-        return result;
+
+        return McR.success();
     }
 
     private String getString(Object label) {
@@ -441,18 +454,16 @@ public class KYSXServiceImpl implements KYSXService {
     public McR updateEmployeeAnnualLeaveNum() {
         //获取员工userId集合
         List<String> userIdList = getEmployeeUserId();
-
+//        List<String> userIdList = Arrays.asList("02145933103920308091");
         //遍历集合给所有员工更新年假余额
-        List<Map> result = new ArrayList<>();
         if (Objects.nonNull(userIdList) && !userIdList.isEmpty()){
             Map map = new HashMap();
             //将userIdList拆分成50长度的多个数组
             List<List<String>> userIdListList = CollectionUtil.splitList(userIdList,50);
             for (List<String> userIdList1 : userIdListList) {
                 map.put("userid_list",String.join(",",userIdList1));
-                result.add(getEmployeeAnnualLeaveNum(map));
+                getEmployeeAnnualLeaveNum(map);
             }
-            log.info("result:{}",result);
         }
 
         return McR.success();

+ 0 - 6
mjava-kaiyue_cd/src/main/java/com/malk/kaiyue_cd/service/KYCDService.java

@@ -17,12 +17,6 @@ public interface KYCDService extends IService<AdvancedLeave> {
     @Async
     McR getEmployeeAnnualLeaveNum(Map<String, Object> map);
 
-    /**
-     * 每年1月1日 00:00定时更新员工旧职级
-     * @return
-     */
-//    McR updateEmployeeOldPositionLevel();
-
     /**
      * 每年1月1日 01:00定时更新员工年假数
      * @return

+ 0 - 83
mjava-kaiyue_cd/src/main/java/com/malk/kaiyue_cd/service/impl/KYCDServiceImpl.java

@@ -353,89 +353,6 @@ public class KYCDServiceImpl extends ServiceImpl<AdvancedLeaveMapper, AdvancedLe
         return McR.success(result);
     }
 
- /*   @Override
-    public McR updateEmployeeOldPositionLevel() {
-        //获取accessToken
-        String access_token = ddClient.getAccessToken();
-        //获取agentId
-        String agentId = ddConf.getAgentId().toString();
-        //获取员工userId列表
-        List<String> userIdList = getEmployeeUserId();
-        for (String userId : userIdList) {
-            if ("344749020127590108".equals(userId)){//测试 只拿沃洲洋
-                //查询接口body添加参数
-                //field_filter_list:要查询字段(花名册字段信息参考:https://open.dingtalk.com/document/orgapp/roster-custom-field-business-code)
-                Map map = new HashMap();
-                map.put("field_filter_list","sys00-name,sys01-positionLevel,b433c687-c3b3-4f97-8498-d23944f3316b");
-                map.put("agentid",agentId);
-                map.put("userid_list",userId);
-
-                List<String> result = new ArrayList<>();
-                //获取员工职级
-                if (Objects.nonNull(map)) {
-                    DDR ddr = (DDR) UtilHttp.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/list", null, DDConf.initTokenParams(access_token), map, DDR.class);
-                    List<Map> employeeDataList = (List<Map>) ddr.getResult();
-                    List<Map> fieldDataList = (List<Map>) employeeDataList.get(0).get("field_data_list");
-
-                    String positionLevel = "";
-                    for (Map fieldData : fieldDataList) {
-                        if ("sys01-positionLevel".equals(fieldData.get("field_code").toString())){
-                            List<Map> fieldValueList = (List<Map>) fieldData.get("field_value_list");
-                            if (Objects.nonNull(fieldValueList.get(0).get("value"))){
-                                positionLevel = fieldValueList.get(0).get("value").toString();
-                                Map updateBody = new HashMap();
-
-                                Map param = new HashMap();
-
-                                List<Map> groups = new ArrayList<>();
-
-                                Map group = new HashMap();
-
-                                List<Map> sections = new ArrayList<>();
-
-                                Map oneSection = new HashMap();
-
-                                List<Map> section = new ArrayList<>();
-                                Map field = new HashMap<>();
-                                field.put("field_code","b433c687-c3b3-4f97-8498-d23944f3316b");
-                                field.put("value",positionLevel);
-                                section.add(field);
-
-                                oneSection.put("section",section);
-                                oneSection.put("old_index",0);
-
-                                sections.add(oneSection);
-
-                                group.put("group_id","customa2cb92d853e34e1ab2cde45d4ee7cfdf");
-                                group.put("sections",sections);
-
-                                groups.add(group);
-
-                                param.put("groups",groups);
-                                param.put("userid",userId);
-
-                                updateBody.put("param",param);
-                                updateBody.put("agentid",agentId);
-
-                                //设置给员工旧职级
-                                UtilHttp.doPost("https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/v2/update", null, DDConf.initTokenParams(access_token), updateBody, DDR.class);
-                            }
-                        }
-
-                    }
-                    //获取员工职级
-
-                    //设置职级给旧职级
-                }
-            }
-
-        }
-
-
-
-        return null;
-    }*/
-
     @Override
     public McR updateEmployeeAnnualLeaveNum() {
         //获取员工userId集合