完善料箱库资源锁定逻辑,出入库都检查资源锁定,在任务下发wcs时锁定资源,任务完成时释放

This commit is contained in:
李宇奇 2025-07-26 12:56:25 +08:00
parent 218946ab0b
commit 107f658af7
8 changed files with 94 additions and 71 deletions

View File

@ -7,8 +7,8 @@ POST {{baseUrl}}/mywms/orderIn
Content-Type: application/json
{
"taskId": "testOrderId6",
"vehicleNo": "1006"
"taskId": "testOrderId9",
"vehicleNo": "1009"
}
### 2. 出库订单接口
@ -17,7 +17,7 @@ Content-Type: application/json
{
"taskId": "testOrderId1",
"vehicleNo": "1004"
"vehicleNo": "1001"
}
### 3. 库存查询接口 - 仅按载具查询

View File

@ -8,7 +8,7 @@ Content-Type: application/json
{
"origin": "R1",
"vehicleNo": "1006",
"vehicleNo": "1009",
"codeMessage": "test",
"remark": "载具入库测试"
}
@ -18,10 +18,10 @@ POST {{baseUrl}}/wms/task/sendTaskResult
Content-Type: application/json
{
"taskId": "1753403954324010001",
"taskId": "1753505539367010001",
"taskStatus": 100,
"vehicleNo": "1004",
"destination": "C1",
"vehicleNo": "1001",
"destination": "A01-02-01-01",
"message": "任务执行成功"
}

View File

@ -412,9 +412,9 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
// } else {
// log.info("[wms]上报成功");
// }
// if (!appOrderInService.removeById(orderIn.getRecordId())) {
// log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
// }
if (!appOrderInService.removeById(orderIn.getRecordId())) {
log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
}
TAppVehicle vehicle = new TAppVehicle();
vehicle.setVehicleId(wmsTask.getVehicleId());
vehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());

View File

@ -177,36 +177,65 @@ public class MyWmsControllerServiceImpl implements IMyWmsControllerService {
@Override
public MyWmsResponse<Boolean> queryCanFeed() {
try {
// 1. 检查库位是否足够
TAppLocation location = stackerTaskService.requestOneLocation(null, L_TEMP_FLAG);
if (location != null && StringUtils.isNotEmpty(location.getLocationId())) {
if (location == null || StringUtils.isEmpty(location.getLocationId())) {
return MyWmsResponse.error("无剩余可用库位", false);
}
// 2. 调用wcs.canFeed检查wcs状态
WcsApiResponse<WcsCanFeedResponse> wcsResponse = wcsApiService.canFeed(new WcsCanFeedRequest("R1"));
if (wcsResponse == null || wcsResponse.getData() == null) {
return MyWmsResponse.error("WCS系统查询失败", false);
}
Boolean wcsAllow = wcsResponse.getData().isAllowAction();
if (!wcsAllow) {
return MyWmsResponse.error("WCS系统不允许入库", false);
}
// 3. 检查agvLock服务获取wms状态
Boolean wmsAllow = agvLockService.canFeedToInboundPort("R1");
if (!wmsAllow) {
return MyWmsResponse.error("入库口锁定中", false);
}
// 释放预占的库位
appLocationService.update(new LambdaUpdateWrapper<TAppLocation>()
.eq(TAppLocation::getLocationId, location.getLocationId())
.set(TAppLocation::getIsOccupy, 0)
.set(TAppLocation::getVehicleId, ""));
return MyWmsResponse.success(true);
} catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", false);
}
return MyWmsResponse.error("无剩余可用库位", false);
}
@Override
public MyWmsResponse<Boolean> queryCanOut() {
try {
// 1. 调用wcs.canFeed检查wcs状态 (使用R1口)
WcsApiResponse<WcsCanFeedResponse> wcsResponse = wcsApiService.canFeed(new WcsCanFeedRequest("R1"));
if (wcsResponse == null || wcsResponse.getData() == null) {
return MyWmsResponse.error("WCS系统查询失败", false);
}
if (wcsResponse != null && wcsResponse.getData() != null) {
Boolean wcsAllow = wcsResponse.getData().isAllowAction();
Boolean wmsAllow = agvLockService.canFeedToInboundPort("R1");
if (!wcsAllow) {
return MyWmsResponse.error("WCS系统不允许出库", false);
}
// 2. 检查agvLock服务获取wms状态 (使用R1口)
Boolean wmsAllow = agvLockService.canFeedToInboundPort("R1");
if (!wmsAllow) {
return MyWmsResponse.error("出库口锁定中", false);
}
if (wcsAllow && wmsAllow) {
return MyWmsResponse.success(true);
} else {
return MyWmsResponse.error("出库口锁定中", null);
}
} else {
return MyWmsResponse.error("WCS系统查询失败", null);
}
} catch (Exception e) {
return MyWmsResponse.error("系统异常,请稍后重试", null);
return MyWmsResponse.error("系统异常,请稍后重试", false);
}
}
}

View File

@ -2,17 +2,12 @@ package com.wms_main.service.controller.serviceImpl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.app.AppCommon;
import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskTypeEnums;
import com.wms_main.constant.enums.wms.*;
import com.wms_main.dao.*;
import com.wms_main.model.bo.wcs.WcsStackerTask;
import com.wms_main.model.dto.request.wcs.WcsTaskResultRequest;
import com.wms_main.model.dto.request.wcs.WcsVehicleInRequest;
import com.wms_main.model.dto.response.wcs.BaseWcsApiResponse;
import com.wms_main.model.dto.response.wcs.InTaskResp;
import com.wms_main.model.dto.response.wcs.WcsApiResponse;
import com.wms_main.model.dto.response.wcs.WcsVehicleInResponse;
import com.wms_main.model.po.*;
import com.wms_main.repository.utils.ConvertUtils;
@ -25,7 +20,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import java.time.LocalDateTime;
import java.util.*;
@ -63,12 +57,6 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
return WcsVehicleInResponse.error(String.format("条码:%s 不存在待入库的订单", vehicleNo));
}
// 检查入库口是否可用不关心具体是哪台AGV
boolean canFeed = agvLockService.canFeedToInboundPort(inboundPort);
if (!canFeed) {
return WcsVehicleInResponse.error("入库口被占用,请等待其他任务完成后再试");
}
/* 查找可用库位 */
TAppLocation useLocation = stackerTaskService.requestOneLocation(null, vehicleNo);
if (useLocation == null) {
@ -107,7 +95,6 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.RUNNING.getCode())
.set(TAppOrderIn::getUpdateTime, LocalDateTime.now())
);
agvLockService.lockInboundPort("AGV", "");
WcsVehicleInResponse success = new WcsVehicleInResponse();
success.setCode("200");
@ -160,16 +147,16 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
.set(TAppOrderIn::getOrderStatus, OrderStatusEnum.COMPLETE.getCode())
.set(TAppOrderIn::getCompleteTime, LocalDateTime.now()));
// 如果是入库任务完成释放入库口锁定
if (wmsTask != null && WmsTaskTypeEnums.IN.getCode().equals(wmsTask.getTaskType())) {
// 任务完成时释放R1口锁定box仓库出入库都使用同一个R1口
if (wmsTask != null) {
try {
String inboundPort = "R1"; // 默认入库
String port = "R1"; // box仓库统一使用R1
// 释放该入库口的所有活动锁定不关心具体是哪台AGV
int releasedCount = agvLockService.releaseAllInboundPortLocks(inboundPort);
log.info("入库任务完成,释放入库口 {} 的锁定,共释放 {} 个锁定", inboundPort, releasedCount);
// 释放该口的所有活动锁定不关心具体是哪台AGV
int releasedCount = agvLockService.releaseAllInboundPortLocks(port);
log.info("任务完成释放R1口的锁定任务类型: {}, 共释放 {} 个锁定", wmsTask.getTaskType(), releasedCount);
} catch (Exception e) {
log.error("释放入库口锁定时发生异常", e);
log.error("释放R1口锁定时发生异常", e);
}
}
// 移除wcs任务并向wcs备份表添加记录

View File

@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.constant.enums.wcs.WcsApiResponseCodeEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskStatusEnums;
import com.wms_main.constant.enums.wcs.WcsStackerTaskTypeEnums;
import com.wms_main.constant.enums.wms.WmsStackerTaskStatusEnums;
import com.wms_main.dao.ITAppTaskService;
import com.wms_main.dao.ITAppWcsTaskService;
@ -14,6 +15,7 @@ import com.wms_main.model.po.TAppTask;
import com.wms_main.model.po.TAppWcsTask;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.service.api.IWcsApiService;
import com.wms_main.service.business.IAgvLockService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
@ -43,6 +45,10 @@ public class WcsStackerTaskSender implements Job {
* Wcs接口服务
*/
private final IWcsApiService wcsApiService;
/**
* AGV锁定服务
*/
private final IAgvLockService agvLockService;
/**
* 运行定时任务
@ -55,8 +61,7 @@ public class WcsStackerTaskSender implements Job {
// 查询到所有的待下发的wcsTask并按优先级排序
List<TAppWcsTask> waitSendWcsTaskList = appWcsTaskService.list(
new LambdaQueryWrapper<TAppWcsTask>()
.eq(TAppWcsTask::getWcsTaskStatus, WcsStackerTaskStatusEnums.INIT.getCode())
);
.eq(TAppWcsTask::getWcsTaskStatus, WcsStackerTaskStatusEnums.INIT.getCode()));
// 按任务优先级排序优先级高的先发送数值大的优先级高
waitSendWcsTaskList.sort((task1, task2) -> Integer.compare(task2.getTaskPriority(), task1.getTaskPriority()));
@ -70,8 +75,7 @@ public class WcsStackerTaskSender implements Job {
wcsTask.getTaskPriority(),
wcsTask.getOrigin(),
wcsTask.getDestination(),
wcsTask.getVehicleId()
);
wcsTask.getVehicleId());
try {
WcsApiResponse<WcsStackerTask> wcsResponse = wcsApiService.sendWcsStackerTask(request);
if (wcsResponse != null && WcsApiResponseCodeEnums.SUCCESS.getCode() == wcsResponse.getCode()) {
@ -80,37 +84,46 @@ public class WcsStackerTaskSender implements Job {
new LambdaUpdateWrapper<TAppWcsTask>()
.set(TAppWcsTask::getWcsTaskStatus, WcsStackerTaskStatusEnums.WAIT.getCode())
.set(TAppWcsTask::getSendTime, LocalDateTime.now())
.eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId())
);
.eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId()));
// 更新当前wcs任务对应的wms任务为已发送
appTaskService.update(
new LambdaUpdateWrapper<TAppTask>()
.set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.SEND.getCode())
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())
);
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId()));
if (!wcsTask.getWcsTaskType().equals(WcsStackerTaskTypeEnums.TRANSFER.getCode())) {
// 任务发送成功后锁定资源不区分出入库都使用R1口
try {
agvLockService.lockInboundPort("AGV", "R1");
log.info("任务发送成功后锁定R1口成功任务ID: {}", wcsTask.getWcsTaskId());
} catch (Exception e) {
log.error("任务发送成功后锁定R1口失败任务ID: {}", wcsTask.getWcsTaskId(), e);
}
}
TAppWcsTask doingWcsTask;
do {
doingWcsTask = appWcsTaskService.getOne(new LambdaQueryWrapper<TAppWcsTask>().eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId()));
doingWcsTask = appWcsTaskService.getOne(new LambdaQueryWrapper<TAppWcsTask>()
.eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId()));
Thread.sleep(1000);
} while (doingWcsTask != null && !Objects.equals(doingWcsTask.getWcsTaskStatus(), WcsStackerTaskStatusEnums.FINISH.getCode()));
} while (doingWcsTask != null && !Objects.equals(doingWcsTask.getWcsTaskStatus(),
WcsStackerTaskStatusEnums.FINISH.getCode()));
} else {
log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request), StringUtils.objectToString(wcsResponse));
log.error("堆垛机任务发送失败,请求{},响应信息{}。", StringUtils.objectToString(request),
StringUtils.objectToString(wcsResponse));
// 更新当前的wcs任务状态为异常
appWcsTaskService.update(
new LambdaUpdateWrapper<TAppWcsTask>()
.set(TAppWcsTask::getWcsTaskStatus, WcsStackerTaskStatusEnums.EXCEPTION.getCode())
.set(TAppWcsTask::getSendTime, LocalDateTime.now())
.eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId())
);
.eq(TAppWcsTask::getWcsTaskId, wcsTask.getWcsTaskId()));
// 更新当前wcs任务对应的wms任务为异常
appTaskService.update(
new LambdaUpdateWrapper<TAppTask>()
.set(TAppTask::getTaskStatus, WmsStackerTaskStatusEnums.EXCEPTION.getCode())
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId())
);
.eq(TAppTask::getWcsTaskId, wcsTask.getWcsTaskId()));
}
} catch (Exception e) {
log.error("堆垛机任务发送失败,任务号:{},载具号:{},起点:{},终点:{}。", request.getTaskId(), request.getVehicleNo(), request.getOrigin(), request.getDestination());
log.error("堆垛机任务发送失败,任务号:{},载具号:{},起点:{},终点:{}。", request.getTaskId(), request.getVehicleNo(),
request.getOrigin(), request.getDestination());
}
}
}

View File

@ -407,9 +407,9 @@ public class StackerTaskServiceImpl implements IStackerTaskService {
// } else {
// log.info("[wms]上报成功");
// }
// if (!appOrderInService.removeById(orderIn.getRecordId())) {
// log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
// }
if (!appOrderInService.removeById(orderIn.getRecordId())) {
log.info("整箱入库完成删除入库单失败,任务:{},原因:删除入库单失败", wmsTask.getTaskId());
}
TAppVehicle vehicle = new TAppVehicle();
vehicle.setVehicleId(wmsTask.getVehicleId());
vehicle.setVehicleStatus(WmsVehicleStatusEnums.ON.getCode());

View File

@ -57,12 +57,6 @@ public class TaskControllerServiceImpl implements ITaskControllerService {
return WcsVehicleInResponse.error(String.format("条码:%s 不存在待入库的订单", vehicleNo));
}
// 检查入库口是否可用不关心具体是哪台AGV
boolean canFeed = agvLockService.canFeedToInboundPort(inboundPort);
if (!canFeed) {
return WcsVehicleInResponse.error("入库口被占用,请等待其他任务完成后再试");
}
/* 查找可用库位 */
TAppLocation useLocation = stackerTaskService.requestOneLocation(null, vehicleNo);
if (useLocation == null) {