自动化立体仓库 - WMS系统
#
zwl
昨天 da5d4106e294a229e3bf72939c6b7630e6345d76
#
39个文件已添加
24个文件已修改
3825 ■■■■ 已修改文件
src/main/java/com/zy/api/controller/HWmsApiController.java 163 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/HmesApiController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/WcsApiController.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/PageRequestParams.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/ReceviceTaskParams.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/WorkTaskParams.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/BaseRequstParam.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/CallAgvParams.java 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/CrnProtocol.java 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/DeviceConfig.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/DeviceStatusVo.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/DualCrnProtocol.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/MatnrsParams.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/OrderItemsParam.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/OrderParams.java 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/OutOrderParams.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/PubOrderParams.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/ReportOrderParam.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/ReportOrderParams.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/StationProtocol.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/StockAdjustParams.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/StockUpOrderParams.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/SyncMatParmas.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/dto/XSR.java 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/enums/LocAreaType.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/enums/MatLocType.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/enums/MatType.java 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/enums/OrderType.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/enums/OrderWkType.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/HWmsApiService.java 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/HmesApiService.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/WcsApiService.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/impl/HWmsApiServiceImpl.java 539 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java 68 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java 239 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/BasArmMastController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/BasArmMastLogController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/BasArmMastSignController.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LocDetlController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LocMastController.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/ManLocDetlController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/StaDescController.java 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/WrkMastController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/WrkMastLogController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/MesToCombParam.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/enums/CommonEnum.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/enums/ContainerType.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/enums/LocStsType.java 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/enums/MatTagType.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/OpenService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java 140 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/AutomaticallyIssueWCSTasksScheduler.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/WorkMastScheduler.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/AutomaticallyIssueWCSTasksHandler.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java 405 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/utils/Utils.java 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/model/StartupDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 612 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/WcsController.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/param/SearchLocParam.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/HWmsApiController.java
New file
@@ -0,0 +1,163 @@
package com.zy.api.controller;
import com.zy.api.controller.params.PageRequestParams;
import com.zy.api.entity.PubOrderParams;
import com.zy.api.entity.ReportOrderParam;
import com.zy.api.entity.StockAdjustParams;
import com.zy.api.entity.StockUpOrderParams;
import com.zy.api.entity.SyncMatParmas;
import com.zy.api.entity.dto.XSR;
import com.zy.api.service.HWmsApiService;
import com.zy.common.web.BaseController;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Objects;
@Slf4j
@RestController
@RequestMapping("/kopen")
public class HWmsApiController extends BaseController{
    @Autowired
    private HWmsApiService kopenApiService;
    /**
     * 上游下发派工单
     *
     * @author Ryan
     * @date 2025/11/24 15:18
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("入库单下发")
    @PostMapping("/sendInDispatch")
    public XSR receiveOrders(@RequestBody List<PubOrderParams> params) {
        if (Objects.isNull(params)) {
            return XSR.error("参数不能为空!!");
        }
//        if (Objects.isNull(params.getType())) {
//            return XSR.error("单据类型不能为空!");
//        }
        return kopenApiService.receiveOrders(params);
    }
    /**
     * 上游下发零件数据变更
     *
     * @author Ryan
     * @date 2025/11/24 15:19
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("零件信息数据更新")
    @PostMapping("/sendPartsMaster")
    public XSR basMatUpdate(@RequestBody List<SyncMatParmas> params) {
        if (Objects.isNull(params) || params.isEmpty()) {
            return XSR.error("参数不能为空!!");
        }
        return kopenApiService.basMatupdate(params);
    }
    /**
     * 上架派工单反馈
     * @author Ryan
     * @date 2025/11/24 15:20
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("上架派工单反馈")
    @PostMapping("/getInDispatchResult")
    public XSR getInDispatchResult(@RequestBody List<ReportOrderParam> params) {
        if (Objects.isNull(params)) {
            return XSR.error("参数不能为空!!");
        }
//        if (Objects.isNull(params.getKopen_id()) && Objects.isNull(params.getInv_no()) && Objects.isNull(params.getDispatch_no())) {
//            return XSR.error("取消条件不能为空!!");
//        }
        return kopenApiService.getInDispatchResult(params, null);
    }
    /**
     * 备货指示派工单下发
     * @author Ryan
     * @date 2025/11/24 15:21
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("备货指示派工单下发")
    @PostMapping("/sendOutDispatch")
    public XSR sendStockPrepareDispatch(@RequestBody List<PubOrderParams> params) {
        if (Objects.isNull(params)) {
            return XSR.error("参数不能为空!!");
        }
//        if (Objects.isNull(params.getDetails()) || params.getDetails().isEmpty()) {
//            return XSR.error("上报订单列表不能为空!!");
//        }
        return kopenApiService.sendOutDispatch(params);
    }
    //  /**
    //  * 备货指示派工单反馈
    //  * @author Ryan
    //  * @date 2025/11/24 15:22
    //  * @param params
    //  * @return com.core.common.R
    //  */
    // @ApiOperation("备货指示派工单反馈")
    // @PostMapping("/getOutDispatchResult")
    // public R getOutDispatchResult(@RequestBody ReportOrderParam params) {
    //     if (Objects.isNull(params)) {
    //         return R.error("参数不能为空!!");
    //     }
    //     if (Objects.isNull(params.getKopen_id()) && Objects.isNull(params.getInv_no()) && Objects.isNull(params.getDispatch_no())) {
    //         return R.error("取消条件不能为空!!");
    //     }
    //     return kopenApiService.getOutDispatchResult(params);
    // }
    /**
     * 备货单下发
     * @author Ryan
     * @date 2025/11/24 15:21
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("备货单下发")
    @PostMapping("/getOutDetails")
    public XSR getOutDetails(@RequestBody List<StockUpOrderParams> params) {
        if (Objects.isNull(params)) {
            return XSR.error("参数不能为空!!");
        }
        return kopenApiService.getOutDetails(params);
    }
    /**
     * 查询WMS库存信息
     * @author Ryan
     * @date 2025/11/24 15:22
     * @param params
     * @return com.core.common.R
     */
    @ApiOperation("查询WMS库存信息")
    @PostMapping("/getStockInfo")
    public XSR getStockInfo(@RequestBody PageRequestParams params) {
        return kopenApiService.getStockInfo(params);
    }
}
src/main/java/com/zy/api/controller/HmesApiController.java
New file
@@ -0,0 +1,15 @@
package com.zy.api.controller;
import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@Api(value = "HMES对接")
@RestController
@RequestMapping("/api")
public class HmesApiController {
}
src/main/java/com/zy/api/controller/WcsApiController.java
New file
@@ -0,0 +1,67 @@
package com.zy.api.controller;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.annotations.ManagerAuth;
import com.core.common.R;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.WaitPakin;
import com.zy.asrs.service.WaitPakinService;
import com.zy.asrs.utils.Utils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Objects;
@Api("WCS交互接口")
@RequestMapping("/wcs")
@RestController
public class WcsApiController {
    @Autowired
    private WcsApiService wcsApiService;
    @Autowired
    private WaitPakinService waitPakinService;
    /**
     * 下发任务至WCS
     * @author Ryan
     * @date 2026/1/10 13:57
     * @param params
     * @return com.core.common.R
     */
    @ManagerAuth
    @ApiOperation("下发任务至WCS")
    @PostMapping("/pub/wrks")
    public R pubWrkToWcs(@RequestBody WorkTaskParams params) {
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        return wcsApiService.pubWrkToWcs(params);
    }
//    @ManagerAuth
    @ApiOperation("设备执行状态回写-wcs任务完成回写")
    @PostMapping("/openapi/report")
    public R receviceTaskFromWcs(@RequestBody ReceviceTaskParams params) {
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        return wcsApiService.receviceTaskFromWcs(params);
    }
    @ManagerAuth
    @ApiOperation("获取组托入库托盘信息")
    @PostMapping("/openapi/waitPakins")
    public R waitPakins() {
        List<WaitPakin> waitPakins = waitPakinService.selectList(new EntityWrapper<WaitPakin>().eq("io_status", "N"));
        return R.ok().add(waitPakins);
    }
}
src/main/java/com/zy/api/controller/params/PageRequestParams.java
New file
@@ -0,0 +1,16 @@
package com.zy.api.controller.params;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel("分页请求参数")
public class PageRequestParams {
    private Integer curr = 1;
    private Integer limit = 50;
}
src/main/java/com/zy/api/controller/params/ReceviceTaskParams.java
New file
@@ -0,0 +1,46 @@
package com.zy.api.controller.params;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "ReceviceTaskParams", description = "穿线墙参数")
public class ReceviceTaskParams implements Serializable {
    @ApiModelProperty("机台号")
    private String devNo;
    @ApiModelProperty("流水号")
    private Long id;
    @ApiModelProperty("通知类型:task")
    private String notifyType;
    @ApiModelProperty("堆垛机号")
    private Integer device;
    @ApiModelProperty("WMS任务号")
    private String superTaskNo;
    @ApiModelProperty("消息类型:task_complete、task_cancel")
    private String msgType;
    @ApiModelProperty("消息描述")
    private String msgDesc;
    @ApiModelProperty("消息数据")
    private String data;
    @ApiModelProperty("重量")
    private Double weight;
    @ApiModelProperty("Y:冻结  N:解冻")
    private String freeze;
}
src/main/java/com/zy/api/controller/params/WorkTaskParams.java
New file
@@ -0,0 +1,49 @@
package com.zy.api.controller.params;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "WorkTaskParams", description = "执行任务参数")
public class WorkTaskParams implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("协议任务编号(对应出库任务号)")
    private String taskNo;
    @ApiModelProperty("工作档任务号")
    private String wrkNo;
    @ApiModelProperty("库位编码")
    private String locNo;
    //源库位
    private String sourceLocNo;
    //源站点
    private String sourceStaNo;
    @ApiModelProperty("条码")
    private String barcode;
    @ApiModelProperty("优先级")
    private Integer taskPri;
    @ApiModelProperty("出库站点")
    private String staNo;
    @ApiModelProperty("作业类型,in: 入库, out:出库")
    private String type;
    @ApiModelProperty("是否余料")
    private Integer isSuplus;
}
src/main/java/com/zy/api/entity/BaseRequstParam.java
New file
@@ -0,0 +1,15 @@
package com.zy.api.entity;
import java.util.Map;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@ApiModel("基础请求参数")
@Accessors(chain = true)
public class BaseRequstParam {
    private Map<String, Object> root;
}
src/main/java/com/zy/api/entity/CallAgvParams.java
New file
@@ -0,0 +1,35 @@
package com.zy.api.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "CallAgvParams", description = "AGV搬运参数")
public class CallAgvParams implements Serializable {
    @ApiModelProperty("呼叫类型:出库:out, 入库:in")
    private String type;
    @ApiModelProperty("原库位")
    private String orgLoc;
    @ApiModelProperty("目标站点")
    private String tarSite;
    @ApiModelProperty("原站点")
    private String orgSite;
    @ApiModelProperty("目标库位")
    private String tarLoc;
    @ApiModelProperty("搬运状态")
    private String status;
    @ApiModelProperty("任务号")
    private String wrkNo;
}
src/main/java/com/zy/api/entity/CrnProtocol.java
New file
@@ -0,0 +1,48 @@
package com.zy.api.entity;
import lombok.Data;
import java.util.Map;
@Data
public class CrnProtocol {
    private Integer crnNo;
    private Integer mode;           // 1=Manual, 2=Auto, 3=Computer
    private Object modeType;        // Enum: CrnModeType
    private Integer alarm;          // Error code
    private Integer taskNo;         // Task number
    private Integer status;         // Current status code
    private Object statusType;      // Enum: CrnStatusType
    private Integer bay;            // Current bay
    private Integer level;          // Current level
    private Integer forkPos;        // Fork position code
    private Object forkPosType;     // Enum: CrnForkPosType
    private Integer liftPos;        // Lift position code
    private Object liftPosType;     // Enum: CrnLiftPosType
    private Integer walkPos;        // 0=In Position, 1=Not in Position
    private Integer loaded;         // 1=Loaded, 0=Empty
    // Speed and Distance
    private Double xSpeed;
    private Double ySpeed;
    private Double zSpeed;
    private Double xDistance;
    private Double yDistance;
    private Double xDuration;
    private Double yDuration;
    // Other Info
    private String lastIo;          // "I"=Inbound, "O"=Outbound
    private Integer crnLane;        // Lane number
    private float weight;
    private String barcode;
    private Long deviceDataLog;
    private Long lastCommandTime;
    // Reserved/Temp
    private Integer temp1;
    private Integer temp2;
    private Integer temp3;
    private Integer temp4;
    private Map<String, Object> extend;
}
src/main/java/com/zy/api/entity/DeviceConfig.java
New file
@@ -0,0 +1,18 @@
package com.zy.api.entity;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
@Data
public class DeviceConfig implements Serializable {
    private Integer id;
    private String ip;
    private Integer port;
    private String threadImpl;
    private Date createTime;
    private String deviceType;
    private Integer deviceNo;
    private Integer fake;
    private String fakeInitStatus;
}
src/main/java/com/zy/api/entity/DeviceStatusVo.java
New file
@@ -0,0 +1,32 @@
package com.zy.api.entity;
import lombok.Data;
import java.util.List;
/**
 * Device Status Response Object
 * Corresponds to the map returned by OpenController.getDeviceStatus
 */
@Data
public class DeviceStatusVo {
    /**
     * Stacker Crane (CRN) Data List
     */
    private List<CrnProtocol> crnList;
    /**
     * RGV Device Config List
     * Note: The controller returns the DeviceConfig list for RGV, not the protocol status list.
     */
    private List<DeviceConfig> rgvList;
    /**
     * Dual-Station Stacker Crane Data List
     */
    private List<DualCrnProtocol> dualCrnList;
    /**
     * Conveyor Station Data List
     */
    private List<StationProtocol> stationList;
}
src/main/java/com/zy/api/entity/DualCrnProtocol.java
New file
@@ -0,0 +1,64 @@
package com.zy.api.entity;
import lombok.Data;
import java.util.Map;
@Data
public class DualCrnProtocol {
    private Integer crnNo;
    private Integer mode;
    private Object modeType;        // Enum: DualCrnModeType
    private Integer alarm;
    // Station 1 Data
    private Integer taskNo;
    private Integer status;
    private Object statusType;      // Enum: DualCrnStatusType
    private Integer bay;
    private Integer level;
    private Integer forkPos;
    private Object forkPosType;     // Enum: DualCrnForkPosType
    private Integer liftPos;
    private Object liftPosType;     // Enum: DualCrnLiftPosType
    private Integer walkPos;
    private Integer loaded;
    private Integer taskReceive;
    // Station 2 Data
    private Integer taskNoTwo;
    private Integer statusTwo;
    private Object statusTypeTwo;
    private Integer bayTwo;
    private Integer levelTwo;
    private Integer forkPosTwo;
    private Object forkPosTypeTwo;
    private Integer liftPosTwo;
    private Object liftPosTypeTwo;
    private Integer walkPosTwo;
    private Integer loadedTwo;
    private Integer taskReceiveTwo;
    // Movement Data (Integer type in DualCrnProtocol)
    private Integer xSpeed;
    private Integer ySpeed;
    private Integer zSpeed;
    private Integer xDistance;
    private Integer yDistance;
    private Integer xDuration;
    private Integer yDuration;
    // Other Info
    private Integer goodsType;
    private String barcode;
    private String lastIo;
    private Integer crnLane;
    private Long deviceDataLog;
    private Long lastCommandTime;
    // Reserved/Temp
    private Integer temp1;
    private Integer temp2;
    private Integer temp3;
    private Integer temp4;
    private Map<String, Object> extend;
}
src/main/java/com/zy/api/entity/MatnrsParams.java
New file
@@ -0,0 +1,43 @@
package com.zy.api.entity;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "MatnrsParams", description = "物料信息")
public class MatnrsParams {
    @ApiModelProperty("单据类型")
    private String pro_komcode;
    @ApiModelProperty("工单类型")
    private String pro_id;
    @ApiModelProperty("订单号")
    private String company_id;
    @ApiModelProperty("订单数量")
    private Double pro_name;
    @ApiModelProperty("操作人")
    private String pro_size;
    @ApiModelProperty("重量")
    private String pro_wet;
    @ApiModelProperty("零件类型")
    private String pro_type;
    @ApiModelProperty("更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private String update_time;
}
src/main/java/com/zy/api/entity/OrderItemsParam.java
New file
@@ -0,0 +1,50 @@
package com.zy.api.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "OrderItemsParam", description = "订单明细参数")
public class OrderItemsParam implements Serializable {
    @ApiModelProperty("BS Code")
    private String total_serial;
    @ApiModelProperty("目标库区")
    private String target_location;
    @ApiModelProperty("零件类型")
    private String pro_type;
    @ApiModelProperty("零件代码")
    private String pro_komcode;
    @ApiModelProperty("供应商编码")
    private String pro_id;
    @ApiModelProperty("入库通知数量")
    private Double inv_qty;
    @ApiModelProperty("指示拣货订单数量")
    private Integer order_qty;
    @ApiModelProperty("原上架派工数量")
    private Integer old_qty;
    @ApiModelProperty("变更数量")
    private Integer new_qty;
    @ApiModelProperty("捆绑/叫料/数量数量")
    private Integer pick_qty;
    @ApiModelProperty("损溢数量")
    private Integer bsby_qty;
    @ApiModelProperty("托盘编号")
    private String location_no;
}
src/main/java/com/zy/api/entity/OrderParams.java
New file
@@ -0,0 +1,66 @@
package com.zy.api.entity;
import java.io.Serializable;
import org.springframework.format.annotation.DateTimeFormat;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "OrderParams", description = "单据信息")
public class OrderParams implements Serializable {
    @ApiModelProperty("流水号(唯一)")
    private String kopen_id;
    @ApiModelProperty("派工单号")
    private String dispatch_no;
    @ApiModelProperty("公司ID")
    private String company_id;
    @ApiModelProperty("入库类型 1: 采购入库,2: 调拨入库,3: 销售退货入库,4: 套包入库, 5:SO, 6:EO, 7:出库")
    private String type;
    @ApiModelProperty("箱号")
    private String pm_tktid;
    @ApiModelProperty("入库通知单号")
    private String inv_no;
    @ApiModelProperty("目标库区")
    private String target_location;
    @ApiModelProperty("源库区")
    private String source_location;
    @ApiModelProperty("拣货单号")
    private String pick_no;
    @ApiModelProperty("订单号")
    private String order_no;
    @ApiModelProperty("客户ID")
    private String cus_id;
    @ApiModelProperty("客户地址")
    private String cus_address;
    @ApiModelProperty("WMS ID")
    private String wms_id;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private String update_time;
}
src/main/java/com/zy/api/entity/OutOrderParams.java
New file
@@ -0,0 +1,34 @@
package com.zy.api.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.List;
@Data
@Accessors(chain = true)
@ApiModel(value = "OutOrderParams", description = "备货订单参数")
public class OutOrderParams implements Serializable {
    @ApiModelProperty("明细备货单号")
    private String pick_no;
    @ApiModelProperty("订单号")
    private String order_no;
    @ApiModelProperty("客户")
    private String cus_id;
    @ApiModelProperty("客户地址")
    private String cus_address;
    @ApiModelProperty("业务类型")
    private String type;
    @ApiModelProperty("订单明细")
    private List<OrderItemsParam> partList;
}
src/main/java/com/zy/api/entity/PubOrderParams.java
New file
@@ -0,0 +1,17 @@
package com.zy.api.entity;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "PubOrderParams", description = "发布订单信息")
public class PubOrderParams extends OrderParams {
    @ApiModelProperty("入库物料列表")
    List<OrderItemsParam> details;
}
src/main/java/com/zy/api/entity/ReportOrderParam.java
New file
@@ -0,0 +1,18 @@
package com.zy.api.entity;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "ReportOrderParam", description = "上报订单信息")
public class ReportOrderParam extends OrderParams{
    @ApiModelProperty("上报订单列表")
    List<ReportOrderParams> details;
}
src/main/java/com/zy/api/entity/ReportOrderParams.java
New file
@@ -0,0 +1,55 @@
package com.zy.api.entity;
import java.io.Serializable;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel("上报订单参数")
public class ReportOrderParams implements Serializable {
        @ApiModelProperty("BS Code")
        private String total_serial;
        @ApiModelProperty("产品类型")
        private String pro_type;
        @ApiModelProperty("零件代码")
        private String pro_komcode;
        @ApiModelProperty("供应商ID")
        private String pro_id;
        @ApiModelProperty("容器编码")
        private String location_no;
        @ApiModelProperty("货位类型")
        private String location_type;
        @ApiModelProperty("上架日期")
        private String sj_date;
        @ApiModelProperty("上架人")
        private String sj_emp;
        @ApiModelProperty("上架数量")
        private Integer pick_qty;
        @ApiModelProperty("破损数量")
        private Integer damage_qty;
        @ApiModelProperty("差异数量")
        private Integer diff_qty;
        @ApiModelProperty("原上架派工数量")
        private Integer old_qty;
        @ApiModelProperty("变更数量")
        private Integer new_qty;
}
src/main/java/com/zy/api/entity/StationProtocol.java
New file
@@ -0,0 +1,28 @@
package com.zy.api.entity;
import lombok.Data;
import java.util.Map;
@Data
public class StationProtocol {
    private Integer stationId;      // Station ID
    private Integer taskNo;         // Task number
    private Integer targetStaNo;    // Target Station ID
    // Status Flags
    private boolean autoing;        // Auto mode
    private boolean loading;        // Has goods
    private boolean inEnable;       // Inbound enabled
    private boolean outEnable;      // Outbound enabled
    private boolean emptyMk;        // Empty pallet mark
    private boolean fullPlt;        // Full pallet
    private boolean runBlock;       // Running blocked
    private boolean enableIn;       // Start inbound
    private Integer palletHeight;
    private Integer error;          // Error code
    private String errorMsg;        // Error message
    private String barcode;
    private Double weight;
    private Map<String, Object> extend;
}
src/main/java/com/zy/api/entity/StockAdjustParams.java
New file
@@ -0,0 +1,27 @@
package com.zy.api.entity;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "StockAdjustParams", description = "零件损溢单参数")
public class StockAdjustParams extends OrderParams {
    @ApiModelProperty("调整原因")
    private String reason;
    @ApiModelProperty("调整原因名称")
    private String reason_name;
    @ApiModelProperty("调整单编号")
    private String bsby_no;
    @ApiModelProperty("调整单明细列表")
    List<OrderItemsParam> details;
}
src/main/java/com/zy/api/entity/StockUpOrderParams.java
New file
@@ -0,0 +1,19 @@
package com.zy.api.entity;
import java.util.List;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "StockUpOrderParams", description = "备货订单参数")
public class StockUpOrderParams extends OrderParams{
    @ApiModelProperty("订单明细")
    private List<OutOrderParams> details;
}
src/main/java/com/zy/api/entity/SyncMatParmas.java
New file
@@ -0,0 +1,45 @@
package com.zy.api.entity;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "SyncMatParmas", description = "物料同步参数")
public class SyncMatParmas implements Serializable {
    @ApiModelProperty("零件类型")
    private String pro_type;
    @ApiModelProperty("零件代码")
    private String pro_komcode;
    @ApiModelProperty("供应商编码")
    private String pro_id;
    @ApiModelProperty("入库通知数量")
    private Double inv_qty;
    @ApiModelProperty("公司ID")
    private String company_id;
    @ApiModelProperty("零件名称")
    private String pro_name;
    @ApiModelProperty("尺寸")
    private String pro_size;
    @ApiModelProperty("重量")
    private String pro_wet;
    @ApiModelProperty("更新时间")
    private String update_time;
}
src/main/java/com/zy/api/entity/dto/XSR.java
New file
@@ -0,0 +1,77 @@
package com.zy.api.entity.dto;
import java.sql.Date;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
@ApiModel(value = "XSR", description = "基础响应")
public class XSR<T> {
    private static final String SUCCESS_CODE = "200";
    private static final String FAIL_CODE = "500";
    private String code;
    private String message;
    private Boolean success;
    private String returnMessage;
    private T result;
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    private Date timestamp;
    public XSR() {
        this.timestamp = new Date(System.currentTimeMillis());
    }
    public static <T> XSR<T> ok() {
        return new XSR<T>()
                .setCode(SUCCESS_CODE)
                .setSuccess(true)
                .setMessage("操作成功")
                .setReturnMessage("操作成功");
    }
    public static <T> XSR<T> ok(T data) {
        return new XSR<T>()
                .setCode(SUCCESS_CODE)
                .setSuccess(true)
                .setMessage("操作成功")
                .setReturnMessage("操作成功")
                .setResult(data);
    }
    public static <T> XSR<T> ok(T data, String message) {
        return new XSR<T>()
                .setCode(SUCCESS_CODE)
                .setSuccess(true)
                .setMessage(message)
                .setReturnMessage(message)
                .setResult(data);
    }
    public static <T> XSR<T> error(String message) {
        return new XSR<T>()
                .setCode(FAIL_CODE)
                .setSuccess(false)
                .setMessage(message)
                .setReturnMessage(message);
    }
    public static <T> XSR<T> error(String code, String message) {
        return new XSR<T>()
                .setCode(code)
                .setSuccess(false)
                .setMessage(message)
                .setReturnMessage(message);
    }
}
src/main/java/com/zy/api/enums/LocAreaType.java
New file
@@ -0,0 +1,24 @@
package com.zy.api.enums;
/**
 * 库区类型
 */
public enum LocAreaType {
    /** 大库区 */
     AUTOMATED("1", "立库"),
    /** 中库区 */
    SO_HOLDING("2", "SO等待区"),
    /** 小件库区 */
    EO_HOLDING("3", "EO等待区");
    public String type;
    public String desc;
    LocAreaType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
}
src/main/java/com/zy/api/enums/MatLocType.java
New file
@@ -0,0 +1,65 @@
package com.zy.api.enums;
/**
 * 物料所属库位类型
 * @author Ryan
 * @date 2025/12/6 10:41
 * @return null
 */
public enum MatLocType {
    /** 小件 */
    AUTOMATED("12", "小件"),
    /** 中件 */
    SO_HOLDING("13", "中件"),
    /** 大件 */
    EO_HOLDING("14", "滤芯");
    public String type;
    public String desc;
    MatLocType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public static String getTagName(String type) {
        if (type.equals(MatLocType.AUTOMATED.type)) {
            return MatLocType.AUTOMATED.desc;
        } else if (type.equals(MatLocType.SO_HOLDING.type)) {
            return MatLocType.SO_HOLDING.desc;
        } else if (type.equals(MatLocType.EO_HOLDING.type)) {
            return MatLocType.EO_HOLDING.desc;
        } else {
            return null;
        }
    }
    public static Long getTag(String type) {
        if (type.equals(MatType.LARGE.type)) {
            return Long.parseLong(MatLocType.AUTOMATED.type);
        } else if (type.equals(MatType.MIDDEL.type)) {
            return Long.parseLong(MatLocType.SO_HOLDING.type);
        } else if (type.equals(MatType.SMALL.type)) {
            return Long.parseLong(MatLocType.EO_HOLDING.type);
        } else {
            return null;
        }
    }
    public static String getMatTag(String type) {
        if (type.equals(MatLocType.AUTOMATED.type)) {
            return MatType.LARGE.type;
        } else if (type.equals(MatLocType.SO_HOLDING.type)) {
            return MatType.MIDDEL.type;
        } else if (type.equals(MatLocType.EO_HOLDING.type)) {
            return MatType.SMALL.type;
        } else {
            return null;
        }
    }
}
src/main/java/com/zy/api/enums/MatType.java
New file
@@ -0,0 +1,36 @@
package com.zy.api.enums;
/**
 * 物料类型
 */
public enum MatType {
    /** 滤芯 */
    LARGE("1", "滤芯"),
    /** 中件 */
    MIDDEL("2", "中件"),
    /** 小件 */
    SMALL("3", "小件");
    public String type;
    public String desc;
    MatType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public static Long getTag(String type) {
        if (type.equals(MatType.LARGE.type)) {
            return Long.parseLong(MatLocType.AUTOMATED.type);
        } else if (type.equals(MatType.MIDDEL.type)) {
            return Long.parseLong(MatLocType.SO_HOLDING.type);
        } else if (type.equals(MatType.SMALL.type)) {
            return Long.parseLong(MatLocType.EO_HOLDING.type);
        } else {
            return null;
        }
    }
}
src/main/java/com/zy/api/enums/OrderType.java
New file
@@ -0,0 +1,57 @@
package com.zy.api.enums;
/**
 * @author Ryan
 * @version 1.0
 * @title PurchaseType
 * @description
 * @create 2025/3/5 15:54
 */
public enum OrderType {
    //订单类型
    ORDER_OUT("out", "出库单"),
    ORDER_IN("in", "入库单"),
    ORDER_TRANSFER("transfer", "调拔单"),
    ORDER_REVISE("revise", "库存调整"),
    ORDER_CHECK("check", "盘点单");
    OrderType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public String type;
    public String desc;
    public static String getTypeVal(String desc) {
        if (desc.equals(OrderType.ORDER_IN.desc)) {
            return OrderType.ORDER_IN.type;
        } else if (desc.equals(OrderType.ORDER_OUT.desc)) {
            return OrderType.ORDER_OUT.type;
        } else if (desc.equals(OrderType.ORDER_CHECK.desc)) {
            return OrderType.ORDER_CHECK.type;
        } else if (desc.equals(OrderType.ORDER_TRANSFER.desc)) {
            return OrderType.ORDER_TRANSFER.type;
        } else if (desc.equals(OrderType.ORDER_REVISE.desc)) {
            return OrderType.ORDER_REVISE.type;
        }
        return null;
    }
    public static String getValType(String type) {
        if (type.equals(OrderType.ORDER_IN.type)) {
            return OrderType.ORDER_IN.desc;
        } else if (type.equals(OrderType.ORDER_OUT.type)) {
            return OrderType.ORDER_OUT.desc;
        } else if (type.equals(OrderType.ORDER_CHECK.type)) {
            return OrderType.ORDER_CHECK.desc;
        } else if (type.equals(OrderType.ORDER_TRANSFER.type)) {
            return OrderType.ORDER_TRANSFER.desc;
        } else if (type.equals(OrderType.ORDER_REVISE.type)) {
            return OrderType.ORDER_REVISE.desc;
        }
        return null;
    }
}
src/main/java/com/zy/api/enums/OrderWkType.java
New file
@@ -0,0 +1,45 @@
package com.zy.api.enums;
public enum OrderWkType {
    // 订单类型
    ORDER_WK_PUR_IN("0", "采购入库"),
    ORDER_WK_TRANSFER_IN("1", "调拔入库"),
    ORDER_WK_SALE_IN("2", "客户退货"),
    ORDER_WK_BAG_IN("5", "索赔入库"),
    ORDER_WK_SUPLUS_IN("7", "报溢入库"),
    ORDER_WK_PRO_UPDATE_IN("8", "件号变更入库"),
    ORDER_WK_MEGER_IN("K", "组合拆零入库"),
    ORDER_WK_ORDER_OUT_EO("11", "备货指示派工单(EO)"),
    ORDER_WK_ORDER_OUT_SO("12", "备货指示派工单(SO)"),
    ORDER_WK_ORDER_OUT("13", "备货单");
    OrderWkType(String val, String desc) {
        this.val = val;
        this.desc = desc;
    }
    public String val;
    public String desc;
    public static String getTypeVal(String val) {
        if (val.equals(OrderWkType.ORDER_WK_PUR_IN.val)
                || val.equals(OrderWkType.ORDER_WK_SUPLUS_IN.val)
                || val.equals(OrderWkType.ORDER_WK_MEGER_IN.val)
                || val.equals(OrderWkType.ORDER_WK_PRO_UPDATE_IN.val)) {
            return OrderType.ORDER_IN.type;
        } else if (val.equals(OrderWkType.ORDER_WK_TRANSFER_IN.val)) {
            return OrderType.ORDER_IN.type;
        } else if (val.equals(OrderWkType.ORDER_WK_SALE_IN.val)) {
            return OrderType.ORDER_IN.type;
        } else if (val.equals(OrderWkType.ORDER_WK_BAG_IN.val)) {
            return OrderType.ORDER_IN.type;
        } else if (val.equals(OrderWkType.ORDER_WK_ORDER_OUT_EO.val)  || val.equals(OrderWkType.ORDER_WK_ORDER_OUT_SO.val)  || val.equals(OrderWkType.ORDER_WK_ORDER_OUT.val)) {
            return OrderType.ORDER_OUT.type;
        } else {
            return null;
        }
    }
}
src/main/java/com/zy/api/service/HWmsApiService.java
New file
@@ -0,0 +1,78 @@
package com.zy.api.service;
import java.util.List;
import com.zy.api.controller.params.PageRequestParams;
import com.zy.api.entity.PubOrderParams;
import com.zy.api.entity.ReportOrderParam;
import com.zy.api.entity.StockAdjustParams;
import com.zy.api.entity.StockUpOrderParams;
import com.zy.api.entity.SyncMatParmas;
import com.zy.api.entity.dto.XSR;
import com.zy.asrs.entity.Order;
public interface HWmsApiService {
    /**
     * 上架派工单下发
     * @author Ryan
     * @date 2025/11/24 14:42
     * @param params
     * @return com.core.common.R
     */
    XSR receiveOrders(List<PubOrderParams> params);
    /**
     * 基础零件变更
     * @author Ryan
     * @date 2025/11/24 15:04
     * @param matnrs
     * @return com.core.common.R
     */
    XSR basMatupdate(List<SyncMatParmas> matnrs);
    /**
     * 新增或修改单据信息
     * @author Ryan
     * @date 2025/11/24 15:33
     */
    void addOrUpdateOrders(PubOrderParams params, String type) ;
    /**
     * 上架派工单反馈
     *
     * @param params
     * @param order
     * @return
     */
    XSR getInDispatchResult(List<ReportOrderParam> params, Order order);
    /**
     * 备货指示派工单下发
     * @param params
     * @return
     */
    XSR sendOutDispatch(List<PubOrderParams> params);
    /**
     * 备货单下发
     * @author Ryan
     * @date 2025/11/24 15:40
     * @param params
     * @return com.core.common.R
     */
    XSR getOutDetails(List<StockUpOrderParams> params);
    /**
     * 查询WMS库存信息
     * @author Ryan
     * @date 2025/11/24 15:22
     * @param params
     * @return com.core.common.R
     */
    XSR getStockInfo(PageRequestParams params);
}
src/main/java/com/zy/api/service/HmesApiService.java
New file
@@ -0,0 +1,12 @@
package com.zy.api.service;
import com.core.common.R;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.asrs.entity.param.OpenOrderPakoutParam;
public interface HmesApiService {
    R pubWorkTask(OpenOrderPakoutParam params);
    R releaseLock(ReceviceTaskParams params);
}
src/main/java/com/zy/api/service/WcsApiService.java
New file
@@ -0,0 +1,37 @@
package com.zy.api.service;
import com.core.common.R;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.StopOutTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import java.util.Set;
public interface WcsApiService {
    /**
     * 下发任务至WCS
     * @author Ryan
     * @date 2026/1/10 13:57
     * @param params
     * @return com.core.common.R
     */
    R pubWrkToWcs(WorkTaskParams params);
    /**
     * 堆垛机任务完成状态上报
     * @author Ryan
     * @date 2026/1/10 16:29
     * @param params
     * @return com.core.common.R
     */
    R receviceTaskFromWcs(ReceviceTaskParams params);
    /**
     * batch pause out tasks
     * @param params
     * @return
     */
    R pauseOutTasks(StopOutTaskParams params);
}
src/main/java/com/zy/api/service/impl/HWmsApiServiceImpl.java
New file
@@ -0,0 +1,539 @@
package com.zy.api.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.core.common.SnowflakeIdWorker;
import com.core.exception.CoolException;
import com.zy.api.controller.params.PageRequestParams;
import com.zy.api.entity.OrderItemsParam;
import com.zy.api.entity.OrderParams;
import com.zy.api.entity.OutOrderParams;
import com.zy.api.entity.PubOrderParams;
import com.zy.api.entity.ReportOrderParam;
import com.zy.api.entity.StockUpOrderParams;
import com.zy.api.entity.SyncMatParmas;
import com.zy.api.entity.dto.XSR;
import com.zy.api.enums.MatLocType;
import com.zy.api.enums.OrderType;
import com.zy.api.enums.OrderWkType;
import com.zy.api.service.HWmsApiService;
import com.zy.asrs.entity.LocDetl;
import com.zy.asrs.entity.Mat;
import com.zy.asrs.entity.Order;
import com.zy.asrs.entity.OrderDetl;
import com.zy.asrs.enums.CommonEnum;
import com.zy.asrs.service.LocDetlService;
import com.zy.asrs.service.MatService;
import com.zy.asrs.service.OrderDetlService;
import com.zy.asrs.service.OrderService;
import com.zy.asrs.utils.Utils;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
@Slf4j
@Service("kopenApiServiceImpl")
public class HWmsApiServiceImpl implements HWmsApiService {
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderDetlService orderDetlService;
    @Autowired
    private MatService matService;
    @Autowired
    private LocDetlService locDetlService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
//    @Value("${kopen.url}")
    private String url;
//    @Value("${kopen.port}")
    private String port;
//    @Value("${kopen.prefix}")
    private String prefix;
    /**
     * 接收下发订单信息
     *
     * @param orderParams
     * @return com.core.common.R
     * @author Ryan
     * @date 2025/11/24 14:49
     */
    @Override
    public XSR receiveOrders(List<PubOrderParams> orderParams) {
        orderParams.forEach(params -> {
            if (params.getType().equals(OrderWkType.getTypeVal(params.getType()))) {
                throw new CoolException("当前类型不是上架派工单!!");
            }
            addOrUpdateOrders(params, "add");
        });
        return XSR.ok("单据下发成功!!");
    }
    /**
     * 上架派工单反馈
     *
     * @author Ryan
     * @date 2025/11/24 15:33
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XSR getInDispatchResult(List<ReportOrderParam> params, Order order) {
        if (Objects.isNull(params)) {
            return XSR.error("参数不能为空!!");
        }
        String response = null;
        try {
            response = new HttpHandler.Builder()
                    .setUri(url + ":" + port)
                    .setPath(prefix + "/getInDispatchResult")
                    .setJson(JSONObject.toJSONString(params))
                    .build()
                    .doPost();
            if (Objects.isNull(response) || response.trim().isEmpty()) {
                return XSR.error("外网接口无响应!!");
            }
            JSONObject jsonObject = JSONObject.parseObject(response);
            Integer code = jsonObject.getInteger("code");
            if (!Objects.isNull(code) && code.equals(200)) {
                if (!Objects.isNull(order)) {
//                    order.setReportOnce(5);
                    orderService.updateById(order);
                }
                return XSR.ok("入库单上报完成!!");
            } else {
                if (!Objects.isNull(order)) {
//                    int reportOnce = order.getReportOnce();
//                    reportOnce ++;
//                    order.setReportOnce(reportOnce);
                    orderService.updateById(order);
                }
                String msg = jsonObject.getString("message");
                return XSR.error(Objects.isNull(msg) ? "上报失败!!" : msg);
            }
        } catch (Exception e) {
            if (!Objects.isNull(order)) {
//                int reportOnce = order.getReportOnce();
//                reportOnce ++;
//                order.setReportOnce(reportOnce);
                orderService.updateById(order);
            }
            log.error(e.getMessage(), e);
            return XSR.error(e.getMessage());
        }
    }
    /**
     * 获取自定义请求头
     * @author Ryan
     * @date 2025/12/29 9:11
     * @return java.util.Map<java.lang.String,java.lang.Object>
     */
    private Map<String, Object> getHeaderParam() {
        Map<String, Object> headerParam = new HashMap<>();
//        headerParam.put("accept", "*/*");
//        headerParam.put("connection", "Keep-Alive");
        //设置请求连接的Token
        headerParam.put("api_key", "WMS");
        headerParam.put("charset", "UTF-8");
        headerParam.put("timestamp", new Date());
        headerParam.put("format", "xml");
        headerParam.put("signature", "c56ced444ed772098ffeb59537bbfa59");
        return headerParam;
    }
    /* */
    /**
     * 备货指示派工单下发
     *
     * @param pubOrderParams
     * @return com.core.common.R
     * @author Ryan
     * @date 2025/11/24 15:21
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public XSR sendOutDispatch(List<PubOrderParams> pubOrderParams) {
        if (Objects.isNull(pubOrderParams) || pubOrderParams.isEmpty()) {
            return XSR.error("参数不能为空!!");
        }
        pubOrderParams.forEach(params -> {
            // 校验参数
            if (Objects.isNull(params.getDispatch_no())) {
                throw new CoolException("派工单编号不能为空!!");
            }
            if (Objects.isNull(params.getKopen_id())) {
                throw new CoolException("流水号不能为空!!");
            }
            if (Objects.isNull(params.getCompany_id())) {
                throw new CoolException("公司ID不能为空!!");
            }
            addOrUpdateOrders(params, "add");
        });
        return XSR.ok("备货指示派工单下发成功!!");
    }
    // /**
    // * 备货指示派工单
    // *
    // * @author Ryan
    // * @date 2025/12/16 9:15
    // * @param params
    // */
    // private void outOrderAddAndUpdate(PubOrderParams params, String type) {
    // if (Objects.isNull(params)) {
    // throw new CoolException("参数不能为空!!");
    // }
    // if (Objects.isNull(params.getType())) {
    // throw new CoolException("订单类型不能为空!!");
    // }
    // OrderParams orderParams =
    // JSONObject.parseObject(JSONObject.toJSONString(params), OrderParams.class);
    // Order order = orderService.selectOne(new
    // EntityWrapper<Order>().eq("order_no", orderParams.getInv_no()));
    // if (type.equals("add") && !Objects.isNull(order)) {
    // throw new CoolException("单据已存在, 不可重复添加!!");
    // }
    // // 判断订单是否存在
    // if (Objects.isNull(order)) {
    // /** 不存在,新增订单 */
    // generateOrders(params);
    // } else {
    // /** 存在,删除老订单,更新插入新订单 */
    // // 删除旧订单明细
    // if (!orderDetlService.delete(new EntityWrapper<OrderDetl>().eq("order_id",
    // order.getId()))) {
    // throw new CoolException("订单明细删除失败!!");
    // }
    // ;
    // if (!orderService.deleteById(order.getId())) {
    // throw new CoolException("原单据删除失败!!");
    // }
    // generateOrders(params);
    // }
    // }
    /**
     * 基础零件变更
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2025/11/24 15:05
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized XSR basMatupdate(List<SyncMatParmas> params) {
        if (Objects.isNull(params) || params.isEmpty()) {
            return XSR.error("参数不能为空!!");
        }
        params.forEach(mats -> {
            if (Objects.isNull(mats)) {
                throw new CoolException("物料编码不能为空!!");
            }
            if (Objects.isNull(mats.getPro_type())) {
                throw new CoolException("零件类型不能为空!!");
            }
            Mat matnr = matService.selectOne(new EntityWrapper<Mat>().eq("matnr", mats.getPro_komcode()));
            if (!Objects.isNull(matnr)) {
//                // 订单时间
//                if (Utils.isValidFormat(mats.getUpdate_time(), "yyyy-MM-dd HH:mm:ss")) {
//                    Date date1 = Utils.getFormateDate(mats.getUpdate_time());
//                    matnr.setUpdateTime(date1);
//                }
//                matnr.setMaktx(mats.getPro_name());
//                matnr.setSpecs(mats.getPro_size());
//                matnr.setWeight(Objects.isNull(mats.getPro_wet()) ? 0.0 : Double.parseDouble(mats.getPro_wet()));
//                matnr.setSuppCode(mats.getPro_id());
//                matnr.setTagId(MatLocType.getTag(mats.getPro_type()));
//                matnr.setLocType(MatLocType.getTag(mats.getPro_type()));
//                matnr.setManu(mats.getCompany_id());
//                if (!matService.updateById(matnr)) {
//                    throw new CoolException("物料更新失败或无需更新!!");
//                }
            } else {
                if (Objects.isNull(matnr)) {
                    matnr = new Mat();
                }
//                // 订单时间
//                if (Utils.isValidFormat(mats.getUpdate_time(), "yyyy-MM-dd HH:mm:ss")) {
//                    Date date1 = Utils.getFormateDate(mats.getUpdate_time());
//                    matnr.setUpdateTime(date1);
//                }
//                matnr.setMaktx(mats.getPro_name());
//                matnr.setMatnr(mats.getPro_komcode());
//                matnr.setSpecs(mats.getPro_size());
//                matnr.setWeight(Double.parseDouble(mats.getPro_wet()));
//                matnr.setSuppCode(mats.getPro_id());
//                matnr.setTagId(MatLocType.getTag(mats.getPro_type()));
//                matnr.setLocType(MatLocType.getTag(mats.getPro_type()));
//                matnr.setManu(mats.getCompany_id());
//                if (!matService.insert(matnr)) {
//                    throw new CoolException("物料更新失败!!");
//                }
            }
        });
        return XSR.ok("保存成功!!");
    }
    /**
     * 新增或修改订单信息
     *
     * @author Ryan
     * @date 2025/11/24 15:32
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrUpdateOrders(PubOrderParams params, String type) {
        if (Objects.isNull(params)) {
            throw new CoolException("参数不能为空!!");
        }
        if (Objects.isNull(params.getType())) {
            throw new CoolException("订单类型不能为空!!");
        }
        OrderParams orderParams = JSONObject.parseObject(JSONObject.toJSONString(params), OrderParams.class);
        // Order order = orderService.selectOne(new
        // EntityWrapper<Order>().eq("order_no", orderParams.getDispatch_no()));
        Order order = null;
        if (OrderType.ORDER_IN.type.equals(OrderWkType.getTypeVal(params.getType()))) {
            // 入库
            order = orderService.selectOne(new EntityWrapper<Order>().eq("order_no",
                    orderParams.getDispatch_no()));
        } else if (OrderType.ORDER_OUT.type.equals(OrderWkType.getTypeVal(params.getType()))) {
            // 出库
            if (OrderWkType.ORDER_WK_ORDER_OUT.val.equals(params.getType())) {
                // 备货单出库
                order = orderService.selectOne(new EntityWrapper<Order>().eq("order_no",
                        orderParams.getPick_no()));
            } else if (OrderWkType.ORDER_WK_ORDER_OUT_EO.val.equals(params.getType())
                    || OrderWkType.ORDER_WK_ORDER_OUT_SO.val.equals(params.getType())) {
                // 备货指示派工单(EO/SO)出库
                order = orderService.selectOne(new EntityWrapper<Order>().eq("order_no",
                        orderParams.getDispatch_no()));
            } else {
                throw new CoolException("单据类型不存在,不支持添加!!");
            }
        } else {
            throw new CoolException("单据类型不存在,不支持添加!!");
        }
        // 出库
        if (type.equals("add") && !Objects.isNull(order)) {
            throw new CoolException("单据已存在, 不可重复添加!!");
        }
        // 判断订单是否存在
        if (Objects.isNull(order)) {
            /** 不存在,新增订单 */
            generateOrders(params);
        } else {
            /** 存在,删除老订单,更新插入新订单 */
            // 删除旧订单明细
            if (!orderDetlService.delete(new EntityWrapper<OrderDetl>().eq("order_id", order.getId()))) {
                throw new CoolException("订单明细删除失败!!");
            }
            if (!orderService.deleteById(order.getId())) {
                throw new CoolException("原单据删除失败!!");
            }
            generateOrders(params);
        }
    }
    public static String generateUUID(OrderParams params) {
        return UUID.randomUUID().toString();
    }
    /**
     * 生成订单信息
     *
     * @param params
     */
    @Transactional(rollbackFor = Exception.class)
    public void generateOrders(PubOrderParams params) {
        // 将数据当新订单插入
        Order newOrder = new Order();
        // 派工单号
        newOrder.setOrderNo(params.getDispatch_no());
        if (OrderType.ORDER_IN.type.equals(OrderWkType.getTypeVal(params.getType()))) {
            // 入库
            newOrder.setPakinPakoutStatus(1);
//            Integer docType = OrderWkType.getDocType(params.getType());
//            newOrder.setDocType(Long.parseLong(docType + ""));
            newOrder.setNumber(params.getInv_no());
        } else if (OrderType.ORDER_OUT.type.equals(OrderWkType.getTypeVal(params.getType()))) {
            // 出库
            if (OrderWkType.ORDER_WK_ORDER_OUT.val.equals(params.getType())) {
                // 备货单出库
                newOrder.setOrderNo(params.getPick_no());
                newOrder.setNumber(params.getDispatch_no());
                newOrder.setShipCode(params.getOrder_no());
                newOrder.setCstmrName(params.getCus_id());
                newOrder.setTel(params.getCus_address());
//                newOrder.setDocType(Long.parseLong(OrderTypeEnum.STOCK.type + ""));
            } else if (OrderWkType.ORDER_WK_ORDER_OUT_EO.val.equals(params.getType())
                    || OrderWkType.ORDER_WK_ORDER_OUT_SO.val.equals(params.getType())) {
                // 备货指示派工单(EO/SO)出库
//                newOrder.setDocType(Long.parseLong(OrderTypeEnum.TRANSFER.type + ""));
            }
            newOrder.setPakinPakoutStatus(2);
        }
        newOrder.setUuid(generateUUID(params));
        // 流水号(唯一)
        newOrder.setDefNumber(params.getKopen_id());
//        newOrder.setTargetLocation(params.getTarget_location());
        // 箱号
        newOrder.setItemName(params.getPm_tktid());
//        newOrder.setSettle(OrderSettle.ORDER_SETTLE_HOLDING.type);
        newOrder.setStatus(CommonEnum.COMMON_ENUM_Y.type);
        // 订单时间
//        if (Utils.isValidFormat(params.getUpdate_time(), "yyyy-MM-dd HH:mm:ss")) {
//            newOrder.setOrderTime(params.getUpdate_time());
//        }
        // 公司ID
        newOrder.setCstmrName(params.getCompany_id());
        newOrder.setCreateTime(new Date());
        newOrder.setUpdateTime(new Date());
        if (!orderService.insert(newOrder)) {
            throw new RuntimeException("新增订单失败!!");
        }
        if (!Objects.isNull(params.getDetails()) && !params.getDetails().isEmpty()) {
            params.getDetails().forEach(item -> {
                Mat matnr = matService.selectOne(new EntityWrapper<Mat>().eq("matnr", item.getPro_komcode()));
                if (Objects.isNull(matnr)) {
                    throw new CoolException("物料编码不存在!!");
                }
                OrderDetl orderItem = new OrderDetl();
                BeanUtils.copyProperties(matnr, orderItem);
                orderItem.setOrderId(newOrder.getId());
                orderItem.setOrderNo(newOrder.getOrderNo());
                if (OrderType.ORDER_IN.type.equals(OrderWkType.getTypeVal(params.getType()))) {
                    // 入库
                    orderItem.setAnfme(Math.round(item.getInv_qty() * 10000) / 10000.0);
                } else if (OrderType.ORDER_OUT.type.equals(OrderWkType.getTypeVal(params.getType()))) {
                    // 出库
                    if (OrderWkType.ORDER_WK_ORDER_OUT.val.equals(params.getType())) {
                        // 备货单出库
                        orderItem.setAnfme(Math.round(item.getPick_qty() * 10000) / 10000.0);
                    } else if (OrderWkType.ORDER_WK_ORDER_OUT_EO.val.equals(params.getType())
                            || OrderWkType.ORDER_WK_ORDER_OUT_SO.val.equals(params.getType())) {
                        // 备货指示派工单(EO/SO)出库
                        orderItem.setAnfme(Math.round(item.getOrder_qty() * 10000) / 10000.0);
                    }
                }
                orderItem.setMatnr(matnr.getMatnr());
                orderItem.setMaktx(matnr.getMaktx());
                orderItem.setBrand(matnr.getBrand());
                orderItem.setBatch("");
                orderItem.setStandby1(item.getPro_id());
                // 关联上加派工单号+零件代码+供应商代码
                orderItem.setThreeCode(item.getTotal_serial());
                // 供应商代码
                orderItem.setSuppCode(item.getPro_id());
                orderItem.setCreateTime(new Date());
                orderItem.setUpdateTime(new Date());
                if (!orderDetlService.insert(orderItem)) {
                    throw new CoolException("订单明细新增失败!!");
                }
            });
        }
    }
    /**
     * 备货单下发
     *
     * @param stockUpParams
     * @return com.core.common.R
     * @author Ryan
     * @date 2025/11/24 15:40
     */
    @Override
    public XSR getOutDetails(List<StockUpOrderParams> stockUpParams) {
        if (Objects.isNull(stockUpParams)) {
            return XSR.error("参数不能为空!!");
        }
        stockUpParams.forEach(params -> {
            if (Objects.isNull(params.getDispatch_no())) {
                throw new CoolException("派工单编号不能为空!!");
            }
            if (Objects.isNull(params.getKopen_id())) {
                throw new CoolException("流水号不能为空!!");
            }
            if (Objects.isNull(params.getCompany_id())) {
                throw new CoolException("公司ID不能为空!!");
            }
            if (Objects.isNull(params.getDetails()) || params.getDetails().isEmpty()) {
                throw new CoolException("订单明细不能为空!!");
            }
            List<OrderItemsParam> items = new ArrayList<>();
            if (params.getDetails() != null) {
                for (OutOrderParams detail : params.getDetails()) {
                    if (detail.getPartList() != null) {
                        items.addAll(detail.getPartList());
                    }
                }
            }
            params.getDetails().forEach(item -> {
                PubOrderParams pubOrderParams = new PubOrderParams();
                BeanUtils.copyProperties(params, pubOrderParams);
                pubOrderParams.setType(item.getType())
                        .setPick_no(item.getPick_no())
                        .setCus_address(item.getCus_address())
                        .setOrder_no(item.getOrder_no())
                        .setUpdate_time(params.getUpdate_time())
                        .setCus_id(item.getCus_id());
                pubOrderParams.setDetails(item.getPartList());
                addOrUpdateOrders(pubOrderParams, "add");
            });
        });
        return XSR.ok("备货单下发成功!!");
    }
    /**
     * 查询WMS库存信息
     *
     * @param params
     * @return com.core.common.R
     */
    @Override
    public XSR getStockInfo(PageRequestParams params) {
        EntityWrapper<LocDetl> wrapper = new EntityWrapper<>();
//        if (!Objects.isNull(params.getPro_id())) {
//            wrapper.eq("supp_code", params.getPro_id());
//        }
//        if (!Objects.isNull(params.getPro_komcode())) {
//            wrapper.eq("matnr", params.getPro_komcode());
//        }
        Page<LocDetl> locDetls = locDetlService.selectPage(new Page<>(params.getCurr(), params.getLimit()),  wrapper);
        return XSR.ok(locDetls.getRecords());
    }
    private String kopen() {
        return url + ":" + port + prefix;
    }
}
src/main/java/com/zy/api/service/impl/HmesApiServiceImpl.java
New file
@@ -0,0 +1,68 @@
package com.zy.api.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.R;
import com.core.common.SnowflakeIdWorker;
import com.core.exception.CoolException;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.service.HmesApiService;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.param.OpenOrderPakoutParam;
import com.zy.asrs.enums.LocStsType;
import com.zy.asrs.service.*;
import com.zy.asrs.service.impl.LocDetlServiceImpl;
import com.zy.asrs.service.impl.OrderDetlPakoutServiceImpl;
import com.zy.asrs.service.impl.OrderPakoutServiceImpl;
import com.zy.common.model.DetlDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class HmesApiServiceImpl implements HmesApiService {
    @Autowired
    private LocMastService locMastService;
    @Autowired
    private WcsApiService wcsApiService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private DocTypeService docTypeService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private MatService matService;
    @Autowired
    private OrderDetlService orderDetlService;
    @Autowired
    private OrderPakoutServiceImpl orderPakoutService;
    @Autowired
    private OrderDetlPakoutServiceImpl orderDetlPakoutService;
    @Autowired
    private LocDetlServiceImpl locDetlService;
    @Override
    public R pubWorkTask(OpenOrderPakoutParam params) {
        return null;
    }
    @Override
    public R releaseLock(ReceviceTaskParams params) {
        return null;
    }
}
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
New file
@@ -0,0 +1,239 @@
package com.zy.api.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.common.R;
import com.core.exception.CoolException;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.StopOutTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.common.constant.MesConstant;
import com.zy.common.service.CommonService;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class WcsApiServiceImpl implements WcsApiService {
    @Autowired
    private LocMastService locMastService;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private WorkService workService;
    @Autowired
    private WrkDetlService wrkDetlService;
    @Autowired
    private MatService matService;
    @Autowired
    private LocDetlService locDetlService;
    @Value("${wcs.switch}")
    private String switchValue;
    @Value("${wcs.address.URL}")
    private String wcs_address;
    @Value("${wcs.address.createOutTask}")
    private String getWcs_address;
    @Value("${wcs.address.createInTask}")
    private String createInTask;
    @Value("${wcs.address.createLocMoveTask}")
    private String createLocMoveTask;
    @Value("${wcs.address.stopOutTask}")
    private String stopOutTask;
    @Autowired
    private CommonService commonService;
    /**
     * 下发任务至WCS
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2026/1/10 13:58
     */
    @Override
    public R pubWrkToWcs(WorkTaskParams params) {
        if (Objects.isNull(params.getTaskNo())) {
            return R.error("任务号不能为空!!");
        }
        if (Objects.isNull(params.getBarcode())) {
            return R.error("托盘码不能为空!!");
        }
        if (Objects.isNull(params.getLocNo())) {
            return R.error("目标库位不能为空!!");
        }
        String url = createInTask;
        if (!Objects.isNull(params.getType()) && params.getType().equals("out")) {
            url = getWcs_address;
        }else if (!Objects.isNull(params.getType()) && params.getType().equals("move")) {
            url = createLocMoveTask;
        }
        String response;
        R r = R.ok();
        WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", params.getTaskNo()));
        if (!Objects.isNull(wrkMast) && "out".equalsIgnoreCase(params.getType()) && "Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
            return R.error("task paused");
        }
        try {
            log.info("下发搬运任务给wcs="+JSON.toJSONString(params));
            response = new HttpHandler.Builder()
                    .setUri(wcs_address)
                    .setPath(url)
                    .setJson(JSON.toJSONString(params))
                    .build()
                    .doPost();
            JSONObject jsonObject = JSON.parseObject(response);
            log.info("下发任务给wcs的返回值="+response);
            Integer code = jsonObject.getInteger("code");
            if (code==200) {
                if (!Objects.isNull(wrkMast)) {
                    if (wrkMast.getIoType()==1 || wrkMast.getIoType()==10) {
                        wrkMast.setWrkSts(2L);
                        wrkMast.setModiTime(new Date());
                        wrkMastService.updateById(wrkMast);
                    }else if(wrkMast.getIoType()==2){
                        wrkMast.setWrkSts(2L);
                        wrkMast.setModiTime(new Date());
                        wrkMastService.updateById(wrkMast);
                    }else if (wrkMast.getIoType()==101 || wrkMast.getIoType()==110) {
                        wrkMast.setWrkSts(12L);
                        wrkMast.setModiTime(new Date());
                        wrkMastService.updateById(wrkMast);
                    }
                }
                //TODO 上报是否成功
            }else {
                r =R.error();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return r;
    }
    /**
     * 堆垛机执行状态上报
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2026/1/10 16:30
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R receviceTaskFromWcs(ReceviceTaskParams params) {
        log.info("wcs任务反馈="+JSON.toJSONString(params));
        if (Objects.isNull(params.getSuperTaskNo())) {
            throw new CoolException("WMS任务号不能为空!!");
        }
        if (Objects.isNull(params.getNotifyType())) {
            throw new CoolException("动作类型不能为空!!");
        }
        WrkMast mast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", params.getSuperTaskNo()));
        if (Objects.isNull(mast)) {
            throw new CoolException("任务档不存在!!");
        }
        if (params.getNotifyType().equals("task")) {
            //任务
            if (params.getMsgType().equals("task_complete")) {
                if (mast.getIoType() == 1 || mast.getIoType() == 2 ||mast.getIoType() == 10) {
                    mast.setWrkSts(4L);
                } else if ((mast.getIoType() == 101||mast.getIoType()==110) && mast.getWrkSts()<14) {
                    mast.setWrkSts(14L);
                    if(Cools.isEmpty(mast.getStaNo())){
                        mast.setOveMk("Y");
                    }
                }
                if (!wrkMastService.updateById(mast)) {
                    throw new CoolException("任务状态修改失败!!");
                }
            } else if (params.getMsgType().equals("task_cancel")) {
                if (mast.getIoType() != null && mast.getIoType() > 100 && mast.getWrkSts() < 14) {
                    mast.setPauseMk("Y");
                    mast.setUpdMk("WCS_CANCELLED");
                    mast.setManuType("WCS_CANCELLED");
                    mast.setModiTime(new Date());
                    if (!wrkMastService.updateById(mast)) {
                        throw new CoolException("task cancel update fail");
                    }
                }
            }else if (params.getMsgType().equals("task_arrive")) {
                //到达目的地
                //如果出库任务是跨区则需要生成新的入库任务入库
                if(!Cools.isEmpty(mast.getLocNo())){
                    mast.setOnlineYn("N");//等待生成跨区入库任务
                }
                mast.setWrkSts(14L);
                if(Cools.isEmpty(mast.getStaNo())){
                    mast.setOveMk("Y");
                }
                mast.setModiTime(new Date());
                if (!wrkMastService.updateById(mast)) {
                    throw new CoolException("任务状态修改失败!!");
                }
            }
        } else if (params.getNotifyType().equals("weight")) {
        }
        return R.ok();
    }
    @Override
    public R pauseOutTasks(StopOutTaskParams params) {
        if (params == null || params.getTasks() == null || params.getTasks().isEmpty()) {
            return R.ok("no tasks to stop");
        }
        if (!Boolean.parseBoolean(String.valueOf(switchValue))) {
            return R.ok("wcs switch off");
        }
        String response;
        try {
            response = new HttpHandler.Builder()
                    .setUri(wcs_address)
                    .setPath(stopOutTask)
                    .setHttps(wcs_address != null && wcs_address.startsWith("https://"))
                    .setTimeout(10, TimeUnit.SECONDS)
                    .setJson(JSON.toJSONString(params))
                    .build()
                    .doPost();
            JSONObject jsonObject = JSON.parseObject(response == null ? "{}" : response);
            Integer code = jsonObject.getInteger("code");
            if (code == null || !Objects.equals(code, 200)) {
                String msg = jsonObject.getString("msg");
                throw new CoolException(Cools.isEmpty(msg) ? "WCS stop out task failed" : msg);
            }
        } catch (IOException e) {
            throw new CoolException("call WCS stop out task fail: " + e.getMessage());
        }
        return R.ok();
    }
}
src/main/java/com/zy/asrs/controller/BasArmMastController.java
@@ -78,9 +78,6 @@
                String[] dates = val.split(RANGE_TIME_LINK);
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else if (entry.getKey().equals("binding_tags")){
                long aLong = Long.parseLong(val);
                wrapper.ge(entry.getKey(), aLong);
            } else {
                wrapper.like(entry.getKey(), val);
            }
src/main/java/com/zy/asrs/controller/BasArmMastLogController.java
@@ -54,9 +54,6 @@
                String[] dates = val.split(RANGE_TIME_LINK);
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else if (entry.getKey().equals("binding_tags")){
                long aLong = Long.parseLong(val);
                wrapper.ge(entry.getKey(), aLong);
            } else {
                wrapper.like(entry.getKey(), val);
            }
src/main/java/com/zy/asrs/controller/BasArmMastSignController.java
@@ -54,9 +54,6 @@
                String[] dates = val.split(RANGE_TIME_LINK);
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else if (entry.getKey().equals("create_time")){
                long aLong = Long.parseLong(val);
                wrapper.ge(entry.getKey(), aLong);
            } else {
                wrapper.like(entry.getKey(), val);
            }
src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -210,7 +210,7 @@
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else {
                if (entry.getKey().equals("locNo")) {
                    wrapper.eq("loc_no", String.valueOf(entry.getValue()));
                    wrapper.like("loc_no", String.valueOf(entry.getValue()));
                } else {
                    wrapper.like(entry.getKey(), String.valueOf(entry.getValue()));
                }
src/main/java/com/zy/asrs/controller/LocMastController.java
@@ -95,13 +95,11 @@
                String[] dates = val.split(RANGE_TIME_LINK);
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else if (entry.getKey().equals("loc_no")){
                wrapper.like(entry.getKey(), val);
            } else {
                if (entry.getKey().equals("loc_type1")){
                    sign=true;
                }
                wrapper.eq(entry.getKey(), val);
                wrapper.like(entry.getKey(), val);
            }
        }
        if (sign){
src/main/java/com/zy/asrs/controller/ManLocDetlController.java
@@ -101,7 +101,7 @@
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else {
                if (entry.getKey().equals("locNo")) {
                    wrapper.eq("loc_no", String.valueOf(entry.getValue()));
                    wrapper.like("loc_no", String.valueOf(entry.getValue()));
                } else {
                    wrapper.like(entry.getKey(), String.valueOf(entry.getValue()));
                }
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -140,6 +140,21 @@
    }
    /**
     * pause out order
     */
    @PostMapping("/order/pakout/pause/default/v1")
    @AppAuth(memo = "pause out order")
    public synchronized R pakoutOrderPause(@RequestHeader(required = false) String appkey,
                                           @RequestBody OpenOrderPakoutPauseParam param,
                                           HttpServletRequest request) {
        auth(appkey, param, request);
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getOrderNo())) {
            return R.error("orderNo is empty");
        }
        return openService.pakoutOrderPause(param);
    }
    /**
     * 出库单回写
     */
//    @PostMapping("/order/pakout/complete/default/v1")
@@ -448,7 +463,7 @@
            // 判断是否有相同条码的数据
            if (waitPakinService.selectCount(new EntityWrapper<WaitPakin>().
                    eq("zpallet", mesToCombParam.getPalletId()).eq("io_status", "N")) > 0) {
                return R.error(mesToCombParam.getPalletId()+"-该托盘码已经存在组托档中");
                waitPakinService.delete(new EntityWrapper<WaitPakin>().eq("zpallet", mesToCombParam.getPalletId()));
            }
            if (mesToCombParam.getPalletId().length() != 8) {
@@ -483,7 +498,4 @@
        }
        return R.ok();
    }
}
src/main/java/com/zy/asrs/controller/StaDescController.java
@@ -5,50 +5,59 @@
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.zy.asrs.entity.StaDesc;
import com.zy.asrs.entity.param.StaDescInitParam;
import com.zy.asrs.mapper.StaDescMapper;
import com.zy.asrs.service.StaDescService;
import com.zy.common.web.BaseController;
import com.core.annotations.ManagerAuth;
import com.core.common.BaseRes;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.common.R;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import com.zy.asrs.entity.StaDesc;
import com.zy.asrs.entity.param.StaDescInitParam;
import com.zy.asrs.service.StaDescService;
import com.zy.common.web.BaseController;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.*;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@RestController
public class StaDescController extends BaseController {
    private static final Logger log = LoggerFactory.getLogger(StaDescController.class);
    @Autowired
    private StaDescService staDescService;
    @Autowired
    private SqlSessionFactory sqlSessionFactory;
    @RequestMapping(value = "/staDesc/init/auth")
    @ManagerAuth(memo = "初始化站点路径")
    @Transactional(rollbackFor = Exception.class)
    public R init(StaDescInitParam param) {
        try{
            if (param.getTypeDesc()==1){
        try {
            if (param.getTypeDesc() == 1) {
                staDescService.delete(new EntityWrapper<>());
            }
            String[] startStaList = param.getStartStaList().split(";");
            String[] endStaList = param.getEndStaList().split(";");
            List<StaDesc> staDescList = new ArrayList<>();
            SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
            StaDescMapper sqlSessionMapper = sqlSession.getMapper(StaDescMapper.class);
            for (String startSta : startStaList){
                for (String endSta : endStaList){
                    for (Integer type:param.getType()){
            Set<String> requestKeys = new HashSet<>();
            for (String startSta : startStaList) {
                for (String endSta : endStaList) {
                    for (Integer type : param.getType()) {
                        String uniqueKey = type + "_" + startSta + "_" + param.getCrnNo() + "_" + endSta;
                        if (!requestKeys.add(uniqueKey)) {
                            continue;
                        }
                        int sameRes = staDescService.selectCount(new EntityWrapper<StaDesc>()
                                .eq("type_no", type)
                                .eq("stn_no", Integer.parseInt(startSta))
@@ -66,22 +75,13 @@
                        staDesc.setModiTime(new Date());
                        staDesc.setAppeUser(getUserId());
                        staDesc.setAppeTime(new Date());
//                        staDescList.add(staDesc);
                        sqlSessionMapper.insert(staDesc);
                        staDescService.insert(staDesc);
                    }
                }
            }
            try{
                sqlSession.commit();
                sqlSession.close();
            }catch (Exception e){
                log.error("初始化站点路径异常===>sql异常:{}",e.getMessage());
            }
//            staDescService.insertBatch(staDescList);
        }catch (Exception e){
            log.error("初始化站点路径异常:{}",e.getMessage());
            return R.error("初始化站点路径异常:"+e.getMessage());
        } catch (Exception e) {
            log.error("初始化站点路径异常:{}", e.getMessage(), e);
            return R.error("初始化站点路径异常:" + e.getMessage());
        }
        return R.ok("ok1").add("ok2");
@@ -95,22 +95,24 @@
    @RequestMapping(value = "/staDesc/list/auth")
    @ManagerAuth
    public R list(@RequestParam(defaultValue = "1")Integer curr,
                  @RequestParam(defaultValue = "10")Integer limit,
                  @RequestParam(required = false)String orderByField,
                  @RequestParam(required = false)String orderByType,
                  @RequestParam Map<String, Object> param){
    public R list(@RequestParam(defaultValue = "1") Integer curr,
                  @RequestParam(defaultValue = "10") Integer limit,
                  @RequestParam(required = false) String orderByField,
                  @RequestParam(required = false) String orderByType,
                  @RequestParam Map<String, Object> param) {
        excludeTrash(param);
        EntityWrapper<StaDesc> wrapper = new EntityWrapper<>();
        convert(param, wrapper);
        if (!Cools.isEmpty(orderByField)){wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType));}
        if (!Cools.isEmpty(orderByField)) {
            wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType));
        }
        return R.ok(staDescService.selectPage(new Page<>(curr, limit), wrapper));
    }
    private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper){
        for (Map.Entry<String, Object> entry : map.entrySet()){
    private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper) {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String val = String.valueOf(entry.getValue());
            if (val.contains(RANGE_TIME_LINK)){
            if (val.contains(RANGE_TIME_LINK)) {
                String[] dates = val.split(RANGE_TIME_LINK);
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
@@ -139,10 +141,10 @@
        return R.ok();
    }
    @RequestMapping(value = "/staDesc/update/auth")
    @ManagerAuth(memo = "站点路径修改")
    public R update(StaDesc staDesc){
        if (Cools.isEmpty(staDesc) || null==staDesc.getTypeId()){
    @RequestMapping(value = "/staDesc/update/auth")
    @ManagerAuth(memo = "站点路径修改")
    public R update(StaDesc staDesc) {
        if (Cools.isEmpty(staDesc) || null == staDesc.getTypeId()) {
            return R.error();
        }
        staDesc.setModiUser(getUserId());
@@ -153,12 +155,12 @@
    @RequestMapping(value = "/staDesc/delete/auth")
    @ManagerAuth(memo = "站点路径删除")
    public R delete(@RequestParam String param){
    public R delete(@RequestParam String param) {
        List<StaDesc> list = JSONArray.parseArray(param, StaDesc.class);
        if (Cools.isEmpty(list)){
        if (Cools.isEmpty(list)) {
            return R.error();
        }
        for (StaDesc entity : list){
        for (StaDesc entity : list) {
            staDescService.delete(new EntityWrapper<>(entity));
        }
        return R.ok();
@@ -166,7 +168,7 @@
    @RequestMapping(value = "/staDesc/export/auth")
    @ManagerAuth(memo = "站点路径导出")
    public R export(@RequestBody JSONObject param){
    public R export(@RequestBody JSONObject param) {
        List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class);
        EntityWrapper<StaDesc> wrapper = new EntityWrapper<>();
        Map<String, Object> map = excludeTrash(param.getJSONObject("staDesc"));
@@ -182,7 +184,7 @@
        wrapper.like("crn_no", condition);
        Page<StaDesc> page = staDescService.selectPage(new Page<>(0, 10), wrapper);
        List<Map<String, Object>> result = new ArrayList<>();
        for (StaDesc staDesc : page.getRecords()){
        for (StaDesc staDesc : page.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", staDesc.getCrnNo());
            map.put("value", staDesc.getCrnNo());
@@ -195,10 +197,9 @@
    @ManagerAuth
    public R query(@RequestBody JSONObject param) {
        Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>().eq(humpToLine(String.valueOf(param.get("key"))), param.get("val"));
        if (null != staDescService.selectOne(wrapper)){
        if (null != staDescService.selectOne(wrapper)) {
            return R.parse(BaseRes.REPEAT).add(getComment(StaDesc.class, String.valueOf(param.get("key"))));
        }
        return R.ok();
    }
}
src/main/java/com/zy/asrs/controller/WrkMastController.java
@@ -61,7 +61,7 @@
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else {
                wrapper.eq(entry.getKey(), val);
                wrapper.like(entry.getKey(), val);
            }
        }
    }
src/main/java/com/zy/asrs/controller/WrkMastLogController.java
@@ -87,11 +87,7 @@
                wrapper.ge(entry.getKey(), DateUtils.convert(dates[0]));
                wrapper.le(entry.getKey(), DateUtils.convert(dates[1]));
            } else {
                if (entry.getKey().equals("manu_type")) {
                    wrapper.like(entry.getKey(), val);
                } else {
                    wrapper.eq(entry.getKey(), val);
                }
                wrapper.like(entry.getKey(), val);
            }
        }
    }
src/main/java/com/zy/asrs/entity/param/MesToCombParam.java
@@ -29,4 +29,6 @@
    private Integer operateType;
    //唯一码
    private String BizNo;
    //是否散货,0 非散货;1 散货;为了管控出货速率,散货可以出慢点。
    private Integer package1;
}
src/main/java/com/zy/asrs/enums/CommonEnum.java
New file
@@ -0,0 +1,25 @@
package com.zy.asrs.enums;
/**
 * @author Ryan
 * @date 2025/9/25
 * @description: 通用类型枚举
 * @version 1.0
 */
public enum CommonEnum {
    //通用类型
    COMMON_ENUM_Y(1, "是"),
    //通用
    COMMON_ENUM_N(0, "否");
    public Integer type;
    public String desc;
    CommonEnum(Integer type, String desc) {
        this.type = type;
        this.desc = desc;
    }
}
src/main/java/com/zy/asrs/enums/ContainerType.java
New file
@@ -0,0 +1,27 @@
package com.zy.asrs.enums;
public enum ContainerType {
    //料箱
    CONTAINER_TYPE_BOX("12", "料箱"),
    //托盘
    CONTAINER_TYPE_SALVER("14", "托盘"),
    CONTAINER_TYPE_CAGE("13", "笼框"),
    CONTAINER_TYPE_CAR("3", "台车"),
    ;
    public Long type;
    public String desc;
    ContainerType(String type, String desc) {
        this.type = Long.valueOf(type);
        this.desc = desc;
    }
}
src/main/java/com/zy/asrs/enums/LocStsType.java
New file
@@ -0,0 +1,60 @@
package com.zy.asrs.enums;
public enum LocStsType {
    //空板
    LOC_STS_TYPE_D("D", "空板"),
    //在库
    LOC_STS_TYPE_F("F", "在库"),
    //空库
    LOC_STS_TYPE_O("O", "空库"),
    //禁用
    LOC_STS_TYPE_X("X", "禁用"),
    //入库预约
    LOC_STS_TYPE_S("S", "入库预约"),
    //出库预约
    LOC_STS_TYPE_R("R", "出库预约"),
    ;
    public String type;
    public String desc;
    LocStsType(String type, String desc) {
        this.type = type;
        this.desc = desc;
    }
    public static LocStsType get(String el) {
        for (LocStsType value : LocStsType.values()) {
            if (el.equals(value.toString())) {
                return value;
            }
        }
        return null;
    }
//    /**
//     * @author Ryan
//     * @date 2025/8/28
//     * @description: RCS库位状态转换
//     * @version 1.0
//     */
//    public static String getLocSts(String val) {
//        if (val.equals(RcsLocStsType.LOC_STS_TYPE_D.type)) {
//            return LocStsType.LOC_STS_TYPE_O.type;
//        } else if (val.equals(RcsLocStsType.LOC_STS_TYPE_F.type)) {
//            return LocStsType.LOC_STS_TYPE_F.type;
//        } else if (val.equals(RcsLocStsType.LOC_STS_TYPE_S.type)) {
//            return LocStsType.LOC_STS_TYPE_S.type;
//        } else if (val.equals(RcsLocStsType.LOC_STS_TYPE_R.type)) {
//            return LocStsType.LOC_STS_TYPE_R.type;
//        } else if (val.equals(RcsLocStsType.LOC_STS_TYPE_X.type)) {
//            return LocStsType.LOC_STS_TYPE_X.type;
//        }
//        return null;
//    }
}
src/main/java/com/zy/asrs/enums/MatTagType.java
New file
@@ -0,0 +1,20 @@
package com.zy.asrs.enums;
public enum MatTagType {
    //中件
    MAT_TAGT_YPE_MIDDLE("13", "中件"),
    //小件
    MAT_TAGT_YPE_SMALL("12", "小件"),
    //滤芯
    MAT_TAGT_YPE_XIN("14", "滤芯")
    ;
    public String id;
    public String type;
    MatTagType(String id, String type) {
        this.type = type;
        this.id = id;
    }
}
src/main/java/com/zy/asrs/service/OpenService.java
@@ -26,6 +26,11 @@
    void pakoutOrderCreate(OpenOrderPakoutParam param);
    /**
     * pause out order
     */
    R pakoutOrderPause(OpenOrderPakoutPauseParam param);
    /**
     * 入库单回写
     */
    List<OpenOrderCompeteResult> pakoutOrderComplete(OpenOrderCompleteParam param);
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -2,6 +2,8 @@
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zy.api.controller.params.StopOutTaskParams;
import com.zy.api.service.WcsApiService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.*;
import com.core.exception.CoolException;
@@ -31,6 +33,7 @@
import javax.rmi.CORBA.Util;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created by vincent on 2022/4/9
@@ -87,6 +90,8 @@
    private WaitPakinService waitPakinService;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private WcsApiService wcsApiService;
    @Override
    @Transactional
@@ -358,6 +363,107 @@
                throw new CoolException("生成单据明细失败,请联系管理员");
            }
        }
    }
    @Override
    @Transactional
    public R pakoutOrderPause(OpenOrderPakoutPauseParam param) {
        if (param == null || Cools.isEmpty(param.getOrderNo())) {
            throw new CoolException("orderNo is empty");
        }
        Order order = orderService.selectByNo(param.getOrderNo());
        if (order == null) {
            order = OrderInAndOutUtil.selectByNo(Boolean.FALSE, param.getOrderNo());
        }
        if (order == null) {
            throw new CoolException("order not found: " + param.getOrderNo());
        }
        List<WrkMast> activeTasks = findActiveOutboundTasks(param.getOrderNo());
        if (activeTasks.isEmpty()) {
            return R.ok("no active out tasks");
        }
        Date now = new Date();
        int pausedCount = 0;
        List<WrkMast> issuedTasks = new ArrayList<>();
        for (WrkMast wrkMast : activeTasks) {
            if (wrkMast == null || "Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
                continue;
            }
            wrkMast.setPauseMk("Y");
            wrkMast.setUpdMk(needNotifyWcsStop(wrkMast) ? "WCS_STOP_REQUESTED" : "WMS_PAUSED");
            wrkMast.setManuType("ERP_PAUSE");
            wrkMast.setModiTime(now);
            wrkMast.setModiUser(9527L);
            if (!wrkMastService.updateById(wrkMast)) {
                throw new CoolException("pause out task failed: " + wrkMast.getWrkNo());
            }
            pausedCount++;
            if (needNotifyWcsStop(wrkMast)) {
                issuedTasks.add(wrkMast);
            }
        }
        if (pausedCount == 0) {
            return R.ok("tasks already paused");
        }
        if (!issuedTasks.isEmpty()) {
            wcsApiService.pauseOutTasks(buildStopOutTaskParams(param, issuedTasks));
        }
        Map<String, Object> result = new HashMap<>();
        result.put("orderNo", param.getOrderNo());
        result.put("pausedCount", pausedCount);
        result.put("wcsStopCount", issuedTasks.size());
        return R.ok("pause out success").add(result);
    }
    private List<WrkMast> findActiveOutboundTasks(String orderNo) {
        List<WrkDetl> wrkDetls = wrkDetlService.selectList(new EntityWrapper<WrkDetl>().eq("order_no", orderNo));
        if (wrkDetls == null || wrkDetls.isEmpty()) {
            return Collections.emptyList();
        }
        Set<Integer> wrkNos = wrkDetls.stream()
                .map(WrkDetl::getWrkNo)
                .filter(Objects::nonNull)
                .collect(Collectors.toCollection(LinkedHashSet::new));
        if (wrkNos.isEmpty()) {
            return Collections.emptyList();
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .in("wrk_no", wrkNos)
                .in("io_type", Arrays.asList(101, 108, 110))
                .lt("wrk_sts", 14L));
        if (wrkMasts == null || wrkMasts.isEmpty()) {
            return Collections.emptyList();
        }
        wrkMasts.sort(Comparator.comparing(WrkMast::getWrkNo));
        return wrkMasts;
    }
    private boolean needNotifyWcsStop(WrkMast wrkMast) {
        return wrkMast != null
                && wrkMast.getWrkSts() != null
                && wrkMast.getWrkSts() >= 12L
                && wrkMast.getWrkSts() < 14L;
    }
    private StopOutTaskParams buildStopOutTaskParams(OpenOrderPakoutPauseParam param, List<WrkMast> wrkMasts) {
        StopOutTaskParams stopParams = new StopOutTaskParams();
        stopParams.setOrderNo(param.getOrderNo());
        stopParams.setReason(param.getReason());
        for (WrkMast wrkMast : wrkMasts) {
            StopOutTaskParams.TaskItem item = new StopOutTaskParams.TaskItem();
            item.setTaskNo(String.valueOf(wrkMast.getWrkNo()));
            if (wrkMast.getStaNo() != null) {
                item.setStaNo(String.valueOf(wrkMast.getStaNo()));
            }
            item.setLocNo(wrkMast.getSourceLocNo());
            stopParams.getTasks().add(item);
        }
        return stopParams;
    }
    @Override
@@ -1037,28 +1143,21 @@
        Mat mat = matService.selectByMatnr(param.getMatnr());
        if (Cools.isEmpty(mat)) {
            if (Cools.isEmpty(param.getFull())) {
                if (param.getAnfme() == 0) {
                    //空托盘
                    mat = matService.selectByMatnr("0");
                } else {
                    //满托盘
                    mat = matService.selectByMatnr("1");
                }
            } else {
                if (param.getFull()==1){
                    //满托盘
                    mat = matService.selectByMatnr("1");
                }else if (param.getFull()==0){
                    //空托盘
                    mat = matService.selectByMatnr("0");
                }
            if (param.getFull() == 1) {
                //满托盘
                mat = matService.selectByMatnr(param.getMatnr());
            } else if (param.getFull() == 0) {
                //空托盘
                mat = matService.selectByMatnr("emptyPallet");
            }
        }
        WaitPakin waitPakin = new WaitPakin();
        waitPakin.sync(mat);
        waitPakin.setBatch(String.valueOf(param.getBatchId()));
        waitPakin.setZpallet(param.getPalletId());   // 托盘码
        waitPakin.setIoStatus("N");     // 入出状态
        waitPakin.setAnfme(param.getAnfme());  // 数量
        waitPakin.setStatus("Y");    // 状态
@@ -1070,6 +1169,7 @@
        waitPakin.setOrigin(String.valueOf(param.getStorageArea()));//建议入库区域
        waitPakin.setManu(String.valueOf(param.getLocId()));//mes具体库位编号
        waitPakin.setThreeCode(param.getBizNo());
        waitPakin.setBeBatch(param.getPackage1());//是否散货,0 非散货;1 散货;为了管控出货速率,散货可以出慢点。
        if (!waitPakinService.insert(waitPakin)) {
            throw new CoolException("保存入库通知档失败");
        }
@@ -1080,7 +1180,7 @@
    public R outOrder(OutTaskParam param) {
        LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_sts", "F").eq("barcode", param.getPalletId()));
        if (locMast == null) {
            return R.error("没有找到托盘码="+param.getPalletId()+"对应的库位");
            return R.error("没有找到托盘码=" + param.getPalletId() + "对应的库位");
        }
        Integer ioType = 101;
        // 获取路径
@@ -1113,11 +1213,11 @@
        wrkMast.setModiUser(9995L);
        wrkMast.setModiTime(now);
        if (!wrkMastService.insert(wrkMast)) {
            throw new CoolException("保存工作档失败,出库库位号:"+locMast.getLocNo());
            throw new CoolException("保存工作档失败,出库库位号:" + locMast.getLocNo());
        }
        List<LocDetl> locNo = locDetlService.selectList(new EntityWrapper<LocDetl>().eq("loc_no", locMast.getLocNo()));
        if (locNo == null || locNo.size() == 0) {
            throw new CoolException("查询库存明细失败,出库库位号:"+locMast.getLocNo());
            throw new CoolException("查询库存明细失败,出库库位号:" + locMast.getLocNo());
        }
        // 生成工作档明细
        for (LocDetl locDetl : locNo) {
@@ -1144,7 +1244,7 @@
            locMast.setModiUser(9995L);
            locMast.setModiTime(now);
            if (!locMastService.updateById(locMast)) {
                throw new CoolException("预约库位状态失败,库位号:"+locMast.getLocNo());
                throw new CoolException("预约库位状态失败,库位号:" + locMast.getLocNo());
            }
        } else {
            log.error(locMast.getLocNo() + "库位不是在库状态");
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -1660,7 +1660,7 @@
        }
        LocTypeDto locTypeDto = new LocTypeDto();
        locTypeDto.setLocType1((short) 1);
        return wcsController.startupFullPutStore(301, list.get(0).getZpallet(), locTypeDto, list);
        return wcsController.startupFullPutStore(301, list.get(0).getZpallet(), locTypeDto, list, null);
    }
    @Override
src/main/java/com/zy/asrs/task/AutomaticallyIssueWCSTasksScheduler.java
@@ -27,6 +27,7 @@
        List<WrkMast> wrkMasts = wrkMastService.selectList(
                new com.baomidou.mybatisplus.mapper.EntityWrapper<WrkMast>()
                        .eq("wrk_sts", 11)
                        .last(" and (pause_mk is null or pause_mk <> 'Y')")
        );
        if (wrkMasts.isEmpty()) {
            return;
src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -26,33 +26,6 @@
    @Autowired
    private WorkMastHandler workMastHandler;
    /**
     * wcs上报任务完成后,将任务上报给erp
     * 2.入库上报
     * 13.出库上报
     */
    @Scheduled(cron = "0/3 * * * * ? ")
    private void execute1(){
        List<WrkMast> wrkMasts = wrkMastService.selectList(
                new com.baomidou.mybatisplus.mapper.EntityWrapper<WrkMast>()
                        .in("wrk_sts", 2, 13)
        );
        if (wrkMasts.isEmpty()) {
            return;
        }
        for (WrkMast wrkMast : wrkMasts) {
            ReturnT<String> returnT = workMastHandler.start1(wrkMast);
            if (!returnT.isSuccess()) {
                wrkMast.setUpdMk("X");
                wrkMast.setErrorMemo(returnT.getMsg());
                wrkMast.setErrorTime(new Date());
                if (!wrkMastService.updateById(wrkMast)) {
                    log.error("工作档[workNo={}]标记待处理失败", wrkMast.getWrkNo());
                }
            }
        }
    }
    @Scheduled(cron = "0/3 * * * * ? ")
    private void execute(){
        List<WrkMast> wrkMasts = wrkMastService.selectToBeCompleteData();
src/main/java/com/zy/asrs/task/handler/AutomaticallyIssueWCSTasksHandler.java
@@ -48,6 +48,9 @@
            for (WrkMast m : wrkMast) {
                if (m == null) { continue; }
                if (Objects.equals(m.getWrkSts(), 11L)) {
                    if ("Y".equalsIgnoreCase(m.getPauseMk())) {
                        continue;
                    }
                    if (m.getUpdMk() != null && "WCS_SENT".equalsIgnoreCase(m.getUpdMk())) {
                        continue;
                    }
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
@@ -1,22 +1,25 @@
package com.zy.asrs.task.handler;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.enums.LocStsType;
import com.zy.asrs.service.*;
import com.zy.asrs.service.impl.*;
import com.zy.asrs.task.AbstractHandler;
import com.zy.asrs.task.core.ReturnT;
import com.zy.common.entity.Parameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import springfox.documentation.spring.web.json.Json;
import java.util.Date;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
 * Created by vincent on 2020/7/4
@@ -25,15 +28,6 @@
@Service
@Transactional
public class WorkMastHandler extends AbstractHandler<String> {
    @Value("${erp.address.URL}")
    private String erpBaseUrl;
    @Value("${erp.address.Inaddress}")
    private String erpInAddress;
    @Value("${erp.address.Outaddress}")
    private String erpOutAddress;
    @Autowired
    private WrkMastService wrkMastService;
@@ -51,19 +45,57 @@
    private OrderDetlPakinService orderDetlPakinService;
    @Autowired
    private OrderDetlPakoutService orderDetlPakoutService;
    @Autowired
    private OrderPakinService orderPakinService;
    @Autowired
    private WorkService workService;
    @Value("${erp.switch.ErpReportOld}")
    private boolean erpReportOld;
    public ReturnT<String> start(WrkMast wrkMast) {
        // 4.入库完成
        if (wrkMast.getWrkSts() == 4) {
            return doIn(wrkMast);
        // 14.出库完成
        } else  if (wrkMast.getWrkSts() == 14) {
            // 14.出库完成
        } else if (wrkMast.getWrkSts() == 14) {
            return doOut(wrkMast);
        }
        return SUCCESS;
    }
    private ReturnT<String> doIn(WrkMast wrkMast){
    private boolean needInboundErpReport(WrkMast wrkMast) {
        if (!erpReportOld) {
            return false;
        }
        String erpReport = Parameter.get().getErpReport();
        if (!Cools.isEmpty(erpReport) && !"true".equalsIgnoreCase(erpReport)) {
            return false;
        }
        if (wrkMast == null || Cools.isEmpty(wrkMast.getBarcode())) {
            return false;
        }
        Integer ioType = wrkMast.getIoType();
        return ioType != null && (ioType == 1 || ioType == 8 || ioType == 53 || ioType == 54 || ioType == 57);
    }
    private boolean needOutboundErpReport(WrkMast wrkMast) {
        if (!erpReportOld) {
            return false;
        }
        String erpReport = Parameter.get().getErpReport();
        if (!Cools.isEmpty(erpReport) && !"true".equalsIgnoreCase(erpReport)) {
            return false;
        }
        if (wrkMast == null || Cools.isEmpty(wrkMast.getBarcode())) {
            return false;
        }
        Integer ioType = wrkMast.getIoType();
        return ioType != null && (ioType == 101 || ioType == 108 || ioType == 110);
    }
    public ReturnT<String> doIn(WrkMast wrkMast) {
        Date now = new Date();
        LocMast locMast = locMastService.selectById(wrkMast.getLocNo());
        try {
@@ -107,12 +139,11 @@
                    }
                    // 遍历工作明细,更新库存明细和入库通知档
                    for (WrkDetl wrkDetl : wrkDetls) {
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand()
                        ,wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand()
                                , wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (null != locDetl) {
                            if (!locDetlService.updateAnfme(wrkDetl.getAnfme(), wrkMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3()
                            ,wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3())) {
                            if (!locDetlService.updateAnfme(wrkDetl.getAnfme(), wrkMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3()
                                    , wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3())) {
//                                exceptionHandle("全板入库 ===>> 更新库存明细失败;[workNo={0}],[locNo={1}]", wrkMast.getWrkNo(), wrkMast.getLocNo());
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("全板入库 ===>> 更新库存明细失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
@@ -125,45 +156,12 @@
                            locDetl.setZpallet(wrkDetl.getZpallet()); // 托盘条码
                            locDetl.setModiTime(now);
                            locDetl.setAppeTime(now);
                            locDetl.setOrigin("在库");
                            if (!locDetlService.insert(locDetl)) {
//                                exceptionHandle("全板入库 ===>> 添加库存明细失败;[workNo={0}],[locNo={1}]", wrkMast.getWrkNo(), wrkMast.getLocNo());
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("全板入库 ===>> 添加库存明细失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                            }
                        }
                        if (!Cools.isEmpty(wrkDetl.getOrderNo())){
                            log.info("进入入库任务完成,带订单:"+ JSON.toJSONString(wrkDetl));
                            // 更新订单完成数量
                            OrderDetlPakin orderDetlPakin = orderDetlPakinService.selectItem
                                    (wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                            wrkDetl.getBatch(), wrkDetl.getBrand(),
                                            wrkDetl.getStandby1(), wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                            wrkDetl.getBoxType1(),wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                            if (orderDetlPakin==null){
                                log.info("进入入库任务完成,查询订单失败:"+ JSON.toJSONString(wrkDetl));
                                orderDetlPakin = orderDetlPakinService.selectItem
                                        (wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                                wrkDetl.getBatch(), wrkDetl.getBrand(),
                                                wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                                wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                            }
                            try {
                                if(!Cools.isEmpty(orderDetlPakin)){
                                    if(!orderDetlPakinService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                            orderDetlPakin.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                            wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3(),wrkDetl.getAnfme())){
//                                    exceptionHandle("全板入库 ===>> 更新订单完成数量失败;[workNo={0}],[locNo={1}]",
//                                            wrkMast.getWrkNo(), wrkMast.getLocNo());
                                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                        return FAIL.setMsg("全板入库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                                    }
                                }
                            } catch (Exception ignore){}
                        }
                    }
                    // 修改库位状态 S ====>> F
                    if (locMast.getLocSts().equals("S")) {
@@ -188,7 +186,6 @@
                    }
                    // 遍历工作明细,更新库存明细和入库通知档
                    for (WrkDetl wrkDetl : wrkDetls8) {
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand()
                                , wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (null != locDetl) {
@@ -233,40 +230,39 @@
                    }
                    for (WrkDetl wrkDetl : wrkDetls53) {
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand()
                                ,wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand()
                                , wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (null != locDetl) {
                            if (!locDetlService.updateAnfme(locDetl.getAnfme() - wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3()
                                    ,wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3())) {
                            if (!locDetlService.updateAnfme(locDetl.getAnfme() - wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3()
                                    , wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3())) {
//                                exceptionHandle("拣料入库 ===>> 修改库存明细数量失败;[workNo={0}],[locNo={1}]", wrkMast.getWrkNo(), wrkMast.getLocNo());
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("拣料入库 ===>> 修改库存明细数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                            }
                        }
                        if (!Cools.isEmpty(wrkDetl.getOrderNo())){
                            // 更新订单完成数量
                            OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem
                                    (wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(),
                                            wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                        // 更新订单完成数量
                        OrderDetlPakin orderDetlPakin = orderDetlPakinService.selectItem
                                (wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(),
                                        wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (orderDetlPakin == null) {
                            orderDetlPakin = orderDetlPakinService.selectItem
                                    (wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                            wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                            if (orderDetlPakout==null){
                                orderDetlPakout = orderDetlPakoutService.selectItem
                                        (wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                                wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                            }
                            try {
                                if(!Cools.isEmpty(orderDetlPakout)){
                                    if(!orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                            orderDetlPakout.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                            wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3(),wrkDetl.getAnfme())){
                        }
                        try {
                            if (!Cools.isEmpty(orderDetlPakin)) {
                                if (!orderDetlPakinService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakin.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3(), wrkDetl.getAnfme())) {
//                                    exceptionHandle("拣料入库 ===>> 更新订单完成数量失败;[workNo={0}],[locNo={1}]",
//                                            wrkMast.getWrkNo(), wrkMast.getLocNo());
                                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                        return FAIL.setMsg("拣料入库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                                    }
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                    return FAIL.setMsg("拣料入库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                                }
                            } catch (Exception ignore){}
                            }
                        } catch (Exception ignore) {
                        }
                    }
@@ -293,13 +289,13 @@
                        return FAIL.setMsg("并板入库 ===>> 工作明细档为空; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                    }
                    // 修改库存明细数量,如无库存,曾新增
                    for (WrkDetl wrkDetl:wrkDetls54) {
                    for (WrkDetl wrkDetl : wrkDetls54) {
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand()
                                ,wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand()
                                , wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (null != locDetl) {
                            if (!locDetlService.updateAnfme(wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3()
                                    ,wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3())) {
                            if (!locDetlService.updateAnfme(wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3()
                                    , wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3())) {
//                                exceptionHandle("并板入库 ===>> 修改库存明细数量失败;[workNo={0}],[matnr={1}]", wrkMast.getWrkNo(), wrkDetl.getMatnr());
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("并板入库 ===>> 修改库存明细数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
@@ -319,17 +315,17 @@
                        }
                        // 更新订单完成数量
                        OrderDetlPakin orderDetlPakin = orderDetlPakinService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(), wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(), wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        OrderDetlPakin orderDetlPakin = orderDetlPakinService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        try {
                            if(!Cools.isEmpty(orderDetlPakin)){
                                if(!orderDetlPakinService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakin.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3(),wrkDetl.getAnfme())){
                            if (!Cools.isEmpty(orderDetlPakin)) {
                                if (!orderDetlPakinService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakin.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3(), wrkDetl.getAnfme())) {
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                    return FAIL.setMsg("并板入库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                                }
                            }
                        } catch (Exception ignore){
                        } catch (Exception ignore) {
                        }
@@ -373,7 +369,7 @@
                    }
                    // 修改库位状态 Q ====>> F
                    if (locMast.getLocSts().equals("Q")) {
                        locMast.setLocSts(wrkMast.getFullPlt().equals("Y")?"F":"D");
                        locMast.setLocSts(wrkMast.getFullPlt().equals("Y") ? "F" : "D");
                        locMast.setBarcode(wrkMast.getBarcode());
                        locMast.setIoTime(now);
                        locMast.setModiTime(now);
@@ -426,7 +422,15 @@
                    break;
            }
            // 修改工作主档状态
            wrkMast.setWrkSts(5L);
            if (needInboundErpReport(wrkMast)) {
                wrkMast.setWrkSts(WorkErpReportHandler.ERP_REPORT_PENDING_WRK_STS);
                wrkMast.setLogMk(WorkErpReportHandler.ERP_REPORT_PENDING_FLAG);
                wrkMast.setExpTime(0D);
                wrkMast.setLogErrMemo(null);
                wrkMast.setLogErrTime(null);
            } else {
                wrkMast.setWrkSts(5L);
            }
            wrkMast.setModiTime(now);
            if (!wrkMastService.updateById(wrkMast)) {
//                exceptionHandle("更新入库完成状态失败;[workNo={0}]", wrkMast.getWrkNo());
@@ -442,11 +446,13 @@
        return SUCCESS;
    }
    private ReturnT<String> doOut(WrkMast wrkMast){
    @Transactional(rollbackFor = Exception.class)
    public ReturnT<String> doOut(WrkMast wrkMast) {
        Date now = new Date();
        LocMast locMast = locMastService.selectById(wrkMast.getSourceLocNo());
        try {
            if (null == locMast && wrkMast.getIoType() !=12) {
            if (null == locMast) {
//                exceptionHandle("工作档[workNo={0}]库位号错误[locNo={1}]", wrkMast.getWrkNo(), wrkMast.getLocNo());
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return FAIL.setMsg("工作档库位号错误; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
@@ -455,6 +461,9 @@
            switch (wrkMast.getIoType()) {
                // 全板出库
                case 101:
                    //如果wrkCode不为空,表示是工作台叫货,如果不为空走移库逻辑
                    //todo 判断如果库位所属不是同一个堆垛机号,需再生成一个新的入库任务
//                    // 出库确认信号位
//                    if (Cools.isEmpty(wrkMast.getInvWh()) || wrkMast.getInvWh().equals("N")) {
//                        return SUCCESS;
@@ -466,33 +475,29 @@
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return FAIL.setMsg("全板出库 ===>> 工作明细档为空; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                    }
                    for (WrkDetl wrkDetl : wrkDetls101) {
                        if (!Cools.isEmpty(wrkDetl.getOrderNo())){
                            // 更新订单完成数量
                            OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                    wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                            if (orderDetlPakout==null){
                                orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                            }
                            try {
                                if(!Cools.isEmpty(orderDetlPakout)){
                                    if(!orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                            orderDetlPakout.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                            wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3(),wrkDetl.getAnfme())){
//                                    exceptionHandle("全板出库 ===>> 更新订单完成数量失败;[workNo={0}],[locNo={1}]",
//                                            wrkMast.getWrkNo(), wrkMast.getLocNo());
                                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                        return FAIL.setMsg("全板出库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                                    }
                        // 更新订单完成数量
                        OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (orderDetlPakout == null) {
                            orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                    wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        }
                        try {
                            if (!Cools.isEmpty(orderDetlPakout)) {
                                if (!orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakout.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3(), wrkDetl.getAnfme())) {
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                    return FAIL.setMsg("全板出库 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                                }
                            } catch (Exception ignore){}
                            }
                        } catch (Exception ignore) {
                        }
                    }
                    // 删除工作档源库位的库存明细
                    if (!locDetlService.delete(new EntityWrapper<LocDetl>().eq("loc_no", wrkMast.getSourceLocNo()))) {
//                        exceptionHandle("全板出库 ===>> 删除库存明细失败;[workNo={0}],[sourceLocNo={1}]", wrkMast.getWrkNo(), wrkMast.getSourceLocNo());
                        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                        return FAIL.setMsg("全板出库 ===>> 删除库存明细失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                    }
@@ -503,11 +508,11 @@
                        locMast.setModiTime(now);
                        locMast.setIoTime(now);
                        if (!locMastService.updateById(locMast)) {
//                            exceptionHandle("全板出库 ===>> 修改源库位状态失败;[workNo={0}],[sourceLocNo={1}]", wrkMast.getWrkNo(), wrkMast.getSourceLocNo());
                            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                            return FAIL.setMsg("全板出库 ===>> 修改源库位状态失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                        }
                    }
                    break;
                // 并板途中捡料
                case 108:
@@ -518,28 +523,29 @@
                        return FAIL.setMsg("并板途中捡料 ===>> 工作明细档为空; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                    }
                    for (WrkDetl wrkDetl : wrkDetls108) {
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand()
                                ,wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        LocDetl locDetl = locDetlService.selectItem(locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand()
                                , wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(), wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        if (null != locDetl) {
                            if (!locDetlService.updateAnfme(locDetl.getAnfme() - wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3()
                                    ,wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3())) {
                            if (!locDetlService.updateAnfme(locDetl.getAnfme() - wrkDetl.getAnfme(), locMast.getLocNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3()
                                    , wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3())) {
                                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                return FAIL.setMsg("并板途中捡料 ===>> 修改库存明细数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getLocNo() + "]");
                            }
                        }
                        // 更新订单完成数量
                        OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3());
                        OrderDetlPakout orderDetlPakout = orderDetlPakoutService.selectItem(wrkDetl.getOrderNo(), wrkDetl.getMatnr(), wrkDetl.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3());
                        try {
                            if(!Cools.isEmpty(orderDetlPakout)){
                                if(!orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakout.getBatch(),wrkDetl.getBrand(),wrkDetl.getStandby1(),wrkDetl.getStandby2(),wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(),wrkDetl.getBoxType2(),wrkDetl.getBoxType3(),wrkDetl.getAnfme())){
                            if (!Cools.isEmpty(orderDetlPakout)) {
                                if (!orderDetlPakoutService.increaseQtyByOrderNo(wrkDetl.getOrderNo(), wrkDetl.getMatnr(),
                                        orderDetlPakout.getBatch(), wrkDetl.getBrand(), wrkDetl.getStandby1(), wrkDetl.getStandby2(), wrkDetl.getStandby3(),
                                        wrkDetl.getBoxType1(), wrkDetl.getBoxType2(), wrkDetl.getBoxType3(), wrkDetl.getAnfme())) {
                                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                                    return FAIL.setMsg("并板途中捡料 ===>> 更新订单完成数量失败; [workNo=" + wrkMast.getWrkNo() + "],[locNo=" + wrkMast.getSourceLocNo() + "]");
                                }
                            }
                        } catch (Exception ignore){}
                        } catch (Exception ignore) {
                        }
                    }
                    break;
                // 空板出库
@@ -557,14 +563,23 @@
                        }
                    }
                    break;
                //3号堆垛机衔接
                case 12:
                    break;
                default:
                    break;
            }
            // 修改工作主档状态
            wrkMast.setWrkSts(15L);
            if (needOutboundErpReport(wrkMast)) {
                wrkMast.setWrkSts(WorkOutErpReportHandler.ERP_REPORT_PENDING_WRK_STS);
                wrkMast.setLogMk(WorkOutErpReportHandler.ERP_REPORT_PENDING_FLAG);
                wrkMast.setExpTime(0D);
                wrkMast.setLogErrMemo(null);
                wrkMast.setLogErrTime(null);
            } else {
                wrkMast.setWrkSts(15L);
            }
//            if (!Objects.isNull(wrkMast.getWrkCode())) {
//                //领料出库任务,不修改
//            } else {
//            }
            wrkMast.setModiTime(now);
            if (!wrkMastService.updateById(wrkMast)) {
//                exceptionHandle("更新出库完成状态失败;[workNo={0}]", wrkMast.getWrkNo());
@@ -579,134 +594,4 @@
        }
        return SUCCESS;
    }
    /**
     * wcs上报任务完成后,将任务上报给erp
     * 2.入库上报
     * 13.出库上报
     */
    public ReturnT<String> start1(WrkMast wrkMast) {
        // 2.入库上报
        if (wrkMast.getWrkSts() == 2) {
            return ErpdoIn(wrkMast);
            // 13.出库上报
        } else  if (wrkMast.getWrkSts() == 13) {
            return ErpdoOut(wrkMast);
        }
        return SUCCESS;
    }
    private ReturnT<String> ErpdoOut(WrkMast wrkMast){
        try {
            com.zy.common.utils.HttpHandler.Builder builder = new com.zy.common.utils.HttpHandler.Builder();
            if (Cools.isEmpty(erpBaseUrl) || Cools.isEmpty(erpOutAddress)) {
                return FAIL.setMsg("ERP出库上报地址未配置[erp.address.URL / erp.address.Outaddress]");
            }
            java.util.List<WrkDetl> wrkDetls = wrkDetlService.selectList(
                    new com.baomidou.mybatisplus.mapper.EntityWrapper<WrkDetl>().eq("wrk_no", wrkMast.getWrkNo())
            );
            if (wrkDetls == null || wrkDetls.isEmpty()) {
                return FAIL.setMsg("ERP出库上报失败, 未找到工作明细[workNo=" + wrkMast.getWrkNo() + "]");
            }
            java.util.Map<String, Object> payload = new java.util.HashMap<>();
            payload.put("palletId", wrkMast.getBarcode());
            payload.put("anfme", wrkDetls.get(0).getAnfme());
            payload.put("locId", wrkMast.getSourceLocNo());
            payload.put("weight", wrkMast.getScWeight());
            payload.put("photos", new java.util.ArrayList<String>());
            if (wrkMast.getModiTime() != null) {
                payload.put("createTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(wrkMast.getModiTime()));
            } else {
                payload.put("createTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
            }
            payload.put("BizNo", String.valueOf(wrkDetls.get(0).getThreeCode()));
            String uri = erpBaseUrl;
            String response = builder
                    .setUri(uri)
                    .setPath(erpOutAddress)
                    .setHttps(uri != null && uri.startsWith("https://"))
                    .setTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .setJson(com.alibaba.fastjson.JSON.toJSONString(payload))
                    .build()
                    .doPost();
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSON.parseObject(response == null ? "{}" : response);
            Integer code = jsonObject.getInteger("code");
            if (code == null || code != 0) {
                String msg = jsonObject.getString("msg");
                return FAIL.setMsg(Cools.isEmpty(msg) ? "ERP出库上报失败" : msg);
            }
            wrkMast.setWrkSts(wrkMast.getWrkSts() + 1);
            wrkMast.setModiTime(new java.util.Date());
            if (!wrkMastService.updateById(wrkMast)) {
                return FAIL.setMsg("ERP出库上报成功但更新工作状态失败; [workNo=" + wrkMast.getWrkNo() + "]");
            }
        } catch (Exception e) {
            return FAIL.setMsg(e.getMessage());
        }
        return SUCCESS;
    }
    private ReturnT<String> ErpdoIn(WrkMast wrkMast){
        try {
            com.zy.common.utils.HttpHandler.Builder builder = new com.zy.common.utils.HttpHandler.Builder();
            if (Cools.isEmpty(erpBaseUrl) || Cools.isEmpty(erpInAddress)) {
                return FAIL.setMsg("ERP入库上报地址未配置[erp.address.URL / erp.address.Inaddress]");
            }
            java.util.Map<String, Object> payload = new java.util.HashMap<>();
            payload.put("palletId", wrkMast.getBarcode());
            java.util.List<WrkDetl> wrkDetls = wrkDetlService.selectList(
                    new com.baomidou.mybatisplus.mapper.EntityWrapper<WrkDetl>().eq("wrk_no", wrkMast.getWrkNo())
            );
            if (wrkDetls == null || wrkDetls.isEmpty()) {
                return FAIL.setMsg("ERP入库上报失败, 未找到工作明细[workNo=" + wrkMast.getWrkNo() + "]");
            }
            double anfme = 0D;
            for (WrkDetl d : wrkDetls) {
                if (d != null && d.getAnfme() != null) {
                    anfme += d.getAnfme();
                }
            }
            payload.put("anfme", anfme);
            payload.put("locId", wrkMast.getLocNo());
            payload.put("weight", wrkMast.getScWeight());
            payload.put("photos", new java.util.ArrayList<String>());
            if (wrkMast.getModiTime() != null) {
                payload.put("createTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(wrkMast.getModiTime()));
            } else {
                payload.put("createTime", new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date()));
            }
            payload.put("BizNo", String.valueOf(wrkDetls.get(0).getThreeCode()));
            String uri = erpBaseUrl;
            String response = builder
                    .setUri(uri)
                    .setPath(erpInAddress)
                    .setHttps(uri != null && uri.startsWith("https://"))
                    .setTimeout(10, java.util.concurrent.TimeUnit.SECONDS)
                    .setJson(com.alibaba.fastjson.JSON.toJSONString(payload))
                    .build()
                    .doPost();
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSON.parseObject(response == null ? "{}" : response);
            Integer code = jsonObject.getInteger("code");
            if (code == null || code != 0) {
                String msg = jsonObject.getString("msg");
                return FAIL.setMsg(Cools.isEmpty(msg) ? "ERP入库上报失败" : msg);
            }
            wrkMast.setWrkSts(wrkMast.getWrkSts() + 1);
            wrkMast.setModiTime(new java.util.Date());
            if (!wrkMastService.updateById(wrkMast)) {
                return FAIL.setMsg("ERP入库上报成功但更新工作状态失败; [workNo=" + wrkMast.getWrkNo() + "]");
            }
        } catch (Exception e) {
            return FAIL.setMsg(e.getMessage());
        }
        return SUCCESS;
    }
}
src/main/java/com/zy/asrs/utils/Utils.java
@@ -739,4 +739,38 @@
        return result;
    }
    //将wms库位号转换成wcs库位号
    public static String WMSLocToWCSLoc(String locNo) {
        String row = locNo.substring(0, 2);
        int i = 0;
        for (char c : row.toCharArray()) {
            if (c == '0') {
                i++;
            }else {
                break;
            }
        }
        row = row.substring(i);
        int j = 0;
        String boy = locNo.substring(2, 5);
        for (char c : boy.toCharArray()) {
            if (c == '0') {
                j++;
            }else {
                break;
            }
        }
        boy = boy.substring(j);
        int k = 0;
        String lev = locNo.substring(5);
        for (char c : lev.toCharArray()) {
            if (c == '0') {
                k++;
            }else {
                break;
            }
        }
        lev = lev.substring(k);
        return row + "-" + boy + "-" + lev;
    }
}
src/main/java/com/zy/common/model/StartupDto.java
@@ -18,4 +18,8 @@
    private Integer workNo;
    private String barcode;
    private String taskNo;
}
src/main/java/com/zy/common/service/CommonService.java
@@ -25,7 +25,9 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
@@ -35,6 +37,7 @@
@Slf4j
@Service
public class CommonService {
    private static final int MIN_SPARE_LOC_COUNT = 2;
    @Autowired
    private WrkMastService wrkMastService;
@@ -126,10 +129,18 @@
     */
    @Transactional
    public StartupDto getLocNo(Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto) {
        return getLocNo(staDescId, sourceStaNo, findLocNoAttributeVo, locTypeDto, null);
    }
    @Transactional
    public StartupDto getLocNo(Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto, List<Integer> recommendRows) {
        try {
            Integer whsType = Utils.GetWhsType(sourceStaNo);
            RowLastno rowLastno = rowLastnoService.selectById(whsType);
            RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
            if (rowLastnoType.getType() == 2) {
                return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, 0);
            }
            /**
             * 库型 1: 标准堆垛机库  2: 平库  3: 穿梭板  4: 四向车  5: AGV  0: 未知
             */
@@ -145,7 +156,7 @@
                case 4:
                    return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 4, locTypeDto, 0);
                case 5:
                    return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, 0);
                    return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, 0, locTypeDto, recommendRows, 0);
                default:
                    log.error("站点={} 未查询到对应的规则", sourceStaNo);
                    break;
@@ -177,7 +188,7 @@
            int availableLocCount = locMastService.selectCount(new EntityWrapper<LocMast>()
                    .eq("row1", nearRow)
                    .eq("loc_sts", "O")
                    .eq("whs_type", rowLastnoType.getType().longValue()));
                    .eq("whs_type", 1));
            int crnCountO = wrkMastService.selectCount(new EntityWrapper<WrkMast>()
                    .eq("crn_no", crnNo).le("io_type", 100));
            if (availableLocCount - crnCountO <= 2) { // 可以提成常量,比如 MIN_SPARE_SLOTS = 2
@@ -188,6 +199,298 @@
            return Optional.of(new CrnRowInfo(crnNo, nearRow, curRow, rowCount, attempt));
        }
        return Optional.empty();
    }
    private Optional<CrnRowInfo> findBalancedCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times,
                                                           FindLocNoAttributeVo findLocNoAttributeVo, LocTypeDto locTypeDto,
                                                           RowLastnoType rowLastnoType) {
        int maxScanTimes = Math.max(crnNumber * 2, 1);
        int scanCurRow = curRow;
        Map<Integer, Integer> availableLocCountCache = new HashMap<>();
        Map<Integer, Integer> crnTaskCountCache = new HashMap<>();
        CrnRowInfo bestInfo = null;
        int bestTaskCount = Integer.MAX_VALUE;
        int bestSpareLocCount = Integer.MIN_VALUE;
        int bestOffset = Integer.MAX_VALUE;
        CrnRowInfo fallbackInfo = null;
        int fallbackTaskCount = Integer.MAX_VALUE;
        int fallbackAvailableLocCount = Integer.MIN_VALUE;
        int fallbackOffset = Integer.MAX_VALUE;
        for (int attempt = 0; attempt < maxScanTimes; attempt++) {
            int[] params = Utils.LocNecessaryParameters(rowLastno, scanCurRow, crnNumber);
            scanCurRow = params[1];
            int rowCount = params[0];
            int crnNo = params[2];
            int nearRow = params[3];
            if (attempt < times) {
                continue;
            }
            int availableLocCount = availableLocCountCache.computeIfAbsent(crnNo, key ->
                    countAvailableLocForCrn(rowLastno, rowLastnoType, key, nearRow));
            int crnTaskCount = crnTaskCountCache.computeIfAbsent(crnNo, key ->
                    wrkMastService.selectCount(new EntityWrapper<WrkMast>()
                            .eq("crn_no", key)
                            .le("io_type", 100)));
            int spareLocCount = availableLocCount - crnTaskCount;
            int offset = attempt - times;
            if (availableLocCount > 0 && isBetterCrnCandidate(crnTaskCount, availableLocCount, offset,
                    fallbackTaskCount, fallbackAvailableLocCount, fallbackOffset)) {
                fallbackInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt);
                fallbackTaskCount = crnTaskCount;
                fallbackAvailableLocCount = availableLocCount;
                fallbackOffset = offset;
            }
            if (spareLocCount <= MIN_SPARE_LOC_COUNT) {
                log.warn("{}号堆垛机可用空库位余量不足,降级候选继续保留。尺寸规格:{},轮询次数:{}", crnNo, JSON.toJSONString(locTypeDto), attempt);
                continue;
            }
            if (isBetterCrnCandidate(crnTaskCount, spareLocCount, offset, bestTaskCount, bestSpareLocCount, bestOffset)) {
                bestInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt);
                bestTaskCount = crnTaskCount;
                bestSpareLocCount = spareLocCount;
                bestOffset = offset;
            }
        }
        if (bestInfo != null) {
            return Optional.of(bestInfo);
        }
        if (fallbackInfo != null) {
            log.warn("堆垛机均衡分配未找到满足余量阈值的候选,降级使用仍有空位的堆垛机: crnNo={}", fallbackInfo.getCrnNo());
        }
        return Optional.ofNullable(fallbackInfo);
    }
    private boolean isBetterCrnCandidate(int taskCount, int spareLocCount, int offset,
                                         int bestTaskCount, int bestSpareLocCount, int bestOffset) {
        if (taskCount != bestTaskCount) {
            return taskCount < bestTaskCount;
        }
        if (spareLocCount != bestSpareLocCount) {
            return spareLocCount > bestSpareLocCount;
        }
        return offset < bestOffset;
    }
    private int countAvailableLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int preferredNearRow) {
        List<Integer> searchRows = getCrnSearchRows(rowLastno, crnNo, preferredNearRow);
        if (searchRows.isEmpty()) {
            return 0;
        }
        return locMastService.selectCount(new EntityWrapper<LocMast>()
                .in("row1", searchRows)
                .eq("loc_sts", "O")
                .eq("whs_type", rowLastnoType.getType().longValue()));
    }
    private int countAvailableSingleExtensionLocForCrn(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int preferredNearRow, LocTypeDto locTypeDto) {
        List<Integer> searchRows = getCrnSearchRows(rowLastno, crnNo, preferredNearRow);
        if (searchRows.isEmpty()) {
            return 0;
        }
        Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>()
                .in("row1", searchRows)
                .eq("loc_sts", "O")
                .eq("whs_type", rowLastnoType.getType().longValue());
        if (locTypeDto != null && locTypeDto.getLocType1() != null) {
            wrapper.eq("loc_type1", locTypeDto.getLocType1());
        }
        return locMastService.selectCount(wrapper);
    }
    private Optional<CrnRowInfo> findBalancedSingleExtensionCrnAndNearRow(RowLastno rowLastno, int curRow, int crnNumber, int times,
                                                                           LocTypeDto locTypeDto, RowLastnoType rowLastnoType) {
        int maxScanTimes = Math.max(crnNumber * 2, 1);
        int scanCurRow = curRow;
        Map<Integer, Integer> availableLocCountCache = new HashMap<>();
        Map<Integer, Integer> crnTaskCountCache = new HashMap<>();
        CrnRowInfo bestInfo = null;
        int bestTaskCount = Integer.MAX_VALUE;
        int bestSpareLocCount = Integer.MIN_VALUE;
        int bestOffset = Integer.MAX_VALUE;
        CrnRowInfo fallbackInfo = null;
        int fallbackTaskCount = Integer.MAX_VALUE;
        int fallbackAvailableLocCount = Integer.MIN_VALUE;
        int fallbackOffset = Integer.MAX_VALUE;
        for (int attempt = 0; attempt < maxScanTimes; attempt++) {
            int[] params = Utils.LocNecessaryParameters(rowLastno, scanCurRow, crnNumber);
            scanCurRow = params[1];
            int rowCount = params[0];
            int crnNo = params[2];
            int nearRow = params[3];
            if (attempt < times) {
                continue;
            }
            int availableLocCount = availableLocCountCache.computeIfAbsent(crnNo, key ->
                    countAvailableSingleExtensionLocForCrn(rowLastno, rowLastnoType, key, nearRow, locTypeDto));
            int crnTaskCount = crnTaskCountCache.computeIfAbsent(crnNo, key ->
                    wrkMastService.selectCount(new EntityWrapper<WrkMast>()
                            .eq("crn_no", key)
                            .le("io_type", 100)));
            int spareLocCount = availableLocCount - crnTaskCount;
            int offset = attempt - times;
            if (availableLocCount > 0 && isBetterCrnCandidate(crnTaskCount, availableLocCount, offset,
                    fallbackTaskCount, fallbackAvailableLocCount, fallbackOffset)) {
                fallbackInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt);
                fallbackTaskCount = crnTaskCount;
                fallbackAvailableLocCount = availableLocCount;
                fallbackOffset = offset;
            }
            if (spareLocCount <= MIN_SPARE_LOC_COUNT) {
                continue;
            }
            if (isBetterCrnCandidate(crnTaskCount, spareLocCount, offset, bestTaskCount, bestSpareLocCount, bestOffset)) {
                bestInfo = new CrnRowInfo(crnNo, nearRow, scanCurRow, rowCount, attempt);
                bestTaskCount = crnTaskCount;
                bestSpareLocCount = spareLocCount;
                bestOffset = offset;
            }
        }
        if (bestInfo != null) {
            return Optional.of(bestInfo);
        }
        return Optional.ofNullable(fallbackInfo);
    }
    private List<Integer> getCrnSearchRows(RowLastno rowLastno, int crnNo, int preferredNearRow) {
        List<Integer> searchRows = new ArrayList<>();
        addSearchRow(searchRows, preferredNearRow, rowLastno);
        Integer rowSpan = getCrnRowSpan(rowLastno.getTypeId());
        if (rowSpan == null) {
            return searchRows;
        }
        int crnOffset = crnNo - rowLastno.getsCrnNo();
        if (crnOffset < 0) {
            return searchRows;
        }
        int startRow = rowLastno.getsRow() + crnOffset * rowSpan;
        switch (rowLastno.getTypeId()) {
            case 1:
                addSearchRow(searchRows, startRow + 1, rowLastno);
                addSearchRow(searchRows, startRow + 2, rowLastno);
                break;
            case 2:
                addSearchRow(searchRows, startRow, rowLastno);
                addSearchRow(searchRows, startRow + 1, rowLastno);
                break;
            default:
                break;
        }
        return searchRows;
    }
    private Integer getCrnRowSpan(Integer typeId) {
        if (typeId == null) {
            return null;
        }
        switch (typeId) {
            case 1:
                return 4;
            case 2:
                return 2;
            default:
                return null;
        }
    }
    private void addSearchRow(List<Integer> searchRows, Integer row, RowLastno rowLastno) {
        if (row == null) {
            return;
        }
        if (row < rowLastno.getsRow() || row > rowLastno.geteRow()) {
            return;
        }
        if (!searchRows.contains(row)) {
            searchRows.add(row);
        }
    }
    private LocMast findStandardEmptyLoc(RowLastno rowLastno, RowLastnoType rowLastnoType, int crnNo, int nearRow, LocTypeDto locTypeDto) {
        for (Integer searchRow : getCrnSearchRows(rowLastno, crnNo, nearRow)) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("row1", searchRow)
                    .eq("loc_sts", "O")
                    .eq("whs_type", rowLastnoType.getType().longValue())
                    .orderBy("lev1", true)
                    .orderBy("bay1", true));
            for (LocMast locMast1 : locMasts) {
                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                    continue;
                }
                if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                    String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                    LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                            .eq("loc_no", shallowLoc)
                            .eq("loc_sts", "O")
                            .eq("whs_type", rowLastnoType.getType().longValue()));
                    if (!Cools.isEmpty(locMast2)) {
                        return locMast2;
                    }
                } else if (!Cools.isEmpty(locMast1)) {
                    return locMast1;
                }
            }
            if (!Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                continue;
            }
            for (LocMast locMast1 : locMasts) {
                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                    continue;
                }
                String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                        .eq("loc_no", shallowLoc)
                        .eq("loc_sts", "O")
                        .eq("whs_type", rowLastnoType.getType().longValue()));
                if (!Cools.isEmpty(locMast2)) {
                    return locMast2;
                }
                locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                        .eq("loc_no", shallowLoc)
                        .eq("loc_sts", "F")
                        .eq("whs_type", rowLastnoType.getType().longValue()));
                if (!Cools.isEmpty(locMast2)) {
                    return locMast1;
                }
                locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                        .eq("loc_no", shallowLoc)
                        .eq("loc_sts", "D")
                        .eq("whs_type", rowLastnoType.getType().longValue()));
                if (!Cools.isEmpty(locMast2)) {
                    return locMast1;
                }
            }
        }
        return null;
    }
    private LocTypeDto buildUpwardCompatibleLocTypeDto(LocTypeDto locTypeDto) {
        if (locTypeDto == null || locTypeDto.getLocType1() == null || locTypeDto.getLocType1() >= 2) {
            return null;
        }
        LocTypeDto compatibleLocTypeDto = new LocTypeDto();
        compatibleLocTypeDto.setLocType1((short) (locTypeDto.getLocType1() + 1));
        compatibleLocTypeDto.setLocType2(locTypeDto.getLocType2());
        compatibleLocTypeDto.setLocType3(locTypeDto.getLocType3());
        compatibleLocTypeDto.setSiteId(locTypeDto.getSiteId());
        return compatibleLocTypeDto;
    }
@@ -241,7 +544,10 @@
        }
        //此程序用于优化堆垛机异常时的运行时间
        Optional<CrnRowInfo> infoOpt = findAvailableCrnAndNearRow(rowLastno, curRow, crnNumber, times, findLocNoAttributeVo, locTypeDto, rowLastnoType);
        Optional<CrnRowInfo> infoOpt = findBalancedCrnAndNearRow(rowLastno, curRow, crnNumber, times, findLocNoAttributeVo, locTypeDto, rowLastnoType);
        if (!infoOpt.isPresent()) {
            infoOpt = findAvailableCrnAndNearRow(rowLastno, curRow, crnNumber, times, findLocNoAttributeVo, locTypeDto, rowLastnoType);
        }
        if (!infoOpt.isPresent()) {
            throw new CoolException("无可用堆垛机");
        }
@@ -370,153 +676,35 @@
            }
        }
        // 开始查找库位 ==============================>>
        // Search empty location ==============================>>
        if (staDescId == 10 && Cools.isEmpty(locMast) && crnNo != 0) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("row1", nearRow)
                    .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())
                    .orderBy("lev1", true).orderBy("bay1", false));
            for (LocMast locMast1 : locMasts) {
                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                    continue;
                }
                if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                    String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                    LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                            .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                    if (!Cools.isEmpty(locMast2)) {
                        locMast = locMast2;
                        break;
                    }
                } else {
                    if (!Cools.isEmpty(locMast1)) {
                        locMast = locMast1;
                        break;
                    }
                }
            }
            if (Cools.isEmpty(locMast) && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                for (LocMast locMast1 : locMasts) {
                    if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                        continue;
                    }
                    if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                        String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                        LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                        if (!Cools.isEmpty(locMast2)) {
                            locMast = locMast2;
                            break;
                        } else {
                            locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                    .eq("loc_no", shallowLoc).eq("loc_sts", "F").eq("whs_type", rowLastnoType.getType().longValue()));
                            if (!Cools.isEmpty(locMast2)) {
                                locMast = locMast1;
                                break;
                            } else {
                                locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                        .eq("loc_no", shallowLoc).eq("loc_sts", "D").eq("whs_type", rowLastnoType.getType().longValue()));
                                if (!Cools.isEmpty(locMast2)) {
                                    locMast = locMast1;
                                    break;
                                }
                            }
                        }
                    } else {
                        if (!Cools.isEmpty(locMast1)) {
                            locMast = locMast1;
                            break;
                        }
                    }
                }
            }
            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
        }
        // 1.按规则查找库位
        if (Cools.isEmpty(locMast) && crnNo != 0) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("row1", nearRow)
                    .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())
                    .orderBy("lev1", true).orderBy("bay1", false));
            for (LocMast locMast1 : locMasts) {
                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                    continue;
                }
                if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                    String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                    LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                            .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                    if (!Cools.isEmpty(locMast2)) {
                        locMast = locMast2;
                        break;
                    }
                } else {
                    if (!Cools.isEmpty(locMast1)) {
                        locMast = locMast1;
                        break;
                    }
                }
            }
            if (Cools.isEmpty(locMast) && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                for (LocMast locMast1 : locMasts) {
                    if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                        continue;
                    }
                    if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                        String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                        LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                        if (!Cools.isEmpty(locMast2)) {
                            locMast = locMast2;
                            break;
                        } else {
                            locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                    .eq("loc_no", shallowLoc).eq("loc_sts", "F").eq("whs_type", rowLastnoType.getType().longValue()));
                            if (!Cools.isEmpty(locMast2)) {
                                locMast = locMast1;
                                break;
                            } else {
                                locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                        .eq("loc_no", shallowLoc).eq("loc_sts", "D").eq("whs_type", rowLastnoType.getType().longValue()));
                                if (!Cools.isEmpty(locMast2)) {
                                    locMast = locMast1;
                                    break;
                                }
                            }
                        }
                    } else {
                        if (!Cools.isEmpty(locMast1)) {
                            locMast = locMast1;
                            break;
                        }
                    }
                }
            }
            locMast = findStandardEmptyLoc(rowLastno, rowLastnoType, crnNo, nearRow, locTypeDto);
        }
        if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) {
            locMast = null;
        }
        // 递归查询
        // Retry search
        if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            // Scan next aisle first, then retry with upward-compatible locType1.
            if (times < rowCount * 2) {
                times = times + 1;
                return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
            }
//            // 2.库位当前所属尺寸无空库位时,调整尺寸参数,向上兼容检索库位
//            if (locTypeDto.getLocType1() < 2) {
//                int i = locTypeDto.getLocType1() + 1;
//                locTypeDto.setLocType1((short)i);
//                return getLocNo(1, staDescId, sourceStaNo, matnr,batch,grade, locTypeDto, 0);
//            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
            LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto);
            if (compatibleLocTypeDto != null) {
                log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto));
                return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0);
            }
            log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d");
        }
        String locNo = locMast.getLocNo();
@@ -528,6 +716,112 @@
        startupDto.setSourceStaNo(sourceStaNo);
        startupDto.setLocNo(locNo);
        return startupDto;
    }
    public StartupDto getLocNoRun2(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
        int crnNo = 0;
        int nearRow = 0;
        int curRow = 0;
        int rowCount = 0;
        LocMast locMast = null;
        StartupDto startupDto = new StartupDto();
        RowLastno rowLastno = rowLastnoService.selectById(whsType);
        if (Cools.isEmpty(rowLastno)) {
            throw new CoolException("数据异常,请联系管理员===>库位规则未知");
        }
        crnNo = rowLastno.getCurrentRow()/2+1;
        RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
        if (Cools.isEmpty(rowLastnoType)) {
            throw new CoolException("数据异常,请联系管理员===》库位规则类型未知");
        }
        int crnNumber = rowLastno.getCrnQty();
        curRow = rowLastno.getCurrentRow();
        Wrapper<StaDesc> wrapper = null;
        StaDesc staDesc = null;
        BasDevp staNo = null;
        if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) {
            wrapper = new EntityWrapper<StaDesc>()
                    .eq("type_no", staDescId)
                    .eq("stn_no", sourceStaNo)
                    .eq("crn_no", crnNo);
            staDesc = staDescService.selectOne(wrapper);
            if (Cools.isEmpty(staDesc)) {
                log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
                crnNo = 0;
            } else {
                staNo = basDevpService.selectById(staDesc.getCrnStn());
                if (!staNo.getAutoing().equals("Y")) {
                    log.error("目标站{}不可用", staDesc.getCrnStn());
                    crnNo = 0;
                }
                startupDto.setStaNo(staNo.getDevNo());
            }
        }
        LocMast locMast1 = locMastService.selectOne(new EntityWrapper<LocMast>()
                .eq("crn_no", crnNo)
                .eq("loc_sts", "O")
                .orderBy("lev1")
                .orderBy("bay1")
                .eq("loc_type1",locTypeDto.getLocType1()));
        if (!Cools.isEmpty(locMast1)) {
            locMast=locMast1;
        }
        if (curRow==rowLastno.geteRow()-1) {
            curRow = 1;
        }else{
            curRow = curRow + 2;
        }
        rowLastno.setCurrentRow(curRow);
        rowLastnoService.updateById(rowLastno);
        if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) {
            locMast = null;
        }
        if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
            if (times < rowCount * 2) {
                times = times + 1;
                return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
            }
            LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto);
            if (compatibleLocTypeDto != null) {
                log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto));
                return getLocNoRun2(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0);
            }
            log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d");
        }
        int workNo = getWorkNo(0);
        startupDto.setWorkNo(workNo);
        startupDto.setCrnNo(crnNo);
        startupDto.setSourceStaNo(sourceStaNo);
        startupDto.setLocNo(locMast.getLocNo());
        return startupDto;
    }
    private LocMast findSingleExtensionEmptyLoc(RowLastno rowLastno, int crnNo, int nearRow, RowLastnoType rowLastnoType, LocTypeDto locTypeDto) {
        for (Integer searchRow : getCrnSearchRows(rowLastno, crnNo, nearRow)) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("row1", searchRow)
                    .eq("loc_sts", "O")
                    .eq("whs_type", rowLastnoType.getType().longValue())
                    .orderBy("bay1", true)
                    .orderBy("lev1", true));
            for (LocMast locMast : locMasts) {
                if (VersionUtils.locMoveCheckLocTypeComplete(locMast, locTypeDto)) {
                    return locMast;
                }
            }
        }
        return null;
    }
    public StartupDto getLocNoRun4(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
@@ -928,10 +1222,10 @@
                        continue;
                    }
                    if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                        //获取目标库位所在巷道并排序
                        // ?????????????
//                        List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow);
                        //获取目标库位所在巷道最浅非空库位
                        // ????????????????
                        LocMast locMast2 = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
                        if (Cools.isEmpty(locMast2)) {
                            LocMast locMast3 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
@@ -953,15 +1247,20 @@
            }
        }
        // 递归查询
        // Retry search
        if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            // Scan next aisle first, then retry with upward-compatible locType1.
            if (times < rowCount * 2) {
                times = times + 1;
                return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
            LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto);
            if (compatibleLocTypeDto != null) {
                log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto));
                return getLocNoRun4(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, 0);
            }
            log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d");
        }
        String locNo = locMast.getLocNo();
@@ -975,7 +1274,7 @@
        return startupDto;
    }
    public StartupDto getLocNoRun5(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
    public StartupDto getLocNoRun5(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, List<Integer> recommendRows, int times) {
        // 初始化参数
        int crnNo = 0;      //堆垛机号
@@ -1045,6 +1344,20 @@
        }
        // 开始查找库位 ==============================>>
        if (Cools.isEmpty(locMast) && !Cools.isEmpty(recommendRows)) {
            for (Integer recommendRow : recommendRows) {
                if (Cools.isEmpty(recommendRow)) {
                    continue;
                }
                LocMast recommendLoc = locMastService.queryFreeLocMast(recommendRow, locTypeDto.getLocType1(), rowLastnoType.getType().longValue());
                if (!Cools.isEmpty(recommendLoc) && VersionUtils.locMoveCheckLocTypeComplete(recommendLoc, locTypeDto)) {
                    locMast = recommendLoc;
                    crnNo = recommendLoc.getCrnNo();
                    break;
                }
            }
        }
        if (Cools.isEmpty(locMast) && sourceStaNo != 4006) {//si'lou'p四楼盘点选择区域
                 List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
@@ -1143,7 +1456,7 @@
                            continue;
                        }
                        if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                            // 获取目标库位所在巷道最深空库位
                            // ???????????????
                            LocMast locMast2 = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
                            if (!Cools.isEmpty(locMast2) && locMast2.getRow1() == curRow) {
                                locMast = locMast2;
@@ -1154,7 +1467,7 @@
                    }
                    if (found) {
                        break; // 找到目标库位后跳出循环
                        break; // ???????????
                    }
                }
            }
@@ -1162,15 +1475,20 @@
        // 递归查询
        // Retry search
        if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            // Scan next aisle first, then retry with upward-compatible locType1.
            if (times < rowCount * 2) {
                times = times + 1;
                return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
                return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, recommendRows, times);
            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
            LocTypeDto compatibleLocTypeDto = buildUpwardCompatibleLocTypeDto(locTypeDto);
            if (compatibleLocTypeDto != null) {
                log.warn("locType1 upward compatibility retry. source={}, target={}", JSON.toJSONString(locTypeDto), JSON.toJSONString(compatibleLocTypeDto));
                return getLocNoRun5(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, compatibleLocTypeDto, recommendRows, 0);
            }
            log.error("No empty location found. spec={}, times={}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("\u6ca1\u6709\u7a7a\u5e93\u4f4d");
        }
        String locNo = locMast.getLocNo();
src/main/java/com/zy/common/web/WcsController.java
@@ -9,6 +9,7 @@
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.result.FindLocNoAttributeVo;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.common.CodeRes;
import com.zy.common.model.LocTypeDto;
import com.zy.common.model.StartupDto;
@@ -64,6 +65,23 @@
            if (Cools.isEmpty(param.getBarcode())) {
                return R.error("条码不能为空");
            }
        WrkMast wrkMast1 = wrkMastService.selectByBarcode(param.getBarcode());
        if (!Cools.isEmpty(wrkMast1)&&wrkMast1.getWrkSts()==2) {
            StartupDto dto1 =new StartupDto();
            dto1.setBarcode(param.getBarcode());
            dto1.setStaNo(Integer.valueOf(wrkMast1.getStaNo()));
            String wcsLoc = Utils.WMSLocToWCSLoc(wrkMast1.getLocNo());
            dto1.setLocNo(wcsLoc);
            dto1.setCrnNo(wrkMast1.getCrnNo());
            dto1.setWorkNo(wrkMast1.getWrkNo());
            dto1.setTaskNo(wrkMast1.getWrkNo()+"");
//            dto1.setTaskPri((int) Math.round(wrkMast1.getIoPri()));
            return R.ok(dto1);
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("io_type", 1));
        if (!Cools.isEmpty(wrkMasts)&&wrkMasts.size()>30) {
            return R.error("限行");
        }
            waitPakins = waitPakinService.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", param.getBarcode()));
            if (Cools.isEmpty(waitPakins)) {
                WrkMast wrkMast = wrkMastService.selectByBarcode(param.getBarcode());
@@ -105,18 +123,7 @@
        sourceStaNo.setLocType1(param.getLocType1());
        LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
        StartupDto dto = null;
        switch (param.getIoType()) {
            case 1://满托盘入库
                assert waitPakins != null;
                dto = startupFullPutStore(param.getSourceStaNo(), param.getBarcode(), locTypeDto, waitPakins);
                break;
            case 10://空托盘入库
                dto = emptyPlateIn(param.getSourceStaNo(), locTypeDto, param.getBarcode());
                break;
            default:
                break;
        }
        StartupDto dto = startupFullPutStore(param.getSourceStaNo(), param.getBarcode(), locTypeDto, waitPakins, param.getRow());
        log.info("WCS入库接口返参:{},托盘码:{}", dto, param.getBarcode());
        return R.ok().add(dto);
    }
@@ -417,7 +424,7 @@
     * 全板入库
     */
    @Transactional
    public StartupDto startupFullPutStore(Integer devpNo, String barcode, LocTypeDto locTypeDto, List<WaitPakin> waitPakins) {
    public StartupDto startupFullPutStore(Integer devpNo, String barcode, LocTypeDto locTypeDto, List<WaitPakin> waitPakins, List<Integer> recommendRows) {
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        // 检索库位
@@ -425,7 +432,7 @@
        List<String> batchs = waitPakins.stream().map(WaitPakin::getBatch).distinct().collect(Collectors.toList());
        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(matnrs.get(0), batchs.get(0));
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(waitPakins.get(0));
        StartupDto dto = commonService.getLocNo( 1, devpNo,findLocNoAttributeVo, locTypeDto);
        StartupDto dto = commonService.getLocNo(1, devpNo, findLocNoAttributeVo, locTypeDto, recommendRows);
        int workNo = dto.getWorkNo();
        Date now = new Date();
        // 生成工作档
@@ -475,12 +482,12 @@
        if (!waitPakinService.update(setParam, wrapper)) {
            throw new CoolException("更新通知档失败");
        }
        // 更新源站点信息
        sourceStaNo.setWrkNo(workNo);
        sourceStaNo.setModiTime(now);
        if (!basDevpService.updateById(sourceStaNo)){
            throw new CoolException("更新源站失败");
        }
//        // 更新源站点信息
//        sourceStaNo.setWrkNo(workNo);
//        sourceStaNo.setModiTime(now);
//        if (!basDevpService.updateById(sourceStaNo)){
//            throw new CoolException("更新源站失败");
//        }
        // 更新目标库位状态
        LocMast locMast = locMastService.selectById(dto.getLocNo());
        if (locMast.getLocSts().equals("O")){
@@ -492,6 +499,9 @@
        } else {
            throw new CoolException(dto.getLocNo()+"目标库位已被占用");
        }
        String wcsLoc = Utils.WMSLocToWCSLoc(dto.getLocNo());
        dto.setLocNo(wcsLoc);
        dto.setTaskNo(workNo+"");
        return dto;
    }
src/main/java/com/zy/common/web/param/SearchLocParam.java
@@ -11,14 +11,11 @@
public class SearchLocParam {
    private String barcode;
    private Integer sourceStaNo;
    private List<Integer> rowList;
    private List<Integer> row;
    // 库位规格( 0:未知, 1:低库位, 2:高库位)
    // 库位规格(0:未知, 1:低库位, 2:高库位)
    private Short locType1;
    private Integer ioType;
    private Integer outArea;
}
src/main/resources/application.yml
@@ -112,3 +112,5 @@
    createOutTask: /openapi/createOutTask
    #移库任务下发地址
    createLocMoveTask: /openapi/createLocMoveTask
    #pause out task
    stopOutTask: /openapi/stopOutTask