diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/api/user/authority/AuthorityUserApi.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/api/user/authority/AuthorityUserApi.java index 8f165468..d1be1fa9 100644 --- a/nflg_project_dev/material/src/main/java/com/nflg/product/material/api/user/authority/AuthorityUserApi.java +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/api/user/authority/AuthorityUserApi.java @@ -17,6 +17,7 @@ import com.nflg.product.material.pojo.vo.AuthorityMenuVO; import com.nflg.product.material.pojo.vo.AuthorityUserVO; import com.nflg.product.material.service.AuthorityPowerService; import com.nflg.product.material.service.AuthorityUserService; +import com.nflg.product.material.service.EhrService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import nflg.product.common.constant.STATE; @@ -174,6 +175,10 @@ public class AuthorityUserApi extends BaseApi { return ResultVO.success(authorityUserService.updateById(user)); } - + @GetMapping("syncEhrEmployee") + @ApiOperation("同步ehr员工的状态") + public ResultVO syncEhrEmployee(){ + return ResultVO.success(authorityUserService.syncEhrEmployee()); + } } diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/job/SaticScheduleTask.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/job/SaticScheduleTask.java index f1f24c20..9c86cb6c 100644 --- a/nflg_project_dev/material/src/main/java/com/nflg/product/material/job/SaticScheduleTask.java +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/job/SaticScheduleTask.java @@ -38,6 +38,9 @@ public class SaticScheduleTask { @Resource private MaterialUpdateBillService materialUpdateBillService; + @Resource + private AuthorityUserService authorityUserService; + /** * 更新AD(每天6点) */ @@ -149,4 +152,12 @@ public class SaticScheduleTask { public void doQueryCurrentTwoYearsUsage() throws Exception { materialMainService.doQueryCurrentTwoYearsUsage(); } + + /** + * 每周六 同步ehr用户人员状态,离职的更新为未启用 + */ + @Scheduled(cron = "${ehr.sync.employee.state.time:0 0 9 ? * SAT}") + public void syncEhrEmployee() { + authorityUserService.syncEhrEmployee(); + } } diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/pojo/dto/EhrEmployeeDTO.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/pojo/dto/EhrEmployeeDTO.java new file mode 100644 index 00000000..76f07804 --- /dev/null +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/pojo/dto/EhrEmployeeDTO.java @@ -0,0 +1,88 @@ +package com.nflg.product.material.pojo.dto; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * packageName com.nflg.product.material.pojo.dto + * + * @author luohj + * @className EhrEmployeeDTO + * @date 2024/8/1 0001 + * @description ehr 员工信息 + */ +@Data +public class EhrEmployeeDTO implements Serializable { + + @ApiModelProperty("员工ID") + private String EmpID; + + @ApiModelProperty("员工编号") + private String EmpNo; + + @ApiModelProperty("员工姓名") + private String EmpName; + + @ApiModelProperty("所属部门ID") + private String DeptId; + + @ApiModelProperty("所属部门编号") + private String DEPTCODE; + + @ApiModelProperty("员工状态 0启用1停用") + private String DISABLE; + + @ApiModelProperty("人员类别 1在职5离职") + private String A0191; + + @ApiModelProperty("手机号码") + private String CELLPHONE; + + @ApiModelProperty("岗位ID") + private String POSITIONID; + + @ApiModelProperty("身份证号") + private String IDCARDNO; + + @ApiModelProperty("性别") + private String SEX; + + @ApiModelProperty("最后修改日期") + private Date LASTMODIFYTIME; + + @ApiModelProperty("开户银行") + private String A0136; + + @ApiModelProperty("银行代码") + private String YHDM; + + @ApiModelProperty("银行账号") + private String A0137; + + @ApiModelProperty("银行国家代码") + private String YHGJDM; + + @ApiModelProperty("职级") + private String GWZJ; + + @ApiModelProperty("序列") + private String RYXL; + + @ApiModelProperty("是否结算加班费") + private String A01190; + + @ApiModelProperty("入职日期") + private String A0141; + + @ApiModelProperty("成本中心编码") + private String COSTNO; + + @ApiModelProperty("成本中心") + private String COSTNAME; + + @ApiModelProperty("第一次合同签订时间") + private Date HT_BEGIN_DATE; +} \ No newline at end of file diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/AuthorityUserService.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/AuthorityUserService.java index c31fdad4..74c76a64 100644 --- a/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/AuthorityUserService.java +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/AuthorityUserService.java @@ -3,10 +3,13 @@ package com.nflg.product.material.service; import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.TypeReference; import cn.hutool.core.util.StrUtil; +import cn.hutool.core.util.XmlUtil; import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Maps; import com.nflg.product.base.core.conmon.util.DESUtil; import com.nflg.product.base.core.vo.PageVO; import com.nflg.product.material.mapper.master.AuthorityPowerMapper; @@ -14,23 +17,30 @@ import com.nflg.product.material.mapper.master.AuthorityPowerPermissionMapper; import com.nflg.product.material.mapper.master.AuthorityRoleMapper; import com.nflg.product.material.mapper.master.AuthorityUserMapper; import com.nflg.product.material.pojo.dto.AuthorityUserDTO; +import com.nflg.product.material.pojo.dto.EhrEmployeeDTO; import com.nflg.product.material.pojo.dto.SaveUserMemuPermissionDTO; import com.nflg.product.material.pojo.dto.UserRoleDTO; import com.nflg.product.material.pojo.entity.AuthorityPowerPermissionEntity; import com.nflg.product.material.pojo.entity.AuthorityUserEntity; import com.nflg.product.material.pojo.query.AuthorityUserQuery; import com.nflg.product.material.pojo.vo.AuthorityUserVO; +import com.nflg.product.material.util.HttpUtils; import com.nflg.product.material.util.ListCommonUtil; +import org.dom4j.Document; +import org.dom4j.DocumentException; +import org.dom4j.DocumentHelper; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import javax.annotation.Resource; +import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import java.util.stream.Collectors; @@ -58,6 +68,8 @@ public class AuthorityUserService extends ServiceImpl userList = this.list(Wrappers.lambdaQuery() + .eq(AuthorityUserEntity::getUserSource,1) + .eq(AuthorityUserEntity::getEnableState,1)); + if(userList.isEmpty()){ + return "正常AD用户数量为0"; + } + String sessionId = ehrService.getSessionId(); + List empList = ehrService.empList(sessionId); + if(empList.isEmpty()){ + return "员工数量为0"; + } + //离职员工编号集合 + List empNoList = empList.stream().filter(emp -> Objects.equals("1",emp.getDISABLE()) || Objects.equals("5",emp.getA0191())) + .map(emp -> emp.getEmpNo().toUpperCase()).collect(Collectors.toList()); + List disableList = userList.stream() + .filter(user -> empNoList.contains(user.getUserCode().toUpperCase())) + .map(user -> { + user.setEnableState(0); + return user; + }).collect(Collectors.toList()); + if(!disableList.isEmpty()){ + this.updateBatchById(disableList); + } + return String.format("正常AD用户数:%d,员工数:%d,离职数:%d,更新记录:%d",userList.size(),empList.size(),empNoList.size(),disableList.size()); + } } diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/EhrService.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/EhrService.java new file mode 100644 index 00000000..b40894ca --- /dev/null +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/service/EhrService.java @@ -0,0 +1,138 @@ +package com.nflg.product.material.service; + +import cn.hutool.core.convert.Convert; +import cn.hutool.core.util.XmlUtil; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.nflg.product.material.pojo.dto.EhrEmployeeDTO; +import com.nflg.product.material.util.CompletableFutureUtil; +import com.nflg.product.material.util.HttpUtils; +import lombok.extern.slf4j.Slf4j; +import org.dom4j.Document; +import org.dom4j.DocumentHelper; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; + +/** + * packageName com.nflg.product.material.service + * + * @author luohj + * @className EhrService + * @date 2024/8/1 0001 + * @description ehr 相关接口 + */ +@Service +@Slf4j +@RefreshScope +public class EhrService { + + private static HttpUtils httpUtils = new HttpUtils(); + + @Value("${ehr.url:http://192.168.163.30:8088/hr/DataInterface/WebService.asmx}") + private String ehrUrl; + @Value("${ehr.user:nflj}") + private String ehrUser; + @Value("${ehr.pwd:nfljadmin}") + private String ehrPwd; + + /** + * 获取ehr sessionId + * @return + */ + public String getSessionId(){ + String sessionId = ""; + Map mp = Maps.newHashMap(); + mp.put("S1",ehrUser); + mp.put("S2",ehrPwd); + try { + String re = httpUtils.doformPost(ehrUrl + "/Login",mp); + Document d = DocumentHelper.parseText(re); + sessionId = d.getRootElement().getStringValue(); + } catch (Exception e) { + log.error("ehr 登录异常: {}",e.getMessage()); + } + return sessionId; + } + + /** + * 获取ehr 员工总数 + * @param sessionId + * @return + */ + public Integer empTotal(String sessionId){ + int total = -1; + Map mp2 = Maps.newHashMap(); + mp2.put("SessionID",sessionId); + mp2.put("NewOnly","0"); + mp2.put("Time",""); + String re2 = null; + try { + re2 = httpUtils.doPost(ehrUrl + "/EmpBeginGetEmployee",mp2); + Document d2 = DocumentHelper.parseText(re2); + total =Integer.valueOf(d2.getRootElement().getStringValue()); + } catch (Exception e) { + e.printStackTrace(); + } + return total; + } + + /** + * ehr 员工列表 + * @param sessionId + * @return + */ + public List empList(String sessionId){ + int total = empTotal(sessionId); + List ehrEmployeeList =Lists.newArrayList(); + //每批次数量 1222 6 22 7 + int batch = 200; + if(total <= 0){ + return ehrEmployeeList; + } + int mul = total / batch; + int rem = total % batch; + int cnt = mul + (rem > 0 ? 1: 0); + List>> taskList = Lists.newArrayList(); + for (int i = 1; i <= cnt; i++) { + int finalI = i; + CompletableFuture> future = CompletableFuture.supplyAsync(() -> { + Map mp3 = Maps.newHashMap(); + mp3.put("SessionID",sessionId); + mp3.put("from",String.valueOf( (finalI -1)*batch + 1 )); + mp3.put("to",String.valueOf( (finalI * batch) > total ? total: (finalI * batch) )); + try { + String re3 = httpUtils.doPost(ehrUrl + "/GetSegment",mp3); + Document d3 = DocumentHelper.parseText(re3); + String r3 = d3.getRootElement().getStringValue(); + Map m3 = XmlUtil.xmlToMap(r3); + return Convert.toList(EhrEmployeeDTO.class,m3.get("Table")); + } catch (Exception e) { + log.error("eHr获取人员信息异常:{},{}",sessionId,e.getMessage()); + } + return Lists.newArrayList(); + }); + taskList.add(future); + } + try { + + CompletableFuture allTask = CompletableFuture.allOf(taskList.stream().map(CompletableFutureUtil::executeActionAsync).toArray(CompletableFuture[]::new)); + allTask.get(); + taskList.forEach(t -> ehrEmployeeList.addAll(t.join())); + + //清除缓存 + Map mp4 = Maps.newHashMap(); + mp4.put("SessionID",sessionId); + httpUtils.doPost(ehrUrl + "/ClearCache",mp4); + } catch (Exception e) { + log.error("eHr获取人员信息异常:{}",e.getMessage()); + } + + return ehrEmployeeList; + } + +} \ No newline at end of file diff --git a/nflg_project_dev/material/src/main/java/com/nflg/product/material/util/CompletableFutureUtil.java b/nflg_project_dev/material/src/main/java/com/nflg/product/material/util/CompletableFutureUtil.java new file mode 100644 index 00000000..75f4ff93 --- /dev/null +++ b/nflg_project_dev/material/src/main/java/com/nflg/product/material/util/CompletableFutureUtil.java @@ -0,0 +1,58 @@ +package com.nflg.product.material.util; + +import lombok.extern.slf4j.Slf4j; + +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.function.Function; +import java.util.stream.Collectors; + +/** + * packageName com.nflg.product.material.util + * + * @author luohj + * @className CompletableFutureUtil + * @date 2024/8/1 0001 + * @description TODO + */ +@Slf4j +public class CompletableFutureUtil { + private static final int MAX_RETRIES = 3; + + + public static List getAllCompleted(List> futuresList) throws Exception { + CompletableFuture allFuturesResult = CompletableFuture + .allOf(futuresList.stream().map(CompletableFutureUtil::executeActionAsync).toArray(CompletableFuture[]::new)); + allFuturesResult.get(); + return futuresList + .stream() + .map(CompletableFuture::join) + .collect(Collectors.toList()); + } + + public static CompletableFuture executeActionAsync(CompletableFuture action) { + return action + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t -> retry(t, action, 0)) + .thenCompose(Function.identity()); + } + + private static CompletableFuture retry(Throwable first, CompletableFuture action, int retry) { + if (retry >= MAX_RETRIES) { + return CompletableFutureUtil.failedFuture(first); + } + return action + .thenApply(CompletableFuture::completedFuture) + .exceptionally(t -> { + // first.addSuppressed(t); + log.info("任务:{} , 重试:{}", action, retry); + return retry(first, action, retry + 1); }) + .thenCompose(Function.identity()); + } + + public static CompletableFuture failedFuture(Throwable t) { + final CompletableFuture cf = new CompletableFuture<>(); + cf.completeExceptionally(t); + return cf; + } +} \ No newline at end of file