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 getRulePage(MesProProcessWageRulePageReqVO pageReqVO) { return ruleMapper.selectPage(pageReqVO); } @Override public List 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 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())); } } }