diff --git a/src/main/java/com/wms/constants/enums/ConfigMapKeyEnum.java b/src/main/java/com/wms/constants/enums/ConfigMapKeyEnum.java index c1c7bde..2923edb 100644 --- a/src/main/java/com/wms/constants/enums/ConfigMapKeyEnum.java +++ b/src/main/java/com/wms/constants/enums/ConfigMapKeyEnum.java @@ -4,7 +4,8 @@ public enum ConfigMapKeyEnum { MAX_WEIGHT("MAX_WEIGHT"), URL_WCS_TASK("URL_WCS_TASK"), URL_NEW_DESTINATION("URL_NEW_DESTINATION"), - URL_WCS_PICK_TASK("URL_WCS_PICK_TASK"); + URL_WCS_PICK_TASK("URL_WCS_PICK_TASK"), + URL_WCS_E_TASK("URL_WCS_E_TASK"); private final String configKey; ConfigMapKeyEnum(String configKey) { this.configKey = configKey; diff --git a/src/main/java/com/wms/controller/TaskController.java b/src/main/java/com/wms/controller/TaskController.java index e513370..1eb1db3 100644 --- a/src/main/java/com/wms/controller/TaskController.java +++ b/src/main/java/com/wms/controller/TaskController.java @@ -1,6 +1,7 @@ package com.wms.controller; import cn.hutool.core.bean.BeanUtil; +import com.alibaba.fastjson2.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; @@ -9,14 +10,10 @@ import com.wms.constants.enums.*; import com.wms.entity.app.*; import com.wms.entity.app.dto.PageDto; import com.wms.entity.app.dto.extend.StockDetailInfo; -import com.wms.entity.app.request.TaskInRequest; -import com.wms.entity.app.request.TaskOutRequest; -import com.wms.entity.app.request.TaskQuery; -import com.wms.entity.app.request.WorkQuery; +import com.wms.entity.app.request.*; +import com.wms.entity.app.vo.StandPickVo; import com.wms.entity.app.vo.TaskVO; -import com.wms.entity.app.wcs.WcsBoxArriveRequest; -import com.wms.entity.app.wcs.WcsTaskResultRequest; -import com.wms.entity.app.wcs.WcsVehicleInRequest; +import com.wms.entity.app.wcs.*; import com.wms.entity.table.*; import com.wms.service.*; import com.wms.service.business.IValidateService; @@ -38,7 +35,9 @@ import org.springframework.web.bind.annotation.*; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.*; +import java.util.stream.Collectors; +import static com.wms.config.InitLocalConfig.configMap; import static com.wms.utils.StringUtils.convertJsonString; import static com.wms.utils.WmsUtils.generateId; @@ -98,6 +97,22 @@ public class TaskController { * 工作流服务 */ private final WorkFlowService workFlowService; + /** + * ETag库位服务 + */ + private final ETagLocationService etagLocationService; + /** + * 电子标签配置服务 + */ + private final ELocationConfigService eLocationConfigService; + /** + * 物料服务 + */ + private final GoodsService goodsService; + /** + * 流转中物料箱号数据 + */ + private final OutsideVehiclesService outsideVehiclesService; /** * 接收入库任务请求 @@ -690,6 +705,7 @@ public class TaskController { /** * WCS向WMS上报箱子到达 + * * @param boxArriveRequest 请求参数 * @return 结果 */ @@ -719,7 +735,7 @@ public class TaskController { response.setMessage("拣选任务查询失败"); return convertJsonString(response); } - pickTask.setPickStatus(2); + pickTask.setPickStatus(PickTaskStatusEnum.FINISH.getCode()); pickTask.setLastUpdateTime(LocalDateTime.now()); // 更新为完成 pickTaskService.updateById(pickTask); @@ -747,7 +763,7 @@ public class TaskController { @PostMapping("/getWorkByStandAndGoods") @ResponseBody @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED) - @MyLog(logTitle = "获取备料工作信息", logMethod = "boxArrive") + @MyLog(logTitle = "获取备料工作信息", logMethod = "getWorkByStandAndGoods") public String getWorkByStandAndGoods(@RequestBody WorkQuery workQuery) { logger.info("接收到获取备料工作信息请求:{},ip地址:{}", convertJsonString(workQuery), HttpUtils.getIpAddr(servletRequest)); ResponseEntity response = new ResponseEntity(); @@ -781,7 +797,7 @@ public class TaskController { // 根据站台号查找对应的载具号 PickTask pickTask = pickTaskService.getOne(new LambdaQueryWrapper() .eq(PickTask::getStandId, standId) - .eq(PickTask::getPickStatus, 2)); + .eq(PickTask::getPickStatus, PickTaskStatusEnum.FINISH.getCode())); if (pickTask == null || StringUtils.isEmpty(pickTask.getVehicleId())) { logger.error("当前站台查不到正在拣选的箱子"); response.setCode(ResponseCode.ERROR.getCode()); @@ -799,12 +815,17 @@ public class TaskController { response.setMessage("请求料号:" + workQuery.getGoodsId() + "与正在拣选的箱子:" + vehicleId + "无对应关系"); return convertJsonString(response); } + // 查一下物料信息 + Goods goodsInfo = goodsService.getOne(new LambdaQueryWrapper() + .eq(Goods::getGoodsId, workQuery.getGoodsId())); // 查找工作流 List workFlows = workFlowService.list(new LambdaQueryWrapper() .eq(WorkFlow::getWorkStation, standId) .eq(WorkFlow::getGoodsId, workQuery.getGoodsId()) .eq(WorkFlow::getWorkStatus, 1) - .ne(WorkFlow::getLightStatus, 2));// 未拍灯 + .ne(WorkFlow::getLightStatus, 2) + .apply("picked_num < needNum") + .orderByDesc(WorkFlow::getLightStatus)); if (workFlows == null || workFlows.isEmpty()) { logger.error("当前站台当前物料查询不到对应的工作"); response.setCode(ResponseCode.ERROR.getCode()); @@ -812,25 +833,272 @@ public class TaskController { return convertJsonString(response); } // 亮灯 + BigDecimal originNum = stock.getGoodsRelated().getRemainNum(); BigDecimal realNum = stock.getGoodsRelated().getRemainNum(); + List eTaskDataList = new ArrayList<>(); for (WorkFlow tempWork : workFlows) { + if (realNum.compareTo(BigDecimal.ZERO) <= 0) {// 当前物料数量不足 + break; + } // 查找对应的标签配置 - + ELocationConfig eConfig = eLocationConfigService.getOne(new LambdaQueryWrapper() + .eq(ELocationConfig::getWorkStation, standId) + .eq(ELocationConfig::getWorkOrder, tempWork.getWorkOrder()) + .eq(ELocationConfig::getWorkCenter, tempWork.getWorkCenter())); + if (eConfig != null) { + // 当次拣选数量 + BigDecimal thisPickNum = realNum.compareTo(tempWork.getNeedNum().subtract(tempWork.getPickedNum())) > 0 ? tempWork.getNeedNum().subtract(tempWork.getPickedNum()) : realNum; + ETaskData eTaskData = new ETaskData(); + eTaskData.setTaskId(tempWork.getWorkFlowId());// 用户查询对应的拣选任务 + eTaskData.setGoodsId(tempWork.getGoodsId()); + eTaskData.setGoodsName(goodsInfo != null ? goodsInfo.getGoodsName() : ""); + eTaskData.setNeedNum(thisPickNum.intValue()); + eTaskData.setLocation(eConfig.getELocationId()); + eTaskDataList.add(eTaskData); + // 设置工作流更新信息 + tempWork.setPickedNum(tempWork.getPickedNum().add(thisPickNum)); + tempWork.setLightStatus(1); + realNum = realNum.subtract(thisPickNum); + } } - // 发送亮灯 - // 返回VO实体 + WcsETaskRequest wcsETaskRequest = new WcsETaskRequest(); + wcsETaskRequest.setTaskGroup(generateId(vehicleId + "_")); + wcsETaskRequest.setTaskType(1); + wcsETaskRequest.setTaskData(eTaskDataList); + wcsETaskRequest.setOrderId(generateId(workQuery.getGoodsId() + "_")); + wcsETaskRequest.setVehicleNo(vehicleId); + String sendToWcsETaskUrl = configMap.get(ConfigMapKeyEnum.URL_WCS_E_TASK.getConfigKey()); + if (StringUtils.isEmpty(sendToWcsETaskUrl)) { + // url地址为空 + logger.error("向Wcs发送电子标签亮灯任务的地址为空"); + throw new Exception("向Wcs发送电子标签亮灯任务的地址为空"); + } else { + // + ResponseEntity result = JSON.parseObject(HttpUtils.sendHttpPostWithoutToken(sendToWcsETaskUrl, convertJsonString(wcsETaskRequest)), ResponseEntity.class); + if (result == null || !Objects.equals(result.getCode(), ResponseCode.OK.getCode())) { + logger.error("发送电子标签亮灯任务失败"); + throw new Exception("发送电子标签亮灯任务失败"); + } else { + // 更新workFlow数据 + workFlowService.updateBatchById(workFlows); + // 更新亮灯数据 + etagLocationService.update(new LambdaUpdateWrapper().set(ETagLocation::getPickStatus, 1).in(ETagLocation::getELocationId, eTaskDataList.stream().map(ETaskData::getLocation).collect(Collectors.toList()))); + // 生成前台VO + StandPickVo standPickVo = new StandPickVo(); + standPickVo.setStandId(standId); + standPickVo.setGoodsId(workQuery.getGoodsId()); + standPickVo.setGoodsUnit(goodsInfo != null ? goodsInfo.getGoodsUnit() : ""); + standPickVo.setPlanPickNum(originNum.subtract(realNum)); + standPickVo.setActualDifference(BigDecimal.ZERO); + try { + // 获取当前站台已完成数量 + List allWorkFlows = workFlowService.list(); + int finishingRows = 0; + BigDecimal finishedCounts = BigDecimal.ZERO; + BigDecimal allCounts = BigDecimal.ZERO; + for (WorkFlow workFlow : allWorkFlows) { + if (workFlow.getWorkStatus() == 2) { + finishingRows++; + } + finishedCounts = finishedCounts.add(workFlow.getPickedNum()); + allCounts = allCounts.add(workFlow.getNeedNum()); + } + standPickVo.setFinishedRows(finishingRows); + standPickVo.setTotalRows(allWorkFlows.size()); + standPickVo.setFinishedCounts(finishedCounts); + standPickVo.setTotalCounts(allCounts); + } catch (Exception e) { + logger.error("获取已完成数据报表失败,可能存在类型转换错误"); + } + standPickVo.setRemark(goodsInfo != null ? goodsInfo.getUnpackingType() : ""); + // 返回成功 + response.setCode(ResponseCode.OK.getCode()); + response.setMessage("获取工作信息成功"); + response.setReturnData(standPickVo); + return convertJsonString(response); + } + } + } catch (Exception e) { + // 回滚事务 + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + logger.error("获取工作信息异常:{}", convertJsonString(e)); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("获取工作信息异常"); + return convertJsonString(response); + } + } - - response.setCode(ResponseCode.OK.getCode()); - response.setMessage("查询成功"); + /** + * 获取电子标签反馈 + * + * @param eTaskFeedbackRequest 反馈信息 + * @return 结果 + */ + @PostMapping("/getETaskFeedBack") + @ResponseBody + @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED) + @MyLog(logTitle = "获取电子标签反馈", logMethod = "getETaskFeedBack") + public String getETaskFeedBack(@RequestBody WcsETaskFeedbackRequest eTaskFeedbackRequest) { + logger.info("接收到获取备料工作信息请求:{},ip地址:{}", convertJsonString(eTaskFeedbackRequest), HttpUtils.getIpAddr(servletRequest)); + ResponseEntity response = new ResponseEntity(); + try { + if (eTaskFeedbackRequest == null || StringUtils.isEmpty(eTaskFeedbackRequest.getTaskId()) || eTaskFeedbackRequest.getTaskType() == null) { + logger.error("请求参数补全,缺少任务号、任务类型。"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("请求参数补全,缺少任务号、任务类型。"); + return convertJsonString(response); + } + if (eTaskFeedbackRequest.getTaskType() == 1) {// 拣选任务 + // 根据taskId查找对应的workFlow + WorkFlow workFlow = workFlowService.getOne(new LambdaQueryWrapper().eq(WorkFlow::getWorkFlowId, eTaskFeedbackRequest.getTaskId())); + if (workFlow == null) { + logger.error("反馈的任务号查找不到对应的工作信息。"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("反馈的任务号查找不到对应的工作信息。"); + return convertJsonString(response); + } + // 更新实际拣选数量 + workFlow.setPickedNum(workFlow.getPickedNum().add(BigDecimal.valueOf(eTaskFeedbackRequest.getConfirmNum() - eTaskFeedbackRequest.getNeedNum()))); + if (workFlow.getPickedNum().compareTo(workFlow.getNeedNum()) < 0) { + // 判断后续有无物料进此站台 + List pickedTasks = pickTaskService.list(new LambdaQueryWrapper() + .eq(PickTask::getStandId, workFlow.getWorkStation()) + .ne(PickTask::getPickStatus, PickTaskStatusEnum.FINISH.getCode())); + List vehicleIds = pickedTasks.stream().map(PickTask::getVehicleId).toList(); + if (outsideVehiclesService.exists(new LambdaQueryWrapper() + .eq(OutsideVehicles::getGoodsId, workFlow.getGoodsId()) + .in(OutsideVehicles::getVehicleId, vehicleIds))) { + workFlow.setLightStatus(1);// 已亮灯 + workFlow.setWorkStatus(1);// 正在做 + } else { + workFlow.setLightStatus(2);// 已拍灯 + workFlow.setWorkStatus(2);// 已完成 + } + } else { + workFlow.setLightStatus(2);// 已拍灯 + workFlow.setWorkStatus(2);// 已完成 + } + // 更新workFlow + workFlowService.updateById(workFlow); + // 更新亮灯信息 + etagLocationService.update(new LambdaUpdateWrapper() + .set(ETagLocation::getPickStatus, 0) + .eq(ETagLocation::getELocationId, eTaskFeedbackRequest.getLocation())); + response.setCode(ResponseCode.OK.getCode()); + response.setMessage("处理反馈成功"); + } else {// 小盒子放入大盒子 + // TODO + logger.info("小盒子放入大盒子"); + } return convertJsonString(response); } catch (Exception e) { // 回滚事务 TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); - logger.error("查询任务发生异常"); + logger.error("处理反馈异常:{}", convertJsonString(e)); response.setCode(ResponseCode.ERROR.getCode()); - response.setMessage("查询任务发生异常"); + response.setMessage("处理反馈异常"); + return convertJsonString(response); + } + } + + /** + * 确认完成---wms界面触发 + * + * @param workConfirmRequest 请求信息 + * @return 结果 + */ + @PostMapping("/confirmFinishedWork") + @ResponseBody + @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED) + @MyLog(logTitle = "确认当前拣货完成(wms界面触发)", logMethod = "confirmFinishedWork") + public String confirmFinishedWork(@RequestBody WorkConfirmRequest workConfirmRequest) { + logger.info("接收到确认当前拣货完成(wms界面触发)请求:{},ip地址:{}", convertJsonString(workConfirmRequest), HttpUtils.getIpAddr(servletRequest)); + ResponseEntity response = new ResponseEntity(); + try { + // 获取站台号 + String standId = ""; + if (StringUtils.isNotEmpty(workConfirmRequest.getStandId())) { + // 站台号从请求参数中获取 + standId = workConfirmRequest.getStandId(); + } else { + // 站台号从ip获取 + Stand standOfIp = standService.getOne(new LambdaQueryWrapper() + .eq(Stand::getStandIp, HttpUtils.getIpAddr(servletRequest)) + .eq(Stand::getStandType, 1)); + if (standOfIp != null && StringUtils.isNotEmpty(standOfIp.getStandId())) { + standId = standOfIp.getStandId(); + } + } + if (StringUtils.isEmpty(standId)) { + logger.error("请求参数缺少站台号。"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("请求参数缺少站台号。"); + return convertJsonString(response); + } + // 判断当前站台是否还有亮灯数据 + if (etagLocationService.exists(new LambdaQueryWrapper() + .eq(ETagLocation::getWorkStation, standId) + .eq(ETagLocation::getPickStatus, 1))) { + logger.error("站台灯光未全部拍灭,请检查。"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("站台灯光未全部拍灭,请检查。"); + return convertJsonString(response); + } + // 查询当前站台的拣货任务 + PickTask pickTasks = pickTaskService.getOne(new LambdaQueryWrapper() + .eq(PickTask::getStandId, standId) + .eq(PickTask::getPickStatus, PickTaskStatusEnum.FINISH.getCode())); + if (pickTasks == null) { + // 没有拣货任务,直接放行 + // TODO 调用Wcs的放行接口 + } else { + // 查询当前载具上的流转中的物料 + List outsideVehicles = outsideVehiclesService.list(new LambdaQueryWrapper() + .eq(OutsideVehicles::getVehicleId, pickTasks.getVehicleId())); + List goodsIdList = new ArrayList<>(); + if (outsideVehicles != null && !outsideVehicles.isEmpty()) { + for (OutsideVehicles outsideVehicle : outsideVehicles) { + if (Objects.equals(outsideVehicle.getGoodsId(), workConfirmRequest.getGoodsId())) { + continue; + } + } + } + } + + + return convertJsonString(response); + } catch (Exception e) { + // 回滚事务 + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + logger.error("获取工作信息异常"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("获取工作信息异常"); + return convertJsonString(response); + } + } + + /** + * Wcs请求释放箱子---站台实体按钮触发 + * + * @param eTaskFeedbackRequest 反馈信息 + * @return 结果 + */ + @PostMapping("/requestFreeVehicle") + @ResponseBody + @Transactional(isolation = Isolation.REPEATABLE_READ, propagation = Propagation.REQUIRED) + @MyLog(logTitle = "Wcs请求释放箱子(站台实体按钮触发)", logMethod = "requestFreeVehicle") + public String requestFreeVehicle(@RequestBody WcsETaskFeedbackRequest eTaskFeedbackRequest) { + logger.info("接收到获取备料工作信息请求:{},ip地址:{}", convertJsonString(eTaskFeedbackRequest), HttpUtils.getIpAddr(servletRequest)); + ResponseEntity response = new ResponseEntity(); + try { + return convertJsonString(response); + } catch (Exception e) { + // 回滚事务 + TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); + logger.error("获取工作信息异常"); + response.setCode(ResponseCode.ERROR.getCode()); + response.setMessage("获取工作信息异常"); return convertJsonString(response); } } diff --git a/src/main/java/com/wms/entity/app/request/WorkConfirmRequest.java b/src/main/java/com/wms/entity/app/request/WorkConfirmRequest.java new file mode 100644 index 0000000..55b8699 --- /dev/null +++ b/src/main/java/com/wms/entity/app/request/WorkConfirmRequest.java @@ -0,0 +1,68 @@ +package com.wms.entity.app.request; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 拣货完成确认请求信息 + */ +@Data +public class WorkConfirmRequest { + /** + * 工作站台 + */ + @JsonProperty("standId") + private String standId; + /** + * 物料编号 + */ + @JsonProperty("goodsId") + private String goodsId; + /** + * 物料单位 + */ + @JsonProperty("goodsUnit") + private String goodsUnit; + /** + * 计划拣选数量 + */ + @JsonProperty("planPickNum") + private BigDecimal planPickNum; + /** + * 实际数量差异 + */ + @JsonProperty("actualDifference") + private BigDecimal actualDifference; + /** + * 备注 + */ + @JsonProperty("remark") + private String remark; + /** + * 已完成行数 + */ + @JsonProperty("finishedRows") + private Integer finishedRows; + /** + * 总行数 + */ + @JsonProperty("totalRows") + private Integer totalRows; + /** + * 已完成数量 + */ + @JsonProperty("finishedCounts") + private BigDecimal finishedCounts; + /** + * 总数量 + */ + @JsonProperty("totalCounts") + private BigDecimal totalCounts; + /** + * 提示 + */ + @JsonProperty("tip") + private String tip; +} diff --git a/src/main/java/com/wms/entity/table/ETagLocation.java b/src/main/java/com/wms/entity/table/ETagLocation.java index fd92178..5a0aed5 100644 --- a/src/main/java/com/wms/entity/table/ETagLocation.java +++ b/src/main/java/com/wms/entity/table/ETagLocation.java @@ -57,6 +57,8 @@ public class ETagLocation { private BigDecimal quantity; /** * 拣货状态 + * 0:未亮灯 + * 1:亮灯中 */ @TableField("pick_status") private Integer pickStatus;