no message

main
HUOJIN\92525 2026-01-30 18:00:48 +08:00
parent 27dafb919b
commit 9cb7b8bf4d
14 changed files with 240 additions and 108 deletions

View File

@ -50,7 +50,7 @@ public interface AgvTaskMapper extends BaseMapper<AgvTask> {
* @param status * @param status
* @param agvVendor ;AGV/TES * @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<AgvTask> queryAgvTaskList(@Param("status") Integer status, @Param("agvVendor") String agvVendor); List<AgvTask> queryAgvTaskList(@Param("status") Integer status, @Param("agvVendor") String agvVendor);
/** /**
@ -73,8 +73,10 @@ public interface AgvTaskMapper extends BaseMapper<AgvTask> {
*/ */
List<Map<String, Object>> pointTaskCountMap(); List<Map<String, Object>> pointTaskCountMap();
/**
List<ConNoAgv> queryIsExecuteAgvTask(); * -)
*/
List<Map<String, Object>> pointTaskMap();
/** /**
* AGV5 * AGV5
@ -82,4 +84,9 @@ public interface AgvTaskMapper extends BaseMapper<AgvTask> {
@Select(value = "select * from data_agv_task where type in ('INBOUND','OUTBOUND') and status=2 LIMIT 5") @Select(value = "select * from data_agv_task where type in ('INBOUND','OUTBOUND') and status=2 LIMIT 5")
List<AgvTask> queryExecuteTopFive(); List<AgvTask> queryExecuteTopFive();
/**
*
*/
@Select(value = "select * from data_agv_task where con_no = #{startCode} and type='MOVE' and status=1 and agv_vendor = 'TES' ")
List<AgvTask> queryOutPointForMove(@Param("startCode") String startCode);
} }

View File

@ -43,4 +43,19 @@
AND bp.iz_active=1 AND bp.iz_active=1
GROUP BY bp.point_code GROUP BY bp.point_code
</select> </select>
<select id="pointTaskMap" resultType="java.util.Map">
SELECT
bp.point_code,
concat(agv.con_no,"-",agv.item_id) as no_item
FROM base_area ba
JOIN base_point bp ON bp.area_id = ba.id
LEFT JOIN data_agv_task agv ON agv.end_code = bp.point_code
AND agv.type = 'OUTBOUND'
AND agv.status=2
AND agv.agv_vendor = 'TES'
WHERE ba.area_code = 'CK_DOCK'
AND bp.iz_active=1
GROUP BY bp.point_code
</select>
</mapper> </mapper>

View File

@ -119,20 +119,6 @@ public class ScanTrayProcessor {
agvTaskService.processAgvTask(data, dstPoint); 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 * @param movePoints
*/ */
public void buildMoveTask(List<Point> movePoints) { public void buildMoveTask(List<Point> movePoints) {
if(CollectionUtils.isEmpty(movePoints)){
return;
}
//定义去重集合,缓存已处理过的容器编码,避免单次调用内重复生成任务
Set<Long> processedStock = new HashSet<>();
List<Task> moveList = new ArrayList<>(); List<Task> moveList = new ArrayList<>();
//库存 //库存
@ -734,10 +725,15 @@ public class ScanTrayProcessor {
for (Inventory inv : moveInventoryList) { for (Inventory inv : moveInventoryList) {
try { try {
//如果移位库位已有出库任务则不需要生成移位任务 //如果移位库位已有出库任务则不需要生成移位任务
Stock stock = stockMap.get(inv.getStockId()); if (processedStock.contains(inv.getStockId())) {
if (agvTaskMapper.existsByStockCode(stock.getStockCode(), AgvVendorEnum.TES.getValue()) != null) {
continue; 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()); Item moveItem = moveItemMap.get(inv.getItemId());
Point fromPoint = fromPointMap.get(inv.getPointId()); Point fromPoint = fromPointMap.get(inv.getPointId());
@ -747,10 +743,11 @@ public class ScanTrayProcessor {
String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO); String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO);
//根据算法找到最优的目标库位 //根据算法找到最优的目标库位
Point toPoint = allocatePoint(itemKeyList, fromPoint, areaCode, BusinessTypeEnum.MOVE.getValue()); 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); moveList.add(moveTask);
pointService.bindPoint(toPoint); pointService.bindPoint(toPoint);
inv.setStatus(InventoryStatusEnum.MOVE.getValue()); inv.setStatus(InventoryStatusEnum.MOVE.getValue());
processedStock.add(inv.getStockId());
log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity()); log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity());
} catch (Exception e) { } catch (Exception e) {
throw e; throw e;

View File

@ -1,12 +1,14 @@
package org.cpte.modules.quartz.job; package org.cpte.modules.quartz.job;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.cpte.modules.agvTask.entity.AgvTask; import org.cpte.modules.agvTask.entity.AgvTask;
import org.cpte.modules.agvTask.mapper.AgvTaskMapper; import org.cpte.modules.agvTask.mapper.AgvTaskMapper;
import org.cpte.modules.constant.GeneralConstant; import org.cpte.modules.constant.GeneralConstant;
import org.cpte.modules.constant.enums.AgvStatusEnum; import org.cpte.modules.constant.enums.AgvStatusEnum;
import org.cpte.modules.constant.enums.AgvVendorEnum; 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.shipping.service.ITaskService;
import org.cpte.modules.tesAgv.service.ITesAgvService; import org.cpte.modules.tesAgv.service.ITesAgvService;
import org.cpte.modules.utils.RedisDistributedLockUtil; import org.cpte.modules.utils.RedisDistributedLockUtil;
@ -15,7 +17,9 @@ import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException; import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
@Slf4j @Slf4j
public class TesAgvJob implements Job { public class TesAgvJob implements Job {
@ -33,7 +37,6 @@ public class TesAgvJob implements Job {
private RedisDistributedLockUtil redissonLock; private RedisDistributedLockUtil redissonLock;
@Override @Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
@ -68,16 +71,93 @@ public class TesAgvJob implements Job {
// 3.下发任务TES // 3.下发任务TES
List<AgvTask> agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue()); List<AgvTask> agvTaskList = agvTaskMapper.queryAgvTaskList(AgvStatusEnum.CREATED.getValue(), AgvVendorEnum.TES.getValue());
if (agvTaskList.isEmpty()) { if (CollectionUtils.isEmpty(agvTaskList)) {
return; 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<String, String> 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<String, String> 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<String, String> pointTaskMap) {
boolean flag = sendTesAgvTask(agvTask);
if (flag) {
pointTaskMap.put(workstationCode, taskKey);
sendOutPointForMove(agvTask);
}
return flag;
}
/**
*
*/
private void sendOutPointForMove(AgvTask currOutAgvTask) {
List<AgvTask> agvTasks = agvTaskMapper.queryOutPointForMove(currOutAgvTask.getStartCode());
if (CollectionUtils.isNotEmpty(agvTasks)) {
for (AgvTask agvTask : agvTasks) {
sendTesAgvTask(agvTask);
}
}
}
private Map<String, String> queryPointTaskMap() {
// 从数据库查询每个工作站当前的任务列表
List<Map<String, Object>> result = agvTaskMapper.pointTaskMap();
Map<String, String> pointTaskMap = new HashMap<>();
for (Map<String, Object> 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;
}
} }

View File

@ -150,6 +150,14 @@ public class Task implements Serializable {
@Excel(name = "是否整托", width = 15) @Excel(name = "是否整托", width = 15)
@Schema(description = "是否整托") @Schema(description = "是否整托")
private java.lang.Integer izAll; private java.lang.Integer izAll;
/**
*
*
*/
@Schema(description = "当前出库库位")
private String currOutCode;
/** /**
* *
*/ */

View File

@ -21,7 +21,7 @@ public interface TaskMapper extends BaseMapper<Task> {
* *
* @return List<Pick> * @return List<Pick>
*/ */
@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<Task> queryUnIssuedTask(); List<Task> queryUnIssuedTask();
@Select("SELECT * FROM data_task WHERE agv_task_id = #{agvTaskId} ") @Select("SELECT * FROM data_task WHERE agv_task_id = #{agvTaskId} ")
@ -39,7 +39,7 @@ public interface TaskMapper extends BaseMapper<Task> {
* *
* @return List<Pick> * @return List<Pick>
*/ */
@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<Task> queryUnallocatedTask(); List<Task> queryUnallocatedTask();
/** /**

View File

@ -32,6 +32,6 @@
JOIN data_pick_detail pd ON pd.pick_id=p.id JOIN data_pick_detail pd ON pd.pick_id=p.id
WHERE p.`status` in (1,2,4) WHERE p.`status` in (1,2,4)
AND pd.order_qty-pd.allocated_qty>0 AND pd.order_qty-pd.allocated_qty>0
ORDER BY p.order_date,pd.line_no ORDER BY p.create_time,pd.create_time
</select> </select>
</mapper> </mapper>

View File

@ -50,7 +50,7 @@ public interface ITaskService extends IService<Task> {
* @param izAll * @param izAll
* @return Task * @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);
/** /**
* TaskAGV * TaskAGV

View File

@ -101,7 +101,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
} }
@Override @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; LoginUser sysUser = null;
try { try {
sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
@ -128,6 +128,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
.taskStatus(1) .taskStatus(1)
.taskType(taskType) .taskType(taskType)
.izAll(izAll) .izAll(izAll)
.currOutCode(currOutCode)
.sysOrgCode(sysUser == null ? "A05" : sysUser.getOrgCode()) .sysOrgCode(sysUser == null ? "A05" : sysUser.getOrgCode())
.tenantId(sysUser == null ? 1000L : Long.parseLong(sysUser.getRelTenantIds())) .tenantId(sysUser == null ? 1000L : Long.parseLong(sysUser.getRelTenantIds()))
.createBy(sysUser == null ? "system" : sysUser.getUsername()) .createBy(sysUser == null ? "system" : sysUser.getUsername())
@ -154,14 +155,19 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
Map<TaskGroupKey, List<Task>> taskGroupMap = taskList.stream() Map<TaskGroupKey, List<Task>> taskGroupMap = taskList.stream()
.sorted(Comparator.comparing(Task::getCreateTime)) .sorted(Comparator.comparing(Task::getCreateTime))
.collect(Collectors.groupingBy(task -> TaskGroupKey.of( .collect(Collectors.groupingBy(task -> TaskGroupKey.of(
task.getStockCode(), task.getStockCode(),
task.getFromPointCode(), task.getFromPointCode(),
task.getToPointCode() task.getToPointCode()
))); ),
LinkedHashMap::new,
Collectors.toList()
)
);
//3.批量创建AGV任务 //3.批量创建AGV任务
List<AgvTask> createToAgvTaskList = new ArrayList<>(); List<AgvTask> createToAgvTaskList = new ArrayList<>();
Map<TaskGroupKey, AgvTask> groupToAgvTaskMap = new HashMap<>(); Map<TaskGroupKey, AgvTask> groupToAgvTaskMap = new LinkedHashMap<>();
for (Map.Entry<TaskGroupKey, List<Task>> entry : taskGroupMap.entrySet()) { for (Map.Entry<TaskGroupKey, List<Task>> entry : taskGroupMap.entrySet()) {
TaskGroupKey key = entry.getKey(); TaskGroupKey key = entry.getKey();
List<Task> tasks = entry.getValue(); List<Task> tasks = entry.getValue();
@ -173,7 +179,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
if (!groupToAgvTaskMap.containsKey(key)) { if (!groupToAgvTaskMap.containsKey(key)) {
Pick pick = pickMap.get(tasks.get(0).getPickId()); Pick pick = pickMap.get(tasks.get(0).getPickId());
Long itemId = tasks.get(0).getItemId(); 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); createToAgvTaskList.add(agvTask);
groupToAgvTaskMap.put(key, agvTask); // 建立映射 groupToAgvTaskMap.put(key, agvTask); // 建立映射
log.info("创建AGV任务{}", agvTask); log.info("创建AGV任务{}", agvTask);
@ -267,10 +274,10 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
Pick pick = pickMap.get(task.getPickId()); Pick pick = pickMap.get(task.getPickId());
//选择最优且任务数最少的工作站 //选择最优且任务数最少的工作站
Point bestOutPoint; 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); bestOutPoint = selectBestAvailableOutboundPoint(fromPoint, outCpPoints, pointTaskCountMap);
}else{ } else {
bestOutPoint=outMjPoints.get(0); bestOutPoint = outMjPoints.get(0);
} }
task.setToPointId(bestOutPoint.getId()); task.setToPointId(bestOutPoint.getId());
task.setToPointCode(bestOutPoint.getPointCode()); task.setToPointCode(bestOutPoint.getPointCode());
@ -307,9 +314,9 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements IT
Map<String, Integer> pointTaskCountMap = new HashMap<>(); Map<String, Integer> pointTaskCountMap = new HashMap<>();
for (Map<String, Object> map : result) { for (Map<String, Object> map : result) {
String key = map.get("point_code").toString(); String key = map.get("point_code").toString();
Integer task_count =Integer.parseInt(map.get("task_count").toString()); Integer task_count = Integer.parseInt(map.get("task_count").toString());
pointTaskCountMap.put(key, task_count); pointTaskCountMap.put(key, task_count);
} }
return pointTaskCountMap; return pointTaskCountMap;

View File

@ -128,13 +128,13 @@ public class AllocateProcessor {
List<Inventory> updateToInventory = new ArrayList<>(); List<Inventory> updateToInventory = new ArrayList<>();
List<PickDetail> updateToPickDetail = new ArrayList<>(); List<PickDetail> updateToPickDetail = new ArrayList<>();
List<Task> createToTask = new ArrayList<>(); List<Task> createToTask = new ArrayList<>();
List<Point> movePoints = new ArrayList<>(); Map<String, List<Point>> moveMap = new HashMap<>();
//4.分配 //4.分配
allocate(data, updateToInventory, updateToPickDetail, createToTask, movePoints, errorMsgSet); allocate(data, updateToInventory, updateToPickDetail, createToTask, moveMap, errorMsgSet);
//5.生成移位任务 //5.生成移位任务
moveTask(createToTask, movePoints); moveTask(createToTask, moveMap);
//6.批量操作 //6.批量操作
batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask); batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask);
@ -167,13 +167,13 @@ public class AllocateProcessor {
List<Inventory> updateToInventory = new ArrayList<>(); List<Inventory> updateToInventory = new ArrayList<>();
List<PickDetail> updateToPickDetail = new ArrayList<>(); List<PickDetail> updateToPickDetail = new ArrayList<>();
List<Task> createToTask = new ArrayList<>(); List<Task> createToTask = new ArrayList<>();
List<Point> movePoints = new ArrayList<>(); Map<String, List<Point>> moveMap = new HashMap<>();
//4.分配 //4.分配
allocate(data, updateToInventory, updateToPickDetail, createToTask, movePoints, errorMsgSet); allocate(data, updateToInventory, updateToPickDetail, createToTask, moveMap, errorMsgSet);
//5.生成移位任务 //5.生成移位任务
moveTask(createToTask, movePoints); moveTask(createToTask, moveMap);
//6.批量操作 //6.批量操作
boolean result = batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask); boolean result = batchProcessor.batchAllocate(updateToInventory, updateToPickDetail, createToTask);
@ -395,10 +395,10 @@ public class AllocateProcessor {
/** /**
* *
*/ */
private void allocate(AllocationData data, List<Inventory> updateToInventory, List<PickDetail> updateToPickDetail, List<Task> createToTask, List<Point> movePoints, Set<String> errorMsgSet) { private void allocate(AllocationData data, List<Inventory> updateToInventory, List<PickDetail> updateToPickDetail, List<Task> createToTask, Map<String, List<Point>> moveMap, Set<String> errorMsgSet) {
for (PickDetail pickDetail : data.getPickDetails()) { for (PickDetail pickDetail : data.getPickDetails()) {
try { try {
allocatePickDetail(pickDetail, data, errorMsgSet, updateToInventory, updateToPickDetail, createToTask, movePoints); allocatePickDetail(pickDetail, data, errorMsgSet, updateToInventory, updateToPickDetail, createToTask, moveMap);
} catch (Exception e) { } catch (Exception e) {
errorMsgSet.add(String.format("分配异常明细ID:%s原因:%s", errorMsgSet.add(String.format("分配异常明细ID:%s原因:%s",
pickDetail.getId(), e.getMessage())); pickDetail.getId(), e.getMessage()));
@ -418,7 +418,7 @@ public class AllocateProcessor {
*/ */
private void allocatePickDetail(PickDetail pickDetail, AllocationData data, private void allocatePickDetail(PickDetail pickDetail, AllocationData data,
Set<String> errorMsgSet, List<Inventory> updateToInventory, Set<String> errorMsgSet, List<Inventory> updateToInventory,
List<PickDetail> updateToPickDetail, List<Task> createToTask, List<Point> movePoints) { List<PickDetail> updateToPickDetail, List<Task> createToTask, Map<String, List<Point>> moveMap) {
Pick pick = data.getPickMap().get(pickDetail.getPickId()); Pick pick = data.getPickMap().get(pickDetail.getPickId());
Item item = data.getItemMap().get(pickDetail.getItemId()); Item item = data.getItemMap().get(pickDetail.getItemId());
@ -443,7 +443,7 @@ public class AllocateProcessor {
throw new RuntimeException("分配处理中,请稍后重试"); throw new RuntimeException("分配处理中,请稍后重试");
} }
allocateInventory(pickDetail, item, pick, matchedInventories, updateToInventory, updateToPickDetail, allocateInventory(pickDetail, item, pick, matchedInventories, updateToInventory, updateToPickDetail,
createToTask, movePoints, data, unAllocatedQty, errorMsgSet); createToTask, moveMap, data, unAllocatedQty, errorMsgSet);
} catch (Exception e) { } catch (Exception e) {
log.error("分配异常出库单ID: {}", pick.getId(), e); log.error("分配异常出库单ID: {}", pick.getId(), e);
throw e; throw e;
@ -518,7 +518,7 @@ public class AllocateProcessor {
*/ */
private void allocateInventory(PickDetail pickDetail, Item item, Pick pick, private void allocateInventory(PickDetail pickDetail, Item item, Pick pick,
List<Inventory> matchedInventories, List<Inventory> updateToInventory, List<Inventory> matchedInventories, List<Inventory> updateToInventory,
List<PickDetail> updateToPickDetail, List<Task> createToTask, List<Point> movePoints, List<PickDetail> updateToPickDetail, List<Task> createToTask, Map<String, List<Point>> moveMap,
AllocationData data, BigDecimal totalUnAllocatedQty, Set<String> errorMsgSet) { AllocationData data, BigDecimal totalUnAllocatedQty, Set<String> errorMsgSet) {
// 智能排序库存 // 智能排序库存
@ -562,7 +562,7 @@ public class AllocateProcessor {
// 创建任务 // 创建任务
createPickTask(pickDetail, pick, item, inventory, inventoryScore, allocateQty, createToTask, data); 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()); //inventoryLogService.addAllocInventoryLog(inventory, inventoryScore.getOutPoint().getId(), allocateQty, pick.getOrderNo(), pickDetail.getId(), pickDetail.getDescription());
// 更新剩余未分配数量 // 更新剩余未分配数量
@ -619,6 +619,8 @@ public class AllocateProcessor {
//移位库位 //移位库位
List<Point> movePoints; List<Point> movePoints;
String currOutPointCode = currPoint.getPointCode();
// 计算距离分数权重30% // 计算距离分数权重30%
//Point bestPoint = getBestOutboundPoint(currPoint, outPoints); //Point bestPoint = getBestOutboundPoint(currPoint, outPoints);
//double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3; //double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3;
@ -652,7 +654,8 @@ public class AllocateProcessor {
log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}", log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}",
currPoint.getPointCode(), distanceScore, moveScore, totalScore, movePoints.size()); 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); 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(); //Point toPoint = inventoryScore.getOutPoint();
@ -859,7 +862,7 @@ public class AllocateProcessor {
Task task = taskService.bulidTask( Task task = taskService.bulidTask(
taskNo, TaskTypeEnum.PICK.getValue(), item, fromPoint, null, taskNo, TaskTypeEnum.PICK.getValue(), item, fromPoint, null,
stock, pick.getId(), pickDetail.getId(), inventory.getItemKeyId(), inventory.getId(), stock, pick.getId(), pickDetail.getId(), inventory.getItemKeyId(), inventory.getId(),
allocateQty, izAll); allocateQty, izAll, null);
if (task != null) { if (task != null) {
createToTask.add(task); createToTask.add(task);
@ -899,15 +902,11 @@ public class AllocateProcessor {
* *
* *
* @param inventoryScore * @param inventoryScore
* @param movePoints * @param moveMap
*/ */
private void getMovePoints(InventoryScore inventoryScore, List<Point> movePoints) { private void getMovePoints(InventoryScore inventoryScore, Map<String, List<Point>> moveMap) {
if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) { if (CollectionUtils.isNotEmpty(inventoryScore.getMovePoints())) {
for (Point movePoint : inventoryScore.getMovePoints()) { moveMap.put(inventoryScore.getCurrOutPointCode(), inventoryScore.getMovePoints());
if (!movePoints.contains(movePoint)) {
movePoints.add(movePoint);
}
}
} else { } else {
log.info("无移位库位"); log.info("无移位库位");
} }
@ -917,35 +916,41 @@ public class AllocateProcessor {
* *
* *
* @param createToTask * @param createToTask
* @param movePoints * @param moveMap
*/ */
void moveTask(List<Task> createToTask, List<Point> movePoints) { void moveTask(List<Task> createToTask, Map<String, List<Point>> moveMap) {
//遍历moveMap
if (CollectionUtils.isNotEmpty(movePoints)) { Set<Long> processedStock = new HashSet<>();
Set<Long> createTaskIds = createToTask.stream() for (Map.Entry<String, List<Point>> entry : moveMap.entrySet()) {
.map(Task::getFromPointId) String currOutPointCode = entry.getKey();
.collect(Collectors.toSet()); List<Point> movePoints = entry.getValue();
List<Point> pointsToMove = movePoints.stream() if (CollectionUtils.isNotEmpty(movePoints)) {
.filter(point -> !createTaskIds.contains(point.getId())) Set<Long> toPointIds = createToTask.stream().map(Task::getFromPointId).collect(Collectors.toSet());
.toList(); movePoints = movePoints.stream().filter(point -> !toPointIds.contains(point.getId())).toList();
if (CollectionUtils.isNotEmpty(pointsToMove)) { if(CollectionUtils.isNotEmpty(movePoints)){
List<Task> moveToTask = buildMoveTask(pointsToMove); List<Task> moveToTask = buildMoveTask(currOutPointCode, movePoints,processedStock);
if (CollectionUtils.isNotEmpty(moveToTask)) { if (CollectionUtils.isNotEmpty(moveToTask)) {
createToTask.addAll(moveToTask); createToTask.addAll(moveToTask);
}
} }
}
}
} }
} }
/** /**
* *
* *
* @param movePoints * @param currOutPointCode
* @param movePoints
* @return * @return
*/ */
public List<Task> buildMoveTask(List<Point> movePoints) { public List<Task> buildMoveTask(String currOutPointCode, List<Point> movePoints,Set<Long> processedStock) {
if(CollectionUtils.isEmpty(movePoints)){
return new ArrayList<>();
}
List<Task> moveList = new ArrayList<>(); List<Task> moveList = new ArrayList<>();
//定义去重集合,缓存已处理过的容器编码,避免单次调用内重复生成任务
//库存 //库存
List<Long> pointIds = movePoints.stream().map(Point::getId).toList(); List<Long> pointIds = movePoints.stream().map(Point::getId).toList();
@ -969,20 +974,26 @@ public class AllocateProcessor {
for (Inventory inv : moveInventoryList) { for (Inventory inv : moveInventoryList) {
try { try {
//如果移位库位已有出库任务则不需要生成移位任务 //如果移位库位已有出库任务则不需要生成移位任务
Stock stock = stockMap.get(inv.getStockId()); if (processedStock.contains(inv.getStockId())) {
if (agvTaskMapper.existsByStockCode(stock.getStockCode(),AgvVendorEnum.TES.getValue())!=null) {
continue; 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()); Item moveItem = moveItemMap.get(inv.getItemId());
Point fromPoint = fromPointMap.get(inv.getPointId()); Point fromPoint = fromPointMap.get(inv.getPointId());
String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO); String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO);
//根据算法找到最优的目标库位 //根据算法找到最优的目标库位
Point toPoint = allocatePoint(fromPoint, itemKeyMap.get(inv.getItemKeyId())); 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); moveList.add(moveTask);
pointService.bindPoint(toPoint); pointService.bindPoint(toPoint);
inv.setStatus(InventoryStatusEnum.MOVE.getValue()); inv.setStatus(InventoryStatusEnum.MOVE.getValue());
processedStock.add(inv.getStockId());
log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity()); log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity());
} catch (Exception e) { } catch (Exception e) {
throw e; throw e;

View File

@ -6,6 +6,7 @@ import org.cpte.modules.base.entity.Point;
import org.cpte.modules.inventory.entity.Inventory; import org.cpte.modules.inventory.entity.Inventory;
import java.util.List; import java.util.List;
import java.util.Map;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@ -20,4 +21,6 @@ public class InventoryScore {
//private Point outPoint; //private Point outPoint;
//移位的库位 //移位的库位
private List<Point> movePoints; private List<Point> movePoints;
//
private String currOutPointCode;
} }

View File

@ -19,7 +19,7 @@ public interface ITesAgvService {
* @param json json * @param json json
* @param agvTask * @param agvTask
*/ */
void sendTesAgvTask(String openApi, String json, AgvTask agvTask); boolean sendTesAgvTask(String openApi, String json, AgvTask agvTask);
/** /**
* *

View File

@ -91,12 +91,11 @@ public class ITesAgvServiceImpl implements ITesAgvService {
} }
@Override @Override
public void sendTesAgvTask(String openApi, String json, AgvTask agvTask) { public boolean sendTesAgvTask(String openApi, String json, AgvTask agvTask) {
log.info("请求报文:{}", json); log.info("请求报文:{}", json);
// 检查接口开关, 未开启则返回 // 检查接口开关, 未开启则返回
if (sysDictMapper.queryByDictCode(GeneralConstant.OPEN_FLAG) == null) { if (sysDictMapper.queryByDictCode(GeneralConstant.OPEN_FLAG) == null) {
updateAgvTaskResponse(agvTask, null, "接口未开启", GeneralConstant.TES_SUCCESS_CODE); return updateAgvTaskResponse(agvTask, null, "接口未开启", GeneralConstant.TES_SUCCESS_CODE);
return;
} }
String url = openApiMapper.getRequestUrl(openApi).getOriginUrl(); String url = openApiMapper.getRequestUrl(openApi).getOriginUrl();
@ -127,11 +126,11 @@ public class ITesAgvServiceImpl implements ITesAgvService {
JSONObject data = resulObject.getJSONObject("data"); JSONObject data = resulObject.getJSONObject("data");
String tesId = data.getString("taskID"); String tesId = data.getString("taskID");
// 更新任务状态 // 更新任务状态
updateAgvTaskResponse(agvTask, Long.parseLong(tesId), returnMsg, returnCode); return updateAgvTaskResponse(agvTask, Long.parseLong(tesId), returnMsg, returnCode);
} catch (Exception e) { } catch (Exception e) {
// 记录异常到 AgvTask // 记录异常到 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 message
* @param code * @param code
*/ */
private void updateAgvTaskResponse(AgvTask agvTask, Long tesId, String message, Integer code) { private boolean updateAgvTaskResponse(AgvTask agvTask, Long tesId, String message, Integer code) {
if (agvTask != null) { if (agvTask == null) {
if (GeneralConstant.TES_SUCCESS_CODE.equals(code)) { return false;
agvTask.setStatus(AgvStatusEnum.EXECUTING.getValue());
agvTask.setTesId(tesId);
}
agvTask.setResMessage(message);
agvTask.setStartTime(new Date());
agvTaskMapper.updateById(agvTask);
} }
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);
} }
} }

View File

@ -285,8 +285,8 @@ public class BatchUtil {
*/ */
@Transactional @Transactional
public void saveBatchTask(List<Task> tasks) { public void saveBatchTask(List<Task> 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) " + 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 (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"; "VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
batchInsert(sql, tasks, (ps, task) -> { batchInsert(sql, tasks, (ps, task) -> {
try { try {
ps.setLong(1, task.getId()); ps.setLong(1, task.getId());
@ -308,10 +308,11 @@ public class BatchUtil {
ps.setInt(17, task.getTaskType()); ps.setInt(17, task.getTaskType());
ps.setInt(18, task.getTaskStatus()); ps.setInt(18, task.getTaskStatus());
ps.setInt(19, task.getIzAll()); ps.setInt(19, task.getIzAll());
ps.setString(20, task.getSysOrgCode()); ps.setString(20, task.getCurrOutCode());
ps.setLong(21, task.getTenantId()); ps.setString(21, task.getSysOrgCode());
ps.setString(22, task.getCreateBy()); ps.setLong(22, task.getTenantId());
ps.setTimestamp(23, new Timestamp(task.getCreateTime().getTime())); ps.setString(23, task.getCreateBy());
ps.setTimestamp(24, new Timestamp(task.getCreateTime().getTime()));
} catch (SQLException e) { } catch (SQLException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }