mirror of
https://codeup.aliyun.com/64f7d6b8ce01efaafef1e678/coal/coal.git
synced 2026-01-25 15:55:18 +08:00
完善
This commit is contained in:
184
src/main/java/cn/lihongjie/coal/common/GroovyScriptManager.java
Normal file
184
src/main/java/cn/lihongjie/coal/common/GroovyScriptManager.java
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package cn.lihongjie.coal.common;
|
||||||
|
|
||||||
|
import com.github.benmanes.caffeine.cache.Cache;
|
||||||
|
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||||
|
import com.github.benmanes.caffeine.cache.CaffeineSpec;
|
||||||
|
|
||||||
|
import groovy.lang.GroovyClassLoader;
|
||||||
|
import groovy.lang.GroovyCodeSource;
|
||||||
|
import groovy.lang.Script;
|
||||||
|
|
||||||
|
import lombok.SneakyThrows;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||||
|
import org.springframework.cglib.core.ReflectUtils;
|
||||||
|
import org.springframework.util.DigestUtils;
|
||||||
|
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
public class GroovyScriptManager {
|
||||||
|
|
||||||
|
private static final AtomicInteger counter = new AtomicInteger(0);
|
||||||
|
private final String name;
|
||||||
|
private final Cache<String, Class> scriptCache;
|
||||||
|
private final GroovyClassLoader groovyClassLoader;
|
||||||
|
private boolean logCompileTime = false;
|
||||||
|
|
||||||
|
public GroovyScriptManager() {
|
||||||
|
this(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroovyScriptManager(boolean logCompileTime) {
|
||||||
|
this((c) -> {}, logCompileTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroovyScriptManager(
|
||||||
|
Consumer<CompilerConfiguration> configCustomizer, boolean logCompileTime) {
|
||||||
|
this(null, configCustomizer, logCompileTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroovyScriptManager(
|
||||||
|
String name, Consumer<CompilerConfiguration> configCustomizer, boolean logCompileTime) {
|
||||||
|
this(name, "maximumSize=1000,expireAfterAccess=1h", configCustomizer, logCompileTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
public GroovyScriptManager(
|
||||||
|
String name,
|
||||||
|
String specification,
|
||||||
|
Consumer<CompilerConfiguration> configConsumer,
|
||||||
|
boolean logCompileTime) {
|
||||||
|
|
||||||
|
this.name = StringUtils.defaultIfBlank(name, "GroovyScriptManager-" + counter.get());
|
||||||
|
scriptCache = Caffeine.from(CaffeineSpec.parse(specification)).build();
|
||||||
|
|
||||||
|
CompilerConfiguration config = new CompilerConfiguration();
|
||||||
|
configConsumer.accept(config);
|
||||||
|
|
||||||
|
this.groovyClassLoader = new GroovyClassLoader(this.getClass().getClassLoader(), config);
|
||||||
|
this.logCompileTime = logCompileTime;
|
||||||
|
|
||||||
|
counter.incrementAndGet();
|
||||||
|
|
||||||
|
log.info("GroovyScriptManager: {} created", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 高性能版本API, 允许自定义缓存key */
|
||||||
|
public Class compile(String key, Supplier<String> scriptSupplier) {
|
||||||
|
|
||||||
|
StringBuilder logText = new StringBuilder();
|
||||||
|
|
||||||
|
logText.append("GroovyScriptManager: ").append(name).append("\n");
|
||||||
|
|
||||||
|
logText.append("compile groovy script: ").append(key).append("\n");
|
||||||
|
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
return scriptCache.get(
|
||||||
|
key,
|
||||||
|
k -> {
|
||||||
|
long getStart = System.currentTimeMillis();
|
||||||
|
String script = scriptSupplier.get();
|
||||||
|
|
||||||
|
long getEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
logText.append("getScriptTime: ").append(getEnd - getStart).append("ms\n");
|
||||||
|
GroovyCodeSource codeSource =
|
||||||
|
new GroovyCodeSource(script, key, "/groovy/script");
|
||||||
|
codeSource.setCachable(false);
|
||||||
|
|
||||||
|
long parseStart = System.currentTimeMillis();
|
||||||
|
Class parsedClass = this.groovyClassLoader.parseClass(codeSource);
|
||||||
|
long parseEnd = System.currentTimeMillis();
|
||||||
|
|
||||||
|
logText.append("parseTime: ").append(parseEnd - parseStart).append("ms\n");
|
||||||
|
return parsedClass;
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
long end = System.currentTimeMillis();
|
||||||
|
|
||||||
|
logText.append("totalTime: ").append(end - start).append("ms");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Script newInstance(String key, Supplier<String> scriptSupplier) {
|
||||||
|
|
||||||
|
Class aClass = compile(key, scriptSupplier);
|
||||||
|
|
||||||
|
Object o = ReflectUtils.newInstance(aClass);
|
||||||
|
|
||||||
|
if (o instanceof Script) {
|
||||||
|
return (Script) o;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"script must be instance of groovy.lang.Script, get " + aClass.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runWithScript(
|
||||||
|
String key, Supplier<String> scriptSupplier, Consumer<Script> scriptCustomizer) {
|
||||||
|
Script script = newInstance(key, scriptSupplier);
|
||||||
|
|
||||||
|
scriptCustomizer.accept(script);
|
||||||
|
|
||||||
|
script.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 易用性API, key 为 脚本内容的md5 */
|
||||||
|
public Class compile(Supplier<String> scriptSupplier) {
|
||||||
|
return compile(
|
||||||
|
DigestUtils.md5DigestAsHex(scriptSupplier.get().getBytes(StandardCharsets.UTF_8)),
|
||||||
|
scriptSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Class compile(String script) {
|
||||||
|
return compile(
|
||||||
|
DigestUtils.md5DigestAsHex(script.getBytes(StandardCharsets.UTF_8)), () -> script);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Script newInstance(Supplier<String> scriptSupplier) {
|
||||||
|
return newInstance(
|
||||||
|
DigestUtils.md5DigestAsHex(scriptSupplier.get().getBytes(StandardCharsets.UTF_8)),
|
||||||
|
scriptSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Script newInstance(String script) {
|
||||||
|
return newInstance(
|
||||||
|
DigestUtils.md5DigestAsHex(script.getBytes(StandardCharsets.UTF_8)), () -> script);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runWithScript(Supplier<String> scriptSupplier, Consumer<Script> scriptCustomizer) {
|
||||||
|
runWithScript(
|
||||||
|
DigestUtils.md5DigestAsHex(scriptSupplier.get().getBytes(StandardCharsets.UTF_8)),
|
||||||
|
scriptSupplier,
|
||||||
|
scriptCustomizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void runWithScript(String script, Consumer<Script> scriptCustomizer) {
|
||||||
|
runWithScript(
|
||||||
|
DigestUtils.md5DigestAsHex(script.getBytes(StandardCharsets.UTF_8)),
|
||||||
|
() -> script,
|
||||||
|
scriptCustomizer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidateAll() {
|
||||||
|
scriptCache.invalidateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void invalidate(String key) {
|
||||||
|
scriptCache.invalidate(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SneakyThrows
|
||||||
|
public void destroy() {
|
||||||
|
scriptCache.invalidateAll();
|
||||||
|
groovyClassLoader.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/main/java/cn/lihongjie/coal/common/MapUtils.java
Normal file
41
src/main/java/cn/lihongjie/coal/common/MapUtils.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.lihongjie.coal.common;
|
||||||
|
|
||||||
|
import lombok.experimental.UtilityClass;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
@UtilityClass
|
||||||
|
public class MapUtils {
|
||||||
|
|
||||||
|
public static <K, V> Map<K, V> keepKey(Map<K, V> src, Collection<K> keys) {
|
||||||
|
return keepOnlyKeys(src, keys::contains, HashMap::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> Map<K, V> keepOnlyKeys(
|
||||||
|
Map<K, V> src, Predicate<K> predicate, Supplier<Map<K, V>> mapSupplier) {
|
||||||
|
Map<K, V> result = mapSupplier.get();
|
||||||
|
|
||||||
|
for (Map.Entry<K, V> entry : src.entrySet()) {
|
||||||
|
if (predicate.test(entry.getKey())) {
|
||||||
|
result.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> void merge(Map<K, V> src, Map<K, V> target, Predicate<K> predicate) {
|
||||||
|
|
||||||
|
for (Map.Entry<K, V> entry : src.entrySet()) {
|
||||||
|
if (predicate.test(entry.getKey())) {
|
||||||
|
target.put(entry.getKey(), entry.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <K, V> void merge(Map<K, V> src, Map<K, V> target, Collection<K> keys) {
|
||||||
|
|
||||||
|
merge(src, target, keys::contains);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import cn.lihongjie.coal.empMonthAttendance.dto.UpdateEmpMonthAttendanceDto;
|
|||||||
import cn.lihongjie.coal.empMonthAttendance.entity.EmpMonthAttendanceEntity;
|
import cn.lihongjie.coal.empMonthAttendance.entity.EmpMonthAttendanceEntity;
|
||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.Mapping;
|
||||||
|
import org.mapstruct.Mappings;
|
||||||
import org.mapstruct.control.DeepClone;
|
import org.mapstruct.control.DeepClone;
|
||||||
|
|
||||||
@Mapper(
|
@Mapper(
|
||||||
@@ -22,4 +24,9 @@ public interface EmpMonthAttendanceMapper
|
|||||||
CreateEmpMonthAttendanceDto,
|
CreateEmpMonthAttendanceDto,
|
||||||
UpdateEmpMonthAttendanceDto> {
|
UpdateEmpMonthAttendanceDto> {
|
||||||
CreateEmpMonthAttendanceDto toCreateDto(UpdateEmpMonthAttendanceDto dto);
|
CreateEmpMonthAttendanceDto toCreateDto(UpdateEmpMonthAttendanceDto dto);
|
||||||
|
|
||||||
|
@Mappings(
|
||||||
|
@Mapping(target = "employee", ignore = true)
|
||||||
|
)
|
||||||
|
EmpMonthAttendanceDto toDto2(EmpMonthAttendanceEntity empMonthAttendance);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package cn.lihongjie.coal.empSalary.dto;
|
|||||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||||
|
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -13,9 +15,13 @@ public class CreateEmpSalaryDto extends OrgCommonDto {
|
|||||||
|
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
|
@NotNull
|
||||||
|
@NotEmpty
|
||||||
private String batch;
|
private String batch;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
|
@NotNull
|
||||||
|
@NotEmpty
|
||||||
private String employee;
|
private String employee;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
package cn.lihongjie.coal.empSalary.dto;
|
package cn.lihongjie.coal.empSalary.dto;
|
||||||
|
|
||||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||||
|
import cn.lihongjie.coal.base.dto.SimpleDto;
|
||||||
import cn.lihongjie.coal.common.DictCode;
|
import cn.lihongjie.coal.common.DictCode;
|
||||||
import cn.lihongjie.coal.empSalaryBatch.dto.EmpSalaryBatchDto;
|
import cn.lihongjie.coal.empSalaryBatch.dto.EmpSalaryBatchDto;
|
||||||
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
|
||||||
import cn.lihongjie.coal.pojoProcessor.DictTranslate;
|
import cn.lihongjie.coal.pojoProcessor.DictTranslate;
|
||||||
|
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
@@ -26,7 +26,7 @@ public class EmpSalaryDto extends OrgCommonDto {
|
|||||||
private EmpSalaryBatchDto batch;
|
private EmpSalaryBatchDto batch;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
private EmployeeDto employee;
|
private SimpleDto employee;
|
||||||
|
|
||||||
|
|
||||||
@Comment("员工快照")
|
@Comment("员工快照")
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package cn.lihongjie.coal.empSalary.dto;
|
|||||||
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||||
|
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.validation.constraints.NotEmpty;
|
||||||
|
import jakarta.validation.constraints.NotNull;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -13,9 +15,13 @@ public class UpdateEmpSalaryDto extends OrgCommonDto {
|
|||||||
|
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
|
@NotNull
|
||||||
|
@NotEmpty
|
||||||
private String batch;
|
private String batch;
|
||||||
|
|
||||||
@ManyToOne
|
@ManyToOne
|
||||||
|
@NotNull
|
||||||
|
@NotEmpty
|
||||||
private String employee;
|
private String employee;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
|||||||
import cn.lihongjie.coal.pojoProcessor.DictTranslate;
|
import cn.lihongjie.coal.pojoProcessor.DictTranslate;
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -33,11 +34,14 @@ public class EmpSalaryEntity extends OrgCommonEntity {
|
|||||||
"item41", "item42", "item43", "item44", "item45", "item46", "item47", "item48",
|
"item41", "item42", "item43", "item44", "item45", "item46", "item47", "item48",
|
||||||
"item49", "item50", "yfheji", "kfheji", "sfheji");
|
"item49", "item50", "yfheji", "kfheji", "sfheji");
|
||||||
|
|
||||||
@ManyToOne private EmpSalaryBatchEntity batch;
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private EmpSalaryBatchEntity batch;
|
||||||
|
|
||||||
@ManyToOne private EmployeeEntity employee;
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private EmployeeEntity employee;
|
||||||
|
|
||||||
@ManyToOne private EmpMonthAttendanceEntity empMonthAttendance;
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
private EmpMonthAttendanceEntity empMonthAttendance;
|
||||||
|
|
||||||
private BigDecimal item0;
|
private BigDecimal item0;
|
||||||
private BigDecimal item1;
|
private BigDecimal item1;
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import cn.lihongjie.coal.base.mapper.CommonEntityMapper;
|
|||||||
import cn.lihongjie.coal.base.mapper.CommonMapper;
|
import cn.lihongjie.coal.base.mapper.CommonMapper;
|
||||||
import cn.lihongjie.coal.empSalary.dto.CreateEmpSalaryDto;
|
import cn.lihongjie.coal.empSalary.dto.CreateEmpSalaryDto;
|
||||||
import cn.lihongjie.coal.empSalary.dto.EmpSalaryDto;
|
import cn.lihongjie.coal.empSalary.dto.EmpSalaryDto;
|
||||||
|
import cn.lihongjie.coal.empSalary.dto.RecalculatePreviewDto;
|
||||||
import cn.lihongjie.coal.empSalary.dto.UpdateEmpSalaryDto;
|
import cn.lihongjie.coal.empSalary.dto.UpdateEmpSalaryDto;
|
||||||
import cn.lihongjie.coal.empSalary.entity.EmpSalaryEntity;
|
import cn.lihongjie.coal.empSalary.entity.EmpSalaryEntity;
|
||||||
|
|
||||||
import org.mapstruct.Mapper;
|
import org.mapstruct.Mapper;
|
||||||
|
import org.mapstruct.MappingTarget;
|
||||||
import org.mapstruct.control.DeepClone;
|
import org.mapstruct.control.DeepClone;
|
||||||
|
|
||||||
@Mapper(
|
@Mapper(
|
||||||
@@ -16,4 +18,6 @@ import org.mapstruct.control.DeepClone;
|
|||||||
uses = {CommonMapper.class, CommonEntityMapper.class},
|
uses = {CommonMapper.class, CommonEntityMapper.class},
|
||||||
mappingControl = DeepClone.class)
|
mappingControl = DeepClone.class)
|
||||||
public interface EmpSalaryMapper
|
public interface EmpSalaryMapper
|
||||||
extends BaseMapper<EmpSalaryEntity, EmpSalaryDto, CreateEmpSalaryDto, UpdateEmpSalaryDto> {}
|
extends BaseMapper<EmpSalaryEntity, EmpSalaryDto, CreateEmpSalaryDto, UpdateEmpSalaryDto> {
|
||||||
|
void updateItems(RecalculatePreviewDto recDto, @MappingTarget UpdateEmpSalaryDto request);
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cn.lihongjie.coal.base.dto.IdRequest;
|
|||||||
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
|
import cn.lihongjie.coal.base.entity.OrgCommonEntity;
|
||||||
import cn.lihongjie.coal.base.service.BaseService;
|
import cn.lihongjie.coal.base.service.BaseService;
|
||||||
import cn.lihongjie.coal.common.GroovyScriptUtils;
|
import cn.lihongjie.coal.common.GroovyScriptUtils;
|
||||||
|
import cn.lihongjie.coal.common.MapUtils;
|
||||||
import cn.lihongjie.coal.common.ReflectUtils;
|
import cn.lihongjie.coal.common.ReflectUtils;
|
||||||
import cn.lihongjie.coal.empMonthAttendance.dto.EmpMonthAttendanceDto;
|
import cn.lihongjie.coal.empMonthAttendance.dto.EmpMonthAttendanceDto;
|
||||||
import cn.lihongjie.coal.empMonthAttendance.entity.EmpMonthAttendanceEntity;
|
import cn.lihongjie.coal.empMonthAttendance.entity.EmpMonthAttendanceEntity;
|
||||||
@@ -19,8 +20,10 @@ import cn.lihongjie.coal.empSalaryBatch.mapper.EmpSalaryBatchMapper;
|
|||||||
import cn.lihongjie.coal.empSalaryBatch.service.EmpSalaryBatchService;
|
import cn.lihongjie.coal.empSalaryBatch.service.EmpSalaryBatchService;
|
||||||
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
||||||
import cn.lihongjie.coal.empSalaryItem.service.EmpSalaryItemService;
|
import cn.lihongjie.coal.empSalaryItem.service.EmpSalaryItemService;
|
||||||
|
import cn.lihongjie.coal.employee.dto.EmployeeCalculateDto;
|
||||||
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
||||||
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
||||||
|
import cn.lihongjie.coal.employee.mapper.EmployeeMapper;
|
||||||
import cn.lihongjie.coal.employee.service.EmployeeService;
|
import cn.lihongjie.coal.employee.service.EmployeeService;
|
||||||
import cn.lihongjie.coal.exception.BizException;
|
import cn.lihongjie.coal.exception.BizException;
|
||||||
|
|
||||||
@@ -70,12 +73,7 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
@Autowired private ConversionService conversionService;
|
@Autowired private ConversionService conversionService;
|
||||||
|
|
||||||
public EmpSalaryDto create(CreateEmpSalaryDto request) {
|
@Autowired EmployeeMapper employeeMapper;
|
||||||
EmpSalaryEntity entity = mapper.toEntity(request);
|
|
||||||
|
|
||||||
this.repository.save(entity);
|
|
||||||
return getById(entity.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@PersistenceContext EntityManager em;
|
@PersistenceContext EntityManager em;
|
||||||
@Autowired RedissonClient redissonClient;
|
@Autowired RedissonClient redissonClient;
|
||||||
@@ -108,11 +106,35 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
@Autowired EmpSalaryItemService empSalaryItemService;
|
@Autowired EmpSalaryItemService empSalaryItemService;
|
||||||
|
|
||||||
|
private static void assertBatchEditable(EmpSalaryBatchEntity salaryBatch) {
|
||||||
|
if (salaryBatch.getStatus() != 1) {
|
||||||
|
throw new BizException("批次不属于编辑状态, 无法编辑或删除");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void removeCommonField(Map<String, Object> ctx) {
|
||||||
|
ReflectUtils.getAllFieldsList(OrgCommonEntity.class)
|
||||||
|
.forEach(
|
||||||
|
f -> {
|
||||||
|
ctx.remove(f.getName());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmpSalaryDto create(CreateEmpSalaryDto request) {
|
||||||
|
assertBatchEditable(request.getBatch());
|
||||||
|
EmpSalaryEntity entity = mapper.toEntity(request);
|
||||||
|
|
||||||
|
this.repository.save(entity);
|
||||||
|
return getById(entity.getId());
|
||||||
|
}
|
||||||
|
|
||||||
public EmpSalaryDto update(UpdateEmpSalaryDto request) {
|
public EmpSalaryDto update(UpdateEmpSalaryDto request) {
|
||||||
|
|
||||||
|
assertBatchEditable(request.getBatch());
|
||||||
|
|
||||||
var recDto = recalculatePreview(request);
|
var recDto = recalculatePreview(request);
|
||||||
|
|
||||||
updateItems(recDto, request);
|
this.mapper.updateItems(recDto, request);
|
||||||
|
|
||||||
EmpSalaryEntity entity = this.repository.get(request.getId());
|
EmpSalaryEntity entity = this.repository.get(request.getId());
|
||||||
if (this.repository.containArchived(request.getId())) {
|
if (this.repository.containArchived(request.getId())) {
|
||||||
@@ -125,21 +147,6 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
return getById(entity.getId());
|
return getById(entity.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateItems(RecalculatePreviewDto recDto, UpdateEmpSalaryDto request) {
|
|
||||||
|
|
||||||
for (String key : EmpSalaryEntity.ITEM_KEYS) {
|
|
||||||
ReflectUtils.writeField(
|
|
||||||
request, key, conversionService.convert(ReflectUtils.readField(recDto, key), BigDecimal.class));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void delete(IdRequest request) {
|
|
||||||
if (this.repository.containArchived(request)) {
|
|
||||||
throw new BizException("部分数据已归档,无法编辑或删除");
|
|
||||||
}
|
|
||||||
this.repository.deleteAllById(request.getIds());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired EmpSalaryBatchService batchService;
|
@Autowired EmpSalaryBatchService batchService;
|
||||||
@Autowired EmployeeService employeeService;
|
@Autowired EmployeeService employeeService;
|
||||||
|
|
||||||
@@ -193,47 +200,23 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
.getResultList();
|
.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private void assertBatchEditable(String batch) {
|
||||||
* 按照ID进行重新计算
|
|
||||||
*
|
|
||||||
* @param ids
|
|
||||||
*/
|
|
||||||
public void recalculate(IdRequest ids) {
|
|
||||||
|
|
||||||
List<EmpSalaryEntity> salaries =
|
EmpSalaryBatchEntity salaryBatch = batchService.get(batch);
|
||||||
em.createQuery(
|
|
||||||
"select s from EmpSalaryEntity s join fetch s.employee join fetch s.batch join fetch s.empMonthAttendance where s.id in :ids",
|
|
||||||
EmpSalaryEntity.class)
|
|
||||||
.setParameter("ids", ids.getIds())
|
|
||||||
.getResultList();
|
|
||||||
|
|
||||||
recalculate(salaries, true);
|
assertBatchEditable(salaryBatch);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 针对某个员工重新计算, 用于编辑表单的预览 */
|
public void delete(IdRequest request) {
|
||||||
@SneakyThrows
|
|
||||||
public RecalculatePreviewDto recalculatePreview(UpdateEmpSalaryDto dto) {
|
|
||||||
|
|
||||||
EmpSalaryBatchEntity batch = this.batchService.get(dto.getBatch());
|
List<EmpSalaryEntity> all = this.findAllByIds(request.getIds());
|
||||||
|
|
||||||
EmpSalaryEntity salary = this.get(dto.getId());
|
all.stream().map(x -> x.getBatch().getId()).distinct().forEach(this::assertBatchEditable);
|
||||||
|
|
||||||
GroovyClassLoader groovyClassLoader = null;
|
if (this.repository.containArchived(request)) {
|
||||||
groovyClassLoader = initClassLoader(groovyClassLoader);
|
throw new BizException("部分数据已归档,无法编辑或删除");
|
||||||
|
}
|
||||||
Script scriptObj = initScriptClass(groovyClassLoader, genScript(batch));
|
this.repository.deleteAllById(request.getIds());
|
||||||
|
|
||||||
Map<String, Object> ctx = buildCtx(null, null, null, salary);
|
|
||||||
|
|
||||||
// 覆盖工资项目
|
|
||||||
|
|
||||||
overWriteSalaryItem(ctx, ReflectUtils.toMap(dto));
|
|
||||||
|
|
||||||
scriptObj.setBinding(new Binding(Map.of("salary", ctx)));
|
|
||||||
|
|
||||||
scriptObj.run();
|
|
||||||
|
|
||||||
return buildDto(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private RecalculatePreviewDto buildDto(Map<String, Object> ctx) {
|
private RecalculatePreviewDto buildDto(Map<String, Object> ctx) {
|
||||||
@@ -264,6 +247,57 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 按照ID进行重新计算
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
public void recalculate(IdRequest ids) {
|
||||||
|
|
||||||
|
List<EmpSalaryEntity> salaries =
|
||||||
|
em.createQuery(
|
||||||
|
"""
|
||||||
|
select s from EmpSalaryEntity s
|
||||||
|
left join fetch s.employee e
|
||||||
|
left join fetch e.department
|
||||||
|
left join fetch e.jobPost
|
||||||
|
|
||||||
|
left join fetch s.batch
|
||||||
|
left join fetch s.empMonthAttendance
|
||||||
|
where s.id in :ids""",
|
||||||
|
EmpSalaryEntity.class)
|
||||||
|
.setParameter("ids", ids.getIds())
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
|
||||||
|
salaries.stream().map(x -> x.getBatch().getId()).distinct().forEach(this::assertBatchEditable);
|
||||||
|
|
||||||
|
recalculate(salaries, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 针对某个员工重新计算, 用于编辑表单的预览 */
|
||||||
|
@SneakyThrows
|
||||||
|
public RecalculatePreviewDto recalculatePreview(UpdateEmpSalaryDto dto) {
|
||||||
|
|
||||||
|
EmpSalaryBatchEntity batch = this.batchService.get(dto.getBatch());
|
||||||
|
|
||||||
|
EmpSalaryEntity salary = this.get(dto.getId());
|
||||||
|
|
||||||
|
Script scriptObj = empSalaryItemService.newScriptInstance(batch.getOrganizationId());
|
||||||
|
|
||||||
|
Map<String, Object> ctx = buildPreviewCtx(dto, salary);
|
||||||
|
|
||||||
|
// 覆盖工资项目
|
||||||
|
|
||||||
|
overWriteSalaryItem(ctx, ReflectUtils.toMap(dto));
|
||||||
|
|
||||||
|
scriptObj.setBinding(new Binding(Map.of("salary", ctx)));
|
||||||
|
|
||||||
|
scriptObj.run();
|
||||||
|
|
||||||
|
return buildDto(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/** 重新计算 */
|
/** 重新计算 */
|
||||||
@SneakyThrows
|
@SneakyThrows
|
||||||
public void recalculate(List<EmpSalaryEntity> salaries, boolean update) {
|
public void recalculate(List<EmpSalaryEntity> salaries, boolean update) {
|
||||||
@@ -274,7 +308,7 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
EmpSalaryBatchEntity batch = salaries.get(0).getBatch();
|
EmpSalaryBatchEntity batch = salaries.get(0).getBatch();
|
||||||
|
|
||||||
StopWatch stopWatch = new StopWatch("initSalary: " + batch.getId());
|
StopWatch stopWatch = new StopWatch("recalculate: " + batch.getId());
|
||||||
|
|
||||||
stopWatch.start("getLock");
|
stopWatch.start("getLock");
|
||||||
RLock lock = redissonClient.getLock("batchModify." + batch.getId());
|
RLock lock = redissonClient.getLock("batchModify." + batch.getId());
|
||||||
@@ -295,26 +329,19 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
checkBatchStatus(batch);
|
checkBatchStatus(batch);
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
// 查询考勤数据
|
|
||||||
|
|
||||||
stopWatch.start("genScript");
|
|
||||||
// 生成计算脚本
|
|
||||||
String script = genScript(batch);
|
|
||||||
|
|
||||||
stopWatch.stop();
|
|
||||||
|
|
||||||
stopWatch.start("parseScript");
|
stopWatch.start("parseScript");
|
||||||
groovyClassLoader = initClassLoader(groovyClassLoader);
|
|
||||||
|
|
||||||
Script scriptObj = initScriptClass(groovyClassLoader, script);
|
|
||||||
|
Script scriptObj = empSalaryItemService.newScriptInstance(batch.getOrganizationId());
|
||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
List<EmployeeDto> dtoByIds =
|
var dtoByIds = salaries.stream().map(x -> x.getEmployee()).map(employeeMapper::toCalculateDto).toList();
|
||||||
this.employeeService.getDtoByIds(
|
|
||||||
salaries.stream().map(e -> e.getEmployee().getId()).toList());
|
|
||||||
|
|
||||||
Map<String, EmployeeDto> dtoMap =
|
|
||||||
|
Map<String, EmployeeCalculateDto> dtoMap =
|
||||||
dtoByIds.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
|
dtoByIds.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
|
||||||
|
|
||||||
// 执行计算脚本
|
// 执行计算脚本
|
||||||
@@ -323,11 +350,9 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
var employee = salary.getEmployee();
|
var employee = salary.getEmployee();
|
||||||
|
|
||||||
EmpMonthAttendanceEntity attendance = salary.getEmpMonthAttendance();
|
|
||||||
stopWatch.start("buildCtx: " + employee.getName());
|
stopWatch.start("buildCtx: " + employee.getName());
|
||||||
|
|
||||||
Map<String, Object> ctx =
|
Map<String, Object> ctx = buildRecalculateCtx(salary);
|
||||||
buildCtx(batch, dtoMap.get(employee.getId()), attendance, salary);
|
|
||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
@@ -347,7 +372,6 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
salary.update(salaryEntity);
|
salary.update(salaryEntity);
|
||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
// salaries.add(salaryEntity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存到数据库
|
// 保存到数据库
|
||||||
@@ -380,11 +404,10 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
public void initSalary(InitSalaryDto initSalaryDto) {
|
public void initSalary(InitSalaryDto initSalaryDto) {
|
||||||
|
|
||||||
EmpSalaryBatchEntity batch = batchService.get(initSalaryDto.getBatchId());
|
EmpSalaryBatchEntity batch = batchService.get(initSalaryDto.getBatchId());
|
||||||
|
|
||||||
List<EmployeeDto> employees = employeeService.getDtoByIds(initSalaryDto.getEmployeesIds());
|
|
||||||
|
|
||||||
StopWatch stopWatch = new StopWatch("initSalary: " + batch.getId());
|
StopWatch stopWatch = new StopWatch("initSalary: " + batch.getId());
|
||||||
|
|
||||||
|
var employees = employeeService.getCalculateDtoByIds(initSalaryDto.getEmployeesIds());
|
||||||
|
|
||||||
stopWatch.start("getLock");
|
stopWatch.start("getLock");
|
||||||
RLock lock = redissonClient.getLock("batchModify." + batch.getId());
|
RLock lock = redissonClient.getLock("batchModify." + batch.getId());
|
||||||
|
|
||||||
@@ -394,7 +417,6 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
if (!tryLock) {
|
if (!tryLock) {
|
||||||
batchModifing(batch);
|
batchModifing(batch);
|
||||||
}
|
}
|
||||||
GroovyClassLoader groovyClassLoader = null;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
@@ -418,12 +440,6 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
stopWatch.start("genScript");
|
|
||||||
// 生成计算脚本
|
|
||||||
String script = genScript(batch);
|
|
||||||
|
|
||||||
stopWatch.stop();
|
|
||||||
|
|
||||||
stopWatch.start("getItems");
|
stopWatch.start("getItems");
|
||||||
// 获取工资项
|
// 获取工资项
|
||||||
List<EmpSalaryItemEntity> items =
|
List<EmpSalaryItemEntity> items =
|
||||||
@@ -434,16 +450,14 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
.filter(
|
.filter(
|
||||||
x ->
|
x ->
|
||||||
BooleanUtils.isTrue(x.getInherit())
|
BooleanUtils.isTrue(x.getInherit())
|
||||||
&& StringUtils.equalsAny(x.getInputType(), "0"))
|
&& StringUtils.equalsAny(x.getInputType(), "1"))
|
||||||
.filter(x -> ObjectUtils.notEqual(x.getStatus(), 0))
|
.filter(x -> ObjectUtils.notEqual(x.getStatus(), 0))
|
||||||
.toList();
|
.toList();
|
||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
stopWatch.start("parseScript");
|
stopWatch.start("newScriptInstance");
|
||||||
groovyClassLoader = initClassLoader(groovyClassLoader);
|
Script scriptObj = empSalaryItemService.newScriptInstance(batch.getOrganizationId());
|
||||||
|
|
||||||
Script scriptObj = initScriptClass(groovyClassLoader, script);
|
|
||||||
|
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
|
|
||||||
@@ -463,7 +477,7 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
List<EmpSalaryEntity> salaries = new ArrayList<>();
|
List<EmpSalaryEntity> salaries = new ArrayList<>();
|
||||||
|
|
||||||
for (EmployeeDto employee : employees) {
|
for (var employee : employees) {
|
||||||
|
|
||||||
EmpMonthAttendanceEntity attendance =
|
EmpMonthAttendanceEntity attendance =
|
||||||
attMap.containsKey(employee.getId())
|
attMap.containsKey(employee.getId())
|
||||||
@@ -471,12 +485,9 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
: null;
|
: null;
|
||||||
stopWatch.start("buildCtx: " + employee.getName());
|
stopWatch.start("buildCtx: " + employee.getName());
|
||||||
|
|
||||||
Map<String, Object> ctx = buildCtx(batch, employee, attendance, null);
|
Map<String, Object> ctx = buildInitCtx(batch, employee, attendance);
|
||||||
|
|
||||||
stopWatch.stop();
|
|
||||||
|
|
||||||
// todo 处理继承项
|
|
||||||
|
|
||||||
|
// 继承历史工资数据
|
||||||
if (salaryHisMap.containsKey(employee.getId())
|
if (salaryHisMap.containsKey(employee.getId())
|
||||||
&& CollectionUtils.isNotEmpty(inheritItems)) {
|
&& CollectionUtils.isNotEmpty(inheritItems)) {
|
||||||
|
|
||||||
@@ -488,6 +499,7 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
salaryHisMap.get(employee.getId()), inheritItem.getCode()));
|
salaryHisMap.get(employee.getId()), inheritItem.getCode()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
stopWatch.stop();
|
||||||
|
|
||||||
// 计算
|
// 计算
|
||||||
|
|
||||||
@@ -521,14 +533,114 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (groovyClassLoader != null) {
|
|
||||||
groovyClassLoader.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info(stopWatch.prettyPrint());
|
log.info(stopWatch.prettyPrint());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> buildInitCtx(
|
||||||
|
EmpSalaryBatchEntity batchEntity,
|
||||||
|
EmployeeCalculateDto employeeEntity,
|
||||||
|
EmpMonthAttendanceEntity monthAttendanceEntity) {
|
||||||
|
|
||||||
|
var employeeCtx = buildCtx(employeeEntity);
|
||||||
|
var batchCtx = buildCtx(batchEntity);
|
||||||
|
var empMonthAttendanceCtx = buildCtx(monthAttendanceEntity);
|
||||||
|
var salaryCtx = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.putAll(salaryCtx);
|
||||||
|
map.putAll(employeeCtx);
|
||||||
|
map.putAll(batchCtx);
|
||||||
|
map.putAll(empMonthAttendanceCtx);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 编辑预览的时候构建上下文 从数据库中取所有冗余数据 + 前端传过来的工资数据
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Map<String, Object> buildPreviewCtx(UpdateEmpSalaryDto dto, EmpSalaryEntity entity) {
|
||||||
|
|
||||||
|
EmpSalaryDto salaryDto = this.mapper.toDto(entity);
|
||||||
|
|
||||||
|
Map<String, Object> userInput = ReflectUtils.toMap(dto);
|
||||||
|
|
||||||
|
Map<String, Object> ctx = ReflectUtils.toMap(salaryDto);
|
||||||
|
|
||||||
|
MapUtils.merge(userInput, ctx, EmpSalaryEntity.ITEM_KEYS);
|
||||||
|
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> buildRecalculateCtx(EmpSalaryEntity entity) {
|
||||||
|
|
||||||
|
var employeeCtx = buildCtx(employeeMapper.toCalculateDto(entity.getEmployee()));
|
||||||
|
var batchCtx = buildCtx(entity.getBatch());
|
||||||
|
var empMonthAttendanceCtx = buildCtx(entity.getEmpMonthAttendance());
|
||||||
|
var salaryCtx = buildCtx(entity, true);
|
||||||
|
|
||||||
|
HashMap<String, Object> map = new HashMap<>();
|
||||||
|
map.putAll(salaryCtx);
|
||||||
|
map.putAll(employeeCtx);
|
||||||
|
map.putAll(batchCtx);
|
||||||
|
map.putAll(empMonthAttendanceCtx);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildCtx(EmpSalaryEntity entity, boolean onlyItems) {
|
||||||
|
|
||||||
|
if (entity == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
EmpSalaryDto salary = empSalaryMapper.toDto(entity);
|
||||||
|
|
||||||
|
Map<String, Object> map = ReflectUtils.toMap(salary);
|
||||||
|
|
||||||
|
if (onlyItems) {
|
||||||
|
|
||||||
|
return MapUtils.keepKey(map, EmpSalaryEntity.ITEM_KEYS);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
removeCommonField(map);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildCtx(EmpMonthAttendanceEntity empMonthAttendance) {
|
||||||
|
|
||||||
|
if (empMonthAttendance == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var attendance = empMonthAttendanceMapper.toDto2(empMonthAttendance);
|
||||||
|
|
||||||
|
Map<String, Object> map = ReflectUtils.toMap(attendance);
|
||||||
|
|
||||||
|
map.put("attendanceId", empMonthAttendance.getId());
|
||||||
|
|
||||||
|
removeCommonField(map);
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildCtx(EmpSalaryBatchEntity batch) {
|
||||||
|
|
||||||
|
if (batch == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
var batchDto = empSalaryBatchMapper.toDto(batch);
|
||||||
|
|
||||||
|
Map<String, Object> batchMap = ReflectUtils.toMap(batchDto);
|
||||||
|
|
||||||
|
batchMap.put("batchId", batch.getId());
|
||||||
|
|
||||||
|
removeCommonField(batchMap);
|
||||||
|
|
||||||
|
return batchMap;
|
||||||
|
}
|
||||||
|
|
||||||
@Autowired EmpMonthAttendanceMapper empMonthAttendanceMapper;
|
@Autowired EmpMonthAttendanceMapper empMonthAttendanceMapper;
|
||||||
|
|
||||||
private String genScript(EmpSalaryBatchEntity batch) {
|
private String genScript(EmpSalaryBatchEntity batch) {
|
||||||
@@ -544,13 +656,38 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Map<String, Object> buildCtx(EmployeeCalculateDto employee) {
|
||||||
|
|
||||||
|
if (employee == null) {
|
||||||
|
return new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> empMap = ReflectUtils.toMap(employee);
|
||||||
|
|
||||||
|
empMap.put("empId", employee.getId());
|
||||||
|
empMap.put("empName", employee.getName());
|
||||||
|
empMap.put("empCode", employee.getCode());
|
||||||
|
|
||||||
|
Try.run(() -> empMap.put("departmentId", employee.getDepartment().getId()));
|
||||||
|
Try.run(() -> empMap.put("departmentCode", employee.getDepartment().getCode()));
|
||||||
|
Try.run(() -> empMap.put("departmentName", employee.getDepartment().getName()));
|
||||||
|
Try.run(() -> empMap.put("jobPostId", employee.getJobPost().getId()));
|
||||||
|
Try.run(() -> empMap.put("jobPostCode", employee.getJobPost().getCode()));
|
||||||
|
Try.run(() -> empMap.put("jobPostName", employee.getJobPost().getName()));
|
||||||
|
|
||||||
|
removeCommonField(empMap);
|
||||||
|
return empMap;
|
||||||
|
}
|
||||||
|
|
||||||
private @NotNull Map<String, List<EmpMonthAttendanceEntity>> queryAttendanceMap(
|
private @NotNull Map<String, List<EmpMonthAttendanceEntity>> queryAttendanceMap(
|
||||||
EmpSalaryBatchEntity batch, List<EmployeeDto> employees) {
|
EmpSalaryBatchEntity batch, List<EmployeeCalculateDto> employees) {
|
||||||
List<EmpMonthAttendanceEntity> attendances =
|
List<EmpMonthAttendanceEntity> attendances =
|
||||||
em.createQuery(
|
em.createQuery(
|
||||||
"select a from EmpMonthAttendanceEntity a where a.employee.id in :empIds and a.yearMonth = :yearMonth",
|
"select a from EmpMonthAttendanceEntity a where a.employee.id in :empIds and a.yearMonth = :yearMonth",
|
||||||
EmpMonthAttendanceEntity.class)
|
EmpMonthAttendanceEntity.class)
|
||||||
.setParameter("empIds", employees.stream().map(EmployeeDto::getId).toList())
|
.setParameter(
|
||||||
|
"empIds",
|
||||||
|
employees.stream().map(EmployeeCalculateDto::getId).toList())
|
||||||
.setParameter("yearMonth", batch.getBatchYearMonth())
|
.setParameter("yearMonth", batch.getBatchYearMonth())
|
||||||
.getResultList();
|
.getResultList();
|
||||||
|
|
||||||
@@ -559,29 +696,11 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
return attMap;
|
return attMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkBatchStatus(EmpSalaryBatchEntity batch) {}
|
private void checkBatchStatus(EmpSalaryBatchEntity batch) {
|
||||||
|
|
||||||
private void checkDuplicate(EmpSalaryBatchEntity batch, List<EmployeeDto> employees) {
|
|
||||||
List<EmpSalaryEntity> exists =
|
|
||||||
em.createQuery(
|
|
||||||
"select s from EmpSalaryEntity s where s.batch.id = :batchId and s.employee.id in :empIds",
|
|
||||||
EmpSalaryEntity.class)
|
|
||||||
.setParameter("batchId", batch.getId())
|
|
||||||
.setParameter("empIds", employees.stream().map(EmployeeDto::getId).toList())
|
|
||||||
.getResultList();
|
|
||||||
|
|
||||||
if (!exists.isEmpty()) {
|
assertBatchEditable(batch);
|
||||||
|
|
||||||
for (EmpSalaryEntity exist : exists) {
|
|
||||||
log.warn("批次 {} 员工 {} 工资数据已存在", batch.getId(), exist.getEmployee().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new BizException(
|
|
||||||
"部分员工工资数据已存在: {}",
|
|
||||||
exists.stream()
|
|
||||||
.map(e -> e.getEmployee().getName())
|
|
||||||
.collect(Collectors.joining(",")));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired EmpSalaryMapper empSalaryMapper;
|
@Autowired EmpSalaryMapper empSalaryMapper;
|
||||||
@@ -595,16 +714,52 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
return groovyClassLoader;
|
return groovyClassLoader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkDuplicate(EmpSalaryBatchEntity batch, List<EmployeeCalculateDto> employees) {
|
||||||
|
List<EmpSalaryEntity> exists =
|
||||||
|
em.createQuery(
|
||||||
|
"select s from EmpSalaryEntity s where s.batch.id = :batchId and s.employee.id in :empIds",
|
||||||
|
EmpSalaryEntity.class)
|
||||||
|
.setParameter("batchId", batch.getId())
|
||||||
|
.setParameter(
|
||||||
|
"empIds",
|
||||||
|
employees.stream().map(EmployeeCalculateDto::getId).toList())
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
if (!exists.isEmpty()) {
|
||||||
|
|
||||||
|
for (EmpSalaryEntity exist : exists) {
|
||||||
|
log.warn("批次 {} 员工 {} 工资数据已存在", batch.getName(), exist.getEmployee().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BizException(
|
||||||
|
"部分员工工资数据已存在: {}",
|
||||||
|
exists.stream()
|
||||||
|
.map(e -> e.getEmployee().getName())
|
||||||
|
.collect(Collectors.joining(",")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<EmpSalaryEntity> queryHisSalary(List<String> employeesIds) {
|
private List<EmpSalaryEntity> queryHisSalary(List<String> employeesIds) {
|
||||||
|
|
||||||
return new ArrayList<>();
|
em.createNativeQuery(
|
||||||
// return this.em
|
"""
|
||||||
// .createQuery(
|
with tmp1 as (
|
||||||
// "select s from EmpSalaryEntity s where s.employee.id in :empIds
|
|
||||||
// and rank() over (partition by s.employee.id order by s.createTime desc ) = 1",
|
select s.id, rank() over (partition by employee_id order by batch_year_month desc ) rk from t_emp_salary s where s.employee_id in :ids
|
||||||
// EmpSalaryEntity.class)
|
)
|
||||||
// .setParameter("empIds", employeesIds)
|
|
||||||
// .getResultList();
|
select id from tmp1 where rk = 1
|
||||||
|
|
||||||
|
""",
|
||||||
|
String.class)
|
||||||
|
.setParameter("ids", employeesIds)
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
return em.createQuery(
|
||||||
|
"select s from EmpSalaryEntity s where s.employee.id in :ids",
|
||||||
|
EmpSalaryEntity.class)
|
||||||
|
.setParameter("ids", employeesIds)
|
||||||
|
.getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -659,11 +814,7 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
// 移除通用字段
|
// 移除通用字段
|
||||||
|
|
||||||
ReflectUtils.getAllFieldsList(OrgCommonEntity.class)
|
removeCommonField(ctx);
|
||||||
.forEach(
|
|
||||||
f -> {
|
|
||||||
ctx.remove(f.getName());
|
|
||||||
});
|
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
@@ -674,15 +825,4 @@ public class EmpSalaryService extends BaseService<EmpSalaryEntity, EmpSalaryRepo
|
|||||||
|
|
||||||
log.info("删除工资数据 {} 条", cnt);
|
log.info("删除工资数据 {} 条", cnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendToAudit(IdRequest request) {
|
|
||||||
|
|
||||||
EmpSalaryBatchEntity batch = this.batchService.get(request.getId());
|
|
||||||
|
|
||||||
if (!StringUtils.equalsAny(batch.getBatchStatus(), "1")) {
|
|
||||||
throw new BizException("批次状态不正确");
|
|
||||||
}
|
|
||||||
|
|
||||||
batch.setBatchStatus("2");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package cn.lihongjie.coal.empSalaryItem.repository;
|
|||||||
import cn.lihongjie.coal.base.dao.BaseRepository;
|
import cn.lihongjie.coal.base.dao.BaseRepository;
|
||||||
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
||||||
|
|
||||||
|
import org.springframework.data.jpa.repository.Query;
|
||||||
|
import org.springframework.data.repository.query.Param;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@@ -11,4 +13,17 @@ public interface EmpSalaryItemRepository extends BaseRepository<EmpSalaryItemEnt
|
|||||||
|
|
||||||
long countByNameContainsAndOrganizationIdAndIdNot(
|
long countByNameContainsAndOrganizationIdAndIdNot(
|
||||||
String name, String organizationId, String id);
|
String name, String organizationId, String id);
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
value =
|
||||||
|
"""
|
||||||
|
select md5(string_agg(t.f, ',')) from (
|
||||||
|
select f from (
|
||||||
|
select code ,formula f from t_emp_salary_item where organization_id = :organizationId
|
||||||
|
union all
|
||||||
|
select code, item_expression f from t_emp_salary_sys_item
|
||||||
|
) as t order by code asc) as t
|
||||||
|
""",
|
||||||
|
nativeQuery = true)
|
||||||
|
String computeCacheKey(@Param("organizationId") String organizationId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,27 +4,27 @@ import cn.lihongjie.coal.base.dto.CommonQuery;
|
|||||||
import cn.lihongjie.coal.base.dto.IdRequest;
|
import cn.lihongjie.coal.base.dto.IdRequest;
|
||||||
import cn.lihongjie.coal.base.service.BaseService;
|
import cn.lihongjie.coal.base.service.BaseService;
|
||||||
import cn.lihongjie.coal.common.Ctx;
|
import cn.lihongjie.coal.common.Ctx;
|
||||||
import cn.lihongjie.coal.empSalary.entity.EmpSalaryEntity;
|
import cn.lihongjie.coal.common.GroovyScriptManager;
|
||||||
import cn.lihongjie.coal.empSalaryBatch.entity.EmpSalaryBatchEntity;
|
|
||||||
import cn.lihongjie.coal.empSalaryItem.dto.CreateEmpSalaryItemDto;
|
import cn.lihongjie.coal.empSalaryItem.dto.CreateEmpSalaryItemDto;
|
||||||
import cn.lihongjie.coal.empSalaryItem.dto.EmpSalaryItemDto;
|
import cn.lihongjie.coal.empSalaryItem.dto.EmpSalaryItemDto;
|
||||||
import cn.lihongjie.coal.empSalaryItem.dto.UpdateEmpSalaryItemDto;
|
import cn.lihongjie.coal.empSalaryItem.dto.UpdateEmpSalaryItemDto;
|
||||||
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
import cn.lihongjie.coal.empSalaryItem.entity.EmpSalaryItemEntity;
|
||||||
import cn.lihongjie.coal.empSalaryItem.mapper.EmpSalaryItemMapper;
|
import cn.lihongjie.coal.empSalaryItem.mapper.EmpSalaryItemMapper;
|
||||||
import cn.lihongjie.coal.empSalaryItem.repository.EmpSalaryItemRepository;
|
import cn.lihongjie.coal.empSalaryItem.repository.EmpSalaryItemRepository;
|
||||||
import cn.lihongjie.coal.empSalaryStandard.dto.EmpSalaryStandardResult;
|
|
||||||
import cn.lihongjie.coal.empSalaryStandard.service.EmpSalaryStandardService;
|
import cn.lihongjie.coal.empSalaryStandard.service.EmpSalaryStandardService;
|
||||||
import cn.lihongjie.coal.empSalarySysItem.entity.EmpSalarySysItemEntity;
|
import cn.lihongjie.coal.empSalarySysItem.entity.EmpSalarySysItemEntity;
|
||||||
import cn.lihongjie.coal.empSalarySysItem.service.EmpSalarySysItemService;
|
import cn.lihongjie.coal.empSalarySysItem.service.EmpSalarySysItemService;
|
||||||
import cn.lihongjie.coal.exception.BizException;
|
import cn.lihongjie.coal.exception.BizException;
|
||||||
|
|
||||||
import groovy.lang.GroovyClassLoader;
|
import groovy.lang.Closure;
|
||||||
import groovy.lang.Script;
|
import groovy.lang.Script;
|
||||||
|
|
||||||
import io.vavr.Tuple;
|
import io.vavr.Tuple;
|
||||||
import io.vavr.Tuple2;
|
import io.vavr.Tuple2;
|
||||||
import io.vavr.collection.Stream;
|
import io.vavr.collection.Stream;
|
||||||
|
|
||||||
|
import jakarta.annotation.PostConstruct;
|
||||||
|
import jakarta.annotation.PreDestroy;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.PersistenceContext;
|
import jakarta.persistence.PersistenceContext;
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
@@ -32,7 +32,6 @@ import jakarta.persistence.criteria.CriteriaQuery;
|
|||||||
import jakarta.persistence.criteria.Predicate;
|
import jakarta.persistence.criteria.Predicate;
|
||||||
import jakarta.persistence.criteria.Root;
|
import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
import lombok.SneakyThrows;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
@@ -43,6 +42,7 @@ import org.codehaus.groovy.ast.CodeVisitorSupport;
|
|||||||
import org.codehaus.groovy.ast.builder.AstStringCompiler;
|
import org.codehaus.groovy.ast.builder.AstStringCompiler;
|
||||||
import org.codehaus.groovy.ast.expr.VariableExpression;
|
import org.codehaus.groovy.ast.expr.VariableExpression;
|
||||||
import org.codehaus.groovy.control.CompilerConfiguration;
|
import org.codehaus.groovy.control.CompilerConfiguration;
|
||||||
|
import org.codehaus.groovy.control.customizers.SecureASTCustomizer;
|
||||||
import org.jgrapht.alg.cycle.CycleDetector;
|
import org.jgrapht.alg.cycle.CycleDetector;
|
||||||
import org.jgrapht.graph.DefaultDirectedGraph;
|
import org.jgrapht.graph.DefaultDirectedGraph;
|
||||||
import org.jgrapht.graph.DefaultEdge;
|
import org.jgrapht.graph.DefaultEdge;
|
||||||
@@ -56,8 +56,10 @@ import org.springframework.data.jpa.domain.Specification;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@@ -74,6 +76,7 @@ public class EmpSalaryItemService
|
|||||||
@Autowired private EmpSalaryStandardService empSalaryStandardService;
|
@Autowired private EmpSalaryStandardService empSalaryStandardService;
|
||||||
|
|
||||||
@PersistenceContext EntityManager em;
|
@PersistenceContext EntityManager em;
|
||||||
|
private GroovyScriptManager groovyScriptManager;
|
||||||
|
|
||||||
public List<EmpSalaryItemEntity> findAllBy(
|
public List<EmpSalaryItemEntity> findAllBy(
|
||||||
String organizationId, List<String> dependOn, List<String> dependOnSysItem) {
|
String organizationId, List<String> dependOn, List<String> dependOnSysItem) {
|
||||||
@@ -176,6 +179,47 @@ public class EmpSalaryItemService
|
|||||||
|
|
||||||
@Autowired EmpSalarySysItemService empSalarySysItemService;
|
@Autowired EmpSalarySysItemService empSalarySysItemService;
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
groovyScriptManager =
|
||||||
|
new GroovyScriptManager(
|
||||||
|
"salaryItemScript",
|
||||||
|
new Consumer<CompilerConfiguration>() {
|
||||||
|
@Override
|
||||||
|
public void accept(CompilerConfiguration compilerConfiguration) {
|
||||||
|
|
||||||
|
compilerConfiguration.addCompilationCustomizers(
|
||||||
|
new SecureASTCustomizer() {
|
||||||
|
{
|
||||||
|
setAllowedImports(List.of("java.lang.Math"));
|
||||||
|
|
||||||
|
setAllowedReceiversClasses(
|
||||||
|
Arrays.asList(
|
||||||
|
Object[].class,
|
||||||
|
Arrays.class,
|
||||||
|
java.math.RoundingMode.class,
|
||||||
|
Closure.class,
|
||||||
|
Map.class,
|
||||||
|
Object.class,
|
||||||
|
Math.class,
|
||||||
|
Integer.class,
|
||||||
|
Float.class,
|
||||||
|
Double.class,
|
||||||
|
Long.class,
|
||||||
|
BigDecimal.class));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void destroy() {
|
||||||
|
groovyScriptManager.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateDep(List<EmpSalaryItemEntity> enabled, List<EmpSalaryItemEntity> allItems) {
|
private void updateDep(List<EmpSalaryItemEntity> enabled, List<EmpSalaryItemEntity> allItems) {
|
||||||
|
|
||||||
List<EmpSalarySysItemEntity> sysItems =
|
List<EmpSalarySysItemEntity> sysItems =
|
||||||
@@ -593,82 +637,6 @@ public class EmpSalaryItemService
|
|||||||
repository.save(item3);
|
repository.save(item3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SneakyThrows
|
|
||||||
public void calculate(
|
|
||||||
String organizationId, EmpSalaryBatchEntity batch, List<EmpSalaryEntity> list) {
|
|
||||||
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
long stdTime = 0;
|
|
||||||
long newInstanceTime = 0;
|
|
||||||
long setPropertyTime = 0;
|
|
||||||
long runTime = 0;
|
|
||||||
|
|
||||||
long x = System.nanoTime();
|
|
||||||
Class scriptClass = genClass(organizationId);
|
|
||||||
long y = System.nanoTime();
|
|
||||||
|
|
||||||
long genClassTime = y - x;
|
|
||||||
|
|
||||||
for (EmpSalaryEntity salary : list) {
|
|
||||||
|
|
||||||
long a = System.nanoTime();
|
|
||||||
Map<String, EmpSalaryStandardResult> stdMap =
|
|
||||||
empSalaryStandardService.calculateSalaryStandard(salary.getEmployee()).stream()
|
|
||||||
.collect(Collectors.toMap(e -> e.getName(), e -> e));
|
|
||||||
long b = System.nanoTime();
|
|
||||||
stdTime = stdTime + (b - a);
|
|
||||||
|
|
||||||
Script script = (Script) scriptClass.newInstance();
|
|
||||||
long c = System.nanoTime();
|
|
||||||
|
|
||||||
newInstanceTime = newInstanceTime + (c - b);
|
|
||||||
|
|
||||||
script.setProperty("salary", salary);
|
|
||||||
script.setProperty("emp", salary.getEmployee());
|
|
||||||
script.setProperty("stdMap", stdMap);
|
|
||||||
script.setProperty("batch", batch);
|
|
||||||
|
|
||||||
long d = System.nanoTime();
|
|
||||||
|
|
||||||
setPropertyTime = setPropertyTime + (d - c);
|
|
||||||
|
|
||||||
script.run();
|
|
||||||
long e = System.nanoTime();
|
|
||||||
|
|
||||||
runTime = runTime + (e - d);
|
|
||||||
}
|
|
||||||
|
|
||||||
long totalTime = stdTime + newInstanceTime + setPropertyTime + runTime + genClassTime;
|
|
||||||
log.info(
|
|
||||||
"totalTime: {} ns {} ms {}%\n"
|
|
||||||
+ "genClassTime: {} ns {} ms {}%\n"
|
|
||||||
+ "stdTime: {} ns {} ms {}%\n"
|
|
||||||
+ "newInstanceTime: {} ns {} ms {}%\n"
|
|
||||||
+ "setPropertyTime: {} ns {} ms {}%\n"
|
|
||||||
+ "runTime: {} ns {} ms {}%\n",
|
|
||||||
totalTime,
|
|
||||||
totalTime / 1000000,
|
|
||||||
1L * 100.0,
|
|
||||||
genClassTime,
|
|
||||||
genClassTime / 1000000,
|
|
||||||
genClassTime / totalTime * 100.0,
|
|
||||||
stdTime,
|
|
||||||
stdTime / 1000000,
|
|
||||||
stdTime / totalTime * 100.0,
|
|
||||||
newInstanceTime,
|
|
||||||
newInstanceTime / 1000000,
|
|
||||||
newInstanceTime / totalTime * 100.0,
|
|
||||||
setPropertyTime,
|
|
||||||
setPropertyTime / 1000000,
|
|
||||||
setPropertyTime / totalTime * 100.0,
|
|
||||||
runTime,
|
|
||||||
runTime / 1000000,
|
|
||||||
runTime / totalTime * 100.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String genScript(String organizationId) {
|
public String genScript(String organizationId) {
|
||||||
|
|
||||||
List<EmpSalaryItemEntity> items =
|
List<EmpSalaryItemEntity> items =
|
||||||
@@ -759,8 +727,26 @@ public class EmpSalaryItemService
|
|||||||
|
|
||||||
script.append("// 工资项目开始\n");
|
script.append("// 工资项目开始\n");
|
||||||
|
|
||||||
|
StringBuilder roundScript = new StringBuilder();
|
||||||
|
roundScript.append("// 保留小数位处理\n");
|
||||||
|
|
||||||
for (EmpSalaryItemEntity item : items) {
|
for (EmpSalaryItemEntity item : items) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
roundScript
|
||||||
|
.append("salary.")
|
||||||
|
.append(item.getCode())
|
||||||
|
.append(" = ")
|
||||||
|
.append(" ROUND( ")
|
||||||
|
.append(" salary.")
|
||||||
|
.append(item.getCode())
|
||||||
|
.append(" , ")
|
||||||
|
.append(ObjectUtils.defaultIfNull(item.getDecimalPlaces(), 2))
|
||||||
|
.append(" , ")
|
||||||
|
.append(StringUtils.defaultIfBlank(item.getDecimalPlacesHandler(), "0"))
|
||||||
|
.append(");\n");
|
||||||
|
|
||||||
if (StringUtils.equalsAnyIgnoreCase(item.getInputType(), "1")) {
|
if (StringUtils.equalsAnyIgnoreCase(item.getInputType(), "1")) {
|
||||||
|
|
||||||
script.append("/** \n")
|
script.append("/** \n")
|
||||||
@@ -793,6 +779,9 @@ public class EmpSalaryItemService
|
|||||||
.append(" ?: 0")
|
.append(" ?: 0")
|
||||||
.append(";\n");
|
.append(";\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,56 +816,19 @@ public class EmpSalaryItemService
|
|||||||
.append(" = (")
|
.append(" = (")
|
||||||
.append(item.getFormula())
|
.append(item.getFormula())
|
||||||
.append(") ?: 0 ;\n");
|
.append(") ?: 0 ;\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
script.append("// 工资项目结束\n");
|
script.append("// 工资项目结束\n");
|
||||||
|
|
||||||
|
roundScript.append("// 保留小数位处理\n");
|
||||||
|
|
||||||
|
script.append(roundScript);
|
||||||
return script.toString();
|
return script.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class genClass(String organizationId) {
|
|
||||||
List<EmpSalaryItemEntity> items =
|
|
||||||
this.findAll(
|
|
||||||
new Specification<EmpSalaryItemEntity>() {
|
|
||||||
@Override
|
|
||||||
public Predicate toPredicate(
|
|
||||||
Root<EmpSalaryItemEntity> root,
|
|
||||||
CriteriaQuery<?> query,
|
|
||||||
CriteriaBuilder criteriaBuilder) {
|
|
||||||
return criteriaBuilder.and(
|
|
||||||
criteriaBuilder.equal(
|
|
||||||
root.get("organizationId"), organizationId),
|
|
||||||
criteriaBuilder.equal(root.get("status"), 1));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
items.sort(Comparator.comparing(EmpSalaryItemEntity::getPriority));
|
|
||||||
|
|
||||||
var script = new StringBuilder();
|
|
||||||
|
|
||||||
for (EmpSalaryItemEntity item : items) {
|
|
||||||
|
|
||||||
if (StringUtils.equalsAnyIgnoreCase(item.getInputType(), "1")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isEmpty(item.getFormula())) {
|
|
||||||
throw new BizException("公式计算项公式不能为空: " + item.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
script.append("salary.")
|
|
||||||
.append(item.getCode())
|
|
||||||
.append(" = ")
|
|
||||||
.append(item.getFormula())
|
|
||||||
.append("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
Class scriptClass =
|
|
||||||
new GroovyClassLoader(this.getClass().getClassLoader(), new CompilerConfiguration())
|
|
||||||
.parseClass(script.toString());
|
|
||||||
return scriptClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<EmpSalaryItemEntity> getItems(String organizationId) {
|
public List<EmpSalaryItemEntity> getItems(String organizationId) {
|
||||||
|
|
||||||
return this.findAll(
|
return this.findAll(
|
||||||
@@ -892,4 +844,20 @@ public class EmpSalaryItemService
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String computeCacheKey(String organizationId) {
|
||||||
|
|
||||||
|
return this.repository.computeCacheKey(organizationId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public Script newScriptInstance(String organizationId){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return groovyScriptManager.newInstance(computeCacheKey(organizationId), () -> genScript(organizationId));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
package cn.lihongjie.coal.employee.dto;
|
||||||
|
|
||||||
|
import cn.lihongjie.coal.base.dto.OrgCommonDto;
|
||||||
|
import cn.lihongjie.coal.common.DictCode;
|
||||||
|
import cn.lihongjie.coal.department.dto.DepartmentDto;
|
||||||
|
import cn.lihongjie.coal.jobPost.dto.JobPostDto;
|
||||||
|
import cn.lihongjie.coal.pojoProcessor.DictTranslate;
|
||||||
|
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import org.hibernate.annotations.Comment;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class EmployeeCalculateDto extends OrgCommonDto {
|
||||||
|
@Comment("性别")
|
||||||
|
private String sex;
|
||||||
|
|
||||||
|
@Comment("性别-名称")
|
||||||
|
@DictTranslate(dictKey = DictCode.SEX)
|
||||||
|
private String sexName;
|
||||||
|
|
||||||
|
@Comment("民族")
|
||||||
|
private String nation;
|
||||||
|
|
||||||
|
@Comment("民族-名称")
|
||||||
|
@DictTranslate(dictKey = DictCode.NATION)
|
||||||
|
private String nationName;
|
||||||
|
|
||||||
|
@Comment("婚姻状况")
|
||||||
|
private String marriage;
|
||||||
|
|
||||||
|
@Comment("婚姻状况-名称")
|
||||||
|
@DictTranslate(dictKey = DictCode.MARRIAGE)
|
||||||
|
private String marriageName;
|
||||||
|
|
||||||
|
@Comment("入职时间")
|
||||||
|
private LocalDate entryDate;
|
||||||
|
|
||||||
|
@Comment("身份证号")
|
||||||
|
private String idCard;
|
||||||
|
|
||||||
|
@Comment("学历")
|
||||||
|
private String education;
|
||||||
|
|
||||||
|
@Comment("学历-名称")
|
||||||
|
@DictTranslate(dictKey = DictCode.EDUCATION)
|
||||||
|
private String educationName;
|
||||||
|
|
||||||
|
@Comment("毕业学校")
|
||||||
|
private String school;
|
||||||
|
|
||||||
|
@Comment("籍贯")
|
||||||
|
private String nativePlace;
|
||||||
|
|
||||||
|
@Comment("住址")
|
||||||
|
private String address;
|
||||||
|
|
||||||
|
@Comment("手机号")
|
||||||
|
private String phone;
|
||||||
|
|
||||||
|
@Comment("部门")
|
||||||
|
@ManyToOne
|
||||||
|
private DepartmentDto department;
|
||||||
|
|
||||||
|
@Comment("岗位")
|
||||||
|
@ManyToOne
|
||||||
|
private JobPostDto jobPost;
|
||||||
|
|
||||||
|
@Comment("银行编码")
|
||||||
|
private String bank;
|
||||||
|
|
||||||
|
@DictTranslate(dictKey = DictCode.BANK)
|
||||||
|
private String bankName;
|
||||||
|
|
||||||
|
@Comment("银行卡号")
|
||||||
|
private String bankCardNumber;
|
||||||
|
|
||||||
|
@Comment("收款人姓名")
|
||||||
|
private String bankCardName;
|
||||||
|
|
||||||
|
@Comment("离职时间")
|
||||||
|
private LocalDate resignDate;
|
||||||
|
|
||||||
|
@Comment("离职原因")
|
||||||
|
private String resignReason;
|
||||||
|
|
||||||
|
@Comment("员工状态")
|
||||||
|
private String empStatus;
|
||||||
|
|
||||||
|
@DictTranslate(dictKey = DictCode.EMP_STATUS)
|
||||||
|
private String empStatusName;
|
||||||
|
|
||||||
|
@Comment("养老保险基数")
|
||||||
|
private Double insurance1Base;
|
||||||
|
|
||||||
|
@Comment("养老保险比例")
|
||||||
|
private Double insurance1Percent;
|
||||||
|
|
||||||
|
@Comment("医疗保险基数")
|
||||||
|
private Double insurance2Base;
|
||||||
|
|
||||||
|
@Comment("医疗保险比例")
|
||||||
|
private Double insurance2Percent;
|
||||||
|
|
||||||
|
@Comment("失业保险基数")
|
||||||
|
private Double insurance3Base;
|
||||||
|
|
||||||
|
@Comment("失业保险比例")
|
||||||
|
private Double insurance3Percent;
|
||||||
|
|
||||||
|
@Comment("工伤保险基数")
|
||||||
|
private Double insurance4Base;
|
||||||
|
|
||||||
|
@Comment("工伤保险比例")
|
||||||
|
private Double insurance4Percent;
|
||||||
|
|
||||||
|
@Comment("生育保险基数")
|
||||||
|
private Double insurance5Base;
|
||||||
|
|
||||||
|
@Comment("生育保险比例")
|
||||||
|
private Double insurance5Percent;
|
||||||
|
|
||||||
|
@Comment("住房公积金基数")
|
||||||
|
private Double insurance6Base;
|
||||||
|
|
||||||
|
@Comment("住房公积金比例")
|
||||||
|
private Double insurance6Percent;
|
||||||
|
|
||||||
|
@Comment("工龄")
|
||||||
|
private Double workAge;
|
||||||
|
|
||||||
|
@Comment("年龄")
|
||||||
|
private Double age;
|
||||||
|
|
||||||
|
@Comment("出生日期")
|
||||||
|
private LocalDate birthday;
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package cn.lihongjie.coal.employee.mapper;
|
|||||||
|
|
||||||
import cn.lihongjie.coal.base.mapper.BaseMapper;
|
import cn.lihongjie.coal.base.mapper.BaseMapper;
|
||||||
import cn.lihongjie.coal.employee.dto.CreateEmployeeDto;
|
import cn.lihongjie.coal.employee.dto.CreateEmployeeDto;
|
||||||
|
import cn.lihongjie.coal.employee.dto.EmployeeCalculateDto;
|
||||||
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
||||||
import cn.lihongjie.coal.employee.dto.UpdateEmployeeDto;
|
import cn.lihongjie.coal.employee.dto.UpdateEmployeeDto;
|
||||||
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
||||||
@@ -17,4 +18,6 @@ public interface EmployeeMapper
|
|||||||
extends BaseMapper<EmployeeEntity, EmployeeDto, CreateEmployeeDto, UpdateEmployeeDto> {
|
extends BaseMapper<EmployeeEntity, EmployeeDto, CreateEmployeeDto, UpdateEmployeeDto> {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EmployeeCalculateDto toCalculateDto(EmployeeEntity list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,10 +10,7 @@ import cn.lihongjie.coal.department.dto.DepartmentDto;
|
|||||||
import cn.lihongjie.coal.department.entity.DepartmentEntity;
|
import cn.lihongjie.coal.department.entity.DepartmentEntity;
|
||||||
import cn.lihongjie.coal.department.service.DepartmentService;
|
import cn.lihongjie.coal.department.service.DepartmentService;
|
||||||
import cn.lihongjie.coal.dictionary.service.DictionaryService;
|
import cn.lihongjie.coal.dictionary.service.DictionaryService;
|
||||||
import cn.lihongjie.coal.employee.dto.CreateEmployeeDto;
|
import cn.lihongjie.coal.employee.dto.*;
|
||||||
import cn.lihongjie.coal.employee.dto.EmployeeDto;
|
|
||||||
import cn.lihongjie.coal.employee.dto.ImportEmpFromExcelRequest;
|
|
||||||
import cn.lihongjie.coal.employee.dto.UpdateEmployeeDto;
|
|
||||||
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
import cn.lihongjie.coal.employee.entity.EmployeeEntity;
|
||||||
import cn.lihongjie.coal.employee.mapper.EmployeeMapper;
|
import cn.lihongjie.coal.employee.mapper.EmployeeMapper;
|
||||||
import cn.lihongjie.coal.employee.repository.EmployeeRepository;
|
import cn.lihongjie.coal.employee.repository.EmployeeRepository;
|
||||||
@@ -267,6 +264,25 @@ public class EmployeeService extends BaseService<EmployeeEntity, EmployeeReposit
|
|||||||
|
|
||||||
return collect;
|
return collect;
|
||||||
}
|
}
|
||||||
|
public List<EmployeeCalculateDto> getCalculateDtoByIds(List<String> employeesIds) {
|
||||||
|
|
||||||
|
|
||||||
|
List<EmployeeEntity> entity = em.createQuery("select e from EmployeeEntity e left join fetch e.jobPost left join fetch e.department where e.id in :ids", EmployeeEntity.class)
|
||||||
|
.setParameter("ids", employeesIds)
|
||||||
|
.getResultList();
|
||||||
|
|
||||||
|
|
||||||
|
List<EmployeeCalculateDto> collect =
|
||||||
|
entity.stream()
|
||||||
|
.map(mapper::toCalculateDto)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
pojoProcessor.process(collect, false);
|
||||||
|
|
||||||
|
return collect;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public void refreshAge(String organizationId) {
|
public void refreshAge(String organizationId) {
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user