Prechádzať zdrojové kódy

【企业微信】【打卡记录对接优化:1.新增根据设备打卡获取打卡记录 2.上次对接时间取获取的打卡数据时间】

wuyx 1 týždeň pred
rodič
commit
9164659949

+ 12 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/OaSdk.java

@@ -36,6 +36,18 @@ public class OaSdk extends BaseSdk {
         assertOK(resp);
         return resp.getBody().getCheckindata();
     }
+    /*
+     *获取设备打卡数据
+    * */
+    public List<GetCheckinByDevDataResp.CheckinData> getCheckinDataByDev(GetCheckinByDevDataReq req) {
+        ResponseEntity<GetCheckinByDevDataResp> resp = restTemplate.postForEntity(
+                baseUrl + "/cgi-bin/hardware/get_hardware_checkin_data?access_token={access_token}",
+                req.build(),
+                GetCheckinByDevDataResp.class,
+                new ModelMap("access_token", getAccessToken(CHECKIN_AGENT_CODE)));
+        assertOK(resp);
+        return resp.getBody().getCheckindata();
+    }
 
     /**
      * 获取打卡规则

+ 51 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/dto/GetCheckinByDevDataReq.java

@@ -0,0 +1,51 @@
+package com.usoftchina.qywx.sdk.dto;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author WUYX
+ */
+public class GetCheckinByDevDataReq {
+
+    private final CheckinType type;
+    private final long startTime;
+    private final long endTime;
+    private final List<String> userList;
+
+    public GetCheckinByDevDataReq(CheckinType type, long startTime, long endTime, List<String> userList) {
+        this.type = type;
+        this.startTime = startTime;
+        this.endTime = endTime;
+        this.userList = userList;
+    }
+
+    public Map<String, Object> build() {
+        Map<String, Object> data = new HashMap<>(4);
+        data.put("filter_type", type.code);
+        data.put("starttime", startTime);
+        data.put("endtime", endTime);
+        data.put("useridlist", userList);
+        return data;
+    }
+
+    /**
+     * 过滤类型,1表示按打卡时间过滤,2表示按设备上传打卡记录的时间过滤,默认值是1
+     */
+    public enum CheckinType {
+        /**
+         * 按打卡时间过滤
+         */
+        BYCHECKIN(1),
+        /**
+         * 按设备上传打卡记录的时间
+         */
+        BYUPLOAD(2);
+        private final int code;
+
+        CheckinType(int code) {
+            this.code = code;
+        }
+    }
+}

+ 67 - 0
qywx-sdk/src/main/java/com/usoftchina/qywx/sdk/dto/GetCheckinByDevDataResp.java

@@ -0,0 +1,67 @@
+package com.usoftchina.qywx.sdk.dto;
+
+import java.util.List;
+
+/**
+ * @author wuyx
+ */
+public class GetCheckinByDevDataResp extends BaseResp{
+
+    private List<CheckinData> checkindata;
+
+    public List<CheckinData> getCheckindata() {
+        return checkindata;
+    }
+
+    public void setCheckindata(List<CheckinData> checkindata) {
+        this.checkindata = checkindata;
+    }
+
+    public static class CheckinData {
+        private String userid;
+        /**
+         * 打卡时间。Unix时间戳
+         */
+        private Long checkin_time;
+        /**
+         * 打卡设备的sn
+         */
+        private String device_sn;
+        /**
+         * 打卡设备名
+         */
+        private String device_name;
+
+        public String getUserid() {
+            return userid;
+        }
+
+        public void setUserid(String userid) {
+            this.userid = userid;
+        }
+
+        public Long getCheckin_time() {
+            return checkin_time;
+        }
+
+        public void setCheckin_time(Long checkin_time) {
+            this.checkin_time = checkin_time;
+        }
+
+        public String getDevice_sn() {
+            return device_sn;
+        }
+
+        public void setDevice_sn(String device_sn) {
+            this.device_sn = device_sn;
+        }
+
+        public String getDevice_name() {
+            return device_name;
+        }
+
+        public void setDevice_name(String device_name) {
+            this.device_name = device_name;
+        }
+    }
+}

+ 70 - 0
uas-office-dingtalk-server/src/main/resources/erp_schema.json

@@ -86,5 +86,75 @@
         "defaultValue": 0
       }
     ]
+  },{
+  "name": "MOBILE_OUTSIGN",
+  "columns": [
+    {
+      "name": "MO_MAN",
+      "type": "varchar2(50)"
+    },{
+      "name": "mo_groupname",
+      "type": "VARCHAR2(100)"
+    },{
+      "name": "mo_checkintype",
+      "type": "VARCHAR2(100)"
+    },{
+      "name": "mo_exceptiontype",
+      "type": "VARCHAR2(500)"
+    },{
+      "name": "mo_wifiname",
+      "type": "VARCHAR2(200)"
+    },{
+      "name": "mo_notes",
+      "type": "VARCHAR2(500)"
+    },{
+      "name": "mo_wifimac",
+      "type": "VARCHAR2(200)"
+    },{
+      "name": "mo_mediaids",
+      "type": "VARCHAR2(4000)"
+    },{
+      "name": "mo_lat",
+      "type": "VARCHAR2(20)"
+    },{
+      "name": "mo_lng",
+      "type": "VARCHAR2(20)"
+    }
+  ]
+},{
+  "name": "MOBILE_OUTSIGN",
+  "columns": [
+    {
+      "name": "MO_MAN",
+      "type": "varchar2(50)"
+    },{
+      "name": "mo_groupname",
+      "type": "VARCHAR2(100)"
+    },{
+      "name": "mo_checkintype",
+      "type": "VARCHAR2(100)"
+    },{
+      "name": "mo_exceptiontype",
+      "type": "VARCHAR2(500)"
+    },{
+      "name": "mo_wifiname",
+      "type": "VARCHAR2(200)"
+    },{
+      "name": "mo_notes",
+      "type": "VARCHAR2(500)"
+    },{
+      "name": "mo_wifimac",
+      "type": "VARCHAR2(200)"
+    },{
+      "name": "mo_mediaids",
+      "type": "VARCHAR2(4000)"
+    },{
+      "name": "mo_lat",
+      "type": "VARCHAR2(20)"
+    },{
+      "name": "mo_lng",
+      "type": "VARCHAR2(20)"
+    }
+  ]
   }
 ]

+ 60 - 0
uas-office-qywx-server/src/main/resources/erp_schema.json

@@ -150,6 +150,33 @@
       {
         "name": "MO_MAN",
         "type": "varchar2(50)"
+      },{
+        "name": "mo_groupname",
+        "type": "VARCHAR2(100)"
+      },{
+        "name": "mo_checkintype",
+        "type": "VARCHAR2(100)"
+      },{
+        "name": "mo_exceptiontype",
+        "type": "VARCHAR2(500)"
+      },{
+        "name": "mo_wifiname",
+        "type": "VARCHAR2(200)"
+      },{
+        "name": "mo_notes",
+        "type": "VARCHAR2(500)"
+      },{
+        "name": "mo_wifimac",
+        "type": "VARCHAR2(200)"
+      },{
+        "name": "mo_mediaids",
+        "type": "VARCHAR2(4000)"
+      },{
+        "name": "mo_lat",
+        "type": "VARCHAR2(20)"
+      },{
+        "name": "mo_lng",
+        "type": "VARCHAR2(20)"
       }
     ]
   },
@@ -162,5 +189,38 @@
         "defaultValue": 0
       }
     ]
+  },
+  {
+    "name": "CardLog",
+    "columns": [
+      {
+        "name": "cl_groupname",
+        "type": "varchar2(100)"
+      },{
+        "name": "cl_checkintype",
+        "type": "varchar2(100)"
+      },{
+        "name": "cl_exceptiontype",
+        "type": "varchar2(500)"
+      },{
+        "name": "cl_wifiname",
+        "type": "varchar2(100)"
+      },{
+        "name": "cl_notes",
+        "type": "varchar2(500)"
+      },{
+        "name": "cl_wifimac",
+        "type": "varchar2(500)"
+      },{
+        "name": "cl_mediaids",
+        "type": "varchar2(4000)"
+      },{
+        "name": "cl_lat",
+        "type": "VARCHAR2(20)"
+      },{
+        "name": "cl_lng",
+        "type": "VARCHAR2(20)"
+      }
+    ]
   }
 ]

+ 22 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/entity/CardLog.java

@@ -1,5 +1,6 @@
 package com.usoftchina.uas.office.qywx.entity;
 
+import com.usoftchina.qywx.sdk.dto.GetCheckinByDevDataResp;
 import com.usoftchina.qywx.sdk.dto.GetCheckinDataResp;
 
 import java.util.Date;
@@ -50,6 +51,27 @@ public class CardLog {
         this.cl_lng = data.getLng();
     }
 
+    public CardLog(Employee employee, GetCheckinByDevDataResp.CheckinData data) {
+        this.cl_sourcetype = "WeChat";
+        this.cl_time = new Date(data.getCheckin_time() * 1000);
+        this.cl_cardcode = employee.getEm_code();
+        this.cl_emid = employee.getEm_id();
+        this.cl_emcode = employee.getEm_code();
+        this.cl_emname = employee.getEm_name();
+        this.cl_address = data.getDevice_name();
+        this.cl_phone = employee.getEm_mobile();
+        this.cl_location = data.getDevice_name();
+        this.cl_groupname = "";
+        this.cl_checkintype ="";
+        this.cl_exceptiontype = "";
+        this.cl_wifiname = "";
+        this.cl_notes = "设备打卡";
+        this.cl_wifimac = "";
+        this.cl_mediaids = data.getDevice_sn();
+        this.cl_lat = 0L;
+        this.cl_lng = 0L;
+    }
+
     public Integer getCl_id() {
         return cl_id;
     }

+ 16 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/service/UasCardLogService.java

@@ -6,6 +6,9 @@ import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
 import org.springframework.jdbc.core.simple.SimpleJdbcInsert;
 import org.springframework.stereotype.Service;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+
 /**
  * @author yingp
  * @date 2020/2/17
@@ -18,4 +21,17 @@ public class UasCardLogService extends AbstractService {
         SimpleJdbcInsert insert = new SimpleJdbcInsert(jdbcTemplate);
         insert.withTableName("CardLog").execute(new BeanPropertySqlParameterSource(log));
     }
+    public void saveWhenNotExist(CardLog log) {
+        DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        jdbcTemplate.execute("insert into CardLog(cl_id,cl_sourcetype,cl_time" +
+                ",cl_cardcode,cl_emid,cl_emcode,cl_emname,cl_address" +
+                ",cl_phone,cl_location,cl_groupname,cl_checkintype,cl_exceptiontype,cl_wifiname" +
+                ",cl_notes,cl_wifimac,cl_mediaids,cl_lat,cl_lng)" +
+                "select CARDLOG_SEQ.NEXTVAL,'"+log.getCl_sourcetype()+"',to_date('"+format.format(log.getCl_time())+"','yyyy-mm-dd hh24:mi:ss')" +
+                ",'"+log.getCl_cardcode()+"',"+log.getCl_emid()+",'"+log.getCl_emcode()+"','"+log.getCl_emname()+"','"+log.getCl_address()+"'" +
+                ",'"+log.getCl_phone()+"','"+log.getCl_location()+"','"+log.getCl_groupname()+"','"+log.getCl_checkintype()+"','"+log.getCl_exceptiontype()+"'" +
+                ",'"+log.getCl_wifiname()+"','"+log.getCl_notes()+"','"+log.getCl_wifimac()+"','"+log.getCl_mediaids()+"','"+log.getCl_lat()+"','"+log.getCl_lng()+"'" +
+                " from dual where not exists (select 1 from CardLog where cl_emcode='"+log.getCl_emcode()+"' AND CL_TIME = TO_DATE('"+format.format(log.getCl_time())+"','YYYY-MM-DD HH24:MI:SS') )");
+    }
+
 }

+ 36 - 0
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/service/UasConfigsService.java

@@ -0,0 +1,36 @@
+package com.usoftchina.uas.office.qywx.service;
+
+import com.usoftchina.uas.office.service.AbstractService;
+import org.springframework.dao.EmptyResultDataAccessException;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author wuyx
+ * @date 2024/7/03
+ * @desc: 参数配置判断
+ */
+@Service
+public class UasConfigsService extends AbstractService {
+    public boolean checkEnable(String caller,String code){
+        boolean enableFlag = false;
+        try{
+           int count = jdbcTemplate.queryForObject( "select count(1) from configs where caller ='"+caller+"' and code = '"+code+"' and nvl(DATA,'0')<>'0'",Integer.class);
+            enableFlag= count > 0;
+        } catch (EmptyResultDataAccessException e) {
+
+        }
+        return enableFlag;
+    }
+
+
+    public String getDBSetting(String caller,String code){
+        String configData = null;
+        try{
+            configData = jdbcTemplate.queryForObject( "select nvl(DATA,'0') DATA from configs where caller ='"+caller+"' and code = '"+code+"' ",String.class);
+        } catch (EmptyResultDataAccessException e) {
+
+        }
+        return configData;
+    }
+
+}

+ 70 - 15
uas-office-qywx/src/main/java/com/usoftchina/uas/office/qywx/task/QywxCheckinTask.java

@@ -1,6 +1,8 @@
 package com.usoftchina.uas.office.qywx.task;
 
 import com.usoftchina.qywx.sdk.OaSdk;
+import com.usoftchina.qywx.sdk.dto.GetCheckinByDevDataReq;
+import com.usoftchina.qywx.sdk.dto.GetCheckinByDevDataResp;
 import com.usoftchina.qywx.sdk.dto.GetCheckinDataReq;
 import com.usoftchina.qywx.sdk.dto.GetCheckinDataResp;
 import com.usoftchina.uas.office.entity.DataCenter;
@@ -10,6 +12,7 @@ import com.usoftchina.uas.office.qywx.entity.Employee;
 import com.usoftchina.uas.office.qywx.entity.OutSign;
 import com.usoftchina.uas.office.qywx.manage.service.QywxSettingService;
 import com.usoftchina.uas.office.qywx.service.UasCardLogService;
+import com.usoftchina.uas.office.qywx.service.UasConfigsService;
 import com.usoftchina.uas.office.qywx.service.UasEmployeeService;
 import com.usoftchina.uas.office.qywx.service.UasOutSignService;
 import org.slf4j.Logger;
@@ -20,11 +23,15 @@ import org.springframework.stereotype.Component;
 import org.springframework.util.CollectionUtils;
 import org.springframework.util.StringUtils;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
 import java.time.LocalDate;
 import java.time.ZoneId;
+import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
@@ -49,6 +56,8 @@ public class QywxCheckinTask {
 
     @Autowired
     private UasOutSignService outSignService;
+    @Autowired
+    private UasConfigsService uasConfigsService;
 
     /**
      * 每次最多条数据
@@ -77,23 +86,51 @@ public class QywxCheckinTask {
                     Long lastTime = settingService.getCheckinTime();
                     if (lastTime == null) {
                         lastTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                    } else {
+                        //@wuyx 默认记录上次对接打卡的最后一次时间,且时间跨度超过1个月的自动更新为当前时间
+                        Calendar cal = Calendar.getInstance();
+                        cal.add(Calendar.MONTH, -1);
+                        long oneMonthAgo = cal.getTimeInMillis();
+                        if (lastTime < oneMonthAgo) {
+                            lastTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli();
+                        }
                     }
+                    logger.debug("get checkin lastTime {}", lastTime);
+//                    lastTime = 1725120000000L;
                     Date now = new Date();
                     //@update 反馈:2021040337 每次往上+1秒 偶尔会导致系统漏获取一条数据
-                    long unixStartTime = lastTime / 1000 ;
+                    long unixStartTime = lastTime / 1000;
                     long unixEndTime = now.getTime() / 1000;
-                    logger.debug("get checkin unixStartTime  {} enable", lastTime);
+                    logger.debug("get checkin unixStartTime  {} unixEndTime {} enable", unixStartTime,unixEndTime);
+                    DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    AtomicReference<Long> endTime = new AtomicReference<>(lastTime / 1000);
                     Stream.iterate(0, n -> n + 1)
                             .limit((int) Math.ceil((double) employees.size() / maxSeed)).forEach(page -> {
-                        GetCheckinDataReq req = new GetCheckinDataReq(GetCheckinDataReq.CheckinType.ALL,
-                                unixStartTime, unixEndTime,
-                                employees.stream().skip(page * maxSeed).limit(maxSeed).map(Employee::getEm_qywx).collect(Collectors.toList()));
-                        logger.debug("get checkin employeeCount  {} ",employees.stream().skip(page * maxSeed).limit(maxSeed).map(Employee::getEm_qywx).count() );
-                        List<GetCheckinDataResp.CheckinData> dataList = oaSdk.getCheckinData(req);
-                        logger.debug("get checkin dataSize  {} ", dataList.size());
-                        saveCheckinData(employeeMap, dataList);
+                        List<String> userList = employees.stream().skip(page * maxSeed).limit(maxSeed).map(Employee::getEm_qywx).collect(Collectors.toList());
+                        logger.debug("get checkin employeeCount  {} ", userList.size());
+                        String configData = uasConfigsService.getDBSetting("CardLog","getCheckinDataType");
+                        //联戎: 根据企业微信打卡方式获取打卡记录 0 仅企业微信打卡 1: 仅设备对接打卡 2:企业微信打卡和设备打卡
+                        if(configData == null || !"1".equals(configData)){
+                            //企业微信打卡记录
+                            GetCheckinDataReq req = new GetCheckinDataReq(GetCheckinDataReq.CheckinType.ALL,
+                                    unixStartTime, unixEndTime,userList
+                            );
+                            List<GetCheckinDataResp.CheckinData> dataList = oaSdk.getCheckinData(req);
+                            logger.debug("get checkin dataSize  {} ", dataList.size());
+                            endTime.set(saveCheckinData(endTime.get(), employeeMap, dataList));
+                            logger.debug("get checkin setCheckinTime-1  {} ", format.format(new Date((endTime.get() * 1000))));
+                        }
+                        //设备对接 联戎
+                        if(configData!=null&&!"0".equals(configData)){
+                            GetCheckinByDevDataReq reqByDev = new GetCheckinByDevDataReq(GetCheckinByDevDataReq.CheckinType.BYUPLOAD,
+                                    unixStartTime, unixEndTime,userList);
+                            List<GetCheckinByDevDataResp.CheckinData> dataListByDev = oaSdk.getCheckinDataByDev(reqByDev);
+                            logger.debug("get checkin ByDev dataSize  {} ", dataListByDev.size());
+                            endTime.set(saveCheckinByDevData(endTime.get(), employeeMap, dataListByDev));
+                            logger.debug("get checkin setCheckinTime-2  {} ", format.format(new Date((endTime.get() * 1000))));
+                        }
                     });
-                    settingService.setCheckinTime(now);
+                    settingService.setCheckinTime(new Date((endTime.get() * 1000)));
                 }
             } finally {
                 DataSourceHolder.clear();
@@ -102,21 +139,39 @@ public class QywxCheckinTask {
         logger.debug("get checkin data === end ===");
     }
 
-    private void saveCheckinData(Map<String, Employee> employeeMap, List<GetCheckinDataResp.CheckinData> dataList) {
-        dataList.forEach(data -> {
+    private Long saveCheckinData(Long endTime, Map<String, Employee> employeeMap, List<GetCheckinDataResp.CheckinData> dataList) {
+        for (GetCheckinDataResp.CheckinData data : dataList) {
             if (!data.getException_type().equals("未打卡")) {
                 Employee employee = employeeMap.get(data.getUserid());
                 logger.debug("get checkin data, user {}, type {}", employee.getEm_name(), data.getCheckin_type());
-                    if ("外出打卡".equals(data.getCheckin_type())) {
+                if (endTime < data.getCheckin_time()) {
+                    endTime = data.getCheckin_time();
+                }
+                if ("外出打卡".equals(data.getCheckin_type())) {
                     // 外勤签到 插入外勤打卡记录
                     outSignService.save(new OutSign(employee, data));
                 } else {
                     // 在企业微信设置了考勤打卡规则的,才同步到uas
                     if (!StringUtils.isEmpty(data.getGroupname())) {
-                        cardLogService.save(new CardLog(employee, data));
+                        cardLogService.saveWhenNotExist(new CardLog(employee, data));
                     }
                 }
             }
-        });
+        }
+        ;
+        return endTime;
+    }
+    private Long saveCheckinByDevData(Long endTime, Map<String, Employee> employeeMap, List<GetCheckinByDevDataResp.CheckinData> dataList) {
+        for (GetCheckinByDevDataResp.CheckinData data : dataList) {
+            Employee employee = employeeMap.get(data.getUserid());
+            DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            logger.debug("get checkin ByDev data, user {}, type {}, checkinTime {}", employee.getEm_name(), data.getDevice_name()
+                    , format.format(new Date((data.getCheckin_time() * 1000))));
+            cardLogService.saveWhenNotExist(new CardLog(employee, data));
+            if (endTime < data.getCheckin_time()) {
+                endTime = data.getCheckin_time();
+            }
+        }
+        return endTime;
     }
 }