Prechádzať zdrojové kódy

库位分配重新编写

xiaoddyy123 3 rokov pred
rodič
commit
09b86dc005

+ 9 - 2
ruoyi-admin/src/test/java/com/ruoyi/admin/test/base/WarehouseTest.java

@@ -159,9 +159,16 @@ public class WarehouseTest {
         }
         List<OutWarehouseDTO> outWarehouseDTOs = new ArrayList<>();
         OutWarehouseDTO sku1 = new OutWarehouseDTO();
-        sku1.setSku("");
+        sku1.setSku("test401");
+        sku1.setQty(150d);
+        outWarehouseDTOs.add(sku1);
+        OutWarehouseDTO sku2 = new OutWarehouseDTO();
+        sku2.setSku("test402");
+        sku2.setQty(50d);
+        outWarehouseDTOs.add(sku2);
         AsnSoStrategy asnSoStrategy = asnSoStrategyMapper.selectAsnSoStrategy();
         Long token = 100L;
-        locationAllocationStrategy.filterLockInv(locationIdList, outWarehouseDTOs, asnSoStrategy, token);
+        List<BaseLocationInfo> locationInfoList = locationAllocationStrategy.filterLockInv(locationIdList, outWarehouseDTOs, asnSoStrategy, token);
+        System.out.println(JSON.toJSONString(locationInfoList));
     }
 }

+ 1 - 1
warewms-ams/src/main/java/com/ruoyi/ams/business/BusinessServiceImpl.java

@@ -101,7 +101,7 @@ public class BusinessServiceImpl implements IBusinessService {
                     if (qty == null || qty < agvCall.getQty()) {
                         throw new ServiceException("所需库存不够");
                     }
-                    // locationFrom = this.zoneLocationAllocation(locationFromList, "locationFrom", "SO", asnSoStrategy, agvCall, token);
+                    //TODO 改成新分配方法
                     while (trySize > 0) {
                         BaseLocationInfo soLocationFrom;
                         if (locationFromList != null && locationFromList.size() > 0) {

+ 4 - 0
warewms-ams/src/main/java/com/ruoyi/ams/business/domain/LocationSortDTO.java

@@ -8,7 +8,11 @@ package com.ruoyi.ams.business.domain;
  */
 public class LocationSortDTO {
 
+    /**
+     * 列号
+     */
     private String colNo;
+    //有效期
     private String lotatt04;
 
     public LocationSortDTO() {

+ 230 - 85
warewms-ams/src/main/java/com/ruoyi/ams/config/service/LocationAllocationStrategy.java

@@ -10,15 +10,18 @@ import com.ruoyi.base.domain.BaseLocationInfo;
 import com.ruoyi.base.domain.vo.BaseLocationLotattListVO;
 import com.ruoyi.base.domain.vo.BaseLocationLotattVO;
 import com.ruoyi.base.domain.vo.LotattInfo;
+import com.ruoyi.base.mapper.BaseLocationInfoMapper;
 import com.ruoyi.base.service.IBaseLocationInfoService;
 import com.ruoyi.common.core.redis.RedisCache;
 import com.ruoyi.common.core.redis.RedisKey;
+import com.ruoyi.common.exception.ServiceException;
 import com.ruoyi.common.utils.StringUtils;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.*;
 
@@ -35,6 +38,8 @@ public class LocationAllocationStrategy {
     private RedisCache redisCache;
     @Autowired
     private IBaseLocationInfoService baseLocationInfoService;
+    @Autowired
+    private BaseLocationInfoMapper baseLocationInfoMapper;
 
     /**
      * 过滤锁定库位
@@ -342,19 +347,6 @@ public class LocationAllocationStrategy {
         return currentLocation;
     }
 
-    private Double checkOutedInvQty(OutWarehouseDTO ow, Map<String, List<LotattInfo>> lockInvList) {
-        Double qty = 0d;
-        for (Map.Entry<String, List<LotattInfo>> entry : lockInvList.entrySet()) {
-            List<LotattInfo> list = entry.getValue();
-            for (LotattInfo info : list) {
-                if (info.getSku().equals(ow.getSku())) {
-                    qty += info.getQty();
-                }
-            }
-        }
-        return qty;
-    }
-
     /**
      * 过滤库存信息
      *
@@ -364,126 +356,279 @@ public class LocationAllocationStrategy {
      * @param token            唯一token用来解锁加锁
      * @return
      */
+    @Transactional
     public List<BaseLocationInfo> filterLockInv(List<Long> locationIdList, List<OutWarehouseDTO> outWarehouseDTOs, AsnSoStrategy asnSoStrategy, Long token) {
         //取出范围内所有的库存
         List<BaseLocationLotattListVO> locationLotattVOList = baseLocationInfoService.selectSortedLocatinListByZoneId(locationIdList, 1L, null, null);
         List<BaseLocationInfo> result = new ArrayList<>(); //返回的结果
-        Map<String, List<LotattInfo>> lockInv = new HashMap<>(); //已锁定的库存列表(key:列名,value:库位库存)
+        Map<String, List<BaseLocationLotattListVO>> lockInv = new HashMap<>(); //已锁定的库存列表(key:列名,value:库位库存)
         //将同一列的库位排序好====================================================>
         LinkedHashMap<String, Boolean> taskingFlag = new LinkedHashMap<>(); //任务中的列
         LinkedHashMap<String, List<BaseLocationLotattListVO>> mapFloor = new LinkedHashMap<>(); //同一列的库存(key:列名,value:库位库存)地堆
-        LinkedHashMap<String, List<BaseLocationLotattListVO>> shelvesFloor = new LinkedHashMap<>(); //同一列的库存(key:列名,value:库位库存)货架
-        LinkedHashMap<String, String> skuTagMap = new LinkedHashMap<>(); //每列存放的物料分类(key:列名,value:sku)
-        List<LocationSortDTO> list = new ArrayList<>();//全部
-        List<LocationSortDTO> sameLotattList = new ArrayList<>(); //同批号
+        LinkedHashMap<String, List<BaseLocationLotattListVO>> mapShelves = new LinkedHashMap<>(); //同一列的库存(key:列名,value:库位库存)货架
+        LinkedHashMap<String, String> skuTagMapFloor = new LinkedHashMap<>(); //每列存放的物料分类(key:列名,value:sku)
+        LinkedHashMap<String, String> skuTagMapShelves = new LinkedHashMap<>(); //每列存放的物料分类(key:列名,value:sku)
         for (BaseLocationLotattListVO info : locationLotattVOList) {
             List<BaseLocationLotattListVO> infoList;
-            if (info.getLocationType().equals("1")) {
-                if (shelvesFloor.containsKey(info.getColNo())) {
-                    infoList = shelvesFloor.get(info.getColNo());
+            if (info.getLocationType().equals("1")) { //货架
+                if (mapShelves.containsKey(info.getColNo())) {
+                    infoList = mapShelves.get(info.getColNo());
                 } else {
                     infoList = new ArrayList<>();
                 }
-            } else {
+            } else { //地堆
                 if (mapFloor.containsKey(info.getColNo())) {
                     infoList = mapFloor.get(info.getColNo());
                 } else {
                     infoList = new ArrayList<>();
                 }
             }
-
+            //将查询出来的baslocation按照列存放到map中
             if (info.getColNo() != null) {
-                if (skuTagMap.containsKey(info.getColNo())) {
-                    String tmp = skuTagMap.get(info.getColNo());
-                    StringBuffer sb = new StringBuffer(tmp);
-                    List<LotattInfo> lotattInfoList = info.getLotattInfoList();
-                    if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
-                        for (LotattInfo lot : lotattInfoList) {
-                            if (lot.getSku() == null || tmp.contains(lot.getSku())) {
-                                continue;
+                if (info.getLocationType().equals("1")) { //货架
+                    //重复代码不用看来逻辑一样的存放的map不一样
+                    if (skuTagMapShelves.containsKey(info.getColNo())) {
+                        String tmp = skuTagMapShelves.get(info.getColNo());
+                        StringBuffer sb = new StringBuffer(tmp);
+                        List<LotattInfo> lotattInfoList = info.getLotattInfoList();
+                        if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
+                            for (LotattInfo lot : lotattInfoList) {
+                                if (lot.getSku() == null || tmp.contains(lot.getSku())) {
+                                    continue;
+                                }
+                                sb.append(",");
+                                sb.append(lot.getSku());
+                            }
+                            if (sb.length() > 0) {
+                                skuTagMapShelves.put(info.getColNo(), sb.toString());
                             }
-                            sb.append(",");
-                            sb.append(lot.getSku());
                         }
-                        if (sb.length() > 0) {
-                            skuTagMap.put(info.getColNo(), sb.toString());
+                    } else {
+                        StringBuffer sb = new StringBuffer("");
+                        List<LotattInfo> lotattInfoList = info.getLotattInfoList();
+                        if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
+                            for (LotattInfo lot : lotattInfoList) {
+                                if (lot.getSku() == null || sb.toString().contains(lot.getSku())) {
+                                    continue;
+                                }
+                                sb.append(",");
+                                sb.append(lot.getSku());
+                            }
+                            if (sb.length() > 0) {
+                                skuTagMapShelves.put(info.getColNo(), sb.toString());
+                            }
                         }
                     }
                 } else {
-                    StringBuffer sb = new StringBuffer("");
-                    List<LotattInfo> lotattInfoList = info.getLotattInfoList();
-                    if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
-                        for (LotattInfo lot : lotattInfoList) {
-                            if (lot.getSku() == null || sb.toString().contains(lot.getSku())) {
-                                continue;
+                    if (skuTagMapFloor.containsKey(info.getColNo())) {
+                        String tmp = skuTagMapFloor.get(info.getColNo());
+                        StringBuffer sb = new StringBuffer(tmp);
+                        List<LotattInfo> lotattInfoList = info.getLotattInfoList();
+                        if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
+                            for (LotattInfo lot : lotattInfoList) {
+                                if (lot.getSku() == null || tmp.contains(lot.getSku())) {
+                                    continue;
+                                }
+                                sb.append(",");
+                                sb.append(lot.getSku());
+                            }
+                            if (sb.length() > 0) {
+                                skuTagMapFloor.put(info.getColNo(), sb.toString());
                             }
-                            sb.append(",");
-                            sb.append(lot.getSku());
                         }
-                        if (sb.length() > 0) {
-                            skuTagMap.put(info.getColNo(), sb.toString());
+                    } else {
+                        StringBuffer sb = new StringBuffer("");
+                        List<LotattInfo> lotattInfoList = info.getLotattInfoList();
+                        if (info.getLotattInfoList() != null && info.getLotattInfoList().size() > 0) {
+                            for (LotattInfo lot : lotattInfoList) {
+                                if (lot.getSku() == null || sb.toString().contains(lot.getSku())) {
+                                    continue;
+                                }
+                                sb.append(",");
+                                sb.append(lot.getSku());
+                            }
+                            if (sb.length() > 0) {
+                                skuTagMapFloor.put(info.getColNo(), sb.toString());
+                            }
                         }
                     }
                 }
             }
-
-            if (info.getStockStatus().equals("10") || redisCache.checkIsLock(RedisKey.LOCK_LOCATION + info.getId())) {
-                taskingFlag.put(info.getColNo(), true);
-                lockInv.put(info.getId().toString(), info.getLotattInfoList());
-                //如果在任务中跳过该库存
-            } else {
-                if (taskingFlag.get(info.getColNo()) == null || taskingFlag.get(info.getColNo()).booleanValue() == false) {
-                    taskingFlag.put(info.getColNo(), false);
-                }
-            }
             infoList.add(info);
-            if (info.getLocationType().equals("1")) {
-                mapFloor.put(info.getColNo(), infoList);
+            if (info.getLocationType().equals("1")) { //把货架和地堆存放到不同的map方便查找
+                mapShelves.put(info.getColNo(), infoList);
             } else {
-                shelvesFloor.put(info.getColNo(), infoList);
-            }
-
-            String period = "";
-            if (asnSoStrategy.getSoPeriodFlag().equals("optimization") || asnSoStrategy.getSoPeriodFlag().equals("force")) {
-                info.getLotattInfoList().get(0).initLotatt();
-                period = info.getLotattInfoList().get(0).getAttMap().get(asnSoStrategy.getSoPeriodLotatt());
-            }
-            LocationSortDTO sortDTO = new LocationSortDTO(info.getColNo(), period);
-            list.add(sortDTO);
-
-            if (asnSoStrategy.getSoSameLotatt1Flag().equals("optimization")) {
-                String lotattValue = redisCache.getCacheObject(asnSoStrategy.getAsnSameLotatt1Value());
-                if (!StringUtils.isEmpty(lotattValue)) {
-                    if (!StringUtils.isEmpty(info.getLotattInfoList().get(0).getAttMap().get(asnSoStrategy.getSoSameLotatt1Value())) && info.getLotattInfoList().get(0).getAttMap().get(asnSoStrategy.getSoSameLotatt1Value()).equals(lotattValue)) {
-                        sameLotattList.add(sortDTO);
-                    }
-                }
+                mapFloor.put(info.getColNo(), infoList);
             }
         }
-        //=========================================================>
-        log.info("检索的库存范围:" + JSON.toJSONString(locationLotattVOList));
+        //===========================库存数据排序完成==============================>
+
+        log.info("检索的库存范围====================================================>");
+        log.info("地堆:" + JSON.toJSONString(mapFloor));
+        log.info("货架:" + JSON.toJSONString(mapShelves));
         log.info("列的任务状态:" + JSON.toJSONString(taskingFlag));
-        log.info("每列存放的物料分类:" + JSON.toJSONString(skuTagMap));
+        log.info("货架每列存放的物料分类:" + JSON.toJSONString(skuTagMapShelves));
+        log.info("地堆每列存放的物料分类:" + JSON.toJSONString(skuTagMapFloor));
 
         for (OutWarehouseDTO ow : outWarehouseDTOs) {
-            //先已锁定的库存中查询是否有可以扣减的库存
+            //先查询已锁定的库存中查询是否有可以扣减的库存,如果已经扣除了那么久不用继续分配
             Double qty = checkOutedInvQty(ow, lockInv);
             if (qty >= ow.getQty()) {
                 continue;
             }
             //过滤出每列可以用的库位并进行分配
-            BaseLocationInfo currentLocation = null;
-            BaseLocationLotattListVO currentLocationLotatt = null;
+            BaseLocationInfo currentLocation;
+            boolean isEnd = false;
             //地堆
-            for (Map.Entry<String, List<BaseLocationLotattListVO>> invList : mapFloor.entrySet()) {
-                
+            List<String> colNosFloor = getColNoBySku(skuTagMapFloor, ow.getSku());
+            for (String s : colNosFloor) {
+                if (isEnd) {
+                    break;
+                }
+                List<BaseLocationLotattListVO> bls = mapFloor.get(s);
+                for (BaseLocationLotattListVO v : bls) {
+                    if (v.getIsEmpty().equals("N") && v.getStockStatus().equals("00")) {
+                        if (redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + v.getId(), v.getId().toString(), token)) {
+                            //判断是否有阻挡
+                            currentLocation = new BaseLocationInfo();
+                            BeanUtils.copyProperties(v, currentLocation);
+                            if (checkCanOut(currentLocation)) {
+                                result.add(currentLocation);
+                                lockInv = addLockInv(lockInv, v.getColNo(), v);
+                                Double currentQty = checkOutedInvQty(ow, lockInv);
+                                if (currentQty >= ow.getQty()) {
+                                    break;
+                                }
+                            } else {
+                                //如果不能出去去除锁定
+                                redisCache.deleteObject(RedisKey.LOCK_LOCATION + v.getId());
+                            }
+                        }
+                    }
+                }
             }
             //货架
-            for (Map.Entry<String, List<BaseLocationLotattListVO>> invList : shelvesFloor.entrySet()) {
+            isEnd = false;
+            List<String> colNosShelves = getColNoBySku(skuTagMapShelves, ow.getSku());
+            for (String s : colNosShelves) {
+                if (isEnd) {
+                    break;
+                }
+                List<BaseLocationLotattListVO> bls = mapShelves.get(s);
+                for (BaseLocationLotattListVO v : bls) {
+                    if (v.getIsEmpty().equals("N") && v.getStockStatus().equals("00")) {
+                        if (redisCache.lockCacheObject(RedisKey.LOCK_LOCATION + v.getId(), v.getId().toString(), token)) {
+                            //判断是否有阻挡
+                            currentLocation = new BaseLocationInfo();
+                            BeanUtils.copyProperties(v, currentLocation);
+                            result.add(currentLocation);
+                            lockInv = addLockInv(lockInv, v.getColNo(), v);
+                            Double currentQty = checkOutedInvQty(ow, lockInv);
+                            if (currentQty >= ow.getQty()) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 添加已锁定库存
+     *
+     * @param lockInv 锁定库存列
+     * @param colNo   列
+     * @param vo      库存对象
+     * @return
+     */
+    public Map<String, List<BaseLocationLotattListVO>> addLockInv(Map<String, List<BaseLocationLotattListVO>> lockInv, String colNo, BaseLocationLotattListVO vo) {
+        List<BaseLocationLotattListVO> result;
+        if (lockInv.containsKey(colNo)) {
+            result = lockInv.get(colNo);
+        } else {
+            result = new ArrayList<>();
+        }
+        result.add(vo);
+        lockInv.put(colNo, result);
+        return lockInv;
+    }
+
+    /**
+     * 检索出物料所属的列号
+     *
+     * @param skuTagMap
+     * @return
+     */
+    private List<String> getColNoBySku(LinkedHashMap<String, String> skuTagMap, String sku) {
+        List<String> colNos = new ArrayList<>();
+        for (Map.Entry<String, String> skuTag : skuTagMap.entrySet()) {
+            if (!colNos.contains(skuTag.getKey())) {
+                if (skuTag.getValue().indexOf(sku) != -1) {
+                    colNos.add(skuTag.getKey());
+                }
+            } else {
+                continue;
+            }
+        }
+        return colNos;
+    }
 
+    /**
+     * 检查需要出库的库存是否满足
+     *
+     * @param ow
+     * @param lockInvList
+     * @return
+     */
+    private Double checkOutedInvQty(OutWarehouseDTO ow, Map<String, List<BaseLocationLotattListVO>> lockInvList) {
+        Double qty = 0d;
+        for (Map.Entry<String, List<BaseLocationLotattListVO>> entry : lockInvList.entrySet()) {
+            List<BaseLocationLotattListVO> list = entry.getValue();
+            for (BaseLocationLotattListVO bv : list) {
+                List<LotattInfo> lotattInfoList = bv.getLotattInfoList();
+                for (LotattInfo info : lotattInfoList) {
+                    if (info.getSku().equals(ow.getSku())) {
+                        qty += info.getQty();
+                    }
+                }
             }
+
         }
+        return qty;
+    }
 
-        return result;
+    /**
+     * 检查同列库位是否有阻挡
+     *
+     * @param b
+     * @return
+     */
+    private boolean checkCanOut(BaseLocationInfo b) {
+        if (b.getLocationType().equals("1")) {
+            return true;
+        }
+        //查询同列的排序库位
+        List<BaseLocationInfo> locationInfoList = baseLocationInfoMapper.selectLocationByColNo(b.getColNo());
+        for (BaseLocationInfo bef : locationInfoList) {
+            if (bef.getId().equals(b.getId())) {
+                return true;
+            }
+            if (bef.getStockStatus().equals("00") && bef.getIsEmpty().equals("Y") && redisCache.checkIsLock(bef.getId().toString()) == false) {
+                return true;
+            } else if (bef.getStockStatus().equals("00") && bef.getIsEmpty().equals("N")) {
+                //判断是否在任务中
+                int count = baseLocationInfoMapper.selectLocationIsTasking(bef.getLocationType(), bef.getId());
+                if (count > 0 && redisCache.checkIsLock(bef.getId().toString())) {
+                    return true;
+                } else {
+                    return false;
+                }
+            } else {
+                return false;
+            }
+        }
+        return true;
     }
 }

+ 4 - 3
warewms-base/src/main/java/com/ruoyi/base/mapper/BaseLocationInfoMapper.java

@@ -91,13 +91,14 @@ public interface BaseLocationInfoMapper {
 
     /**
      * 根据zoneId和批次属性查询库位信息带批次属性
+     *
      * @param zoneId
      * @param lotatt
      * @return
      */
-    List<BaseLocationLotattVO> selectSortedLocationLotattListByZoneIdList(@Param("zoneId") List<Long> zoneId,@Param("warehouseId")Long warehouseId,@Param("lotatt") Map<String, String> lotatt);
+    List<BaseLocationLotattVO> selectSortedLocationLotattListByZoneIdList(@Param("zoneId") List<Long> zoneId, @Param("warehouseId") Long warehouseId, @Param("lotatt") Map<String, String> lotatt);
 
-    List<BaseLocationLotattVO> selectSortedLocationLotattListByLocationIdList(@Param("locationId") List<Long> locationId,@Param("warehouseId")Long warehouseId,@Param("lotatt") Map<String, String> lotatt,@Param("sku") String sku);
+    List<BaseLocationLotattVO> selectSortedLocationLotattListByLocationIdList(@Param("locationId") List<Long> locationId, @Param("warehouseId") Long warehouseId, @Param("lotatt") Map<String, String> lotatt, @Param("sku") String sku);
 
     LotattVO selectInvLotattById(@Param("id") Long id);
 
@@ -165,5 +166,5 @@ public interface BaseLocationInfoMapper {
      */
     List<BaseLocationInfo> selectLocationByColNos(@Param("colNos") List<String> colNos);
 
-
+    int selectLocationIsTasking(@Param("locationType") String locationType, @Param("locationId") Long locationId);
 }

+ 10 - 1
warewms-base/src/main/resources/mapper/base/BaseLocationInfoMapper.xml

@@ -371,7 +371,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
     <select id="selectLocationByColNo" parameterType="string" resultMap="BaseLocationInfoResult">
-        select * from base_location_info where col_no = #{colNo}
+        select * from base_location_info where col_no = #{colNo} order by lpad(row_no, 11, '0'),row_index,lpad(shift_no, 11, '0'),shift_index,lpad(col_no, 11, '0'),col_index desc
     </select>
 
     <select id="selectLocationByColNos" parameterType="java.util.List" resultMap="BaseLocationInfoResult">
@@ -379,6 +379,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         where col_no in
         <foreach item="item" collection="colNos" separator="," open="(" close=")" index="">  #{item, jdbcType=VARCHAR}
         </foreach>
+        order by lpad(row_no, 11, '0'),row_index,lpad(shift_no, 11, '0'),shift_index,lpad(col_no, 11, '0'),col_index desc
+    </select>
+
+    <select id="selectLocationIsTasking" resultType="int">
+        select count(*) con from wcs_task
+        where 1 = 1 and state in (9,0,1)
+        <if test="locationType = 'from'"> and location_from = #{locationId}</if>
+        <if test="locationType = 'to'"> and location_to = #{locationId}</if>
+        order by lpad(row_no, 11, '0'),row_index,lpad(shift_no, 11, '0'),shift_index,lpad(col_no, 11, '0'),col_index desc
     </select>
 
     <select id="selectSortedLocationLotattListByZoneIdList" parameterType="BaseLocationInfo" resultMap="BaseLocationInfoLotattResult">