diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoCallAirShaftTask.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoCallAirShaftTask.java index a0e632f91..cc58db2d7 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoCallAirShaftTask.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/auto/AutoCallAirShaftTask.java @@ -43,6 +43,7 @@ import org.nl.system.service.notice.ISysNoticeService; import org.nl.system.service.param.ISysParamService; import org.nl.system.service.param.dao.Param; import org.nl.wms.ext.acs.service.WmsToAcsService; +import org.nl.wms.pdm.ivt.deliverycache.service.IDeliverycachepointivtService; import org.nl.wms.sch.manage.TaskStatusEnum; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; @@ -103,12 +104,16 @@ public class AutoCallAirShaftTask extends Prun { private RedisUtils redisUtils; @Autowired private IMdPbPapervehicleService papervehicleService; + @Autowired + private IDeliverycachepointivtService iDeliverycachepointivtService; public final static String PARAM_CODE_PLAN_AREA = "PARAM_CODE_PLAN_AREA"; public final static String IS_ONLY_PULLING = "IS_ONLY_PULLING"; public final static String TZ_DAY = "TZ_DAY"; public final static String USE_XN = "USE_XN"; public final static String BZ_CHECK_EMPTY = "BZ_CHECK_EMPTY"; + /** 合单配送 */ + public final static String IS_COMBINED_ORDER = "IS_COMBINED_ORDER"; public List stepErrorInfo = new ArrayList<>(); @Autowired private RedissonClient redissonClient; @@ -1244,6 +1249,19 @@ public class AutoCallAirShaftTask extends Prun { } List stringList = cuts2.stream().map(BstIvtCutpointivt::getPoint_code).collect(Collectors.toList()); stepErrorInfo.add("设备" + dto.getResource_name() + "检测到暂存架" + stringList + "有套好的管芯,不会进行套轴。"); + + // 检测是否存在气胀轴缓存架子上 + Param codParam = paramService.findByCode(IS_COMBINED_ORDER); + + // 不允许拼单(不拼单代表不使用拼单逻辑,无需检测) + if (ObjectUtil.isEmpty(codParam) || !"1".equals(codParam.getValue())) { + return true; + } + // 检测 todo: 可以优化考虑任务,但似乎没太大作用 + Integer num = iDeliverycachepointivtService.countPendingUseByDevice(dto.getResource_name()); + if (num == 0) { + return true; + } } log.info("检查有同母卷不允许套轴:{}", dto); // 有就返回true diff --git a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/service/impl/SlitterServiceImpl.java b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/service/impl/SlitterServiceImpl.java index 7c09f2cd8..f607d8046 100644 --- a/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/service/impl/SlitterServiceImpl.java +++ b/lms/nladmin-system/src/main/java/org/nl/b_lms/sch/tasks/slitter/service/impl/SlitterServiceImpl.java @@ -64,6 +64,8 @@ import org.redisson.api.RedissonClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import java.math.BigDecimal; import java.util.ArrayList; @@ -370,6 +372,13 @@ public class SlitterServiceImpl implements SlitterService { /** * 拼单规则:双轴不拼,单轴拼,同区域拼 + * validateAndGetPlans() - 验证并获取分切计划 + * handleExceptionCase() - 处理异常情况 + * updatePlanWeights() - 更新分切计划重量 + * generateQzzNo() - 生成气胀轴编码 + * completeShaftLoading() - 完成套轴 + * tryCombineOrder() - 尝试拼单逻辑 + * handleNormalProcess() - 处理正常业务流程 * @param param * @return */ @@ -377,286 +386,86 @@ public class SlitterServiceImpl implements SlitterService { @Override @Transactional(rollbackFor = Exception.class) public JSONObject acsFinishLoadShaft(JSONObject param) { - String msg = ""; - JSONObject res = new JSONObject(); - // 穿拔轴位 String deviceCode = param.getString("device_code"); List stepTipLogs = getRedisListValue("ERROR" + deviceCode); - // 枷锁 + RLock lock = redissonClient.getLock("doAcsFinishLoadShaft"); boolean tryLock = lock.tryLock(10, TimeUnit.SECONDS); + try { - if (tryLock) { - log.info("ACS申请套管完成参数: {}", param); - // 纸管 - BigDecimal weight1 = param.getBigDecimal("weight1"); - String material1 = param.getString("material1"); - BigDecimal weight2 = param.getBigDecimal("weight2"); - String material2 = param.getString("material2"); - BstIvtShafttubeivt startPoint = shafttubeivtService.getOne(new LambdaQueryWrapper() - .eq(BstIvtShafttubeivt::getPoint_code, deviceCode)); - // 获取分切计划 - List collect = Stream.of(startPoint.getContainer_name1(), startPoint.getContainer_name2()) - .filter(value -> value != null && !value.isEmpty()).collect(Collectors.toList()); - if (collect.size() == 0) { - log.error("找不到[{}]对应的分切计划!", deviceCode); - stepTipLogs.add("套轴完成->找不到[" + deviceCode + "]点位记录的分切计划!分切计划可能被删除或者拼接!"); - redisUtils.set("ERROR" + deviceCode, stepTipLogs); - throw new BadRequestException("找不到[" + deviceCode + "]对应的分切计划!"); - } - List plans = slittingproductionplanService.list( - new LambdaQueryWrapper() - .in(PdmBiSlittingproductionplan::getContainer_name, collect) - .eq(PdmBiSlittingproductionplan::getStatus, "01") - .eq(PdmBiSlittingproductionplan::getIs_delete, "0")); - // 判断是否有未完成的任务 - List list = taskService.list(new LambdaQueryWrapper() - .eq(SchBaseTask::getPoint_code1, deviceCode) - .like(SchBaseTask::getRequest_param, collect.get(0)) - .lt(SchBaseTask::getTask_status, "07")); - if (list.size() > 0) { - log.error("点位[{}]存在未完成得任务!", deviceCode); - stepTipLogs.add("套轴完成->点位[" + deviceCode + "]存在未完成得任务!"); - redisUtils.set("ERROR" + deviceCode, stepTipLogs); - throw new BadRequestException("点位[" + deviceCode + "]存在未完成得任务!"); - } - // 去异常位 - if (plans.size() == 0) { - log.error("找不到[{}]对应的分切计划,分切计划可能被删除或者拼接!", collect); - // 移动到异常处理位(随机一个点位,在送到B2对面的位置) - List exceptionPointCodes = bcutpointivtService.getCanUseMinPointByShelf("4", "0"); - if (exceptionPointCodes.size() > 0) { - String exceptionPoint = exceptionPointCodes.get(0); - JSONObject exParam = new JSONObject(); - exParam.put("point_code1", startPoint.getPoint_code()); - exParam.put("point_code2", exceptionPoint); - if (exceptionPoint.endsWith("A")) { - exParam.put("vehicle_code1", collect); - } else { - exParam.put("vehicle_code2", collect); - } - exParam.put("task_type", SlitterEnum.TASK_TYPE.code("套轴异常处理桁架任务")); - exParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); - exParam.put("acs_task_type", "6"); - exParam.put("containers", collect); - exParam.put("qzz_size", startPoint.getQzz_size()); - sendNBJExceptionPointTask.createTask(exParam); - res.put("status", HttpStatus.HTTP_OK); - res.put("message", "创建送至异常处理位!"); - return res; - } - - // 半条任务等待补齐 - stepTipLogs.add("套轴完成->[" + collect + "]对应的分切计划状态已更改,无暂存位置,创建任务失败!"); - redisUtils.set("ERROR" + deviceCode, stepTipLogs); - JSONObject exParam = new JSONObject(); - exParam.put("point_code1", startPoint.getPoint_code()); - exParam.put("point_code2", "-"); - exParam.put("vehicle_code1", collect); - exParam.put("task_type", SlitterEnum.TASK_TYPE.code("套轴异常处理桁架任务")); - exParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); - exParam.put("task_status", TaskStatusEnum.SURE_START.getCode()); - exParam.put("acs_task_type", "6"); - exParam.put("containers", collect); - exParam.put("qzz_size", startPoint.getQzz_size()); - sendNBJExceptionPointTask.createTask(exParam); - res.put("status", HttpStatus.HTTP_OK); - res.put("message", "请求成功"); - res.put("msg", msg); - return res; - } - // 分切计划设置纸卷重量 - for (PdmBiSlittingproductionplan plan : plans) { - if (SlitterConstant.SLITTER_SUB_VOLUME_LEFT.equals(plan.getLeft_or_right())) { - plan.setPaper_weight(String.valueOf(NumberUtil.round(weight1, 2))); - msg = msg + "子卷号:" + plan.getContainer_name() + "的纸管重量: " + weight1 + " | "; - } else { - plan.setPaper_weight(String.valueOf(NumberUtil.round(weight2, 2))); - msg = msg + "子卷号:" + plan.getContainer_name() + "的纸管重量: " + weight2 + " | "; - } - TaskUtils.updateOptMessageBySlitterPlan(plan); - } - slittingproductionplanService.updateBatchById(plans); - - // 当前套轴的分切计划 - PdmBiSlittingproductionplan demoPlan = plans.get(0); - // 分切计划设置套轴完成 - String resourceName = demoPlan.getResource_name(); - String qzzNo = resourceName.substring(0, 2) - + resourceName.substring(resourceName.length() - 2) - + demoPlan.getSplit_group() - + TaskUtils.getDateTime("yyMMddHHmmss") + "-" - + demoPlan.getUp_or_down(); - plans.forEach(plan -> { - plan.setIs_child_tz_ok(SlitterConstant.SLITTER_YES); - plan.setQzzno(qzzNo); - TaskUtils.updateOptMessageBySlitterPlan(plan); - }); - slittingproductionplanService.updateBatchById(plans); - // 搬运的点 - BstIvtCutpointivt cutPoint; - //============================= 拼单业务 ============================== - // 标记是否是通过拼单的 - String flag = "0"; - // 标记气胀轴编码是存到任务的载具号1还是2 - String vehicleLocation = "1"; - // 指定点位 - String specialPoint = ""; - // 合单开关 - Param codParam = paramService.findByCode(IS_COMBINED_ORDER); - // 总判断是否有同组(判断自己能不能拼单) - Integer sameNumber = slittingproductionplanService.getSameTripParentContainerPlanCount(demoPlan); - // 允许拼单 - if (sameNumber == 0 && ObjectUtil.isNotEmpty(codParam) && "1".equals(codParam.getValue())) { - StIvtCutpointivt deviceInfo = cutpointivtService.getPintByExtCode(resourceName, false); - List emptyNotTaskPoint; - // 查找能够拼单(没任务)的点位 - emptyNotTaskPoint = slitterMapper.getCombinedOrders(CombinedOrderDto - .builder() - .pointStatus("2") - .pointType("1") - .pointLocation(deviceInfo.getPoint_location()) - .plan(deviceInfo.getPlan()) - .device(resourceName).build()); - flag = "1"; - // 如果为空,看看路上的那根轴能不能拼单 - if (emptyNotTaskPoint.size() == 0) { - SchBaseTask runningTask = taskService.getOne(new LambdaQueryWrapper() - .eq(SchBaseTask::getHandle_class, "org.nl.b_lms.sch.tasks.slitter.TrussSendAirShaftTask") - .lt(SchBaseTask::getTask_status, "07") - .eq(SchBaseTask::getIs_delete, "0") - .ne(SchBaseTask::getPoint_code1, deviceCode)); - if (ObjectUtil.isNotEmpty(runningTask) && ObjectUtil.isNotEmpty(runningTask.getPoint_code2())) { - List runningShafts = slittingproductionplanService.getByQzzNos(Arrays.asList(runningTask.getVehicle_code(), runningTask.getVehicle_code2())); - if (runningShafts.size() > 0) { - PdmBiSlittingproductionplan runningShaft = runningShafts.get(0); - // 判断有没有同组同母卷同设备不同轴的卷号,没有则判断和当前计划是不是允许拼单的 - Integer otherPlans = - slittingproductionplanService.getSameTripParentContainerPlanCount(runningShaft); - if (otherPlans == 0) { - StIvtCutpointivt runDeviceInfo = cutpointivtService.getPintByExtCode(runningShaft.getResource_name(), false); - // 判断对应设备与当前计划设是否能够拼在一起 - if (runDeviceInfo.getPlan().equals(deviceInfo.getPlan())) { - // 可以拼单 - BstIvtCutpointivt one = bcutpointivtService.getOne(new LambdaQueryWrapper() - .eq(BstIvtCutpointivt::getTruss_point_code1, runningTask.getPoint_code2()).or() - .eq(BstIvtCutpointivt::getTruss_point_code2, runningTask.getPoint_code2())); - // 判断目标点是否为空 - specialPoint = one.getTruss_point_code1().equals(runningTask.getPoint_code2()) - ? one.getTruss_point_code2() : one.getTruss_point_code1(); - vehicleLocation = one.getTruss_point_code1().equals(runningTask.getPoint_code2()) - ? "2" : "1"; - if ((specialPoint.equals(one.getTruss_point_code1()) - && ObjectUtil.isNotEmpty(one.getQzz_no1())) - || (specialPoint.equals(one.getTruss_point_code2()) - && ObjectUtil.isNotEmpty(one.getQzz_no2()))) { - emptyNotTaskPoint.add(one); - flag = "2"; - } - } - } - } - } - } - if (emptyNotTaskPoint.size() > 0) { - cutPoint = emptyNotTaskPoint.get(0); - // 创建任务 - JSONObject taskParam = new JSONObject(); - taskParam.put("point_code1", startPoint.getPoint_code()); - taskParam.put("point_code2", - "2".equals(flag) ? specialPoint - : "1".equals(flag) ? ObjectUtil.isEmpty(cutPoint.getQzz_no1()) - ? cutPoint.getTruss_point_code1() : cutPoint.getTruss_point_code2() - : SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) - ? cutPoint.getTruss_point_code1() : cutPoint.getTruss_point_code2()); - taskParam.put("vehicle_code1", - "2".equals(flag) ? "1".equals(vehicleLocation) ? qzzNo : "" - : "1".equals(flag) ? ObjectUtil.isEmpty(cutPoint.getQzz_no1()) - ? qzzNo : "" - : SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("vehicle_code2", - "2".equals(flag) ? "2".equals(vehicleLocation) ? qzzNo : "" - : "1".equals(flag) ? ObjectUtil.isEmpty(cutPoint.getQzz_no2()) - ? qzzNo : "" - : SlitterConstant.SLITTER_SHAFT_DOWN.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("task_type", "010814"); - taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); - taskParam.put("immediateNotifyAcs", "1"); - trussSendAirShaftTask.createTask(taskParam); - res.put("status", HttpStatus.HTTP_OK); - res.put("message", "请求成功"); - res.put("msg", msg); - return res; - } - } - flag = "0"; - //============================= 不进行拼单的正常业务 ============================== - // 查找是否有同组的气胀轴位置 - cutPoint = slitterMapper.getSameGroupPoint(demoPlan); - if (ObjectUtil.isEmpty(cutPoint)) { - // 也有可能在路上, 获取任务的终点 - String endPoint = slitterMapper.getSameGroupTaskPoint(demoPlan); - if (ObjectUtil.isNotEmpty(endPoint)) { - cutPoint = bcutpointivtService.getOne(new LambdaQueryWrapper() - .eq(BstIvtCutpointivt::getTruss_point_code1, endPoint).or() - .eq(BstIvtCutpointivt::getTruss_point_code2, endPoint)); - } - } - if (ObjectUtil.isEmpty(cutPoint)) { - // 获取一个空位 (上下区域) - List emptyNotTaskPoint = bcutpointivtService.getNBJAreaNotTaskPointByStatus( - "1", "1", startPoint.getPoint_location(), "1"); - if (emptyNotTaskPoint.size() > 0) { - cutPoint = emptyNotTaskPoint.get(0); - } else { - stepTipLogs.add("提示:套轴完成->找不到可用套轴对接位,创建半条任务,等待AGV取货完成触发!"); - redisUtils.set("ERROR" + deviceCode, stepTipLogs); - // 创建任务 - JSONObject taskParam = new JSONObject(); - taskParam.put("point_code1", startPoint.getPoint_code()); - taskParam.put("point_code2", "-"); - taskParam.put("needPosition", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) - ? "A" : "B"); - taskParam.put("vehicle_code1", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("vehicle_code2", SlitterConstant.SLITTER_SHAFT_DOWN.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("task_type", "010814"); - taskParam.put("containers", collect); - taskParam.put("qzz_size", demoPlan.getQzz_size()); - taskParam.put("task_status", TaskStatusEnum.SURE_START.getCode()); - taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); - taskParam.put("immediateNotifyAcs", "0"); - trussSendAirShaftTask.createTask(taskParam); - } - } - if (ObjectUtil.isNotEmpty(cutPoint)) { - // 创建任务 - JSONObject taskParam = new JSONObject(); - taskParam.put("point_code1", startPoint.getPoint_code()); - taskParam.put("point_code2", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) - ? cutPoint.getTruss_point_code1() : cutPoint.getTruss_point_code2()); - taskParam.put("vehicle_code1", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("vehicle_code2", SlitterConstant.SLITTER_SHAFT_DOWN.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); - taskParam.put("task_type", "010814"); - taskParam.put("containers", collect); - taskParam.put("qzz_size", demoPlan.getQzz_size()); - taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); - taskParam.put("immediateNotifyAcs", "1"); - trussSendAirShaftTask.createTask(taskParam); - } - } else { + if (!tryLock) { stepTipLogs.add("套轴完成->系统繁忙,稍后在试!"); redisUtils.set("ERROR" + deviceCode, stepTipLogs); throw new BadRequestException("系统繁忙,稍后在试!"); } + + log.info("ACS申请套管完成参数: {}", param); + + // 1. 获取起点和分切计划 + BstIvtShafttubeivt startPoint = shafttubeivtService.getOne( + new LambdaQueryWrapper() + .eq(BstIvtShafttubeivt::getPoint_code, deviceCode)); + + List plans = validateAndGetPlans(deviceCode, startPoint, stepTipLogs); + + // 2. 处理异常情况 - 分切计划不存在 + if (plans.isEmpty()) { + List containerNames = Stream.of(startPoint.getContainer_name1(), startPoint.getContainer_name2()) + .filter(ObjectUtil::isNotEmpty) + .collect(Collectors.toList()); + return handleExceptionCase(deviceCode, startPoint, containerNames, stepTipLogs); + } + + // 3. 更新分切计划重量 + BigDecimal weight1 = param.getBigDecimal("weight1"); + BigDecimal weight2 = param.getBigDecimal("weight2"); + String msg = updatePlanWeights(plans, weight1, weight2); + + // 4. 生成气胀轴编码并完成套轴 + PdmBiSlittingproductionplan demoPlan = plans.get(0); + String qzzNo = generateQzzNo(demoPlan); + completeShaftLoading(plans, qzzNo); + + // 5. 获取子卷名称列表 + List containerNames = Stream.of(startPoint.getContainer_name1(), startPoint.getContainer_name2()) + .filter(ObjectUtil::isNotEmpty) + .collect(Collectors.toList()); + + // 6. 尝试拼单 + BstIvtCutpointivt combinedPoint = tryCombineOrder(demoPlan, deviceCode, startPoint, qzzNo); + if (combinedPoint == null) { + // 7. 正常业务流程(不拼单) + handleNormalProcess(demoPlan, startPoint, qzzNo, containerNames, deviceCode, stepTipLogs); + } + JSONObject res = new JSONObject(); + res.put("status", HttpStatus.HTTP_OK); + res.put("message", "请求成功"); + res.put("msg", msg); + return res; + } finally { if (tryLock) { - lock.unlock(); + // 使用 TransactionSynchronization 在事务提交后释放锁 + // 避免锁释放但事务未提交导致的并发问题 + if (TransactionSynchronizationManager.isSynchronizationActive()) { + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCompletion(int status) { + try { + lock.unlock(); + log.debug("分布式锁已在事务完成后释放: doAcsFinishLoadShaft, 事务状态: {}", + status == STATUS_COMMITTED ? "已提交" : "已回滚"); + } catch (Exception e) { + log.error("释放分布式锁失败", e); + } + } + }); + } else { + // 如果没有事务,直接释放锁 + lock.unlock(); + } } } - res.put("status", HttpStatus.HTTP_OK); - res.put("message", "请求成功"); - res.put("msg", msg); - return res; } @SneakyThrows @@ -3506,4 +3315,377 @@ public class SlitterServiceImpl implements SlitterService { } return stepTipLogs; } + + /** + * 验证并获取分切计划 + */ + private List validateAndGetPlans(String deviceCode, BstIvtShafttubeivt startPoint, List stepTipLogs) { + List containerNames = Stream.of(startPoint.getContainer_name1(), startPoint.getContainer_name2()) + .filter(value -> value != null && !value.isEmpty()) + .collect(Collectors.toList()); + + if (containerNames.isEmpty()) { + log.error("找不到[{}]对应的分切计划!", deviceCode); + stepTipLogs.add("套轴完成->找不到[" + deviceCode + "]点位记录的分切计划!分切计划可能被删除或者拼接!"); + redisUtils.set("ERROR" + deviceCode, stepTipLogs); + throw new BadRequestException("找不到[" + deviceCode + "]对应的分切计划!"); + } + + // 判断是否有未完成的任务 + List existingTasks = taskService.list(new LambdaQueryWrapper() + .eq(SchBaseTask::getPoint_code1, deviceCode) + .like(SchBaseTask::getRequest_param, containerNames.get(0)) + .lt(SchBaseTask::getTask_status, "07")); + + if (!existingTasks.isEmpty()) { + log.error("点位[{}]存在未完成得任务!", deviceCode); + stepTipLogs.add("套轴完成->点位[" + deviceCode + "]存在未完成得任务!"); + redisUtils.set("ERROR" + deviceCode, stepTipLogs); + throw new BadRequestException("点位[" + deviceCode + "]存在未完成得任务!"); + } + + return slittingproductionplanService.list( + new LambdaQueryWrapper() + .in(PdmBiSlittingproductionplan::getContainer_name, containerNames) + .eq(PdmBiSlittingproductionplan::getStatus, "01") + .eq(PdmBiSlittingproductionplan::getIs_delete, "0")); + } + + /** + * 处理异常情况 - 分切计划不存在 + */ + private JSONObject handleExceptionCase(String deviceCode, BstIvtShafttubeivt startPoint, + List containerNames, List stepTipLogs) { + log.error("找不到[{}]对应的分切计划,分切计划可能被删除或者拼接!", containerNames); + + // 尝试移动到异常处理位 + List exceptionPointCodes = bcutpointivtService.getCanUseMinPointByShelf("4", "0"); + if (!exceptionPointCodes.isEmpty()) { + String exceptionPoint = exceptionPointCodes.get(0); + JSONObject exParam = buildExceptionTaskParam(startPoint, exceptionPoint, containerNames); + sendNBJExceptionPointTask.createTask(exParam); + + JSONObject res = new JSONObject(); + res.put("status", HttpStatus.HTTP_OK); + res.put("message", "创建送至异常处理位!"); + return res; + } + + // 创建半条任务等待补齐 + stepTipLogs.add("套轴完成->[" + containerNames + "]对应的分切计划状态已更改,无暂存位置,创建任务失败!"); + redisUtils.set("ERROR" + deviceCode, stepTipLogs); + + JSONObject exParam = buildWaitingTaskParam(startPoint, containerNames); + sendNBJExceptionPointTask.createTask(exParam); + + JSONObject res = new JSONObject(); + res.put("status", HttpStatus.HTTP_OK); + res.put("message", "请求成功"); + return res; + } + + /** + * 构建异常任务参数 + */ + private JSONObject buildExceptionTaskParam(BstIvtShafttubeivt startPoint, String exceptionPoint, List containerNames) { + JSONObject exParam = new JSONObject(); + exParam.put("point_code1", startPoint.getPoint_code()); + exParam.put("point_code2", exceptionPoint); + + if (exceptionPoint.endsWith("A")) { + exParam.put("vehicle_code1", containerNames); + } else { + exParam.put("vehicle_code2", containerNames); + } + + exParam.put("task_type", SlitterEnum.TASK_TYPE.code("套轴异常处理桁架任务")); + exParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + exParam.put("acs_task_type", "6"); + exParam.put("containers", containerNames); + exParam.put("qzz_size", startPoint.getQzz_size()); + + return exParam; + } + + /** + * 构建等待任务参数 + */ + private JSONObject buildWaitingTaskParam(BstIvtShafttubeivt startPoint, List containerNames) { + JSONObject exParam = new JSONObject(); + exParam.put("point_code1", startPoint.getPoint_code()); + exParam.put("point_code2", "-"); + exParam.put("vehicle_code1", containerNames); + exParam.put("task_type", SlitterEnum.TASK_TYPE.code("套轴异常处理桁架任务")); + exParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + exParam.put("task_status", TaskStatusEnum.SURE_START.getCode()); + exParam.put("acs_task_type", "6"); + exParam.put("containers", containerNames); + exParam.put("qzz_size", startPoint.getQzz_size()); + + return exParam; + } + + /** + * 更新分切计划重量 + */ + private String updatePlanWeights(List plans, BigDecimal weight1, BigDecimal weight2) { + StringBuilder msg = new StringBuilder(); + + for (PdmBiSlittingproductionplan plan : plans) { + if (SlitterConstant.SLITTER_SUB_VOLUME_LEFT.equals(plan.getLeft_or_right())) { + plan.setPaper_weight(String.valueOf(NumberUtil.round(weight1, 2))); + msg.append("子卷号:").append(plan.getContainer_name()).append("的纸管重量: ").append(weight1).append(" | "); + } else { + plan.setPaper_weight(String.valueOf(NumberUtil.round(weight2, 2))); + msg.append("子卷号:").append(plan.getContainer_name()).append("的纸管重量: ").append(weight2).append(" | "); + } + TaskUtils.updateOptMessageBySlitterPlan(plan); + } + + slittingproductionplanService.updateBatchById(plans); + return msg.toString(); + } + + /** + * 生成气胀轴编码 + */ + private String generateQzzNo(PdmBiSlittingproductionplan demoPlan) { + String resourceName = demoPlan.getResource_name(); + return resourceName.substring(0, 2) + + resourceName.substring(resourceName.length() - 2) + + demoPlan.getSplit_group() + + TaskUtils.getDateTime("yyMMddHHmmss") + "-" + + demoPlan.getUp_or_down(); + } + + /** + * 完成套轴并更新计划 + */ + private void completeShaftLoading(List plans, String qzzNo) { + plans.forEach(plan -> { + plan.setIs_child_tz_ok(SlitterConstant.SLITTER_YES); + plan.setQzzno(qzzNo); + TaskUtils.updateOptMessageBySlitterPlan(plan); + }); + slittingproductionplanService.updateBatchById(plans); + } + + /** + * 尝试拼单逻辑 + */ + private BstIvtCutpointivt tryCombineOrder(PdmBiSlittingproductionplan demoPlan, String deviceCode, + BstIvtShafttubeivt startPoint, String qzzNo) { + Param codParam = paramService.findByCode(IS_COMBINED_ORDER); + // 判断是否有同组(判断自己能不能拼单) + Integer sameNumber = slittingproductionplanService.getSameTripParentContainerPlanCount(demoPlan); + + // 不允许拼单(未开启拼单逻辑) + if (sameNumber != 0 || ObjectUtil.isEmpty(codParam) || !"1".equals(codParam.getValue())) { + log.info("本身不允许拼单或者拼单配置未设置或者设置不拼单..."); + return null; + } + + String resourceName = demoPlan.getResource_name(); + StIvtCutpointivt deviceInfo = cutpointivtService.getPintByExtCode(resourceName, false); + + // 查找能够拼单的点位(查找套轴对接位) + List emptyNotTaskPoint = slitterMapper.getCombinedOrders( + CombinedOrderDto.builder() + .pointStatus("2") + .pointType("1") + .pointLocation(deviceInfo.getPoint_location()) + .plan(deviceInfo.getPlan()) + .device(resourceName) + .build()); + + // 如果没有空点位,尝试与路上的轴拼单 + if (emptyNotTaskPoint.isEmpty()) { + emptyNotTaskPoint = tryMatchRunningTask(demoPlan, deviceCode, deviceInfo); + } + + // 如果找到可拼单点位,创建任务 + if (!emptyNotTaskPoint.isEmpty()) { + BstIvtCutpointivt cutPoint = emptyNotTaskPoint.get(0); + createCombinedOrderTask(cutPoint, startPoint, demoPlan, qzzNo); + return cutPoint; + } + + return null; + } + + /** + * 尝试与运行中的任务拼单 + */ + private List tryMatchRunningTask(PdmBiSlittingproductionplan demoPlan, + String deviceCode, StIvtCutpointivt deviceInfo) { + List result = new ArrayList<>(); + + SchBaseTask runningTask = taskService.getOne(new LambdaQueryWrapper() + .eq(SchBaseTask::getHandle_class, "org.nl.b_lms.sch.tasks.slitter.TrussSendAirShaftTask") + .lt(SchBaseTask::getTask_status, "07") + .eq(SchBaseTask::getIs_delete, "0") + .ne(SchBaseTask::getPoint_code1, deviceCode)); + + if (ObjectUtil.isEmpty(runningTask) || ObjectUtil.isEmpty(runningTask.getPoint_code2())) { + return result; + } + + List runningShafts = slittingproductionplanService.getByQzzNos( + Arrays.asList(runningTask.getVehicle_code(), runningTask.getVehicle_code2())); + + if (runningShafts.isEmpty()) { + return result; + } + + PdmBiSlittingproductionplan runningShaft = runningShafts.get(0); + // 判断路上的轴能不能拼 + Integer otherPlans = slittingproductionplanService.getSameTripParentContainerPlanCount(runningShaft); + + if (otherPlans == 0) { + StIvtCutpointivt runDeviceInfo = cutpointivtService.getPintByExtCode(runningShaft.getResource_name(), false); + // 同个子区域 + if (runDeviceInfo.getPlan().equals(deviceInfo.getPlan())) { + BstIvtCutpointivt one = bcutpointivtService.getOne(new LambdaQueryWrapper() + .eq(BstIvtCutpointivt::getTruss_point_code1, runningTask.getPoint_code2()).or() + .eq(BstIvtCutpointivt::getTruss_point_code2, runningTask.getPoint_code2())); + + if (one != null && canCombineWithRunningTask(one, runningTask)) { + result.add(one); + } + } + } + + return result; + } + + /** + * 判断是否可以与运行中的任务拼单 + */ + private boolean canCombineWithRunningTask(BstIvtCutpointivt one, SchBaseTask runningTask) { + String specialPoint = one.getTruss_point_code1().equals(runningTask.getPoint_code2()) + ? one.getTruss_point_code2() : one.getTruss_point_code1(); + + return (specialPoint.equals(one.getTruss_point_code1()) && ObjectUtil.isNotEmpty(one.getQzz_no1())) + || (specialPoint.equals(one.getTruss_point_code2()) && ObjectUtil.isNotEmpty(one.getQzz_no2())); + } + + /** + * 创建拼单任务 + * @param cutPoint 分切点位 + * @param startPoint 穿拔轴点位 + * @param demoPlan 分切计划 + * @param qzzNo 气胀轴编码 + */ + private void createCombinedOrderTask(BstIvtCutpointivt cutPoint, BstIvtShafttubeivt startPoint, + PdmBiSlittingproductionplan demoPlan, String qzzNo) { + JSONObject taskParam = new JSONObject(); + taskParam.put("point_code1", startPoint.getPoint_code()); + + String pointCode2 = ObjectUtil.isEmpty(cutPoint.getQzz_no1()) + ? cutPoint.getTruss_point_code1() : cutPoint.getTruss_point_code2(); + taskParam.put("point_code2", pointCode2); + + String vehicleCode1 = ObjectUtil.isEmpty(cutPoint.getQzz_no1()) ? qzzNo : ""; + String vehicleCode2 = ObjectUtil.isEmpty(cutPoint.getQzz_no2()) ? qzzNo : ""; + taskParam.put("vehicle_code1", vehicleCode1); + taskParam.put("vehicle_code2", vehicleCode2); + taskParam.put("flag", "1"); + taskParam.put("task_type", "010814"); + taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + taskParam.put("immediateNotifyAcs", "1"); + + trussSendAirShaftTask.createTask(taskParam); + } + + /** + * 处理正常业务流程(不拼单) + */ + private void handleNormalProcess(PdmBiSlittingproductionplan demoPlan, BstIvtShafttubeivt startPoint, + String qzzNo, List containerNames, String deviceCode, + List stepTipLogs) { + // 查找是否有同组的气胀轴位置 + BstIvtCutpointivt cutPoint = findSameGroupPoint(demoPlan); + + if (ObjectUtil.isEmpty(cutPoint)) { + // 获取一个空位 + List emptyNotTaskPoint = bcutpointivtService.getNBJAreaNotTaskPointByStatus( + "1", "1", startPoint.getPoint_location(), "1"); + + if (!emptyNotTaskPoint.isEmpty()) { + cutPoint = emptyNotTaskPoint.get(0); + } else { + // 创建半条任务 + createHalfTask(startPoint, demoPlan, qzzNo, containerNames, deviceCode, stepTipLogs); + return; + } + } + + // 创建完整任务 + createNormalTask(cutPoint, startPoint, demoPlan, qzzNo, containerNames); + } + + /** + * 查找同组点位 + */ + private BstIvtCutpointivt findSameGroupPoint(PdmBiSlittingproductionplan demoPlan) { + BstIvtCutpointivt cutPoint = slitterMapper.getSameGroupPoint(demoPlan); + + if (ObjectUtil.isEmpty(cutPoint)) { + String endPoint = slitterMapper.getSameGroupTaskPoint(demoPlan); + if (ObjectUtil.isNotEmpty(endPoint)) { + cutPoint = bcutpointivtService.getOne(new LambdaQueryWrapper() + .eq(BstIvtCutpointivt::getTruss_point_code1, endPoint).or() + .eq(BstIvtCutpointivt::getTruss_point_code2, endPoint)); + } + } + + return cutPoint; + } + + /** + * 创建半条任务 + */ + private void createHalfTask(BstIvtShafttubeivt startPoint, PdmBiSlittingproductionplan demoPlan, + String qzzNo, List containerNames, String deviceCode, + List stepTipLogs) { + stepTipLogs.add("提示:套轴完成->找不到可用套轴对接位,创建半条任务,等待AGV取货完成触发!"); + redisUtils.set("ERROR" + deviceCode, stepTipLogs); + + JSONObject taskParam = new JSONObject(); + taskParam.put("point_code1", startPoint.getPoint_code()); + taskParam.put("point_code2", "-"); + taskParam.put("needPosition", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? "A" : "B"); + taskParam.put("vehicle_code1", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); + taskParam.put("vehicle_code2", SlitterConstant.SLITTER_SHAFT_DOWN.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); + taskParam.put("task_type", "010814"); + taskParam.put("containers", containerNames); + taskParam.put("qzz_size", demoPlan.getQzz_size()); + taskParam.put("task_status", TaskStatusEnum.SURE_START.getCode()); + taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + taskParam.put("immediateNotifyAcs", "0"); + + trussSendAirShaftTask.createTask(taskParam); + } + + /** + * 创建正常任务 + */ + private void createNormalTask(BstIvtCutpointivt cutPoint, BstIvtShafttubeivt startPoint, + PdmBiSlittingproductionplan demoPlan, String qzzNo, + List containerNames) { + JSONObject taskParam = new JSONObject(); + taskParam.put("point_code1", startPoint.getPoint_code()); + taskParam.put("point_code2", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) + ? cutPoint.getTruss_point_code1() : cutPoint.getTruss_point_code2()); + taskParam.put("vehicle_code1", SlitterConstant.SLITTER_SHAFT_UP.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); + taskParam.put("vehicle_code2", SlitterConstant.SLITTER_SHAFT_DOWN.equals(demoPlan.getUp_or_down()) ? qzzNo : ""); + taskParam.put("task_type", "010814"); + taskParam.put("containers", containerNames); + taskParam.put("flag", "0"); + taskParam.put("qzz_size", demoPlan.getQzz_size()); + taskParam.put("product_area", SlitterConstant.SLITTER_TASK_AREA); + taskParam.put("immediateNotifyAcs", "1"); + + trussSendAirShaftTask.createTask(taskParam); + } } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/IDeliverycachepointivtService.java b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/IDeliverycachepointivtService.java index 6087806f9..18bf92467 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/IDeliverycachepointivtService.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/IDeliverycachepointivtService.java @@ -84,4 +84,11 @@ public interface IDeliverycachepointivtService extends IService getMoreConformShaft(String gxCode1, String gcCode2, String area, String location); + + /** + * 获取待使用的点位 + * @param resourceName + * @return + */ + Integer countPendingUseByDevice(String resourceName); } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.java b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.java index 7c258b07a..8bdb277fe 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.java @@ -24,4 +24,6 @@ public interface DeliverycachepointivtMapper extends BaseMapper getMoreConformShaft(String gxCode1, String gcCode2, String area, String location); IPage selectPageLeftJoin(IPage pages, DeliverycachepointivtQuery param); + + Integer countPendingUseByDevice(String resourceName); } diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.xml b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.xml index 9d1301e1d..a620af4d8 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.xml +++ b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/dao/mapper/DeliverycachepointivtMapper.xml @@ -136,4 +136,16 @@ + diff --git a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/impl/DeliverycachepointivtServiceImpl.java b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/impl/DeliverycachepointivtServiceImpl.java index 5a3ece738..fdc7a04ce 100644 --- a/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/impl/DeliverycachepointivtServiceImpl.java +++ b/lms/nladmin-system/src/main/java/org/nl/wms/pdm/ivt/deliverycache/service/impl/DeliverycachepointivtServiceImpl.java @@ -116,4 +116,9 @@ public class DeliverycachepointivtServiceImpl extends ServiceImpl 1%", "last 2 versions" - ] + ], + "volta": { + "node": "14.21.3" + } }