自动化立体仓库 - WMS系统
erp出库作业完善
1.出库任务下发给wcs之前会先卡住,等erp发立即出库时再给wcs下发(补丁,后需要删掉)
2.给wcs自动下发出库任务
3.新增出库任务完成后上报erp接口(三次上报失败后直接转历史档这个地方有点问题)
15个文件已修改
229 ■■■■■ 已修改文件
src/main/java/com/zy/api/controller/params/StopOutTaskParams.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMast.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/OpenOrderPakoutPauseParam.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/AutomaticallyIssueWCSTasksScheduler.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/WorkMastScheduler.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/AutomaticallyIssueWCSTasksHandler.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastLogMapper.xml 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastMapper.xml 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/StopOutTaskParams.java
@@ -18,7 +18,7 @@
    private String orderNo;
    @ApiModelProperty("pause reason")
    private String reason;
    private Integer reason;
    @ApiModelProperty("task list")
    private List<TaskItem> tasks = new ArrayList<>();
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
@@ -96,8 +96,13 @@
        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())) {
        if (!Objects.isNull(wrkMast) && "out".equalsIgnoreCase(params.getType())) {
            if ("Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
            return R.error("task paused");
            }
            if (requiresOutboundErpConfirm(wrkMast) && !"Y".equalsIgnoreCase(wrkMast.getPdcType())) {
                return R.error("task not confirmed by erp");
            }
        }
        try {
            log.info("下发搬运任务给wcs="+JSON.toJSONString(params));
@@ -179,8 +184,8 @@
            } 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.setUpdMk("WCS_CANCELLED");
//                    mast.setManuType("WCS_CANCELLED");
                    mast.setModiTime(new Date());
                    if (!wrkMastService.updateById(mast)) {
                        throw new CoolException("task cancel update fail");
@@ -206,6 +211,11 @@
        }
        return R.ok();
    }
    private boolean requiresOutboundErpConfirm(WrkMast wrkMast) {
        Integer ioType = wrkMast == null ? null : wrkMast.getIoType();
        return ioType != null && (ioType == 101 || ioType == 103 || ioType == 104 || ioType == 107 || ioType == 110);
    }
    @Override
    public R pauseOutTasks(StopOutTaskParams params) {
        if (params == null || params.getTasks() == null || params.getTasks().isEmpty()) {
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -116,16 +116,7 @@
    /**
     * pause out order
     */
    @PostMapping("/order/pakout/pause/default/v1")
    public synchronized R pakoutOrderPause(@RequestBody OpenOrderPakoutPauseParam param){
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getOrderId())) {
            return R.error("orderNo is empty");
        }
        return openService.pakoutOrderPause(param);
    }
    /**
     * 出库单回写
@@ -472,26 +463,14 @@
    }
    /**
     * 添加出库单
     * pause out order
     */
    @PostMapping("/order/pakout/default/v1")
//    @AppAuth(memo = "添加订单出库")
    public synchronized R pakoutOrderCreate(@RequestBody OpenOrderPakoutParam param) {
//        auth(appkey, param, request);
        if (Cools.isEmpty(param)) {
            return R.parse(BaseRes.PARAM);
    @PostMapping("/order/pakout/pause/default/v1")
    public synchronized R pakoutOrderPause(@RequestBody OpenOrderPakoutPauseParam param){
        if (Cools.isEmpty(param) || Cools.isEmpty(param.getOrderId())) {
            return R.error("orderNo is empty");
        }
        if (Cools.isEmpty(param.getOrderNo())) {
            return R.error("单据编号[orderNo]不能为空");
        }
        if (Cools.isEmpty(param.getOrderType())) {
            return R.error("单据类型[orderType]不能为空");
        }
        if (Cools.isEmpty(param.getOrderDetails())) {
            return R.error("单据明细[orderDetails]不能为空");
        }
        openService.pakoutOrderCreate(param);
        return R.ok();
        return openService.pakoutOrderPause(param);
    }
}
src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -292,7 +292,7 @@
    @ApiModelProperty(value= "条码")
    private String barcode;
    // Y:销售订单出库任务
    // ERP出库确认标记:Y 允许下发WCS,N/空 不允许
    @ApiModelProperty(value= "")
    @TableField("Pdc_type")
    private String PdcType;
src/main/java/com/zy/asrs/entity/param/OpenOrderPakoutPauseParam.java
@@ -7,5 +7,5 @@
    private String orderId;
    private String reason;
    private Integer reason;
}
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -248,6 +248,7 @@
        wrkMast.setIoTime(now);
        wrkMast.setWrkSts(11L); // 工作状态:101.生成出库
        wrkMast.setIoType(104); // 入出库状态
        wrkMast.setPdcType("N");
        wrkMast.setIoPri(13D); // 优先级:13
        wrkMast.setSourceStaNo(staDesc.getCrnStn()); // 源站
        wrkMast.setStaNo(staDesc.getStnNo()); // 目标站
@@ -1316,6 +1317,7 @@
        wrkMast.setExitMk("N"); // 退出
        wrkMast.setEmptyMk("N"); // 空板
        wrkMast.setLinkMis("N");
        wrkMast.setPdcType("N");
        wrkMast.setAppeUser(userId); // 操作人员数据
        wrkMast.setAppeTime(now);
        wrkMast.setModiUser(userId);
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -377,53 +377,35 @@
        if (param == null || Cools.isEmpty(param.getOrderId())) {
            throw new CoolException("orderNo is empty");
        }
        Order order = orderService.selectByNo(param.getOrderId());
        if (order == null) {
            order = OrderInAndOutUtil.selectByNo(Boolean.FALSE, param.getOrderId());
        }
        if (order == null) {
            throw new CoolException("order not found: " + param.getOrderId());
        }
        List<WrkMast> activeTasks = findActiveOutboundTasks(param.getOrderId());
        Map<String, Object> result = new HashMap<>();
        result.put("orderNo", param.getOrderId());
        result.put("taskCount", activeTasks.size());
        if (activeTasks.isEmpty()) {
            return R.ok("no active out tasks");
            result.put("confirmedCount", 0);
            return R.ok("no active out tasks").add(result);
        }
        Date now = new Date();
        int pausedCount = 0;
        List<WrkMast> issuedTasks = new ArrayList<>();
        int confirmedCount = 0;
        for (WrkMast wrkMast : activeTasks) {
            if (wrkMast == null || "Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
            if (wrkMast == null || "Y".equalsIgnoreCase(wrkMast.getPdcType())) {
                continue;
            }
            wrkMast.setPauseMk("Y");
            wrkMast.setUpdMk(needNotifyWcsStop(wrkMast) ? "WCS_STOP_REQUESTED" : "WMS_PAUSED");
            wrkMast.setManuType("ERP_PAUSE");
            wrkMast.setPdcType("Y");
//            wrkMast.setUpdMk("ERP_CONFIRMED");
//            wrkMast.setManuType("ERP_CONFIRM_OUT");
            wrkMast.setModiTime(now);
            wrkMast.setModiUser(9527L);
            if (!wrkMastService.updateById(wrkMast)) {
                throw new CoolException("pause out task failed: " + wrkMast.getWrkNo());
                throw new CoolException("confirm out task failed: " + wrkMast.getWrkNo());
            }
            pausedCount++;
            if (needNotifyWcsStop(wrkMast)) {
                issuedTasks.add(wrkMast);
            }
            confirmedCount++;
        }
        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.getOrderId());
        result.put("pausedCount", pausedCount);
        result.put("wcsStopCount", issuedTasks.size());
        return R.ok("pause out success").add(result);
        result.put("confirmedCount", confirmedCount);
        return R.ok(confirmedCount == 0 ? "tasks already confirmed" : "erp confirm out success").add(result);
    }
    @Override
@@ -440,8 +422,8 @@
        }
        if (Objects.equals(param.getExecute(), 2)) {
            OpenOrderPakoutPauseParam pauseParam = new OpenOrderPakoutPauseParam();
//            pauseParam.getOrderId(param.getOrderId());
//            pauseParam.setReason("OPEN_API_PAUSE");
            pauseParam.setOrderId(param.getOrderId());
//            pauseParam.setReason("OPEN_API_CONFIRM_OUT");
            return pakoutOrderPause(pauseParam);
        }
        throw new CoolException("execute only supports 1 or 2");
@@ -461,8 +443,8 @@
        }
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>()
                .in("wrk_no", wrkNos)
                .in("io_type", Arrays.asList(101, 103, 107, 108, 110))
                .lt("wrk_sts", 14L));
                .in("io_type", Arrays.asList(101, 103, 104, 107, 108, 110))
                .eq("wrk_sts", 11L));
        if (wrkMasts == null || wrkMasts.isEmpty()) {
            return Collections.emptyList();
        }
@@ -1336,6 +1318,7 @@
        wrkMast.setExitMk("N"); // 退出
        wrkMast.setEmptyMk("N"); // 空板
        wrkMast.setLinkMis("N");
        wrkMast.setPdcType("N");
        wrkMast.setUserNo(param.getOrderId());//订单号
        wrkMast.setPltType(param.getSeq());//出库顺序,从1开始
        wrkMast.setTakeNone("0");  //0非自动
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -367,6 +367,7 @@
            wrkMast.setExitMk("N"); // 退出
            wrkMast.setEmptyMk("N"); // 空板
            wrkMast.setLinkMis("N");
            wrkMast.setPdcType("N");
            wrkMast.setBarcode(locMast.getBarcode());
            wrkMast.setTakeNone("0");  //0非自动
@@ -749,6 +750,7 @@
        wrkMast.setExitMk("N"); // 退出
        wrkMast.setEmptyMk("N"); // 空板
        wrkMast.setLinkMis("N");
        wrkMast.setPdcType("N");
        wrkMast.setBarcode(locMast.getBarcode());
        wrkMast.setAppeUser(userId); // 操作人员数据
        wrkMast.setAppeTime(now);
@@ -984,6 +986,7 @@
            wrkMast.setExitMk("N"); // 退出
            wrkMast.setEmptyMk("Y"); // 空板
            wrkMast.setLinkMis("N");
            wrkMast.setPdcType("N");
            wrkMast.setAppeUser(userId);
            wrkMast.setAppeTime(now);
            wrkMast.setModiUser(userId);
@@ -1046,6 +1049,7 @@
            wrkMast.setExitMk("N"); // 退出
            wrkMast.setEmptyMk("Y"); // 空板
            wrkMast.setLinkMis("N");
            wrkMast.setPdcType("N");
            wrkMast.setAppeUser(1L);
            wrkMast.setAppeTime(now);
            wrkMast.setModiUser(1L);
src/main/java/com/zy/asrs/task/AutomaticallyIssueWCSTasksScheduler.java
@@ -22,12 +22,12 @@
    @Autowired
    private AutomaticallyIssueWCSTasksHandler automaticallyIssueWCSTasksHandler;
    @Scheduled(cron = "0/3 * * * * ? ")
//    @Scheduled(cron = "0/3 * * * * ? ")
    private void execute(){
        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')")
                        .last(" and (pause_mk is null or pause_mk <> 'Y') and (io_type not in (101,103,104,107,110) or Pdc_type = 'Y')")
        );
        if (wrkMasts.isEmpty()) {
            return;
src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -1,15 +1,24 @@
package com.zy.asrs.task;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.common.R;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.LocMast;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.service.WrkMastService;
import com.zy.asrs.task.core.ReturnT;
import com.zy.asrs.task.handler.WorkMastHandler;
import com.zy.asrs.utils.Utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -21,6 +30,8 @@
    private static final Logger log = LoggerFactory.getLogger(WorkMastScheduler.class);
    @Autowired
    private WcsApiService wcsApiService;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
@@ -45,4 +56,60 @@
        }
    }
    /**
     * 任务自动下发
     *
     * @author Ryan
     * @date 2026/1/10 14:42
     */
    @Scheduled(cron = "0/3 * * * * ? ")
    private void autoPubTasks() {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().in("wrk_sts", Arrays.asList(1L, 11L)));
        if (wrkMasts.isEmpty()) {
            return;
        }
        Collections.shuffle(wrkMasts);
        for (WrkMast wrkMast : wrkMasts) {
            if (wrkMast.getIoType()>100&& !wrkMast.getPdcType().equals("Y")) {
                continue;
            }
            Integer crnNo = wrkMast.getCrnNo();
            //该堆垛机已经下发任务给wcs后不再下发新的搬运任务
            List<WrkMast> wrkMasts1 = wrkMastService.selectList(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).in("wrk_sts", Arrays.asList(2L, 12L)));
            if (!wrkMasts1.isEmpty()) {
                continue;
            }
            String wcsSourceLocNo = Cools.isEmpty(wrkMast.getSourceLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getSourceLocNo());
            String wcsLocNo = Cools.isEmpty(wrkMast.getLocNo()) ? "" : Utils.WMSLocToWCSLoc(wrkMast.getLocNo());
            WorkTaskParams params = new WorkTaskParams();
            //出库和移库
            if(wrkMast.getIoType()==101&&!Cools.isEmpty(wrkMast.getStaNo())&& !wrkMast.getStaNo().equals("0")) {
                params.setType("out")
                        .setTaskNo(wrkMast.getWrkNo()+"")
                        .setLocNo(wcsSourceLocNo)
                        .setStaNo(String.valueOf(wrkMast.getStaNo()))
                        .setTaskPri(wrkMast.getIoPri().intValue())
                        .setBarcode(wrkMast.getBarcode());
            }else if(wrkMast.getIoType()==2&& !Cools.isEmpty(wrkMast.getSourceStaNo())){
                params.setType("in")
                        .setTaskNo(wrkMast.getWrkNo()+"")
                        .setSourceStaNo(String.valueOf(wrkMast.getSourceStaNo()))
                        .setLocNo(wcsLocNo)
                        .setTaskPri(wrkMast.getIoPri().intValue())
                        .setBarcode(wrkMast.getBarcode());
            } else {
                params.setType("move")
                        .setTaskNo(wrkMast.getWrkNo()+"")
                        .setSourceLocNo(wcsSourceLocNo)
                        .setLocNo(wcsLocNo)
                        .setBarcode(wrkMast.getBarcode());
            }
            R r = wcsApiService.pubWrkToWcs(params);
            if (r.get("code").equals(200)){
                break;
            }
        };
    }
}
src/main/java/com/zy/asrs/task/handler/AutomaticallyIssueWCSTasksHandler.java
@@ -51,6 +51,9 @@
                    if ("Y".equalsIgnoreCase(m.getPauseMk())) {
                        continue;
                    }
                    if (requiresOutboundErpConfirm(m) && !"Y".equalsIgnoreCase(m.getPdcType())) {
                        continue;
                    }
                    if (m.getUpdMk() != null && "WCS_SENT".equalsIgnoreCase(m.getUpdMk())) {
                        continue;
                    }
@@ -139,4 +142,9 @@
        }
        return SUCCESS;
    }
    private boolean requiresOutboundErpConfirm(WrkMast wrkMast) {
        Integer ioType = wrkMast == null ? null : wrkMast.getIoType();
        return ioType != null && (ioType == 101 || ioType == 103 || ioType == 104 || ioType == 107 || ioType == 110);
    }
}
src/main/java/com/zy/asrs/task/handler/WorkMastHandler.java
@@ -88,11 +88,30 @@
        if (!Cools.isEmpty(erpReport) && !"true".equalsIgnoreCase(erpReport)) {
            return false;
        }
        if (wrkMast == null || Cools.isEmpty(wrkMast.getBarcode())) {
        if (wrkMast == null) {
            return false;
        }
        Integer ioType = wrkMast.getIoType();
        return ioType != null && (ioType == 101 || ioType == 108 || ioType == 110);
        if (ioType == null || (ioType != 101 && ioType != 108 && ioType != 110)) {
            return false;
        }
        return !Cools.isEmpty(resolveOutboundPalletId(wrkMast));
    }
    private String resolveOutboundPalletId(WrkMast wrkMast) {
        if (!Cools.isEmpty(wrkMast.getBarcode())) {
            return wrkMast.getBarcode();
        }
        List<WrkDetl> wrkDetls = wrkDetlService.selectByWrkNo(wrkMast.getWrkNo());
        if (Cools.isEmpty(wrkDetls)) {
            return null;
        }
        for (WrkDetl wrkDetl : wrkDetls) {
            if (!Cools.isEmpty(wrkDetl.getZpallet())) {
                return wrkDetl.getZpallet();
            }
        }
        return null;
    }
    public ReturnT<String> doIn(WrkMast wrkMast) {
@@ -595,3 +614,4 @@
        return SUCCESS;
    }
}
src/main/resources/application.yml
@@ -96,7 +96,7 @@
    URL: http://192.168.160.8:8088
    #入库上报
    Inaddress: /api/Service/InPalletCompleted
    #商品档案地址
    #出库上报
    Outaddress: /kapi/v2/eap7/basedata/bd_material/batchQuery
#wcs任务下发
@@ -105,7 +105,7 @@
  switch: true
  #  地址
  address:
    URL: https://127.0.0.1:9090
    URL: https://127.0.0.1:9090/wcs
    #入库任务下发地址
    createInTask : /openapi/createInTask
    #出库任务下发地址
src/main/resources/mapper/WrkMastLogMapper.xml
@@ -57,6 +57,7 @@
        <result column="log_err_time" property="logErrTime" />
        <result column="log_err_memo" property="logErrMemo" />
        <result column="barcode" property="barcode" />
        <result column="Pdc_type" property="PdcType" />
        <result column="ctn_no" property="ctnNo" />
        <result column="full_plt" property="fullPlt" />
        <result column="pre_have" property="preHave" />
src/main/resources/mapper/WrkMastMapper.xml
@@ -56,6 +56,7 @@
        <result column="log_err_time" property="logErrTime" />
        <result column="log_err_memo" property="logErrMemo" />
        <result column="barcode" property="barcode" />
        <result column="Pdc_type" property="PdcType" />
        <result column="ctn_no" property="ctnNo" />
        <result column="full_plt" property="fullPlt" />
        <result column="pre_have" property="preHave" />
@@ -70,6 +71,7 @@
        select * from asr_wrk_mast
        where wrk_sts=5
        or (wrk_sts=15 and take_none = '1' and ove_mk='Y' and wrk_no not in (select wrk_no from asr_bas_devp) and wrk_no not in (select wrk_no from asr_wrk_mast_sta))
        or (wrk_sts=15 and log_mk='F' and exp_time &gt;= 3 and wrk_no not in (select wrk_no from asr_bas_devp))
        or (wrk_sts=15 and dateadd(mi,3,crn_end_time) &lt;= getdate() and wrk_no not in (select wrk_no from asr_bas_devp))
        or (wrk_sts=15 and crn_end_time is null and wrk_no not in (select wrk_no from asr_bas_devp))
        or (wrk_no in (9997,9996) and wrk_sts = 15)
@@ -156,3 +158,4 @@
    </select>
</mapper>