package cn.iocoder.yudao.module.mes.service.pro.wage;
|
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.wage.vo.MesProProcessWageRulePageReqVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.wage.vo.MesProProcessWageRuleResolveRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.wage.vo.MesProProcessWageRuleSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.dv.machinery.MesDvMachineryDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.wage.MesProProcessWageRuleDO;
|
import cn.iocoder.yudao.module.mes.dal.mysql.pro.wage.MesProProcessWageRuleMapper;
|
import cn.iocoder.yudao.module.mes.service.dv.machinery.MesDvMachineryService;
|
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
|
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteService;
|
import jakarta.annotation.Resource;
|
import org.springframework.stereotype.Service;
|
import org.springframework.validation.annotation.Validated;
|
|
import java.math.BigDecimal;
|
import java.time.LocalDate;
|
import java.util.Comparator;
|
import java.util.List;
|
import java.util.Objects;
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*;
|
|
/**
|
* MES 工序工资单价规则 Service 实现类
|
*
|
* @author 超级管理员
|
*/
|
@Service
|
@Validated
|
public class MesProProcessWageRuleServiceImpl implements MesProProcessWageRuleService {
|
|
@Resource
|
private MesProProcessWageRuleMapper ruleMapper;
|
@Resource
|
private MesProProcessService processService;
|
@Resource
|
private MesProRouteService routeService;
|
@Resource
|
private MesDvMachineryService machineryService;
|
|
@Override
|
public PageResult<MesProProcessWageRuleDO> getRulePage(MesProProcessWageRulePageReqVO pageReqVO) {
|
return ruleMapper.selectPage(pageReqVO);
|
}
|
|
@Override
|
public List<MesProProcessWageRuleDO> getRuleListByProcessId(Long processId) {
|
return ruleMapper.selectListByProcessId(processId);
|
}
|
|
@Override
|
public Long createRule(MesProProcessWageRuleSaveReqVO createReqVO) {
|
validateRule(createReqVO);
|
MesProProcessWageRuleDO rule = BeanUtils.toBean(createReqVO, MesProProcessWageRuleDO.class)
|
.setId(null)
|
.setStatus(ObjUtil.defaultIfNull(createReqVO.getStatus(), CommonStatusEnum.ENABLE.getStatus()))
|
.setPriority(ObjUtil.defaultIfNull(createReqVO.getPriority(), 0));
|
ruleMapper.insert(rule);
|
return rule.getId();
|
}
|
|
@Override
|
public void updateRule(MesProProcessWageRuleSaveReqVO updateReqVO) {
|
validateRuleExists(updateReqVO.getId());
|
validateRule(updateReqVO);
|
ruleMapper.updateById(BeanUtils.toBean(updateReqVO, MesProProcessWageRuleDO.class));
|
}
|
|
@Override
|
public void deleteRule(Long id) {
|
validateRuleExists(id);
|
ruleMapper.deleteById(id);
|
}
|
|
@Override
|
public MesProProcessWageRuleResolveRespVO resolve(Long processId, Long routeId, Long machineryId,
|
Integer billingType, LocalDate date) {
|
MesProProcessDO process = processService.getProcess(processId);
|
if (process == null) {
|
throw exception(PRO_FEEDBACK_PROCESS_NOT_EXISTS, processId);
|
}
|
LocalDate matchDate = date != null ? date : LocalDate.now();
|
List<MesProProcessWageRuleDO> candidates = ruleMapper.selectListByProcessId(processId).stream()
|
.filter(rule -> Objects.equals(rule.getStatus(), CommonStatusEnum.ENABLE.getStatus()))
|
.filter(rule -> billingType == null || Objects.equals(rule.getBillingType(), billingType))
|
.filter(rule -> matchEffective(rule, matchDate))
|
.filter(rule -> rule.getRouteId() == null || Objects.equals(rule.getRouteId(), routeId))
|
.filter(rule -> rule.getMachineryId() == null || Objects.equals(rule.getMachineryId(), machineryId))
|
.sorted(Comparator
|
.comparingInt((MesProProcessWageRuleDO rule) -> matchScore(rule, routeId, machineryId)).reversed()
|
.thenComparing(Comparator.comparingInt(
|
(MesProProcessWageRuleDO rule) -> ObjUtil.defaultIfNull(rule.getPriority(), 0)).reversed())
|
.thenComparing(Comparator.comparing(
|
MesProProcessWageRuleDO::getEffectiveFrom,
|
Comparator.nullsLast(Comparator.reverseOrder())))
|
.thenComparing(Comparator.comparing(MesProProcessWageRuleDO::getId).reversed()))
|
.toList();
|
|
MesProProcessWageRuleResolveRespVO resp = new MesProProcessWageRuleResolveRespVO()
|
.setProcessId(processId).setRouteId(routeId).setMachineryId(machineryId)
|
.setBillingType(billingType != null ? billingType : process.getBillingType());
|
if (candidates.isEmpty()) {
|
resp.setWageRate(process.getWageRate() != null ? process.getWageRate() : BigDecimal.ZERO)
|
.setMatchLevel("DEFAULT");
|
return resp;
|
}
|
MesProProcessWageRuleDO rule = candidates.get(0);
|
resp.setWageRate(rule.getWageRate()).setRuleId(rule.getId())
|
.setMatchLevel(matchLevel(rule, routeId, machineryId));
|
return resp;
|
}
|
|
private static boolean matchEffective(MesProProcessWageRuleDO rule, LocalDate date) {
|
if (rule.getEffectiveFrom() != null && date.isBefore(rule.getEffectiveFrom())) {
|
return false;
|
}
|
return rule.getEffectiveTo() == null || !date.isAfter(rule.getEffectiveTo());
|
}
|
|
private static int matchScore(MesProProcessWageRuleDO rule, Long routeId, Long machineryId) {
|
int score = 0;
|
if (rule.getRouteId() != null && Objects.equals(rule.getRouteId(), routeId)) {
|
score += 2;
|
}
|
if (rule.getMachineryId() != null && Objects.equals(rule.getMachineryId(), machineryId)) {
|
score += 1;
|
}
|
return score;
|
}
|
|
private static String matchLevel(MesProProcessWageRuleDO rule, Long routeId, Long machineryId) {
|
boolean routeMatched = rule.getRouteId() != null && Objects.equals(rule.getRouteId(), routeId);
|
boolean machineryMatched = rule.getMachineryId() != null && Objects.equals(rule.getMachineryId(), machineryId);
|
if (routeMatched && machineryMatched) {
|
return "EXACT";
|
}
|
if (routeMatched) {
|
return "ROUTE";
|
}
|
if (machineryMatched) {
|
return "MACHINERY";
|
}
|
return "DEFAULT";
|
}
|
|
private MesProProcessWageRuleDO validateRuleExists(Long id) {
|
MesProProcessWageRuleDO rule = ruleMapper.selectById(id);
|
if (rule == null) {
|
throw exception(PRO_PROCESS_WAGE_RULE_NOT_EXISTS);
|
}
|
return rule;
|
}
|
|
private void validateRule(MesProProcessWageRuleSaveReqVO reqVO) {
|
MesProProcessDO process = processService.getProcess(reqVO.getProcessId());
|
if (process == null) {
|
throw exception(PRO_FEEDBACK_PROCESS_NOT_EXISTS, reqVO.getProcessId());
|
}
|
if (reqVO.getRouteId() != null) {
|
MesProRouteDO route = routeService.getRoute(reqVO.getRouteId());
|
if (route == null) {
|
throw new ServiceException(PRO_ROUTE_NOT_EXISTS.getCode(),
|
StrUtil.format("工序[{}]的工资规则引用的工艺路线 ID={} 不存在;请重新选择工艺路线",
|
process.getName(), reqVO.getRouteId()));
|
}
|
}
|
if (reqVO.getMachineryId() != null) {
|
MesDvMachineryDO machinery = machineryService.getMachinery(reqVO.getMachineryId());
|
if (machinery == null) {
|
throw new ServiceException(DV_MACHINERY_NOT_EXISTS.getCode(),
|
StrUtil.format("工序[{}]的工资规则引用的设备 ID={} 不存在;请重新选择设备",
|
process.getName(), reqVO.getMachineryId()));
|
}
|
}
|
if (reqVO.getEffectiveFrom() != null && reqVO.getEffectiveTo() != null
|
&& reqVO.getEffectiveFrom().isAfter(reqVO.getEffectiveTo())) {
|
throw new ServiceException(PRO_PROCESS_WAGE_RULE_DUPLICATE.getCode(),
|
StrUtil.format("工序[{}]的工资规则生效开始日期[{}]晚于结束日期[{}];请调整生效区间后重试",
|
process.getName(), reqVO.getEffectiveFrom(), reqVO.getEffectiveTo()));
|
}
|
}
|
|
}
|