|
|
|
|
@ -70,10 +70,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
static { |
|
|
|
|
// 初始化运行中任务状态
|
|
|
|
|
RUNNING_STATUSES.add(Task.STATUS_START); // 任务启动
|
|
|
|
|
RUNNING_STATUSES.add(Task.STATUS_RETURNED); // 退回
|
|
|
|
|
RUNNING_STATUSES.add(Task.STATUS_CONVEYOR_END); // 配送
|
|
|
|
|
RUNNING_STATUSES.add(Task.STATUS_FINISHED); // 结束
|
|
|
|
|
RUNNING_STATUSES.add(Task.STATUS_FAILING); // 失败
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public IOrderBoxServiceImpl(IYieldOrderService iYieldOrderService, ITaskService iTaskService, IOrderBindService iOrderBindService, IStationService iStationService, ILocationService iLocationService, AgvTaskTypeUtil agvTaskTypeUtil, IBsWorkCenterService bsWorkCenterService, ITaskExecuteRecordService iTaskExecuteRecordService) { |
|
|
|
|
@ -122,9 +119,12 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
return iYieldOrderService.updateById(list.get(0)) ? R.success() : R.fail("实际称重维护:卡号维护失败"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 箱条码与订单绑定核心方法 |
|
|
|
|
* 流程:参数校验 → 任务状态校验 → 订单绑定状态校验 → 站点/库位分配 → 任务创建 → 订单绑定 |
|
|
|
|
* 流程:参数校验 → 任务状态校验 → 订单绑定状态校验 → 任务创建 → 订单绑定 |
|
|
|
|
* |
|
|
|
|
* @param boxBinding 箱绑定参数(包含箱条码、订单ID列表、工位ID等) |
|
|
|
|
* @return R<?> 绑定结果 |
|
|
|
|
@ -153,255 +153,65 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
if (!orderCheckResult.isSuccess()) { |
|
|
|
|
return orderCheckResult; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 4. 构建任务基础信息
|
|
|
|
|
Long wcId = boxBinding.getWcId(); |
|
|
|
|
Task task = new Task(); |
|
|
|
|
task.setBoxBarcode(boxBarcode); |
|
|
|
|
task.setWcId(wcId); |
|
|
|
|
|
|
|
|
|
// 5. 获取当前可用的站点/库位并分配
|
|
|
|
|
R location = getSiteLocation(task); |
|
|
|
|
if (!location.isSuccess()) { |
|
|
|
|
return location; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 6. 完善任务信息并保存
|
|
|
|
|
task = (Task) location.getData(); |
|
|
|
|
task.setTaskStatus(Task.STATUS_START); // 设置任务初始状态为启动
|
|
|
|
|
task.setCreateTime(new Date()); // 设置任务创建时间
|
|
|
|
|
task.setCreateUser(AuthUtil.getUserId()); |
|
|
|
|
// 7. 计算订单总重量(无订单则重量为0)
|
|
|
|
|
// 4. 计算订单总重量(无订单则重量为0)
|
|
|
|
|
boolean orderBool = boxBinding.getOrderIdList() == null || boxBinding.getOrderIdList().size() == 0; |
|
|
|
|
if (orderBool) { |
|
|
|
|
task.setWeight(new BigDecimal(0)); |
|
|
|
|
} else { |
|
|
|
|
task.setWeight(getWeightByOrderIdList(boxBinding.getOrderIdList())); |
|
|
|
|
} |
|
|
|
|
// 8. 重量校验(小于50kg才允许绑定,避免超重)
|
|
|
|
|
if (task.getWeight().compareTo(BigDecimal.valueOf(50)) > 0) { |
|
|
|
|
return R.fail("箱条码绑定的订单重量过重,请重新进行绑定"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 9. 保存任务记录
|
|
|
|
|
if (!iTaskService.save(task)) { |
|
|
|
|
return R.fail("保存绑定箱条码异常"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 10. 无订单则直接返回成功,有订单则执行订单绑定
|
|
|
|
|
if (orderBool) { |
|
|
|
|
return R.success(); |
|
|
|
|
} else { |
|
|
|
|
return saveOrderBindingList(task.getId(), boxBinding.getOrderIdList()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 释放站点并调用AGV小车接口 |
|
|
|
|
* <p> |
|
|
|
|
* 业务场景:任务结束后释放指定站点,根据终点类型触发不同的AGV小车调度逻辑 |
|
|
|
|
* 核心流程: |
|
|
|
|
* 1. 校验入参和基础数据(站点、任务、终点信息) |
|
|
|
|
* 2. 分两种场景处理AGV调度: |
|
|
|
|
* - 场景1:仅指定终点名称(下料输送线)→ 直接调度AGV到下料线 |
|
|
|
|
* - 场景2:指定终点站点ID → 调度AGV到目标空闲站点 |
|
|
|
|
* 3. AGV调用失败时自动回滚站点状态,保证数据一致性 |
|
|
|
|
* |
|
|
|
|
* @param returnToWarehouseDto 回库请求参数DTO |
|
|
|
|
* @return 统一返回结果 |
|
|
|
|
* @throws IllegalArgumentException 入参无效、基础数据不存在时抛出 |
|
|
|
|
*/ |
|
|
|
|
@Override |
|
|
|
|
public R inventoryReturnToWarehouse(ReturnToWarehouseDto returnToWarehouseDto) { |
|
|
|
|
// ========== 1. 入参和基础数据校验(前置校验,提前失败) ==========
|
|
|
|
|
// 校验DTO非空
|
|
|
|
|
Assert.notNull(returnToWarehouseDto, "回库请求参数不能为空"); |
|
|
|
|
String stationCode = returnToWarehouseDto.getStationCode(); |
|
|
|
|
Assert.hasText(stationCode, "站点编号不能为空"); |
|
|
|
|
|
|
|
|
|
// 查询站点信息(封装为方法,提升可读性)
|
|
|
|
|
Station targetStation = getStationByCode(stationCode); |
|
|
|
|
// 查询有效任务列表
|
|
|
|
|
List<Task> validTaskList = getValidTaskList(returnToWarehouseDto.getBoxBarcode()); |
|
|
|
|
// 校验站点状态
|
|
|
|
|
checkStationStatus(targetStation); |
|
|
|
|
// 校验终点信息
|
|
|
|
|
checkEndLocationInfo(returnToWarehouseDto); |
|
|
|
|
|
|
|
|
|
// ========== 2. 分场景处理AGV调度 ==========
|
|
|
|
|
try { |
|
|
|
|
if (isDropoffConveyorLineScenario(returnToWarehouseDto)) { |
|
|
|
|
// 场景1:仅指定下料输送线名称 → 调度AGV到下料线
|
|
|
|
|
return handleDropoffConveyorLineScenario(targetStation, validTaskList); |
|
|
|
|
} else { |
|
|
|
|
// 场景2:指定终点站点ID → 调度AGV到目标站点
|
|
|
|
|
return handleTargetStationScenario(targetStation, returnToWarehouseDto, validTaskList); |
|
|
|
|
if (!orderBool) { |
|
|
|
|
BigDecimal weightByOrderIdList = getWeightByOrderIdList(boxBinding.getOrderIdList()); |
|
|
|
|
if (weightByOrderIdList.compareTo(BigDecimal.valueOf(50)) > 0) { |
|
|
|
|
return R.fail("箱条码绑定的订单重量过重,请重新进行绑定"); |
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
log.error("库存回库-AGV调度异常,站点编号:{}", stationCode, e); |
|
|
|
|
return R.fail("库存回库操作失败:" + e.getMessage()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 根据站点编号查询站点信息(不存在则抛异常) |
|
|
|
|
*/ |
|
|
|
|
private Station getStationByCode(String stationCode) { |
|
|
|
|
LambdaQueryWrapper<Station> stationQuery = new LambdaQueryWrapper<Station>() |
|
|
|
|
.eq(Station::getStationCode, stationCode); |
|
|
|
|
List<Station> stationList = iStationService.list(stationQuery); |
|
|
|
|
|
|
|
|
|
if (stationList == null || stationList.isEmpty()) { |
|
|
|
|
log.warn("站点编号不存在,入参:{}", stationCode); |
|
|
|
|
throw new IllegalArgumentException("输入站点编号不存在"); |
|
|
|
|
} |
|
|
|
|
return stationList.get(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 查询有效任务列表(运行中状态,不存在则抛异常) |
|
|
|
|
*/ |
|
|
|
|
private List<Task> getValidTaskList(String boxBarcode) { |
|
|
|
|
LambdaQueryWrapper<Task> taskQuery = new LambdaQueryWrapper<Task>() |
|
|
|
|
.eq(Task::getBoxBarcode, boxBarcode) |
|
|
|
|
.in(Task::getTaskStatus, RUNNING_STATUSES); // RUNNING_STATUSES建议抽取为常量
|
|
|
|
|
List<Task> taskList = iTaskService.list(taskQuery); |
|
|
|
|
|
|
|
|
|
if (taskList == null || taskList.isEmpty()) { |
|
|
|
|
log.warn("箱条码数据异常,箱条码编号:{}", boxBarcode); |
|
|
|
|
throw new IllegalArgumentException("箱条码数据异常"); |
|
|
|
|
} |
|
|
|
|
return taskList; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 校验站点状态(必须为空闲) |
|
|
|
|
*/ |
|
|
|
|
private void checkStationStatus(Station station) { |
|
|
|
|
if (!STATUS_FREE.equals(station.getStationStatus())) { |
|
|
|
|
log.warn("站点被占用,站点编号:{},当前状态:{}", station.getStationCode(), station.getStationStatus()); |
|
|
|
|
throw new IllegalArgumentException("该站点正在被使用,请使用其他站点"); |
|
|
|
|
} |
|
|
|
|
// 5. 保存箱订单表
|
|
|
|
|
return saveOrderBindingList(boxBinding.getBoxBarcode(), boxBinding.getOrderIdList()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 校验终点信息(终点ID/名称不能为空) |
|
|
|
|
* 批量保存订单与任务的绑定关系 |
|
|
|
|
* 核心:创建订单绑定记录并批量插入,插入失败则回滚任务(删除已创建的任务) |
|
|
|
|
* |
|
|
|
|
* @param boxBarcode 箱条码 |
|
|
|
|
* @param orderIdList 订单ID列表 |
|
|
|
|
* @return R<?> 保存结果 |
|
|
|
|
* - 成功:R.success() |
|
|
|
|
* - 失败:R.fail(),删除任务并返回异常信息 |
|
|
|
|
*/ |
|
|
|
|
private void checkEndLocationInfo(ReturnToWarehouseDto dto) { |
|
|
|
|
Long endLocationId = dto.getEndLocationId(); |
|
|
|
|
String endName = dto.getEndName(); |
|
|
|
|
|
|
|
|
|
// 终点ID和名称都为空 → 异常
|
|
|
|
|
if ((endLocationId == null || endLocationId == 0) && (endName == null || endName.isBlank())) { |
|
|
|
|
throw new IllegalArgumentException("请检查运送线终点,运送线终点为空"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 仅终点ID为空 → 校验终点名称是否为下料线
|
|
|
|
|
if ((endLocationId == null || endLocationId == 0) && !DROPOFF_CONVEYOR_LINE_NAME.equals(endName)) { |
|
|
|
|
throw new IllegalArgumentException("请检查运送线终点位置异常"); |
|
|
|
|
private R saveOrderBindingList(String boxBarcode, ArrayList<Long> orderIdList) { |
|
|
|
|
ArrayList<OrderBind> orderBindList = new ArrayList<>(); |
|
|
|
|
// 构建订单绑定记录
|
|
|
|
|
for (Long orderId : orderIdList) { |
|
|
|
|
OrderBind orderBind = new OrderBind(); |
|
|
|
|
orderBind.setBindingStatus(OrderBind.STATUS_BOUND); // 绑定状态:已绑定
|
|
|
|
|
orderBind.setBoxBarcode(boxBarcode); // 关联箱条码
|
|
|
|
|
orderBind.setOrderId(orderId); // 关联订单ID
|
|
|
|
|
orderBindList.add(orderBind); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 判断是否为「下料输送线」场景 |
|
|
|
|
*/ |
|
|
|
|
private boolean isDropoffConveyorLineScenario(ReturnToWarehouseDto dto) { |
|
|
|
|
Long endLocationId = dto.getEndLocationId(); |
|
|
|
|
return endLocationId == null || endLocationId == 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 处理「下料输送线」场景的AGV调度 |
|
|
|
|
*/ |
|
|
|
|
private R<?> handleDropoffConveyorLineScenario(Station targetStation, List<Task> taskList) { |
|
|
|
|
String stationCode = targetStation.getStationCode(); |
|
|
|
|
// 1. 占用站点
|
|
|
|
|
updateStationStatus(targetStation, STATUS_OCCUPIED); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
// 2. 获取AGV任务类型并调用调度接口
|
|
|
|
|
String taskType = agvTaskTypeUtil.getTaskTypeByPositions(stationCode,DROPOFF_CONVEYOR_LINE); |
|
|
|
|
boolean agvResult = iTaskExecuteRecordService.genAgvSchedulingTask( |
|
|
|
|
taskType, stationCode, DROPOFF_CONVEYOR_LINE, EQUIPMENT_TYPE_AGV, taskList.get(0) |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
if (agvResult) { |
|
|
|
|
log.info("AGV调度成功(下料线场景),站点编号:{}", stationCode); |
|
|
|
|
return R.success(); |
|
|
|
|
} else { |
|
|
|
|
throw new RuntimeException("调用AGV小车异常"); |
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
// 3. AGV调用失败 → 回滚站点状态
|
|
|
|
|
updateStationStatus(targetStation, STATUS_FREE); |
|
|
|
|
throw e; |
|
|
|
|
// 批量插入绑定记录,失败则删除任务
|
|
|
|
|
if (iOrderBindService.saveBatch(orderBindList)) { |
|
|
|
|
return R.success(); |
|
|
|
|
} else { |
|
|
|
|
return R.fail("订单绑定箱条码异常"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 处理「目标站点」场景的AGV调度 |
|
|
|
|
* 根据订单ID列表计算订单总重量 |
|
|
|
|
* 逻辑:查询订单对应的工单 → 累加实际称重值(过滤null值) |
|
|
|
|
* |
|
|
|
|
* @param orderIdList 订单ID列表 |
|
|
|
|
* @return BigDecimal 订单总重量(单位:业务约定,如千克) |
|
|
|
|
*/ |
|
|
|
|
private R<?> handleTargetStationScenario(Station targetStation, ReturnToWarehouseDto dto, List<Task> taskList) { |
|
|
|
|
String sourceStationCode = targetStation.getStationCode(); |
|
|
|
|
Long endLocationId = dto.getEndLocationId(); |
|
|
|
|
|
|
|
|
|
// 1. 查询终点空闲站点
|
|
|
|
|
Station endStation = getFreeStationByWcId(endLocationId); |
|
|
|
|
|
|
|
|
|
// 2. 占用源站点 + 预占用终点站点
|
|
|
|
|
updateStationStatus(targetStation, STATUS_OCCUPIED); |
|
|
|
|
updateStationStatus(endStation, PRE_STATUS_OCCUPIED); |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
// 3. 获取AGV任务类型并调用调度接口
|
|
|
|
|
String taskType = agvTaskTypeUtil.getTaskTypeByPositions(sourceStationCode,endStation.getStationCode()); |
|
|
|
|
boolean agvResult = iTaskExecuteRecordService.genAgvSchedulingTask( |
|
|
|
|
taskType, sourceStationCode, endStation.getStationCode(), EQUIPMENT_TYPE_AGV, taskList.get(0) |
|
|
|
|
); |
|
|
|
|
private BigDecimal getWeightByOrderIdList(List<Long> orderIdList) { |
|
|
|
|
// 查询订单对应的工单列表
|
|
|
|
|
List<YieldOrder> orderList = iYieldOrderService.list(new LambdaQueryWrapper<YieldOrder>().in(YieldOrder::getId, orderIdList)); |
|
|
|
|
|
|
|
|
|
if (agvResult) { |
|
|
|
|
log.info("AGV调度成功(目标站点场景),源站点:{},终点站点:{}", sourceStationCode, endStation.getStationCode()); |
|
|
|
|
return R.success(); |
|
|
|
|
} else { |
|
|
|
|
throw new RuntimeException("调用AGV小车异常"); |
|
|
|
|
} |
|
|
|
|
} catch (Exception e) { |
|
|
|
|
// 4. AGV调用失败 → 回滚两个站点状态
|
|
|
|
|
updateStationStatus(targetStation, STATUS_FREE); |
|
|
|
|
updateStationStatus(endStation, STATUS_FREE); |
|
|
|
|
throw e; |
|
|
|
|
} |
|
|
|
|
// 流式累加实际称重值(过滤null,初始值为0)
|
|
|
|
|
return orderList.stream() |
|
|
|
|
.map(YieldOrder::getActualWeighing) |
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 根据WCID查询空闲的终点站点(不存在则抛异常) |
|
|
|
|
*/ |
|
|
|
|
private Station getFreeStationByWcId(Long wcId) { |
|
|
|
|
LambdaQueryWrapper<Station> endStationQuery = new LambdaQueryWrapper<Station>() |
|
|
|
|
.eq(Station::getWcId, wcId) |
|
|
|
|
.eq(Station::getStationStatus, STATUS_FREE); |
|
|
|
|
List<Station> endStationList = iStationService.list(endStationQuery); |
|
|
|
|
|
|
|
|
|
if (endStationList == null || endStationList.isEmpty()) { |
|
|
|
|
log.warn("结束站点异常,WCID:{}", wcId); |
|
|
|
|
throw new IllegalArgumentException("结束站点异常"); |
|
|
|
|
} |
|
|
|
|
return endStationList.get(0); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 统一更新站点状态(封装重复逻辑) |
|
|
|
|
*/ |
|
|
|
|
private void updateStationStatus(Station station, Integer newStatus) { |
|
|
|
|
station.setStationStatus(newStatus); |
|
|
|
|
boolean updateResult = iStationService.updateById(station); |
|
|
|
|
if (!updateResult) { |
|
|
|
|
log.error("站点状态更新失败,站点编号:{},目标状态:{}", station.getStationCode(), newStatus); |
|
|
|
|
throw new RuntimeException("站点状态更新失败"); |
|
|
|
|
} |
|
|
|
|
log.debug("站点状态更新成功,站点编号:{},状态:{}", station.getStationCode(), newStatus); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public R returnToWarehouseList() { |
|
|
|
|
@ -415,7 +225,9 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
List<Long> list = stationList.stream().map(Station::getWcId).distinct().collect(Collectors.toList()); |
|
|
|
|
List<BsWorkCenterVO> bwList = bsWorkCenterService.getByIds(list); |
|
|
|
|
if (!bwList.isEmpty()) { |
|
|
|
|
bwList.forEach(s->{bsWorkCenterVOList.add(s);}); |
|
|
|
|
bwList.forEach(s -> { |
|
|
|
|
bsWorkCenterVOList.add(s); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
@ -450,54 +262,104 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
return R.fail("站点切换空闲异常"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 批量保存订单与任务的绑定关系 |
|
|
|
|
* 核心:创建订单绑定记录并批量插入,插入失败则回滚任务(删除已创建的任务) |
|
|
|
|
* |
|
|
|
|
* @param taskId 任务ID(关联箱条码) |
|
|
|
|
* @param orderIdList 订单ID列表 |
|
|
|
|
* @return R<?> 保存结果 |
|
|
|
|
* - 成功:R.success() |
|
|
|
|
* - 失败:R.fail(),删除任务并返回异常信息 |
|
|
|
|
*/ |
|
|
|
|
private R saveOrderBindingList(Long taskId, ArrayList<Long> orderIdList) { |
|
|
|
|
ArrayList<OrderBind> orderBindList = new ArrayList<>(); |
|
|
|
|
// 构建订单绑定记录
|
|
|
|
|
for (Long orderId : orderIdList) { |
|
|
|
|
OrderBind orderBind = new OrderBind(); |
|
|
|
|
orderBind.setBindingStatus(OrderBind.STATUS_BOUND); // 绑定状态:已绑定
|
|
|
|
|
orderBind.setTaskId(taskId); // 关联任务ID
|
|
|
|
|
orderBind.setOrderId(orderId); // 关联订单ID
|
|
|
|
|
orderBindList.add(orderBind); |
|
|
|
|
@Override |
|
|
|
|
public R saveTask(ReturnToWarehouseDto returnToWarehouseDto,Boolean agvSend) { |
|
|
|
|
if (returnToWarehouseDto.getEndWcId()==null) { |
|
|
|
|
R.fail("结束位置不能都为空"); |
|
|
|
|
} |
|
|
|
|
String stationCode=""; |
|
|
|
|
String endStationCode=""; |
|
|
|
|
if (!returnToWarehouseDto.getStartStationCode().isEmpty()) { |
|
|
|
|
List<Station> stationList = iStationService.list(new LambdaQueryWrapper<Station>().eq(Station::getStationCode, returnToWarehouseDto.getStartStationCode())); |
|
|
|
|
if (stationList.isEmpty()) { |
|
|
|
|
return R.fail("站点编码不存在"); |
|
|
|
|
} |
|
|
|
|
if (!stationList.get(0).getStationStatus().equals(STATUS_FREE)) { |
|
|
|
|
return R.fail("站点编码不存在"); |
|
|
|
|
} |
|
|
|
|
stationCode= returnToWarehouseDto.getStartStationCode(); |
|
|
|
|
}else { |
|
|
|
|
stationCode=Station.PICKUP_CONVEYOR_LINE; |
|
|
|
|
} |
|
|
|
|
Task task = new Task(); |
|
|
|
|
//判断箱条码是否为空,如果不为空判断是否在使用
|
|
|
|
|
if (!returnToWarehouseDto.getBoxBarcode().isEmpty()) { |
|
|
|
|
R taskCheckResult = checkBoxBarcodeRunningTask(returnToWarehouseDto.getBoxBarcode()); |
|
|
|
|
if (!taskCheckResult.isSuccess()) { |
|
|
|
|
return taskCheckResult; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// 批量插入绑定记录,失败则删除任务
|
|
|
|
|
if (iOrderBindService.saveBatch(orderBindList)) { |
|
|
|
|
} |
|
|
|
|
task.setBoxBarcode(returnToWarehouseDto.getBoxBarcode().isEmpty()?"":returnToWarehouseDto.getBoxBarcode()); |
|
|
|
|
task.setWcId(returnToWarehouseDto.getEndWcId()); |
|
|
|
|
if (returnToWarehouseDto.getEndWcId()==0) { |
|
|
|
|
//todo:查看输送线回库
|
|
|
|
|
task.setWcId(0L); |
|
|
|
|
endStationCode= DROPOFF_CONVEYOR_LINE; |
|
|
|
|
}else { |
|
|
|
|
// 5. 获取当前可用的站点/库位并分配
|
|
|
|
|
R locationResult = getSiteLocation(task); |
|
|
|
|
if (!locationResult.isSuccess()) { |
|
|
|
|
return locationResult; |
|
|
|
|
} |
|
|
|
|
// 6. 完善任务信息并保存
|
|
|
|
|
task = (Task) locationResult.getData(); |
|
|
|
|
if (task.getStationId()==null&&agvSend) { |
|
|
|
|
List<Location> locationList = iLocationService.list(new LambdaQueryWrapper<Location>().eq(Location::getId, task.getLocationId())); |
|
|
|
|
if (!CollectionUtils.isEmpty(locationList)) { |
|
|
|
|
Location location = locationList.get(0); |
|
|
|
|
location.setLocationStatus(Location.STATUS_FREE); |
|
|
|
|
iLocationService.updateById(location); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
return R.fail("结束站点被占用"); |
|
|
|
|
}else { |
|
|
|
|
endStationCode=iStationService.getById(task.getStationId()).getStationCode(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
task.setTaskStatus(Task.STATUS_START); // 设置任务初始状态为启动
|
|
|
|
|
task.setCreateTime(new Date()); // 设置任务创建时间
|
|
|
|
|
task.setCreateUser(AuthUtil.getUserId()); |
|
|
|
|
if (!returnToWarehouseDto.getBoxBarcode().isEmpty()) { |
|
|
|
|
List<OrderBind> orderBindList = iOrderBindService.list(new LambdaQueryWrapper<OrderBind>().eq(OrderBind::getBoxBarcode, returnToWarehouseDto.getBoxBarcode()).eq(false, OrderBind::getBindingStatus, OrderBind.STATUS_UNBINDED)); |
|
|
|
|
if (orderBindList.isEmpty()) { |
|
|
|
|
task.setWeight(new BigDecimal(0)); |
|
|
|
|
}else { |
|
|
|
|
List<Long> orderIdsList = orderBindList.stream() |
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
.map(OrderBind::getOrderId) |
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
task.setWeight(getWeightByOrderIdList(orderIdsList)); |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
}else { |
|
|
|
|
task.setWeight(new BigDecimal(0)); |
|
|
|
|
} |
|
|
|
|
if (!iTaskService.save(task)) { |
|
|
|
|
return R.fail("保存任务表异常"); |
|
|
|
|
} |
|
|
|
|
if (agvSend) { |
|
|
|
|
String taskType = agvTaskTypeUtil.getTaskTypeByPositions(stationCode,endStationCode); |
|
|
|
|
boolean agvResult = iTaskExecuteRecordService.genAgvSchedulingTask( |
|
|
|
|
taskType, stationCode, endStationCode, EQUIPMENT_TYPE_AGV, task); |
|
|
|
|
if (agvResult) { |
|
|
|
|
return R.success(); |
|
|
|
|
}else { |
|
|
|
|
return R.fail("AGV小车调用异常"); |
|
|
|
|
} |
|
|
|
|
}else { |
|
|
|
|
return R.success(); |
|
|
|
|
} else { |
|
|
|
|
iTaskService.removeById(taskId); // 回滚:删除已创建的任务
|
|
|
|
|
return R.fail("订单绑定箱条码异常"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 根据订单ID列表计算订单总重量 |
|
|
|
|
* 逻辑:查询订单对应的工单 → 累加实际称重值(过滤null值) |
|
|
|
|
* |
|
|
|
|
* @param orderIdList 订单ID列表 |
|
|
|
|
* @return BigDecimal 订单总重量(单位:业务约定,如千克) |
|
|
|
|
*/ |
|
|
|
|
private BigDecimal getWeightByOrderIdList(ArrayList<Long> orderIdList) { |
|
|
|
|
// 查询订单对应的工单列表
|
|
|
|
|
List<YieldOrder> orderList = iYieldOrderService.list(new LambdaQueryWrapper<YieldOrder>().in(YieldOrder::getId, orderIdList)); |
|
|
|
|
|
|
|
|
|
// 流式累加实际称重值(过滤null,初始值为0)
|
|
|
|
|
return orderList.stream() |
|
|
|
|
.map(YieldOrder::getActualWeighing) |
|
|
|
|
.filter(Objects::nonNull) |
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 获取当前工位可用的站点/库位并分配 |
|
|
|
|
* 优先级:先分配站点 → 站点无可用则分配库位 → 均无则返回失败 |
|
|
|
|
@ -509,7 +371,7 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
*/ |
|
|
|
|
private R getSiteLocation(Task task) { |
|
|
|
|
// 1. 查询当前工位可用的站点(状态为占用的站点)
|
|
|
|
|
List<Station> list = iStationService.list(new LambdaQueryWrapper<Station>().eq(Station::getWcId, task.getWcId()).eq(Station::getStationStatus, STATUS_FREE)); |
|
|
|
|
List<Station> list = iStationService.list(new LambdaQueryWrapper<Station>().eq(Station::getWcId, task.getWcId()).eq(Station::getStationStatus, STATUS_OCCUPIED)); |
|
|
|
|
if (!CollectionUtils.isEmpty(list)) { |
|
|
|
|
task.setStationId(list.get(0).getId()); // 分配第一个可用站点
|
|
|
|
|
// 更新站点状态为预占用(锁定站点)
|
|
|
|
|
@ -534,6 +396,9 @@ public class IOrderBoxServiceImpl implements IOrderBoxService { |
|
|
|
|
return R.fail("当前班次库位繁忙,请空闲后再试"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* 校验箱条码是否存在运行中的任务 |
|
|
|
|
* 核心:避免同一箱条码同时存在多个未完成的绑定任务 |
|
|
|
|
|