From 9cb7b8bf4d4b56514744184d33ec8153311d13b4 Mon Sep 17 00:00:00 2001 From: "HUOJIN\\92525" Date: Fri, 30 Jan 2026 18:00:48 +0800 Subject: [PATCH] no message --- .../modules/agvTask/mapper/AgvTaskMapper.java | 13 ++- .../agvTask/mapper/xml/AgvTaskMapper.xml | 15 +++ .../service/processor/ScanTrayProcessor.java | 31 +++--- .../cpte/modules/quartz/job/TesAgvJob.java | 96 +++++++++++++++++-- .../cpte/modules/shipping/entity/Task.java | 8 ++ .../modules/shipping/mapper/TaskMapper.java | 4 +- .../shipping/mapper/xml/PickDetailMapper.xml | 2 +- .../shipping/service/ITaskService.java | 2 +- .../service/impl/TaskServiceImpl.java | 33 ++++--- .../service/processor/AllocateProcessor.java | 95 ++++++++++-------- .../modules/shipping/vo/InventoryScore.java | 3 + .../tesAgv/service/ITesAgvService.java | 2 +- .../service/impl/ITesAgvServiceImpl.java | 31 +++--- .../org/cpte/modules/utils/BatchUtil.java | 13 +-- 14 files changed, 240 insertions(+), 108 deletions(-) diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java index cf4329b..0b39adf 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/AgvTaskMapper.java @@ -50,7 +50,7 @@ public interface AgvTaskMapper extends BaseMapper { * @param status 状态 * @param agvVendor 供应商;AGV/TES */ - @Select(value = "select * from data_agv_task where status = #{status} and agv_vendor = #{agvVendor}") + @Select(value = "select * from data_agv_task where status = #{status} and agv_vendor = #{agvVendor} ORDER BY id ") List queryAgvTaskList(@Param("status") Integer status, @Param("agvVendor") String agvVendor); /** @@ -73,8 +73,10 @@ public interface AgvTaskMapper extends BaseMapper { */ List> pointTaskCountMap(); - - List queryIsExecuteAgvTask(); + /** + * 每个出库工作站当前任务(工作站,柜号-物料) + */ + List> pointTaskMap(); /** * 查询正在执行的AGV任务前5个 @@ -82,4 +84,9 @@ public interface AgvTaskMapper extends BaseMapper { @Select(value = "select * from data_agv_task where type in ('INBOUND','OUTBOUND') and status=2 LIMIT 5") List queryExecuteTopFive(); + /** + * 根据出库的起点找到对应需要移位的任务 + */ + @Select(value = "select * from data_agv_task where con_no = #{startCode} and type='MOVE' and status=1 and agv_vendor = 'TES' ") + List queryOutPointForMove(@Param("startCode") String startCode); } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/xml/AgvTaskMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/xml/AgvTaskMapper.xml index 9172557..f9ebb18 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/xml/AgvTaskMapper.xml +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/agvTask/mapper/xml/AgvTaskMapper.xml @@ -43,4 +43,19 @@ AND bp.iz_active=1 GROUP BY bp.point_code + + \ No newline at end of file diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/processor/ScanTrayProcessor.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/processor/ScanTrayProcessor.java index 57656b5..c5428d2 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/processor/ScanTrayProcessor.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/conveyorLine/service/processor/ScanTrayProcessor.java @@ -119,20 +119,6 @@ public class ScanTrayProcessor { agvTaskService.processAgvTask(data, dstPoint); } - /** - * 参数校验 - * - * @param scanTrayRequest 扫描参数 - */ - private void validateParams(ScanTrayRequest scanTrayRequest) { - if (StringUtils.isBlank(scanTrayRequest.getContent().getSignal().getBarCode())) { - throw new RuntimeException("托盘码不能为空"); - } - if (StringUtils.isBlank(scanTrayRequest.getContent().getStationCode())) { - throw new RuntimeException("工作站不能为空"); - } - } - /** * 数据准备 * @@ -709,6 +695,11 @@ public class ScanTrayProcessor { * @param movePoints 移库目标库位 */ public void buildMoveTask(List movePoints) { + if(CollectionUtils.isEmpty(movePoints)){ + return; + } + //定义去重集合,缓存已处理过的容器编码,避免单次调用内重复生成任务 + Set processedStock = new HashSet<>(); List moveList = new ArrayList<>(); //库存 @@ -734,10 +725,15 @@ public class ScanTrayProcessor { for (Inventory inv : moveInventoryList) { try { //如果移位库位已有出库任务则不需要生成移位任务 - Stock stock = stockMap.get(inv.getStockId()); - if (agvTaskMapper.existsByStockCode(stock.getStockCode(), AgvVendorEnum.TES.getValue()) != null) { + if (processedStock.contains(inv.getStockId())) { continue; } + Stock stock = stockMap.get(inv.getStockId()); + if (agvTaskMapper.existsByStockCode(stock.getStockCode(), AgvVendorEnum.TES.getValue()) != null) { + processedStock.add(inv.getStockId()); + continue; + } + Item moveItem = moveItemMap.get(inv.getItemId()); Point fromPoint = fromPointMap.get(inv.getPointId()); @@ -747,10 +743,11 @@ public class ScanTrayProcessor { String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO); //根据算法找到最优的目标库位 Point toPoint = allocatePoint(itemKeyList, fromPoint, areaCode, BusinessTypeEnum.MOVE.getValue()); - Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0); + Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0, null); moveList.add(moveTask); pointService.bindPoint(toPoint); inv.setStatus(InventoryStatusEnum.MOVE.getValue()); + processedStock.add(inv.getStockId()); log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity()); } catch (Exception e) { throw e; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java index dd6c19b..0a13f98 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/quartz/job/TesAgvJob.java @@ -1,12 +1,14 @@ package org.cpte.modules.quartz.job; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.cpte.modules.agvTask.entity.AgvTask; import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.constant.GeneralConstant; import org.cpte.modules.constant.enums.AgvStatusEnum; import org.cpte.modules.constant.enums.AgvVendorEnum; +import org.cpte.modules.constant.enums.BusinessTypeEnum; import org.cpte.modules.shipping.service.ITaskService; import org.cpte.modules.tesAgv.service.ITesAgvService; import org.cpte.modules.utils.RedisDistributedLockUtil; @@ -15,7 +17,9 @@ import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Slf4j public class TesAgvJob implements Job { @@ -33,7 +37,6 @@ public class TesAgvJob implements Job { private RedisDistributedLockUtil redissonLock; - @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { @@ -68,16 +71,93 @@ public class TesAgvJob implements Job { // 3.下发任务TES List agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue()); - if (agvTaskList.isEmpty()) { + if (CollectionUtils.isEmpty(agvTaskList)) { return; } - for (AgvTask agvTask : agvTaskList) { - tesAgvService.sendTesAgvTask( - GeneralConstant.TES_POD_TASK, - tesAgvService.generateTesAgvTaskJson(agvTask), - agvTask - ); + for (AgvTask agvTask : agvTaskList) { + if (BusinessTypeEnum.INBOUND.getValue().equals(agvTask.getType())) { + sendTesAgvTask(agvTask); + } else if (BusinessTypeEnum.OUTBOUND.getValue().equals(agvTask.getType())) { + Map pointTaskMap = queryPointTaskMap(); + boolean flag = sendOutTesAgvTask(agvTask, pointTaskMap); + } else if (BusinessTypeEnum.MOVE.getValue().equals(agvTask.getType())) { + //如果没有柜号说明是入库的移位 + if (StringUtils.isEmpty(agvTask.getConNo())) { + sendTesAgvTask(agvTask); + } + } } } + + /** + * 发送TES任务 + */ + private boolean sendTesAgvTask(AgvTask agvTask) { + return tesAgvService.sendTesAgvTask(GeneralConstant.TES_POD_TASK, tesAgvService.generateTesAgvTaskJson(agvTask), agvTask); + } + + /** + * 发送TES出库任务 + */ + private boolean sendOutTesAgvTask(AgvTask agvTask, Map pointTaskMap) { + + // 标记当前任务的key + String currKey = agvTask.getConNo() + "_" + agvTask.getItemId(); + + // 获取当前任务的目标工作站 + String targetEndCode = agvTask.getEndCode(); + + // 1. 检查目标工作站 + String executeKey = pointTaskMap.get(targetEndCode); + if (StringUtils.isEmpty(executeKey)) { + // 目标工作站空闲,直接下发 + return sendTaskToWorkstation(agvTask, targetEndCode, currKey, pointTaskMap); + } + + // 2. 目标工作站任务匹配 + if (currKey.equals(executeKey)) { + return sendTaskToWorkstation(agvTask, targetEndCode, currKey, pointTaskMap); + } + + return false; + } + + + /** + * 下发任务到指定工作站 + */ + private boolean sendTaskToWorkstation(AgvTask agvTask, String workstationCode, String taskKey, + Map pointTaskMap) { + boolean flag = sendTesAgvTask(agvTask); + if (flag) { + pointTaskMap.put(workstationCode, taskKey); + sendOutPointForMove(agvTask); + } + return flag; + } + + /** + * 当前出库任务有移位任务则下发移位任务 + */ + private void sendOutPointForMove(AgvTask currOutAgvTask) { + List agvTasks = agvTaskMapper.queryOutPointForMove(currOutAgvTask.getStartCode()); + if (CollectionUtils.isNotEmpty(agvTasks)) { + for (AgvTask agvTask : agvTasks) { + sendTesAgvTask(agvTask); + } + } + } + + private Map queryPointTaskMap() { + // 从数据库查询每个工作站当前的任务列表 + List> result = agvTaskMapper.pointTaskMap(); + Map pointTaskMap = new HashMap<>(); + for (Map map : result) { + String key = map.get("point_code").toString(); + String no_item = map.get("no_item") == null ? "" : map.get("no_item").toString(); + pointTaskMap.put(key, no_item); + } + return pointTaskMap; + } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Task.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Task.java index 03814ae..a55b243 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Task.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/entity/Task.java @@ -150,6 +150,14 @@ public class Task implements Serializable { @Excel(name = "是否整托", width = 15) @Schema(description = "是否整托") private java.lang.Integer izAll; + + /** + * 当前出库库位,移位时需要用到 + * + */ + @Schema(description = "当前出库库位") + private String currOutCode; + /** * 开始时间 */ diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/TaskMapper.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/TaskMapper.java index a581348..f67dd27 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/TaskMapper.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/TaskMapper.java @@ -21,7 +21,7 @@ public interface TaskMapper extends BaseMapper { * * @return List */ - @Select("SELECT * FROM data_task WHERE agv_task_id is null and to_point_id is not null order by create_time ") + @Select("SELECT * FROM data_task WHERE agv_task_id is null and to_point_id is not null order by id ") List queryUnIssuedTask(); @Select("SELECT * FROM data_task WHERE agv_task_id = #{agvTaskId} ") @@ -39,7 +39,7 @@ public interface TaskMapper extends BaseMapper { * * @return List */ - @Select("SELECT * FROM data_task WHERE agv_task_id is null and to_point_id is null") + @Select("SELECT * FROM data_task WHERE agv_task_id is null and to_point_id is null ORDER BY id") List queryUnallocatedTask(); /** diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml index ae93eeb..33210d6 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/mapper/xml/PickDetailMapper.xml @@ -32,6 +32,6 @@ JOIN data_pick_detail pd ON pd.pick_id=p.id WHERE p.`status` in (1,2,4) AND pd.order_qty-pd.allocated_qty>0 - ORDER BY p.order_date,pd.line_no + ORDER BY p.create_time,pd.create_time diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/ITaskService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/ITaskService.java index de1b375..74698a5 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/ITaskService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/ITaskService.java @@ -50,7 +50,7 @@ public interface ITaskService extends IService { * @param izAll 是否整托 * @return Task */ - Task bulidTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId,Long itemKeyId, Long inventoryId, BigDecimal planQty, Integer izAll); + Task bulidTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId,Long itemKeyId, Long inventoryId, BigDecimal planQty, Integer izAll,String currOutCode); /** * 根据Task集合生成AGV出库任务 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/TaskServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/TaskServiceImpl.java index 8749240..ceda14b 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/TaskServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/impl/TaskServiceImpl.java @@ -101,7 +101,7 @@ public class TaskServiceImpl extends ServiceImpl implements IT } @Override - public Task bulidTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId, Long itemKeyId, Long inventoryId, BigDecimal planQty, Integer izAll) { + public Task bulidTask(String taskNo, Integer taskType, Item item, Point fromPoint, Point toPoint, Stock stock, Long pickId, Long pickDetailId, Long itemKeyId, Long inventoryId, BigDecimal planQty, Integer izAll, String currOutCode) { LoginUser sysUser = null; try { sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); @@ -128,6 +128,7 @@ public class TaskServiceImpl extends ServiceImpl implements IT .taskStatus(1) .taskType(taskType) .izAll(izAll) + .currOutCode(currOutCode) .sysOrgCode(sysUser == null ? "A05" : sysUser.getOrgCode()) .tenantId(sysUser == null ? 1000L : Long.parseLong(sysUser.getRelTenantIds())) .createBy(sysUser == null ? "system" : sysUser.getUsername()) @@ -154,14 +155,19 @@ public class TaskServiceImpl extends ServiceImpl implements IT Map> taskGroupMap = taskList.stream() .sorted(Comparator.comparing(Task::getCreateTime)) .collect(Collectors.groupingBy(task -> TaskGroupKey.of( - task.getStockCode(), - task.getFromPointCode(), - task.getToPointCode() - ))); + task.getStockCode(), + task.getFromPointCode(), + task.getToPointCode() + ), + LinkedHashMap::new, + Collectors.toList() + ) + ); //3.批量创建AGV任务 List createToAgvTaskList = new ArrayList<>(); - Map groupToAgvTaskMap = new HashMap<>(); + Map groupToAgvTaskMap = new LinkedHashMap<>(); + for (Map.Entry> entry : taskGroupMap.entrySet()) { TaskGroupKey key = entry.getKey(); List tasks = entry.getValue(); @@ -173,7 +179,8 @@ public class TaskServiceImpl extends ServiceImpl implements IT if (!groupToAgvTaskMap.containsKey(key)) { Pick pick = pickMap.get(tasks.get(0).getPickId()); Long itemId = tasks.get(0).getItemId(); - AgvTask agvTask = agvTaskService.bulidAgvTask(pick == null ? null : pick.getConNo(), itemId, null, key.getStockCode(), key.getFromPointCode(), key.getToPointCode(), null, businessType, izAll, AgvVendorEnum.TES.getValue()); + String currOutCode = tasks.get(0).getCurrOutCode(); + AgvTask agvTask = agvTaskService.bulidAgvTask(pick == null ? currOutCode : pick.getConNo(), itemId, null, key.getStockCode(), key.getFromPointCode(), key.getToPointCode(), null, businessType, izAll, AgvVendorEnum.TES.getValue()); createToAgvTaskList.add(agvTask); groupToAgvTaskMap.put(key, agvTask); // 建立映射 log.info("创建AGV任务:{}", agvTask); @@ -267,10 +274,10 @@ public class TaskServiceImpl extends ServiceImpl implements IT Pick pick = pickMap.get(task.getPickId()); //选择最优且任务数最少的工作站 Point bestOutPoint; - if(Set.of(4, 5, 6, 7).contains(pick.getOrderType())){ + if (Set.of(4, 5, 6, 7).contains(pick.getOrderType())) { bestOutPoint = selectBestAvailableOutboundPoint(fromPoint, outCpPoints, pointTaskCountMap); - }else{ - bestOutPoint=outMjPoints.get(0); + } else { + bestOutPoint = outMjPoints.get(0); } task.setToPointId(bestOutPoint.getId()); task.setToPointCode(bestOutPoint.getPointCode()); @@ -307,9 +314,9 @@ public class TaskServiceImpl extends ServiceImpl implements IT Map pointTaskCountMap = new HashMap<>(); for (Map map : result) { - String key = map.get("point_code").toString(); - Integer task_count =Integer.parseInt(map.get("task_count").toString()); - pointTaskCountMap.put(key, task_count); + String key = map.get("point_code").toString(); + Integer task_count = Integer.parseInt(map.get("task_count").toString()); + pointTaskCountMap.put(key, task_count); } return pointTaskCountMap; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/processor/AllocateProcessor.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/processor/AllocateProcessor.java index fbcfd5a..235dddd 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/processor/AllocateProcessor.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/service/processor/AllocateProcessor.java @@ -128,13 +128,13 @@ public class AllocateProcessor { List updateToInventory = new ArrayList<>(); List updateToPickDetail = new ArrayList<>(); List createToTask = new ArrayList<>(); - List movePoints = new ArrayList<>(); + Map> moveMap = new HashMap<>(); //4.分配 - allocate(data, updateToInventory, updateToPickDetail, createToTask, movePoints, errorMsgSet); + allocate(data, updateToInventory, updateToPickDetail, createToTask, moveMap, errorMsgSet); //5.生成移位任务 - moveTask(createToTask, movePoints); + moveTask(createToTask, moveMap); //6.批量操作 batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask); @@ -167,13 +167,13 @@ public class AllocateProcessor { List updateToInventory = new ArrayList<>(); List updateToPickDetail = new ArrayList<>(); List createToTask = new ArrayList<>(); - List movePoints = new ArrayList<>(); + Map> moveMap = new HashMap<>(); //4.分配 - allocate(data, updateToInventory, updateToPickDetail, createToTask, movePoints, errorMsgSet); + allocate(data, updateToInventory, updateToPickDetail, createToTask, moveMap, errorMsgSet); //5.生成移位任务 - moveTask(createToTask, movePoints); + moveTask(createToTask, moveMap); //6.批量操作 boolean result = batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask); @@ -395,10 +395,10 @@ public class AllocateProcessor { /** * 分配 */ - private void allocate(AllocationData data, List updateToInventory, List updateToPickDetail, List createToTask, List movePoints, Set errorMsgSet) { + private void allocate(AllocationData data, List updateToInventory, List updateToPickDetail, List createToTask, Map> moveMap, Set errorMsgSet) { for (PickDetail pickDetail : data.getPickDetails()) { try { - allocatePickDetail(pickDetail, data, errorMsgSet, updateToInventory, updateToPickDetail, createToTask, movePoints); + allocatePickDetail(pickDetail, data, errorMsgSet, updateToInventory, updateToPickDetail, createToTask, moveMap); } catch (Exception e) { errorMsgSet.add(String.format("分配异常,明细ID:%s,原因:%s", pickDetail.getId(), e.getMessage())); @@ -418,7 +418,7 @@ public class AllocateProcessor { */ private void allocatePickDetail(PickDetail pickDetail, AllocationData data, Set errorMsgSet, List updateToInventory, - List updateToPickDetail, List createToTask, List movePoints) { + List updateToPickDetail, List createToTask, Map> moveMap) { Pick pick = data.getPickMap().get(pickDetail.getPickId()); Item item = data.getItemMap().get(pickDetail.getItemId()); @@ -443,7 +443,7 @@ public class AllocateProcessor { throw new RuntimeException("分配处理中,请稍后重试"); } allocateInventory(pickDetail, item, pick, matchedInventories, updateToInventory, updateToPickDetail, - createToTask, movePoints, data, unAllocatedQty, errorMsgSet); + createToTask, moveMap, data, unAllocatedQty, errorMsgSet); } catch (Exception e) { log.error("分配异常,出库单ID: {}", pick.getId(), e); throw e; @@ -518,7 +518,7 @@ public class AllocateProcessor { */ private void allocateInventory(PickDetail pickDetail, Item item, Pick pick, List matchedInventories, List updateToInventory, - List updateToPickDetail, List createToTask, List movePoints, + List updateToPickDetail, List createToTask, Map> moveMap, AllocationData data, BigDecimal totalUnAllocatedQty, Set errorMsgSet) { // 智能排序库存 @@ -562,7 +562,7 @@ public class AllocateProcessor { // 创建任务 createPickTask(pickDetail, pick, item, inventory, inventoryScore, allocateQty, createToTask, data); // 获取需要移位的库位 - getMovePoints(inventoryScore, movePoints); + getMovePoints(inventoryScore, moveMap); // 记录分配日志 //inventoryLogService.addAllocInventoryLog(inventory, inventoryScore.getOutPoint().getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription()); // 更新剩余未分配数量 @@ -619,6 +619,8 @@ public class AllocateProcessor { //移位库位 List movePoints; + String currOutPointCode = currPoint.getPointCode(); + // 计算距离分数(权重30%) //Point bestPoint = getBestOutboundPoint(currPoint, outPoints); //double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3; @@ -652,7 +654,8 @@ public class AllocateProcessor { log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}", currPoint.getPointCode(), distanceScore, moveScore, totalScore, movePoints.size()); - return new InventoryScore(inventory, inventory.getStockId(), totalScore, movePoints); + + return new InventoryScore(inventory, inventory.getStockId(), totalScore, movePoints, currOutPointCode); } /** @@ -849,7 +852,7 @@ public class AllocateProcessor { // 判断是否整托分配 BigDecimal availableQty = BigDecimalUtil.subtract(inventory.getQuantity(), inventory.getQueuedQty(), 0); - Integer izAll = availableQty.compareTo(BigDecimal.ZERO) <=0 ? 0 : 1; + Integer izAll = availableQty.compareTo(BigDecimal.ZERO) <= 0 ? 0 : 1; // 目标库位 //Point toPoint = inventoryScore.getOutPoint(); @@ -859,7 +862,7 @@ public class AllocateProcessor { Task task = taskService.bulidTask( taskNo, TaskTypeEnum.PICK.getValue(), item, fromPoint, null, stock, pick.getId(), pickDetail.getId(), inventory.getItemKeyId(), inventory.getId(), - allocateQty, izAll); + allocateQty, izAll, null); if (task != null) { createToTask.add(task); @@ -899,15 +902,11 @@ public class AllocateProcessor { * 获取移位库位 * * @param inventoryScore 库位评分 - * @param movePoints 移位库位 + * @param moveMap 移位库位 */ - private void getMovePoints(InventoryScore inventoryScore, List movePoints) { + private void getMovePoints(InventoryScore inventoryScore, Map> moveMap) { if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) { - for (Point movePoint : inventoryScore.getMovePoints()) { - if (!movePoints.contains(movePoint)) { - movePoints.add(movePoint); - } - } + moveMap.put(inventoryScore.getCurrOutPointCode(), inventoryScore.getMovePoints()); } else { log.info("无移位库位"); } @@ -917,35 +916,41 @@ public class AllocateProcessor { * 移位任务 * * @param createToTask 创建的出库任务 - * @param movePoints 移位库位 + * @param moveMap 移位库位 */ - void moveTask(List createToTask, List movePoints) { - - if (CollectionUtils.isNotEmpty(movePoints)) { - Set createTaskIds = createToTask.stream() - .map(Task::getFromPointId) - .collect(Collectors.toSet()); - List pointsToMove = movePoints.stream() - .filter(point -> !createTaskIds.contains(point.getId())) - .toList(); - if (CollectionUtils.isNotEmpty(pointsToMove)) { - List moveToTask = buildMoveTask(pointsToMove); - if (CollectionUtils.isNotEmpty(moveToTask)) { - createToTask.addAll(moveToTask); + void moveTask(List createToTask, Map> moveMap) { + //遍历moveMap + Set processedStock = new HashSet<>(); + for (Map.Entry> entry : moveMap.entrySet()) { + String currOutPointCode = entry.getKey(); + List movePoints = entry.getValue(); + if (CollectionUtils.isNotEmpty(movePoints)) { + Set toPointIds = createToTask.stream().map(Task::getFromPointId).collect(Collectors.toSet()); + movePoints = movePoints.stream().filter(point -> !toPointIds.contains(point.getId())).toList(); + if(CollectionUtils.isNotEmpty(movePoints)){ + List moveToTask = buildMoveTask(currOutPointCode, movePoints,processedStock); + if (CollectionUtils.isNotEmpty(moveToTask)) { + createToTask.addAll(moveToTask); + } } - } + } } } /** * 创建移位任务 * - * @param movePoints 移位库位 + * @param currOutPointCode 当前出库库位 + * @param movePoints 移位库位 * @return 移位任务 */ - public List buildMoveTask(List movePoints) { + public List buildMoveTask(String currOutPointCode, List movePoints,Set processedStock) { + if(CollectionUtils.isEmpty(movePoints)){ + return new ArrayList<>(); + } List moveList = new ArrayList<>(); + //定义去重集合,缓存已处理过的容器编码,避免单次调用内重复生成任务 //库存 List pointIds = movePoints.stream().map(Point::getId).toList(); @@ -969,20 +974,26 @@ public class AllocateProcessor { for (Inventory inv : moveInventoryList) { try { //如果移位库位已有出库任务则不需要生成移位任务 - Stock stock = stockMap.get(inv.getStockId()); - if (agvTaskMapper.existsByStockCode(stock.getStockCode(),AgvVendorEnum.TES.getValue())!=null) { + if (processedStock.contains(inv.getStockId())) { continue; } + Stock stock = stockMap.get(inv.getStockId()); + if (agvTaskMapper.existsByStockCode(stock.getStockCode(), AgvVendorEnum.TES.getValue()) != null) { + processedStock.add(inv.getStockId()); + continue; + } + Item moveItem = moveItemMap.get(inv.getItemId()); Point fromPoint = fromPointMap.get(inv.getPointId()); String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO); //根据算法找到最优的目标库位 Point toPoint = allocatePoint(fromPoint, itemKeyMap.get(inv.getItemKeyId())); - Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0); + Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0, currOutPointCode); moveList.add(moveTask); pointService.bindPoint(toPoint); inv.setStatus(InventoryStatusEnum.MOVE.getValue()); + processedStock.add(inv.getStockId()); log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity()); } catch (Exception e) { throw e; diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryScore.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryScore.java index 3eb5230..bce5aa8 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryScore.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/shipping/vo/InventoryScore.java @@ -6,6 +6,7 @@ import org.cpte.modules.base.entity.Point; import org.cpte.modules.inventory.entity.Inventory; import java.util.List; +import java.util.Map; @Data @AllArgsConstructor @@ -20,4 +21,6 @@ public class InventoryScore { //private Point outPoint; //移位的库位 private List movePoints; + // + private String currOutPointCode; } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java index 874deac..81fd509 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/ITesAgvService.java @@ -19,7 +19,7 @@ public interface ITesAgvService { * @param json 接口json * @param agvTask 任务 */ - void sendTesAgvTask(String openApi, String json, AgvTask agvTask); + boolean sendTesAgvTask(String openApi, String json, AgvTask agvTask); /** * 任务上报 diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java index 51e6e63..7da7080 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/tesAgv/service/impl/ITesAgvServiceImpl.java @@ -91,12 +91,11 @@ public class ITesAgvServiceImpl implements ITesAgvService { } @Override - public void sendTesAgvTask(String openApi, String json, AgvTask agvTask) { + public boolean sendTesAgvTask(String openApi, String json, AgvTask agvTask) { log.info("请求报文:{}", json); // 检查接口开关, 未开启则返回 if (sysDictMapper.queryByDictCode(GeneralConstant.OPEN_FLAG) == null) { - updateAgvTaskResponse(agvTask, null, "接口未开启", GeneralConstant.TES_SUCCESS_CODE); - return; + return updateAgvTaskResponse(agvTask, null, "接口未开启", GeneralConstant.TES_SUCCESS_CODE); } String url = openApiMapper.getRequestUrl(openApi).getOriginUrl(); @@ -127,11 +126,11 @@ public class ITesAgvServiceImpl implements ITesAgvService { JSONObject data = resulObject.getJSONObject("data"); String tesId = data.getString("taskID"); // 更新任务状态 - updateAgvTaskResponse(agvTask, Long.parseLong(tesId), returnMsg, returnCode); + return updateAgvTaskResponse(agvTask, Long.parseLong(tesId), returnMsg, returnCode); } catch (Exception e) { // 记录异常到 AgvTask - updateAgvTaskResponse(agvTask, null, e.getMessage(), GeneralConstant.TES_FAIL_CODE); + return updateAgvTaskResponse(agvTask, null, e.getMessage(), GeneralConstant.TES_FAIL_CODE); } } @@ -326,16 +325,20 @@ public class ITesAgvServiceImpl implements ITesAgvService { * @param message 信息 * @param code 状态码 */ - private void updateAgvTaskResponse(AgvTask agvTask, Long tesId, String message, Integer code) { - if (agvTask != null) { - if (GeneralConstant.TES_SUCCESS_CODE.equals(code)) { - agvTask.setStatus(AgvStatusEnum.EXECUTING.getValue()); - agvTask.setTesId(tesId); - } - agvTask.setResMessage(message); - agvTask.setStartTime(new Date()); - agvTaskMapper.updateById(agvTask); + private boolean updateAgvTaskResponse(AgvTask agvTask, Long tesId, String message, Integer code) { + if (agvTask == null) { + return false; } + agvTask.setResMessage(message); + agvTask.setStartTime(new Date()); + if (GeneralConstant.TES_SUCCESS_CODE.equals(code)) { + agvTask.setStatus(AgvStatusEnum.EXECUTING.getValue()); + agvTask.setTesId(tesId); + } + + agvTaskMapper.updateById(agvTask); + + return GeneralConstant.TES_SUCCESS_CODE.equals(code); } } diff --git a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/BatchUtil.java b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/BatchUtil.java index ebd0c77..1571e3c 100644 --- a/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/BatchUtil.java +++ b/cpte-boot-module/cpte-module-wms/src/main/java/org/cpte/modules/utils/BatchUtil.java @@ -285,8 +285,8 @@ public class BatchUtil { */ @Transactional public void saveBatchTask(List tasks) { - String sql = "INSERT INTO data_task (id,task_no,item_id,item_code,from_point_id,from_point_code,to_point_id,to_point_code,stock_id,stock_code,pick_id,pick_detail_id,item_key_id,inventory_id,plan_qty,move_qty,task_type,task_status,iz_all,sys_org_code,tenant_id,create_by,create_time) " + - "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; + String sql = "INSERT INTO data_task (id,task_no,item_id,item_code,from_point_id,from_point_code,to_point_id,to_point_code,stock_id,stock_code,pick_id,pick_detail_id,item_key_id,inventory_id,plan_qty,move_qty,task_type,task_status,iz_all,curr_out_code,sys_org_code,tenant_id,create_by,create_time) " + + "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; batchInsert(sql, tasks, (ps, task) -> { try { ps.setLong(1, task.getId()); @@ -308,10 +308,11 @@ public class BatchUtil { ps.setInt(17, task.getTaskType()); ps.setInt(18, task.getTaskStatus()); ps.setInt(19, task.getIzAll()); - ps.setString(20, task.getSysOrgCode()); - ps.setLong(21, task.getTenantId()); - ps.setString(22, task.getCreateBy()); - ps.setTimestamp(23, new Timestamp(task.getCreateTime().getTime())); + ps.setString(20, task.getCurrOutCode()); + ps.setString(21, task.getSysOrgCode()); + ps.setLong(22, task.getTenantId()); + ps.setString(23, task.getCreateBy()); + ps.setTimestamp(24, new Timestamp(task.getCreateTime().getTime())); } catch (SQLException e) { throw new RuntimeException(e); }