| | |
| | | import com.vincent.rsf.server.api.entity.dto.LocTypeDto; |
| | | import com.vincent.rsf.server.api.controller.erp.params.TaskInParam; |
| | | import com.vincent.rsf.server.api.entity.dto.SyncLocsDto; |
| | | import com.vincent.rsf.server.api.entity.enums.CallBackEvent; |
| | | import com.vincent.rsf.server.api.entity.params.CommonRequest; |
| | | import com.vincent.rsf.server.api.entity.params.ExMsgParams; |
| | | import com.vincent.rsf.server.api.entity.params.WcsTaskParams; |
| | |
| | | |
| | | // 设置工作单号并返回 |
| | | locNo.setWorkNo(ruleCode); |
| | | locNo.setTaskId(task.getId()); |
| | | return locNo; |
| | | } |
| | | |
| | |
| | | private WaitPakin validateWaitPakin(String barcode) { |
| | | WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>() |
| | | .eq(WaitPakin::getBarcode, barcode) |
| | | .eq(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val)); |
| | | .in(WaitPakin::getIoStatus, PakinIOStatus.PAKIN_IO_STATUS_DONE.val, PakinIOStatus.PAKIN_IO_STATUS_TASK_EXCE.val)); |
| | | |
| | | if (Cools.isEmpty(waitPakin)) { |
| | | throw new CoolException("请检查组拖状态是否完成!!"); |
| | |
| | | |
| | | /** |
| | | * 获取并验证组拖明细 |
| | | * 只返回未完全使用的明细(workQty < anfme 或 workQty 为 null) |
| | | */ |
| | | private List<WaitPakinItem> getWaitPakinItems(Long pakinId) { |
| | | List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, pakinId)); |
| | | List<WaitPakinItem> waitPakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>() |
| | | .eq(WaitPakinItem::getPakinId, pakinId)); |
| | | |
| | | if (waitPakinItems.isEmpty()) { |
| | | throw new CoolException("数据错误:组拖明细不存在"); |
| | | } |
| | | return waitPakinItems; |
| | | |
| | | // 过滤掉已完全使用的明细(workQty >= anfme) |
| | | List<WaitPakinItem> availableItems = waitPakinItems.stream() |
| | | .filter(item -> { |
| | | Double workQty = item.getWorkQty() == null ? 0.0 : item.getWorkQty(); |
| | | Double anfme = item.getAnfme() == null ? 0.0 : item.getAnfme(); |
| | | return workQty < anfme; // 只返回未完全使用的明细 |
| | | }) |
| | | .collect(Collectors.toList()); |
| | | |
| | | if (availableItems.isEmpty()) { |
| | | throw new CoolException("组拖明细已全部使用,无法再次创建任务"); |
| | | } |
| | | |
| | | return availableItems; |
| | | } |
| | | |
| | | /** |
| | |
| | | if (!taskItemService.saveBatch(taskItems)) { |
| | | throw new CoolException("任务明细保存失败!!"); |
| | | } |
| | | |
| | | // 更新组托明细的执行数量,标记明细已被提取使用 |
| | | waitPakinItems.forEach(item -> { |
| | | if (!waitPakinItemService.update(new LambdaUpdateWrapper<WaitPakinItem>() |
| | | .set(WaitPakinItem::getWorkQty, item.getAnfme()) |
| | | .eq(WaitPakinItem::getId, item.getId()))) { |
| | | throw new CoolException("组托明细执行数量修改失败!!"); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | /** |
| | |
| | | ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1); |
| | | scheduled.scheduleWithFixedDelay(new Runnable() { |
| | | int current = 1; |
| | | |
| | | @Override |
| | | public void run() { |
| | | params.setCurrent(current); |
| | |
| | | for (SyncLocsDto dto : dtos) { |
| | | Loc loc = new Loc(); |
| | | String string = new Random().nextInt(10000000) + ""; |
| | | Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, string)); |
| | | Loc one = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, dto.getLocNo())); |
| | | if (!Objects.isNull(one)) { |
| | | string = new Random().nextInt(10000000) + ""; |
| | | } |
| | |
| | | .setRow(dto.getRow()) |
| | | .setLev(dto.getLev()) |
| | | .setId(null) |
| | | .setAreaId(41L) |
| | | .setWarehouseId(27L) |
| | | .setAreaId(42L) |
| | | .setWarehouseId(29L) |
| | | .setBarcode(string) |
| | | .setCol(dto.getBay()) |
| | | .setType(dto.getLocType()) |
| | | .setType(dto.getLocType().equals("16") ? "17" : "15") |
| | | .setStatus(dto.getStatusBool()) |
| | | .setUseStatus(LocStsType.getLocSts(dto.getLocSts())); |
| | | if (!locService.save(loc)) { |
| | |
| | | |
| | | /** |
| | | * 异常信息上报 |
| | | * |
| | | * @return |
| | | */ |
| | | @Override |
| | | public R receiveExMsg(ExMsgParams params) { |
| | | if (Objects.isNull(params)) { |
| | | log.error("RCS回调为空!"); |
| | | return R.error("参数不能为空!!"); |
| | | } |
| | | |
| | | Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, params.getSeqNum())); |
| | | log.info("========== 接收RCS回调 =========="); |
| | | log.info("任务编号:{},批次号:{},事件类型:{}", params.getSeqNum(), params.getBatchNo(), params.getEventType()); |
| | | |
| | | // 优先使用批次号查询任务主表(批次号 = 任务编码,更可靠) |
| | | String taskCode = params.getBatchNo(); |
| | | String taskNo = params.getSeqNum(); |
| | | String locCode = null; // 库位代码(多库位任务时从任务号中提取) |
| | | |
| | | // 如果批次号为空,使用任务号查询 |
| | | if (StringUtils.isBlank(taskCode)) { |
| | | taskCode = taskNo; |
| | | } |
| | | |
| | | // 处理出库任务多库位的情况:任务号格式可能是 "任务编码_库位代码" |
| | | // 如果任务号包含下划线,提取库位代码 |
| | | if (StringUtils.isNotBlank(taskNo) && taskNo.contains("_")) { |
| | | locCode = taskNo.substring(taskNo.lastIndexOf("_") + 1); |
| | | // 如果批次号为空,从任务号中提取原始任务编码 |
| | | if (StringUtils.isBlank(taskCode)) { |
| | | taskCode = taskNo.substring(0, taskNo.lastIndexOf("_")); |
| | | } |
| | | log.info("检测到多库位任务,提取库位代码:{},原始任务编码:{}", locCode, taskCode); |
| | | } |
| | | |
| | | // 使用批次号(任务编码)查询任务主表 |
| | | Task task = taskService.getOne(new LambdaQueryWrapper<Task>().eq(Task::getTaskCode, taskCode)); |
| | | |
| | | if (Objects.isNull(task)) { |
| | | throw new CoolException("任务不存在!!"); |
| | | log.error("任务不存在或已结束!任务编号:{},批次号:{}", taskNo, taskCode); |
| | | throw new CoolException("任务不存在或已结束!!任务编号:" + taskNo + ",批次号:" + taskCode); |
| | | } |
| | | |
| | | // 验证批次号和任务号的关联关系 |
| | | if (StringUtils.isNotBlank(params.getBatchNo()) && !params.getBatchNo().equals(task.getTaskCode())) { |
| | | log.warn("批次号与任务编码不匹配!批次号:{},任务编码:{}", params.getBatchNo(), task.getTaskCode()); |
| | | } |
| | | log.info("查询到任务 - 任务编码:{},任务类型:{},当前状态:{}", |
| | | task.getTaskCode(), task.getTaskType(), task.getTaskStatus()); |
| | | |
| | | // 对于多库位出库任务,通过库位代码精确关联任务明细 |
| | | List<TaskItem> relatedTaskItems = null; |
| | | if (StringUtils.isNotBlank(locCode)) { |
| | | // 1. 通过库位代码查询LocItem |
| | | LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocCode, locCode)); |
| | | if (Objects.isNull(locItem)) { |
| | | log.warn("未找到库位明细!库位代码:{},任务编码:{}", locCode, task.getTaskCode()); |
| | | } else { |
| | | // 2. 通过任务ID和LocItem.id(即TaskItem.source)查询对应的任务明细 |
| | | relatedTaskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>() |
| | | .eq(TaskItem::getTaskId, task.getId()) |
| | | .eq(TaskItem::getSource, locItem.getId())); |
| | | if (relatedTaskItems.isEmpty()) { |
| | | log.warn("未找到对应的任务明细!任务编码:{},库位代码:{},LocItem.id:{}", |
| | | task.getTaskCode(), locCode, locItem.getId()); |
| | | } else { |
| | | log.info("通过库位代码精确关联到任务明细 - 任务编码:{},库位代码:{},任务明细数量:{}", |
| | | task.getTaskCode(), locCode, relatedTaskItems.size()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 验证任务状态:只有已下发到RCS的任务才能被回调处理 |
| | | // 入库任务:状态 >= WCS_EXECUTE_IN(2) 表示已下发 |
| | | // 出库任务:状态 >= WCS_EXECUTE_OUT(102) 表示已下发 |
| | | boolean isValidStatus = false; |
| | | if (task.getTaskType() < 100) { |
| | | // 入库任务 |
| | | if (task.getTaskStatus() >= TaskStsType.WCS_EXECUTE_IN.id) { |
| | | isValidStatus = true; |
| | | } |
| | | } else { |
| | | // 出库任务 |
| | | if (task.getTaskStatus() >= TaskStsType.WCS_EXECUTE_OUT.id) { |
| | | isValidStatus = true; |
| | | } |
| | | } |
| | | |
| | | if (!isValidStatus) { |
| | | log.error("任务状态不正确,无法处理回调!任务编码:{},任务类型:{},当前状态:{},期望状态:已下发到RCS", |
| | | task.getTaskCode(), task.getTaskType(), task.getTaskStatus()); |
| | | throw new CoolException("任务状态不正确,无法处理回调!任务编码:" + task.getTaskCode() + |
| | | ",当前状态:" + task.getTaskStatus() + ",任务可能未下发到RCS或已被处理"); |
| | | } |
| | | |
| | | if (params.getEventType().equals("END")) { |
| | | /**料箱搬运中, 修改站点状态*/ |
| | | // if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_OBIT.event)) { |
| | | // if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type) |
| | | // || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) |
| | | // || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type) |
| | | // || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type) |
| | | // || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type) |
| | | // || task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { |
| | | // |
| | | // } |
| | | // /**取箱完成, 修改任务状态*/ |
| | | // } else |
| | | if (params.getEventType().equals(CallBackEvent.CALL_BACK_EVENT_END.event)) { |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_IN.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_IN.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_IN.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_IN.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { |
| | | if (!taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()) |
| | | .set(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id))) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | |
| | | if (!task.getTaskType().equals(TaskType.TASK_TYPE_LOC_MOVE.type)) { |
| | | BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>().eq(BasStation::getStationName, task.getOrgSite())); |
| | | if (Objects.isNull(station)) { |
| | | log.error("入库站点不存在 - 站点名称:{},任务编码:{}", task.getOrgSite(), task.getTaskCode()); |
| | | throw new CoolException("数据错误,站点不存在!!"); |
| | | } |
| | | log.info("查询到入库站点 - 站点名称:{},站点类型:{},当前状态:{}", |
| | | station.getStationName(), station.getType(), station.getUseStatus()); |
| | | if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { |
| | | log.info("更新入库站点状态 - 站点名称:{},新状态:{}", station.getStationName(), LocStsType.LOC_STS_TYPE_O.type); |
| | | station.setUseStatus(LocStsType.LOC_STS_TYPE_O.type); |
| | | if (!basStationService.updateById(station)) { |
| | | log.error("入库站点状态修改失败 - 站点名称:{}", station.getStationName()); |
| | | throw new CoolException("站点状态修改失败!!"); |
| | | } |
| | | log.info("入库站点状态更新成功 - 站点名称:{}", station.getStationName()); |
| | | } |
| | | } |
| | | |
| | | log.info("准备更新入库任务状态 - 任务编码:{},当前状态:{},目标状态:{}", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_IN.id); |
| | | |
| | | // 如果任务状态已经大于等于目标状态,跳过更新 |
| | | if (task.getTaskStatus() >= TaskStsType.COMPLETE_IN.id) { |
| | | log.warn("入库任务状态已大于等于目标状态,跳过更新 - 任务编码:{},当前状态:{},目标状态:{}", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_IN.id); |
| | | } else { |
| | | boolean updated = taskService.update(new LambdaUpdateWrapper<Task>() |
| | | .lt(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id) |
| | | .eq(Task::getTaskCode, task.getTaskCode()) |
| | | .set(Task::getTaskStatus, TaskStsType.COMPLETE_IN.id)); |
| | | if (!updated) { |
| | | log.error("入库任务状态修改失败 - 任务编码:{},当前状态:{},目标状态:{},可能任务状态已大于等于目标状态", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_IN.id); |
| | | throw new CoolException("任务状态修改失败!!当前任务状态:" + task.getTaskStatus() + ",目标状态:" + TaskStsType.COMPLETE_IN.id); |
| | | } |
| | | log.info("入库任务状态更新成功 - 任务编码:{}", task.getTaskCode()); |
| | | } |
| | | } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_MERGE_OUT.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type) |
| | | || task.getTaskType().equals(TaskType.TASK_TYPE_EMPITY_OUT.type)) { |
| | | if (!taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()) |
| | | .set(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id))) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | |
| | | /**修改出库站点状态*/ |
| | | BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>() |
| | | .eq(BasStation::getStationName, task.getTargSite())); |
| | | if (Objects.isNull(station)) { |
| | | log.error("出库站点不存在 - 站点名称:{},任务编码:{}", task.getTargSite(), task.getTaskCode()); |
| | | throw new CoolException("数据错误,站点不存在!!"); |
| | | } |
| | | log.info("查询到出库站点 - 站点名称:{},站点类型:{},当前状态:{}", |
| | | station.getStationName(), station.getType(), station.getUseStatus()); |
| | | if (station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { |
| | | log.info("更新出库站点状态 - 站点名称:{},新状态:{}", station.getStationName(), LocStsType.LOC_STS_TYPE_F.type); |
| | | station.setUseStatus(LocStsType.LOC_STS_TYPE_F.type); |
| | | if (!basStationService.updateById(station)) { |
| | | log.error("出库站点状态修改失败 - 站点名称:{}", station.getStationName()); |
| | | throw new CoolException("站点状态修改失败!!"); |
| | | } |
| | | log.info("出库站点状态更新成功 - 站点名称:{}", station.getStationName()); |
| | | } |
| | | log.info("准备更新出库任务状态 - 任务编码:{},当前状态:{},目标状态:{}", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_OUT.id); |
| | | |
| | | // 如果任务状态已经大于等于目标状态,跳过更新 |
| | | if (task.getTaskStatus() >= TaskStsType.COMPLETE_OUT.id) { |
| | | log.warn("出库任务状态已大于等于目标状态,跳过更新 - 任务编码:{},当前状态:{},目标状态:{}", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_OUT.id); |
| | | } else { |
| | | boolean updated = taskService.update(new LambdaUpdateWrapper<Task>().eq(Task::getTaskCode, task.getTaskCode()) |
| | | .lt(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id) |
| | | .set(Task::getTaskStatus, TaskStsType.COMPLETE_OUT.id)); |
| | | if (!updated) { |
| | | log.error("出库任务状态修改失败 - 任务编码:{},当前状态:{},目标状态:{},可能任务状态已大于等于目标状态", |
| | | task.getTaskCode(), task.getTaskStatus(), TaskStsType.COMPLETE_OUT.id); |
| | | throw new CoolException("任务状态修改失败!!当前任务状态:" + task.getTaskStatus() + ",目标状态:" + TaskStsType.COMPLETE_OUT.id); |
| | | } |
| | | log.info("出库任务状态更新成功 - 任务编码:{}", task.getTaskCode()); |
| | | } |
| | | } |
| | | } else { |
| | | log.warn("未处理的事件类型 - 事件类型:{},任务编码:{},任务类型:{}", |
| | | params.getEventType(), task.getTaskCode(), task.getTaskType()); |
| | | } |
| | | |
| | | log.info(JSONObject.toJSONString(params)); |
| | | log.info("========== 任务执行通知上报处理完成 =========="); |
| | | log.info("处理结果:{}", JSONObject.toJSONString(params)); |
| | | return R.ok(JSONObject.toJSONString(params)); |
| | | } |
| | | |
| | | /** |
| | | * 下发任务至中转API |
| | | * |
| | | * @param params |
| | | * @return |
| | | */ |
| | | @Override |
| | | public R pubWcsTask(WcsTaskParams params) { |
| | | String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.pubTask; |
| | | log.info("任务下发,请求地址: {}, 请求参数: {}", rcsUrl, JSONObject.toJSONString(params)); |
| | | log.info("任务下发,请求地址3: {}, 请求参数: {}", rcsUrl, JSONObject.toJSONString(params)); |
| | | HttpHeaders headers = new HttpHeaders(); |
| | | headers.add("Content-Type", "application/json"); |
| | | headers.add("api-version", "v2.0"); |
| | |
| | | int deviceNo = 0; |
| | | Loc loc = new Loc(); |
| | | InTaskMsgDto inTaskMsgDto = new InTaskMsgDto(); |
| | | locTypeDto.setLocType1(18); |
| | | List<Loc> loc1 = locService.list(new LambdaQueryWrapper<Loc>() |
| | | .eq(Loc::getAreaId, area) |
| | | .eq(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_O.type) |
| | | .eq(Loc::getType, locTypeDto.getLocType1()) |
| | | .ge(Loc::getRow, deviceBind.getStartRow()) |
| | | .le(Loc::getRow, deviceBind.getEndRow()) |
| | | .orderByAsc(Loc::getLev) |
| | | .orderByAsc(Loc::getCol) |
| | | .orderByAsc(Loc::getRow) |
| | |
| | | inTaskMsgDto.setLocNo(locNo); |
| | | return inTaskMsgDto; |
| | | } |
| | | |
| | | /** |
| | | * @author Ryan |
| | | * @date 2026/2/6 |
| | | * @description: 申请入库任务,分配库位 |
| | | * @version 1.0 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public R allocateLocation(String barcode, String staNo, Integer type) { |
| | | log.info("========== 开始申请入库任务,分配库位 =========="); |
| | | log.info("料箱码:{},入库站点:{},入库类型:{}", barcode, staNo, type); |
| | | |
| | | // 构建 TaskInParam 参数,与 /wcs/create/in/task 接口参数一致 |
| | | TaskInParam param = new TaskInParam(); |
| | | param.setBarcode(barcode); |
| | | param.setSourceStaNo(staNo); |
| | | param.setIoType(TaskType.TASK_TYPE_IN.type); // 入库类型 |
| | | param.setLocType1(type); // 库位类型(高低检测信号) |
| | | param.setUser(1L); // 默认用户ID,可以根据实际需求调整 |
| | | |
| | | // 调用 createInTask 方法,创建完整的入库任务 |
| | | // 该方法会执行以下流程: |
| | | // 1. 验证设备站点 |
| | | // 2. 验证组拖状态 |
| | | // 3. 生成任务编码 |
| | | // 4. 获取库位号 |
| | | // 5. 创建并保存任务 |
| | | // 6. 更新库位状态 |
| | | // 7. 获取并验证组拖明细 |
| | | // 8. 创建并保存任务明细 |
| | | // 9. 更新组托状态 |
| | | InTaskMsgDto msgDto = createInTask(param); |
| | | //RCS已经在输送线上,所以不需要下发任务 |
| | | taskService.updateById(new Task(){{setId(msgDto.getTaskId());setTaskStatus(2);}}); |
| | | log.info("========== RCS-申请入库任务成功 =========="); |
| | | log.info("RCS-返回 任务编码:{},库位号:{}", msgDto.getWorkNo(), msgDto.getLocNo()); |
| | | |
| | | // 返回结果,只返回库位号(根据接口文档要求) |
| | | JSONObject result = new JSONObject(); |
| | | result.put("locNo", msgDto.getLocNo()); |
| | | result.put("batchNo", msgDto.getWorkNo()); |
| | | result.put("taskNo", msgDto.getWorkNo()); |
| | | return R.ok(result); |
| | | } |
| | | } |