diff --git a/servo/src/main/java/com/galaxis/rcs/RCSService.java b/servo/src/main/java/com/galaxis/rcs/RCSService.java index c5fb6a0..2e5d267 100644 --- a/servo/src/main/java/com/galaxis/rcs/RCSService.java +++ b/servo/src/main/java/com/galaxis/rcs/RCSService.java @@ -10,7 +10,7 @@ import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntimeService; import com.yvan.logisticsModel.StaticItem; import com.yvan.workbench.SpringContext; -import com.yvan.workbench.model.entity.LccProject; +import com.yvan.entity.LccProject; import com.yvan.workbench.service.LccMapService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; diff --git a/servo/src/main/java/com/galaxis/rcs/inv/InvManager.java b/servo/src/main/java/com/galaxis/rcs/inv/InvManager.java index 6d52ec2..df779af 100644 --- a/servo/src/main/java/com/galaxis/rcs/inv/InvManager.java +++ b/servo/src/main/java/com/galaxis/rcs/inv/InvManager.java @@ -2,6 +2,7 @@ package com.galaxis.rcs.inv; import com.galaxis.rcs.common.entity.LccInvLpn; import com.querydsl.core.util.StringUtils; +import org.clever.core.id.SnowFlake; import org.clever.data.jdbc.DaoFactory; import org.clever.data.jdbc.QueryDSL; @@ -15,15 +16,16 @@ public class InvManager { /** * 记录库存 - * @param envId 环境ID - * @param lpn 容器号 - * @param locCode 库位号 + * + * @param envId 环境ID + * @param lpn 容器号 + * @param locCode 库位号 * @param layerIndex 堆叠层 - * @param qty 数量 >0 增加数量 <0 减数量 - * @param qtyIn 入库数量 >0 减数量 <0 减数量 - * @param qtyOut 出库数量 >0 减数量 <0 减数量 + * @param qty 数量 >0 增加数量 <0 减数量 + * @param qtyIn 入库数量 >0 减数量 <0 减数量 + * @param qtyOut 出库数量 >0 减数量 <0 减数量 */ - public static void invSave(Long envId, String lpn, String locCode, Integer layerIndex, int qty, int qtyIn, int qtyOut) { + public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, Integer layerIndex, int qty, int qtyIn, int qtyOut) { if (envId == null || envId <= 0 || lpn == null || StringUtils.isNullOrEmpty(lpn) || lpn.equals("N/A") || locCode == null || StringUtils.isNullOrEmpty(locCode) || locCode.equals("N/A") @@ -73,98 +75,117 @@ public class InvManager { } } - queryDSL.beginTX(status -> { - if (lccInvLpnData != null) { - queryDSL.update(lccInvLpn) - .set(lccInvLpn.qty, lccInvLpn.qty.add(qty)) - .set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn)) - .set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut)) - .set(lccInvLpn.layerIndex, layerIndex) -// .set(lccInvLpn.updateAt, ) - .where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn))) - .execute(); - // 记录账页 - queryDSL.insert(lccInvLedger) - .set(lccInvLedger.envId, envId) - .set(lccInvLedger.lpn, lpn) - .set(lccInvLedger.locCode, locCode) - .set(lccInvLedger.layerIndex, layerIndex) - .set(lccInvLedger.qtyChange, qty) - .set(lccInvLedger.qtyInChange, qtyIn) - .set(lccInvLedger.qtyOutChange, qtyOut) - .set(lccInvLedger.qty, lccInvLpnData.getQty() + qty) - .set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn) - .set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + qtyOut) - .set(lccInvLedger.ledgerType, "记账") - .set(lccInvLedger.ledgerRemark, "N/A") - .execute(); - } else { - queryDSL.insert(lccInvLpn) - .set(lccInvLpn.envId, envId) - .set(lccInvLpn.lpn, lpn) - .set(lccInvLpn.locCode, locCode) - .set(lccInvLpn.layerIndex, layerIndex) - .set(lccInvLpn.qty, qty) - .set(lccInvLpn.qtyIn, qtyIn) - .set(lccInvLpn.qtyOut, qtyOut) - .execute(); - // 记录账页 - queryDSL.insert(lccInvLedger) - .set(lccInvLedger.envId, envId) - .set(lccInvLedger.lpn, lpn) - .set(lccInvLedger.locCode, locCode) - .set(lccInvLedger.layerIndex, layerIndex) - .set(lccInvLedger.qtyChange, qty) - .set(lccInvLedger.qtyInChange, qtyIn) - .set(lccInvLedger.qtyOutChange, qtyOut) - .set(lccInvLedger.qty, qty) - .set(lccInvLedger.qtyIn, qtyIn) - .set(lccInvLedger.qtyOut, qtyOut) - .set(lccInvLedger.ledgerType, "记账") - .set(lccInvLedger.ledgerRemark, "N/A") - .execute(); - } - // 删除所有数量预占预扣都为0的库存 - queryDSL.delete(lccInvLpn).where(lccInvLpn.qty.eq(0).and(lccInvLpn.qtyIn.eq(0)).and(lccInvLpn.qtyOut.eq(0))).execute(); - }); + + if (lccInvLpnData != null) { + queryDSL.update(lccInvLpn) + .set(lccInvLpn.qty, lccInvLpn.qty.add(qty)) + .set(lccInvLpn.qtyIn, lccInvLpn.qtyIn.add(qtyIn)) + .set(lccInvLpn.qtyOut, lccInvLpn.qtyOut.add(qtyOut)) + .set(lccInvLpn.layerIndex, layerIndex) + .set(lccInvLpn.updateAt, new Date(System.currentTimeMillis())) + .set(lccInvLpn.updateBy, "system") + .where(lccInvLpn.envId.eq(envId).and(lccInvLpn.locCode.eq(locCode)).and(lccInvLpn.lpn.eq(lpn))) + .execute(); + // 记录账页 + queryDSL.insert(lccInvLedger) + .set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId()) + .set(lccInvLedger.envId, envId) + .set(lccInvLedger.lpn, lpn) + .set(lccInvLedger.bizTaskId, bizTaskId) + .set(lccInvLedger.locCode, locCode) + .set(lccInvLedger.layerIndex, layerIndex) + .set(lccInvLedger.qtyChange, qty) + .set(lccInvLedger.qtyInChange, qtyIn) + .set(lccInvLedger.qtyOutChange, qtyOut) + .set(lccInvLedger.qty, lccInvLpnData.getQty() + qty) + .set(lccInvLedger.qtyIn, lccInvLpnData.getQtyIn() + qtyIn) + .set(lccInvLedger.qtyOut, lccInvLpnData.getQtyOut() + qtyOut) + .set(lccInvLedger.ledgerType, "记账") + .set(lccInvLedger.ledgerRemark, "N/A") + .set(lccInvLedger.createAt, new Date(System.currentTimeMillis())) + .set(lccInvLedger.createBy, "system") + .set(lccInvLedger.updateAt, new Date(System.currentTimeMillis())) + .set(lccInvLedger.updateBy, "system") + .execute(); + } else { + queryDSL.insert(lccInvLpn) + .set(lccInvLpn.envId, envId) + .set(lccInvLpn.lpn, lpn) + .set(lccInvLpn.locCode, locCode) + .set(lccInvLpn.layerIndex, layerIndex) + .set(lccInvLpn.qty, qty) + .set(lccInvLpn.qtyIn, qtyIn) + .set(lccInvLpn.qtyOut, qtyOut) + .set(lccInvLpn.createAt, new Date(System.currentTimeMillis())) + .set(lccInvLpn.createBy, "system") + .set(lccInvLpn.updateAt, new Date(System.currentTimeMillis())) + .set(lccInvLpn.updateBy, "system") + .execute(); + // 记录账页 + queryDSL.insert(lccInvLedger) + .set(lccInvLedger.ledgerId, SnowFlake.SNOW_FLAKE.nextId()) + .set(lccInvLedger.envId, envId) + .set(lccInvLedger.lpn, lpn) + .set(lccInvLedger.bizTaskId, bizTaskId) + .set(lccInvLedger.locCode, locCode) + .set(lccInvLedger.layerIndex, layerIndex) + .set(lccInvLedger.qtyChange, qty) + .set(lccInvLedger.qtyInChange, qtyIn) + .set(lccInvLedger.qtyOutChange, qtyOut) + .set(lccInvLedger.qty, qty) + .set(lccInvLedger.qtyIn, qtyIn) + .set(lccInvLedger.qtyOut, qtyOut) + .set(lccInvLedger.ledgerType, "记账") + .set(lccInvLedger.ledgerRemark, "N/A") + .set(lccInvLedger.createAt, new Date(System.currentTimeMillis())) + .set(lccInvLedger.createBy, "system") + .set(lccInvLedger.updateAt, new Date(System.currentTimeMillis())) + .set(lccInvLedger.updateBy, "system") + .execute(); + } + // 删除所有数量预占预扣都为0的库存 + queryDSL.delete(lccInvLpn).where(lccInvLpn.qty.eq(0).and(lccInvLpn.qtyIn.eq(0)).and(lccInvLpn.qtyOut.eq(0))).execute(); } /** * 记录库存 - * @param envId 环境ID - * @param lpn 容器号 + * + * @param envId 环境ID + * @param lpn 容器号 * @param locCode 库位号 - * @param qty 数量 >0 减数量 <0 减数量 - * @param qtyIn 入库数量 >0 减数量 <0 减数量 - * @param qtyOut 出库数量 >0 减数量 <0 减数量 + * @param qty 数量 >0 减数量 <0 减数量 + * @param qtyIn 入库数量 >0 减数量 <0 减数量 + * @param qtyOut 出库数量 >0 减数量 <0 减数量 */ - public static void invSave(Long envId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) { - invSave(envId, lpn, locCode, 0, qty, qtyIn, qtyOut); + public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty, int qtyIn, int qtyOut) { + invSave(envId, bizTaskId, lpn, locCode, 0, qty, qtyIn, qtyOut); } /** * 保存库存 - * @param envId 环境ID - * @param lpn 容器号 - * @param locCode 库位号 + * + * @param envId 环境ID + * @param lpn 容器号 + * @param locCode 库位号 * @param layerIndex 堆叠层 - * @param qty 数量 >0 减数量 <0 减数量 + * @param qty 数量 >0 减数量 <0 减数量 */ - public static void invSave(Long envId, String lpn, String locCode, int layerIndex, int qty) { - invSave(envId, lpn, locCode, layerIndex, qty, 0, 0); + public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int layerIndex, int qty) { + invSave(envId, bizTaskId, lpn, locCode, layerIndex, qty, 0, 0); } /** * 保存库存 - * @param envId 环境ID - * @param lpn 容器号 + * + * @param envId 环境ID + * @param lpn 容器号 * @param locCode 库位号 - * @param qty 数量 >0 减数量 <0 减数量 + * @param qty 数量 >0 减数量 <0 减数量 */ - public static void invSave(Long envId, String lpn, String locCode, int qty) { - invSave(envId, lpn, locCode, 0, qty, 0, 0); + public static void invSave(Long envId, Long bizTaskId, String lpn, String locCode, int qty) { + invSave(envId, bizTaskId, lpn, locCode, 0, qty, 0, 0); } } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java index b73e4d6..34cbac7 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/PlanTaskSequence.java @@ -6,12 +6,10 @@ import com.galaxis.rcs.common.entity.RcsTaskPlan; import com.galaxis.rcs.common.enums.PlanTaskStatus; import com.galaxis.rcs.common.enums.PlanTaskType; import com.google.common.base.Joiner; -import com.google.common.base.Splitter; import com.google.common.collect.Lists; +import com.yvan.entity.BasLocationVo; import com.yvan.logisticsModel.LogisticsRuntime; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.clever.core.BannerUtils; import org.clever.core.id.SnowFlake; import org.clever.core.json.JsonWrapper; @@ -33,7 +31,12 @@ public class PlanTaskSequence { public String lastWayPointId; public Float lastRotationAngle = null; - public String lastLoadLpn = ""; + + public String carryLpn; + public BasLocationVo loadBasLocationVo; + public BasLocationVo unloadBasLocationVo; + public BasLocationVo executorVo; + public int carryQty; public PlanTaskSequence(String executorId, LogisticsRuntime logisticsRuntime, RcsTaskBiz bizTask, String createBy) { this.executorId = executorId; @@ -90,13 +93,12 @@ public class PlanTaskSequence { } // 添加取货动作 - public RcsTaskPlan addLoad(String lpn, String rackId, int bay, int level, int cell) { + public RcsTaskPlan addLoad( String rackId, int bay, int level, int cell) { RcsTaskPlan task = this.createTaskPlanEntity(PlanTaskType.LOAD.toString()); task.setTargetId(rackId); task.setTargetBay(bay); task.setTargetLevel(level); task.setTargetCell(cell); - this.lastLoadLpn = lpn; return task; } @@ -107,7 +109,6 @@ public class PlanTaskSequence { task.setTargetBay(bay); task.setTargetLevel(level); task.setTargetCell(cell); - this.lastLoadLpn = ""; return task; } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/path/PtrPathPlanner.java b/servo/src/main/java/com/galaxis/rcs/plan/path/PtrPathPlanner.java index 17f2cb4..d6f82a5 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/path/PtrPathPlanner.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/path/PtrPathPlanner.java @@ -123,7 +123,7 @@ public class PtrPathPlanner { // 生成指令序列 generateMoves(plan, toLoadPath); - plan.addLoad(task.lpn(), loadRackId, pickupBay, task.from().level(), task.from().cell()); + plan.addLoad(loadRackId, pickupBay, task.from().level(), task.from().cell()); generateMoves(plan, toUnloadPath); plan.addUnload(unloadRackId, task.to().level(), task.to().bay(), task.to().cell()); @@ -218,7 +218,7 @@ public class PtrPathPlanner { // 生成指令序列 generateMoves(plan, toLoadPath); - plan.addLoad("N/A", loadRackId, task.to().level(), task.to().bay(), task.to().cell()); + plan.addLoad(loadRackId, task.to().level(), task.to().bay(), task.to().cell()); plan.addFinish(); } diff --git a/servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java b/servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java index 8a49546..ced33af 100644 --- a/servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java +++ b/servo/src/main/java/com/galaxis/rcs/plan/task/CarryTask.java @@ -26,7 +26,6 @@ import com.galaxis.rcs.common.entity.StoreLocation; */ public record CarryTask( String agv, - String lpn, int priority, StoreLocation from, StoreLocation to diff --git a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java index 15dea96..f4e7b0f 100644 --- a/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java +++ b/servo/src/main/java/com/galaxis/rcs/ptr/PtrAgvItem.java @@ -136,6 +136,19 @@ public abstract class PtrAgvItem extends ExecutorItem { public synchronized void dispatchTask(PlanTaskSequence taskSequence) { if (!isFree()) { + if (!this.runtime.isRunning()) { + throw new IllegalStateException("runtime is not running!"); + } + if (planTaskSequence != null && !planTaskSequence.isAllCompleted()) { + throw new IllegalStateException("AGV is busy with an existing task sequence"); + } + if (!deviceTaskQueue.isEmpty()) { + throw new IllegalStateException("AGV has pending device tasks in the queue"); + } + if (!isOnline) { + throw new IllegalStateException("AGV is not online and cannot accept new tasks"); + } + throw new IllegalStateException("AGV is not free to accept new tasks"); } diff --git a/servo/src/main/java/com/yvan/entity/BasLocationVo.java b/servo/src/main/java/com/yvan/entity/BasLocationVo.java new file mode 100644 index 0000000..bb703de --- /dev/null +++ b/servo/src/main/java/com/yvan/entity/BasLocationVo.java @@ -0,0 +1,60 @@ +package com.yvan.entity; + +import com.galaxis.rcs.common.entity.LccBasLocation; +import com.yvan.logisticsModel.ExecutorItem; +import lombok.Data; + +/** + * 用于表示货位的值对象 + */ +@Data +public class BasLocationVo { + /** + * 位置编码 + */ + String locCode; + + /** + * 货位类型 + */ + String locType; + + /** + * 货位 + */ + String rack; + + /** + * 列 + */ + int bay; + + /** + * 层 + */ + int level; + + /** + * 格 + */ + int cell; + + public BasLocationVo(LccBasLocation basLocation) { + this.locCode = basLocation.getLocCode(); + this.locType = basLocation.getLocType(); + this.rack = basLocation.getRack(); + this.bay = basLocation.getBay(); + this.level = basLocation.getLevel(); + this.cell = basLocation.getCell(); + } + + public BasLocationVo(ExecutorItem executorItem) { + // 从 ExecutorItem 中提取信息并赋值给 BasLocationVo + this.locCode = "AGV_" + executorItem.getId(); + this.locType = executorItem.getT(); + this.rack = "N/A"; + this.bay = 0; + this.level = 0; + this.cell = 0; + } +} diff --git a/servo/src/main/java/com/yvan/workbench/model/entity/LccProject.java b/servo/src/main/java/com/yvan/entity/LccProject.java similarity index 93% rename from servo/src/main/java/com/yvan/workbench/model/entity/LccProject.java rename to servo/src/main/java/com/yvan/entity/LccProject.java index 9bc29be..93b33cc 100644 --- a/servo/src/main/java/com/yvan/workbench/model/entity/LccProject.java +++ b/servo/src/main/java/com/yvan/entity/LccProject.java @@ -1,4 +1,4 @@ -package com.yvan.workbench.model.entity; +package com.yvan.entity; import lombok.Data; diff --git a/servo/src/main/java/com/yvan/workbench/model/entity/LccProjectEnv.java b/servo/src/main/java/com/yvan/entity/LccProjectEnv.java similarity index 86% rename from servo/src/main/java/com/yvan/workbench/model/entity/LccProjectEnv.java rename to servo/src/main/java/com/yvan/entity/LccProjectEnv.java index 9e9fe5f..0c64b9f 100644 --- a/servo/src/main/java/com/yvan/workbench/model/entity/LccProjectEnv.java +++ b/servo/src/main/java/com/yvan/entity/LccProjectEnv.java @@ -1,4 +1,4 @@ -package com.yvan.workbench.model.entity; +package com.yvan.entity; import com.yvan.logisticsEnv.EnvConfig; import lombok.Data; diff --git a/servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java b/servo/src/main/java/com/yvan/entity/Vector2.java similarity index 74% rename from servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java rename to servo/src/main/java/com/yvan/entity/Vector2.java index c81c29a..8c8e646 100644 --- a/servo/src/main/java/com/yvan/workbench/model/entity/Vector2.java +++ b/servo/src/main/java/com/yvan/entity/Vector2.java @@ -1,4 +1,4 @@ -package com.yvan.workbench.model.entity; +package com.yvan.entity; public record Vector2( /** diff --git a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java index cfc54fa..00a720f 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java +++ b/servo/src/main/java/com/yvan/logisticsModel/ExecutorItem.java @@ -1,14 +1,8 @@ package com.yvan.logisticsModel; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.galaxis.rcs.common.entity.RcsTaskPlan; import com.galaxis.rcs.plan.PlanTaskSequence; -import com.google.common.collect.Queues; -import com.yvan.workbench.model.entity.Vector2; import java.util.Map; -import java.util.Queue; -import java.util.concurrent.BlockingQueue; /** * 物流任务执行单元(如拣货台、小车、AGV、堆垛机、人等) diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java index 069c961..e471c72 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntime.java @@ -1,6 +1,10 @@ package com.yvan.logisticsModel; +import com.galaxis.rcs.common.entity.RcsTaskPlan; +import com.galaxis.rcs.common.enums.PlanTaskType; import com.galaxis.rcs.connector.cl2.Cl2Item; +import com.galaxis.rcs.inv.InvManager; +import com.galaxis.rcs.plan.PlanTaskSequence; import com.galaxis.rcs.plan.path.NavigationGraph; import com.galaxis.rcs.plan.path.PtrPathPlanner; import com.galaxis.rcs.ptr.AmrMessageHandler; @@ -12,26 +16,27 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.yvan.event.AgvEventManager; import com.yvan.event.AgvEventType; -import com.yvan.mqtt.FrontendMessagePushService; +import com.yvan.pusher.FrontendMessagePushService; import com.yvan.redis.LccRedisService; -import com.yvan.workbench.model.entity.LccProject; -import com.yvan.workbench.model.entity.LccProjectEnv; +import com.yvan.entity.LccProject; +import com.yvan.entity.LccProjectEnv; import lombok.extern.slf4j.Slf4j; import org.clever.core.BannerUtils; import org.clever.core.Conv; +import org.clever.data.jdbc.DaoFactory; +import org.clever.data.jdbc.QueryDSL; import org.clever.data.redis.Redis; import org.clever.data.redis.RedisAdmin; -import java.util.Date; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * 物流运行时 */ @Slf4j public class LogisticsRuntime { + public final QueryDSL queryDSL = DaoFactory.getQueryDSL(); + /** * 项目UUID */ @@ -134,12 +139,53 @@ public class LogisticsRuntime { for (int i = 1; i < args.length; i++) { eventArgs[i - 1] = Conv.asString(args[i]); } + if (type == AgvEventType.PLAN_TASK_COMPLETE) { + PlanTaskSequence taskSequence = (PlanTaskSequence) args[1]; + RcsTaskPlan taskPlan = (RcsTaskPlan) args[2]; + PlanTaskType planType = PlanTaskType.valueOf(taskPlan.getPlanType()); + if (planType == PlanTaskType.LOAD) { + // 处理库存变化 rack-> agv + changeInvOfLoad(taskSequence, taskPlan); + } else if (planType == PlanTaskType.UNLOAD) { + // 处理库存变化 agv -> rack + changeInvOfUnload(taskSequence, taskPlan); + } + + } BannerUtils.printConfig(log, this.projectUuid + "(" + this.envId + ") " + type + " AGV:" + sender.getId(), eventArgs); }); } /** + * 库存转移 AGV->货架 + */ + private void changeInvOfUnload(PlanTaskSequence taskSequence, RcsTaskPlan taskPlan) { + queryDSL.beginTX(status -> { + String lpn = taskSequence.carryLpn; + + InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.executorVo.getLocCode(), -taskSequence.carryQty); + InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.unloadBasLocationVo.getLocCode(), taskSequence.carryQty); + + this.frontendMessagePushService.pushInventoryUpdate(lpn, taskSequence.executorVo, taskSequence.unloadBasLocationVo, taskSequence.carryQty); + }); + } + + /** + * 库存转移 货架->AGV + */ + private void changeInvOfLoad(PlanTaskSequence taskSequence, RcsTaskPlan taskPlan) { + queryDSL.beginTX(status -> { + String lpn = taskSequence.carryLpn; + + InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.loadBasLocationVo.getLocCode(), -taskSequence.carryQty); + InvManager.invSave(this.envId, taskSequence.bizTask.getBizTaskId(), lpn, taskSequence.executorVo.getLocCode(), taskSequence.carryQty); + + this.frontendMessagePushService.pushInventoryUpdate(lpn, taskSequence.loadBasLocationVo, taskSequence.executorVo, taskSequence.carryQty); + }); + } + + /** * 获取当前空闲的执行器列表 */ public List getFreeExecutorList() { diff --git a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java index 274c4a0..21c811f 100644 --- a/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java +++ b/servo/src/main/java/com/yvan/logisticsModel/LogisticsRuntimeService.java @@ -1,8 +1,8 @@ package com.yvan.logisticsModel; import com.google.common.collect.Maps; -import com.yvan.workbench.model.entity.LccProject; -import com.yvan.workbench.model.entity.LccProjectEnv; +import com.yvan.entity.LccProject; +import com.yvan.entity.LccProjectEnv; import lombok.SneakyThrows; import java.net.InetAddress; diff --git a/servo/src/main/java/com/yvan/mqtt/FrontendMessagePushService.java b/servo/src/main/java/com/yvan/pusher/FrontendMessagePushService.java similarity index 96% rename from servo/src/main/java/com/yvan/mqtt/FrontendMessagePushService.java rename to servo/src/main/java/com/yvan/pusher/FrontendMessagePushService.java index a22c7c5..c58ddff 100644 --- a/servo/src/main/java/com/yvan/mqtt/FrontendMessagePushService.java +++ b/servo/src/main/java/com/yvan/pusher/FrontendMessagePushService.java @@ -1,5 +1,6 @@ -package com.yvan.mqtt; +package com.yvan.pusher; +import com.yvan.entity.BasLocationVo; import com.yvan.logisticsEnv.EnvConfig; import com.yvan.logisticsModel.LogisticsRuntime; import lombok.Getter; @@ -165,18 +166,20 @@ public class FrontendMessagePushService implements MqttCallback { /** * 推送库存更新 - * /lcc/{proj_id}/{env_id}/inv/{catalogCode} + * /lcc/{proj_id}/{env_id}/inv * - * @param catalogCode 货位目录编码 - * @param before 更新前库存 - * @param after 更新后库存 + * @param lpn 容器号 + * @param before 更新前库存 + * @param after 更新后库存 */ - public void pushInventoryUpdate(String catalogCode, Object before, Object after) { - String topic = buildTopic("inv/" + catalogCode); + public void pushInventoryUpdate(String lpn, BasLocationVo before, BasLocationVo after, int qty) { + String topic = buildTopic("inv"); Map data = new HashMap<>(); + data.put("lpn", lpn); data.put("before", before); data.put("after", after); + data.put("qty", qty); publishJson(topic, data); } diff --git a/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java b/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java index 6107a1c..cec4143 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java +++ b/servo/src/main/java/com/yvan/workbench/controller/LccModelManager.java @@ -4,7 +4,7 @@ import com.galaxis.rcs.common.entity.LccBasLocation; import com.galaxis.rcs.common.entity.StoreLocation; import com.galaxis.rcs.ptr.JacksonUtils; import com.yvan.workbench.SpringContext; -import com.yvan.workbench.model.entity.LccProject; +import com.yvan.entity.LccProject; import com.yvan.workbench.service.LccMapService; import jakarta.servlet.http.HttpServletResponse; import lombok.SneakyThrows; diff --git a/servo/src/main/java/com/yvan/workbench/controller/RcsController.java b/servo/src/main/java/com/yvan/workbench/controller/RcsController.java index 1db96a6..f82aa07 100644 --- a/servo/src/main/java/com/yvan/workbench/controller/RcsController.java +++ b/servo/src/main/java/com/yvan/workbench/controller/RcsController.java @@ -1,6 +1,6 @@ package com.yvan.workbench.controller; -import com.galaxis.rcs.RCSService; +import com.galaxis.rcs.common.entity.LccBasLocation; import com.galaxis.rcs.common.entity.RcsTaskBiz; import com.galaxis.rcs.common.entity.StoreLocation; import com.galaxis.rcs.common.enums.BizTaskStatus; @@ -11,6 +11,7 @@ import com.galaxis.rcs.plan.task.*; import com.galaxis.rcs.ptr.PtrAgvItem; import com.google.common.base.Strings; import com.google.common.collect.Maps; +import com.yvan.entity.BasLocationVo; import com.yvan.logisticsModel.ExecutorItem; import com.yvan.logisticsModel.LogisticsRuntime; import com.yvan.logisticsModel.LogisticsRuntimeService; @@ -22,6 +23,9 @@ import org.clever.web.mvc.annotation.RequestBody; import java.util.Map; +import static com.galaxis.rcs.common.query.QLccBasLocation.lccBasLocation; +import static com.galaxis.rcs.common.query.QLccInvLpn.lccInvLpn; + public class RcsController { static final SnowFlake snowFlake = new SnowFlake(); @@ -130,6 +134,101 @@ public class RcsController { return R.success(executorItem); } + public static R agvCarry(@RequestBody Map params) { + Object ret = getCommonParamAndCreateBizTask(params); + if (ret instanceof R) { + // 异常 + return (R) ret; + } + RcsCommonParam ps = (RcsCommonParam) ret; + + + // ==================== 查找来源货位 ==================== + String fromStoreLoc = Conv.asString(params.get("fromStoreLoc")); + if (Strings.isNullOrEmpty(fromStoreLoc)) { + return R.fail("fromStoreLoc Must not be empty"); + } + StoreLocation sourceLocation = StoreLocation.of(fromStoreLoc, "/"); + StaticItem sourceItem = ps.runtime.getStaticItemById(sourceLocation.rackId()); + if (sourceItem == null) { + return R.fail("fromStoreLoc storePoint not found!"); + } + // 查找货位基础资料 + LccBasLocation loadBasLocation = ps.runtime.queryDSL.selectFrom( + lccBasLocation + ) + .where(lccBasLocation.envId.eq(ps.envId)) + .where(lccBasLocation.rack.eq(sourceLocation.rackId())) + .where(lccBasLocation.bay.eq(sourceLocation.bay())) + .where(lccBasLocation.level.eq(sourceLocation.level())) + .where(lccBasLocation.cell.eq(sourceLocation.cell())) + .fetchFirst(); + if (loadBasLocation == null) { + return R.fail("fromStoreLoc location not found!"); + } + + + // ==================== 查找卸货货位 ==================== + String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); + if (Strings.isNullOrEmpty(targetStoreLoc)) { + return R.fail("targetStoreLoc Must not be empty"); + } + StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); + StaticItem targetItem = ps.runtime.getStaticItemById(targetLocation.rackId()); + if (targetItem == null) { + return R.fail("targetStoreLoc storePoint not found!"); + } + // 查找货位基础资料 + LccBasLocation unloadBasLocation = ps.runtime.queryDSL.selectFrom( + lccBasLocation + ) + .where(lccBasLocation.envId.eq(ps.envId)) + .where(lccBasLocation.rack.eq(targetLocation.rackId())) + .where(lccBasLocation.bay.eq(targetLocation.bay())) + .where(lccBasLocation.level.eq(targetLocation.level())) + .where(lccBasLocation.cell.eq(targetLocation.cell())) + .fetchFirst(); + if (unloadBasLocation == null) { + return R.fail("targetStoreLoc location not found!"); + } + + // ==================== 找到托盘号 ==================== + String lpn = ps.runtime.queryDSL + .select(lccInvLpn.lpn) + .from(lccInvLpn) + .where(lccInvLpn.envId.eq(ps.envId)) + .where(lccInvLpn.locCode.eq(loadBasLocation.getLocCode())) + .fetchFirst(); + if (Strings.isNullOrEmpty(lpn)) { + return R.fail("LPN not found at fromStoreLoc: " + fromStoreLoc); + } + + // ==================== 布置任务 ==================== + ps.bizTask.setLpn(lpn); + ps.bizTask.setTaskFrom(loadBasLocation.getCatalogCode()); + ps.bizTask.setTaskTo(unloadBasLocation.getLocCode()); + + CarryTask carryTask = new CarryTask( + ps.agvId, ps.bizTask.getPriority(), + sourceLocation, + targetLocation + ); + ps.planSequence.executorVo = new BasLocationVo(ps.agv); + ps.planSequence.loadBasLocationVo = new BasLocationVo(loadBasLocation); + ps.planSequence.unloadBasLocationVo = new BasLocationVo(unloadBasLocation); + ps.planSequence.carryLpn = lpn; + ps.planSequence.carryQty = 1; + + ps.runtime.pathPlannerMap.get(ps.agv.getT()) + .planCarryTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, carryTask); + + ps.agv.logicX = ps.fromItem.logicX; + ps.agv.logicY = ps.fromItem.logicY; + ps.agv.dispatchTask(ps.planSequence); + + return R.success(ps.planSequence.toPrettyMap()); + } + public static R agvUnload(@RequestBody Map params) { Object ret = getCommonParamAndCreateBizTask(params); if (ret instanceof R) { @@ -138,16 +237,52 @@ public class RcsController { } RcsCommonParam ps = (RcsCommonParam) ret; + // ==================== 查找卸货货位 ==================== String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); if (Strings.isNullOrEmpty(targetStoreLoc)) { return R.fail("targetStoreLoc Must not be empty"); } StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); + // 查找货位基础资料 + LccBasLocation unloadBasLocation = ps.runtime.queryDSL.selectFrom( + lccBasLocation + ) + .where(lccBasLocation.envId.eq(ps.envId)) + .where(lccBasLocation.rack.eq(targetLocation.rackId())) + .where(lccBasLocation.bay.eq(targetLocation.bay())) + .where(lccBasLocation.level.eq(targetLocation.level())) + .where(lccBasLocation.cell.eq(targetLocation.cell())) + .fetchFirst(); + if (unloadBasLocation == null) { + return R.fail("targetStoreLoc location not found!"); + } + + // ==================== 找到托盘号 ==================== + BasLocationVo executorVo = new BasLocationVo(ps.agv); + String lpn = ps.runtime.queryDSL + .select(lccInvLpn.lpn) + .from(lccInvLpn) + .where(lccInvLpn.envId.eq(ps.envId)) + .where(lccInvLpn.locCode.eq(executorVo.getLocCode())) + .fetchFirst(); + if (Strings.isNullOrEmpty(lpn)) { + return R.fail("LPN not found at StoreLoc: " + executorVo.getLocCode()); + } + + // ==================== 布置任务 ==================== + ps.bizTask.setLpn(lpn); + ps.bizTask.setTaskFrom(ps.fromItem.getId()); + ps.bizTask.setTaskTo(unloadBasLocation.getLocCode()); UnloadTask unloadTask = new UnloadTask( ps.agvId, ps.bizTask.getPriority(), targetLocation ); + ps.planSequence.executorVo = executorVo; + ps.planSequence.loadBasLocationVo = null; + ps.planSequence.unloadBasLocationVo = new BasLocationVo(unloadBasLocation); + ps.planSequence.carryLpn = lpn; + ps.planSequence.carryQty = 1; ps.runtime.pathPlannerMap.get(ps.agv.getT()) .planUnloadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, unloadTask); @@ -167,16 +302,51 @@ public class RcsController { } RcsCommonParam ps = (RcsCommonParam) ret; + // ==================== 查找来源货位 ==================== String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); if (Strings.isNullOrEmpty(targetStoreLoc)) { return R.fail("targetStoreLoc Must not be empty"); } StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); + // 查找货位基础资料 + LccBasLocation loadBasLocation = ps.runtime.queryDSL.selectFrom( + lccBasLocation + ) + .where(lccBasLocation.envId.eq(ps.envId)) + .where(lccBasLocation.rack.eq(targetLocation.rackId())) + .where(lccBasLocation.bay.eq(targetLocation.bay())) + .where(lccBasLocation.level.eq(targetLocation.level())) + .where(lccBasLocation.cell.eq(targetLocation.cell())) + .fetchFirst(); + if (loadBasLocation == null) { + return R.fail("targetStoreLoc location not found!"); + } + + // ==================== 找到托盘号 ==================== + String lpn = ps.runtime.queryDSL + .select(lccInvLpn.lpn) + .from(lccInvLpn) + .where(lccInvLpn.envId.eq(ps.envId)) + .where(lccInvLpn.locCode.eq(loadBasLocation.getLocCode())) + .fetchFirst(); + if (Strings.isNullOrEmpty(lpn)) { + return R.fail("LPN not found at targetStoreLoc: " + loadBasLocation.getLocCode()); + } + + // ==================== 布置任务 ==================== + ps.bizTask.setLpn(lpn); + ps.bizTask.setTaskFrom(ps.fromItem.getId()); + ps.bizTask.setTaskTo(loadBasLocation.getLocCode()); LoadTask loadTask = new LoadTask( ps.agvId, ps.bizTask.getPriority(), targetLocation ); + ps.planSequence.executorVo = new BasLocationVo(ps.agv); + ps.planSequence.loadBasLocationVo = new BasLocationVo(loadBasLocation); + ps.planSequence.unloadBasLocationVo = null; + ps.planSequence.carryLpn = lpn; + ps.planSequence.carryQty = 1; ps.runtime.pathPlannerMap.get(ps.agv.getT()) .planLoadTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, loadTask); @@ -224,56 +394,6 @@ public class RcsController { return R.success(cost); } - public static R agvCarry(@RequestBody Map params) { - Object ret = getCommonParamAndCreateBizTask(params); - if (ret instanceof R) { - // 异常 - return (R) ret; - } - RcsCommonParam ps = (RcsCommonParam) ret; - - String fromStoreLoc = Conv.asString(params.get("fromStoreLoc")); - String targetStoreLoc = Conv.asString(params.get("targetStoreLoc")); - - if (Strings.isNullOrEmpty(fromStoreLoc)) { - return R.fail("fromStoreLoc Must not be empty"); - } - if (Strings.isNullOrEmpty(targetStoreLoc)) { - return R.fail("targetStoreLoc Must not be empty"); - } - - StoreLocation sourceLocation = StoreLocation.of(fromStoreLoc, "/"); - StoreLocation targetLocation = StoreLocation.of(targetStoreLoc, "/"); - - StaticItem sourceItem = ps.runtime.getStaticItemById(sourceLocation.rackId()); - if (sourceItem == null) { - return R.fail("fromStoreLoc storePoint not found!"); - } - StaticItem targetItem = ps.runtime.getStaticItemById(targetLocation.rackId()); - if (targetItem == null) { - return R.fail("targetStoreLoc storePoint not found!"); - } - - ps.bizTask.setTaskFrom(fromStoreLoc); - ps.bizTask.setTaskTo(targetStoreLoc); - - CarryTask carryTask = new CarryTask( - ps.agvId, "N/A", ps.bizTask.getPriority(), - sourceLocation, - targetLocation - ); - - ps.runtime.pathPlannerMap.get(ps.agv.getT()) - .planCarryTask(ps.planSequence, ps.fromItem.getId(), ps.fromDirection, carryTask); - - ps.agv.logicX = ps.fromItem.logicX; - ps.agv.logicY = ps.fromItem.logicY; - ps.agv.dispatchTask(ps.planSequence); - - return R.success(ps.planSequence.toPrettyMap()); - } - - public static Object getCommonParamAndCreateBizTask(@RequestBody Map params) { String projectUUID = Conv.asString(params.get("projectUUID")); Long envId = Conv.asLong(params.get("envId")); diff --git a/servo/src/main/java/com/yvan/workbench/service/LccMapService.java b/servo/src/main/java/com/yvan/workbench/service/LccMapService.java index 554c62b..c0f31c3 100644 --- a/servo/src/main/java/com/yvan/workbench/service/LccMapService.java +++ b/servo/src/main/java/com/yvan/workbench/service/LccMapService.java @@ -1,21 +1,18 @@ package com.yvan.workbench.service; -import com.google.common.base.Joiner; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.yvan.LccUtils; import com.yvan.workbench.autoconfigure.LccConfigProperties; -import com.yvan.workbench.model.entity.LccProject; -import com.yvan.workbench.model.entity.LccProjectEnv; +import com.yvan.entity.LccProject; +import com.yvan.entity.LccProjectEnv; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.clever.core.Conv; import org.clever.core.mapper.JacksonMapper; import java.io.File; -import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import java.util.Objects;