应公司要求,公司人事HR系统需要对接钉钉考勤数据,所以需要获取钉钉的打卡记录、出差、外出、请假、调岗的数据,然后转换成HR系统数据。
1、首先需要管理员登录钉钉开放平台,创建应用。
说明 只有管理员和子管理员可登录开发者后台。
钉钉开放平台:钉钉开放平台能力中心
2、在应用开发页面,选择企业内部开发,然后单击创建应用。
3、填写应用的基本信息,然后单击确定创建。
应用创建后,在基础信息页可获取AppKey和AppSecret。
如果是定制服务商创建的应用,应用的key为CustomKey。开发者需要使用应用的CustomKey和CustomSecret获取调用服务端API的授权凭证。
在应用详情页,单击开发管理配置应用的基本信息。
配置 |
是否必选 |
配置说明 |
---|---|---|
开发模式 |
H5微应用必须配置 |
选择开发模式:
|
服务器出口IP |
是 |
输入调用钉钉服务端API时使用的IP即企业服务器的公网IP,多个IP请以英文逗号","隔开,支持带一个*号通配符的IP格式。 |
应用首页地址 |
H5微应用必须配置 |
输入应用首页URL,在移动端工作台点击应用图标会跳转到此页面。 可输入后端服务部署的服务器的IP或域名。例如: |
PC端首页地址 |
否 |
输入在PC端钉钉工作台上打开应用的地址。链接地址必须以http或https开头。 说明如果未填写,在钉钉PC端工作台点击应用图标时,会提示“电脑版暂不支持显示,请用手机钉钉扫描下方二维码查看”。只能在手机钉钉客户端使用该应用。 |
管理后台地址 |
否 |
输入管理员在钉钉管理后台访问该应用的地址。 |
由于jar是在本地项目,不是中央Maven库,所以要如下引用
com.taobao.top
top-api-sdk-dev
ding-open-mc-SNAPSHOT
system
${pom.basedir}/src/main/webapp/WEB-INF/lib/taobao-sdk-java-auto_1479188381469-20210517.jar
公司项目使用mybatis,所以部分代码忽略。
process_code:审批流的唯一码。在审批流编辑页面的URL中获取。
DingDingUtil 与钉钉对接工具类
import com.dingtalk.api.DefaultDingTalkClient;
import com.dingtalk.api.DingTalkClient;
import com.dingtalk.api.request.*;
import com.dingtalk.api.response.*;
import com.taobao.api.ApiException;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
/**
* 钉钉工具类
*/
@Slf4j
public class DingDingUtil {
private final static String SYSTEM_ERROR ="SYSTEM_ERROR";
private final static String APPKEY ="";
private final static String APPSECRET="";
private final static Long AGENTID = 0L;
public final static String LEAVE_PROCESS_CODE = "PROC-70A9A9C2-BF877C09E3FE";
public final static String PUBLIC_PROCESS_CODE = "PROC-C6B6F367-BE545F51D9E0";
public final static String TRAVELWORK_PROCESS_CODE = "PROC-8763D6A9-A788E7CEC119";
public final static String TRANSFER_PROCESS_CODE = "PROC-E05FD7DE-5A2B9D7CD6AC";
//获取token
public static String getToken (){
Object object = LocalCacheClient.get("access_token");
if(object != null){
return object.toString();
}
DefaultDingTalkClient client = new
DefaultDingTalkClient("https://oapi.dingtalk.com/gettoken");
OapiGettokenRequest request = new OapiGettokenRequest();
request.setAppkey(DingDingUtil.APPKEY);
request.setAppsecret(DingDingUtil.APPSECRET);
request.setHttpMethod("GET");
try {
OapiGettokenResponse response = client.execute(request);
LocalCacheClient.set("access_token", response.getAccessToken(),7200*1000);
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.getAccessToken();
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取部门列表
public static List getDepartment(){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/department/listsub");
OapiV2DepartmentListsubRequest request = new OapiV2DepartmentListsubRequest();
//获取根部门下所有部门列表 根部门的部门id为1
// request.setDeptId(1L);
request.setHttpMethod("GET");
try {
OapiV2DepartmentListsubResponse response = client.execute(request, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess() ? response.getResult():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取部门下的所有用户列表
public static List getDepartmentUserId(Long departmentId){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/user/listid");
OapiUserListidRequest req = new OapiUserListidRequest();
req.setDeptId(departmentId);
try {
OapiUserListidResponse response = client.execute(req, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess()?response.getResult().getUseridList():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取部门下的所有用户列表
public static OapiV2UserListResponse.PageResult getDepartmentUser(Long departmentId, long cursor, long size){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/v2/user/list");
OapiV2UserListRequest request = new OapiV2UserListRequest();
request.setDeptId(departmentId);
request.setCursor(cursor);
request.setSize(size);
request.setOrderField("modify_desc");
request.setHttpMethod("GET");
try {
OapiV2UserListResponse response = client.execute(request, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess()?response.getResult():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取钉钉考勤记录
public static List getAttendanceList(String startWorkDate, String endWorkDate, List userIdList, long offset, long limit) {
// 通过调用接口获取考勤打卡结果
DingTalkClient clientDingTalkClient = new DefaultDingTalkClient("https://oapi.dingtalk.com/attendance/list");
OapiAttendanceListRequest requestAttendanceListRequest = new OapiAttendanceListRequest();
// 查询考勤打卡记录的起始工作日
requestAttendanceListRequest.setWorkDateFrom(startWorkDate);
// 查询考勤打卡记录的结束工作日
requestAttendanceListRequest.setWorkDateTo(endWorkDate);
// 员工在企业内的userid列表,最多不能超过50个。
requestAttendanceListRequest.setUserIdList(userIdList);
// 表示获取考勤数据的起始点
requestAttendanceListRequest.setOffset(offset);
// 表示获取考勤数据的条数,最大不能超过50条。
requestAttendanceListRequest.setLimit(limit);
OapiAttendanceListResponse response = null;
try {
response = clientDingTalkClient.execute(requestAttendanceListRequest,DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess()?response.getRecordresult():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//给用户推送消息(文字消息)
public static Object pushUser(String userIds,String content){
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/message/corpconversation/asyncsend_v2");
OapiMessageCorpconversationAsyncsendV2Request request = new OapiMessageCorpconversationAsyncsendV2Request();
request.setUseridList(userIds);
request.setAgentId(AGENTID);
request.setToAllUser(false);
OapiMessageCorpconversationAsyncsendV2Request.Msg msg = new OapiMessageCorpconversationAsyncsendV2Request.Msg();
msg.setMsgtype("text");
msg.setText(new OapiMessageCorpconversationAsyncsendV2Request.Text());
msg.getText().setContent(content);
request.setMsg(msg);
try {
OapiMessageCorpconversationAsyncsendV2Response response = client.execute(request, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取审批实例ID列表
public static OapiProcessinstanceListidsResponse.PageResult getProcessinstanceListid(String processCode, Long startTime, Long endTime, long cursor, long size) {
try {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/listids");
OapiProcessinstanceListidsRequest request = new OapiProcessinstanceListidsRequest();
request.setProcessCode(processCode);
request.setStartTime(startTime);
if(endTime != null) {
request.setEndTime(endTime);
}
request.setSize(size);
request.setCursor(cursor);
OapiProcessinstanceListidsResponse response = client.execute(request, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess()?response.getResult():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
//获取审批实例详情
public static OapiProcessinstanceGetResponse.ProcessInstanceTopVo getProcessinstanceInfo(String processInstanceId) {
try {
DingTalkClient client = new DefaultDingTalkClient("https://oapi.dingtalk.com/topapi/processinstance/get");
OapiProcessinstanceGetRequest request = new OapiProcessinstanceGetRequest();
request.setProcessInstanceId(processInstanceId);
OapiProcessinstanceGetResponse response = client.execute(request, DingDingUtil.getToken());
if(!response.isSuccess()) {
log.error("调用钉钉接口失败:"+response.getMessage());
}
return response.isSuccess()?response.getProcessInstance():null;
} catch (ApiException e) {
log.error(DingDingUtil.SYSTEM_ERROR, e);
}
return null;
}
}
LocalCacheClient 本地缓存工具
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* 本地缓存工具
*/
public class LocalCacheClient {
// 缓存map
private static Map cacheMap = new HashMap();
// 缓存有效期map
private static Map expireTimeMap = new HashMap();
/**
* 获取指定的value,如果key不存在或者已过期,则返回null
* @param key
* @return
*/
public static Object get(String key) {
if (!cacheMap.containsKey(key)) {
return null;
}
if (expireTimeMap.containsKey(key)) {
if (expireTimeMap.get(key) < System.currentTimeMillis()) { // 缓存失效,已过期
return null;
}
}
return cacheMap.get(key);
}
/**
* @param key
* @param
* @return
*/
public static T getT(String key) {
Object obj = get(key);
return obj == null ? null : (T) obj;
}
/**
* 设置value(不过期)
* @param key
* @param value
*/
public static void set(String key, Object value) {
cacheMap.put(key, value);
}
/**
* 设置value
* @param key
* @param value
* @param millSeconds 过期时间(毫秒)
*/
public static void set(final String key, Object value, int millSeconds) {
final long expireTime = System.currentTimeMillis() + millSeconds;
cacheMap.put(key, value);
expireTimeMap.put(key, expireTime);
if (cacheMap.size() > 2) { // 清除过期数据
new Thread(new Runnable() {
public void run() {
// 此处若使用foreach进行循环遍历,删除过期数据,会抛出java.util.ConcurrentModificationException异常
Iterator> iterator = cacheMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry entry = iterator.next();
if (expireTimeMap.containsKey(entry.getKey())) {
long expireTime = expireTimeMap.get(key);
if (System.currentTimeMillis() > expireTime) {
iterator.remove();
expireTimeMap.remove(entry.getKey());
}
}
}
}
}).start();
}
}
/**
* key是否存在
* @param key
* @return
*/
public static boolean isExist(String key) {
return cacheMap.containsKey(key);
}
}
对接钉钉业务代码
单独获取钉钉人员、部门方法
@Test
public void doBaseTask() {
log.info("--------------------------钉钉人员部门基本任务开始-----------------------");
Date now = new Date();
try {
List departmentList = DingDingUtil.getDepartment();
if(departmentList != null && departmentList.size() > 0) {
List userIdList = new ArrayList<>();
List dingdingDeptList = new ArrayList<>();
List userList = new ArrayList();
for(OapiV2DepartmentListsubResponse.DeptBaseResponse department:departmentList) {
long cursor = 0L;
long size = 50L;
OapiV2UserListResponse.PageResult userPageResult = DingDingUtil.getDepartmentUser(department.getDeptId(), cursor, size);
while (userPageResult != null && userPageResult.getHasMore()) {
userList.addAll(userPageResult.getList());
cursor = userPageResult.getNextCursor();
userPageResult = DingDingUtil.getDepartmentUser(department.getDeptId(), cursor, size);
}
if(userPageResult != null && userPageResult.getList() != null && userPageResult.getList().size() > 0) {
userList.addAll(userPageResult.getList());
}
HrDingdingDept hrDingdingDept = new HrDingdingDept();
hrDingdingDept.setDeptId(department.getDeptId());
hrDingdingDept.setName(department.getName());
hrDingdingDept.setParentId(department.getParentId());
hrDingdingDept.setUpdateTime(now);
dingdingDeptList.add(hrDingdingDept);
}
hrDingdingService.insertOrUpdateDept(dingdingDeptList);
if(userList != null && userList.size() > 0) {
List hrDingdingUserList = new ArrayList<>();
for(OapiV2UserListResponse.ListUserResponse user:userList) {
userIdList.add(user.getUserid());
HrDingdingUser hrDingdingUser = new HrDingdingUser();
hrDingdingUser.setUserid(user.getUserid());
hrDingdingUser.setUnionid(user.getUnionid());
hrDingdingUser.setName(user.getName());
hrDingdingUser.setAvatar(user.getAvatar());
hrDingdingUser.setStateCode(user.getStateCode());
hrDingdingUser.setMobile(user.getMobile());
hrDingdingUser.setHideMobile(user.getHideMobile()?"true":"false");
hrDingdingUser.setTelephone(user.getTelephone());
hrDingdingUser.setJobNumber(user.getJobNumber());
hrDingdingUser.setTitle(user.getTitle());
hrDingdingUser.setEmail(user.getEmail());
hrDingdingUser.setOrgEmail(user.getOrgEmail());
hrDingdingUser.setWorkPlace(user.getWorkPlace());
hrDingdingUser.setRemark(user.getRemark());
hrDingdingUser.setDeptIdList(JSON.toJSONString(user.getDeptIdList()));
hrDingdingUser.setExtension(user.getExtension());
hrDingdingUser.setAdmin(user.getAdmin()?"true":"false");
hrDingdingUser.setBoss(user.getBoss()?"true":"false");
hrDingdingUser.setLeader(user.getLeader()?"true":"false");
if(user.getHiredDate() != null) {
hrDingdingUser.setHiredDate(new Date(Long.valueOf(user.getHiredDate())));
}
hrDingdingUser.setExclusiveAccountType(user.getExclusiveAccountType());
hrDingdingUser.setExclusiveAccount(user.getExclusiveAccount()?"true":"false");
hrDingdingUser.setLoginId(user.getLoginId());
hrDingdingUser.setUpdateTime(now);
hrDingdingUserList.add(hrDingdingUser);
}
hrDingdingService.insertOrUpdateUser(hrDingdingUserList);
}
}
} catch (Exception e) {
log.error(ConstantsUtil.SYSTEM_ERROR, e);
}
log.info("--------------------------钉钉人员部门基本任务结束-----------------------");
}
单独获取钉钉打卡记录
@Test
public void doAttendTest() {
System.out.println(DingDingUtil.getToken());
Date now = new Date();
String workDate = DateUtils.getDate(DateUtils.addDay(new Date(), -3));
String nowDate = DateUtils.getDate(new Date());
String startWorkDate = workDate + " 00:00:00";
String endWorkDate = nowDate + " 23:59:59";
List attendanceList = new ArrayList<>();
List departmentList = DingDingUtil.getDepartment();
if(departmentList != null && departmentList.size() > 0) {
List userIdList = new ArrayList<>();
for(OapiV2DepartmentListsubResponse.DeptBaseResponse department:departmentList) {
List userIdListTmp = DingDingUtil.getDepartmentUserId(department.getDeptId());
if(userIdListTmp != null && userIdListTmp.size() > 0) {
userIdList.addAll(userIdListTmp);
}
}
if(userIdList != null && userIdList.size() > 0) {
List> userIds = Lists.partition(userIdList, 50);
for(List users:userIds) {
int count = 1;
long offset = 0L;
long limit = 50L;
List attendanceListTmp = DingDingUtil.getAttendanceList(startWorkDate, endWorkDate, users, offset, limit);
if(attendanceListTmp != null && attendanceListTmp.size() > 0) {
attendanceList.addAll(attendanceListTmp);
while (attendanceListTmp.size() <= 50) {
count++;
offset = (count - 1) * limit;
attendanceListTmp = DingDingUtil.getAttendanceList(startWorkDate, endWorkDate, users, offset, limit);
if(attendanceListTmp == null || attendanceListTmp.size() == 0) {
break;
}
attendanceList.addAll(attendanceListTmp);
}
}
}
}
if(attendanceList != null && attendanceList.size() > 0) {
List hrDingdingAttendanceList = new ArrayList<>();
for(OapiAttendanceListResponse.Recordresult attendance: attendanceList) {
HrDingdingAttendance hrDingdingAttendance = new HrDingdingAttendance();
hrDingdingAttendance.setAttendanceId(attendance.getId());
hrDingdingAttendance.setSourceType(attendance.getSourceType());
hrDingdingAttendance.setBaseCheckTime(attendance.getBaseCheckTime());
hrDingdingAttendance.setUserCheckTime(attendance.getUserCheckTime());
hrDingdingAttendance.setProcInstId(attendance.getProcInstId());
hrDingdingAttendance.setApproveId(attendance.getApproveId());
hrDingdingAttendance.setLocationResult(attendance.getLocationResult());
hrDingdingAttendance.setTimeResult(attendance.getTimeResult());
hrDingdingAttendance.setCheckType(attendance.getCheckType());
hrDingdingAttendance.setUserId(attendance.getUserId());
hrDingdingAttendance.setWorkDate(attendance.getWorkDate());
hrDingdingAttendance.setRecordId(attendance.getRecordId());
hrDingdingAttendance.setPlanId(attendance.getPlanId());
hrDingdingAttendance.setGroupId(attendance.getGroupId());
hrDingdingAttendance.setUpdateTime(now);
hrDingdingAttendanceList.add(hrDingdingAttendance);
}
hrDingdingService.insertOrUpdateAttendance(hrDingdingAttendanceList);
}
}
}
获取工作流程数据
@Test
public void doJXProcessinstanceTest() {
String type = "";
//出差
String processCode = DingDingUtil.TRAVELWORK_PROCESS_CODE;
if(StringUtils.isNotBlank(processCode)) {
if(DingDingUtil.TRANSFER_PROCESS_CODE.equals(processCode)) {
type = "transfer";//调岗
} else if(DingDingUtil.TRAVELWORK_PROCESS_CODE.equals(processCode)) {
type = "travelwork";//出差
} else if(DingDingUtil.PUBLIC_PROCESS_CODE.equals(processCode)) {
type = "public";//外出
} else if(DingDingUtil.LEAVE_PROCESS_CODE.equals(processCode)) {
type = "leave";//请假
}
}
try {
List processinstanceList = hrDingdingService.getProcessinstanceList(processCode);
if(processinstanceList != null && processinstanceList.size() > 0) {
hrDingdingService.insertOrUpdateProcessInstance(type, processinstanceList);
}
} catch (Exception e) {
e.printStackTrace();
}
}
public List getProcessinstanceListid(String processCode) {
Date now = new Date();
//仅仅获取30天以为的工作流程
String workDate = DateUtils.getDate(DateUtils.addDay(new Date(), -30));
String startDate = workDate + " 00:00:00";
long startTime = Long.valueOf(DateUtils.stringToTime(startDate, EnumDateStyle.YYYY_MM_DD_HH_MM_SS));
List processinstanceList = new ArrayList<>();
List processinstanceListids = new ArrayList<>();
long cursor = 0L;
long size = 10L;
OapiProcessinstanceListidsResponse.PageResult processinstanceListidsResponse = DingDingUtil.getProcessinstanceListid(processCode, startTime, null, cursor, size);
while (processinstanceListidsResponse != null && processinstanceListidsResponse.getNextCursor() != null) {
processinstanceListids.addAll(processinstanceListidsResponse.getList());
cursor = processinstanceListidsResponse.getNextCursor();
processinstanceListidsResponse = DingDingUtil.getProcessinstanceListid(processCode, startTime, null, cursor, size);
}
if(processinstanceListidsResponse != null && processinstanceListidsResponse.getList() != null && processinstanceListidsResponse.getList().size() > 0) {
processinstanceListids.addAll(processinstanceListidsResponse.getList());
}
if(processinstanceListids != null && processinstanceListids.size() > 0) {
for(String processInstanceId:processinstanceListids) {
OapiProcessinstanceGetResponse.ProcessInstanceTopVo processInstanceTopVo = DingDingUtil.getProcessinstanceInfo(processInstanceId);
if(processInstanceTopVo != null) {
HrDingdingProcessWithBLOBs hrDingdingProcess = new HrDingdingProcessWithBLOBs();
hrDingdingProcess.setProcessInstanceId(processInstanceId);
hrDingdingProcess.setProcessCode(processCode);
hrDingdingProcess.setTitle(processInstanceTopVo.getTitle());
hrDingdingProcess.setCreateTime(processInstanceTopVo.getCreateTime());
hrDingdingProcess.setFinishTime(processInstanceTopVo.getFinishTime());
if(StringUtils.isNotBlank(processInstanceTopVo.getOriginatorDeptId())) {
hrDingdingProcess.setOriginatorDeptId(Long.valueOf(processInstanceTopVo.getOriginatorDeptId()));
}
hrDingdingProcess.setOriginatorDeptName(processInstanceTopVo.getOriginatorDeptName());
hrDingdingProcess.setOriginatorUserid(processInstanceTopVo.getOriginatorUserid());
hrDingdingProcess.setStatus(processInstanceTopVo.getStatus());
hrDingdingProcess.setResult(processInstanceTopVo.getResult());
hrDingdingProcess.setBusinessId(processInstanceTopVo.getBusinessId());
hrDingdingProcess.setBizAction(processInstanceTopVo.getBizAction());
hrDingdingProcess.setMainProcessInstanceId(processInstanceTopVo.getMainProcessInstanceId());
hrDingdingProcess.setFormComponentValues(JSON.toJSONString(processInstanceTopVo.getFormComponentValues()));
hrDingdingProcess.setOperationRecords(JSON.toJSONString(processInstanceTopVo.getOperationRecords()));
hrDingdingProcess.setUpdateTime(now);
processinstanceList.add(hrDingdingProcess);
}
}
}
return processinstanceList;
}
HrDingdingServiceImpl 钉钉数据转换人事HR系统业务数据,省略了部分业务代码
@Slf4j
@Service
public class HrDingdingServiceImpl implements HrDingdingService {
@Autowired
private HrDingdingUserMapper hrDingdingUserMapper;
@Autowired
private HrDingdingDeptMapper hrDingdingDeptMapper;
@Autowired
private HrDingdingAttendanceMapper hrDingdingAttendanceMapper;
@Autowired
private HrDingdingProcessMapper hrDingdingProcessMapper;
//以下为系统其它业务类,本例不展示其详细代码
......
@Override
public void insert(HrDingdingAttendance hrDingdingAttendance) {
hrDingdingAttendanceMapper.insert(hrDingdingAttendance);
}
@Override
public void insertOrUpdateAttendance(List hrDingdingAttendanceList) {
if(hrDingdingAttendanceList != null && hrDingdingAttendanceList.size() > 0) {
for(HrDingdingAttendance hrDingdingAttendance:hrDingdingAttendanceList) {
HrDingdingAttendanceExample hrDingdingAttendanceExample = new HrDingdingAttendanceExample();
hrDingdingAttendanceExample.createCriteria().andAttendanceIdEqualTo(hrDingdingAttendance.getAttendanceId());
List list = hrDingdingAttendanceMapper.selectByExample(hrDingdingAttendanceExample);
if(list != null && list.size() > 0) {
hrDingdingAttendanceMapper.updateByExampleSelective(hrDingdingAttendance, hrDingdingAttendanceExample);
}else {
hrDingdingAttendanceMapper.insert(hrDingdingAttendance);
}
if(hrDingdingAttendance.getUserCheckTime() != null) {
HrDingdingUser hrDingdingUser = getDingdingUserByUserId(hrDingdingAttendance.getUserId());
if(hrDingdingUser != null) {
//根据手机号获取档案用户
CMUser cmUser = getHrUserByPhone(hrDingdingUser.getMobile());
if(cmUser != null) {
//保存HR系统打卡记录
HrAttendPunchRecord hapr = new HrAttendPunchRecord();
hapr.setHrUserId(cmUser.getHrUserId());
hapr.setUserNumber(cmUser.getUserName());
hapr.setNameCn(cmUser.getRealName());
hapr.setAttendanceTime(String.valueOf(hrDingdingAttendance.getUserCheckTime().getTime()/1000));
......
}else {
log.warn("HR系统不存在手机号["+hrDingdingUser.getMobile()+"]的用户");
}
}
}
}
}
}
private CMUser getHrUserByPhone(String phone) {
//根据手机号获取HR系统人员信息
}
/**
* 根据userid获取钉钉人员详细信息
*/
private HrDingdingUser getDingdingUserByUserId(String userId) {
HrDingdingUserExample hrDingdingUserExample = new HrDingdingUserExample();
hrDingdingUserExample.createCriteria().andUseridEqualTo(userId);
List hrDingdingUserList = hrDingdingUserMapper.selectByExample(hrDingdingUserExample);
if(hrDingdingUserList != null && hrDingdingUserList.size() > 0) {
return hrDingdingUserList.get(0);
}
return null;
}
/**
* 根据名称获取钉钉人员详细信息
*/
private HrDingdingUser getDingdingUserByName(String userName) {
HrDingdingUserExample hrDingdingUserExample = new HrDingdingUserExample();
hrDingdingUserExample.createCriteria().andNameEqualTo(userName);
List hrDingdingUserList = hrDingdingUserMapper.selectByExample(hrDingdingUserExample);
if(hrDingdingUserList != null && hrDingdingUserList.size() > 0) {
return hrDingdingUserList.get(0);
}
return null;
}
@Override
public void insertOrUpdateUser(List hrDingdingUserList) {
if(hrDingdingUserList != null && hrDingdingUserList.size() > 0) {
for(HrDingdingUser hrDingdingUser:hrDingdingUserList) {
HrDingdingUserExample hrDingdingUserExample = new HrDingdingUserExample();
hrDingdingUserExample.createCriteria().andUseridEqualTo(hrDingdingUser.getUserid());
List list = hrDingdingUserMapper.selectByExample(hrDingdingUserExample);
if(list != null && list.size() > 0) {
hrDingdingUserMapper.updateByExampleSelective(hrDingdingUser, hrDingdingUserExample);
}else {
hrDingdingUserMapper.insert(hrDingdingUser);
}
}
}
}
@Override
public void insertOrUpdateDept(List dingdingDeptList) {
if(dingdingDeptList != null && dingdingDeptList.size() > 0) {
for(HrDingdingDept hrDingdingDept:dingdingDeptList) {
HrDingdingDeptExample hrDingdingDeptExample = new HrDingdingDeptExample();
hrDingdingDeptExample.createCriteria().andDeptIdEqualTo(hrDingdingDept.getDeptId());
List list = hrDingdingDeptMapper.selectByExample(hrDingdingDeptExample);
if(list != null && list.size() > 0) {
hrDingdingDeptMapper.updateByExampleSelective(hrDingdingDept, hrDingdingDeptExample);
}else {
hrDingdingDeptMapper.insert(hrDingdingDept);
}
}
}
}
@Override
public void insertOrUpdateProcessInstance(String type, List processinstanceList) {
if(processinstanceList != null && processinstanceList.size() > 0) {
for(HrDingdingProcessWithBLOBs hrDingdingProcess:processinstanceList) {
HrDingdingProcessExample hrDingdingProcessExample = new HrDingdingProcessExample();
hrDingdingProcessExample.createCriteria().andProcessInstanceIdEqualTo(hrDingdingProcess.getProcessInstanceId());
List list = hrDingdingProcessMapper.selectByExample(hrDingdingProcessExample);
if(list != null && list.size() > 0) {
hrDingdingProcessMapper.updateByExampleSelective(hrDingdingProcess, hrDingdingProcessExample);
}else {
hrDingdingProcessMapper.insert(hrDingdingProcess);
}
try {
if("leave".equals(type)) {
convertHrLeave(hrDingdingProcess);
}else if("public".equals(type)) {
convertHrPublic(hrDingdingProcess);
}else if("travelwork".equals(type)) {
convertHrTravelwork(hrDingdingProcess);
}else if("transfer".equals(type)) {
convertHrTransfer(hrDingdingProcess);
}
} catch (Exception e) {
log.error(ConstantsUtil.SYSTEM_ERROR, e);
}
}
}
}
private void convertHrTransfer(HrDingdingProcessWithBLOBs hrDingdingProcess) {
if("COMPLETED".equals(hrDingdingProcess.getStatus()) && "agree".equals(hrDingdingProcess.getResult())) {
HrDingdingUser hrDingdingUser = getDingdingUserByUserId(hrDingdingProcess.getOriginatorUserid());
if(hrDingdingUser != null) {
//根据手机号获取档案用户
CMUser cmUser = getHrUserByPhone(hrDingdingUser.getMobile());
if (cmUser != null) {
ExtOaPeopleDataModel oaModel = new ExtOaPeopleDataModel();
//保存人员信息
......
if(StringUtils.isNotBlank(hrDingdingProcess.getFormComponentValues())) {
JSONArray jsonArray = JSONArray.parseArray(hrDingdingProcess.getFormComponentValues());
if(jsonArray != null && jsonArray.size() > 0) {
JSONObject jsonObject = jsonArray.getJSONObject(0);
String value = jsonObject.getString("value");
JSONArray valueArr = JSONArray.parseArray(value);
for(int i=0;i result = hrUserEditService.updateOaPeopleData(oaModel);
if (result != null && !result.getSuccess()) {
log.warn("保存转岗信息失败:"+result.getMessage());
}
}else {
log.warn("HR系统不存在手机号["+hrDingdingUser.getMobile()+"]的用户");
}
}
}
}
private void convertHrTravelwork(HrDingdingProcessWithBLOBs hrDingdingProcess) {
if("COMPLETED".equals(hrDingdingProcess.getStatus()) && "agree".equals(hrDingdingProcess.getResult())) {
HrDingdingUser hrDingdingUser = getDingdingUserByUserId(hrDingdingProcess.getOriginatorUserid());
if(hrDingdingUser != null) {
//根据手机号获取档案用户
CMUser cmUser = getHrUserByPhone(hrDingdingUser.getMobile());
if (cmUser != null) {
HrOaAttendTravelwork hrOaAttendTravelwork = new HrOaAttendTravelwork();
List hrOaAttendTravelworkList = new ArrayList<>();
//保存人员信息
......
hrOaAttendTravelwork.setSqrq(DateUtils.DateToString(hrDingdingProcess.getCreateTime(), EnumDateStyle.YYYY_MM_DD));
hrOaAttendTravelwork.setZw(String.valueOf(oaMapTableService.getPositionOaId(cmUser.getHrUserId()).getResult()));
hrOaAttendTravelwork.setSfjk("0");
if(StringUtils.isNotBlank(hrDingdingProcess.getFormComponentValues())) {
JSONArray jsonArray = JSONArray.parseArray(hrDingdingProcess.getFormComponentValues());
if(jsonArray != null && jsonArray.size() > 0) {
JSONObject formObj = jsonArray.getJSONObject(0);
JSONArray propsArr = JSONArray.parseArray(formObj.getString("value"));
if(propsArr != null && propsArr.size() > 0) {
if(propsArr != null && propsArr.size() > 0) {
for(int i=0;i 0) {
for(int j=0; j 0) {
for(HrOaAttendTravelwork travelwork:hrOaAttendTravelworkList) {
hrOaAttendTravelwork.setCcmdd(travelwork.getCcmdd());
hrOaAttendTravelwork.setCcrq(travelwork.getCcrq());
hrOaAttendTravelwork.setCcrqa(travelwork.getCcrqa());
ServiceResult result = attendTravelworkService.saveTravelworkData(hrOaAttendTravelwork);
if (result != null && !result.getSuccess()) {
log.warn("保存出差信息失败:"+result.getMessage());
}
}
}
}else {
log.warn("HR系统不存在手机号["+hrDingdingUser.getMobile()+"]的用户");
}
}
}
}
private void convertHrPublic(HrDingdingProcessWithBLOBs hrDingdingProcess) {
if("COMPLETED".equals(hrDingdingProcess.getStatus()) && "agree".equals(hrDingdingProcess.getResult())) {
HrDingdingUser hrDingdingUser = getDingdingUserByUserId(hrDingdingProcess.getOriginatorUserid());
if(hrDingdingUser != null) {
//根据手机号获取档案用户
CMUser cmUser = getHrUserByPhone(hrDingdingUser.getMobile());
if (cmUser != null) {
//实体类
HrOaAttendPublicLeave hrOaAttendPublicLeave = new HrOaAttendPublicLeave();
hrOaAttendPublicLeave.setUserName(cmUser.getUserName());
hrOaAttendPublicLeave.setHrUserId(cmUser.getHrUserId());
//保存人员信息
......
hrOaAttendPublicLeave.setApplyDate(String.valueOf(hrDingdingProcess.getCreateTime().getTime()/1000));
hrOaAttendPublicLeave.setBorrowMoney("0");
if(StringUtils.isNotBlank(hrDingdingProcess.getFormComponentValues())) {
JSONArray jsonArray = JSONArray.parseArray(hrDingdingProcess.getFormComponentValues());
if(jsonArray != null && jsonArray.size() > 0) {
for(int i = 0; i result = attendLeaveListService.insertLeaveDetail(model);
if (result != null && !result.getSuccess()) {
log.warn("保存请假信息失败:"+result.getMessage());
}
}else {
log.warn("HR系统不存在手机号["+hrDingdingUser.getMobile()+"]的用户");
}
}
}
}
}
实体类
import com.lxhr.mybatis.bean.BaseBean;
import java.io.Serializable;
import java.util.Date;
//钉钉人员表
public class HrDingdingUser extends BaseBean implements Serializable {
private Long id;
private String userid;
private String unionid;
private String name;
private String avatar;
private String stateCode;
private String mobile;
private String hideMobile;
private String telephone;
private String jobNumber;
private String title;
private String email;
private String orgEmail;
private String workPlace;
private String remark;
private String deptIdList;
private String extension;
private String admin;
private String boss;
private String leader;
private Date hiredDate;
private String exclusiveAccount;
private String loginId;
private String exclusiveAccountType;
private Date updateTime;
private static final long serialVersionUID = 1L;
//get set ...
}
import com.lxhr.mybatis.bean.BaseBean;
import java.io.Serializable;
import java.util.Date;
//钉钉部门表
public class HrDingdingDept extends BaseBean implements Serializable {
private Long id;
private Long deptId;
private String name;
private Long parentId;
private Date updateTime;
private static final long serialVersionUID = 1L;
//get set ...
}
import com.lxhr.mybatis.bean.BaseBean;
import java.io.Serializable;
import java.util.Date;
//打卡记录表
public class HrDingdingAttendance extends BaseBean implements Serializable {
private Long id;
private Long attendanceId;
private String sourceType;
private Date baseCheckTime;
private Date userCheckTime;
private String procInstId;
private Long approveId;
private String locationResult;
private String timeResult;
private String checkType;
private String userId;
private Date workDate;
private Long recordId;
private Long planId;
private Long groupId;
private Date updateTime;
private static final long serialVersionUID = 1L;
//get set ...
}
import com.lxhr.mybatis.bean.BaseBean;
import java.io.Serializable;
import java.util.Date;
//流程表
public class HrDingdingProcess extends BaseBean implements Serializable {
private Long id;
private String processInstanceId;
private String processCode;
private String title;
private Date createTime;
private Date finishTime;
private String originatorUserid;
private Long originatorDeptId;
private String originatorDeptName;
private String status;
private String result;
private String businessId;
private String bizAction;
private String mainProcessInstanceId;
private Date updateTime;
private static final long serialVersionUID = 1L;
//get set ...
}
实体类对应表结构
CREATE TABLE `hr_dingding_attendance` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`attendance_id` bigint(11) NOT NULL COMMENT '打卡ID',
`source_type` varchar(20) DEFAULT '' COMMENT '数据来源:ATM:考勤机打卡(指纹/人脸打卡)BEACON:IBeacon DING_ATM:钉钉考勤机(考勤机蓝牙打卡) USER:用户打卡 BOSS:老板改签 APPROVE:审批系统 SYSTEM:考勤系统 AUTO_CHECK:自动打卡',
`base_check_time` datetime DEFAULT NULL COMMENT '计算迟到和早退,基准时间。',
`user_check_time` datetime DEFAULT NULL COMMENT '实际打卡时间, 用户打卡时间的毫秒数。',
`proc_inst_id` varchar(36) DEFAULT NULL COMMENT '关联的审批实例ID,当该字段非空时,表示打卡记录与请假、加班等审批有关。',
`approve_id` bigint(11) DEFAULT NULL COMMENT '关联的审批ID,当该字段非空时,表示打卡记录与请假、加班等审批有关。',
`location_result` varchar(20) DEFAULT NULL COMMENT '位置结果: Normal:范围内 Outside:范围外 NotSigned:未打卡',
`time_result` varchar(20) DEFAULT NULL COMMENT '打卡结果: Normal:正常 Early:早退 Late:迟到 SeriousLate:严重迟到 Absenteeism:旷工迟到 NotSigned:未打卡',
`check_type` varchar(20) DEFAULT NULL COMMENT '考勤类型: OnDuty:上班 OffDuty:下班',
`user_id` varchar(36) DEFAULT NULL COMMENT '打卡人的UserID。',
`work_date` datetime DEFAULT NULL COMMENT '工作日。',
`record_id` bigint(11) DEFAULT NULL COMMENT '打卡记录ID。',
`plan_id` bigint(11) DEFAULT NULL COMMENT '排班ID。',
`group_id` bigint(11) DEFAULT NULL COMMENT '考勤组ID。',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) COMMENT='钉钉打开记录';
CREATE TABLE `hr_dingding_user` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`userid` varchar(36) DEFAULT NULL COMMENT '用户的userid。',
`unionid` varchar(36) DEFAULT NULL COMMENT '用户在当前开发者企业账号范围内的唯一标识。',
`name` varchar(50) DEFAULT NULL COMMENT '用户姓名。',
`avatar` varchar(255) DEFAULT NULL COMMENT '头像地址。',
`state_code` varchar(10) DEFAULT NULL COMMENT '国际电话区号。',
`mobile` varchar(20) DEFAULT NULL COMMENT '手机号码。',
`hide_mobile` varchar(10) DEFAULT NULL COMMENT '是否号码隐藏:true:隐藏 false:不隐藏',
`telephone` varchar(20) DEFAULT NULL COMMENT '分机号。',
`job_number` varchar(10) DEFAULT NULL COMMENT '员工工号。',
`title` varchar(20) DEFAULT NULL COMMENT '职位。',
`email` varchar(50) DEFAULT NULL COMMENT '员工邮箱。',
`org_email` varchar(50) DEFAULT NULL COMMENT '员工的企业邮箱。',
`work_place` varchar(255) DEFAULT NULL COMMENT '办公地点。',
`remark` varchar(255) DEFAULT NULL COMMENT '备注。',
`dept_id_list` varchar(200) DEFAULT NULL COMMENT '所属部门ID列表。',
`extension` varchar(255) DEFAULT NULL COMMENT '扩展属性。',
`admin` varchar(10) DEFAULT NULL COMMENT '是否为企业的管理员:true:是 false:不是',
`boss` varchar(10) DEFAULT NULL COMMENT '是否为企业的老板:true:是 false:不是',
`leader` varchar(10) DEFAULT NULL COMMENT '是否是部门的主管:true:是 false:不是',
`hired_date` datetime DEFAULT NULL COMMENT '入职时间,单位毫秒。',
`exclusive_account` varchar(10) DEFAULT NULL COMMENT '是否专属帐号:true:是 false:不是',
`login_id` varchar(50) DEFAULT NULL COMMENT '专属帐号登录名。',
`exclusive_account_type` varchar(10) DEFAULT NULL COMMENT '专属帐号类型:sso:企业自建专属帐号 dingtalk:钉钉自建专属帐号',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) COMMENT='钉钉用户信息';
CREATE TABLE `hr_dingding_dept` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`dept_id` bigint(11) DEFAULT NULL COMMENT '部门ID。',
`name` varchar(50) DEFAULT NULL COMMENT '部门名称。',
`parent_id` bigint(11) DEFAULT NULL COMMENT '父部门ID。',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) COMMENT='钉钉部门表';
CREATE TABLE `hr_dingding_process` (
`id` bigint(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`process_instance_id` varchar(50) DEFAULT NULL COMMENT '流程实例标识。',
`process_code` varchar(100) DEFAULT NULL COMMENT '审批流的唯一码。',
`title` varchar(200) DEFAULT NULL COMMENT '审批实例标题。',
`create_time` datetime DEFAULT NULL COMMENT '开始时间',
`finish_time` datetime DEFAULT NULL COMMENT '结束时间。',
`originator_userid` varchar(36) DEFAULT NULL COMMENT '发起人的userid。',
`originator_dept_id` bigint(11) DEFAULT NULL COMMENT '发起人的部门。-1表示根部门。',
`originator_dept_name` varchar(50) DEFAULT NULL COMMENT '发起部门。',
`status` varchar(20) DEFAULT NULL COMMENT '审批状态:NEW:新创建 RUNNING:审批中 TERMINATED:被终止 COMPLETED:完成 CANCELED:取消',
`result` varchar(10) DEFAULT NULL COMMENT '审批结果:agree:同意 refuse:拒绝',
`business_id` varchar(36) DEFAULT NULL COMMENT '审批实例业务编号。',
`biz_action` varchar(10) DEFAULT NULL COMMENT '审批实例业务动作:MODIFY:表示该审批实例是基于原来的实例修改而来 REVOKE:表示该审批实例是由原来的实例撤销后重新发起的 NONE表示正常发起',
`main_process_instance_id` varchar(50) DEFAULT NULL COMMENT '主流程实例标识。',
`form_component_values` text COMMENT '表单详情列表。',
`operation_records` text COMMENT '操作记录列表。',
`update_time` datetime DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) COMMENT='钉钉流程表';
最新sdk下载地址:服务端SDK下载 - 钉钉开放平台
我项目使用sdk地址:JAVA版钉钉开发SDK包dingtalk-sdk-java.zip_OapiV2DepartmentListsubResponse-互联网文档类资源-CSDN下载