Explorar el Código

企业微信考勤打卡记录同步

yurk hace 2 años
padre
commit
9873ed7e00

+ 2 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/WxCorpInfoService.java

@@ -41,4 +41,6 @@ public interface WxCorpInfoService extends IService<WxCorpInfo> {
     public String syncTranslation(String authCorpid,String mediaId,String outPutFileName,String outputFileFormat) throws Exception;
 
     public String getSyncTranslationResult(String jobId) throws Exception;
+
+    public HttpRespMsg getUserPunchRecord(int companyId, String userId, LocalDateTime startDateTime, LocalDateTime endDateTime, boolean showLog);
 }

+ 174 - 0
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/service/impl/WxCorpInfoServiceImpl.java

@@ -5,6 +5,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.google.gson.JsonArray;
 import com.google.gson.JsonObject;
 import com.management.platform.controller.WeiXinCorpController;
 import com.management.platform.entity.*;
@@ -14,6 +15,7 @@ import com.management.platform.util.*;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.http.client.utils.HttpClientUtils;
+import org.apache.tomcat.jni.Local;
 import org.json.HTTP;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -22,6 +24,7 @@ import org.springframework.http.*;
 import org.springframework.stereotype.Service;
 import org.springframework.util.LinkedMultiValueMap;
 import org.springframework.util.MultiValueMap;
+import org.springframework.util.unit.DataUnit;
 import org.springframework.web.client.RestTemplate;
 import org.springframework.web.util.UriComponentsBuilder;
 import sun.net.www.http.HttpClient;
@@ -29,6 +32,7 @@ import sun.net.www.http.HttpClient;
 import javax.annotation.Resource;
 import java.io.*;
 import java.lang.reflect.Array;
+import java.math.BigDecimal;
 import java.net.URI;
 import java.text.SimpleDateFormat;
 import java.time.*;
@@ -55,6 +59,10 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
 
     public static final String GET_CHECKIN_DAYDATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckin_daydata?access_token=ACCESS_TOKEN";
 
+    public static final String GET_CHECKIN_DATA = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckindata?access_token=ACCESS_TOKEN";
+
+    public static final String GET_CHECKIN_OPTION = "https://qyapi.weixin.qq.com/cgi-bin/checkin/getcheckinoption?access_token=ACCESS_TOKEN";
+
 
     @Value("${suitId}")
     private String suitId;
@@ -452,6 +460,153 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         return msg;
     }
 
+    @Override
+    public HttpRespMsg getUserPunchRecord(int companyId, String userId, LocalDateTime startDateTime, LocalDateTime endDateTime, boolean showLog) {
+        HttpRespMsg msg = new HttpRespMsg();
+        WxCorpInfo corpInfo = wxCorpInfoMapper.selectOne(new QueryWrapper<WxCorpInfo>().eq("company_id", companyId));
+        if (corpInfo == null) {
+            //msg.setError("该企业未对接企业微信");
+            msg.setError(MessageUtils.message("wx.dockError"));
+            return msg;
+        }
+        String url = null;
+        try {
+            startDateTime = startDateTime.withHour(0).withMinute(0).withSecond(0).withNano(0);
+            long startTime = startDateTime.toEpochSecond(ZoneOffset.of("+8"));
+            endDateTime = endDateTime.withHour(23).withMinute(59).withSecond(0).withNano(0);
+            long endTime = endDateTime.toEpochSecond(ZoneOffset.of("+8"));
+            System.out.println("startTime=" + startTime + ",endTime=" + endTime);
+
+            int batchCount = 1;
+            int batchSize = 100;
+            int totalLength = 1;
+            List<String> corpwxUserIds = new ArrayList<>();
+            if (userId == null) {
+                //获取企业下的全部员工
+                List<User> users = userMapper.selectList(new QueryWrapper<User>().eq("company_id", companyId).isNotNull("corpwx_userid").eq("is_active", 1));
+                System.out.println("获取考勤记录users size==" + users.size());
+                corpwxUserIds = users.stream().map(User::getCorpwxUserid).collect(Collectors.toList());
+                totalLength = corpwxUserIds.size();
+                batchCount = totalLength / batchSize + (totalLength % batchSize == 0 ? 0 : 1);
+            } else {
+                //指定获取员工
+                User user = userMapper.selectById(userId);
+                corpwxUserIds.add(user.getCorpwxUserid());
+                System.out.println("获取corpwxuserid==" + user.getCorpwxUserid() + "的考勤记录");
+            }
+            //按批调用
+            for (int i = 0; i < batchCount; i++) {
+                int fromIndex = i * batchSize;
+                int toIndex = (i + 1) * batchSize;
+                if (toIndex > totalLength) toIndex = totalLength;
+                Object[] objects = corpwxUserIds.subList(fromIndex, toIndex).toArray(new String[0]);
+                reqPunchRecord(corpInfo, startTime, endTime, objects, showLog);
+            }
+        } catch (Exception exception) {
+            exception.printStackTrace();
+        }
+
+        return msg;
+    }
+
+    public void reqPunchRecord(WxCorpInfo corpInfo, long startTime, long endTime, Object[] objects, boolean showLog)throws Exception {
+        DateTimeFormatter mdFormat = DateTimeFormatter.ofPattern("yyyy/M/d");
+        LocalDateTime needDataTime = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
+        long dataTime = needDataTime.toEpochSecond(ZoneOffset.of("+8"));
+        String checkinOption = getCheckinOption(corpInfo, dataTime, objects);
+        JSONObject optionObject = JSONObject.parseObject(checkinOption);
+        JSONArray  optionDatas= optionObject.getJSONArray("info");
+        String url = GET_CHECKIN_DATA.replace("ACCESS_TOKEN", getCorpAccessToken(corpInfo));
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        System.out.println("" + objects.toString());
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("starttime", startTime);
+        reqParam.put("endtime", endTime);
+        reqParam.put("useridlist", objects);
+        reqParam.put("opencheckindatatype", 3);
+        HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
+        ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,
+                HttpMethod.POST, requestEntity, String.class);
+
+        if (responseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = responseEntity.getBody();
+            if (showLog) System.out.println(resp);
+            JSONObject json = JSONObject.parseObject(resp);
+            DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+            if (json.getIntValue("errcode") == 0) {
+                JSONArray checkindata = json.getJSONArray("checkindata");
+                System.out.println(checkindata);
+                for (int i = 0; i < objects.length; i++) {
+                    List<Integer> upList=new ArrayList<>();
+                    List<Integer> downList=new ArrayList<>();
+                    for (int j = 0; j < checkindata.size(); j++) {
+                        JSONObject jsonObject = checkindata.getJSONObject(j);
+                        if (jsonObject.get("userid").equals(objects[i])) {
+                            //todo: 获取最早上班打卡时间以及最晚下班打卡时间
+                            Integer time = (Integer) jsonObject.get("checkin_time");
+                            if (jsonObject.get("checkin_type").equals("上班打卡")) {
+                                upList.add(time);
+                            } else if(jsonObject.get("checkin_type").equals("下班打卡")) downList.add(time);
+                        }
+                    }
+                    double restTime = 0.0;//小时为单位
+                    for (int k = 0; k < optionDatas.size(); k++) {
+                        if(optionDatas.getJSONObject(k).get("userid").equals(objects[i])){
+                            JSONObject group = optionDatas.getJSONObject(k).getJSONObject("group");
+                            JSONArray workRules = group.getJSONArray("checkindate").getJSONObject(0).getJSONArray("checkintime");
+                            if (workRules.size() <= 1) {
+                                restTime = 1.0;//一个小时午休
+                            } else {
+                                restTime = 1.0 * (workRules.getJSONObject(1).getIntValue("work_sec") - workRules.getJSONObject(0).getIntValue("off_work_sec")) / 3600;
+                            }
+                        }
+                    }
+                    UserCorpwxTime userCorpwxTime=new UserCorpwxTime();
+                    userCorpwxTime.setCorpwxUserid((String) objects[i]);
+                    userCorpwxTime.setCompanyId(corpInfo.getCompanyId());
+                    for (Integer integer : upList) {
+                        if(objects[i].equals("woy9TkCAAArkpTq76GOJYsbYGgzk1g1w")){
+                            System.out.println("上班"+DateTimeUtil.getTimeFromSeconds(integer));
+                        }
+                    }
+                    for (Integer integer : downList) {
+                        if(objects[i].equals("woy9TkCAAArkpTq76GOJYsbYGgzk1g1w")){
+                            System.out.println("下班"+DateTimeUtil.getTimeFromSeconds(integer));
+                        }
+                    }
+                    if(upList.isEmpty()||downList.isEmpty()){
+                        continue;
+                    }
+                    Integer min = Collections.min(upList);
+                    Integer max = Collections.max(downList);
+                    String minTime = DateTimeUtil.getTimeFromSeconds(min);
+                    String maxTime = DateTimeUtil.getTimeFromSeconds(max);
+                    DateTimeFormatter df = DateTimeFormatter.ofPattern("HH:mm");
+                    userCorpwxTime.setStartTime(LocalTime.parse(minTime,df).plusHours(8).format(df));
+                    userCorpwxTime.setEndTime(LocalTime.parse(maxTime,df).plusHours(8).format(df));
+                    userCorpwxTime.setCreateDate(LocalDate.now());
+                    userCorpwxTime.setWxCorpid(corpInfo.getCorpid());
+                    userCorpwxTime.setWeekDay(LocalDate.now().getDayOfWeek().getValue());
+                    userCorpwxTime.setWeekDayTxt(DateTimeUtil.getWeekDayTxt(userCorpwxTime.getWeekDay()));
+                    BigDecimal bigDecimal=new BigDecimal(Duration.between(LocalTime.parse(minTime,df).plusHours(8),LocalTime.parse(maxTime,df).plusHours(8)).toMinutes());
+                    bigDecimal=bigDecimal.divide(BigDecimal.valueOf(60),1,BigDecimal.ROUND_HALF_UP).subtract(new BigDecimal(restTime));
+                    userCorpwxTime.setWorkHours(bigDecimal.doubleValue());
+                    System.out.println(userCorpwxTime);
+                    UserCorpwxTime item = userCorpwxTimeMapper.selectOne(new QueryWrapper<UserCorpwxTime>().eq("corpwx_userid", (String) objects[i])
+                            .eq("create_date", LocalDate.now()));
+                    if (item != null) {
+                        userCorpwxTime.setId(item.getId());
+                        //已存在记录,进行更新
+                        userCorpwxTimeMapper.updateById(userCorpwxTime);
+                    } else {
+                        userCorpwxTimeMapper.insert(userCorpwxTime);
+                    }
+                }
+            }
+        }
+    }
+
     @Override
     public HttpRespMsg syncMembByCardTime(WxCorpInfo wxCorpInfo) {
         HttpRespMsg msg = new HttpRespMsg();
@@ -527,6 +682,25 @@ public class WxCorpInfoServiceImpl extends ServiceImpl<WxCorpInfoMapper, WxCorpI
         return msg;
     }
 
+    private String getCheckinOption(WxCorpInfo corpInfo,long dataTime,Object[] objects) throws  Exception{
+        String url = GET_CHECKIN_OPTION.replace("ACCESS_TOKEN", getCorpAccessToken(corpInfo));
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_JSON);
+        System.out.println("" + objects.toString());
+        JSONObject reqParam = new JSONObject();
+        reqParam.put("datetime", dataTime);
+        reqParam.put("useridlist", objects);
+        HttpEntity<String> requestEntity = new HttpEntity<String>(reqParam.toJSONString(), headers);
+        ResponseEntity<String> responseEntity = this.restTemplate.exchange(url,
+                HttpMethod.POST, requestEntity, String.class);
+
+        if (responseEntity.getStatusCode() == HttpStatus.OK) {
+            String resp = responseEntity.getBody();
+            return resp;
+        }
+        return "";
+    }
+
 
     private void reqOnceCardTime(WxCorpInfo corpInfo, long startTime, long endTime, Object[] objects, boolean showLog) throws Exception {
         DateTimeFormatter mdFormat = DateTimeFormatter.ofPattern("yyyy/M/d");

+ 18 - 2
fhKeeper/formulahousekeeper/management-platform/src/main/java/com/management/platform/task/TimingTask.java

@@ -472,8 +472,21 @@ public class TimingTask {
         }
     }
 
+    @Scheduled(cron = "0 30,0/5 17-19 * * ?")
+    public void  getClockRecordWithCorpWx(){
+        /*if(isDev) return;*/
+        //todo: 有限制无考勤不填报的情况才获取
+        LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX).withSecond(0).withNano(0);
+        List<TimeType> typeList = timeTypeMapper.selectList(new QueryWrapper<TimeType>().eq("not_allowed_no_attendance", 1));
+        for (TimeType type : typeList) {
+            Integer companyId = type.getCompanyId();
+            wxCorpInfoService.getUserPunchRecord(companyId, null, start, end, false);
+        }
+    }
+
     public static void main(String[] args) {
-        int passwordLength = 30;
+        /*int passwordLength = 30;
         List<String> stringList=new ArrayList<>();
         new SecureRandom().ints(passwordLength, 0, VALID_TOKEN_CHARS.size())
                 .map(VALID_TOKEN_CHARS::get).forEach(v->stringList.add(String.valueOf((char) v)));
@@ -481,7 +494,10 @@ public class TimingTask {
         for (String s : stringList) {
             token+=s;
         }
-        System.out.println(token);
+        System.out.println(token);*/
+        LocalDateTime start = LocalDateTime.of(LocalDate.now(), LocalTime.MIN);
+        LocalDateTime end = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
+        System.out.println(start+"  "+end);
     }
 
     //发送上周填写的工时统计

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 49545 - 8815
fhKeeper/formulahousekeeper/management-platform/workTime.log