فهرست منبع

入库库位策略分配

andy 3 سال پیش
والد
کامیت
af4df3112d

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

@@ -2,9 +2,14 @@ package com.ruoyi.admin.test.base;
 
 import com.alibaba.fastjson.JSON;
 import com.ruoyi.RuoYiApplication;
+import com.ruoyi.ams.config.domain.dto.InWarehouseDTO;
+import com.ruoyi.ams.config.service.IBusinessService;
+import com.ruoyi.ams.config.service.LocationAllocationStrategy;
+import com.ruoyi.base.domain.BaseLocationInfo;
 import com.ruoyi.base.domain.BaseWarehouse;
 import com.ruoyi.base.service.IBaseWarehouseService;
 import com.ruoyi.framework.web.domain.server.Sys;
+import io.swagger.models.auth.In;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -24,10 +29,31 @@ public class WarehouseTest {
 
     @Autowired
     private IBaseWarehouseService baseWarehouseService;
+    @Autowired
+    private LocationAllocationStrategy locationAllocationStrategy;
+    @Autowired
+    private IBusinessService businessService;
 
     @Test
     public void test() {
-       List<BaseWarehouse> warehouseList =  baseWarehouseService.selectBaseWarehouseList(null);
-       System.out.println(JSON.toJSONString(warehouseList));
+        List<BaseWarehouse> warehouseList = baseWarehouseService.selectBaseWarehouseList(null);
+        System.out.println(JSON.toJSONString(warehouseList));
+    }
+
+    @Test
+    public void test1() {
+        InWarehouseDTO inWarehouseDTO = new InWarehouseDTO();
+        inWarehouseDTO.setSku("A");
+        inWarehouseDTO.setWarehouseId(1L);
+        BaseLocationInfo locationInfo = businessService.inLocationAllocation(inWarehouseDTO);
+        if (locationInfo != null) {
+            System.out.println("-------------------");
+            System.out.println(locationInfo.getId());
+        }
+    }
+
+    @Test
+    public void test2() {
+
     }
 }

+ 47 - 0
warewms-ams/src/main/java/com/ruoyi/ams/config/domain/dto/OutWarehouseDTO.java

@@ -1,10 +1,14 @@
 package com.ruoyi.ams.config.domain.dto;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * 出库业务模型
  */
 public class OutWarehouseDTO {
     //出库可以使用物料也可以根据物料类型匹配
+    private Double qty;
     private String sku;
     private String skuType;
     private Double weight;
@@ -13,6 +17,33 @@ public class OutWarehouseDTO {
     private String locationTo;
     private LotattDTO lotattDTO;
 
+    private Map<String, String> attMap;
+
+    public void initLotatt() {
+        attMap = new HashMap<>();
+        if (lotattDTO == null) {
+            lotattDTO = new LotattDTO();
+        }
+        this.attMap.put("lotatt01", lotattDTO.getLotatt01());
+        this.attMap.put("lotatt02", lotattDTO.getLotatt02());
+        this.attMap.put("lotatt03", lotattDTO.getLotatt03());
+        this.attMap.put("lotatt04", lotattDTO.getLotatt04());
+        this.attMap.put("lotatt05", lotattDTO.getLotatt05());
+        this.attMap.put("lotatt06", lotattDTO.getLotatt06());
+        this.attMap.put("lotatt07", lotattDTO.getLotatt07());
+        this.attMap.put("lotatt08", lotattDTO.getLotatt08());
+        this.attMap.put("lotatt09", lotattDTO.getLotatt09());
+        this.attMap.put("lotatt10", lotattDTO.getLotatt10());
+        this.attMap.put("lotatt11", lotattDTO.getLotatt11());
+        this.attMap.put("lotatt12", lotattDTO.getLotatt12());
+        this.attMap.put("lotatt13", lotattDTO.getLotatt13());
+        this.attMap.put("lotatt14", lotattDTO.getLotatt14());
+        this.attMap.put("lotatt15", lotattDTO.getLotatt15());
+        this.attMap.put("lotatt16", lotattDTO.getLotatt16());
+        this.attMap.put("lotatt17", lotattDTO.getLotatt17());
+        this.attMap.put("lotatt18", lotattDTO.getLotatt18());
+    }
+
     public String getSku() {
         return sku;
     }
@@ -68,4 +99,20 @@ public class OutWarehouseDTO {
     public void setLotattDTO(LotattDTO lotattDTO) {
         this.lotattDTO = lotattDTO;
     }
+
+    public Double getQty() {
+        return qty;
+    }
+
+    public void setQty(Double qty) {
+        this.qty = qty;
+    }
+
+    public Map<String, String> getAttMap() {
+        return attMap;
+    }
+
+    public void setAttMap(Map<String, String> attMap) {
+        this.attMap = attMap;
+    }
 }

+ 31 - 20
warewms-ams/src/main/java/com/ruoyi/ams/config/mapper/LocationPriorityHeaderMapper.java

@@ -7,7 +7,7 @@ import com.ruoyi.ams.config.domain.vo.LocationPriorityDetailsVO;
 import com.ruoyi.ams.config.domain.vo.LocationPriorityHeaderVO;
 
 /**
- * 路径规划Mapper接口
+ * 出入库策略Mapper接口
  * 
  * @author andy
  * @date 2022-02-25
@@ -15,49 +15,54 @@ import com.ruoyi.ams.config.domain.vo.LocationPriorityHeaderVO;
 public interface LocationPriorityHeaderMapper 
 {
     /**
-     * 查询路径规划
+     * 查询出入库策略
      * 
-     * @param id 路径规划主键
-     * @return 路径规划
+     * @param id 出入库策略主键
+     * @return 出入库策略
      */
     LocationPriorityHeaderVO selectLocationPriorityHeaderById(Long id);
 
     /**
-     * 查询路径规划列表
+     * 查询出入库策略列表
      * 
-     * @param locationPriorityHeader 路径规划
-     * @return 路径规划集合
+     * @param locationPriorityHeader 出入库策略
+     * @return 出入库策略集合
      */
      List<LocationPriorityHeaderVO> selectLocationPriorityHeaderList(LocationPriorityHeader locationPriorityHeader);
 
+    /**
+     * 查询
+     * @param id
+     * @return
+     */
      List<LocationPriorityDetailsVO> selectLocationPriorityDetailsList(Long id);
 
     /**
-     * 新增路径规划
+     * 新增出入库策略
      * 
-     * @param locationPriorityHeader 路径规划
+     * @param locationPriorityHeader 出入库策略
      * @return 结果
      */
      int insertLocationPriorityHeader(LocationPriorityHeader locationPriorityHeader);
 
     /**
-     * 修改路径规划
+     * 修改出入库策略
      * 
-     * @param locationPriorityHeader 路径规划
+     * @param locationPriorityHeader 出入库策略
      * @return 结果
      */
      int updateLocationPriorityHeader(LocationPriorityHeader locationPriorityHeader);
 
     /**
-     * 删除路径规划
+     * 删除出入库策略
      * 
-     * @param id 路径规划主键
+     * @param id 出入库策略主键
      * @return 结果
      */
      int deleteLocationPriorityHeaderById(Long id);
 
     /**
-     * 批量删除路径规划
+     * 批量删除出入库策略
      * 
      * @param ids 需要删除的数据主键集合
      * @return 结果
@@ -65,7 +70,7 @@ public interface LocationPriorityHeaderMapper
      int deleteLocationPriorityHeaderByIds(Long[] ids);
 
     /**
-     * 批量删除路径规划
+     * 批量删除出入库策略
      * 
      * @param ids 需要删除的数据主键集合
      * @return 结果
@@ -73,19 +78,25 @@ public interface LocationPriorityHeaderMapper
      int deleteLocationPriorityDetailsByHeaderIds(Long[] ids);
     
     /**
-     * 批量新增路径规划
+     * 批量新增出入库策略
      * 
-     * @param locationPriorityDetailsList 路径规划列表
+     * @param locationPriorityDetailsList 出入库策略列表
      * @return 结果
      */
      int batchLocationPriorityDetails(List<LocationPriorityDetails> locationPriorityDetailsList);
-    
 
     /**
-     * 通过路径规划主键删除路径规划信息
+     * 通过出入库策略主键删除出入库策略信息
      * 
-     * @param id 路径规划ID
+     * @param id 出入库策略ID
      * @return 结果
      */
      int deleteLocationPriorityDetailsByHeaderId(Long id);
+
+    /**
+     * 根据sku匹配可以存放的区域
+     * @param sku
+     * @return
+     */
+     List<Long> selectZoneIdListBySku(String sku);
 }

+ 79 - 10
warewms-ams/src/main/java/com/ruoyi/ams/config/service/LocationAllocationStrategy.java

@@ -1,11 +1,13 @@
 package com.ruoyi.ams.config.service;
 
+import com.ruoyi.ams.config.domain.dto.InWarehouseDTO;
 import com.ruoyi.ams.config.domain.vo.LocationPriorityDetailsVO;
 import com.ruoyi.ams.config.domain.vo.LocationPriorityHeaderVO;
 import com.ruoyi.ams.config.mapper.LocationPriorityHeaderMapper;
 import com.ruoyi.base.domain.BaseLocationInfo;
 import com.ruoyi.base.domain.vo.BaseLocationLotattVO;
 import com.ruoyi.base.mapper.BaseLocationInfoMapper;
+import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
@@ -75,33 +77,100 @@ public class LocationAllocationStrategy {
     /**
      * 根据策略过滤锁定库位
      *
-     * @param zoneId                   区域id
+     * @param zoneId                   入库区域
+     * @param inWarehouseDTO           入库信息
      * @param locationPriorityHeaderVO 出入库策略
      * @return
      */
-    public BaseLocationInfo filterLockLocation(Long zoneId, Long warehouseId, LocationPriorityHeaderVO locationPriorityHeaderVO) {
-        /*BaseLocationInfo query = new BaseLocationInfo();
-        query.setWarehouseId(warehouseId);
+    public BaseLocationInfo filterLockLocation(Long zoneId, InWarehouseDTO inWarehouseDTO, LocationPriorityHeaderVO locationPriorityHeaderVO) {
+        BaseLocationInfo query = new BaseLocationInfo();
+        query.setWarehouseId(inWarehouseDTO.getWarehouseId());
         query.setZoneId(zoneId);
         List<BaseLocationLotattVO> locationLotattVOList = baseLocationInfoMapper.selectSortedLocationLotattListByZoneId(query);
         List<LocationPriorityDetailsVO> locationPriorityDetails = locationPriorityHeaderMapper.selectLocationPriorityDetailsList(locationPriorityHeaderVO.getId());
         //批次属性
         LinkedHashMap<String, String> lotatt = new LinkedHashMap<>();
-        for (LocationPriorityDetailsVO vo : locationPriorityDetails) {
-            lotatt.put(vo.getLotattId(),vo.getLotattValue());
+        if (locationPriorityDetails != null && locationPriorityDetails.size() > 0) {
+            for (LocationPriorityDetailsVO vo : locationPriorityDetails) {
+                lotatt.put(vo.getLotattId(), vo.getLotattValue());
+            }
         }
+
         //将同一列的库位排序好
-        LinkedHashMap<String, List<BaseLocationInfo>> map = new LinkedHashMap<>();
+        Integer parallelCount = 0;
+        LinkedHashMap<String, Boolean> taskingFlag = new LinkedHashMap<>();
+        LinkedHashMap<String, List<BaseLocationLotattVO>> map = new LinkedHashMap<>();
         for (BaseLocationLotattVO info : locationLotattVOList) {
-            List<BaseLocationInfo> infoList;
+            List<BaseLocationLotattVO> infoList;
             if (map.containsKey(info.getColNo())) {
                 infoList = map.get(info.getColNo());
             } else {
                 infoList = new ArrayList<>();
             }
+            if (info.getStockStatus().equals("10")) {
+                taskingFlag.put(info.getColNo(), true);
+                parallelCount++;
+            } else {
+                if (taskingFlag.get(info.getColNo()) == null || taskingFlag.get(info.getColNo()).booleanValue() == false) {
+                    taskingFlag.put(info.getColNo(), false);
+                }
+            }
             infoList.add(info);
             map.put(info.getColNo(), infoList);
-        }*/
-        return null;
+        }
+
+        //过滤出每列可以用的库位并进行分配
+        BaseLocationInfo currentLocation = null;
+        for (Map.Entry<String, List<BaseLocationLotattVO>> entry : map.entrySet()) {
+            List<BaseLocationLotattVO> locationInfoList = entry.getValue();
+            for (BaseLocationLotattVO b : locationInfoList) {
+                //如果允许并行则跳过已经分配过的列
+                if (locationPriorityHeaderVO.getParallelFlag().equals("Y")) {
+                    //如果达到并行数量,则当前区域不再进行分配
+                    if (parallelCount + 1 > locationPriorityHeaderVO.getParallelCount()) {
+                        return null;
+                    }
+                    if (taskingFlag.get(b.getColNo())) {
+                        continue;
+                    }
+                }
+                // TODO 优先寻找匹配批次属性的库存库位进行存放
+                if (lotatt.size() > 0 && b.getLotattVO() != null) { //指定了批次属性的需要对相同批次属性的库存进行匹配
+                    b.initLotatt();
+                    boolean isSame = true;
+                    for (Map.Entry<String, String> attEntry : lotatt.entrySet()) {
+                        if (!b.getAttMap().get(attEntry.getKey()).equals(attEntry.getValue())) {
+                            isSame = false;
+                        }
+                    }
+                    if (isSame == false) {
+                        continue;
+                    }
+                }
+
+                if (currentLocation == null) {
+                    if (b.getIsEmpty().equals("Y") && b.getStockStatus().equals("00")) {
+                        BaseLocationInfo locationInfo = new BaseLocationInfo();
+                        BeanUtils.copyProperties(b, locationInfo);
+                        currentLocation = locationInfo;
+                    }
+                } else {
+                    //如果前面的库位已阻挡则之前的库位不可用
+                    if (!b.getIsEmpty().equals("Y") || !b.getStockStatus().equals("00")) {
+                        currentLocation = null;
+                    } else {
+                        continue;
+                    }
+                }
+            }
+            if (currentLocation != null) {
+                break;
+            }
+        }
+        return currentLocation;
     }
+
+    /*public BaseLocationInfo filterLockInv() {
+
+    }*/
 }

+ 15 - 12
warewms-ams/src/main/java/com/ruoyi/ams/config/service/impl/BusinessServiceImpl.java

@@ -5,6 +5,7 @@ import com.ruoyi.ams.config.domain.dto.AgvCallDTO;
 import com.ruoyi.ams.config.domain.dto.InWarehouseDTO;
 import com.ruoyi.ams.config.domain.dto.OutWarehouseDTO;
 import com.ruoyi.ams.config.domain.vo.LocationPriorityHeaderVO;
+import com.ruoyi.ams.config.mapper.LocationPriorityHeaderMapper;
 import com.ruoyi.ams.config.service.IBusinessService;
 import com.ruoyi.ams.config.service.ILocationPriorityHeaderService;
 import com.ruoyi.ams.config.service.LocationAllocationStrategy;
@@ -17,7 +18,6 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
-import java.util.LinkedHashMap;
 import java.util.List;
 
 @Service
@@ -31,6 +31,8 @@ public class BusinessServiceImpl implements IBusinessService {
     private ILocationPriorityHeaderService locationPriorityHeaderService;
     @Autowired
     private LocationAllocationStrategy locationAllocationStrategy;
+    @Autowired
+    private LocationPriorityHeaderMapper locationPriorityHeaderMapper;
 
     @Transactional
     @Override
@@ -61,13 +63,15 @@ public class BusinessServiceImpl implements IBusinessService {
         } else {
             List<Long> zoneList = new ArrayList<>();
             if (StringUtils.isEmpty(inWarehouseDTO.getLocationZoneTo()) && StringUtils.isEmpty(inWarehouseDTO.getLocationTo())) { //不指定目标库位和区域
-                // TODO 没有指定目标的根据sku进行匹配并进行分配
-                // TODO 如果可以混放的区域不匹配物料也可以选择,否则只选择可以存放的区域
+                // 没有指定目标的根据sku进行匹配并进行分配
+                // 如果可以混放的区域不匹配物料也可以选择,否则只选择可以存放的区域
+                List<Long> list = locationPriorityHeaderMapper.selectZoneIdListBySku(inWarehouseDTO.getSku());
+                zoneList.addAll(list);
             } else {
                 // 指定区域的
                 zoneList.add(Long.parseLong(inWarehouseDTO.getLocationZoneTo()));
             }
-
+            BaseLocationInfo resultLocation = null;
             for (Long zoneId : zoneList) {
                 LocationPriorityHeader query = new LocationPriorityHeader();
                 query.setLocationZone(zoneId.toString());
@@ -76,24 +80,23 @@ public class BusinessServiceImpl implements IBusinessService {
                     //根据策略进行库位分配
                     //sku 批次属性 库存
                     LocationPriorityHeaderVO locationPriorityHeaderVO = list.get(0);
-
-                    List<BaseLocationInfo> locationInfoList = baseLocationInfoService.selectSortedLocatinListByZoneId(zoneId, inWarehouseDTO.getWarehouseId());
-
-
-                    return null;
+                    resultLocation = locationAllocationStrategy.filterLockLocation(zoneId, inWarehouseDTO, locationPriorityHeaderVO);
                 } else {
                     // 如果指定区域没有配置策略则随意分配一个可用的空库位
                     List<BaseLocationInfo> locationInfoList = baseLocationInfoService.selectSortedLocatinListByZoneId(zoneId, inWarehouseDTO.getWarehouseId());
-                    BaseLocationInfo locationInfo = locationAllocationStrategy.filterLockLocation(locationInfoList);
-                    return locationInfo;
+                    resultLocation = locationAllocationStrategy.filterLockLocation(locationInfoList);
+
                 }
             }
-            return null;
+            return resultLocation;
         }
     }
 
     @Override
     public BaseLocationInfo OutInvAllocation(OutWarehouseDTO outWarehouseDTO) {
+        /**
+         *
+         */
         return null;
     }
 }

+ 8 - 1
warewms-ams/src/main/resources/mapper/ams/LocationPriorityHeaderMapper.xml

@@ -65,7 +65,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     </select>
 
     <select id="selectLocationPriorityDetailsList" parameterType="Long" resultMap="LocationPriorityDetailsResult">
-        select * from location_priority_details where header_id = #{id}
+        select
+        b.id as sub_id, b.header_id as sub_header_id, b.lotatt_id as sub_lotatt_id, b.lotatt_value as sub_lotatt_value, b.create_by as sub_create_by, b.create_time as sub_create_time, b.update_by as sub_update_by, b.update_time as sub_update_time, b.remark as sub_remark
+        from location_priority_details b where header_id = #{id}
     </select>
     
     <select id="selectLocationPriorityHeaderById" parameterType="Long" resultMap="LocationPriorityHeaderLocationPriorityDetailsResult">
@@ -181,4 +183,9 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
             ( #{item.id}, #{item.headerId}, #{item.lotattId}, #{item.lotattValue}, #{item.createBy}, #{item.createTime}, #{item.updateBy}, #{item.updateTime}, #{item.remark})
         </foreach>
     </insert>
+
+    <select id="selectZoneIdListBySku" parameterType="string" resultType="java.lang.Long">
+        select z.zone_id from base_location_zone z left join location_priority_header l on z.zone_id = l.location_zone
+        where l.sku = #{sku} or l.sku is null
+    </select>
 </mapper>

+ 37 - 0
warewms-base/src/main/java/com/ruoyi/base/domain/vo/BaseLocationLotattVO.java

@@ -3,6 +3,9 @@ package com.ruoyi.base.domain.vo;
 import com.ruoyi.base.domain.BaseLocationInfo;
 import com.ruoyi.base.domain.LotattVO;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * Created by IntelliJ IDEA.
  * User: andy.qu
@@ -12,6 +15,32 @@ public class BaseLocationLotattVO extends BaseLocationInfo {
     private String sku;
     private Float qty;
     private LotattVO lotattVO;
+    private Map<String, String> attMap;
+
+    public void initLotatt() {
+        attMap = new HashMap<>();
+        if (lotattVO == null) {
+            lotattVO = new LotattVO();
+        }
+        this.attMap.put("lotatt01", lotattVO.getLotatt01());
+        this.attMap.put("lotatt02", lotattVO.getLotatt02());
+        this.attMap.put("lotatt03", lotattVO.getLotatt03());
+        this.attMap.put("lotatt04", lotattVO.getLotatt04());
+        this.attMap.put("lotatt05", lotattVO.getLotatt05());
+        this.attMap.put("lotatt06", lotattVO.getLotatt06());
+        this.attMap.put("lotatt07", lotattVO.getLotatt07());
+        this.attMap.put("lotatt08", lotattVO.getLotatt08());
+        this.attMap.put("lotatt09", lotattVO.getLotatt09());
+        this.attMap.put("lotatt10", lotattVO.getLotatt10());
+        this.attMap.put("lotatt11", lotattVO.getLotatt11());
+        this.attMap.put("lotatt12", lotattVO.getLotatt12());
+        this.attMap.put("lotatt13", lotattVO.getLotatt13());
+        this.attMap.put("lotatt14", lotattVO.getLotatt14());
+        this.attMap.put("lotatt15", lotattVO.getLotatt15());
+        this.attMap.put("lotatt16", lotattVO.getLotatt16());
+        this.attMap.put("lotatt17", lotattVO.getLotatt17());
+        this.attMap.put("lotatt18", lotattVO.getLotatt18());
+    }
 
     public String getSku() {
         return sku;
@@ -36,4 +65,12 @@ public class BaseLocationLotattVO extends BaseLocationInfo {
     public void setLotattVO(LotattVO lotattVO) {
         this.lotattVO = lotattVO;
     }
+
+    public Map<String, String> getAttMap() {
+        return attMap;
+    }
+
+    public void setAttMap(Map<String, String> attMap) {
+        this.attMap = attMap;
+    }
 }