no message
parent
27dafb919b
commit
9cb7b8bf4d
|
|
@ -50,7 +50,7 @@ public interface AgvTaskMapper extends BaseMapper<AgvTask> {
|
|||
* @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<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<ConNoAgv> queryIsExecuteAgvTask();
|
||||
/**
|
||||
* 每个出库工作站当前任务(工作站,柜号-物料)
|
||||
*/
|
||||
List<Map<String, Object>> pointTaskMap();
|
||||
|
||||
/**
|
||||
* 查询正在执行的AGV任务前5个
|
||||
|
|
@ -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")
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,4 +43,19 @@
|
|||
AND bp.iz_active=1
|
||||
GROUP BY bp.point_code
|
||||
</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>
|
||||
|
|
@ -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<Point> movePoints) {
|
||||
if(CollectionUtils.isEmpty(movePoints)){
|
||||
return;
|
||||
}
|
||||
//定义去重集合,缓存已处理过的容器编码,避免单次调用内重复生成任务
|
||||
Set<Long> processedStock = new HashSet<>();
|
||||
List<Task> 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;
|
||||
|
|
|
|||
|
|
@ -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<AgvTask> 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<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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 开始时间
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ public interface TaskMapper extends BaseMapper<Task> {
|
|||
*
|
||||
* @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();
|
||||
|
||||
@Select("SELECT * FROM data_task WHERE agv_task_id = #{agvTaskId} ")
|
||||
|
|
@ -39,7 +39,7 @@ public interface TaskMapper extends BaseMapper<Task> {
|
|||
*
|
||||
* @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();
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
</select>
|
||||
</mapper>
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public interface ITaskService extends IService<Task> {
|
|||
* @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出库任务
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> 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<TaskMapper, Task> 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<TaskMapper, Task> implements IT
|
|||
Map<TaskGroupKey, List<Task>> 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<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()) {
|
||||
TaskGroupKey key = entry.getKey();
|
||||
List<Task> tasks = entry.getValue();
|
||||
|
|
@ -173,7 +179,8 @@ public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> 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<TaskMapper, Task> 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<TaskMapper, Task> implements IT
|
|||
Map<String, Integer> pointTaskCountMap = new HashMap<>();
|
||||
|
||||
for (Map<String, Object> 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;
|
||||
|
|
|
|||
|
|
@ -128,13 +128,13 @@ public class AllocateProcessor {
|
|||
List<Inventory> updateToInventory = new ArrayList<>();
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>();
|
||||
List<Task> createToTask = new ArrayList<>();
|
||||
List<Point> movePoints = new ArrayList<>();
|
||||
Map<String, List<Point>> 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<Inventory> updateToInventory = new ArrayList<>();
|
||||
List<PickDetail> updateToPickDetail = new ArrayList<>();
|
||||
List<Task> createToTask = new ArrayList<>();
|
||||
List<Point> movePoints = new ArrayList<>();
|
||||
Map<String, List<Point>> 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<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()) {
|
||||
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<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());
|
||||
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<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) {
|
||||
|
||||
// 智能排序库存
|
||||
|
|
@ -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<Point> 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<Point> movePoints) {
|
||||
private void getMovePoints(InventoryScore inventoryScore, Map<String, List<Point>> 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<Task> createToTask, List<Point> movePoints) {
|
||||
|
||||
if (CollectionUtils.isNotEmpty(movePoints)) {
|
||||
Set<Long> createTaskIds = createToTask.stream()
|
||||
.map(Task::getFromPointId)
|
||||
.collect(Collectors.toSet());
|
||||
List<Point> pointsToMove = movePoints.stream()
|
||||
.filter(point -> !createTaskIds.contains(point.getId()))
|
||||
.toList();
|
||||
if (CollectionUtils.isNotEmpty(pointsToMove)) {
|
||||
List<Task> moveToTask = buildMoveTask(pointsToMove);
|
||||
if (CollectionUtils.isNotEmpty(moveToTask)) {
|
||||
createToTask.addAll(moveToTask);
|
||||
void moveTask(List<Task> createToTask, Map<String, List<Point>> moveMap) {
|
||||
//遍历moveMap
|
||||
Set<Long> processedStock = new HashSet<>();
|
||||
for (Map.Entry<String, List<Point>> entry : moveMap.entrySet()) {
|
||||
String currOutPointCode = entry.getKey();
|
||||
List<Point> movePoints = entry.getValue();
|
||||
if (CollectionUtils.isNotEmpty(movePoints)) {
|
||||
Set<Long> toPointIds = createToTask.stream().map(Task::getFromPointId).collect(Collectors.toSet());
|
||||
movePoints = movePoints.stream().filter(point -> !toPointIds.contains(point.getId())).toList();
|
||||
if(CollectionUtils.isNotEmpty(movePoints)){
|
||||
List<Task> moveToTask = buildMoveTask(currOutPointCode, movePoints,processedStock);
|
||||
if (CollectionUtils.isNotEmpty(moveToTask)) {
|
||||
createToTask.addAll(moveToTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建移位任务
|
||||
*
|
||||
* @param movePoints 移位库位
|
||||
* @param currOutPointCode 当前出库库位
|
||||
* @param movePoints 移位库位
|
||||
* @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<Long> 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;
|
||||
|
|
|
|||
|
|
@ -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<Point> movePoints;
|
||||
//
|
||||
private String currOutPointCode;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 任务上报
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -285,8 +285,8 @@ public class BatchUtil {
|
|||
*/
|
||||
@Transactional
|
||||
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) " +
|
||||
"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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue