自动化立体仓库 - WMS系统
LSH
2023-07-24 485dabe1952c39eeb83291247e9ee1fe77a51df1
#入库逻辑待完善
10个文件已修改
320 ■■■■ 已修改文件
src/main/java/com/zy/asrs/entity/result/KeyValueVo.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/BasCrnpService.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/LocDetlService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasCrnpServiceImpl.java 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/LocDetlServiceImpl.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/WcsController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/result/KeyValueVo.java
@@ -12,4 +12,12 @@
    private Object value;
    public KeyValueVo() {
    }
    public KeyValueVo(String name, Object value) {
        this.name = name;
        this.value = value;
    }
}
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java
@@ -37,6 +37,9 @@
    @Select("SELECT ld.loc_no FROM asr_loc_detl ld LEFT JOIN asr_loc_mast lm ON ld.loc_no = lm.loc_no WHERE (1 = 1 AND ld.matnr = #{matnr} AND (lm.row1 >= #{start} AND lm.row1 <= #{end})  AND lm.loc_sts = 'F' AND DateDiff(dd, ld.appe_time, getdate()) = 0) ORDER BY ld.appe_time ASC")
    List<String> selectSameDetlToday(@Param("matnr") String matnr, @Param("start") Integer start, @Param("end") Integer end);
    @Select("SELECT distinct ld.loc_no FROM asr_loc_detl ld LEFT JOIN asr_loc_mast lm ON ld.loc_no = lm.loc_no WHERE 1 = 1 AND ld.matnr = #{matnr} AND (lm.row1 >= #{start} AND lm.row1 <= #{end}) AND lm.loc_sts = 'F' AND DateDiff(dd, lm.modi_time, getdate()) = 0 AND (left(ld.batch, 4)) = (left(#{batch}, 4))")
    List<String> selectSameDetlToday2(@Param("matnr") String matnr, @Param("batch") String batch, @Param("start") Integer start, @Param("end") Integer end);
    List<LocDetl> getStockStatis(Map<String, Object> map);
    Integer getStockStatisCount(Map<String, Object> map);
src/main/java/com/zy/asrs/service/BasCrnpService.java
@@ -8,5 +8,6 @@
    BasCrnp checkSiteStatus(Integer crnId);
    boolean checkSiteError(Integer crnNo, boolean pakin);
//    boolean checkSiteError2(Integer crnNo, boolean pakin, Integer sourceStaNo);
}
src/main/java/com/zy/asrs/service/LocDetlService.java
@@ -57,4 +57,11 @@
    Double getLocDetlSumQty(String locNo);
    void updateMatTurn(String matnrOld,String matnr);
    /**
     * 获取当天相同规格货物的深库位号
     * @param matnr 商品编号
     * @return locNo 库位号
     */
    List<String> getSameDetlToday2(String matnr, String batch, Integer start, Integer end);
}
src/main/java/com/zy/asrs/service/impl/BasCrnpServiceImpl.java
@@ -1,10 +1,12 @@
package com.zy.asrs.service.impl;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.BasCrnp;
import com.zy.asrs.entity.BasDevp;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.mapper.BasCrnpMapper;
import com.zy.asrs.service.BasCrnpService;
import com.zy.asrs.service.BasDevpService;
@@ -122,4 +124,121 @@
        return true;
    }
//    //杰克
//    @Override
//    public boolean checkSiteError2(Integer crnNo, boolean pakin, Integer sourceStaNo) {
//        BasCrnp crnp = this.selectById(crnNo);
//        if (Cools.isEmpty(crnp)) {
//            log.error("{}号堆垛机不存在", crnNo);
//            return false;
//        }
//        if (crnp.getCrnErr() != null && crnp.getCrnSts() != 3){
//            log.error("{}号堆垛机非自动连线状态,无法作业!", crnNo);
//            return false;
//        }
//        if (crnp.getCrnErr() != null) {
//            if (crnp.getCrnErr() != 0) {
//                log.error("{}号堆垛机异常,异常码{}", crnNo, crnp.getCrnErr());
//                return false;
//            }
//        }
//
//        if (pakin) {
//            //TODO控制入库暂存数,防止主干道堵塞,2022-5-24 ADD
//            int staNo = 0;
//            String crnNos = "";
//            switch (crnNo){
//                case 1:
//                    staNo = 123;
//                    crnNos = "1,2,3,4";
//                    break;
//                case 2:
//                    staNo = 121;
//                    crnNos = "1,2,3,4";
//                    break;
//                case 3:
//                    staNo = 119;
//                    crnNos = "1,2,3,4";
//                    break;
//                case 4:
//                    staNo = 117;
//                    crnNos = "1,2,3,4";
//                    break;
//                case 5:
//                    staNo = 115;
//                    crnNos = "5,6,7,8";
//                    break;
//                case 6:
//                    staNo = 113;
//                    crnNos = "5,6,7,8";
//                    break;
//                case 7:
//                    staNo = 111;
//                    crnNos = "5,6,7,8";
//                    break;
//                case 8:
//                    staNo = 109;
//                    crnNos = "5,6,7,8";
//                    break;
//                case 9:
//                    staNo = 106;
//                    crnNos = "9,10,11,12";
//                    break;
//                case 10:
//                    staNo = 105;
//                    crnNos = "9,10,11,12";
//                    break;
//                case 11:
//                    staNo = 103;
//                    crnNos = "9,10,11,12";
//                    break;
//                case 12:
//                    staNo = 101;
//                    crnNos = "9,10,11,12";
//                    break;
//            }
//            int maxCount = 2;
//            int storeCount = wrkMastService.getStoreCount(crnNo);
//
//            //分北中南三个区判断,每4台堆垛机1个区。除1号有3个暂存以外,只要有出库任务入库暂存数就只能为1个
//            //没有出库任务时,暂存数在devp表in_qty字段配置
////            int pakOutCunt = wrkMastService.getPakOutCount(crnNos);
////            if(pakOutCunt > 0){
////                maxCount = crnNo!= 1 ? 1 : 3;//1号3个入库暂存
////            } else {
//            BasDevp devp = basDevpService.selectById(staNo);
//            if(!Cools.isEmpty(devp)){
//                maxCount = devp.getInQty();
//            }
////            }
//
//            if(storeCount >= maxCount){
//                log.error("{}号堆垛机暂存数已满![storeCount:{},maxCount:{}]", crnNo, storeCount, maxCount);
//                return false;
//            }
//
//            if ("N".equals(crnp.getInEnable())) {
//                log.error("{}号堆垛机不可入", crnNo);
//                return false;
//            }
//
//            //1--8号堆垛机,二楼入库时判断是否有对应出库任务,如果有则堆垛机不可用
//            if (sourceStaNo > 299 && crnNo < 9){
//                WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>()
//                        .eq("crn_no",crnNo).last(" and source_sta_no > 300 and ( wrk_sts in (11,12) or (wrk_sts=14 and wrk_no in (select wrk_no from asr_bas_devp)))"));
//                if(!Cools.isEmpty(wrkMast)){
//                    log.error("{}号堆垛机存在出库任务,任务号{}", crnNo, wrkMast.getWrkNo());
//                    return false;
//                }
//            }
//        } else {
//            if ("N".equals(crnp.getOutEnable())) {
//                log.error("{}号堆垛机不可出", crnNo);
//                return false;
//            }
//        }
//
//        return true;
//    }
}
src/main/java/com/zy/asrs/service/impl/LocDetlServiceImpl.java
@@ -48,6 +48,11 @@
        return this.baseMapper.selectSameDetlToday(matnr, start, end);
    }
    @Override
    public List<String> getSameDetlToday2(String matnr, String batch, Integer start, Integer end) {
        return this.baseMapper.selectSameDetlToday2(matnr, batch, start, end);
    }
    @Override
    public Page<LocDetl> getStockStatis(Page<LocDetl> page) {
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -90,8 +90,8 @@
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(param.getDevpNo(), true);
        // 检索库位
        LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
        List<String> matnrs = param.getList().stream().map(FullStoreParam.MatCodeStore::getMatnr).distinct().collect(Collectors.toList());
        StartupDto dto = commonService.getLocNo(DEFAULT_ROW_NO_TYPE, 1, param.getDevpNo(), matnrs, locTypeDto, 0);
//        List<String> matnrs = param.getList().stream().map(FullStoreParam.MatCodeStore::getMatnr).distinct().collect(Collectors.toList());
        StartupDto dto = commonService.getLocNo(DEFAULT_ROW_NO_TYPE, 1, param.getDevpNo(), null, locTypeDto, 0);
        // 生成工作号
        int workNo = dto.getWorkNo();
        // 生成工作档
src/main/java/com/zy/common/service/CommonService.java
@@ -7,6 +7,7 @@
import com.core.common.Cools;
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.result.KeyValueVo;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.asrs.utils.VersionUtils;
@@ -92,14 +93,15 @@
     * @param whsType 类型 1:双深式货架
     * @param staDescId 路径工作类型
     * @param sourceStaNo 源站
     * @param matNos 商品编号集合
     * @param list 商品编号集合
     * @return locNo 检索到的库位号
     */
    @Transactional
    public StartupDto getLocNo(Integer whsType, Integer staDescId, Integer sourceStaNo, List<String> matNos, LocTypeDto locTypeDto, int times) {
    public StartupDto getLocNo(Integer whsType, Integer staDescId, Integer sourceStaNo, List<KeyValueVo> list, LocTypeDto locTypeDto, int times) {
        whsType = 1;
        StartupDto startupDto = new StartupDto();
        // 生成工作号
        int workNo = getWorkNo(0);
        RowLastno rowLastno = rowLastnoService.selectById(whsType);
        if (Cools.isEmpty(rowLastno)) {
            throw new CoolException("数据异常,请联系管理员");
@@ -111,29 +113,64 @@
        int eRow = rowLastno.geteRow();
        int crn_qty = rowLastno.getCrnQty();
        int rowCount = eRow - sRow + 1;
        // 目标堆垛机号
        int crnNo = 0;
        // 目标库位
        LocMast locMast = null;
        // 靠近摆放规则 --- 同天同规格物料
        if (!Cools.isEmpty(matNos)) {
            List<String> locNos = locDetlService.getSameDetlToday(matNos.get(0), sRow, eRow);
            for (String locNo : locNos) {
                if (Utils.isShallowLoc(slaveProperties, locNo)) {
                    continue;
        if (!Cools.isEmpty(list)) {
            boolean sameMatnr = true;
            String matnr = "";
            String batch = "";
            for (KeyValueVo vo : list) {
                if (Cools.isEmpty(matnr)) {
                    matnr = vo.getName();
                } else {
                    if (!matnr.equals(vo.getName())) {
                        sameMatnr = false;
                        break;
                    }
                }
                String shallowLocNo = Utils.getShallowLoc(slaveProperties, locNo);
                // 检测目标库位是否为空库位
                LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
                    if (VersionUtils.locMoveCheckLocType(shallowLoc, locTypeDto)) {
                        if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                            locMast = shallowLoc;
                            break;
                String val = String.valueOf(vo.getValue());
                if (Cools.isEmpty(batch)) {
                    batch = val;
                } else {
                    int year0 = Integer.parseInt(batch.substring(0, 2));
                    int month0 = Integer.parseInt(batch.substring(2, 4));
                    int year = Integer.parseInt(val.substring(0, 2));
                    int month = Integer.parseInt(val.substring(2, 4));
                    if (year <= year0) {
                        if (month < month0) {
                            batch = val;
                        }
                    }
                }
            }
            if (sameMatnr) {
                List<String> locNos = locDetlService.getSameDetlToday2(matnr, batch, sRow, eRow);
                for (String locNo : locNos) {
                    if (Utils.isShallowLoc(slaveProperties, locNo)) {
                        continue;
                    }
                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, locNo);
                    // 检测目标库位是否为空库位
                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                    if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
                        if (VersionUtils.locMoveCheckLocType(shallowLoc, locTypeDto)) {
                            // 因库位移转、需预留空库位
                            if (locMastService.checkEmptyCount(shallowLoc)) {
                                if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                                    locMast = shallowLoc;
                                    crnNo = locMast.getCrnNo();
                                    break;
                                }
                            }
                        }
                    }
                }
            }
        }
        // 靠近摆放规则 --- 空托
@@ -148,9 +185,13 @@
                    // 检测目标库位是否为空库位
                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                    if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
                        if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                            locMast = shallowLoc;
                            break;
                        // 因库位移转、需预留空库位
                        if (locMastService.checkEmptyCount(shallowLoc)) {
                            if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                                locMast = shallowLoc;
                                crnNo = locMast.getCrnNo();
                                break;
                            }
                        }
                    }
                }
@@ -158,10 +199,41 @@
        }
        // 如果没有相近物料,则按规则轮询货架
        if (null == locMast){
            curRow = getCurRow(curRow);
        if (null == locMast) {
            Shelves shelves = new Shelves(rowCount, crn_qty);
            for (int i = 0; i < shelves.group; i ++) {
                curRow = shelves.start(curRow);
                if (curRow < 0) {
                    throw new CoolException("检索库位失败,请联系管理员");
                }
                Integer crnNo1 = shelves.get(curRow);
                if (basCrnpService.checkSiteError(crnNo1, true)) {
                    crnNo = crnNo1;
                    break;
                }
            }
        }
        if (crnNo == 0) {
            throw new CoolException("没有可用的堆垛机");
        }
        // 获取目标站
        Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
                .eq("type_no", staDescId)
                .eq("stn_no", sourceStaNo)
                .eq("crn_no", crnNo);
        StaDesc staDesc = staDescService.selectOne(wrapper);
        if (Cools.isEmpty(staDesc)) {
            log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
            throw new CoolException("入库路径不存在");
        }
        BasDevp staNo = basDevpService.selectById(staDesc.getCrnStn());
        boolean sign = true;
        if (!staNo.getAutoing().equals("Y")) {
//            throw new CoolException("目标站"+staDesc.getCrnStn()+"不可用");
            log.error("目标站"+staDesc.getCrnStn()+"不可用");
            sign = false;
        }
        // 更新库位排号
        rowLastno.setCurrentRow(curRow);
        rowLastnoService.updateById(rowLastno);
@@ -169,22 +241,24 @@
        // 开始查找库位 ==============================>>
        // 1.当检索库排为浅库位排时,优先寻找当前库排的深库位排
        if (locMast == null) {
        if (locMast == null && sign) {
            if (Utils.isShallowLoc(slaveProperties, curRow)) {
                Integer deepRow = Utils.getDeepRow(slaveProperties, curRow);
                locMast = locMastService.queryFreeLocMast(deepRow, locTypeDto.getLocType1());
                // todo:luxiaotao 如果用浅排找到的深库位,那么则需要判断这个深库位对应的浅库位是否有货(F、X、D)
                // 因库位移转、需预留空库位
                if (!locMastService.checkEmptyCount(locMast)) {
                if (locMast !=null && !locMastService.checkEmptyCount(locMast)) {
                    locMast = null;
                }
            }
            if (Cools.isEmpty(locMast)) {
                locMast = locMastService.queryFreeLocMast(curRow, locTypeDto.getLocType1());
                // 因库位移转、需预留空库位
                if (!locMastService.checkEmptyCount(locMast)) {
                    locMast = null;
                }
                // 目标库位 ===>> 浅库位, 则校验其深库位是否为 F D X
                if (null != locMast && Utils.isShallowLoc(slaveProperties, locMast.getLocNo())) {
                    LocMast deepLoc = locMastService.selectById(Utils.getDeepLoc(slaveProperties, locMast.getLocNo()));
@@ -201,51 +275,27 @@
                }
            }
        }
        Integer crnNo = 0;
        BasDevp staNo =null;
        boolean sign=false;
        if (!Cools.isEmpty(locMast)){
            try{
                crnNo = locMast.getCrnNo();
                // 获取目标站
                Wrapper<StaDesc> wrapper = new EntityWrapper<StaDesc>()
                        .eq("type_no", staDescId)
                        .eq("stn_no", sourceStaNo)
                        .eq("crn_no", crnNo);
                StaDesc staDesc = staDescService.selectOne(wrapper);
                if (Cools.isEmpty(staDesc)) {
                    log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
                    throw new CoolException("入库路径不存在");
                }
                staNo = basDevpService.selectById(staDesc.getCrnStn());
                if (!staNo.getAutoing().equals("Y")) {
                    throw new CoolException("目标站"+staDesc.getCrnStn()+"不可用");
                }
            }catch (Exception e){
                sign=true;
            }
        }
        // 2.库位当前所属尺寸无空库位时,调整尺寸参数,向上兼容检索库位
        if (Cools.isEmpty(locMast) || sign) {
        if (Cools.isEmpty(locMast)) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            if (times < rowCount) {
                times = times + 1;
                return getLocNo(1, staDescId, sourceStaNo, matNos, locTypeDto, times);
                return getLocNo(1, staDescId, sourceStaNo, list, locTypeDto, times);
            } else {
                times = 0;
            }
            // 轻货物找轻库位为空时,可以去找重库位仓
            if (locTypeDto.getLocType1() == 1) {
                locTypeDto.setLocType1((short) 2);
                return getLocNo(1, staDescId, sourceStaNo, matNos, locTypeDto, times);
                return getLocNo(1, staDescId, sourceStaNo, list, locTypeDto, times);
            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
        }
        String locNo = locMast.getLocNo();
        // 生成工作号
        int workNo = getWorkNo(0);
        // 返回dto
        startupDto.setWorkNo(workNo);
        startupDto.setCrnNo(crnNo);
@@ -254,6 +304,7 @@
        startupDto.setLocNo(locNo);
        return startupDto;
    }
    public static String zerofill(String msg, Integer count) {
@@ -274,7 +325,7 @@
     * 根据入库站获取库位排号分配
     */
    private Integer getCurRow(Integer curRow) {
        if (Utils.isDeepLocLeft(slaveProperties,curRow)){
        if (Utils.isDeepLocLeft(slaveProperties,curRow)){ //判断是否为左深库位
            curRow=curRow+3;
        }else if (Utils.isDeepLocLeft(slaveProperties,curRow-1)){
            curRow=curRow+1;
src/main/java/com/zy/common/web/WcsController.java
@@ -7,6 +7,7 @@
import com.core.exception.CoolException;
import com.zy.asrs.entity.*;
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.result.KeyValueVo;
import com.zy.asrs.service.*;
import com.zy.common.CodeRes;
import com.zy.common.model.LocTypeDto;
@@ -159,9 +160,11 @@
    public StartupDto startupFullPutStore(Integer devpNo, String barcode, LocTypeDto locTypeDto, List<WaitPakin> waitPakins) {
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        // 检索库位
        List<String> matNos = waitPakins.stream().map(WaitPakin::getMatnr).distinct().collect(Collectors.toList());
        StartupDto dto = commonService.getLocNo(1, 1, devpNo, matNos, locTypeDto,0);
        List<KeyValueVo> list = waitPakins.stream().map(item-> new KeyValueVo(item.getMatnr(), item.getBatch())).distinct().collect(Collectors.toList());
//        List<String> matNos = waitPakins.stream().map(WaitPakin::getMatnr).distinct().collect(Collectors.toList());
        StartupDto dto = commonService.getLocNo(1, 1, devpNo, list, locTypeDto,0);
        int workNo = dto.getWorkNo();
        Date now = new Date();
        // 生成工作档
src/main/resources/application.yml
@@ -46,14 +46,13 @@
  # 双深
  doubleDeep: true
  # 双深库位排号
#  doubleLocs: 1,4,11,14,21,24
  doubleLocs: 1,4,5,8,9,12
  doubleLocs: 1,4,5,8,9,12,13,16,17,20,21,24
  # 一个堆垛机负责的货架排数
  groupCount: 4
  # 左深库位排号
  doubleLocsLeft : 1,5,9
  doubleLocsLeft : 1,5,9,13,17,21
  # 右深库位排号
  doubleLocsRight : 4,8,12
  doubleLocsRight : 4,8,12,16,20,24
comb: