weaver-hrm-salary/src/com/engine/salary/service/impl/AttendQuoteDataServiceImpl....

1047 lines
51 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.engine.salary.service.impl;
import cn.hutool.core.util.NumberUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.alibaba.fastjson.JSONObject;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.cloudstore.eccom.pc.table.WeaTable;
import com.cloudstore.eccom.pc.table.WeaTableColumn;
import com.cloudstore.eccom.result.WeaResultMsg;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.biz.AttendQuoteBiz;
import com.engine.salary.biz.AttendQuoteDataBiz;
import com.engine.salary.biz.AttendQuoteDataValueBiz;
import com.engine.salary.biz.AttendQuoteFieldBiz;
import com.engine.salary.common.LocalDateRange;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.datacollection.bo.AttendQuoteDataBO;
import com.engine.salary.entity.datacollection.dto.*;
import com.engine.salary.entity.datacollection.param.*;
import com.engine.salary.entity.datacollection.po.AttendQuoteDataPO;
import com.engine.salary.entity.datacollection.po.AttendQuoteDataValuePO;
import com.engine.salary.entity.datacollection.po.AttendQuoteFieldPO;
import com.engine.salary.entity.datacollection.po.AttendQuotePO;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctEmployeeBO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctEmployeePO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveDataDTO;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.datacollection.AttendQuoteSourceTypeEnum;
import com.engine.salary.enums.datacollection.UseEmployeeTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.datacollection.AttendQuoteDataMapper;
import com.engine.salary.mapper.salarysob.SalarySobMapper;
import com.engine.salary.mapper.salarysob.SalarySobRangeMapper;
import com.engine.salary.mapper.sys.SalarySysConfMapper;
import com.engine.salary.remote.attend.entity.Attend4Salary;
import com.engine.salary.remote.attend.service.RemoteAttend4SalaryService;
import com.engine.salary.remote.attend.service.impl.RemoteAttend4SalaryServiceImpl;
import com.engine.salary.service.*;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.sys.entity.vo.OrderRuleVO;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.excel.ExcelParseHelper;
import com.engine.salary.util.excel.ExcelSupport;
import com.engine.salary.util.excel.ExcelUtil;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.file.ImageFileManager;
import weaver.general.BaseBean;
import weaver.general.Util;
import weaver.hrm.User;
import weaver.wechat.util.Utils;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.YearMonth;
import java.util.*;
import java.util.stream.Collectors;
import static com.engine.salary.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;
/**
* 数据采集-考勤引用数据
* <p>Copyright: Copyright (c) 2022</p>
* <p>Company: 泛微软件</p>
*
* @author qiantao
* @version 1.0
**/
@Slf4j
public class AttendQuoteDataServiceImpl extends Service implements AttendQuoteDataService {
private final Boolean isLog = "true".equals(new BaseBean().getPropValue("hrmSalary", "log"));
private AttendQuoteBiz quoteBiz = new AttendQuoteBiz();
private AttendQuoteDataBiz dataBiz = new AttendQuoteDataBiz();
private AttendQuoteDataValueBiz dataValueBiz = new AttendQuoteDataValueBiz();
private AttendQuoteFieldBiz fieldBiz = new AttendQuoteFieldBiz();
private AttendQuoteFieldSettingService getFieldSettingService(User user) {
return ServiceUtil.getService(AttendQuoteFieldSettingServiceImpl.class, user);
}
private SalarySysConfService getSalarySysConfService(User user) {
return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
}
private SalarySobService getSalarySobService(User user) {
return ServiceUtil.getService(SalarySobServiceImpl.class, user);
}
private AttendQuoteService getAttendQuoteService(User user) {
return ServiceUtil.getService(AttendQuoteServiceImpl.class, user);
}
private AttendQuoteDataMapper getAttendQuoteDataMapper() {
return MapperProxyFactory.getProxy(AttendQuoteDataMapper.class);
}
private SalarySobMapper getSalarySobMapper() {
return MapperProxyFactory.getProxy(SalarySobMapper.class);
}
private SalarySobRangeMapper getSalarySobRangeMapper() {
return MapperProxyFactory.getProxy(SalarySobRangeMapper.class);
}
private SalaryArchiveService getSalaryArchiveService(User user) {
return ServiceUtil.getService(SalaryArchiveServiceImpl.class, user);
}
private RemoteAttend4SalaryService getRemoteAttend4SalaryService(User user) {
return ServiceUtil.getService(RemoteAttend4SalaryServiceImpl.class, user);
}
private SalaryEmployeeService getSalaryEmployeeService(User user) {
return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
}
private SalarySysConfMapper getSalarySysConfMapper() {
return SqlProxyHandle.getProxy(SalarySysConfMapper.class);
}
@Override
public PageInfo<AttendQuoteDataBaseDTO> listPage(AttendQuoteDataQueryParam queryParam) {
//排序配置
OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
queryParam.setOrderRule(orderRule);
List<AttendQuoteDataBaseDTO> list = getAttendQuoteDataMapper().list(queryParam);
PageInfo<AttendQuoteDataBaseDTO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), list, AttendQuoteDataBaseDTO.class);
return page;
}
/**
* 获取所有考勤字段
*
* @return
*/
private List<AttendQuoteFieldPO> getAllAttendQuoteFields() {
return fieldBiz.listSome(AttendQuoteFieldPO.builder().build());
}
/**
* 获取考勤数据结果
*
* @param attendQuoteDataBases
* @return
*/
public List<Map<String, Object>> getListMaps(List<AttendQuoteDataBaseDTO> attendQuoteDataBases) {
if (CollectionUtils.isEmpty(attendQuoteDataBases)) {
return new ArrayList<>();
}
// 考核数据值
List<AttendQuoteDataValuePO> attendQuoteDataValues = dataValueBiz.listSome(AttendQuoteDataValuePO.builder().attendQuoteId(attendQuoteDataBases.get(0).getAttendQuoteId()).build());
return attendQuoteDataBases.stream().map(m -> {
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", m.getId());
map.put("username", m.getUsername());
map.put("departmentName", m.getDepartmentName());
map.put("mobile", m.getMobile());
map.put("jobNum", m.getJobNum());
map.put("idNo", m.getIdNo());
// 考勤数据
attendQuoteDataValues.stream().filter(a -> a.getAttendQuoteDataId().equals(m.getId())).collect(Collectors.toList()).forEach(e -> {
map.put(e.getAttendQuoteFieldId() + "_attendQuoteData", e.getDataValue());
});
return map;
}).collect(Collectors.toList());
}
@Override
public List<AttendQuoteDataDTO> getAttendQuoteData(YearMonth salaryYearMonth, Long salarySobId, List<Long> employeeIds) {
if (salaryYearMonth == null || salarySobId == null) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100358, "参数有误薪资所属月、薪资账套id"));
}
List<AttendQuoteDataDTO> list = new ArrayList<>();
Date salaryYearMonthDay = SalaryDateUtil.localDateToDate(salaryYearMonth.atDay(1));
//查询引用主表
List<AttendQuotePO> attendQuotes = quoteBiz.listSome(AttendQuotePO.builder().salaryYearMonth(salaryYearMonthDay).salarySobId(salarySobId).build());
if (CollectionUtils.isEmpty(attendQuotes)) {
return Collections.emptyList();
}
AttendQuotePO attendQuote = attendQuotes.get(0);
//查询考勤数据值
List<AttendQuoteDataValuePO> attendQuoteDataValues = dataValueBiz.listSome(AttendQuoteDataValuePO.builder().attendQuoteId(attendQuote.getId()).employeeIds(employeeIds).build());
if (CollectionUtils.isEmpty(employeeIds)) {
employeeIds = attendQuoteDataValues.stream().map(AttendQuoteDataValuePO::getEmployeeId)
.distinct().collect(Collectors.toList());
}
employeeIds.forEach(e -> {
AttendQuoteDataDTO attendQuoteData = new AttendQuoteDataDTO();
attendQuoteData.setEmployeeId(e);
List<AttendQuoteDataValueDTO> dataValues = attendQuoteDataValues.stream().filter(v -> v.getEmployeeId().equals(e)).map(m ->
AttendQuoteDataValueDTO.builder()
.attendQuoteFieldId(m.getAttendQuoteFieldId())
.dataValue(m.getDataValue())
.build()).collect(Collectors.toList());
attendQuoteData.setDataValues(dataValues);
list.add(attendQuoteData);
});
return list;
}
@Override
public XSSFWorkbook export(AttendQuoteDataQueryParam queryParam) {
if (queryParam.getAttendQuoteId() == null) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100253, "考勤引用id不能为空"));
}
//排序配置
OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
queryParam.setOrderRule(orderRule);
// 考勤数据分页主数据
List<AttendQuoteDataBaseDTO> attendQuoteDataBases = dataBiz.list(queryParam);
// 所有考勤字段
List<AttendQuoteFieldPO> attendQuoteFields = getAllAttendQuoteFields();
// 获取最终结果
List<Map<String, Object>> listMaps = getListMaps(attendQuoteDataBases);
//当前引用的值
List<String> effectiveColumns = listMaps.stream()
.map(Map::keySet)
.max(Comparator.comparingInt(Set::size))
.orElse(new HashSet<>())
.stream()
.map(key -> key.split("_")[0])
.collect(Collectors.toList());
// 1.工作簿名称
String sheetName = SalaryI18nUtil.getI18nLabel(93931, "考勤数据");
List<Object> header = new ArrayList<>();
header.add(SalaryI18nUtil.getI18nLabel(85429, "姓名"));
header.add(SalaryI18nUtil.getI18nLabel(86185, "部门"));
header.add(SalaryI18nUtil.getI18nLabel(86186, "手机号"));
header.add(SalaryI18nUtil.getI18nLabel(86317, "工号"));
// 动态列
List<AttendQuoteFieldPO> effectiveFields = new ArrayList<>();
if (CollectionUtils.isNotEmpty(listMaps)) {
effectiveFields = attendQuoteFields.stream()
.filter(attendQuoteField -> effectiveColumns.contains(Util.null2String(attendQuoteField.getId())))
.collect(Collectors.toList());
effectiveFields.forEach(attendQuoteField -> {
header.add(attendQuoteField.getFieldName());
}
);
}
List<List<Object>> rows = new ArrayList<>();
// 2.表头
rows.add(header);
// 3.表数据
for (Map<String, Object> dto : listMaps) {
List<Object> row = new ArrayList<>();
row.add(dto.get("username"));
row.add(dto.get("departmentName"));
row.add(dto.get("mobile"));
row.add(dto.get("jobNum"));
// 动态列
for (AttendQuoteFieldPO attendQuoteField : effectiveFields) {
Object o = dto.get(attendQuoteField.getId().toString() + "_attendQuoteData");
try {
if (o != null && NumberUtil.isNumber(o.toString())) {
row.add(new BigDecimal(o.toString()));
} else {
row.add(o);
}
} catch (Exception e) {
row.add(o);
}
}
rows.add(row);
}
// 记录日志
AttendQuotePO attendQuotePO = getAttendQuoteService(user).getById(queryParam.getAttendQuoteId());
SalarySobPO salarySob = getSalarySobService(user).getById(attendQuotePO.getSalarySobId());
LoggerContext loggerContext = new LoggerContext();
loggerContext.setUser(user);
loggerContext.setTargetId(String.valueOf(attendQuotePO.getId()));
loggerContext.setTargetName(SalaryDateUtil.getFormatYearMonth(attendQuotePO.getSalaryYearMonth()) + " " + (salarySob != null ? salarySob.getName() : ""));
loggerContext.setOperateType(OperateTypeEnum.EXCEL_EXPORT.getValue());
loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "导出考勤数据"));
loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
SalaryElogConfig.attendQuoteLoggerTemplate.write(loggerContext);
return ExcelUtil.genWorkbookV2(rows, sheetName);
}
/**
* 获取表头设置字段
*
* @param sourceType
* @return
*/
private List<AttendQuoteFieldPO> getAttendQuoteSetFields(AttendQuoteSourceTypeEnum sourceType) {
List<AttendQuoteFieldPO> allAttendQuoteFields = getAllAttendQuoteFields();
List<AttendQuoteFieldSettingListDTO> attendQuoteFieldSettingList = getFieldSettingService(user).listNoSync(AttendQuoteFieldSettingQueryParam.builder().sourceType(sourceType).isViewChecked(Boolean.TRUE).build());
List<AttendQuoteFieldPO> attendQuoteFields = new ArrayList<>();
attendQuoteFieldSettingList.forEach(s -> {
List<AttendQuoteFieldSettingFieldListDTO> items = s.getItems();
if (CollectionUtils.isNotEmpty(items)) {
items.forEach(i -> {
Optional<AttendQuoteFieldPO> optional = allAttendQuoteFields.stream().filter(f -> f.getId().equals(i.getId())).findFirst();
optional.ifPresent(attendQuoteFields::add);
});
}
});
return attendQuoteFields;
}
@Override
public String syncAttendQuoteData(AttendQuoteDataSyncParam syncParam) {
AttendQuoteDataSyncParam.checkParam(syncParam);
List<Long> salarySobIds = syncParam.getSalarySobIds();
String salaryYearMonth = syncParam.getSalaryYearMonth();
int year = Integer.parseInt(salaryYearMonth.split("-")[0]);
int month = Integer.parseInt(salaryYearMonth.split("-")[1]);
if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误,正确格式示例为'2021-01'"));
}
// 1.获取已设置的可同步的考勤字段
List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.QUOTE);
if (CollectionUtils.isEmpty(attendQuoteFields)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100366, "请先设置同步字段"));
}
String errorMsg = "";
for (Long salarySobId : salarySobIds) {
// 获取薪资账套
SalarySobCycleDTO salarySobCycleDTO = getSalarySobService(user).getSalarySobCycle(salarySobId, YearMonth.of(year, month));
SalarySobPO salarySobPO = getSalarySobService(user).getById(salarySobId);
// 根据薪资账套查询人员
List<DataCollectionEmployee> salaryEmployees = getSalaryEmployeeService(user).listBySalarySobId(salarySobId,false);
if (CollectionUtils.isEmpty(salaryEmployees)) {
errorMsg = errorMsg + "" + salarySobPO.getName() + "】薪资账套没有人员; ";
} else {
// 根据薪资账套查询薪资周期
List<Long> taxAgentIds = salarySobPO.getTaxAgentIds();
// 查询薪资档案,获取人员的个税扣缴义务人
List<Long> employeeIds = SalaryEntityUtil.properties(salaryEmployees, DataCollectionEmployee::getEmployeeId, Collectors.toList());
List<SalaryArchiveDataDTO> salaryArchiveDataDTOS = getSalaryArchiveService(user).getSalaryArchiveTaxAgentData(salarySobCycleDTO.getSalaryCycle(), employeeIds, taxAgentIds);
// 转换成薪资核算人员po
Date salaryDate = SalaryDateUtil.dateStrToLocalDate(salaryYearMonth + "-01");
// 查询领悦自定义岗位信息
Map<Long, Map<String, String>> ufJobtitleMap = getSalaryEmployeeService(user).listUfJobtitleMap(employeeIds);
List<SalaryAcctEmployeePO> salaryAcctEmployeePOS = SalaryAcctEmployeeBO.convert2Employee(salaryEmployees, SalaryAcctRecordPO.builder().salarySobId(salarySobId).salaryMonth(salaryDate).build(), salaryArchiveDataDTOS, ufJobtitleMap, (long) user.getUID());
//过滤掉不属于当前账套扣缴义务人的人员
employeeIds = salaryAcctEmployeePOS.stream().filter(po -> taxAgentIds.contains(po.getTaxAgentId())).map(SalaryAcctEmployeePO::getEmployeeId).collect(Collectors.toList());
// 4.获取考勤模块数据
List<Map<String, Object>> attendQuoteSyncData = getAttendQuoteDataFromRemoteAttend(salarySobCycleDTO.getAttendCycle(), employeeIds, attendQuoteFields);
List<AttendQuoteDataPO> pos = new ArrayList<>();
List<AttendQuoteDataValuePO> values = new ArrayList<>();
// 5.考勤引用数据处理
Date now = new Date();
if (CollectionUtils.isNotEmpty(attendQuoteSyncData)) {
// 3.生成考勤引用
AttendQuotePO attendQuote = getAttendQuote(AttendQuoteSourceTypeEnum.QUOTE, salarySobId, year, month, syncParam.getDescription());
for (Long employeeId : employeeIds) {
AttendQuoteDataPO po = new AttendQuoteDataPO();
po.setId(IdGenerator.generate());
po.setCreateTime(now);
po.setUpdateTime(now);
po.setCreator((long) user.getUID());
po.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
// 考勤引用表的主键id
po.setAttendQuoteId(attendQuote.getId());
po.setEmployeeId(employeeId);
pos.add(po);
for (Map<String, Object> attendQuoteData : attendQuoteSyncData) {
if (!Objects.isNull(attendQuoteData.get("employeeId")) &&
!Objects.isNull(employeeId) &&
!Objects.isNull(attendQuoteData.get("attendQuoteFieldId")) &&
attendQuoteData.get("employeeId").toString().equals(employeeId.toString())) {
values.add(AttendQuoteDataValuePO.builder()
.createTime(now)
.updateTime(now)
.creator((long) user.getUID())
.tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
.employeeId(employeeId)
.attendQuoteId(attendQuote.getId())
.attendQuoteDataId(po.getId())
.attendQuoteFieldId(Long.valueOf(attendQuoteData.get("attendQuoteFieldId").toString()))
.dataValue(Utils.null2String(attendQuoteData.get("dataValue")))
.build());
}
}
}
// 6.数据落库处理
handleDataToDB(attendQuote.getId(), pos, values);
// 记录日志
recordLog(attendQuote);
} else {
errorMsg = errorMsg + "" + salarySobPO.getName() + "" + "暂无考勤数据可以同步; ";
}
}
}
if (StringUtils.isNotBlank(errorMsg)) {
throw new SalaryRunTimeException(errorMsg);
}
return null;
}
private void recordLog(AttendQuotePO attendQuote) {
SalarySobPO salarySob = getSalarySobService(user).getById(attendQuote.getSalarySobId());
String sourceType = AttendQuoteSourceTypeEnum.getDefaultLabelByValue(attendQuote.getSourceType());
LoggerContext loggerContext = new LoggerContext();
loggerContext.setUser(user);
loggerContext.setTargetId(String.valueOf(attendQuote.getId()));
loggerContext.setTargetName(SalaryDateUtil.getFormatYearMonth(attendQuote.getSalaryYearMonth()) + " " + (salarySob != null ? salarySob.getName() : ""));
loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
loggerContext.setOperateTypeName(sourceType + SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
loggerContext.setOperatedesc(sourceType + SalaryI18nUtil.getI18nLabel(0, "考勤数据"));
loggerContext.setNewValues(attendQuote);
SalaryElogConfig.attendQuoteLoggerTemplate.write(loggerContext);
}
/**
* 获取考勤引用
*
* @param salarySobId
* @param year
* @param month
* @return
*/
private AttendQuotePO getAttendQuote(AttendQuoteSourceTypeEnum sourceType, Long salarySobId, int year, int month, String description) {
SalarySobCycleDTO salarySobCycle = getSalarySobService(user).getSalarySobCycle(salarySobId, YearMonth.of(year, month));
Date salaryYearMonthDayDate = SalaryDateUtil.localDateToDate(YearMonth.of(year, month).atDay(1));
List<AttendQuotePO> attendQuotes = quoteBiz.listSome(AttendQuotePO.builder().salarySobId(salarySobId).salaryYearMonth(salaryYearMonthDayDate).build());
// 考勤引用
AttendQuotePO attendQuote = new AttendQuotePO();
if (CollectionUtils.isNotEmpty(attendQuotes)) {
attendQuote = attendQuotes.get(0);
}
attendQuote.setSalarySobId(salarySobCycle.getSalarySobId());
LocalDateRange salaryCycleRange = salarySobCycle.getSalaryCycle();
LocalDateRange attendCycleRange = salarySobCycle.getAttendCycle();
// 考勤周期
attendQuote.setAttendCycle(SalaryDateUtil.getFormatLocalDate(attendCycleRange.getFromDate()) + " ~ " + SalaryDateUtil.getFormatLocalDate(attendCycleRange.getEndDate()));
// 薪资周期
attendQuote.setSalaryCycle(SalaryDateUtil.getFormatLocalDate(salaryCycleRange.getFromDate()) + " ~ " + SalaryDateUtil.getFormatLocalDate(salaryCycleRange.getEndDate()));
attendQuote.setSalaryYearMonth(salaryYearMonthDayDate);
// 来源:导入
attendQuote.setSourceType(sourceType.getValue());
attendQuote.setDescription(description);
Date now = new Date();
attendQuote.setCreateTime(now);
attendQuote.setUpdateTime(now);
attendQuote.setCreator((long) user.getUID());
attendQuote.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
// 新增或修改考勤引用
if (attendQuote.getId() != null) {
quoteBiz.updateById(attendQuote);
} else {
attendQuote.setId(IdGenerator.generate());
quoteBiz.insert(attendQuote);
}
return attendQuote;
}
/**
* 获取考勤模块数据
*
* @param attendCycleRange
* @param employeeIds
* @param attendQuoteFields
* @return
*/
private List<Map<String, Object>> getAttendQuoteDataFromRemoteAttend(LocalDateRange attendCycleRange, List<Long> employeeIds, List<AttendQuoteFieldPO> attendQuoteFields) {
List<Map<String, Object>> attendQuoteSyncData = new ArrayList<>();
Attend4Salary attend4Salary = new Attend4Salary();
try {
int partSize = 500;
List<List<Long>> partition = Lists.partition(employeeIds, partSize);
for (List<Long> part : partition) {
attend4Salary.setBeginDate(attendCycleRange.getFromDate());
attend4Salary.setEndDate(attendCycleRange.getEndDate());
attend4Salary.setOnlyEmpIds(part);
//班次信息
String attendanceSerial = attendQuoteFields.stream()
.filter(f -> f.getCode() != null && f.getCode().startsWith("attendanceSerial_"))
.map(f -> f.getCode().replace("attendanceSerial_", ""))
.collect(Collectors.joining(","));
attend4Salary.setAttendanceSerial(attendanceSerial);
List<Map<String, String>> attendResult = getRemoteAttend4SalaryService(user).getDatas(attend4Salary);
AttendQuoteDataBO.buildAttendDataFromRemote(attendResult, attendQuoteFields, attendQuoteSyncData);
}
} catch (Exception e) {
log.error("salaryAttend获取考勤数据错误失败:{}", String.format("参数:%s,错误信息:%s", JSONObject.toJSONString(attend4Salary), e.getMessage()), e);
return attendQuoteSyncData;
}
if (isLog) {
log.info("salaryAttend同步的考勤数据:{}", JSONUtils.toJSONString(attendQuoteSyncData));
}
return attendQuoteSyncData;
}
/**
* 引用同步或导入落库处理
*
* @param attendQuoteId
* @param pos
* @param values
*/
private void handleDataToDB(Long attendQuoteId, List<AttendQuoteDataPO> pos, List<AttendQuoteDataValuePO> values) {
// 数据落库处理
if (CollectionUtils.isEmpty(pos)) {
return;
}
// 多条相同人的则以第一条为准如果逆序排列用于重复的则以最后一条为准Collections.reverse(pos);
pos = pos.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getEmployeeId()))), ArrayList::new));
// 删除考勤数据
ArrayList<Long> quoteIds = new ArrayList<>();
quoteIds.add(attendQuoteId);
dataBiz.deleteByAttendQuoteIds(quoteIds);
// 新增考勤数据
dataBiz.insertData(pos);
// 删除考勤值数据
// dataValueBiz.deleteByAttendQuoteDataIds(pos.stream().map(AttendQuoteDataPO::getId).collect(Collectors.toList()));
dataValueBiz.deleteByAttendQuoteIds(quoteIds);
// 新增考勤值数据
if (CollectionUtils.isNotEmpty(values)) {
//去除空值
values = values.stream().filter(po -> StringUtils.isNotBlank(po.getDataValue())).collect(Collectors.toList());
dataValueBiz.insertData(values);
}
}
@Override
public XSSFWorkbook downloadTemplate(AttendQuoteDataExportTemplateParam exportParam) {
try {
// 考勤主数据
Date salaryYearMonth = SalaryDateUtil.localDateToDate(exportParam.getSalaryYearMonth().atDay(1));
List<AttendQuotePO> attendQuotePOS = quoteBiz.listSome(AttendQuotePO.builder()
.salarySobId(exportParam.getSalarySobId())
.salaryYearMonth(salaryYearMonth)
.ids(exportParam.getIds()).build());
AttendQuotePO po = CollectionUtils.isNotEmpty(attendQuotePOS) ? attendQuotePOS.get(0) : null;
AttendQuoteDataQueryParam queryParam = AttendQuoteDataQueryParam.builder().attendQuoteId(po == null ? 0L : po.getId()).build();
List<AttendQuoteDataBaseDTO> attendQuoteDataBases = dataBiz.list(queryParam);
// 获取已设置的可同步的字段
List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.IMPORT);
// 获取最终结果
List<Map<String, Object>> listMaps = getListMaps(attendQuoteDataBases);
// 1.工作簿名称
String sheetName = SalaryI18nUtil.getI18nLabel(101606, "考勤引用导入模板");
List<Object> header = new ArrayList<>();
header.add(SalaryI18nUtil.getI18nLabel(85429, "姓名"));
header.add(SalaryI18nUtil.getI18nLabel(86185, "部门"));
header.add(SalaryI18nUtil.getI18nLabel(86186, "手机号"));
header.add(SalaryI18nUtil.getI18nLabel(86317, "工号"));
header.add(SalaryI18nUtil.getI18nLabel(86317, "证件号码"));
// 动态列
for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
header.add(attendQuoteField.getFieldName());
}
List<List<Object>> rows = new ArrayList<>();
rows.add(header);
for (Map<String, Object> dto : listMaps) {
List<Object> row = new ArrayList<>();
row.add(dto.get("username"));
row.add(dto.get("departmentName"));
row.add(dto.get("mobile"));
row.add(dto.get("jobNum"));
// // 动态列
// Map<String, Object> map = listMaps.get(0);
// for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
// row.add(map.containsKey(attendQuoteField.getId() + "_attendQuoteData") ? dto.get(attendQuoteField.getId() + "_attendQuoteData") : "");
// }
rows.add(row);
}
return ExcelUtil.genWorkbookV2(rows, sheetName);
} catch (Exception e) {
log.error("salaryAttend下载模板失败", e);
}
return null;
}
/**
* 导入的数据插入到数据库中
*/
public Map<String, Object> preview(AttendQuoteDataImportParam param) {
ValidUtil.doValidator(param);
Long salarySobId = param.getSalarySobId();
SalarySobPO salarySobPO = getSalarySobService(user).getById(salarySobId);
if (salarySobPO == null) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100537, "薪资账套不存在"));
}
String salaryYearMonth = param.getSalaryYearMonth();
if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误,正确格式示例为'2021-01'"));
}
InputStream fileInputStream = null;
try {
fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
Map<String, Object> apidatas = new HashMap<String, Object>();
apidatas.put("headers", ExcelSupport.getSheetHeader(sheet, 0));
apidatas.put("list", ExcelParseHelper.parse2List(sheet, 1));
return apidatas;
} finally {
IOUtils.closeQuietly(fileInputStream);
}
}
/**
* 导入的数据插入到数据库中
*/
public Map<String, Object> importAttendQuoteData(AttendQuoteDataImportParam param) {
ValidUtil.doValidator(param);
Long salarySobId = param.getSalarySobId();
SalarySobPO salarySobPO = getSalarySobService(user).getById(salarySobId);
if (salarySobPO == null) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100537, "薪资账套不存在"));
}
String salaryYearMonth = param.getSalaryYearMonth();
if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100365, "薪资所属月格式有误,正确格式示例为'2021-01'"));
}
int year = Integer.parseInt(salaryYearMonth.split("-")[0]);
int month = Integer.parseInt(salaryYearMonth.split("-")[1]);
//查询对于人员信息导入筛选的全局配置
SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";
// 获取租户下所有的人员
List<DataCollectionEmployee> employees = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);
// 获取已设置的可同步的考勤字段
List<AttendQuoteFieldPO> attendQuoteFields = getAttendQuoteSetFields(AttendQuoteSourceTypeEnum.IMPORT);
// 生成获取考勤引用
AttendQuotePO attendQuote = getAttendQuote(AttendQuoteSourceTypeEnum.IMPORT, salarySobId, year, month, StringUtils.EMPTY);
int total = 0;
int index = 0;
int successCount = 0;
int errorCount = 0;
// 待导入数据
List<AttendQuoteDataPO> pos = new ArrayList<>();
List<AttendQuoteDataValuePO> values = new ArrayList<>();
String valI18n = SalaryI18nUtil.getI18nLabel(100581, "请输入数字");
InputStream fileInputStream = null;
try {
fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));
Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
// 表头
List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);
// 错误sheet数据
List<Map<String, Object>> errorData = new ArrayList<>();
// 错误提示
List<Map<String, String>> excelComments = new ArrayList<>();
//验证字段是否缺失
String isValidHeader = checkHeaders(headers, attendQuoteFields);
if (StringUtils.isNotBlank(isValidHeader)) {
Map<String, Object> apidatas = new HashMap<String, Object>();
apidatas.put("successCount", successCount);
apidatas.put("errorCount", errorCount);
Map<String, String> errorMessageMap = Maps.newHashMap();
errorMessageMap.put("message", isValidHeader);
excelComments.add(errorMessageMap);
apidatas.put("errorData", excelComments);
return apidatas;
}
// 处理数值
List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 1);
total = data.size();
Map<String, Object> map;
Date now = new Date();
AttendQuoteDataPO po;
for (int i = 0; i < data.size(); i++) {
index += 1;
String rowIndex = "" + index + "";
map = data.get(i);
po = new AttendQuoteDataPO();
po.setId(IdGenerator.generate());
po.setCreateTime(now);
po.setUpdateTime(now);
po.setCreator((long) user.getUID());
po.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
// 考勤引用表的主键id
po.setAttendQuoteId(attendQuote.getId());
int errorSum = 0;
String userName = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(85429, "姓名"))).orElse("").toString();
String deparmentName = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86185, "部门"))).orElse("").toString();
String mobile = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86186, "手机号"))).orElse("").toString();
String workcode = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86317, "工号"))).orElse("").toString();
String idNo = Optional.ofNullable(map.get(SalaryI18nUtil.getI18nLabel(86317, "证件号码"))).orElse("").toString();
List<Long> employeeSameIds = new ArrayList<>();
//筛选导入人员信息可以在人力资源池中匹配到的人员信息
List<DataCollectionEmployee> emps = getSalaryEmployeeService(user).matchImportEmployee(confValue, employees, userName, deparmentName, mobile, workcode, idNo, null);
//含在职和离职,选在职数据
if (CollectionUtils.isNotEmpty(emps) && emps.size() > 1) {
employeeSameIds = emps.stream()
.filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
.map(DataCollectionEmployee::getEmployeeId)
.collect(Collectors.toList());
}
if (CollectionUtils.isNotEmpty(emps) && emps.size() == 1) {
employeeSameIds = emps.stream()
.map(DataCollectionEmployee::getEmployeeId)
.collect(Collectors.toList());
}
for (int j = 0; j < headers.size(); j++) {
String key = headers.get(j);
if (key == null) {
continue;
}
String cellVal = Optional.ofNullable(map.get(key.toString())).orElse("").toString();
if (SalaryI18nUtil.getI18nLabel(85429, "姓名").equals(key.toString())) {
//当人员信息导入筛选的全局配置为"0"时,姓名才是必填项
if (StringUtils.isEmpty(cellVal) && "0".equals(confValue)) {
Map<String, String> errorMessageMap = Maps.newHashMap();
errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "姓名不能为空"));
excelComments.add(errorMessageMap);
errorSum += 1;
} else if (CollectionUtils.isEmpty(employeeSameIds) || employeeSameIds.size() > 1) {
Map<String, String> errorMessageMap = Maps.newHashMap();
errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "员工信息不存在或者存在多个员工"));
excelComments.add(errorMessageMap);
errorSum += 1;
} else {
Long employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0) : null;
if (employeeId != null && employeeId > 0) {
po.setEmployeeId(employeeId);
} else {
Map<String, String> errorMessageMap = Maps.newHashMap();
errorMessageMap.put("message", rowIndex + SalaryI18nUtil.getI18nLabel(100579, "姓名错误,系统内不存在该姓名"));
excelComments.add(errorMessageMap);
errorSum += 1;
}
}
}
if (po.getEmployeeId() != null) {
String bigDecimalValue;
for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
if (attendQuoteField.getFieldName().equals(key)) {
if (1 == attendQuoteField.getFieldType()) {
bigDecimalValue = bigDecimalVal(cellVal, excelComments, valI18n, errorCount + 1, j);
errorSum += StringUtils.isEmpty(bigDecimalValue) ? 1 : 0;
if (StringUtils.isNotEmpty(bigDecimalValue)) {
values.add(AttendQuoteDataValuePO.builder()
.createTime(now)
.updateTime(now)
.creator((long) user.getUID())
.tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
.employeeId(po.getEmployeeId())
.attendQuoteId(attendQuote.getId())
.attendQuoteDataId(po.getId())
.attendQuoteFieldId(attendQuoteField.getId())
.dataValue(Utils.null2String(bigDecimalValue))
.build());
}
} else {
values.add(AttendQuoteDataValuePO.builder()
.createTime(now)
.updateTime(now)
.creator((long) user.getUID())
.tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
.employeeId(po.getEmployeeId())
.attendQuoteId(attendQuote.getId())
.attendQuoteDataId(po.getId())
.attendQuoteFieldId(attendQuoteField.getId())
.dataValue(Utils.null2String(cellVal))
.build());
}
}
}
}
}
if (errorSum > 0) {
errorCount += 1;
// 添加错误数据
errorData.add(map);
} else {
successCount += 1;
// 成功一条就添加一条记录
pos.add(po);
}
// 导入进度
// salaryBatchService.sendImportRate(message.getBizId(), total, index);
}
// 数据入库处理
handleDataToDB(attendQuote.getId(), pos, values);
// 记录日志
recordLog(attendQuote);
Map<String, Object> apidatas = new HashMap<String, Object>();
apidatas.put("successCount", successCount);
apidatas.put("errorCount", errorCount);
apidatas.put("errorData", excelComments);
return apidatas;
} finally {
IOUtils.closeQuietly(fileInputStream);
}
}
/**
* @return null
* @description 编辑数据
* @author Harryxzy
* @date 2022/10/28 14:40
*/
@Override
public void editData(AttendQuoteDataEditParam attendQuoteDataEditParam) {
Map<String, String> attendQuoteData = attendQuoteDataEditParam.getAttendQuoteData();
AttendQuoteDataBiz dataBiz = new AttendQuoteDataBiz();
AttendQuoteDataValueBiz attendQuoteDataValueBiz = new AttendQuoteDataValueBiz();
ArrayList<Long> ids = new ArrayList<>();
ids.add(attendQuoteDataEditParam.getId());
AttendQuoteDataQueryParam build = AttendQuoteDataQueryParam.builder().ids(ids).build();
List<AttendQuoteDataBaseDTO> list = dataBiz.list(build);
if (list == null || list.size() == 0) {
throw new SalaryRunTimeException("该数据不存在!");
}
Map<String, String> attendQuoteFieldData = new HashMap<>();
for (Map.Entry<String, String> entrySet : attendQuoteData.entrySet()) {
String[] s = entrySet.getKey().split("_");
attendQuoteFieldData.put(s[0], entrySet.getValue());
}
for (Map.Entry<String, String> entrySet : attendQuoteFieldData.entrySet()) {
AttendQuoteDataValuePO updatePO = AttendQuoteDataValuePO.builder().employeeId(list.get(0).getEmployeeId()).attendQuoteFieldId(SalaryEntityUtil.string2Long(entrySet.getKey())).dataValue(entrySet.getValue()).build();
attendQuoteDataValueBiz.updateDataValue(updatePO);
}
}
/**
* @return void
* @description 获取数据
* @author Harryxzy
* @date 2022/10/31 14:12
*/
@Override
public Map<String, Object> getData(AttendQuoteDataEditParam attendQuoteDataEditParam) {
ArrayList<Long> ids = new ArrayList<>();
ids.add(attendQuoteDataEditParam.getId());
AttendQuoteDataQueryParam build = AttendQuoteDataQueryParam.builder().ids(ids).build();
List<AttendQuoteDataBaseDTO> list = dataBiz.list(build);
if (list == null || list.size() == 0) {
throw new SalaryRunTimeException("该数据不存在!");
}
// 所有考勤字段
List<AttendQuoteFieldPO> attendQuoteFields = getAllAttendQuoteFields();
// 获取最终结果
List<Map<String, Object>> listMaps = getListMaps(list);
List<WeaTableColumn> columns = new ArrayList<>();
columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(85429, "姓名"), "username"));
columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86185, "部门"), "departmentName"));
columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86186, "手机号"), "mobile"));
columns.add(new WeaTableColumn("150", SalaryI18nUtil.getI18nLabel(86317, "工号"), "jobNum"));
// 动态列
if (CollectionUtils.isNotEmpty(listMaps)) {
Map<String, Object> map = listMaps.stream().max(Comparator.comparingInt(m -> m.keySet().size())).get();
for (AttendQuoteFieldPO attendQuoteField : attendQuoteFields) {
if (map.containsKey(attendQuoteField.getId() + "_attendQuoteData")) {
columns.add(new WeaTableColumn("150", attendQuoteField.getFieldName(), attendQuoteField.getId() + "_attendQuoteData"));
}
}
}
WeaTable weaTable = new WeaTable();
weaTable.setColumns(columns);
WeaResultMsg result = new WeaResultMsg(false);
result.putAll(weaTable.makeDataResult());
result.success();
Map<String, Object> datas = new HashMap<>();
datas.put("data", listMaps.get(0));
datas.put("dataKey", result.getResultMap());
return datas;
}
/**
* 获取金额数字值
*
* @param bigDecimalValStr
* @param excelComments
* @param i
* @param j
* @return
*/
private String bigDecimalVal(String bigDecimalValStr, List<Map<String, String>> excelComments, String valI18n, int i, int j) {
if (StringUtils.isBlank(bigDecimalValStr)) {
return BigDecimal.ZERO.toString();
}
BigDecimal bigDecimalVal = null;
try {
bigDecimalVal = new BigDecimal(bigDecimalValStr);
} catch (Exception e) {
Map<String, String> errorMessageMap = Maps.newHashMap();
errorMessageMap.put("message", valI18n);
excelComments.add(errorMessageMap);
// salaryBatchService.createExcelComment(excelComments, valI18n, i, i, j, j);
}
return bigDecimalVal == null ? "" : bigDecimalVal.toString();
}
/**
* 检查参数
*
* @param message
* @param params
* @return
*/
// private boolean checkParams(BatchDocumentMessage message, Map<String, Object> params) {
// boolean isValid = true;
// String errorMsg = "";
// if (params == null) {
// errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100582, "参数必传");
// } else {
// if (!params.containsKey("salaryYearMonth")
// || !params.containsKey("salarySobId")
// || params.get("salaryYearMonth") == null
// || params.get("salarySobId") == null) {
// errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100588, "薪资所属月和薪资账套必传");
// } else {
// String salaryYearMonth = params.get("salaryYearMonth").toString();
// if (!SalaryDateUtil.checkYearMonth(salaryYearMonth)) {
// errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100365, "薪资所属月格式有误,正确格式示例为'2021-01'");
// } else {
// List<SalarySobPO> salarySobs = new LambdaQueryChainWrapper<>(getSalarySobMapper())
// .eq(SalarySobPO::getTenantKey, message.getTenantKey())
// .eq(SalarySobPO::getDeleteType, 0)
// .eq(SalarySobPO::getId, Long.valueOf(params.get("salarySobId").toString()))
// .list();
// if (CollectionUtils.isEmpty(salarySobs)) {
// errorMsg = SalaryI18nUtil.getI18nLabel(message.getTenantKey(), message.getUserId(), 100537, "薪资账套不存在");
// }
// }
// }
// }
// // 有错误信息发送
// if (StringUtils.isNotEmpty(errorMsg)) {
// // 发送导入回调信息
// salaryBatchService.sendImportCallBackInfo(message, errorMsg);
// isValid = false;
// }
// return isValid;
// }
/**
* 检查列头
*
* @return
*/
private String checkHeaders(List<String> headerList, List<AttendQuoteFieldPO> attendQuoteFields) {
boolean isValid = true;
String userNameI18n = SalaryI18nUtil.getI18nLabel(85429, "姓名");
List<String> mustHeaders = attendQuoteFields.stream().map(AttendQuoteFieldPO::getFieldName).collect(Collectors.toList());
mustHeaders.add(userNameI18n);
// 缺少的必须列
List<String> lackHeaders = mustHeaders.stream().filter(item -> !headerList.contains(item)).collect(Collectors.toList());
String errorMsg = "";
String checkHeaderI18n = SalaryI18nUtil.getI18nLabel(101850, "缺少如下列,请检查:");
if (CollectionUtils.isEmpty(attendQuoteFields)) {
errorMsg = SalaryI18nUtil.getI18nLabel(101849, "考勤字段列缺失,请补充");
} else if (CollectionUtils.isNotEmpty(lackHeaders)) {
errorMsg = checkHeaderI18n + Joiner.on(",").join((Iterable<?>) lackHeaders);
}
return errorMsg;
}
}