package com.malk.rongzhi.service.impl; import com.malk.Util.UtilDateTime; import com.malk.Util.UtilHttp; import com.malk.Util.UtilMap; import com.malk.rongzhi.repository.dao.RzEkbRecordDao; import com.malk.rongzhi.repository.entity.RzEkbRecordPo; import com.malk.rongzhi.server.RZConf; import com.malk.rongzhi.server.RZR; import com.malk.rongzhi.service.RZService; import com.malk.server.dingtalk.DDConf; import com.malk.server.ekuaibao.EKBR; import com.malk.service.dingtalk.DDClient_Attendance; import com.malk.service.dingtalk.DDClient_Contacts; import com.malk.service.ekuaibao.EKBClient; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.time.LocalDateTime; import java.util.*; import java.util.stream.Collectors; @Slf4j @Service public class RZServiceImpl implements RZService { @Autowired private DDClient_Contacts ddClientImpl_contacts; @Autowired private DDClient_Attendance ddClient_attendance; @Autowired private EKBClient ekbClient; @Autowired private RzEkbRecordDao rzEkbRecordDao; /// 获取调用授权 @Override public String getAccessToken(RZConf.TYPE type) { String timestamp = String.valueOf(new Date().getTime()); String signature = DigestUtils.md5Hex("Max" + timestamp + RZConf.NONCE); Map header = new HashMap(); header.put("timestamp", timestamp); header.put("nonce", RZConf.NONCE); header.put("signature", signature); RZR rsp = (RZR) UtilHttp.doGet("https://one-api.max-digital.cn/v1/token" + type.getPath(), header, null, RZR.class); return rsp.getData(); } // 同步考勤数据到e快报 @Override public void uploadTravelData() { // 获取用户数据 log.info("###### [DD]开始同步组织架构 ######"); List userIds = new ArrayList<>(); syncOrganizationalStructure(DDConf.TOP_DEPARTMENT, userIds); log.info("###### [DD]同步组织架构结束 ######"); // 获取用户考勤 for (int i = 0; i < userIds.size(); i += 50) { int to = (i + 50) > userIds.size() ? userIds.size() : i + 50; // 考勤范围从当日 7.30 到次日 7.30 Date now = new Date(); String from = UtilDateTime.formatDate(now) + " 07:30:00"; String end = UtilDateTime.formatDate(now) + " 23:59:59"; // fixme: [凌晨以后同步新的考勤时段] if (LocalDateTime.now().getHour() <= 7) { from = UtilDateTime.formatDate(now) + " 00:00:00"; end = UtilDateTime.formatDate(now) + " 07:30:00"; } // String from = "2023-04-18 07:30:00"; // String end = "2023-04-19 07:30:00"; List users = userIds.subList(i, to); List list = ddClient_attendance.listAttendanceRecord(getAccessToken(RZConf.TYPE.dingtalk), users, from, end); // 匹配数据考勤 users.forEach(user -> { List records = list.stream().filter(item -> user.equals(item.get("userId"))).collect(Collectors.toList()); // 有下班打卡 if (records.size() > 1) { long checkIn = (long) records.get(0).get("userCheckTime"); long checkOut = (long) records.get(records.size() - 1).get("userCheckTime"); String userId = String.valueOf(records.get(0).get("userId")); LocalDateTime begin = UtilDateTime.getLocalDateTimeFromTimestamp(checkIn); LocalDateTime finish = UtilDateTime.getLocalDateTimeFromTimestamp(checkOut); // 下班超过22点, 且当天考勤超过11小时 float hour = UtilDateTime.betweenHour(begin, finish); if (hour > 11.0f && finish.getHour() >= 22) { String checkDate = UtilDateTime.formatLocalDate(begin.toLocalDate()); if (!rzEkbRecordDao.existsByUserIdAndCheckDate(userId, checkDate)) { log.info("匹配符合数据, {}, {}, {}", userId, UtilDateTime.formatLocalDateTime(begin), UtilDateTime.formatLocalDateTime(finish)); // 易快报同步默认是打卡结束时间, 若是23点以后下班, 第二天可打车, 结束传递+1天 if (finish.getHour() == 23) { checkOut += 24 * 60 * 60 * 1000L; } pushTemplateByRecord(userId, checkIn, checkOut, checkDate); } else { log.info("数据已经推送, {}, {}, {}", userId, UtilDateTime.formatLocalDateTime(begin), UtilDateTime.formatLocalDateTime(finish)); } } } }); } } // 匹配userId, 以最新数据为准 private void syncOrganizationalStructure(Number deptId, List userIds) { // 同步一级部门用户 if (deptId.equals(DDConf.TOP_DEPARTMENT)) { userIds.addAll(ddClientImpl_contacts.listDepartmentUserId(getAccessToken(RZConf.TYPE.dingtalk), DDConf.TOP_DEPARTMENT)); } // 同步除一级部门外所有部门用户 ddClientImpl_contacts.listSubDepartmentId(getAccessToken(RZConf.TYPE.dingtalk), deptId).forEach(dept -> { List ids = ddClientImpl_contacts.listDepartmentUserId(getAccessToken(RZConf.TYPE.dingtalk), dept); userIds.addAll(ids); syncOrganizationalStructure(dept, userIds); }); } // 推送易快报 private void pushTemplateByRecord(String userId, long start, long end, String checkDate) { // 获取用户Id [易快报corpId:钉钉userId] Map userInfo = ekbClient.getStaffInfo(getAccessToken(RZConf.TYPE.ekuaibao), "USERID", Arrays.asList(userId)).get(0); // 获取自定义模板Id [通过list接口查询到固定模板ID, 再实时换取单据版本ID] Map template = ekbClient.getTemplateIdById(getAccessToken(RZConf.TYPE.ekuaibao), Arrays.asList(RZConf.REQUEST_TEMPLATE_ID)).get(0); // 组装自定义模板数据 [手动创建一条记录查询比对模板字段] Map formData = UtilMap.map("submitterId, specificationId", RZConf.SUBMITTED_ID, template.get("id")); // 固定提交人, 查看权限 formData.put("travelers", Arrays.asList(userInfo.get("id"))); // 同行人, 即打车人 formData.put("expenseDepartment", userInfo.get("defaultDepartment")); Map travel = UtilMap.map("E_e9101f64b75c7b57a3c0_name, E_e9101f64b75c7b57a3c0_住宿地", "上海市/上海市区", "[{\"key\":\"858\",\"label\":\"上海市/上海市区\"}]"); // 固定打车行程地点 travel.put("E_e9101f64b75c7b57a3c0_入住日期", start); // 上班打卡日期 travel.put("E_e9101f64b75c7b57a3c0_离店日期", end); // 下班打卡日期 formData.put("u_行程规划", Arrays.asList(UtilMap.map("dataLinkForm, dataLinkTemplateId", travel, "ID01nORyvKjEPJ"))); // 行程ID通过查询记录复制 // 创建单据数据, 推送易快报审批作为打车依据 EKBR ekbr = ekbClient.createFormInstance(getAccessToken(RZConf.TYPE.ekuaibao), true, false, formData, null); // 记录当天的推送结果 rzEkbRecordDao.save(RzEkbRecordPo.builder() .userId(userId) .checkDate(checkDate).build()); log.info("易快报推送结果, {}", ekbr.getFlow()); } }