维护工具v1

This commit is contained in:
钱涛 2023-04-23 16:27:11 +08:00
parent ce8ca9cdb8
commit 413de52d6a
3 changed files with 386 additions and 5 deletions

View File

@ -1,11 +1,7 @@
package com.engine.salary.cache;
/**
* @description: 用于定义本服务内部使用的缓存key
* @author: xiajun
* @modified By: xiajun
* @date: Created in 12/13/21 11:12 AM
* @version:v1.0
* 用于定义本服务内部使用的缓存key
*/
public class SalaryCacheKey {

View File

@ -0,0 +1,351 @@
package com.engine.salary.maintainer.salaryacct;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.datacollection.dto.AttendQuoteFieldListDTO;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctCalculateBO;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctCalculatePriorityBO;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctResultBO;
import com.engine.salary.entity.salaryacct.dto.SalaryAcctProgressDTO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctEmployeePO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctResultPO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctResultTempPO;
import com.engine.salary.entity.salaryformula.ExpressFormula;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.po.SalarySobAdjustRulePO;
import com.engine.salary.entity.salarysob.po.SalarySobBackItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobItemPO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.salaryacct.SalaryAcctResultMapper;
import com.engine.salary.service.*;
import com.engine.salary.service.impl.*;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.MapperProxyFactory;
import com.google.common.collect.Lists;
import com.weaver.util.threadPool.ThreadPoolUtil;
import com.weaver.util.threadPool.constant.ModulePoolEnum;
import com.weaver.util.threadPool.entity.LocalRunnable;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import weaver.hrm.User;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;
/**
* 薪资核算维护类
* <p>Copyright: Copyright (c) 2022</p>
* <p>Company: 泛微软件</p>
*
* @author qiantao
* @version 1.0
**/
@Slf4j
public class SalaryAcctManager extends Service {
private SalaryAcctResultMapper getSalaryAcctResultMapper() {
return MapperProxyFactory.getProxy(SalaryAcctResultMapper.class);
}
private SalaryAcctEmployeeService getSalaryAcctEmployeeService(User user) {
return ServiceUtil.getService(SalaryAcctEmployeeServiceImpl.class, user);
}
private SalaryAcctResultService getSalaryAcctResultService(User user) {
return ServiceUtil.getService(SalaryAcctResultServiceImpl.class, user);
}
private SalarySobItemService getSalarySobItemService(User user) {
return ServiceUtil.getService(SalarySobItemServiceImpl.class, user);
}
private SalaryItemService getSalaryItemService(User user) {
return ServiceUtil.getService(SalaryItemServiceImpl.class, user);
}
private SalarySobEmpFieldService getSalarySobEmpFieldService(User user) {
return ServiceUtil.getService(SalarySobEmpFieldServiceImpl.class, user);
}
private SalarySobService getSalarySobService(User user) {
return ServiceUtil.getService(SalarySobServiceImpl.class, user);
}
private SalaryAcctRecordService getSalaryAcctRecordService(User user) {
return ServiceUtil.getService(SalaryAcctRecordServiceImpl.class, user);
}
private TaxAgentService getTaxAgentService(User user) {
return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
}
private SalaryEmployeeService getSalaryEmployeeService(User user) {
return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
}
private SalaryFormulaService getSalaryFormulaService(User user) {
return ServiceUtil.getService(SalaryFormulaServiceImpl.class, user);
}
private SalarySobAdjustRuleService getSalarySobAdjustRuleService(User user) {
return ServiceUtil.getService(SalarySobAdjustRuleServiceImpl.class, user);
}
private SalarySobItemHideService getSalarySobItemHideService(User user) {
return ServiceUtil.getService(SalarySobItemHideServiceImpl.class, user);
}
private SalaryAcctCalculateService getSalaryAcctCalculateService(User user) {
return ServiceUtil.getService(SalaryAcctCalculateServiceImpl.class, user);
}
private SalaryAcctProgressService getSalaryAcctProgressService(User user) {
return ServiceUtil.getService(SalaryAcctProgressServiceImpl.class, user);
}
private DataSourceTransactionManager dataSourceTransactionManager;
private SalaryAcctResultTempService getSalaryAcctResultTempService(User user) {
return ServiceUtil.getService(SalaryAcctResultTempServiceImpl.class, user);
}
// private LoggerTemplate salaryAcctRecordLoggerTemplate;
private SIAccountService getSIAccountService(User user) {
return ServiceUtil.getService(SIAccountServiceImpl.class, user);
}
private AttendQuoteFieldService getAttendQuoteFieldService(User user) {
return ServiceUtil.getService(AttendQuoteFieldServiceImpl.class, user);
}
private SalaryAcctReportService getSalaryAcctReportService(User user) {
return ServiceUtil.getService(SalaryAcctReportServiceImpl.class, user);
}
private SalarySobItemGroupService getSalarySobItemGroupService(User user) {
return ServiceUtil.getService(SalarySobItemGroupServiceImpl.class, user);
}
private SalarySobBackItemService getSalarySobBackItemService(User user) {
return ServiceUtil.getService(SalarySobBackItemServiceImpl.class, user);
}
/**
* 补充核算
* 核算已归档后需要重新核算某一项
*/
public void supplementAcctRecord(SalaryAcctSupplementParam param) {
}
/**
* 薪资核算-核算
*
* @param calculateParam 薪资核算的参数
*/
public void calculate(SalaryAcctSupplementParam calculateParam) {
log.info("开始核算V1{}", calculateParam);
//当前登陆人员
DataCollectionEmployee simpleEmployee = new DataCollectionEmployee();
simpleEmployee.setEmployeeId((long) user.getUID());
// 检查是否正在核算中
SalaryAcctProgressDTO salaryAcctProgressDTO = getSalaryAcctProgressService(user).getProgress("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId());
if (Objects.nonNull(salaryAcctProgressDTO) && salaryAcctProgressDTO.isStatus() && Optional.ofNullable(salaryAcctProgressDTO.getProgress()).orElse(BigDecimal.ZERO).compareTo(BigDecimal.ONE) < 0) {
return;
}
// 初始化进度
SalaryAcctProgressDTO initProgress = new SalaryAcctProgressDTO()
.setTitle(SalaryI18nUtil.getI18nLabel(97515, "核算中"))
.setTitleLabelId(97515L)
.setTotalQuantity(NumberUtils.INTEGER_ONE)
.setCalculatedQuantity(NumberUtils.INTEGER_ZERO)
.setProgress(BigDecimal.ZERO)
.setStatus(true)
.setMessage(StringUtils.EMPTY);
getSalaryAcctProgressService(user).initProgress("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId(), initProgress);
new Thread() {
public void run() {
calculate(calculateParam, simpleEmployee);
}
}.start();
}
public void calculate(SalaryAcctSupplementParam calculateParam, DataCollectionEmployee simpleEmployee) {
try {
// 1查询薪资核算记录
SalaryAcctRecordPO salaryAcctRecordPO = getSalaryAcctRecordService(user).getById(calculateParam.getSalaryAcctRecordId());
if (Objects.isNull(salaryAcctRecordPO)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
}
//查询对应账套
SalarySobPO salarySobPO = getSalarySobService(user).getById(salaryAcctRecordPO.getSalarySobId());
if (Objects.isNull(salarySobPO)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资账套不存在或已被删除"));
}
// 2查询薪资核算记录的薪资周期考勤周期等
SalarySobCycleDTO salarySobCycleDTO = getSalaryAcctRecordService(user).getSalarySobCycleById(calculateParam.getSalaryAcctRecordId());
// 3查询薪资核算记录所用薪资账套的薪资项目副本
List<SalarySobItemPO> salarySobItemPOS = getSalarySobItemService(user).listBySalarySobId(salaryAcctRecordPO.getSalarySobId());
if (CollectionUtils.isEmpty(salarySobItemPOS)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99151, "当前所用的薪资账套未选择任何薪资项目,无法核算"));
}
// 回算薪资项目
List<SalarySobBackItemPO> salarySobBackItems = Collections.emptyList();
if (Objects.equals(salaryAcctRecordPO.getBackCalcStatus(), 1)) {
salarySobBackItems = getSalarySobBackItemService(user).listBySalarySobId(salaryAcctRecordPO.getSalarySobId());
}
// 4查询当前租户的所有薪资项目
List<SalaryItemPO> salaryItemPOS = getSalaryItemService(user).listAll();
// 5查询薪资核算记录所用薪资账套的调薪计薪规则
List<SalarySobAdjustRulePO> salarySobAdjustRulePOS = getSalarySobAdjustRuleService(user).listBySalarySobId(salaryAcctRecordPO.getSalarySobId());
// 6查询社保福利的所有字段
Map<String, String> welfareColumns = getSIAccountService(user).welfareColumns();
// 7查询考勤引用的所有字段
List<AttendQuoteFieldListDTO> attendQuoteFieldListDTOS = getAttendQuoteFieldService(user).listAll();
//核算锁定值
List<Long> lockSalaryItemIds = salaryAcctRecordPO.getLockSalaryItemIds();
Map<String, SalaryAcctResultPO> acctResults = new HashMap<>();
if (CollectionUtils.isNotEmpty(lockSalaryItemIds)) {
List<SalaryAcctResultPO> acctResultPOS = getSalaryAcctResultService(user).listBySalaryAcctRecordIds(Collections.singleton(calculateParam.getSalaryAcctRecordId()));
acctResults = Optional.ofNullable(acctResultPOS)
.orElse(new ArrayList<>())
.stream()
.filter(po -> lockSalaryItemIds.contains(po.getSalaryItemId()))
.collect(Collectors.toMap(po -> po.getSalaryItemId() + "_" + po.getSalaryAcctEmpId(), a -> a, (a, b) -> a));
}
// 8查询公式详情
Set<Long> formulaIds = SalaryEntityUtil.properties(salarySobItemPOS, SalarySobItemPO::getFormulaId);
formulaIds.addAll(SalaryEntityUtil.properties(salaryItemPOS, SalaryItemPO::getFormulaId));
formulaIds.addAll(SalaryEntityUtil.properties(salarySobBackItems, SalarySobBackItemPO::getFormulaId));
List<ExpressFormula> expressFormulas = getSalaryFormulaService(user).listExpressFormula(formulaIds);
// 本次运算的回算薪资项目所涉及的变量
Set<String> issuedFieldIds = new HashSet<>();
// 9计算薪资项目的运算优先级
List<List<Long>> salarySobItemsWithPriority = SalaryAcctCalculatePriorityBO.calculatePriority(salarySobItemPOS, salaryItemPOS, expressFormulas, salarySobBackItems, issuedFieldIds);
// 10根据id查询其他合并计税的薪资核算记录
List<SalaryAcctRecordPO> otherSalaryAcctRecordPOS = getSalaryAcctRecordService(user).listById4OtherConsolidatedTax(salaryAcctRecordPO.getId());
// 11查询本次核算人员
List<SalaryAcctEmployeePO> salaryAcctEmployeePOS;
if (CollectionUtils.isEmpty(calculateParam.getIds())) {
salaryAcctEmployeePOS = getSalaryAcctEmployeeService(user).listBySalaryAcctRecordId(salaryAcctRecordPO.getId());
} else {
salaryAcctEmployeePOS = getSalaryAcctEmployeeService(user).listByIds(calculateParam.getIds());
}
if (CollectionUtils.isEmpty(salaryAcctEmployeePOS)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(103378, "薪资核算人员不能为空"));
}
// 11.1初始化进度
SalaryAcctProgressDTO initProgress = new SalaryAcctProgressDTO().setTitle(SalaryI18nUtil.getI18nLabel(97515, "核算中")).setTitleLabelId(97515L).setTotalQuantity(salaryAcctEmployeePOS.size() * 2 + 1).setCalculatedQuantity(0).setProgress(BigDecimal.ZERO).setStatus(true).setMessage(StringUtils.EMPTY);
getSalaryAcctProgressService(user).initProgress("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId(), initProgress);
// 12对薪资核算人员进行拆分
List<List<SalaryAcctEmployeePO>> partition = Lists.partition(salaryAcctEmployeePOS, 5000);
// 12.1监控子线程的任务执行
CountDownLatch childMonitor = new CountDownLatch(partition.size());
// 12.2记录子线程的执行结果
BlockingDeque<SalaryAcctCalculateBO.Result> calculateResults = new LinkedBlockingDeque<>(partition.size());
// 12.3生成本次运算的key
String calculateKey = UUID.randomUUID().toString();
// 12.4多线程运算运算结果存放在临时表中
for (List<SalaryAcctEmployeePO> acctEmployeePOS : partition) {
SalaryAcctCalculateBO salaryAcctCalculateBO = new SalaryAcctCalculateBO()
.setSalaryAcctRecordPO(salaryAcctRecordPO)
.setSalarySobPO(salarySobPO)
.setSalarySobCycleDTO(salarySobCycleDTO)
.setOtherSalaryAcctRecordPOS(otherSalaryAcctRecordPOS)
.setSalaryAcctLockResultPOS(MapUtils.emptyIfNull(acctResults))
.setLockSalaryItemIds(lockSalaryItemIds)
.setSalarySobItemPOS(salarySobItemPOS)
.setSalaryItemIdWithPriorityList(salarySobItemsWithPriority)
.setExpressFormulas(expressFormulas)
.setSalaryItemPOS(salaryItemPOS)
.setSalarySobAdjustRulePOS(salarySobAdjustRulePOS)
.setWelfareColumns(MapUtils.emptyIfNull(welfareColumns))
.setAttendQuoteFieldListDTOS(attendQuoteFieldListDTOS)
.setSalaryAcctEmployeePOS(acctEmployeePOS)
.setIssuedFieldIds(issuedFieldIds)
.setChildMonitor(childMonitor)
.setResults(calculateResults)
.setCalculateKey(calculateKey);
List<SalarySobBackItemPO> finalSalarySobBackItems = salarySobBackItems;
LocalRunnable localRunnable = new LocalRunnable() {
@Override
public void execute() {
getSalaryAcctCalculateService(user).calculate(salaryAcctCalculateBO, simpleEmployee, finalSalarySobBackItems);
}
};
ThreadPoolUtil.fixedPoolExecute(ModulePoolEnum.HRM, "salaryAcctCalculateV2", localRunnable);
}
// 13等待所有子线程执行完毕
childMonitor.await();
// 14判断子线程执行结果
boolean allSuccess = calculateResults.stream().allMatch(SalaryAcctCalculateBO.Result::isStatus);
if (!allSuccess) {
// 薪资核算实现的线程的错误信息
String errorMsg = calculateResults.stream().filter(result -> !result.isStatus()).map(SalaryAcctCalculateBO.Result::getErrMsg).collect(Collectors.joining("|"));
getSalaryAcctProgressService(user).fail("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId(), errorMsg);
// 删除薪资核算临时存储表中的数据
getSalaryAcctResultTempService(user).deleteByCalculateKey(calculateKey);
return;
}
// 15处理核算结果临时表数据
handleSalaryAcctResultTemp(calculateParam, calculateKey);
getSalaryAcctProgressService(user).finish("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId(), true);
} catch (Exception e) {
log.info("薪资核算出错:{}", e.getMessage(), e);
// throw new SalaryRunTimeException(e);
getSalaryAcctProgressService(user).fail("SalaryCacheKey.ACCT_PROGRESS" + calculateParam.getSalaryAcctRecordId(), SalaryI18nUtil.getI18nLabel(99642, "薪资核算出错") + ": " + e.getMessage());
} finally {
// 数据库字段加密用
}
}
/**
* 处理薪资核算临时存储表中的数据
*
* @param calculateParam
* @param calculateKey
*/
private void handleSalaryAcctResultTemp(SalaryAcctSupplementParam calculateParam, String calculateKey) {
// 查询薪资核算结果的临时存储
List<SalaryAcctResultTempPO> salaryAcctResultTempPOS = getSalaryAcctResultTempService(user).listByCalculateKey(calculateKey);
// 删除原来的薪资核算结果
if (CollectionUtils.isNotEmpty(calculateParam.getIds())) {
getSalaryAcctResultMapper().deleteBySalaryAcctEmpIds(calculateParam.getIds());
} else {
getSalaryAcctResultMapper().deleteBySalaryAcctRecordIds(Collections.singleton(calculateParam.getSalaryAcctRecordId()));
getSalaryAcctReportService(user).deleteBySalaryAcctRecordId(calculateParam.getSalaryAcctRecordId());
}
// 保存薪资的薪资核算结果
List<SalaryAcctResultPO> salaryAcctResultPOS = SalaryAcctResultBO.convert2ResultPO(salaryAcctResultTempPOS);
// batchSave(salaryAcctResultPOS);
//保存核算报表数据
// List<SalaryAcctResultReportPO> salaryAcctResultReportPOS = SalaryAcctResultReportBO.convert2ReportPO(salaryAcctResultTempPOS, calculateParam.getEmps());
// getSalaryAcctReportService(user).batchSave(salaryAcctResultReportPOS);
// 删除薪资核算临时存储表中的数据
getSalaryAcctResultTempService(user).deleteByCalculateKey(calculateKey);
}
}

View File

@ -0,0 +1,34 @@
package com.engine.salary.maintainer.salaryacct;
import com.engine.salary.util.valid.DataCheck;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Collection;
/**
* 薪资补充核算的参数
* <p>Copyright: Copyright (c) 2022</p>
* <p>Company: 泛微软件</p>
*
* @author qiantao
* @version 1.0
**/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SalaryAcctSupplementParam {
//核算人员的id,不是employeeId而是salaryAcctEmpId
private Collection<Long> ids;
@DataCheck(require = true,message = "参数错误薪资核算记录ID不能为空")
private Long salaryAcctRecordId;
@DataCheck(require = true,message = "参数错误薪资项目ID不能为空")
private String salaryItemIds;
}