LocationAllocationServiceImpl.java 13.4 KB
package com.huaheng.api.wcs.service.warecellAllocation;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaheng.common.constant.QuantityConstant;
import com.huaheng.common.exception.service.ServiceException;
import com.huaheng.common.utils.StringUtils;
import com.huaheng.framework.web.service.ConfigService;
import com.huaheng.pc.config.container.domain.Container;
import com.huaheng.pc.config.container.service.ContainerService;
import com.huaheng.pc.config.containerType.domain.ContainerType;
import com.huaheng.pc.config.containerType.service.ContainerTypeService;
import com.huaheng.pc.config.location.domain.Location;
import com.huaheng.pc.config.location.service.LocationService;
import com.huaheng.pc.config.locationType.domain.LocationType;
import com.huaheng.pc.config.locationType.service.LocationTypeService;
import com.huaheng.pc.config.zone.domain.Zone;
import com.huaheng.pc.config.zone.service.ZoneService;
import com.huaheng.pc.inventory.inventoryDetail.domain.InventoryDetail;
import com.huaheng.pc.inventory.inventoryDetail.service.InventoryDetailService;
import com.huaheng.pc.task.taskHeader.domain.TaskHeader;
import com.huaheng.pc.task.taskHeader.service.TaskHeaderService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

@Service
public class LocationAllocationServiceImpl implements LocationAllocationService {

    @Resource
    private LocationService locationService;
    @Resource
    private LocationTypeService locationTypeService;
    @Resource
    private ContainerService containerService;
    @Resource
    private ContainerTypeService containerTypeService;
    @Resource
    private TaskHeaderService taskHeaderService;
    @Resource
    private ZoneService zoneService;
    @Resource
    private ConfigService configService;
    @Resource
    private LocationAllocationService locationAllocationService;
    @Resource
    private InventoryDetailService inventoryDetailService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String allocation(int locationRule, List<String> locationTypeCodeList,
                             int high, String area, List<String> roadWays, String warehouseCode,
                             String containerCode, String materialAreaCode, String materialCode) {
        // 查询容器信息
        Container container = containerService.getOne(Wrappers.<Container>lambdaQuery()
                .eq(Container::getCode, containerCode)
                .eq(Container::getWarehouseCode, warehouseCode));

        // 获取容器类型
        ContainerType containerType = containerTypeService.getOne(Wrappers.<ContainerType>lambdaQuery()
                .eq(ContainerType::getCode, container.getContainerType())
                .eq(ContainerType::getWarehouseCode, warehouseCode));

        List<LocationType> locationTypeList = new ArrayList<>();
        if (containerType != null) {
            // 获取容器适用的库位类型列表
            String[] locationTypes = containerType.getLocationType().split(",");
            for (String typeCode : locationTypes) {
                LocationType locationType = locationTypeService.getOne(Wrappers.<LocationType>lambdaQuery()
                        .eq(LocationType::getWarehouseCode, warehouseCode)
                        .eq(LocationType::getCode, typeCode));
                locationTypeList.add(locationType);
            }
        } else {
            // 如果没有容器类型信息,按库区获取默认的库位类型
            Zone zone = zoneService.getOne(Wrappers.<Zone>lambdaQuery()
                    .eq(Zone::getWarehouseCode, warehouseCode)
                    .eq(Zone::getArea, area));
            if (zone != null) {
                locationTypeList = locationTypeService.list(Wrappers.<LocationType>lambdaQuery()
                        .eq(LocationType::getWarehouseCode, warehouseCode)
                        .eq(LocationType::getZoneCode, zone.getCode()));
            }
        }

        // 获取库位类型代码列表
        List<String> locationTypeCodes = locationTypeList.stream()
                .map(LocationType::getCode)
                .collect(Collectors.toList());

        // 合并库位类型代码
        List<String> mergedLocationTypeCodeList = locationTypeCodeList.stream()
                .filter(locationTypeCodes::contains)
                .collect(Collectors.toList());

        // 根据入库规则分配库位
        switch (locationRule) {
            case QuantityConstant.DOUBLE_FORK:
                return locationAllocationService.doubleRk(area, roadWays, high, warehouseCode, mergedLocationTypeCodeList, materialAreaCode);
            case QuantityConstant.SINGLE_FORK:
                if (area.equals("3")) {
                    return locationAllocationService.singleRkToC(area, roadWays, high, warehouseCode, mergedLocationTypeCodeList, materialAreaCode, materialCode);
                } else {
                    return locationAllocationService.singleRk(area, roadWays, high, warehouseCode, mergedLocationTypeCodeList, materialAreaCode);
                }
            default:
                return null;
        }
    }

    /**
     * 双伸位库位入库分配
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String doubleRk(String area, List<String> roadWays, int high, String warehouseCode,
                            List<String> locationTypeCodeList, String materialAreaCode) {
        // 查询符合条件的空置外侧库位
        List<Location> locationList = locationService.list(Wrappers.<Location>lambdaQuery()
                .eq(Location::getArea, area)
                .eq(Location::getWarehouseCode, warehouseCode)
                .in(StringUtils.isNotEmpty(roadWays), Location::getRoadway, roadWays)
                .eq(Location::getStatus, QuantityConstant.STATUS_LOCATION_EMPTY)
                .eq(Location::getHigh, high)
                .eq(StringUtils.isNotEmpty(materialAreaCode), Location::getMaterialAreaCode, materialAreaCode)
                .eq(Location::getRowFlag, QuantityConstant.ROW_OUT)
                .in(Location::getLocationType, locationTypeCodeList)
                .eq(Location::getContainerCode, ""));

        // 如果没有空置外侧库位,查询内侧库位
        if (locationList.isEmpty()) {
            locationList = locationService.list(Wrappers.<Location>lambdaQuery()
                    .eq(Location::getArea, area)
                    .eq(Location::getWarehouseCode, warehouseCode)
                    .in(StringUtils.isNotEmpty(roadWays), Location::getRoadway, roadWays)
                    .eq(Location::getStatus, QuantityConstant.STATUS_LOCATION_EMPTY)
                    .eq(Location::getHigh, high)
                    .eq(StringUtils.isNotEmpty(materialAreaCode), Location::getMaterialAreaCode, materialAreaCode)
                    .eq(Location::getRowFlag, QuantityConstant.ROW_IN)
                    .in(Location::getLocationType, locationTypeCodeList)
                    .eq(Location::getContainerCode, ""));

            // 排除有未完成任务的库位
            locationList.removeIf(location -> taskHeaderService.getUncompleteTaskInNear(location) > 0);
        }
        return locationList.stream().findFirst().map(Location::getCode).orElse(null);
    }

    /**
     * 单伸位库位入库分配
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String singleRk(String area, List<String> roadWays, int high, String warehouseCode,
                            List<String> locationTypeCodeList, String materialAreaCode) {
        // 根据物料分区调整参数
        if (materialAreaCode != null) {
            if ((Integer.valueOf(area) == 1 || Integer.valueOf(area) == 2)
                    && materialAreaCode.equals(QuantityConstant.STATUS_CONTAINER_MANY)) {
                materialAreaCode = "C";
            }
        }
        if (Integer.valueOf(area) == 3 && high == 3) {
            high = 1;
            materialAreaCode = "A";
        }

        // 查询符合条件的库位
        List<Location> locationList = locationService.list(Wrappers.<Location>lambdaQuery()
                .eq(Location::getArea, area)
                .eq(Location::getWarehouseCode, warehouseCode)
                .in(StringUtils.isNotEmpty(roadWays), Location::getRoadway, roadWays)
                .eq(Location::getStatus, QuantityConstant.STATUS_LOCATION_EMPTY)
                .eq(Location::getHigh, high)
                .eq(StringUtils.isNotEmpty(materialAreaCode), Location::getMaterialAreaCode, materialAreaCode)
                .in(Location::getLocationType, locationTypeCodeList)
                .eq(Location::getContainerCode, ""));

        // 通过配置调整库位顺序
        String cs = configService.getKey(QuantityConstant.Reverse_Engine_Sequence);
        if ("1".equals(cs) && "1".equals(area)) {
            Collections.reverse(locationList);
        }

        // 返回第一个符合条件的库位编码
        return locationList.stream().findFirst().map(Location::getCode).orElseThrow(() ->
                new ServiceException("未找到合适的库位,可能是库位已满"));
    }

    /**
     * 单伸位库位入库分配
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String singleRkToC(String area, List<String> roadWays, int high, String warehouseCode,
                           List<String> locationTypeCodeList, String materialAreaCode, String materialCode) {
        // 根据物料分区调整参数
        if (materialAreaCode != null) {
            if ((Integer.valueOf(area) == 1 || Integer.valueOf(area) == 2)
                    && materialAreaCode.equals(QuantityConstant.STATUS_CONTAINER_MANY)) {
                materialAreaCode = "C";
            }
        }
        if (Integer.valueOf(area) == 3 && high == 3) {
            high = 1;
            materialAreaCode = "A";
        }
        String roadWay =  locationAllocationService.getRoadWayByMinMaterial(roadWays, materialCode, area, warehouseCode);
        // 查询符合条件的库位
        List<Location> locationList = locationService.list(Wrappers.<Location>lambdaQuery()
                .eq(Location::getArea, area)
                .eq(Location::getWarehouseCode, warehouseCode)
                .in(StringUtils.isNotEmpty(roadWay), Location::getRoadway, roadWay)
                .eq(Location::getStatus, QuantityConstant.STATUS_LOCATION_EMPTY)
                .eq(Location::getHigh, high)
                .eq(StringUtils.isNotEmpty(materialAreaCode), Location::getMaterialAreaCode, materialAreaCode)
                .in(Location::getLocationType, locationTypeCodeList)
                .eq(Location::getContainerCode, ""));

        // 通过配置调整库位顺序
        String cs = configService.getKey(QuantityConstant.Reverse_Engine_Sequence);
        if ("1".equals(cs) && "1".equals(area)) {
            Collections.reverse(locationList);
        }

        // 返回第一个符合条件的库位编码
        return locationList.stream().findFirst().map(Location::getCode).orElseThrow(() ->
                new ServiceException("未找到合适的库位,可能是库位已满"));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String getRoadWayByMinMaterial(List<String> roadWays, String materialCode, String area, String warehouseCode) {
        if (CollectionUtils.isEmpty(roadWays)) {
            throw new ServiceException("分配库位时, 巷道为空");
        }
        Collections.shuffle(roadWays);// 打乱巷道排序
        String roadWay = roadWays.get(0);
        if (roadWays.size() == 1) {
            return roadWay;
        }
        int min = Integer.MAX_VALUE;
        List<String> locationCodes = new ArrayList<>();
        Zone zone = zoneService.getZoneByArea(area);
        List<InventoryDetail> inventoryDetailList = inventoryDetailService.getInventoryDetailListByMaterialCodeAndZoneCode(materialCode, zone.getCode(), warehouseCode);
        if (CollectionUtils.isNotEmpty(inventoryDetailList)) {
            Map<String, List<InventoryDetail>> map = inventoryDetailList.stream().collect(Collectors.groupingBy(InventoryDetail::getLocationCode));
            locationCodes.addAll(map.keySet());
        }
        if (CollectionUtils.isNotEmpty(locationCodes)) {
            LambdaQueryWrapper<Location> locationLambdaQueryWrapper = Wrappers.lambdaQuery();
            locationLambdaQueryWrapper.eq(Location::getWarehouseCode, warehouseCode);
            locationLambdaQueryWrapper.eq(Location::getArea, area);
            locationLambdaQueryWrapper.in(Location::getCode, locationCodes);
            List<Location> locationList = locationService.list(locationLambdaQueryWrapper);
            List<String> roadWayList = locationList.stream().map(Location::getRoadway).collect(toList());
            roadWayList.removeAll(Collections.singleton(null));
            for (String road : roadWays) {
                // i是查出现次数 这里速度很快返回次数
                int i = Collections.frequency(roadWayList, road);
                if (min > i) {
                    min = i;
                    roadWay = road;
                }
            }
        }
        return roadWay;
    }

}