diff --git a/blade-ops/blade-job/src/main/java/org/springblade/job/processor/oem/OemOrderOutProcessor.java b/blade-ops/blade-job/src/main/java/org/springblade/job/processor/oem/OemOrderOutProcessor.java new file mode 100644 index 000000000..ace839ae4 --- /dev/null +++ b/blade-ops/blade-job/src/main/java/org/springblade/job/processor/oem/OemOrderOutProcessor.java @@ -0,0 +1,35 @@ +package org.springblade.job.processor.oem; + +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springblade.desk.produce.feign.IWorkOrderRunOutClient; +import org.springframework.stereotype.Component; +import tech.powerjob.worker.core.processor.ProcessResult; +import tech.powerjob.worker.core.processor.TaskContext; +import tech.powerjob.worker.core.processor.sdk.BasicProcessor; + +/** + * 外协订单下达ERP定时任务 + * + * @author zangzhipeng + */ +@Component +@Slf4j +public class OemOrderOutProcessor implements BasicProcessor { + + @Resource + private IWorkOrderRunOutClient workOrderRunOutClient; + + @Override + public ProcessResult process(TaskContext context) throws Exception { + log.info("外协订单下达ERP定时任务开始"); + try { + workOrderRunOutClient.oemOrderOut(); + log.info("外协订单下达ERP定时任务执行完毕"); + return new ProcessResult(true); + } catch (Exception e) { + log.error("外协订单下达ERP定时任务执行失败", e); + return new ProcessResult(false, e.getMessage()); + } + } +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/feign/IWorkOrderRunOutClient.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/feign/IWorkOrderRunOutClient.java new file mode 100644 index 000000000..a49cbfd14 --- /dev/null +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/feign/IWorkOrderRunOutClient.java @@ -0,0 +1,26 @@ +package org.springblade.desk.produce.feign; + +import org.springblade.core.launch.constant.AppConstant; +import org.springblade.core.tool.api.R; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; + +/** + * 外协订单下达ERP定时任务 Feign接口 + * + * @author zangzhipeng + */ +@FeignClient( + value = AppConstant.APPLICATION_DESK_NAME +) +public interface IWorkOrderRunOutClient { + + String API_PREFIX = "/feign/client/workOrderRunOut"; + String OEM_ORDER_OUT = API_PREFIX + "/oemOrderOut"; + + /** + * 外协订单下达ERP(定时任务调用) + */ + @GetMapping(OEM_ORDER_OUT) + R oemOrderOut(); +} diff --git a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/entity/WorkOrderRun.java b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/entity/WorkOrderRun.java index 64888d264..1dc0065fe 100644 --- a/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/entity/WorkOrderRun.java +++ b/blade-service-api/blade-desk-api/src/main/java/org/springblade/desk/produce/pojo/entity/WorkOrderRun.java @@ -26,7 +26,7 @@ public class WorkOrderRun extends BaseEntity { private static final long serialVersionUID = 1L; public WorkOrderRun(Long woId, String woCode, Short runType, Long outTeam, Long inTeam, Long outCustomer, - Long inCustomer, String memo, Long approvalMan, String systemData, String collaborate) { + Long inCustomer, String memo, Long approvalMan, String systemData, String collaborate, Short oemStatus) { this.woId = woId; this.woCode = woCode; this.runType = runType; @@ -39,6 +39,7 @@ public class WorkOrderRun extends BaseEntity { this.systemData = systemData; this.collaborate = collaborate; this.runStatus = RUN_STATUS_ISSUED; + this.oemStatus = oemStatus; } public WorkOrderRun() { diff --git a/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClient.java b/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClient.java index aec14320d..a6b57a6aa 100644 --- a/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClient.java +++ b/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClient.java @@ -8,6 +8,7 @@ import org.springblade.erpdata.pojo.dto.view.MesRbWo; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; import java.util.List; @@ -35,6 +36,7 @@ public interface IErpMesRbWoClient { String SYN_OUTSOURCING = API_PREFIX + "/synOutsourcing"; String SYN_CRAFT = API_PREFIX + "/synCraft"; String SYN_SUPPORTING_FACILITIES = API_PREFIX + "/synSupportingFacilities"; + String GET_DEMAND_DATE = API_PREFIX + "/getDemandDateByWono"; /** * 查询烧结配套信息 @@ -73,4 +75,13 @@ public interface IErpMesRbWoClient { R synCraft(); @GetMapping(SYN_SUPPORTING_FACILITIES) R synSupportingFacilities(); + + /** + * 根据工作订单号查询ERP需求日期 + * + * @param wono 工作订单号 + * @return 需求日期字符串 + */ + @GetMapping(GET_DEMAND_DATE) + R getDemandDateByWono(@RequestParam(required = true) String wono); } diff --git a/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClientFallback.java b/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClientFallback.java index 14907451f..d1f19c425 100644 --- a/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClientFallback.java +++ b/blade-service-api/blade-erpdata-api/src/main/java/org/springblade/erpdata/feign/IErpMesRbWoClientFallback.java @@ -75,4 +75,9 @@ public class IErpMesRbWoClientFallback implements IErpMesRbWoClient { public R synSupportingFacilities() { return R.fail("获取数据失败"); } + + @Override + public R getDemandDateByWono(String wono) { + return R.fail("获取数据失败"); + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/IYieldOrderCraftService.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/IYieldOrderCraftService.java index 1fbf812d3..21a88162e 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/IYieldOrderCraftService.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/IYieldOrderCraftService.java @@ -15,39 +15,41 @@ import java.util.List; */ public interface IYieldOrderCraftService extends BaseService { - /** - * 自定义分页 - * - * @param page - * @param entity - * @return - */ - IPage selectPage(IPage page, YieldOrderCraft entity); - - /** - * 根据生产订单ID查询工艺列表 - * - * @param yoId - * @return - */ - List listByYoId(Long yoId); - - /** - * 根据生产订单ID删除工艺列表 - * - * @param yoId - * @return - */ - int deleteByYoId(Long yoId); - - /** - * 查找订单各工序的加工单位 - * - * @param yieldOrderCraftList 订单工艺列表 - * @param yieldOrder 生产订单 - * @param factor null 整体 ,true : 转厂内 ,false:转厂外 - * @param rxlSpace 需要特殊分派,true:需要, false:不需要,null:不需要 - * @throws BusinessException - */ - void automaticDispatch(List yieldOrderCraftList, YieldOrder yieldOrder, Boolean factor, Boolean rxlSpace) throws Exception; + /** + * 自定义分页 + * + * @param page + * @param entity + * @return + */ + IPage selectPage(IPage page, YieldOrderCraft entity); + + /** + * 根据生产订单ID查询工艺列表 + * + * @param yoId + * @return + */ + List listByYoId(Long yoId); + + /** + * 根据生产订单ID删除工艺列表 + * + * @param yoId + * @return + */ + int deleteByYoId(Long yoId); + + /** + * 查找订单各工序的加工单位 + * + * @param yieldOrderCraftList 订单工艺列表 + * @param yieldOrder 生产订单 + * @param factor null 整体 ,true : 转厂内 ,false:转厂外 + * @param rxlSpace 需要特殊分派,true:需要, false:不需要,null:不需要 + * @throws BusinessException + */ + void automaticDispatch(List yieldOrderCraftList, YieldOrder yieldOrder, Boolean factor, Boolean rxlSpace) throws Exception; + + List listByYoIdAndNo(Long id, String orders); } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderCraftServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderCraftServiceImpl.java index 58a7ed950..49e8593cc 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderCraftServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/order/service/impl/YieldOrderCraftServiceImpl.java @@ -51,714 +51,743 @@ import java.util.stream.Collectors; @Service public class YieldOrderCraftServiceImpl extends BaseServiceImpl implements IYieldOrderCraftService { - private final IWorkCenterService workCenterService; - private final IOemService oemService; - private final IOemCraftAbilityService oemCraftAbilityService; - private final IBsCraftAbilityService craftAbilityService; - private final IBsAssignService assignService; - private final IYieldOrderDailyAssignService dailyAssignService; - - private final IYieldOrderAssignSteerService assignSteerService; - private final IBsProcessSetService processSetService; - private final IBsTeamSetService teamSetService; - private final YieldOrderMapper yieldOrderMapper; - private final ICraftAbilityService iCraftAbilityService; - - @Override - public IPage selectPage(IPage page, YieldOrderCraft entity) { - List dataList = baseMapper.selectPage(page, entity); - return page.setRecords(dataList); - } - - @Override - public List listByYoId(Long yoId) { - LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(YieldOrderCraft.class) - .eq(YieldOrderCraft::getYoId, yoId) - .eq(YieldOrderCraft::getIsDeleted, CommonConstant.DELETE_FALSE).orderByAsc(YieldOrderCraft::getProcessNo); - List craftList = baseMapper.selectList(queryWrapper); - craftList.stream().forEach(item ->{ - BsProcessSetEntity processSet = processSetService.getById(item.getPpsId()); - if(processSet != null){ - item.setProcessCode(processSet.getCode()); - item.setProcessName(processSet.getName()); - } - if(item.getIsOutsource()){ - if(null != item.getOcId()){ - Oem oem = oemService.getById(item.getOcId()); - if(null != oem){ - item.setWorkCenterName(oem.getOcName()); - } - } - }else { - if(null != item.getWorkCenterId()){ - WorkCenter workCenter = workCenterService.getById(item.getWorkCenterId()); - if(null != workCenter){ - item.setWorkCenterName(workCenter.getWcName()); - } - } - } - }); - return craftList; - } - - @Override - public int deleteByYoId(Long yoId) { - LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery(YieldOrderCraft.class).eq(YieldOrderCraft::getYoId, yoId).eq(YieldOrderCraft::getIsDeleted, CommonConstant.DELETE_FALSE); - return baseMapper.delete(deleteWrapper); - } - - @Override - public void automaticDispatch(List yieldOrderCraftList, YieldOrder yieldOrder, Boolean factor, Boolean rxlSpace) throws Exception { - // 组装key为工艺能力的作业计划map - Map> craftAbilityMap = yieldOrderCraftList.stream() - .collect(Collectors.groupingBy(YieldOrderCraft::getCaId,LinkedHashMap::new,Collectors.toList())); - //作业计划map工艺能力key集合 - Set craftKeys = craftAbilityMap.keySet(); - //获取到认定的主工艺能力(默认第一个工艺能力为主工艺能力) - Long hostAbilityId = craftKeys.iterator().next(); - BsCraftAbilityEntity craftAbility = craftAbilityService.getById(hostAbilityId); - //获取可以做此主工艺能力的作业中心集合 - Map workCenterMap = workCenterService.selectByAbility(hostAbilityId, yieldOrder.getYpQty(), yieldOrder.getYpArea(), yieldOrder.getPartCode(), yieldOrder.getPrimaryCraft(), yieldOrder.getYieldType(), rxlSpace); - //获取可以做此主工艺能力的外协商集合 - List oemList = oemService.selectByAbility(hostAbilityId, yieldOrder.getYpQty(), yieldOrder.getYpArea(), yieldOrder.getPartCode(), yieldOrder.getPrimaryCraft(), yieldOrder.getYieldType(), yieldOrder.getPlate(), rxlSpace); - - // 如果未找到适合的班组或者供应商,提示排查方向 - if ((workCenterMap == null || workCenterMap.size() == 0) && (oemList == null || oemList.size() == 0)) { - throw new BusinessException("未找到合适的作业中心或者供应商!请排查工艺能力、作业中心等因素!"); - } - - // 查询是否存在必须厂内且等级要求的规则,如果是则需要验证作业中心必须有值 - List mustAssignList = assignService.listMustAssign(hostAbilityId, BsAssignEntity.IN_FACTORY); - if (mustAssignList != null && mustAssignList.size() > 0) { - // 遍历强制规则,查找跟订单匹配的质量等级规则,若规则不为空,判定厂内作业中心列表是否为空 - for (BsAssignEntity mustAssign : mustAssignList) { - if (StringUtils.isNotBlank(mustAssign.getProdMark())) { - if (mustAssign.getProdMark().contains("\"" + yieldOrder.getProductIdent() + "\"")) { - if (workCenterMap == null || workCenterMap.size() == 0) { - throw new BusinessException("未找到合适的作业中心或者供应商!请排查工艺能力、作业中心等因素!"); - } - } - } - } - } - - //获取到可以做主工艺能力的最合适的作业中心,并且标记必须、优先、正常 - WorkCenter workCenter = null; - //获取到可以做主工艺能力的最合适的外协商,并且标记必须、优先、正常 - Oem oemCustomer = null; - //自动分派后的结果集 - List dispatchCraftList = null; - - // 根据车间订单是否厂内标识判定是否强制厂内(单工序时不进行标识验证) - if (yieldOrder.getSiteWork() && factor == null) { - log.info("自动分派,流程卡号:{},标注厂内生产", yieldOrder.getCardNo()); - //订单强制分派厂内,若未找到工艺能力对应的作业中心,则提示异常 - if (workCenterMap == null || workCenterMap.isEmpty()) { - throw new BusinessException("此订单需强制分派厂内,未找到满足条件得作业中心,自动分派失败!1"); - } - //寻找最合适的作业中心 - workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - if (workCenter == null) { - throw new BusinessException("此订单需强制分派厂内,未找到满足条件得作业中心,自动分派失败!2"); - } - } else if (factor != null) { - if (factor) { - workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - } else if (!factor) { - oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - } - } else { - // 先判定规则是否存在零件级强制匹配 - BsAssignEntity partAssign = assignService.getByPartCode(hostAbilityId, yieldOrder.getPartCode()); - if (partAssign != null && partAssign.getCenterId() != null) { - log.info("自动分派,流程卡号:{},指定厂内作业中心生产", yieldOrder.getCardNo()); - // 指定厂内作业中心生产 - workCenter = workCenterService.getWorkCenter(partAssign.getCenterId()); - } else if (partAssign != null && partAssign.getOemId() != null) { - // 指定外协商生产 - log.info("自动分派,流程卡号:{},指定外协商生产", yieldOrder.getCardNo()); - oemCustomer = oemService.getById(partAssign.getOemId()); - } else if (partAssign != null && partAssign.getLimitType().equals(BsAssignEntity.MUST.toString())) { - if (partAssign.getPointType().equals(BsAssignEntity.IN_FACTORY.toString())) { - // 必须厂内生产 - log.info("自动分派,流程卡号:{},必须厂内生产", yieldOrder.getCardNo()); - workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - } else { - //必须外协生产 - log.info("自动分派,流程卡号:{},必须外协生产", yieldOrder.getCardNo()); - oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - } - } else { - // 寻找最合适的作业中心 - log.info("自动分派,流程卡号:{},寻找最合适的作业中心或班组", yieldOrder.getCardNo()); - workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_NORMAL); - oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_NORMAL); - } - } - log.info("自动分派,流程卡号:{},作业中心:{},外协商:{}", yieldOrder.getCardNo(), workCenter, oemCustomer); - // factor等于null代表是整体,有值时代表是单工序,true转厂内,false转厂外 - if (factor == null) { - if (workCenter != null && oemCustomer == null) { - log.info("自动分派,流程卡号:{},分派到厂内", yieldOrder.getCardNo()); - //只有厂内有工艺能力 - dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } else if (oemCustomer != null && workCenter == null) { - log.info("自动分派,流程卡号:{},分派到外协", yieldOrder.getCardNo()); - //只有厂外有工艺能力 - dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } else if (workCenter != null && oemCustomer != null) { - log.info("自动分派,流程卡号:{},分派到厂内或外协", yieldOrder.getCardNo()); - //场内外共有工艺能力 - if (workCenter.getLimitType().equals(WorkCenter.LIMIT_TYPE_MUST)) { - log.info("自动分派,流程卡号:{},必须厂内2", yieldOrder.getCardNo()); - dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } else if (oemCustomer.getLimitType().equals(WorkCenter.LIMIT_TYPE_MUST)) { - log.info("自动分派,流程卡号:{},必须外协2", yieldOrder.getCardNo()); - dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } - - //如果匹配到了作业单位,则直接停止 - if (dispatchCraftList != null && dispatchCraftList.size() > 0) { - return; - } - - // 厂内优先 - if (workCenter.getLimitType().equals(WorkCenter.LIMIT_TYPE_PRIOR)) { - log.info("自动分派,流程卡号:{},优先厂内", yieldOrder.getCardNo()); - dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } - - //如果匹配到了作业单位,则直接停止 - if (dispatchCraftList != null && dispatchCraftList.size() > 0) { - return; - } - - //外协优先 - if (oemCustomer.getLimitType().equals(WorkCenter.LIMIT_TYPE_PRIOR)) { - log.info("自动分派,流程卡号:{},优先外协", yieldOrder.getCardNo()); - dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } - - //如果匹配到了作业单位,则直接停止 - if (dispatchCraftList != null && dispatchCraftList.size() > 0) { - return; - } - - // 开始根据分派比例分派 - Long facTotalNum = 0L; - YieldOrderAssignCount facCapacity = dailyAssignService.queryCount(hostAbilityId, BsAssignEntity.IN_FACTORY); - if (facCapacity != null) { - facTotalNum = facCapacity.getTotalNum(); - } - // 获取厂外已经分派的总量 - Long oemTotalNum = 0L; - YieldOrderAssignCount oemCapacity = dailyAssignService.queryCount(hostAbilityId, BsAssignEntity.OUTSOURCE); - if (oemCapacity != null) { - oemTotalNum = oemCapacity.getTotalNum(); - } - - //日分派总量 - Long totalNum = facTotalNum + oemTotalNum; - // 厂内分派比列 - Double rate = 0D; - if (totalNum > 0) { - rate = Double.valueOf(facTotalNum) / Double.valueOf(totalNum) * 100; - } - log.info("自动分派,流程卡号:{},分派总量:{},厂内分派比列:{}", yieldOrder.getCardNo(), totalNum, rate); - - // 如果厂内占比大于已经设置的比列,则直接分派外协 - if (rate <= Double.parseDouble(craftAbility.getInRate())) { - log.info("{}自动分派按照比例分派给厂内:{},分派比例:{} 应分比例:{}", yieldOrder.getCardNo(), workCenter.getWcName(), rate, craftAbility.getInRate()); - dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } - - //如果匹配到了作业单位,则直接停止 - if (dispatchCraftList != null && !dispatchCraftList.isEmpty()) { - return; - } - - // 外协 - log.info("{}自动分派按照比例分派给外协:{},分派比例:{} 应分比例:{}", yieldOrder.getCardNo(), oemCustomer.getOcName(), rate, craftAbility.getInRate()); - dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); - } - } else { - if (Boolean.TRUE.equals(factor)) { - if (workCenter == null) { - throw new BusinessException("未找到合适的班组或者供应商!请排查工艺能力、班组日分派时间、相似零件、键位零件等因素!"); - } - dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, true); - } else { - if (oemCustomer == null) { - throw new BusinessException("未找到合适的班组或者供应商!请排查工艺能力、班组日分派时间、相似零件、键位零件等因素!"); - } - dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, false); - } - } - - if (dispatchCraftList == null || dispatchCraftList.size() == 0) { - throw new ServiceException("自动分派失败,未找到合适的班组或者供应商!"); - } - - if(workCenter != null){ - yieldOrder.setWorkCenterId(workCenter.getId()); - yieldOrderMapper.updateById(yieldOrder); - } - // 分派成功,保存分派结果 - this.saveOrUpdateBatch(dispatchCraftList); - } - - /** - * @param hostCaId 主工艺能力 - * @param wcMap 拥有主工艺能力的作业中心 - * @param yieldOrder 生产订单 - * @param limitType 0: 正常,1:优先,2:必须 - * @return BsWorkCenter - * @Description: 寻找满足条件的作业中心 - * @Author dxl - * @CreateTime 2023/3/7 18:30 - */ - private WorkCenter inPlantDistribution(Long hostCaId, Map wcMap, YieldOrder yieldOrder, Integer limitType) { - //没有工艺能力的对应作业中心,直接分派厂外 - if (wcMap == null || wcMap.size() == 0) { - return null; - } - - //组装wcList集合 - List wcList = new ArrayList<>(); - wcList.addAll(wcMap.keySet()); - - //作业中心 - WorkCenter workCenter = null; - //在规则表中匹配是否存在匹配的条件(查厂内) - BsAssignEntity assign = this.getRules(yieldOrder, hostCaId, BsAssignEntity.IN_FACTORY); - if (assign != null) { - //限制类型是必须(强制运用此规则),反之则优先分派厂内 - if (assign.getLimitType().equals(BsAssignEntity.MUST)) { - if (assign.getCenterId() != null) { - //判断规则中配置的工作中心是否满足当前工艺能力要求,如果不满足,则此条规则作废 - if (wcMap.get(assign.getCenterId()) != null) { - workCenter = workCenterService.getWorkCenter(assign.getCenterId()); - workCenter.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_MUST); - return workCenter; - } - } - //挑选一个最合适的作业中心 - return this.priorityInPlantDistribution(hostCaId, wcList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); - } else { - //优先规则配置的作业中心,若无则,规则 - if (assign.getCenterId() != null) { - //判断规则中配置的工作中心是否满足当前工艺能力要求,如果不满足,则此条规则作废 - if (wcMap.get(assign.getCenterId()) != null) { - //查询当前作业中心是否满足生产当前这批活的条件,若不满足,则考虑其他满足的作业中心 - YieldOrderAssignDaily dayAbilityAssignment = dailyAssignService.findMinNum(hostCaId, wcList); - if (dayAbilityAssignment != null) { - workCenter = workCenterService.getWorkCenter(assign.getCenterId()); - //外部如果限制类型不是必须,则直接考虑规则限制类型 - if (limitType.equals(BsWorkCenterEntity.LIMIT_TYPE_MUST)) { - workCenter.setLimitType(limitType); - } else { - workCenter.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_PRIOR); - } - return workCenter; - } - } - } - } - } - //挑选一个最合适的作业中心 - return this.priorityInPlantDistribution(hostCaId, wcList, yieldOrder, limitType); - } - - /** - * @param hostCaId 主工艺能力 - * @param wcList 作业中心集合 - * @param yieldOrder 生产订单 - * @param limitType 正常,1:优先,2:必须 - * @return BsWorkCenter - * @Description: 多作业中心挑选合适的作业中心 - * @Author dxl - * @CreateTime 2023/3/7 18:31 - */ - private WorkCenter priorityInPlantDistribution(Long hostCaId, List wcList, YieldOrder yieldOrder, Integer limitType) { - //没有工艺能力的对应作业中心,直接分派厂外 - if (wcList == null || wcList.size() == 0) { - return null; - } - - //作业中心 - WorkCenter workCenter = null; - //如果找到合适的作业中心直接分派,反之如果未找到合适的作业中心(bool 是true的情况下强制厂内,bool是false是优先厂内,不满足的情况下直接返回空) - // todo 待完善 - YieldOrderAssignDaily dayAbilityAssignment = dailyAssignService.findMinNum(hostCaId, wcList); - if (Func.isEmpty(dayAbilityAssignment)) { - return null; - } - workCenter = workCenterService.getWorkCenter(dayAbilityAssignment.getWorkCenterId()); - workCenter.setLimitType(limitType); - return workCenter; - } - - /** - * 为每个工序绑定作业中心 - * - * @param workCenterId 作业中心 - * @param workCenterMap 作业中心和班组集合 - * @param craftAbilityId 工艺能力 - * @param craftAbilityMap 工艺能力组装的生产计划map - * @param craftKeys 当前生产订单下的工艺能力集合 - * @return List - * @Description: 分配到班组 - * @Author dxl - * @CreateTime 2023/3/8 15:30 - */ - private List bindWorkCenter(Long workCenterId, Map workCenterMap, Long craftAbilityId, - Map> craftAbilityMap, Set craftKeys, - YieldOrder yieldOrder, Boolean factor) throws Exception { - log.info("自动分派,流程卡号:{},分给厂内,作业中心为:{}", yieldOrder.getCardNo(), workCenterId); - List orderCrafts = new ArrayList<>(); - // 开始循环生产订单中组合的工艺能力key集合, 主工艺能力之前的全部分配到此作业中心 - for (Long craftId : craftKeys) { - //验证工艺能力 + private final IWorkCenterService workCenterService; + private final IOemService oemService; + private final IOemCraftAbilityService oemCraftAbilityService; + private final IBsCraftAbilityService craftAbilityService; + private final IBsAssignService assignService; + private final IYieldOrderDailyAssignService dailyAssignService; + + private final IYieldOrderAssignSteerService assignSteerService; + private final IBsProcessSetService processSetService; + private final IBsTeamSetService teamSetService; + private final YieldOrderMapper yieldOrderMapper; + private final ICraftAbilityService iCraftAbilityService; + + @Override + public IPage selectPage(IPage page, YieldOrderCraft entity) { + List dataList = baseMapper.selectPage(page, entity); + return page.setRecords(dataList); + } + + @Override + public List listByYoId(Long yoId) { + LambdaQueryWrapper queryWrapper = Wrappers.lambdaQuery(YieldOrderCraft.class) + .eq(YieldOrderCraft::getYoId, yoId) + .eq(YieldOrderCraft::getIsDeleted, CommonConstant.DELETE_FALSE).orderByAsc(YieldOrderCraft::getProcessNo); + List craftList = baseMapper.selectList(queryWrapper); + craftList.stream().forEach(item -> { + BsProcessSetEntity processSet = processSetService.getById(item.getPpsId()); + if (processSet != null) { + item.setProcessCode(processSet.getCode()); + item.setProcessName(processSet.getName()); + } + if (item.getIsOutsource()) { + if (null != item.getOcId()) { + Oem oem = oemService.getById(item.getOcId()); + if (null != oem) { + item.setWorkCenterName(oem.getOcName()); + } + } + } else { + if (null != item.getWorkCenterId()) { + WorkCenter workCenter = workCenterService.getById(item.getWorkCenterId()); + if (null != workCenter) { + item.setWorkCenterName(workCenter.getWcName()); + } + } + } + }); + return craftList; + } + + @Override + public int deleteByYoId(Long yoId) { + LambdaQueryWrapper deleteWrapper = Wrappers.lambdaQuery(YieldOrderCraft.class).eq(YieldOrderCraft::getYoId, yoId).eq(YieldOrderCraft::getIsDeleted, CommonConstant.DELETE_FALSE); + return baseMapper.delete(deleteWrapper); + } + + @Override + public void automaticDispatch(List yieldOrderCraftList, YieldOrder yieldOrder, Boolean factor, Boolean rxlSpace) throws Exception { + // 组装key为工艺能力的作业计划map + Map> craftAbilityMap = yieldOrderCraftList.stream() + .collect(Collectors.groupingBy(YieldOrderCraft::getCaId, LinkedHashMap::new, Collectors.toList())); + //作业计划map工艺能力key集合 + Set craftKeys = craftAbilityMap.keySet(); + //获取到认定的主工艺能力(默认第一个工艺能力为主工艺能力) + Long hostAbilityId = craftKeys.iterator().next(); + BsCraftAbilityEntity craftAbility = craftAbilityService.getById(hostAbilityId); + //获取可以做此主工艺能力的作业中心集合 + Map workCenterMap = workCenterService.selectByAbility(hostAbilityId, yieldOrder.getYpQty(), yieldOrder.getYpArea(), yieldOrder.getPartCode(), yieldOrder.getPrimaryCraft(), yieldOrder.getYieldType(), rxlSpace); + //获取可以做此主工艺能力的外协商集合 + List oemList = oemService.selectByAbility(hostAbilityId, yieldOrder.getYpQty(), yieldOrder.getYpArea(), yieldOrder.getPartCode(), yieldOrder.getPrimaryCraft(), yieldOrder.getYieldType(), yieldOrder.getPlate(), rxlSpace); + + // 如果未找到适合的班组或者供应商,提示排查方向 + if ((workCenterMap == null || workCenterMap.size() == 0) && (oemList == null || oemList.size() == 0)) { + throw new BusinessException("未找到合适的作业中心或者供应商!请排查工艺能力、作业中心等因素!"); + } + + // 查询是否存在必须厂内且等级要求的规则,如果是则需要验证作业中心必须有值 + List mustAssignList = assignService.listMustAssign(hostAbilityId, BsAssignEntity.IN_FACTORY); + if (mustAssignList != null && mustAssignList.size() > 0) { + // 遍历强制规则,查找跟订单匹配的质量等级规则,若规则不为空,判定厂内作业中心列表是否为空 + for (BsAssignEntity mustAssign : mustAssignList) { + if (StringUtils.isNotBlank(mustAssign.getProdMark())) { + if (mustAssign.getProdMark().contains("\"" + yieldOrder.getProductIdent() + "\"")) { + if (workCenterMap == null || workCenterMap.size() == 0) { + throw new BusinessException("未找到合适的作业中心或者供应商!请排查工艺能力、作业中心等因素!"); + } + } + } + } + } + + //获取到可以做主工艺能力的最合适的作业中心,并且标记必须、优先、正常 + WorkCenter workCenter = null; + //获取到可以做主工艺能力的最合适的外协商,并且标记必须、优先、正常 + Oem oemCustomer = null; + //自动分派后的结果集 + List dispatchCraftList = null; + + // 根据车间订单是否厂内标识判定是否强制厂内(单工序时不进行标识验证) + if (yieldOrder.getSiteWork() && factor == null) { + log.info("自动分派,流程卡号:{},标注厂内生产", yieldOrder.getCardNo()); + //订单强制分派厂内,若未找到工艺能力对应的作业中心,则提示异常 + if (workCenterMap == null || workCenterMap.isEmpty()) { + throw new BusinessException("此订单需强制分派厂内,未找到满足条件得作业中心,自动分派失败!1"); + } + //寻找最合适的作业中心 + workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + if (workCenter == null) { + throw new BusinessException("此订单需强制分派厂内,未找到满足条件得作业中心,自动分派失败!2"); + } + } else if (factor != null) { + if (factor) { + workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + } else if (!factor) { + oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + } + } else { + // 先判定规则是否存在零件级强制匹配 + BsAssignEntity partAssign = assignService.getByPartCode(hostAbilityId, yieldOrder.getPartCode()); + if (partAssign != null && partAssign.getCenterId() != null) { + log.info("自动分派,流程卡号:{},指定厂内作业中心生产", yieldOrder.getCardNo()); + // 指定厂内作业中心生产 + workCenter = workCenterService.getWorkCenter(partAssign.getCenterId()); + } else if (partAssign != null && partAssign.getOemId() != null) { + // 指定外协商生产 + log.info("自动分派,流程卡号:{},指定外协商生产", yieldOrder.getCardNo()); + oemCustomer = oemService.getById(partAssign.getOemId()); + } else if (partAssign != null && partAssign.getLimitType().equals(BsAssignEntity.MUST.toString())) { + if (partAssign.getPointType().equals(BsAssignEntity.IN_FACTORY.toString())) { + // 必须厂内生产 + log.info("自动分派,流程卡号:{},必须厂内生产", yieldOrder.getCardNo()); + workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + } else { + //必须外协生产 + log.info("自动分派,流程卡号:{},必须外协生产", yieldOrder.getCardNo()); + oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + } + } else { + // 寻找最合适的作业中心 + log.info("自动分派,流程卡号:{},寻找最合适的作业中心或班组", yieldOrder.getCardNo()); + workCenter = this.inPlantDistribution(hostAbilityId, workCenterMap, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_NORMAL); + oemCustomer = this.offsiteDistribution(hostAbilityId, oemList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_NORMAL); + } + } + log.info("自动分派,流程卡号:{},作业中心:{},外协商:{}", yieldOrder.getCardNo(), workCenter, oemCustomer); + // factor等于null代表是整体,有值时代表是单工序,true转厂内,false转厂外 + if (factor == null) { + if (workCenter != null && oemCustomer == null) { + log.info("自动分派,流程卡号:{},分派到厂内", yieldOrder.getCardNo()); + //只有厂内有工艺能力 + dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } else if (oemCustomer != null && workCenter == null) { + log.info("自动分派,流程卡号:{},分派到外协", yieldOrder.getCardNo()); + //只有厂外有工艺能力 + dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } else if (workCenter != null && oemCustomer != null) { + log.info("自动分派,流程卡号:{},分派到厂内或外协", yieldOrder.getCardNo()); + //场内外共有工艺能力 + if (workCenter.getLimitType().equals(WorkCenter.LIMIT_TYPE_MUST)) { + log.info("自动分派,流程卡号:{},必须厂内2", yieldOrder.getCardNo()); + dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } else if (oemCustomer.getLimitType().equals(WorkCenter.LIMIT_TYPE_MUST)) { + log.info("自动分派,流程卡号:{},必须外协2", yieldOrder.getCardNo()); + dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } + + //如果匹配到了作业单位,则直接停止 + if (dispatchCraftList != null && dispatchCraftList.size() > 0) { + return; + } + + // 厂内优先 + if (workCenter.getLimitType().equals(WorkCenter.LIMIT_TYPE_PRIOR)) { + log.info("自动分派,流程卡号:{},优先厂内", yieldOrder.getCardNo()); + dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } + + //如果匹配到了作业单位,则直接停止 + if (dispatchCraftList != null && dispatchCraftList.size() > 0) { + return; + } + + //外协优先 + if (oemCustomer.getLimitType().equals(WorkCenter.LIMIT_TYPE_PRIOR)) { + log.info("自动分派,流程卡号:{},优先外协", yieldOrder.getCardNo()); + dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } + + //如果匹配到了作业单位,则直接停止 + if (dispatchCraftList != null && dispatchCraftList.size() > 0) { + return; + } + + // 开始根据分派比例分派 + Long facTotalNum = 0L; + YieldOrderAssignCount facCapacity = dailyAssignService.queryCount(hostAbilityId, BsAssignEntity.IN_FACTORY); + if (facCapacity != null) { + facTotalNum = facCapacity.getTotalNum(); + } + // 获取厂外已经分派的总量 + Long oemTotalNum = 0L; + YieldOrderAssignCount oemCapacity = dailyAssignService.queryCount(hostAbilityId, BsAssignEntity.OUTSOURCE); + if (oemCapacity != null) { + oemTotalNum = oemCapacity.getTotalNum(); + } + + //日分派总量 + Long totalNum = facTotalNum + oemTotalNum; + // 厂内分派比列 + Double rate = 0D; + if (totalNum > 0) { + rate = Double.valueOf(facTotalNum) / Double.valueOf(totalNum) * 100; + } + log.info("自动分派,流程卡号:{},分派总量:{},厂内分派比列:{}", yieldOrder.getCardNo(), totalNum, rate); + + // 如果厂内占比大于已经设置的比列,则直接分派外协 + if (rate <= Double.parseDouble(craftAbility.getInRate())) { + log.info("{}自动分派按照比例分派给厂内:{},分派比例:{} 应分比例:{}", yieldOrder.getCardNo(), workCenter.getWcName(), rate, craftAbility.getInRate()); + dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } + + //如果匹配到了作业单位,则直接停止 + if (dispatchCraftList != null && !dispatchCraftList.isEmpty()) { + return; + } + + // 外协 + log.info("{}自动分派按照比例分派给外协:{},分派比例:{} 应分比例:{}", yieldOrder.getCardNo(), oemCustomer.getOcName(), rate, craftAbility.getInRate()); + dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, null); + } + } else { + if (Boolean.TRUE.equals(factor)) { + if (workCenter == null) { + throw new BusinessException("未找到合适的班组或者供应商!请排查工艺能力、班组日分派时间、相似零件、键位零件等因素!"); + } + dispatchCraftList = this.bindWorkCenter(workCenter.getId(), workCenterMap, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, true); + } else { + if (oemCustomer == null) { + throw new BusinessException("未找到合适的班组或者供应商!请排查工艺能力、班组日分派时间、相似零件、键位零件等因素!"); + } + dispatchCraftList = this.bindOem(oemCustomer, hostAbilityId, craftAbilityMap, craftKeys, yieldOrder, false); + } + } + + if (dispatchCraftList == null || dispatchCraftList.size() == 0) { + throw new ServiceException("自动分派失败,未找到合适的班组或者供应商!"); + } + + if (workCenter != null) { + yieldOrder.setWorkCenterId(workCenter.getId()); + yieldOrderMapper.updateById(yieldOrder); + } + // 分派成功,保存分派结果 + this.saveOrUpdateBatch(dispatchCraftList); + } + + @Override + public List listByYoIdAndNo(Long id, String orders) { + List craftList = this.list(Wrappers.lambdaQuery(YieldOrderCraft.class).eq(YieldOrderCraft::getYoId, id) + .gt(YieldOrderCraft::getProcessNo, orders).orderByAsc(YieldOrderCraft::getProcessNo)); + craftList.forEach(item -> { + BsProcessSetEntity processSet = processSetService.getById(item.getPpsId()); + if (processSet != null) { + item.setProcessCode(processSet.getCode()); + item.setProcessName(processSet.getName()); + } + if (item.getIsOutsource()) { + if (null != item.getOcId()) { + Oem oem = oemService.getById(item.getOcId()); + if (null != oem) { + item.setWorkCenterName(oem.getOcName()); + } + } + } else { + if (null != item.getWorkCenterId()) { + WorkCenter workCenter = workCenterService.getById(item.getWorkCenterId()); + if (null != workCenter) { + item.setWorkCenterName(workCenter.getWcName()); + } + } + } + }); + return craftList; + } + + /** + * @param hostCaId 主工艺能力 + * @param wcMap 拥有主工艺能力的作业中心 + * @param yieldOrder 生产订单 + * @param limitType 0: 正常,1:优先,2:必须 + * @return BsWorkCenter + * @Description: 寻找满足条件的作业中心 + * @Author dxl + * @CreateTime 2023/3/7 18:30 + */ + private WorkCenter inPlantDistribution(Long hostCaId, Map wcMap, YieldOrder yieldOrder, Integer limitType) { + //没有工艺能力的对应作业中心,直接分派厂外 + if (wcMap == null || wcMap.size() == 0) { + return null; + } + + //组装wcList集合 + List wcList = new ArrayList<>(); + wcList.addAll(wcMap.keySet()); + + //作业中心 + WorkCenter workCenter = null; + //在规则表中匹配是否存在匹配的条件(查厂内) + BsAssignEntity assign = this.getRules(yieldOrder, hostCaId, BsAssignEntity.IN_FACTORY); + if (assign != null) { + //限制类型是必须(强制运用此规则),反之则优先分派厂内 + if (assign.getLimitType().equals(BsAssignEntity.MUST)) { + if (assign.getCenterId() != null) { + //判断规则中配置的工作中心是否满足当前工艺能力要求,如果不满足,则此条规则作废 + if (wcMap.get(assign.getCenterId()) != null) { + workCenter = workCenterService.getWorkCenter(assign.getCenterId()); + workCenter.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_MUST); + return workCenter; + } + } + //挑选一个最合适的作业中心 + return this.priorityInPlantDistribution(hostCaId, wcList, yieldOrder, BsWorkCenterEntity.LIMIT_TYPE_MUST); + } else { + //优先规则配置的作业中心,若无则,规则 + if (assign.getCenterId() != null) { + //判断规则中配置的工作中心是否满足当前工艺能力要求,如果不满足,则此条规则作废 + if (wcMap.get(assign.getCenterId()) != null) { + //查询当前作业中心是否满足生产当前这批活的条件,若不满足,则考虑其他满足的作业中心 + YieldOrderAssignDaily dayAbilityAssignment = dailyAssignService.findMinNum(hostCaId, wcList); + if (dayAbilityAssignment != null) { + workCenter = workCenterService.getWorkCenter(assign.getCenterId()); + //外部如果限制类型不是必须,则直接考虑规则限制类型 + if (limitType.equals(BsWorkCenterEntity.LIMIT_TYPE_MUST)) { + workCenter.setLimitType(limitType); + } else { + workCenter.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_PRIOR); + } + return workCenter; + } + } + } + } + } + //挑选一个最合适的作业中心 + return this.priorityInPlantDistribution(hostCaId, wcList, yieldOrder, limitType); + } + + /** + * @param hostCaId 主工艺能力 + * @param wcList 作业中心集合 + * @param yieldOrder 生产订单 + * @param limitType 正常,1:优先,2:必须 + * @return BsWorkCenter + * @Description: 多作业中心挑选合适的作业中心 + * @Author dxl + * @CreateTime 2023/3/7 18:31 + */ + private WorkCenter priorityInPlantDistribution(Long hostCaId, List wcList, YieldOrder yieldOrder, Integer limitType) { + //没有工艺能力的对应作业中心,直接分派厂外 + if (wcList == null || wcList.size() == 0) { + return null; + } + + //作业中心 + WorkCenter workCenter = null; + //如果找到合适的作业中心直接分派,反之如果未找到合适的作业中心(bool 是true的情况下强制厂内,bool是false是优先厂内,不满足的情况下直接返回空) + // todo 待完善 + YieldOrderAssignDaily dayAbilityAssignment = dailyAssignService.findMinNum(hostCaId, wcList); + if (Func.isEmpty(dayAbilityAssignment)) { + return null; + } + workCenter = workCenterService.getWorkCenter(dayAbilityAssignment.getWorkCenterId()); + workCenter.setLimitType(limitType); + return workCenter; + } + + /** + * 为每个工序绑定作业中心 + * + * @param workCenterId 作业中心 + * @param workCenterMap 作业中心和班组集合 + * @param craftAbilityId 工艺能力 + * @param craftAbilityMap 工艺能力组装的生产计划map + * @param craftKeys 当前生产订单下的工艺能力集合 + * @return List + * @Description: 分配到班组 + * @Author dxl + * @CreateTime 2023/3/8 15:30 + */ + private List bindWorkCenter(Long workCenterId, Map workCenterMap, Long craftAbilityId, + Map> craftAbilityMap, Set craftKeys, + YieldOrder yieldOrder, Boolean factor) throws Exception { + log.info("自动分派,流程卡号:{},分给厂内,作业中心为:{}", yieldOrder.getCardNo(), workCenterId); + List orderCrafts = new ArrayList<>(); + // 开始循环生产订单中组合的工艺能力key集合, 主工艺能力之前的全部分配到此作业中心 + for (Long craftId : craftKeys) { + //验证工艺能力 /*WorkCenter workCenter = workCenterService.getOne(Wrappers.lambdaQuery().eq(BaseEntity::getId,workCenterId).like(WorkCenter::getCraftAbilityId,craftId)); if (workCenter == null) { break; }*/ - orderCrafts.addAll(craftAbilityMap.get(craftId)); - } - - // 开始分派到作业中心 - for (YieldOrderCraft orderCraft : orderCrafts) { - Long centerId = orderCraft.getWorkCenterId(); - // 判定是否是特殊工序 - BsProcessSetEntity processSet = processSetService.getById(orderCraft.getPpsId()); - if (Func.isNotEmpty(processSet) && Func.isNotBlank(processSet.getTeam())) { - BsTeamSetEntity teamSetEntity = teamSetService.selectByTeamName(processSet.getTeam()); - if (Func.isNotEmpty(teamSetEntity)) { - centerId = teamSetEntity.getWcId(); - } - } - WorkCenter workCenter = null; - if(orderCraft.getCaId().equals(craftAbilityId)){ - workCenter = workCenterMap.get(workCenterId); - }else{ - workCenter = workCenterService.getOne(Wrappers.lambdaQuery().apply("INSTR(',' || CRAFT_ABILITY_ID || ',', ',' || {0} || ',') > 0", orderCraft.getCaId())); - } - - if(centerId != null){ - orderCraft.setWorkCenterId(centerId); - }else{ - if(workCenter == null){ - throw new ServiceException("工艺" + orderCraft.getCaId() + "未查询到对应作业中心"); - } - orderCraft.setWorkCenterId(workCenter.getId()); - } - orderCraft.setIsOutsource(Boolean.FALSE); - } - //factor等于null代表是整体,有值时代表是单工序 - if (factor == null) { - // 更新主工序工艺能力日产能信息 - dailyAssignService.saveOrEdit(workCenterId, null, craftAbilityId, yieldOrder.getYpArea(), yieldOrder.getYpQty()); - } - return orderCrafts; - } - - /** - * @param hostCaId 主工艺能力 - * @param ocList 拥有主工艺能力的外协商 - * @param yieldOrder 生产订单 - * @param limitType 0: 正常,1:优先,2:必须 - * @return Oem - * @Description: 寻找满足条件的外协商 - * @Author dxl - * @CreateTime 2023/3/8 13:49 - */ - private Oem offsiteDistribution(Long hostCaId, List ocList, YieldOrder yieldOrder, Integer limitType) { - //没有工艺能力直接跳过 - if (ocList == null || ocList.size() == 0) { - return null; - } - //作业中心 - Oem oemCustomer = null; - //在规则表中匹配是否存在匹配的条件(查厂外) - BsAssignEntity assign = this.getRules(yieldOrder, hostCaId, BsAssignEntity.OUTSOURCE); - if (assign != null) { - //限制类型是必须(强制按此规则分派) - if (assign.getLimitType().equals(BsAssignEntity.MUST.toString())) { - //如果指定了外协商,则强制分派到此外协商;反之则分派至厂外有同种工艺能力的外协商 - if (assign.getOemId() != null) { - //判断规则中配置的外协商是否满足当前工艺能力要求,如果不满足,则此条规则作废 - if (ocList.contains(assign.getOemId())) { - //直接安排给主工艺能力对应的外协商 - oemCustomer = oemService.getById(assign.getOemId()); - oemCustomer.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_MUST); - return oemCustomer; - } - } - //挑选一个最合适的外协商 - return this.priorityOffsiteDistribution(hostCaId, ocList, BsWorkCenterEntity.LIMIT_TYPE_MUST, yieldOrder); - } else { - //如果指定了外协商,则优先判定此外协商是否满足条件,满足则分给当前外协商;反之则分派至厂外有同种工艺能力的外协商 - if (assign.getOemId() != null) { - //指定了外协商(判断规则中配置的供应商是否满足当前工艺能力要求,如果不满足,则此条规则作废) - if (ocList.contains(assign.getOemId())) { - //验证此外协商是否满足分派条件,若不满足,则在现有规则中挑选一个满足条件的供应商 - List thisLst = new ArrayList<>(); - thisLst.add(assign.getOemId()); - //查询当前外协商是否满足生产当前这批活的条件,若不满足,则考虑其他满足的供应商 - YieldOrderAssignSteer planAssignSteer = assignSteerService.findByOcIdLstAndCaId(thisLst, null, yieldOrder.getPartCode()); - //用于标识匹配规则是按零件还是工艺能力 - boolean bool = true; - if (planAssignSteer == null) { - bool = false; - planAssignSteer = assignSteerService.findByOcIdLstAndCaId(thisLst, hostCaId, null); - } - - if (planAssignSteer != null) { - oemCustomer = oemService.getById(assign.getOemId()); - oemCustomer.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_PRIOR); - oemCustomer.setPartCodeYesOrNo(bool); - return oemCustomer; - } - } - } - } - } - //挑选一个最合适的外协商 - return this.priorityOffsiteDistribution(hostCaId, ocList, limitType, yieldOrder); - } - - /** - * @param hostCaId 主工艺能力 - * @param ocList 外协商集合 - * @param limitType 正常,1:优先,2:必须 - * @return Oem - * @Description: 多外协商挑选合适的作业中心 - * @Author dxl - * @CreateTime 2023/3/8 14:03 - */ - private Oem priorityOffsiteDistribution(Long hostCaId, List ocList, Integer limitType, YieldOrder yieldOrder) { - // 没有工艺能力的对应作业中心,直接分派厂外 - if (ocList == null || ocList.size() == 0) { - return null; - } - - // 外协商 - Oem oemCustomer = null; - // 首先根据零件号查询是否存在零件级的分派规则 - YieldOrderAssignSteer planAssignSteer = assignSteerService.findByOcIdLstAndCaId(ocList, null, yieldOrder.getPartCode()); - //用于标识匹配规则是按零件还是工艺能力 - boolean bool = true; - if (planAssignSteer == null) { - bool = false; - - // 获取到满足条件的供应商 - // 对有能力做这个单子厂家按照偏差因子排序 - if (!ocList.isEmpty()) { - List bsPlanAssignSteerList = assignSteerService.sortDataByFactor(ocList, hostCaId); - CraftAbilityEntity craftAbility = iCraftAbilityService.getById(hostCaId); - for (YieldOrderAssignSteer bsPlanAssignSteer : bsPlanAssignSteerList) { - oemCustomer = oemService.getById(bsPlanAssignSteer.getOemId()); - String oemCode = oemCustomer.getCode(); - - // 改伊川喷砂工艺能力不限制厂家等级资质 - // 使用工艺能力表中加工类型字段控制工艺能力是否需要进行外协等级资质判断 - boolean aBoolean = false; - aBoolean = assignSteerService.queryOemAndCaid(oemCode, yieldOrder.getProductIdent()); - //zxh 20251015 工作订单备注中包含zdzx时,单独校验厂家是否有JI以及JHT资质,若不存在相关等级资质,不允许派此厂家 - if (yieldOrder.getYpMemo() != null && yieldOrder.getYpMemo().toLowerCase(Locale.ROOT).contains("zdzx")) { - boolean aBooleanJI = assignSteerService.queryOemAndCaid(oemCode, "JI"); - boolean aBooleanJHT = assignSteerService.queryOemAndCaid(oemCode, "JHT"); - if (!aBooleanJI || !aBooleanJHT) { - aBoolean = false; - } - } - - if ("0".equals(craftAbility.getWtId())) { - aBoolean = true; - } - - if (aBoolean) { - oemCustomer.setLimitType(limitType); - oemCustomer.setPartCodeYesOrNo(bool); - return oemCustomer; - } - } - } - } - // 如果找到合适的外协商直接分派,反之如果未找到合适的外协商 - if (planAssignSteer != null) { - oemCustomer = oemService.getById(planAssignSteer.getOemId()); - oemCustomer.setLimitType(limitType); - oemCustomer.setPartCodeYesOrNo(bool); - return oemCustomer; - } - return null; - } - - /** - * @param oemCustomer 外协商 - * @param craftAbilityMap 工艺能力组装的生产计划map - * @param keys 当前生产订单下的工艺能力集合 - * @return List - * @Description: 绑定外协商到生成计划 - * @Author dxl - * @CreateTime 2023/2/17 16:28 - */ - private List bindOem(Oem oemCustomer, Long craftAbilityId, Map> craftAbilityMap, Set keys, YieldOrder yieldOrder, Boolean factor) throws Exception { - log.info("自动分派,流程卡号:{},分给外协,外协商为:{}", yieldOrder.getCardNo(), JSONObject.toJSONString(oemCustomer)); - List rtnList = new ArrayList<>(); - - OemCraftAbilityEntity oemAbility = null; - //开始循环生产订单中组合的工艺能力key集合,主工艺能力之前的全部分配到此外协商 - for (Long key : keys) { - //验证工艺能力 + orderCrafts.addAll(craftAbilityMap.get(craftId)); + } + + // 开始分派到作业中心 + for (YieldOrderCraft orderCraft : orderCrafts) { + Long centerId = orderCraft.getWorkCenterId(); + // 判定是否是特殊工序 + BsProcessSetEntity processSet = processSetService.getById(orderCraft.getPpsId()); + if (Func.isNotEmpty(processSet) && Func.isNotBlank(processSet.getTeam())) { + BsTeamSetEntity teamSetEntity = teamSetService.selectByTeamName(processSet.getTeam()); + if (Func.isNotEmpty(teamSetEntity)) { + centerId = teamSetEntity.getWcId(); + } + } + WorkCenter workCenter = null; + if (orderCraft.getCaId().equals(craftAbilityId)) { + workCenter = workCenterMap.get(workCenterId); + } else { + workCenter = workCenterService.getOne(Wrappers.lambdaQuery().apply("INSTR(',' || CRAFT_ABILITY_ID || ',', ',' || {0} || ',') > 0", orderCraft.getCaId())); + } + + if (centerId != null) { + orderCraft.setWorkCenterId(centerId); + } else { + if (workCenter == null) { + throw new ServiceException("工艺" + orderCraft.getCaId() + "未查询到对应作业中心"); + } + orderCraft.setWorkCenterId(workCenter.getId()); + } + orderCraft.setIsOutsource(Boolean.FALSE); + } + //factor等于null代表是整体,有值时代表是单工序 + if (factor == null) { + // 更新主工序工艺能力日产能信息 + dailyAssignService.saveOrEdit(workCenterId, null, craftAbilityId, yieldOrder.getYpArea(), yieldOrder.getYpQty()); + } + return orderCrafts; + } + + /** + * @param hostCaId 主工艺能力 + * @param ocList 拥有主工艺能力的外协商 + * @param yieldOrder 生产订单 + * @param limitType 0: 正常,1:优先,2:必须 + * @return Oem + * @Description: 寻找满足条件的外协商 + * @Author dxl + * @CreateTime 2023/3/8 13:49 + */ + private Oem offsiteDistribution(Long hostCaId, List ocList, YieldOrder yieldOrder, Integer limitType) { + //没有工艺能力直接跳过 + if (ocList == null || ocList.size() == 0) { + return null; + } + //作业中心 + Oem oemCustomer = null; + //在规则表中匹配是否存在匹配的条件(查厂外) + BsAssignEntity assign = this.getRules(yieldOrder, hostCaId, BsAssignEntity.OUTSOURCE); + if (assign != null) { + //限制类型是必须(强制按此规则分派) + if (assign.getLimitType().equals(BsAssignEntity.MUST.toString())) { + //如果指定了外协商,则强制分派到此外协商;反之则分派至厂外有同种工艺能力的外协商 + if (assign.getOemId() != null) { + //判断规则中配置的外协商是否满足当前工艺能力要求,如果不满足,则此条规则作废 + if (ocList.contains(assign.getOemId())) { + //直接安排给主工艺能力对应的外协商 + oemCustomer = oemService.getById(assign.getOemId()); + oemCustomer.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_MUST); + return oemCustomer; + } + } + //挑选一个最合适的外协商 + return this.priorityOffsiteDistribution(hostCaId, ocList, BsWorkCenterEntity.LIMIT_TYPE_MUST, yieldOrder); + } else { + //如果指定了外协商,则优先判定此外协商是否满足条件,满足则分给当前外协商;反之则分派至厂外有同种工艺能力的外协商 + if (assign.getOemId() != null) { + //指定了外协商(判断规则中配置的供应商是否满足当前工艺能力要求,如果不满足,则此条规则作废) + if (ocList.contains(assign.getOemId())) { + //验证此外协商是否满足分派条件,若不满足,则在现有规则中挑选一个满足条件的供应商 + List thisLst = new ArrayList<>(); + thisLst.add(assign.getOemId()); + //查询当前外协商是否满足生产当前这批活的条件,若不满足,则考虑其他满足的供应商 + YieldOrderAssignSteer planAssignSteer = assignSteerService.findByOcIdLstAndCaId(thisLst, null, yieldOrder.getPartCode()); + //用于标识匹配规则是按零件还是工艺能力 + boolean bool = true; + if (planAssignSteer == null) { + bool = false; + planAssignSteer = assignSteerService.findByOcIdLstAndCaId(thisLst, hostCaId, null); + } + + if (planAssignSteer != null) { + oemCustomer = oemService.getById(assign.getOemId()); + oemCustomer.setLimitType(BsWorkCenterEntity.LIMIT_TYPE_PRIOR); + oemCustomer.setPartCodeYesOrNo(bool); + return oemCustomer; + } + } + } + } + } + //挑选一个最合适的外协商 + return this.priorityOffsiteDistribution(hostCaId, ocList, limitType, yieldOrder); + } + + /** + * @param hostCaId 主工艺能力 + * @param ocList 外协商集合 + * @param limitType 正常,1:优先,2:必须 + * @return Oem + * @Description: 多外协商挑选合适的作业中心 + * @Author dxl + * @CreateTime 2023/3/8 14:03 + */ + private Oem priorityOffsiteDistribution(Long hostCaId, List ocList, Integer limitType, YieldOrder yieldOrder) { + // 没有工艺能力的对应作业中心,直接分派厂外 + if (ocList == null || ocList.size() == 0) { + return null; + } + + // 外协商 + Oem oemCustomer = null; + // 首先根据零件号查询是否存在零件级的分派规则 + YieldOrderAssignSteer planAssignSteer = assignSteerService.findByOcIdLstAndCaId(ocList, null, yieldOrder.getPartCode()); + //用于标识匹配规则是按零件还是工艺能力 + boolean bool = true; + if (planAssignSteer == null) { + bool = false; + + // 获取到满足条件的供应商 + // 对有能力做这个单子厂家按照偏差因子排序 + if (!ocList.isEmpty()) { + List bsPlanAssignSteerList = assignSteerService.sortDataByFactor(ocList, hostCaId); + CraftAbilityEntity craftAbility = iCraftAbilityService.getById(hostCaId); + for (YieldOrderAssignSteer bsPlanAssignSteer : bsPlanAssignSteerList) { + oemCustomer = oemService.getById(bsPlanAssignSteer.getOemId()); + String oemCode = oemCustomer.getCode(); + + // 改伊川喷砂工艺能力不限制厂家等级资质 + // 使用工艺能力表中加工类型字段控制工艺能力是否需要进行外协等级资质判断 + boolean aBoolean = false; + aBoolean = assignSteerService.queryOemAndCaid(oemCode, yieldOrder.getProductIdent()); + //zxh 20251015 工作订单备注中包含zdzx时,单独校验厂家是否有JI以及JHT资质,若不存在相关等级资质,不允许派此厂家 + if (yieldOrder.getYpMemo() != null && yieldOrder.getYpMemo().toLowerCase(Locale.ROOT).contains("zdzx")) { + boolean aBooleanJI = assignSteerService.queryOemAndCaid(oemCode, "JI"); + boolean aBooleanJHT = assignSteerService.queryOemAndCaid(oemCode, "JHT"); + if (!aBooleanJI || !aBooleanJHT) { + aBoolean = false; + } + } + + if ("0".equals(craftAbility.getWtId())) { + aBoolean = true; + } + + if (aBoolean) { + oemCustomer.setLimitType(limitType); + oemCustomer.setPartCodeYesOrNo(bool); + return oemCustomer; + } + } + } + } + // 如果找到合适的外协商直接分派,反之如果未找到合适的外协商 + if (planAssignSteer != null) { + oemCustomer = oemService.getById(planAssignSteer.getOemId()); + oemCustomer.setLimitType(limitType); + oemCustomer.setPartCodeYesOrNo(bool); + return oemCustomer; + } + return null; + } + + /** + * @param oemCustomer 外协商 + * @param craftAbilityMap 工艺能力组装的生产计划map + * @param keys 当前生产订单下的工艺能力集合 + * @return List + * @Description: 绑定外协商到生成计划 + * @Author dxl + * @CreateTime 2023/2/17 16:28 + */ + private List bindOem(Oem oemCustomer, Long craftAbilityId, Map> craftAbilityMap, Set keys, YieldOrder yieldOrder, Boolean factor) throws Exception { + log.info("自动分派,流程卡号:{},分给外协,外协商为:{}", yieldOrder.getCardNo(), JSONObject.toJSONString(oemCustomer)); + List rtnList = new ArrayList<>(); + + OemCraftAbilityEntity oemAbility = null; + //开始循环生产订单中组合的工艺能力key集合,主工艺能力之前的全部分配到此外协商 + for (Long key : keys) { + //验证工艺能力 // oemAbility = oemCraftAbilityService.findBsOemAbility(oemCustomer.getId(), key); // if (oemAbility == null) { // break; // } - rtnList.addAll(craftAbilityMap.get(key)); - } - // 开始分派到外协商 - WorkCenter workCenter = null; - for (YieldOrderCraft orderCraft : rtnList) { - BsProcessSetEntity processSet = processSetService.getById(orderCraft.getPpsId()); - if (processSet != null && "1".equals(processSet.getIsDispatch())) { - workCenter = workCenterService.getOne(Wrappers.lambdaQuery().apply("INSTR(',' || CRAFT_ABILITY_ID || ',', ',' || {0} || ',') > 0", orderCraft.getCaId())); - if (workCenter == null) { - throw new ServiceException("工艺" + orderCraft.getCaId() + "未查询到对应作业中心"); - } - orderCraft.setWorkCenterId(workCenter.getId()); - orderCraft.setIsOutsource(Boolean.FALSE); - } else { - orderCraft.setOcId(oemCustomer.getId()); - orderCraft.setIsOutsource(Boolean.TRUE); - } - } - - if (workCenter != null) { - yieldOrder.setWorkCenterId(workCenter.getId()); - yieldOrderMapper.updateById(yieldOrder); - } - - // 更新主工序工艺能力日产能信息 - dailyAssignService.saveOrEdit(null, oemCustomer.getId(), craftAbilityId, yieldOrder.getYpArea(), yieldOrder.getYpQty()); - return rtnList; - } - - /** - * 获取一个优先级最高的规则 - * - * @param yieldOrder 生产订单 - * @param caId 工艺能力 - * @return PjRules - * @Description: 匹配规则条件 - * @Author dxl - * @CreateTime 2023/2/16 17:30 - */ - private BsAssignEntity getRules(YieldOrder yieldOrder, Long caId, int appointType) { - List rulesList = assignService.listByPointType(appointType); - BsAssignEntity rtnRule = null; - int num = 0, rtn = 0; - for (BsAssignEntity rules : rulesList) { - rtn = this.analysesRule(rules, yieldOrder, caId); - if (rtn > num) { - // 判定规则优先级,如果本次匹配到的规则的RulesOrder如果大于上次匹配规则的RulesOrder,则跳过 - if (rtnRule != null && rtnRule.getSort() < rules.getSort()) { - continue; - } - num = rtn; - rtnRule = rules; - } - } - // 质量等级规则监控 - if (rtnRule != null && StringUtils.isNotBlank(rtnRule.getProdMark())) { - log.error("生产订单id: " + yieldOrder.getId() + "等级:" + yieldOrder.getProductIdent() + "规则id:" + (rtnRule == null ? "" : rtnRule.getId())); - } - return rtnRule; - } - - /** - * 根据规则的匹配项, 计算使用能力的优先级 - * - * @param rules 规则记录 - * @param yieldOrder 生产订单 - * @param caId 工艺能力 - * @return int - * @Description: 匹配条件 - * @Author dxl - * @CreateTime 2023/2/16 17:26 - */ - private int analysesRule(BsAssignEntity rules, YieldOrder yieldOrder, Long caId) { - //条件匹配根据占比累计 - int sum = 0; - - //工艺能力 - if (rules.getCraftAbilityId() != null) { - if (caId.equals(rules.getCraftAbilityId())) { - sum = sum + 51; - } else { - return 0; - } - } - - //零件号 - if (StringUtils.isNotBlank(rules.getPartCode())) { - if (yieldOrder.getPartCode().equals(rules.getPartCode())) { - sum = sum + 25; - } else { - return 0; - } - } - - // 质量等级 - if (StringUtils.isNotBlank(rules.getProdMark())) { - if (rules.getProdMark().contains("\"" + yieldOrder.getProductIdent() + "\"")) { - sum = sum + 13; - } else { - return 0; - } - } - - Double totalArea = yieldOrder.getYpArea() * yieldOrder.getYpQty(); - BigDecimal areaVal = new BigDecimal(totalArea); - - //单批面积规则和单位面积规则取其一,如果单批面积存在则按照单批面积规则 - if ((rules.getSingleUpArea() != null && rules.getSingleUpArea().compareTo(BigDecimal.ZERO) > 0) || (rules.getSingleDownArea() != null && rules.getSingleDownArea().compareTo(BigDecimal.ZERO) > 0)) { - //单批面积下限 - if (rules.getSingleDownArea() != null && rules.getSingleDownArea().compareTo(BigDecimal.ZERO) > 0) { - if (areaVal.compareTo(rules.getSingleDownArea()) >= 0) { - sum = sum + 7; - } else { - return 0; - } - } - //单批面积上限 - if (rules.getSingleUpArea() != null && rules.getSingleUpArea().compareTo(BigDecimal.ZERO) > 0) { - if (areaVal.compareTo(rules.getSingleUpArea()) <= 0) { - sum = sum + 4; - } else { - return 0; - } - } - } else { - //单位面积下限 - if (rules.getLowArea() != null && rules.getLowArea().compareTo(BigDecimal.ZERO) > 0) { - if (areaVal.compareTo(rules.getLowArea()) >= 0) { - sum = sum + 7; - } else { - return 0; - } - } - //单位面积上限 - if (rules.getUpArea() != null && rules.getUpArea().compareTo(BigDecimal.ZERO) > 0) { - if (areaVal.compareTo(rules.getUpArea()) <= 0) { - sum = sum + 4; - } else { - return 0; - } - } - } - return sum; - } + rtnList.addAll(craftAbilityMap.get(key)); + } + // 开始分派到外协商 + WorkCenter workCenter = null; + for (YieldOrderCraft orderCraft : rtnList) { + BsProcessSetEntity processSet = processSetService.getById(orderCraft.getPpsId()); + if (processSet != null && "1".equals(processSet.getIsDispatch())) { + workCenter = workCenterService.getOne(Wrappers.lambdaQuery().apply("INSTR(',' || CRAFT_ABILITY_ID || ',', ',' || {0} || ',') > 0", orderCraft.getCaId())); + if (workCenter == null) { + throw new ServiceException("工艺" + orderCraft.getCaId() + "未查询到对应作业中心"); + } + orderCraft.setWorkCenterId(workCenter.getId()); + orderCraft.setIsOutsource(Boolean.FALSE); + } else { + orderCraft.setOcId(oemCustomer.getId()); + orderCraft.setIsOutsource(Boolean.TRUE); + } + } + + if (workCenter != null) { + yieldOrder.setWorkCenterId(workCenter.getId()); + yieldOrderMapper.updateById(yieldOrder); + } + + // 更新主工序工艺能力日产能信息 + dailyAssignService.saveOrEdit(null, oemCustomer.getId(), craftAbilityId, yieldOrder.getYpArea(), yieldOrder.getYpQty()); + return rtnList; + } + + /** + * 获取一个优先级最高的规则 + * + * @param yieldOrder 生产订单 + * @param caId 工艺能力 + * @return PjRules + * @Description: 匹配规则条件 + * @Author dxl + * @CreateTime 2023/2/16 17:30 + */ + private BsAssignEntity getRules(YieldOrder yieldOrder, Long caId, int appointType) { + List rulesList = assignService.listByPointType(appointType); + BsAssignEntity rtnRule = null; + int num = 0, rtn = 0; + for (BsAssignEntity rules : rulesList) { + rtn = this.analysesRule(rules, yieldOrder, caId); + if (rtn > num) { + // 判定规则优先级,如果本次匹配到的规则的RulesOrder如果大于上次匹配规则的RulesOrder,则跳过 + if (rtnRule != null && rtnRule.getSort() < rules.getSort()) { + continue; + } + num = rtn; + rtnRule = rules; + } + } + // 质量等级规则监控 + if (rtnRule != null && StringUtils.isNotBlank(rtnRule.getProdMark())) { + log.error("生产订单id: " + yieldOrder.getId() + "等级:" + yieldOrder.getProductIdent() + "规则id:" + (rtnRule == null ? "" : rtnRule.getId())); + } + return rtnRule; + } + + /** + * 根据规则的匹配项, 计算使用能力的优先级 + * + * @param rules 规则记录 + * @param yieldOrder 生产订单 + * @param caId 工艺能力 + * @return int + * @Description: 匹配条件 + * @Author dxl + * @CreateTime 2023/2/16 17:26 + */ + private int analysesRule(BsAssignEntity rules, YieldOrder yieldOrder, Long caId) { + //条件匹配根据占比累计 + int sum = 0; + + //工艺能力 + if (rules.getCraftAbilityId() != null) { + if (caId.equals(rules.getCraftAbilityId())) { + sum = sum + 51; + } else { + return 0; + } + } + + //零件号 + if (StringUtils.isNotBlank(rules.getPartCode())) { + if (yieldOrder.getPartCode().equals(rules.getPartCode())) { + sum = sum + 25; + } else { + return 0; + } + } + + // 质量等级 + if (StringUtils.isNotBlank(rules.getProdMark())) { + if (rules.getProdMark().contains("\"" + yieldOrder.getProductIdent() + "\"")) { + sum = sum + 13; + } else { + return 0; + } + } + + Double totalArea = yieldOrder.getYpArea() * yieldOrder.getYpQty(); + BigDecimal areaVal = new BigDecimal(totalArea); + + //单批面积规则和单位面积规则取其一,如果单批面积存在则按照单批面积规则 + if ((rules.getSingleUpArea() != null && rules.getSingleUpArea().compareTo(BigDecimal.ZERO) > 0) || (rules.getSingleDownArea() != null && rules.getSingleDownArea().compareTo(BigDecimal.ZERO) > 0)) { + //单批面积下限 + if (rules.getSingleDownArea() != null && rules.getSingleDownArea().compareTo(BigDecimal.ZERO) > 0) { + if (areaVal.compareTo(rules.getSingleDownArea()) >= 0) { + sum = sum + 7; + } else { + return 0; + } + } + //单批面积上限 + if (rules.getSingleUpArea() != null && rules.getSingleUpArea().compareTo(BigDecimal.ZERO) > 0) { + if (areaVal.compareTo(rules.getSingleUpArea()) <= 0) { + sum = sum + 4; + } else { + return 0; + } + } + } else { + //单位面积下限 + if (rules.getLowArea() != null && rules.getLowArea().compareTo(BigDecimal.ZERO) > 0) { + if (areaVal.compareTo(rules.getLowArea()) >= 0) { + sum = sum + 7; + } else { + return 0; + } + } + //单位面积上限 + if (rules.getUpArea() != null && rules.getUpArea().compareTo(BigDecimal.ZERO) > 0) { + if (areaVal.compareTo(rules.getUpArea()) <= 0) { + sum = sum + 4; + } else { + return 0; + } + } + } + return sum; + } } diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/feign/WorkOrderRunOutClient.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/feign/WorkOrderRunOutClient.java new file mode 100644 index 000000000..6f53f7580 --- /dev/null +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/feign/WorkOrderRunOutClient.java @@ -0,0 +1,27 @@ +package org.springblade.desk.produce.feign; + +import io.swagger.v3.oas.annotations.Hidden; +import lombok.RequiredArgsConstructor; +import org.springblade.core.tenant.annotation.NonDS; +import org.springblade.core.tool.api.R; +import org.springblade.desk.produce.service.IWorkOrderRunService; +import org.springframework.web.bind.annotation.RestController; + +/** + * 外协订单下达ERP Feign实现 + * + * @author zangzhipeng + */ +@NonDS +@Hidden +@RestController +@RequiredArgsConstructor +public class WorkOrderRunOutClient implements IWorkOrderRunOutClient { + + private final IWorkOrderRunService workOrderRunService; + + @Override + public R oemOrderOut() { + return workOrderRunService.oemOrderOut(); + } +} diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/PdaLoadServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/PdaLoadServiceImpl.java index ee350b7ea..91f11161a 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/PdaLoadServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/PdaLoadServiceImpl.java @@ -441,10 +441,8 @@ public class PdaLoadServiceImpl extends BaseServiceImpl yieldOrderCrafts = yieldOrderCraftService.listByYoId(yieldOrder.getId()); + // 调用转厂内自动分派逻辑,只查询外协工序之后的工序 + List yieldOrderCrafts = yieldOrderCraftService.listByYoIdAndNo(yieldOrder.getId(), deliverablePlan.getOrders()); +// List yieldOrderCrafts = yieldOrderCraftService.listByYoId(yieldOrder.getId(), deliverablePlan.getOrders()); try { yieldOrderCraftService.automaticDispatch(yieldOrderCrafts, yieldOrder, Boolean.TRUE, null); } catch (Exception e) { @@ -336,7 +342,7 @@ public class WorkOrderRunServiceImpl extends BaseServiceImpl processSets = processSetMapper.selectByIds(wpList.stream().filter(workPlan -> oem.getId().equals(workPlan.getOcId())).map(WorkPlan::getPpsId).collect(Collectors.toList())); - String ppsName = processSets.stream().map(BsProcessSetEntity::getName).collect(Collectors.joining(",")); - // 获取wpList最大的计划结束时间 - LocalDateTime maxPlanEndTime = wpList.stream().map(WorkPlan::getPlanEndTime).max(LocalDateTime::compareTo).orElse(null); - if (maxPlanEndTime == null) { - maxPlanEndTime = LocalDateTime.now(); - } - wxWoCode = erpDataOemClient.fullOrderOutsourcing(yo.getPartCode(), yo.getProductIdent(), wo.getBatchNo(), oem != null ? oem.getCode() : "", ppsName, yo.getYoCode(), - planner != null ? planner.getName() : "", maxPlanEndTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")), wo.getMakeQty(), "").getData(); - } else { - User user = UserCache.getUser(workOrderRun.getCreateUser()); - User dispatcher = UserCache.getUser(wo.getDispatcher()); - String roamNo = null; - String craftNo = null; - Long craftId = yo.getCraftId(); - // 返工单号 - if (craftId != null && wo.getReworkCode() == null) { - Map craftInfo = baseMapper.selectRoamAndCraftNoByCraftId(craftId); - roamNo = craftInfo.get("ROAMNO"); - craftNo = craftInfo.get("CRAFTNO"); - if (roamNo == null) { - craftInfo = baseMapper.selectRoamAndCraftNoByPartCode(yo.getPartCode()); - roamNo = craftInfo.get("ROAMNO"); - craftNo = craftInfo.get("CRAFTNO"); - } - } else if (StringUtils.isNotBlank(wo.getReworkCode())) { - roamNo = wo.getReworkCode(); - craftNo = "返修"; - craftId = Long.valueOf(wo.getReworkNo()); - } - String format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault()).format(yo.getDemandDate().toInstant()); - wxWoCode = erpDataOemClient.collaborativeOutsourcing(yo.getPartCode(), yo.getProductIdent(), format, wo.getMakeQty(), yo.getUseDeptCode(), yo.getUseDept(), - wo.getBatchNo(), oem != null ? oem.getCode() : "", yo.getPlate(), yo.getYpCode(), yo.getYoCode(), user != null ? user.getName() : "", - planner != null ? planner.getName() : "", dispatcher != null ? dispatcher.getName() : "", roamNo, craftNo, craftId).getData(); - } - // 赋值wx号,erp返回 - workOrderRun.setWoCode(wxWoCode); - if (StringUtils.isNotBlank(wxWoCode)) { - updateWorkPlanAndOrderStatus(wo, wxWoCode); - } } else { //转厂内业务 WorkPlan nextWorkPlan; @@ -549,7 +509,7 @@ public class WorkOrderRunServiceImpl extends BaseServiceImpl result = erpMesRbWoClient.getDemandDateByWono(ypCode); + if (result.isSuccess() && StringUtils.isNotBlank(result.getData())) { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + return sdf.parse(result.getData()); + } + } catch (Exception e) { + log.warn("从ERP查询需求日期失败,ypCode={},使用默认值"); + } + // 默认当前日期+10天 + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_MONTH, 10); + return cal.getTime(); + } + @Transactional(rollbackFor = Exception.class) @Override public R changeOemManufacturer(Long worId, Long ocId) { @@ -924,7 +908,7 @@ public class WorkOrderRunServiceImpl extends BaseServiceImpl wprList = workPlanRunMapper.selectList( - new LambdaQueryWrapper() - .eq(WorkPlanRun::getWorId, workOrderRun.getId())); - if (!wprList.isEmpty()) { - List wpIds = wprList.stream().map(WorkPlanRun::getWpId).collect(Collectors.toList()); - List oemPlans = workPlanMapper.selectList( - new LambdaQueryWrapper().in(WorkPlan::getId, wpIds)); - for (WorkPlan wp : oemPlans) { - wp.setStatus(WorkPlan.STATUS_WORK_OK); - wp.setFactStartTime(startTime); - wp.setFactEndTime(endTime); - wp.setWorkQty(workOrder.getMakeQty()); - wp.setQualifiedQty(workOrder.getMakeQty()); - } - workPlanMapper.updateById(oemPlans); + List oemPlans = workPlanMapper.selectList(Wrappers.lambdaQuery(WorkPlan.class).eq(WorkPlan::getOem, "1") + .eq(WorkPlan::getWoId, deliverablePlan.getWoId()).lt(WorkPlan::getStatus, WorkPlan.STATUS_WORK_OK) + .lt(WorkPlan::getOrders, deliverablePlan.getOrders())); + for (WorkPlan wp : oemPlans) { + wp.setStatus(WorkPlan.STATUS_COMPLETE); + wp.setFactStartTime(startTime); + wp.setFactEndTime(endTime); + wp.setWorkQty(workOrder.getMakeQty()); + wp.setQualifiedQty(workOrder.getMakeQty()); } + workPlanMapper.updateById(oemPlans); } /** diff --git a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java index 1cc9acb8b..9e9d0b290 100644 --- a/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java +++ b/blade-service/blade-desk/src/main/java/org/springblade/desk/produce/service/impl/WorkOrderServiceImpl.java @@ -2936,7 +2936,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl getDemandDateByWono(String wono) { + return R.data(erpMesRbWoService.getDemandDateByWono(wono)); + } } diff --git a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.java b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.java index 5f99b5750..7fb1d87f4 100644 --- a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.java +++ b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.java @@ -20,4 +20,12 @@ public interface ErpMesRbWoMapper extends Mapper { List getYieldPlanErpList(String newlevdateMax); String getNewlevdateMax(String selectTime); + + /** + * 根据工作订单号查询需求日期 + * + * @param wono 工作订单号 + * @return 需求日期字符串 + */ + String getDemandDateByWono(String wono); } diff --git a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.xml b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.xml index 2640b1b7d..6e667dcd2 100644 --- a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.xml +++ b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/mapper/ErpMesRbWoMapper.xml @@ -43,4 +43,8 @@ a.wopordat >= TO_DATE(#{selectTime}, 'YYYY-MM-DD HH24:MI:SS') + + diff --git a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/IErpMesRbWoService.java b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/IErpMesRbWoService.java index 7b153acd6..3d084f33d 100644 --- a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/IErpMesRbWoService.java +++ b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/IErpMesRbWoService.java @@ -56,4 +56,12 @@ public interface IErpMesRbWoService { * 同步配套数据 */ void synSupportingFacilities(); + + /** + * 根据工作订单号查询ERP需求日期 + * + * @param wono 工作订单号 + * @return 需求日期字符串,查不到返回null + */ + String getDemandDateByWono(String wono); } diff --git a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpDataWmsServiceImpl.java b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpDataWmsServiceImpl.java index 2dd6379fb..4afee4e9b 100644 --- a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpDataWmsServiceImpl.java +++ b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpDataWmsServiceImpl.java @@ -325,7 +325,7 @@ public class ErpDataWmsServiceImpl implements IErpDataWmsService { Map inParams = new HashMap<>(); inParams.put("v_prtno", goodsCode == null ? "" : goodsCode); inParams.put("v_prtdesc", goodsName == null ? "" : goodsName); - inParams.put("v_desno", null); + inParams.put("v_desno", ""); // 执行存储过程 Map resultMap = jdbcCall.execute(inParams); diff --git a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpMesRbWoServiceImpl.java b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpMesRbWoServiceImpl.java index 3cc06cf97..ddac3f5f6 100644 --- a/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpMesRbWoServiceImpl.java +++ b/blade-service/blade-erpdata/src/main/java/org/springblade/erpdata/service/impl/ErpMesRbWoServiceImpl.java @@ -817,6 +817,11 @@ public class ErpMesRbWoServiceImpl implements IErpMesRbWoService { // apsOrderClient.saveOrderList(yieldOrderList); } + @Override + public String getDemandDateByWono(String wono) { + return mesRbWoMapper.getDemandDateByWono(wono); + } + private YieldOrder updateYieldType(YieldOrder yieldOrder,String pritno,String firseq){ //从零件表中查询零件信息 DsPartEntity part=apsOrderClient.getDsCraftListByCode(pritno); diff --git a/blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/WorkOrderServiceImpl.java b/blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/WorkOrderServiceImpl.java index 1335eae6a..4499e9adf 100644 --- a/blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/WorkOrderServiceImpl.java +++ b/blade-service/blade-scheduling/src/main/java/org/springblade/scheduling/scheduling/service/impl/WorkOrderServiceImpl.java @@ -2174,27 +2174,27 @@ public class WorkOrderServiceImpl extends BaseServiceImpl 5) { - result = (5.8 * sumOfQuota + 20) / 60 + 0.8; + result = (6.2 * sumOfQuota + 20) / 60 + 0.8; if (y > 2) { result = 1.5 * result; } if (hb) { - result = result + 0.5 * sumOfQuota / 60 + 0.2; + result = result + 1 * sumOfQuota / 60 + 0.2; } if (x > 3) { result = 1.2 * result + 3; } } if (sumOfQuota <= 30 && sumOfQuota > 20) { - result = (6 * sumOfQuota + 20) / 60 + 0.8; + result = (6.5 * sumOfQuota + 20) / 60 + 0.8; if (y > 2) { result = 1.6 * result; } if (hb) { - result = result + (1 * sumOfQuota) / 60 + 0.2; + result = result + (1.3 * sumOfQuota) / 60 + 0.2; } if (x > 3) { result = 1.5 * result + 5; @@ -2206,7 +2206,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl 3) { result = 1.8 * result + 6; @@ -2215,10 +2215,10 @@ public class WorkOrderServiceImpl extends BaseServiceImpl 50) { result = (6.4 * sumOfQuota + 25) / 60 + 1.5; if (y > 2) { - result = 2 * result; + result = 2.1 * result; } if (hb) { - result = result + (3 * sumOfQuota) / 60 + 0.5; + result = result + (3 * sumOfQuota) / 60 + 1.5; } if (x > 3) { result = 2.2 * result + 9; @@ -2227,10 +2227,10 @@ public class WorkOrderServiceImpl extends BaseServiceImpl 80) { result = (6.5 * sumOfQuota + 25) / 60 + 1.8; if (y > 2) { - result = 2 * result; + result = 2.1 * result; } if (hb) { - result = result + (3.5 * sumOfQuota) / 60 + 0.7; + result = result + (3.5 * sumOfQuota) / 60 + 2; } if (x > 3) { result = 2.5 * result + 12; @@ -2242,7 +2242,7 @@ public class WorkOrderServiceImpl extends BaseServiceImpl 3) { result = 2.5 * result + 15; diff --git a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.java b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.java index 717e2b5fc..91c19651f 100644 --- a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.java +++ b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.java @@ -55,6 +55,6 @@ public interface StGlassCakeOutMapper extends BaseMapper { List getYieldOrderList(Long id, String yieldType); - DsPartRelationEntity getPartQuota(String partCode, String goodsCode); + DsPartRelationEntity getPartQuota(String partCode, String subCode); } diff --git a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.xml b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.xml index 12cff5949..21eecd685 100644 --- a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.xml +++ b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGlassCakeOutMapper.xml @@ -41,7 +41,7 @@ gco.part_name, gco.batch_code, gco.card_no, gco.quantity, gco.require_qty, gco.stove_pi_no, gco.out_qty, gco.cur_status, gco.est_use_time, gco.out_time, gco.out_users, gco.out_code, - gco.memo, gco.picker, + gco.memo, gco.picker, gco.pre_out_qty, -- 物料表字段(根据实际ST_GOODS字段调整,无则删对应行) g.goods_code, g.id AS goodsId, diff --git a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGraphiteMoldOutMapper.xml b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGraphiteMoldOutMapper.xml index d259f1ec9..42a12dbd8 100644 --- a/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGraphiteMoldOutMapper.xml +++ b/blade-service/blade-wms/src/main/java/org/springblade/wms/mapper/StGraphiteMoldOutMapper.xml @@ -35,6 +35,7 @@ gmo.sir_id, gmo.yo_code, gmo.pi_no, gmo.card_no, gmo.need_quantity, gmo.outed_quantity, gmo.cur_status, gmo.out_time, gmo.out_user, gmo.out_code, gmo.picker, + gmo.parent_out_code, gmo.complete_quantity, -- 物料表字段 g.goods_code, g.id AS goodsId, diff --git a/blade-service/blade-wms/src/main/java/org/springblade/wms/service/impl/StGraphiteMoldOutServiceImpl.java b/blade-service/blade-wms/src/main/java/org/springblade/wms/service/impl/StGraphiteMoldOutServiceImpl.java index bbaed0734..929e3a5f5 100644 --- a/blade-service/blade-wms/src/main/java/org/springblade/wms/service/impl/StGraphiteMoldOutServiceImpl.java +++ b/blade-service/blade-wms/src/main/java/org/springblade/wms/service/impl/StGraphiteMoldOutServiceImpl.java @@ -1,6 +1,5 @@ package org.springblade.wms.service.impl; -import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; @@ -22,8 +21,6 @@ import org.springblade.wms.mapper.StGraphiteMoldOutMapper; import org.springblade.wms.mapper.StRealtimeStockMapper; import org.springblade.wms.mapper.StStockInoutRecordMapper; import org.springblade.wms.pojo.dto.StGraphiteMoldOutDTO; -import org.springblade.wms.pojo.dto.StockOccupyTempDTO; -import org.springblade.wms.pojo.dto.SubItemStockDTO; import org.springblade.wms.pojo.entity.*; import org.springblade.wms.pojo.vo.StGraphiteMoldOutVO; import org.springblade.wms.service.*; @@ -105,83 +102,36 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl sourceSubStockList = new ArrayList<>(); - for (DsPartEntity bom : allChildPartList) { - SubItemStockDTO item = new SubItemStockDTO(); - item.setSubGoodsCode(bom.getPartCode()); - // 单套子件耗用数量 - DsPartRelationEntity dsPartRelation = stGlassCakeOutMapper.getPartQuota(faYieldOrder.getPartCode(), item.getSubGoodsCode()); - item.setSingleUseQty(dsPartRelation.getQuota()); + int maxCanMakeSet = (int) Math.floor(totalNeedSetInt); + for (DsPartEntity sub : allChildPartList) { + String subCode = sub.getPartCode(); + DsPartRelationEntity dsPartRelation = stGlassCakeOutMapper.getPartQuota(faYieldOrder.getPartCode(), subCode); + double singleUse = dsPartRelation.getQuota(); + // 查询该子件所有可用库存 - List stockAll = stRealtimeStockMapper.selectMaxUsableStockByMoldAttr(item.getSubGoodsCode()); - item.setStockList(stockAll); - // 实时剩余可用总库存(动态变化,逐套消耗) - double usableTotal = 0D; - if (CollUtil.isNotEmpty(stockAll)) { - usableTotal = stockAll.stream() - .mapToDouble(s -> s.getQuantity() - Optional.ofNullable(s.getOccupyQuantity()).orElse(0D)) - .sum(); + List stockList = stRealtimeStockMapper.selectMaxUsableStockByMoldAttr(subCode); + if (stockList == null || stockList.isEmpty()) { + maxCanMakeSet = 0; + break; } - item.setRemainUsable(usableTotal); - sourceSubStockList.add(item); - } - - // 存放最终要生成的出库明细、占用、锁库数据 - List needOccupyList = new ArrayList<>(); - // 成功齐套的套数 - int successSet = 0; - - // 2、逐套循环校验,能齐一套算一套 - for (; successSet < totalNeedSetInt; ) { - boolean oneSetAllOk = true; - // 本套需要占用的临时数据 - List tempOccupy = new ArrayList<>(); - - for (SubItemStockDTO sub : sourceSubStockList) { - double needPerSet = sub.getSingleUseQty(); - // 当前子件剩余可用不足单套用量 → 本套不齐套,跳出 - if (sub.getRemainUsable() < needPerSet - 0.001) { - oneSetAllOk = false; - break; - } - // 从子件库存里扣对应数量,优先耗前面批次库存 - double surplusNeed = needPerSet; - List stockList = sub.getStockList(); - for (StRealtimeStock stock : stockList) { - if (surplusNeed <= 0.001) break; - double occ = Optional.ofNullable(stock.getOccupyQuantity()).orElse(0D); - double usable = stock.getQuantity() - occ; - if (usable <= 0) continue; - - double takeQty = Math.min(usable, surplusNeed); - // 暂存本次占用信息,齐套成功才真正落库 - StockOccupyTempDTO temp = new StockOccupyTempDTO(); - temp.setStock(stock); - temp.setTakeQty(takeQty); - temp.setSubGoodsCode(sub.getSubGoodsCode()); - tempOccupy.add(temp); - - surplusNeed -= takeQty; - } - // 子件总可用扣减本套耗用 - sub.setRemainUsable(sub.getRemainUsable() - needPerSet); - } + // 总可用库存 + double totalUsable = stockList.stream() + .mapToDouble(s -> s.getQuantity() - Optional.ofNullable(s.getOccupyQuantity()).orElse(0D)) + .filter(v -> v > 0) + .sum(); - if (oneSetAllOk) { - // 本套齐套,临时占用转正,加入最终列表 - needOccupyList.addAll(tempOccupy); - successSet++; - } else { - // 任意子件不齐套,终止整套循环,不再尝试后续套数 - break; - } + // 当前子件最多可做套数 + int subCanMake = (int) Math.floor(totalUsable / singleUse); + maxCanMakeSet = Math.min(maxCanMakeSet, subCanMake); } - if (CollUtil.isEmpty(needOccupyList)) { - log.info("父件{}无任何可齐套库存,需求{}套,生成0套预出库", partOne.getPartCode(), totalNeedSet); + // 无可齐套套数,直接返回 + if (maxCanMakeSet <= 0) { + log.info("父件【{}】无可用齐套库存,需求{}套,生成0套预出库", faYieldOrder.getPartCode(), totalNeedSetInt); return Collections.emptyList(); } + log.info("父件【{}】最终可齐套套数:{} 套", faYieldOrder.getPartCode(), maxCanMakeSet); List preOutStockList = new ArrayList<>(); @@ -195,59 +145,77 @@ public class StGraphiteMoldOutServiceImpl extends BaseServiceImpl stockList = stRealtimeStockMapper.selectMaxUsableStockByMoldAttr(subCode); + double remainNeed = totalNeed; + + // 遍历库存,一个不够用下一个,自动生成多条出库 + for (StRealtimeStock maxStock : stockList) { + if (remainNeed <= 0.001) { + break; + } + + double occupyQty = Optional.ofNullable(maxStock.getOccupyQuantity()).orElse(0D); + double usableQty = maxStock.getQuantity() - occupyQty; + if (usableQty <= 0) { + continue; + } + + // 本次实际扣减数量 + double actualTake = Math.min(usableQty, remainNeed); + StGraphiteMoldOut preOutStock = new StGraphiteMoldOut(); + preOutStock.setYoCode(faYieldOrder.getYoCode()); + preOutStock.setCardNo(dto.getCardNo()); + + String parentOutCode = datePrefix + StrUtil.padPre(String.valueOf(lastNum), 4, '0'); + preOutStock.setParentOutCode(parentOutCode); + String outCode = parentOutCode + "-" + childNum; + preOutStock.setOutCode(outCode); + childNum++; // preOutStock.setOutCode(stStockInoutRecordService.generateCode()); - SubItemStockDTO currSub = sourceSubStockList.stream() - .filter(s -> s.getSubGoodsCode().equals(temp.getSubGoodsCode())) - .findFirst().get(); - preOutStock.setNeedQuantity(currSub.getSingleUseQty() * totalNeedSet); - preOutStock.setCompleteQuantity(takeQty); - preOutStock.setGoodsId(maxStock.getGoodsId()); - StGoods stGoods = stGoodsService.getById(maxStock.getGoodsId()); - preOutStock.setGoodsName(stGoods.getGoodsName()); - preOutStock.setGoodsCode(stGoods.getGoodsCode()); - preOutStock.setSlId(maxStock.getSlId()); - StStorageLocation location = stStorageLocationService.getById(maxStock.getSlId()); - preOutStock.setLocation(location.getLocation()); - preOutStock.setShId(maxStock.getShId()); - StStorehouse storehouse = stStorehouseService.getById(maxStock.getShId()); - preOutStock.setShName(storehouse.getShName()); - preOutStock.setRlsId(maxStock.getId()); - preOutStock.setPiNo(maxStock.getPiNo()); - - preOutStock.setCurStatus(0L); - preOutStock.setCreateTime(now); - preOutStock.setUpdateTime(now); - - preOutStockList.add(preOutStock); - System.out.println("石墨模子件[编码:" + preOutStock.getGoodsCode() + "]库存充足,已构建预出库信息,库存ID:" + maxStock.getId()); - - // 更新实时库存占用数量 - double oldOccupy = Optional.ofNullable(maxStock.getOccupyQuantity()).orElse(0D); - maxStock.setOccupyQuantity(oldOccupy + takeQty); - stRealtimeStockService.updateById(maxStock); - - StRealtimeStockLock lock = new StRealtimeStockLock(); - lock.setId(IdUtil.getSnowflake().nextId()); - lock.setRlsId(maxStock.getId()); - lock.setWoNo(preOutStock.getCardNo()); - lock.setOccupyQuantity(takeQty); - lock.setStatus(0); - stRealtimeStockMapper.insertStockLock(lock); + preOutStock.setNeedQuantity(singleUse * totalNeedSet); + preOutStock.setCompleteQuantity(totalNeed); + preOutStock.setGoodsId(maxStock.getGoodsId()); + StGoods stGoods = stGoodsService.getById(maxStock.getGoodsId()); + preOutStock.setGoodsName(stGoods.getGoodsName()); + preOutStock.setGoodsCode(stGoods.getGoodsCode()); + preOutStock.setSlId(maxStock.getSlId()); + StStorageLocation location = stStorageLocationService.getById(maxStock.getSlId()); + preOutStock.setLocation(location.getLocation()); + preOutStock.setShId(maxStock.getShId()); + StStorehouse storehouse = stStorehouseService.getById(maxStock.getShId()); + preOutStock.setShName(storehouse.getShName()); + preOutStock.setRlsId(maxStock.getId()); + preOutStock.setPiNo(maxStock.getPiNo()); + + preOutStock.setCurStatus(0L); + preOutStock.setCreateTime(now); + preOutStock.setUpdateTime(now); + + preOutStockList.add(preOutStock); + System.out.println("石墨模子件[编码:" + preOutStock.getGoodsCode() + "]库存充足,已构建预出库信息,库存ID:" + maxStock.getId()); + + // 更新实时库存占用数量 + maxStock.setOccupyQuantity(occupyQty + actualTake); + stRealtimeStockService.updateById(maxStock); + + StRealtimeStockLock lock = new StRealtimeStockLock(); + lock.setId(IdUtil.getSnowflake().nextId()); + lock.setRlsId(maxStock.getId()); + lock.setWoNo(preOutStock.getCardNo()); + lock.setOccupyQuantity(actualTake); + lock.setStatus(0); + stRealtimeStockMapper.insertStockLock(lock); + + remainNeed -= actualTake; + } } System.out.println("石墨模子件预出库全部完成!");