|
|
@@ -0,0 +1,298 @@
|
|
|
+package org.sky.scientific.service.impl;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSON;
|
|
|
+import com.alibaba.fastjson.JSONArray;
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import lombok.AllArgsConstructor;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.sky.core.log.exception.ServiceException;
|
|
|
+import org.sky.core.secure.utils.SecureUtil;
|
|
|
+import org.sky.core.tool.api.R;
|
|
|
+import org.sky.core.tool.utils.DateUtil;
|
|
|
+import org.sky.core.tool.utils.Func;
|
|
|
+import org.sky.scientific.mapper.TechnicianMapper;
|
|
|
+import org.sky.scientific.mapper.XmMapper;
|
|
|
+import org.sky.scientific.mapper.XmTechnicianHoursMapper;
|
|
|
+import org.sky.scientific.pojo.dto.HoursSyncDto;
|
|
|
+import org.sky.scientific.pojo.entity.TechnicianEntity;
|
|
|
+import org.sky.scientific.pojo.entity.XmTechnicianHours;
|
|
|
+import org.sky.scientific.pojo.vo.XmVO;
|
|
|
+import org.sky.scientific.service.IHoursSyncService;
|
|
|
+import org.sky.system.feign.ISysClient;
|
|
|
+import org.sky.system.pojo.entity.Tenant;
|
|
|
+import org.springframework.http.*;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.web.client.RestClientException;
|
|
|
+import org.springframework.web.client.RestTemplate;
|
|
|
+import org.springframework.web.util.UriComponentsBuilder;
|
|
|
+
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Data
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@AllArgsConstructor
|
|
|
+public class HoursSyncServiceImpl implements IHoursSyncService {
|
|
|
+
|
|
|
+ private final XmTechnicianHoursMapper hoursMapper;
|
|
|
+ private final RestTemplate restTemplate;
|
|
|
+ private final ISysClient sysClient;
|
|
|
+ private final XmMapper xmMapper;
|
|
|
+ private final TechnicianMapper technicianMapper;
|
|
|
+ private static final String BASE_URL = "https://yanfa.jishutao.com/prod-api";
|
|
|
+ private static final String URL_LOGIN = BASE_URL + "/login";
|
|
|
+ private static final String URL_SYNC_HOURS = BASE_URL + "/api/project/pushCompanyData";
|
|
|
+ private static final String URL_ACCEPT_HOURS = BASE_URL + "/api/project/getCompanyClock";
|
|
|
+
|
|
|
+ private static final String HEAD_AUTHORIZATION = "Authorization";
|
|
|
+ private static final String USERNAME = "yandongli";
|
|
|
+ private static final String PASSWORD = "123456";
|
|
|
+ private static final Integer BATCH_SIZE = 100;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean syncHoursData(HoursSyncDto dto) {
|
|
|
+ //先登录
|
|
|
+ String token = this.login();
|
|
|
+ if (token != null) {
|
|
|
+ JSONObject reqBody = getBasicInfo(dto.getYearAndMonth());
|
|
|
+
|
|
|
+ List<JSONObject> hoursList = hoursMapper.selectListForSync(dto.getYearAndMonth());
|
|
|
+ List<JSONObject> rdList = new ArrayList<>();
|
|
|
+ for (JSONObject hours : hoursList) {
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ data.put("projectNumber", hours.getString("xmbh"));
|
|
|
+ data.put("adminKyId", SecureUtil.getTenantId() + "_" + hours.getString("unicode"));
|
|
|
+ data.put("recordTime", DateUtil.format(DateUtil.parse(hours.getString("workDate"), DateUtil.PATTERN_YYYYMMDD), DateUtil.PATTERN_DATE));
|
|
|
+ data.put("duration", hours.getString("workHours"));
|
|
|
+ rdList.add(data);
|
|
|
+ }
|
|
|
+ reqBody.put("usci", SecureUtil.getTenantId());
|
|
|
+ reqBody.put("rdList", rdList);
|
|
|
+ log.info("同步至工时系统:{}", JSON.toJSONString(reqBody));
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+ headers.add(HEAD_AUTHORIZATION, token);
|
|
|
+ HttpEntity<JSONObject> request = new HttpEntity<>(reqBody, headers);
|
|
|
+ ResponseEntity<String> response = restTemplate.exchange(URL_SYNC_HOURS, HttpMethod.POST, request, String.class);
|
|
|
+ if (response.getStatusCode().is2xxSuccessful()) {
|
|
|
+ JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
|
+ assert resp != null;
|
|
|
+ Integer code = resp.getInteger("code");
|
|
|
+ if (code == 200) {
|
|
|
+ log.info("成功同步至工时系统");
|
|
|
+ } else {
|
|
|
+ log.error("同步至工时系统失败:{}", resp.getString("msg"));
|
|
|
+ throw new ServiceException("同步至工时系统失败:" + resp.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("同步至工时系统失败:" + response.getStatusCode());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private JSONObject getBasicInfo(String yearAndMonth) {
|
|
|
+ JSONObject reqBody = new JSONObject();
|
|
|
+
|
|
|
+ List<JSONObject> listDep = new ArrayList<>();
|
|
|
+ JSONObject dep = new JSONObject();
|
|
|
+ R<Tenant> tenant = sysClient.getTenant(SecureUtil.getTenantId());
|
|
|
+ if (tenant.isSuccess()) {
|
|
|
+ dep.put("kyId", String.valueOf(tenant.getData().getId()));
|
|
|
+ dep.put("deptName", tenant.getData().getTenantName());
|
|
|
+ dep.put("kySuperId", null);
|
|
|
+ }
|
|
|
+ dep.put("usci", SecureUtil.getTenantId());
|
|
|
+ listDep.add(dep);
|
|
|
+
|
|
|
+ List<JSONObject> listUser = new ArrayList<>();
|
|
|
+ List<JSONObject> hoursList = hoursMapper.selectListForSync(yearAndMonth);
|
|
|
+ if (Func.isEmpty(hoursList)) {
|
|
|
+ throw new ServiceException("无数据可同步");
|
|
|
+ }
|
|
|
+ List<String> unicodeList = hoursList.stream().map(rd -> rd.getString("unicode")).distinct().toList();
|
|
|
+ for (String unicode : unicodeList) {
|
|
|
+ JSONObject user = new JSONObject();
|
|
|
+ user.put("kyDeptId", dep.get("kyId"));
|
|
|
+ user.put("userName", SecureUtil.getTenantId() + "_" + unicode);
|
|
|
+ TechnicianEntity dbTechnician = technicianMapper.selectByUnicodeAndYearAndMonth(unicode, yearAndMonth);
|
|
|
+ if (Func.notNull(dbTechnician)) {
|
|
|
+ user.put("nickName", dbTechnician.getName());
|
|
|
+ }
|
|
|
+ user.put("kyId", user.getString("userName"));
|
|
|
+ user.put("kySuperId", null);
|
|
|
+ listUser.add(user);
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Long> xmIdList = hoursList.stream().map(rd -> rd.getLong("xmId")).distinct().toList();
|
|
|
+ List<XmVO> xmList = xmMapper.selectByXmIdList(xmIdList);
|
|
|
+ Map<Long, List<String>> mapByXmId = hoursList.stream().collect(Collectors.groupingBy(rd -> rd.getLong("xmId"), Collectors.mapping(rd -> rd.getString("unicode"), Collectors.toList())));
|
|
|
+
|
|
|
+ List<JSONObject> listUserProject = new ArrayList<>();
|
|
|
+ for (XmVO xmVO : xmList) {
|
|
|
+ JSONObject data = new JSONObject();
|
|
|
+ data.put("projectName", xmVO.getXmmc());
|
|
|
+ TechnicianEntity dbTechnician = technicianMapper.selectById(xmVO.getXmfzr());
|
|
|
+ if (Func.notNull(dbTechnician)) {
|
|
|
+ String username = SecureUtil.getTenantId() + "_" + dbTechnician.getUnicode();
|
|
|
+ if (listUser.stream().noneMatch(user -> user.getString("userName").equals(username))) {
|
|
|
+ JSONObject user = new JSONObject();
|
|
|
+ user.put("kyDeptId", dep.get("kyId"));
|
|
|
+ user.put("userName", username);
|
|
|
+ user.put("nickName", dbTechnician.getName());
|
|
|
+ user.put("kyId", username);
|
|
|
+ user.put("kySuperId", null);
|
|
|
+ listUser.add(user);
|
|
|
+ }
|
|
|
+ data.put("aid", username);
|
|
|
+ }
|
|
|
+
|
|
|
+ data.put("projectNumber", xmVO.getXmbh());
|
|
|
+ data.put("startTime", DateUtil.format(xmVO.getXmkssj(), DateUtil.PATTERN_DATE));
|
|
|
+ data.put("endTime", DateUtil.format(xmVO.getXmjssj(), DateUtil.PATTERN_DATE));
|
|
|
+ data.put("projectYear", DateUtil.format(xmVO.getXmkssj(), DateUtil.PATTERN_YYYY));
|
|
|
+ data.put("createYear", DateUtil.format(xmVO.getCreateTime(), DateUtil.PATTERN_YYYY));
|
|
|
+ List<String> unicodes = mapByXmId.get(xmVO.getId());
|
|
|
+ data.put("staffIds", unicodes.stream().distinct().map(unicode -> SecureUtil.getTenantId() + "_" + unicode).collect(Collectors.joining(",")));
|
|
|
+ listUserProject.add(data);
|
|
|
+ }
|
|
|
+
|
|
|
+ reqBody.put("listDep", listDep);
|
|
|
+ reqBody.put("listUser", listUser);
|
|
|
+ reqBody.put("listUserProject", listUserProject);
|
|
|
+
|
|
|
+ return reqBody;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public boolean acceptRdData(HoursSyncDto dto) {
|
|
|
+ //先登录
|
|
|
+ String token = this.login();
|
|
|
+ if (token != null) {
|
|
|
+ String url = UriComponentsBuilder.fromHttpUrl(URL_ACCEPT_HOURS)
|
|
|
+ .queryParam("usci", SecureUtil.getTenantId())
|
|
|
+ .queryParam("year", Integer.valueOf(dto.getYearAndMonth().substring(0, 4)))
|
|
|
+ .queryParam("month", Integer.valueOf(dto.getYearAndMonth().substring(4, 6))).toUriString();
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+ headers.add(HEAD_AUTHORIZATION, token);
|
|
|
+ HttpEntity<JSONObject> request = new HttpEntity<>(headers);
|
|
|
+ ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, request, String.class);
|
|
|
+ if (response.getStatusCode().is2xxSuccessful()) {
|
|
|
+ JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
|
+ assert resp != null;
|
|
|
+ Integer code = resp.getInteger("code");
|
|
|
+ if (code == 200) {
|
|
|
+ JSONObject data = resp.getJSONObject("data");
|
|
|
+ JSONArray rdList = data.getJSONArray("rdList");
|
|
|
+ Map<String, Long> xmMap = new HashMap<>();
|
|
|
+
|
|
|
+ List<JSONObject> dbHoursList = hoursMapper.selectListForSync(dto.getYearAndMonth());
|
|
|
+ List<String> identifierList = dbHoursList.stream().map(t ->
|
|
|
+ t.getString("tenantId") + ":" + t.getString("xmId") + ":" + t.getString("unicode") + ":" + t.getString("workDate")).toList();
|
|
|
+ List<XmTechnicianHours> insertList = new ArrayList<>();
|
|
|
+ List<XmTechnicianHours> updateList = new ArrayList<>();
|
|
|
+ for (Object o : rdList) {
|
|
|
+ JSONObject rd = (JSONObject) o;
|
|
|
+ Double duration = rd.getDouble("duration");
|
|
|
+
|
|
|
+ String adminKyId = rd.getString("adminKyId");
|
|
|
+ List<String> tenantAndUnicode = Arrays.asList(adminKyId.split("_"));
|
|
|
+
|
|
|
+ String recordTime = rd.getString("recordTime");
|
|
|
+ recordTime = DateUtil.format(DateUtil.parse(recordTime, DateUtil.PATTERN_YYYY_MM_DD), DateUtil.PATTERN_YYYYMMDD);
|
|
|
+
|
|
|
+ String projectNumber = rd.getString("projectNumber");
|
|
|
+ if (!xmMap.containsKey(projectNumber)) {
|
|
|
+ Long xmId = xmMapper.getXmIdByXmbh(projectNumber);
|
|
|
+ if (xmId == null) {
|
|
|
+ xmId = 0L;
|
|
|
+ }
|
|
|
+ xmMap.put(projectNumber, xmId);
|
|
|
+ }
|
|
|
+ Long xmId = xmMap.get(projectNumber);
|
|
|
+ if (xmId <= 0L) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ String identifier = SecureUtil.getTenantId() + ":" + xmId + ":" + tenantAndUnicode.get(1) + ":" + recordTime;
|
|
|
+ if (identifierList.contains(identifier)) {
|
|
|
+ //现有的,做修改
|
|
|
+ XmTechnicianHours updateEntity = new XmTechnicianHours();
|
|
|
+ updateEntity.setTenantId(SecureUtil.getTenantId());
|
|
|
+ updateEntity.setXmId(xmId);
|
|
|
+ updateEntity.setUnicode(tenantAndUnicode.get(1));
|
|
|
+ updateEntity.setWorkDate(recordTime);
|
|
|
+ updateEntity.setWorkHours(duration);
|
|
|
+ updateList.add(updateEntity);
|
|
|
+ } else {
|
|
|
+ //新的,做插入
|
|
|
+ XmTechnicianHours insertEntity = new XmTechnicianHours();
|
|
|
+ insertEntity.setTenantId(SecureUtil.getTenantId());
|
|
|
+ insertEntity.setXmId(xmId);
|
|
|
+ insertEntity.setUnicode(tenantAndUnicode.get(1));
|
|
|
+ insertEntity.setWorkDate(recordTime);
|
|
|
+ insertEntity.setWorkHours(duration);
|
|
|
+ insertList.add(insertEntity);
|
|
|
+ }
|
|
|
+ if (Func.isNotEmpty(insertList) && insertList.size() % BATCH_SIZE == 0) {
|
|
|
+ hoursMapper.insert(insertList);
|
|
|
+ insertList.clear();
|
|
|
+ }
|
|
|
+ if (Func.isNotEmpty(updateList) && updateList.size() % BATCH_SIZE == 0) {
|
|
|
+ hoursMapper.batchUpdateHours(updateList);
|
|
|
+ updateList.clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (Func.isNotEmpty(insertList)) {
|
|
|
+ hoursMapper.insert(insertList);
|
|
|
+ }
|
|
|
+ if (Func.isNotEmpty(updateList)) {
|
|
|
+ hoursMapper.batchUpdateHours(updateList);
|
|
|
+ }
|
|
|
+ log.info("同步至本系统,响应数据:{}", data);
|
|
|
+ } else {
|
|
|
+ log.error("同步至本系统失败:{}", resp.getString("msg"));
|
|
|
+ throw new ServiceException("同步至本系统失败:" + resp.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("同步至本系统失败:" + response.getStatusCode());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ private String login() {
|
|
|
+ try {
|
|
|
+ HttpHeaders headers = new HttpHeaders();
|
|
|
+ headers.setContentType(MediaType.APPLICATION_JSON);
|
|
|
+ JSONObject loginBody = new JSONObject();
|
|
|
+ loginBody.put("username", USERNAME);
|
|
|
+ loginBody.put("password", PASSWORD);
|
|
|
+ HttpEntity<JSONObject> request = new HttpEntity<>(loginBody, headers);
|
|
|
+ ResponseEntity<String> response = restTemplate.exchange(URL_LOGIN, HttpMethod.POST, request, String.class);
|
|
|
+ if (response.getStatusCode().is2xxSuccessful()) {
|
|
|
+ JSONObject resp = JSONObject.parseObject(response.getBody());
|
|
|
+ assert resp != null;
|
|
|
+ Integer code = resp.getInteger("code");
|
|
|
+ if (code == 200) {
|
|
|
+ String token = resp.getString("token");
|
|
|
+ log.info("成功登录工时系统:{}", token);
|
|
|
+ return token;
|
|
|
+ } else {
|
|
|
+ log.error("登录工时系统失败:{}", resp.getString("msg"));
|
|
|
+ throw new ServiceException("登录工时系统失败:" + resp.getString("msg"));
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ throw new ServiceException("登录工时系统失败:" + response.getStatusCode());
|
|
|
+ }
|
|
|
+ } catch (RestClientException e) {
|
|
|
+ log.error("请求失败: {}", e.getMessage());
|
|
|
+ throw new ServiceException("请求失败:" + e.getMessage());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+}
|