From 4906e505fb88b9e30e7ec3aed1f2dd0c8f63e8ed Mon Sep 17 00:00:00 2001 From: icewint Date: Wed, 10 Jul 2024 16:22:54 +0800 Subject: [PATCH] =?UTF-8?q?[important]=E5=9F=BA=E6=9C=AC=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E7=BB=99=E5=9B=9B=E5=90=91=E8=BD=A6=E7=9A=84API?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/wms/bussiness/TaskOperation.java | 303 ++++++++++++++++++ .../com/wms/constants/enums/TaskType.java | 12 +- .../parent/ContainerController.java | 35 +- .../container/ContainerApiLocalResponse.java | 42 +++ .../container/CreateInstoreTaskRequest.java | 56 ++++ .../container/CreateInstoreTaskResponse.java | 57 ++++ .../app/container/TaskStateNoticeRequest.java | 39 +++ .../wms/filter/GlobalExceptionHandler.java | 6 + src/main/java/com/wms/mapper/StockMapper.java | 32 ++ src/main/java/com/wms/mapper/TaskMapper.java | 3 + .../com/wms/service/ContainerService.java | 27 ++ .../parent/ContainerImplement.java | 174 ++++++++++ src/main/java/com/wms/utils/StringUtils.java | 19 +- .../com/wms/utils/storage/LocationUtils.java | 106 ++++++ src/main/resources/mapper/StockMapper.xml | 19 ++ src/main/resources/mapper/TaskMapper.xml | 9 + 16 files changed, 933 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/wms/bussiness/TaskOperation.java create mode 100644 src/main/java/com/wms/entity/app/container/ContainerApiLocalResponse.java create mode 100644 src/main/java/com/wms/entity/app/container/CreateInstoreTaskRequest.java create mode 100644 src/main/java/com/wms/entity/app/container/CreateInstoreTaskResponse.java create mode 100644 src/main/java/com/wms/entity/app/container/TaskStateNoticeRequest.java create mode 100644 src/main/java/com/wms/service/ContainerService.java create mode 100644 src/main/java/com/wms/service/serviceImplements/parent/ContainerImplement.java create mode 100644 src/main/java/com/wms/utils/storage/LocationUtils.java diff --git a/src/main/java/com/wms/bussiness/TaskOperation.java b/src/main/java/com/wms/bussiness/TaskOperation.java new file mode 100644 index 0000000..b49577c --- /dev/null +++ b/src/main/java/com/wms/bussiness/TaskOperation.java @@ -0,0 +1,303 @@ +package com.wms.bussiness; + +import com.wms.constants.enums.LocationStatus; +import com.wms.constants.enums.StockStatus; +import com.wms.constants.enums.TaskType; +import com.wms.constants.enums.WmsTaskStatus; +import com.wms.entity.table.Location; +import com.wms.entity.table.Stock; +import com.wms.entity.table.Task; +import com.wms.mapper.LocationMapper; +import com.wms.mapper.StockMapper; +import com.wms.mapper.TaskMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.swing.plaf.synth.Region; +import java.util.Date; +import java.util.List; + + +/** + * 对任务的操作 + */ +@Slf4j +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class TaskOperation { + + /** + * 库存 Mapper + */ + private final StockMapper stockMapper; + + /** + * 任务表操作类 + */ + private final TaskMapper taskMapper; + + /** + * 库位表操作类 + */ + private final LocationMapper locationMapper; + + + + + //region 完成任务 + /** + * 完成任务 + * @param task 要完成的任务 + * @return 操作结果 + */ + public boolean completeTask(Task task) { + if(task == null) { + return false; + } + TaskType taskType = TaskType.getTaskType(task.getTaskType()); + if(taskType == null) { + return false; + } + /* 根据任务类型判断 */ + return switch (taskType) { + case IN -> completeInTask(task); + case OUT -> completeOutTask(task); + case INVENTORY -> completeInventoryTask(task); + case MOVE -> completeMoveTask(task); + }; + } + + /** + * 完成入库任务 + * @param task 要完成的入库任务 + * @return 结果 + */ + private boolean completeInTask(Task task) { + /* 将任务更新为完成,将库存更新为正常库存,将库位更新为占用 */ + // 更新任务状态 + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.FINISH.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("完成入库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 更新库存状态 + Stock stockQuery = new Stock(); + stockQuery.setLocationId(task.getDestination()); + List stocks = stockMapper.selStocks(stockQuery); + if(stocks == null) { + log.warn(String.format("完成入库任务查询库存 查询数据库失败,任务号:%s", task.getTaskId())); + return false; + } + if(stocks.isEmpty()) { + log.warn(String.format("完成入库任务查询库存没有库存数据,任务号:%s", task.getTaskId())); + return false; + } + for(Stock stock : stocks) { + Stock updateStock = new Stock(); + updateStock.setStockId(stock.getStockId()); + updateStock.setStockStatus(StockStatus.OK.getCode()); + updateStock.setLastUpdateTime(new Date()); + updateStock.setCreateTime(new Date()); + int updateStockResult = stockMapper.modifyStock(updateStock); + if(updateStockResult != 1) { + log.warn(String.format("完成入库任务更新库存状态失败,任务号:%s , 库存号:%s", task.getTaskId(), stock.getStockId())); + } + } + return true; + } + + /** + * 完成出库任务 + * @param task 要完成的出库任务 + * @return 执行结果 + */ + private boolean completeOutTask(Task task) { + /* 将任务更新为完成,删除库存,将库位释放 */ + // 更新任务状态 + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.FINISH.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("完成出库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 删除库存 + Stock stockQuery = new Stock(); + stockQuery.setLocationId(task.getDestination()); + List stocks = stockMapper.selStocks(stockQuery); + if(stocks == null) { + log.warn(String.format("完成出库任务查询库存 查询数据库失败,任务号:%s", task.getTaskId())); + return false; + } + if(stocks.isEmpty()) { + log.warn(String.format("完成出库任务查询库存没有库存数据,任务号:%s", task.getTaskId())); + return false; + } + for(Stock stock : stocks) { + int deleteStockResult = stockMapper.deleteStock(stock.getStockId()); + if(deleteStockResult != 1) { + log.warn(String.format("完成出库任务删除库存状态失败,任务号:%s , 库存号:%s", task.getTaskId(), stock.getStockId())); + } + } + // 释放库位 + Location location = new Location(); + location.setLocationId(task.getDestination()); + location.setLocationStatus(LocationStatus.EMPTY.getCode()); + locationMapper.modifyLocation(location); + return true; + } + + private boolean completeInventoryTask(Task task) { + return true; + } + + private boolean completeMoveTask(Task task) { + /* 将任务更新为完成;更新库存状态;更新库位状态 */ + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.FINISH.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("完成移库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 更新库存 + int updateLocationResult = stockMapper.updateLocationAndStatus(task.getOrigin(), task.getDestination(), StockStatus.OK.getCode()); + if(updateLocationResult < 1) { + log.warn(String.format("完成移库任务更新库存状态失败,任务号:%s ,原库位:%s,新库位:%s", task.getTaskId(), task.getOrigin(), task.getDestination())); + return false; + } + // 释放原库位 + Location location = new Location(); + location.setLocationId(task.getOrigin()); + location.setLocationStatus(LocationStatus.EMPTY.getCode()); + locationMapper.modifyLocation(location); + return true; + } + //endregion + + + + //region 取消任务 + + /** + * 取消任务 + * @param task 要完成的任务 + * @return 操作结果 + */ + public boolean cancelTask(Task task) { + if(task == null) { + return false; + } + TaskType taskType = TaskType.getTaskType(task.getTaskType()); + if(taskType == null) { + return false; + } + /* 根据任务类型判断 */ + return switch (taskType) { + case IN -> cancelInTask(task); + case OUT -> cancelOutTask(task); + case INVENTORY -> cancelInventoryTask(task); + case MOVE -> cancelMoveTask(task); + }; + } + + /** + * 取消入库任务 + * @param task 要取消的入库任务 + * @return 结果 + */ + private boolean cancelInTask(Task task) { + /* 将任务更新为取消,将库存删除,将库位更新为空闲 */ + // 更新任务状态 + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.CANCEL.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("取消入库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 删除库存 + int deleteResult = stockMapper.deleteStockWithLocationId(task.getDestination()); + if(deleteResult < 1) { + log.warn(String.format("取消入库删除库存失败,任务号:%s,入库点位:%s -> %s", task.getTaskId(), task.getOrigin(), task.getDestination())); + } + // 释放库位 + Location location = new Location(); + location.setLocationId(task.getDestination()); + location.setLocationStatus(LocationStatus.EMPTY.getCode()); + locationMapper.modifyLocation(location); + return true; + } + + /** + * 取消出库任务 + * @param task 要取消的出库任务 + * @return 执行结果 + */ + private boolean cancelOutTask(Task task) { + /* 将任务更新为取消,将库存更新为库存中 */ + // 更新任务状态 + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.CANCEL.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("取消出库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 更新库存信息为库存中 + int updateResult = stockMapper.updateStockStatusWithLocationId(task.getOrigin(), StockStatus.OK.getCode()); + if(updateResult < 1) { + log.warn(String.format("取消出库任务更新库存状态失败,任务号:%s,出库点位:%s -> %s", task.getTaskId(), task.getOrigin(), task.getDestination())); + } + return true; + } + + private boolean cancelInventoryTask(Task task) { + return true; + } + + private boolean cancelMoveTask(Task task) { + /* 将任务更新为取消;更新库存状态为正常;释放终点库位 */ + Task updateTask = new Task(); + updateTask.setTaskId(task.getTaskId()); + updateTask.setTaskStatus(WmsTaskStatus.CANCEL.getCode()); + updateTask.setFinishTime(new Date()); + int updateRow = taskMapper.executeTask(updateTask); + if(updateRow != 1) { + log.warn(String.format("完成移库任务更新任务状态失败,任务号:%s", task.getTaskId())); + return false; + } + // 更新库存信息为库存中 + int updateResult = stockMapper.updateStockStatusWithLocationId(task.getOrigin(), StockStatus.OK.getCode()); + if(updateResult < 1) { + log.warn(String.format("取消出库任务更新库存状态失败,任务号:%s,出库点位:%s -> %s", task.getTaskId(), task.getOrigin(), task.getDestination())); + } + // 释放新库位 + Location location = new Location(); + location.setLocationId(task.getDestination()); + location.setLocationStatus(LocationStatus.EMPTY.getCode()); + locationMapper.modifyLocation(location); + return true; + } + + + //endregion + + + + +} diff --git a/src/main/java/com/wms/constants/enums/TaskType.java b/src/main/java/com/wms/constants/enums/TaskType.java index f607857..e46a232 100644 --- a/src/main/java/com/wms/constants/enums/TaskType.java +++ b/src/main/java/com/wms/constants/enums/TaskType.java @@ -6,7 +6,8 @@ package com.wms.constants.enums; public enum TaskType { IN(1, "入库"), OUT(2, "出库"), - INVENTORY(3, "盘点"); + INVENTORY(3, "盘点"), + MOVE(9, "移库"); private final Integer code; @@ -24,4 +25,13 @@ public enum TaskType { public String getValue() { return value; } + + public static TaskType getTaskType(Integer code) { + for (TaskType taskType : TaskType.values()) { + if (taskType.getCode().equals(code)) { + return taskType; + } + } + return null; + } } diff --git a/src/main/java/com/wms/controller/parent/ContainerController.java b/src/main/java/com/wms/controller/parent/ContainerController.java index 81183c9..191cd6b 100644 --- a/src/main/java/com/wms/controller/parent/ContainerController.java +++ b/src/main/java/com/wms/controller/parent/ContainerController.java @@ -1,23 +1,50 @@ package com.wms.controller.parent; import com.wms.controller.BaseController; +import com.wms.entity.app.container.ContainerApiLocalResponse; +import com.wms.entity.app.container.CreateInstoreTaskRequest; +import com.wms.entity.app.container.CreateInstoreTaskResponse; +import com.wms.entity.app.container.TaskStateNoticeRequest; +import com.wms.service.ContainerService; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; /** * 四向车交互 * @author icewint */ -@Controller +@RestController @CrossOrigin -@RequestMapping(value = "/wms/mes") +@RequestMapping(value = "/api/container") @RequiredArgsConstructor(onConstructor = @__(@Autowired)) public class ContainerController extends BaseController { + private final ContainerService containerService; + + /** + * 接收四向车扫码入库信息 + * @param request 请求信息 + * @return 返回信息 + */ + @PostMapping("/CreateInstoreTask") + public CreateInstoreTaskResponse createInstoreTask(@RequestBody @Validated CreateInstoreTaskRequest request) { + return containerService.createInstoreTask(request); + } + + + /** + * 接收四向车任务状态通知 + * @param request 请求信息 + * @return 响应信息 + */ + @PostMapping("/TaskStateNotice") + public ContainerApiLocalResponse taskStateNotice(@RequestBody @Validated TaskStateNoticeRequest request){ + return containerService.taskStateNotice(request); + } } diff --git a/src/main/java/com/wms/entity/app/container/ContainerApiLocalResponse.java b/src/main/java/com/wms/entity/app/container/ContainerApiLocalResponse.java new file mode 100644 index 0000000..5ec7700 --- /dev/null +++ b/src/main/java/com/wms/entity/app/container/ContainerApiLocalResponse.java @@ -0,0 +1,42 @@ +package com.wms.entity.app.container; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 给四向车服务的通用返回类 + */ +@Data +public class ContainerApiLocalResponse { + + public ContainerApiLocalResponse(String code, String message) { + this.code = code; + this.message = message; + } + + public ContainerApiLocalResponse(String code, String wmsTaskId, String message) { + this.code = code; + this.wmsTaskId = wmsTaskId; + this.message = message; + } + + /** + * 响应代码 + */ + @JsonProperty("code") + private String code; + + /** + * wms 任务号 + */ + @JsonProperty("wmstaskid") + private String wmsTaskId; + + /** + * 响应信息 + */ + @JsonProperty("message") + private String message; + + +} diff --git a/src/main/java/com/wms/entity/app/container/CreateInstoreTaskRequest.java b/src/main/java/com/wms/entity/app/container/CreateInstoreTaskRequest.java new file mode 100644 index 0000000..86194c7 --- /dev/null +++ b/src/main/java/com/wms/entity/app/container/CreateInstoreTaskRequest.java @@ -0,0 +1,56 @@ +package com.wms.entity.app.container; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; + +/** + * 四向车扫码入库的请求 + */ +@Data +public class CreateInstoreTaskRequest { + + /** + * 请求号 + */ + @NotBlank(message = "请求号不允许为空") + @JsonProperty("requestid") + private String requestId; + + /** + * 密钥 + */ + @NotBlank(message = "密钥不允许为空") + @JsonProperty("key") + private String key; + + /** + * 托盘号 + */ + @NotBlank(message = "托盘号不允许为空") + @JsonProperty("palletno") + private String palletNo; + + /** + * 长 + */ + @Pattern(regexp = "^\\d+$", message = "长不允许为空或者为非数字") + @JsonProperty("height") + private String height; + + /** + * 宽 + */ + @Pattern(regexp = "^\\d+$", message = "宽不允许为空或者为非数字") + @JsonProperty("weight") + private String weight; + + /** + * 起点位置 + */ + @NotBlank(message = "起点位置不允许为空") + @JsonProperty("fromcellno") + private String fromCellNo; + +} diff --git a/src/main/java/com/wms/entity/app/container/CreateInstoreTaskResponse.java b/src/main/java/com/wms/entity/app/container/CreateInstoreTaskResponse.java new file mode 100644 index 0000000..2808b93 --- /dev/null +++ b/src/main/java/com/wms/entity/app/container/CreateInstoreTaskResponse.java @@ -0,0 +1,57 @@ +package com.wms.entity.app.container; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * 四向车扫码入库的接口的返回响应 + */ +@Data +public class CreateInstoreTaskResponse { + + public CreateInstoreTaskResponse(String code, String message) { + this.code = code; + this.message = message; + } + + public CreateInstoreTaskResponse() { + } + + /** + * 响应代码 + */ + @JsonProperty("code") + private String code; + + /** + * wms 任务号 + */ + @JsonProperty("wmstaskid") + private String wmsTaskId; + + /** + * 载具号 + */ + @JsonProperty("palletno") + private String palletNo; + + /** + * 起始位置 + */ + @JsonProperty("fromcellno") + private String fromCellNo; + + /** + * 目的位置 + */ + @JsonProperty("tocellno") + private String toCellNo; + + /** + * 信息 + */ + @JsonProperty("message") + private String message; + + +} diff --git a/src/main/java/com/wms/entity/app/container/TaskStateNoticeRequest.java b/src/main/java/com/wms/entity/app/container/TaskStateNoticeRequest.java new file mode 100644 index 0000000..8f5d818 --- /dev/null +++ b/src/main/java/com/wms/entity/app/container/TaskStateNoticeRequest.java @@ -0,0 +1,39 @@ +package com.wms.entity.app.container; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +@Data +public class TaskStateNoticeRequest { + + /** + * 请求ID + */ + @NotBlank + @JsonProperty("requestid") + private String requestId; + + /** + * 密钥 + */ + @NotBlank + @JsonProperty("key") + private String key; + + /** + * wms任务号 + */ + @NotBlank + @JsonProperty("wmstaskid") + private String wmsTaskId; + + /** + * 任务状态 + */ + @NotBlank + @JsonProperty("taskstate") + private String taskState; + +} diff --git a/src/main/java/com/wms/filter/GlobalExceptionHandler.java b/src/main/java/com/wms/filter/GlobalExceptionHandler.java index 6f80736..21c07d0 100644 --- a/src/main/java/com/wms/filter/GlobalExceptionHandler.java +++ b/src/main/java/com/wms/filter/GlobalExceptionHandler.java @@ -1,6 +1,7 @@ package com.wms.filter; import com.alibaba.fastjson.JSON; +import com.wms.entity.app.container.ContainerApiLocalResponse; import com.wms.entity.app.mes.MesApiLocalResponse; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.validation.ObjectError; @@ -26,8 +27,13 @@ public class GlobalExceptionHandler { Class controllerClass = method.getDeclaringClass(); String className = controllerClass.getName(); if(className.contains("MesController")) { + /* 给mes返回的异常信息 */ return JSON.toJSONString(new MesApiLocalResponse(0, message)); } + if(className.contains("ContainerController")) { + /* 给四向车返回的异常信息 */ + return JSON.toJSONString(new ContainerApiLocalResponse("999", message)); + } } return String.format("{\"code\": 999, \"message\": \"%s\"}", message); } diff --git a/src/main/java/com/wms/mapper/StockMapper.java b/src/main/java/com/wms/mapper/StockMapper.java index b7b0fa5..eab7c12 100644 --- a/src/main/java/com/wms/mapper/StockMapper.java +++ b/src/main/java/com/wms/mapper/StockMapper.java @@ -37,6 +37,23 @@ public interface StockMapper { */ int modifyStock(Stock stock); + /** + * 修改库存存储的位置 + * @param oldLocationId 旧库位 + * @param newLocationId 新库位 + * @return 结果 + */ + int updateLocation(@Param("oldLocationId") String oldLocationId, @Param("newLocationId") String newLocationId); + + /** + * 更新库存里的库位和库存状态 + * @param oldLocationId 旧库位 + * @param newLocationId 新库位 + * @param status 状态 + * @return 结果 + */ + int updateLocationAndStatus(@Param("oldLocationId") String oldLocationId, @Param("newLocationId") String newLocationId, @Param("status") Integer status); + /** * 删除库存 * @param stockId @@ -44,6 +61,21 @@ public interface StockMapper { */ int deleteStock(String stockId); + /** + * 根据库位删除库存 + * @param locationId 库位 + * @return 删除结果 + */ + int deleteStockWithLocationId(@Param("locationId") String locationId); + + /** + * 根据库位更新库位状态 + * @param locationId 库位 + * @param status 状态 + * @return 更新结果 + */ + int updateStockStatusWithLocationId(@Param("locationId") String locationId, @Param("status") Integer status); + List selStocksByGoodsId(Stock stock); List selStockOutOfDate(); diff --git a/src/main/java/com/wms/mapper/TaskMapper.java b/src/main/java/com/wms/mapper/TaskMapper.java index 3c760bc..f00d23e 100644 --- a/src/main/java/com/wms/mapper/TaskMapper.java +++ b/src/main/java/com/wms/mapper/TaskMapper.java @@ -35,4 +35,7 @@ public interface TaskMapper { * @return */ int deleteTask(String taskId); + + + List haveNotCompleteTask(String location); } diff --git a/src/main/java/com/wms/service/ContainerService.java b/src/main/java/com/wms/service/ContainerService.java new file mode 100644 index 0000000..1fa5a38 --- /dev/null +++ b/src/main/java/com/wms/service/ContainerService.java @@ -0,0 +1,27 @@ +package com.wms.service; + +import com.wms.entity.app.container.ContainerApiLocalResponse; +import com.wms.entity.app.container.CreateInstoreTaskRequest; +import com.wms.entity.app.container.CreateInstoreTaskResponse; +import com.wms.entity.app.container.TaskStateNoticeRequest; + +/** + * 四向车api的Service + */ +public interface ContainerService { + + /** + * 接收四向车扫码入库信息 + * @param request 请求信息 + * @return 返回信息 + */ + CreateInstoreTaskResponse createInstoreTask(CreateInstoreTaskRequest request); + + + /** + * 接收四向车任务状态通知 + * @param request 请求信息 + * @return 响应信息 + */ + ContainerApiLocalResponse taskStateNotice( TaskStateNoticeRequest request); +} diff --git a/src/main/java/com/wms/service/serviceImplements/parent/ContainerImplement.java b/src/main/java/com/wms/service/serviceImplements/parent/ContainerImplement.java new file mode 100644 index 0000000..f873e9f --- /dev/null +++ b/src/main/java/com/wms/service/serviceImplements/parent/ContainerImplement.java @@ -0,0 +1,174 @@ +package com.wms.service.serviceImplements.parent; + +import com.wms.bussiness.TaskOperation; +import com.wms.constants.enums.LocationStatus; +import com.wms.constants.enums.StockStatus; +import com.wms.constants.enums.TaskType; +import com.wms.constants.enums.WmsTaskStatus; +import com.wms.entity.app.container.ContainerApiLocalResponse; +import com.wms.entity.app.container.CreateInstoreTaskRequest; +import com.wms.entity.app.container.CreateInstoreTaskResponse; +import com.wms.entity.app.container.TaskStateNoticeRequest; +import com.wms.entity.table.Location; +import com.wms.entity.table.Stock; +import com.wms.entity.table.Task; +import com.wms.mapper.LocationMapper; +import com.wms.mapper.StockMapper; +import com.wms.mapper.TaskMapper; +import com.wms.service.ContainerService; +import com.wms.utils.StringUtils; +import com.wms.utils.storage.LocationUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.Objects; +import java.util.UUID; + +/** + * 四向车 api service 的实现 + */ +@Service +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class ContainerImplement implements ContainerService { + + + /** + * 库存 Mapper + */ + private final StockMapper stockMapper; + + /** + * 库位操作类 + */ + private final LocationUtils locationUtils; + + /** + * 任务表操作类 + */ + private final TaskMapper taskMapper; + + /** + * 库位 Mapper + */ + private final LocationMapper locationMapper; + + /** + * 任务操作类 + */ + private final TaskOperation taskOperation; + + /** + * 接收四向车请求扫码入库 + * @param request 请求信息 + * @return 响应信息 + */ + @Override + public CreateInstoreTaskResponse createInstoreTask(CreateInstoreTaskRequest request) { + String md5 = StringUtils.containerMd5(request.getRequestId()); + if(!md5.equals(request.getKey())) { + return new CreateInstoreTaskResponse("400", "请求失败,密钥校验未通过"); + } + /* 判断条码是否存在任务,条码扫出来的是批次号 */ + Stock waitInStockQuery = new Stock(); + waitInStockQuery.setBatchNo(request.getPalletNo()); + waitInStockQuery.setStockStatus(StockStatus.WAIT_IN.getCode()); + List waitInStockList = stockMapper.selStocks(waitInStockQuery); // 查找待入库的批次号 + if(waitInStockList.isEmpty()) { + return new CreateInstoreTaskResponse("400", String.format("条码:%s 不存在待入库的任务", request.getPalletNo())); + } + /* 查找可用库位 */ + List canUseLocations = locationUtils.getNewLocation(2); + if(canUseLocations.isEmpty()){ + return new CreateInstoreTaskResponse("400", "没有可用库位"); + } + Location useLocation = locationUtils.checkCanUse(canUseLocations); + if(useLocation == null) { + return new CreateInstoreTaskResponse("400", "暂没有可以直接使用的库位,因为存在互锁的库位,请等待当前任务都执行完成后再试"); + } + /* 找到可用的库位 */ /* 生成任务(生成的任务直接运行中,因为此处会把任务直接回回去),更新库存表内状态为入库中 */ + // 新建任务 插入任务表 + Task newInTask = new Task(); + newInTask.setTaskId(UUID.randomUUID().toString()); + newInTask.setTaskGroup(UUID.randomUUID().toString()); + newInTask.setTaskType(TaskType.IN.getCode()); + newInTask.setTaskStatus(WmsTaskStatus.WAIT.getCode()); // 因为任务是直接返回去的,所以直接是已下发状态 + newInTask.setOrigin(request.getFromCellNo()); + newInTask.setDestination(useLocation.getLocationId()); + newInTask.setGoodsId(String.format("%s 等 %d 个物料", waitInStockList.get(0).getGoodsId(), waitInStockList.size())); + newInTask.setWeight(Double.valueOf(request.getWeight())); + newInTask.setCreateTime(new java.util.Date()); + newInTask.setUserName("四向车API"); + newInTask.setVehicleSize(Integer.valueOf(request.getHeight())); + newInTask.setVehicleNo(request.getPalletNo()); + newInTask.setTaskPriority(1); + int insertTaskResult = taskMapper.addTask(newInTask); // 添加入库任务 + if(insertTaskResult < 1) { + return new CreateInstoreTaskResponse("400", "生成任务失败,无法插入新的入库任务"); + } + // 更新库存中的待入库记录为入库中,并将库位更新进去 + for(Stock waitInStock : waitInStockList) { + Stock updateStock = new Stock(); + updateStock.setStockId(waitInStock.getStockId()); + updateStock.setStockStatus(StockStatus.IN_ING.getCode()); + updateStock.setLocationId(useLocation.getLocationId()); + stockMapper.modifyStock(updateStock); + } + // 释放库位 + Location location = new Location(); + location.setLocationId(useLocation.getLocationId()); + location.setLocationStatus(LocationStatus.EMPTY.getCode()); + locationMapper.modifyLocation(location); + + CreateInstoreTaskResponse success = new CreateInstoreTaskResponse(); + success.setCode("200"); + success.setMessage("生成入库任务成功"); + success.setWmsTaskId(newInTask.getTaskId()); + success.setPalletNo(request.getPalletNo()); + success.setFromCellNo(request.getFromCellNo()); + success.setToCellNo(useLocation.getLocationId()); + return success; + } + + /** + * 接收四向车任务状态通知 + * @param request 请求信息 + * @return 响应信息 + */ + @Override + public ContainerApiLocalResponse taskStateNotice(TaskStateNoticeRequest request) { + String md5 = StringUtils.containerMd5(request.getRequestId()); + if(!md5.equals(request.getKey())) { + return new ContainerApiLocalResponse("400", "请求失败,密钥校验未通过"); + } + /* 查找出相关任务 */ + Task queryTask = new Task(); + queryTask.setTaskId(request.getWmsTaskId()); + List taskList = taskMapper.selTasks(queryTask); + if(taskList == null) { + return new ContainerApiLocalResponse("400", String.format("任务:%s 未找到任务,数据库查询失败", request.getWmsTaskId())); + } + if(taskList.isEmpty()) { + return new ContainerApiLocalResponse("400", String.format("任务:%s 不存在", request.getWmsTaskId())); + } + Task thisTask = taskList.get(0); + if(request.getTaskState().equals("20")) { // 任务完成 + boolean completeResult = taskOperation.completeTask(thisTask); + if(!completeResult) { + return new ContainerApiLocalResponse("400", String.format("任务:%s 完成事件异常,请重试", request.getWmsTaskId())); + } + return new ContainerApiLocalResponse("200", "任务完成"); + } + if(request.getTaskState().equals("21")) { // 任务取消 + boolean cancelResult = taskOperation.cancelTask(thisTask); + if(!cancelResult) { + return new ContainerApiLocalResponse("400", String.format("任务:%s 取消事件异常,请重试", request.getWmsTaskId())); + } + return new ContainerApiLocalResponse("200", "任务取消"); + } + return new ContainerApiLocalResponse("400", String.format("不支持的任务状态:%s", request.getTaskState())); + + + } +} diff --git a/src/main/java/com/wms/utils/StringUtils.java b/src/main/java/com/wms/utils/StringUtils.java index b28745c..8520285 100644 --- a/src/main/java/com/wms/utils/StringUtils.java +++ b/src/main/java/com/wms/utils/StringUtils.java @@ -1,6 +1,8 @@ package com.wms.utils; -import javax.xml.crypto.Data; +import org.slf4j.Logger; +import org.springframework.util.DigestUtils; + import java.text.SimpleDateFormat; import java.util.Date; @@ -10,6 +12,9 @@ import java.util.Date; * @date 2023/2/13 */ public class StringUtils { + + private static final Logger logger = org.slf4j.LoggerFactory.getLogger(StringUtils.class); + /** 空字符串 */ private static final String NULLSTR = ""; @@ -127,4 +132,16 @@ public class StringUtils { return new Date(0); } } + + private static final String containerMd5Key = "safer*123"; // 四向车接口密钥 + + /** + * 四向车 MD5 加密 + * @param string 要加密的字符串 + * @return 加密之后的值 + */ + public static String containerMd5(String string) { + String needMd5Str = string + containerMd5Key; + return DigestUtils.md5DigestAsHex(needMd5Str.getBytes()); + } } diff --git a/src/main/java/com/wms/utils/storage/LocationUtils.java b/src/main/java/com/wms/utils/storage/LocationUtils.java new file mode 100644 index 0000000..e3d5ccc --- /dev/null +++ b/src/main/java/com/wms/utils/storage/LocationUtils.java @@ -0,0 +1,106 @@ +package com.wms.utils.storage; + +import com.wms.constants.enums.LocationStatus; +import com.wms.entity.table.Location; +import com.wms.entity.table.Stock; +import com.wms.entity.table.Task; +import com.wms.mapper.LocationMapper; +import com.wms.mapper.StockMapper; +import com.wms.mapper.TaskMapper; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 库位工具类 + */ +@Component +@RequiredArgsConstructor(onConstructor = @__(@Autowired)) +public class LocationUtils { + + /** + * 库存 Mapper + */ + private final StockMapper stockMapper; + + /** + * 库位 Mapper + */ + private final LocationMapper locationMapper; + + /** + * 任务mapper + */ + private final TaskMapper taskMapper; + + /** + * 获取一个区域的可用的库位 + * @param areaId 区域ID + * @return 可用的库位排序 + */ + public List getNewLocation(Integer areaId) { + Location query = new Location(); + query.setAreaId(areaId); + query.setLocationStatus(LocationStatus.EMPTY.getCode()); + return locationMapper.selNextLocation(query); + } + + /** + * 在一堆空闲的库位中寻找一个可用的入库库位 + * @param canUseLocations 可用的库位 + * @return 可用的库位,若没有可用的库位则返回 null + */ + public Location checkCanUse(List canUseLocations) { + if(canUseLocations == null || canUseLocations.isEmpty()) { + return null; + } + for (Location location : canUseLocations) { + /* 校验此位置是否有遮挡 */ /* 如果这位置有库存(可能出现记错导致有库存),或者这位置其他深度(不论深度大小)有任务则不采用此位置 */ + /* 1 判断库存 */ + Stock checkStock = new Stock(); + checkStock.setLocationId(location.getLocationId()); + List checkResult = stockMapper.selStocks(checkStock); + if(!checkResult.isEmpty()) { + continue; // 库存不为空,跳过 + } + /* 2 判断同位置不同深度是否有任务 */ + // 找出此位置不同深度的库位 + Location queryDifferentDepthLocation = new Location(); + queryDifferentDepthLocation.setAreaId(location.getAreaId()); + queryDifferentDepthLocation.setEquipmentId(location.getEquipmentId()); + queryDifferentDepthLocation.setQueue(location.getQueue()); + queryDifferentDepthLocation.setLine(location.getLine()); + queryDifferentDepthLocation.setLayer(location.getLayer()); + List differentDepthLocations = locationMapper.selLocations(queryDifferentDepthLocation); + if(differentDepthLocations == null) { + continue; // 数据库查询失败 + } + boolean canUse = false; // 指示当前库位是否可用,若可用会置成 true + if(!differentDepthLocations.isEmpty()) { + // 存在干涉库位,检验其是否有未完成的任务 + for (Location differentDepthLocation : differentDepthLocations) { + // 找出此位置不同深度的库位 + Location queryLocationTask = new Location(); + queryLocationTask.setLocationId(differentDepthLocation.getLocationId()); + List locationTasks = taskMapper.haveNotCompleteTask(differentDepthLocation.getLocationId()); + if(locationTasks == null) { + continue; // 数据库查询失败 + } + if(!locationTasks.isEmpty()) { + break; // 有任务这个库位不行 + } + } + canUse = true; + } + if(canUse) { + return location; + } + } + return null; + } + + + +} diff --git a/src/main/resources/mapper/StockMapper.xml b/src/main/resources/mapper/StockMapper.xml index bfa6205..146c648 100644 --- a/src/main/resources/mapper/StockMapper.xml +++ b/src/main/resources/mapper/StockMapper.xml @@ -183,6 +183,15 @@ where stock_id = #{stockId} + + update tbl_app_stock set location_id = #{newLocationId} where location_id = #{oldLocationId} + + + update tbl_app_stock set location_id = #{newLocationId}, stock_status = #{status} where location_id = #{oldLocationId} + + + + update tbl_app_stock set available_num = real_num; @@ -191,4 +200,14 @@ delete from tbl_app_stock where stock_id = #{stockId} + + + + delete from tbl_app_stock where location_id = #{locationId} + + + + update tbl_app_stock set stock_status = #{status} where location_id = #{locationId} + + \ No newline at end of file diff --git a/src/main/resources/mapper/TaskMapper.xml b/src/main/resources/mapper/TaskMapper.xml index 72ef873..a984afb 100644 --- a/src/main/resources/mapper/TaskMapper.xml +++ b/src/main/resources/mapper/TaskMapper.xml @@ -146,4 +146,13 @@ delete from tbl_app_task where task_id = #{taskId} + + + \ No newline at end of file