WarecellAllocationServiceImpl.java 19 KB
package com.huaheng.api.wcs.service.warecellAllocation;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.huaheng.api.wcs.domain.WCSInfo;
import com.huaheng.common.constant.QuantityConstant;
import com.huaheng.common.exception.service.ServiceException;
import com.huaheng.common.support.Convert;
import com.huaheng.common.utils.StringUtils;
import com.huaheng.common.utils.security.ShiroUtils;
import com.huaheng.framework.web.domain.AjaxResult;
import com.huaheng.pc.config.FilterConfigDetail.domain.FilterConfigDetail;
import com.huaheng.pc.config.FilterConfigDetail.service.FilterConfigDetailService;
import com.huaheng.pc.config.configValue.domain.ConfigValue;
import com.huaheng.pc.config.configValue.service.ConfigValueService;
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.material.domain.Material;
import com.huaheng.pc.config.material.service.MaterialService;
import com.huaheng.pc.config.materialType.domain.MaterialType;
import com.huaheng.pc.config.materialType.service.MaterialTypeService;
import com.huaheng.pc.config.receiptPreference.domain.ReceiptPreference;
import com.huaheng.pc.config.receiptPreference.service.ReceiptPreferenceService;
import com.huaheng.pc.receipt.receiptContainerDetail.domain.ReceiptContainerDetail;
import com.huaheng.pc.receipt.receiptContainerDetail.service.ReceiptContainerDetailService;
import com.huaheng.pc.receipt.receiptContainerHeader.domain.ReceiptContainerHeader;
import com.huaheng.pc.receipt.receiptContainerHeader.service.ReceiptContainerHeaderService;
import com.huaheng.pc.receipt.receiptDetail.service.ReceiptDetailService;
import com.huaheng.pc.task.taskDetail.domain.TaskDetail;
import com.huaheng.pc.task.taskDetail.service.TaskDetailService;
import com.huaheng.pc.task.taskHeader.domain.TaskHeader;
import com.huaheng.pc.task.taskHeader.service.TaskHeaderService;
import com.huaheng.pc.task.taskHeader.service.TransferTaskService;
import com.huaheng.pc.task.taskHeader.service.WorkTaskService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.huaheng.api.wcs.domain.WcsTask;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class WarecellAllocationServiceImpl implements WarecellAllocationService {

    @Resource
    private LocationTypeService locationTypeService;
    @Resource
    private LocationService locationService;
    @Resource
    private ContainerService containerService;
    @Resource
    private ContainerTypeService containerTypeService;
    @Resource
    private ConfigValueService configValueService;
    @Resource
    private ReceiptPreferenceService receiptPreferenceService;
    @Resource
    private FilterConfigDetailService filterConfigDetailService;
    @Resource
    private TaskDetailService taskDetailService;
    @Resource
    private TaskHeaderService taskHeaderService;
    @Resource
    private ReceiptContainerDetailService receiptContainerDetailService;
    @Resource
    private ReceiptContainerHeaderService receiptContainerHeaderService;
    @Resource
    private ReceiptDetailService receiptDetailService;
    @Resource
    private MaterialService materialService;
    @Resource
    private MaterialTypeService materialTypeService;
    @Resource
    private WorkTaskService workTaskService;
    @Resource
    private TransferTaskService transferTaskService;
    @Resource
    private LocationAllocationService locationAllocationService;

    /**
     * 立库仓位分配
     * 1、判断非空字段
     * 2、实体转换
     * 3、查询满足条件的库位类型
     *
     * @param wcsTask
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult warecellAllocation(WcsTask wcsTask) {
        //1、判断非空字段
        if (StringUtils.isEmpty(wcsTask.getTaskNo())) {
            return AjaxResult.error("任务号为空");
        }
        if (StringUtils.isEmpty(wcsTask.getDestination())) {
            return AjaxResult.error("目的区域为空");
        }
        if (StringUtils.isNull(wcsTask.getLength())) {
            return AjaxResult.error("长为空");
        }
        if (StringUtils.isNull(wcsTask.getWidth())) {
            return AjaxResult.error("宽为空");
        }
        if (StringUtils.isNull(wcsTask.getHeight())) {
            return AjaxResult.error("高为空");
        }
        if (StringUtils.isNull(wcsTask.getWeight())) {
            return AjaxResult.error("重为空");
        }
        return verticalWarehouseAllocation(wcsTask);
    }

    public AjaxResult verticalWarehouseAllocation(WcsTask wcsTask) {
        String warehouseCode = wcsTask.getWarehouseCode();
        //查询满足条件的库位类型
        LambdaQueryWrapper<LocationType> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.gt(LocationType::getLength, wcsTask.getLength())
                .gt(LocationType::getWidth, wcsTask.getWidth())
                .gt(LocationType::getHeight, wcsTask.getHeight())
                .gt(LocationType::getMaxWeight, wcsTask.getWidth())
                .eq(LocationType::getWarehouseCode, warehouseCode);
        List<LocationType> locationTypeList = locationTypeService.list(lambdaQueryWrapper);

        String locationCode = null;
        //查询任务明细
        LambdaQueryWrapper<TaskDetail> taskDetailLambda = Wrappers.lambdaQuery();
        taskDetailLambda.eq(TaskDetail::getTaskId, wcsTask.getTaskNo());
        List<TaskDetail> taskDetailList = taskDetailService.list(taskDetailLambda);

        TaskHeader taskHeader = taskHeaderService.getById(wcsTask.getTaskNo());
        if (taskHeader.getStatus() == 100) {
            return AjaxResult.error("任务已经完成,不能再分库位");
        }
        String containerCode = taskHeader.getContainerCode();

        /* 循环查询入库组盘明细*/
        List<ReceiptContainerDetail> receiptContainerDetailList = new ArrayList<>();
        for (TaskDetail taskDetail : taskDetailList) {
            ReceiptContainerDetail receiptContainerDetail = receiptContainerDetailService.getById(taskDetail.getAllocationId());
            if (receiptContainerDetail != null) {
                receiptContainerDetailList.add(receiptContainerDetail);
            }
        }
        //去重
        receiptContainerDetailList = receiptContainerDetailList.stream().distinct().collect(Collectors.toList());

        String locatingRule = null;
        ReceiptContainerHeader receiptContainerHeader = null;
        if (StringUtils.isEmpty(locatingRule)) {
            //物料类别中定位规则为空时,查询入库首选项
            LambdaQueryWrapper<ConfigValue> configValueLambda = Wrappers.lambdaQuery();
            configValueLambda.eq(ConfigValue::getWarehouseCode, warehouseCode)
                    .eq(ConfigValue::getModuleType, "receipt")
                    .eq(ConfigValue::getRecordType, "入库首选项");
            ConfigValue configValue = configValueService.getOne(configValueLambda);
            LambdaQueryWrapper<ReceiptPreference> receiptPreferenceLambda = Wrappers.lambdaQuery();
            receiptPreferenceLambda.eq(ReceiptPreference::getCode, configValue.getValue())
                    .eq(ReceiptPreference::getWarehouseCode, warehouseCode);
            ReceiptPreference receiptPreference = receiptPreferenceService.getOne(receiptPreferenceLambda);
            locatingRule = receiptPreference.getLocationRule();
        }

        if (StringUtils.isEmpty(locatingRule)){
            throw new ServiceException("未绑定定位规则");
        }
        Integer materialAreas = 0;
        if(receiptContainerDetailList != null && receiptContainerDetailList.size() > 0) {
            String materialCode = receiptContainerDetailList.get(0).getMaterialCode();
            Material material = materialService.findAllByCode(materialCode, warehouseCode);
            materialAreas = material.getMaterialAreas();
        }
        locationCode = locationAllocationService.allocation(locatingRule, wcsTask.getDestination(), warehouseCode, containerCode, materialAreas);
        if (StringUtils.isEmpty(locationCode)) {
            return AjaxResult.error("没有库位可分配");
        }

        if (StringUtils.isNotEmpty(locationCode)) {
            locationService.updateStatus(locationCode, QuantityConstant.STATUS_LOCATION_LOCK, warehouseCode);
            if (StringUtils.isNotEmpty(taskHeader.getToLocation()) && !locationCode.equals(taskHeader.getToLocation())) {
                locationService.updateStatus(taskHeader.getToLocation(), QuantityConstant.STATUS_LOCATION_EMPTY, warehouseCode);
            }
        } else {
            throw new ServiceException("定位失败,请检查定位规则是否正确");
        }
        if (receiptContainerDetailList != null && receiptContainerDetailList.size() > 0) {
            //更新库位编码到组盘头表
            ReceiptContainerDetail receiptContainerDetail = receiptContainerDetailList.get(0);
            if (receiptContainerDetail != null) {
                receiptContainerHeader = receiptContainerHeaderService.getById(receiptContainerDetail.getReceiptContainerId());
                receiptContainerHeader.setToLocation(locationCode);
                if (!receiptContainerHeaderService.updateById(receiptContainerHeader)) {
                    throw new ServiceException("更新库位失败");
                }

                //把库位编码赋到该入库组盘头表下的所有明细
                LambdaQueryWrapper<ReceiptContainerDetail> lambda = Wrappers.lambdaQuery();
                lambda.eq(ReceiptContainerDetail::getReceiptContainerId, receiptContainerHeader.getId())
                        .eq(ReceiptContainerDetail::getWarehouseCode, warehouseCode);
                List<ReceiptContainerDetail> receiptContainerDetails = receiptContainerDetailService.list(lambda);
                for (ReceiptContainerDetail receiptContainerDetail2 : receiptContainerDetails) {
                    receiptContainerDetail2.setLocationCode(locationCode);
                    if (!receiptContainerDetailService.updateById(receiptContainerDetail2)) {
                        throw new ServiceException("更新库位编码到入库组盘明细");
                    }
                }
            }
        }

        for (TaskDetail taskDetail : taskDetailList) {
            taskDetail.setToLocation(locationCode);
            if (!taskDetailService.updateById(taskDetail)) {
                throw new ServiceException("更新任务明细目标库位失败");
            }
        }

        //修改任务明细目标库位
        LambdaQueryWrapper<Location> locationLambdaQueryWrapper = Wrappers.lambdaQuery();
        locationLambdaQueryWrapper.eq(Location::getCode, locationCode)
                                    .eq(Location::getWarehouseCode, warehouseCode);
        Location location = locationService.getOne(locationLambdaQueryWrapper);
        int rowFlag = location.getRowFlag().intValue();
        Integer preTaskNo = 0;
        //如果是外侧库位,那么就要判断该库位对应的内侧库位是不是有托盘
        if (rowFlag == 1) {
            Location insideLocation = locationService.getInsideNear(location);
            if (StringUtils.isNotEmpty(insideLocation.getContainerCode())) {
                Location destinationLocation = locationService.getEmptyLocation(insideLocation);
                AjaxResult ajaxResult = transferTaskService.createTransferTask(insideLocation.getCode(), destinationLocation.getCode());
                preTaskNo = (Integer) ajaxResult.getData();
                if (ajaxResult.hasErr()) {
                    throw new ServiceException("创建移库任务失败");
                }
                taskHeaderService.sendTaskToWcs(Convert.toIntArray(String.valueOf(preTaskNo)));
            }
        }

        taskHeader.setPreTaskNo(preTaskNo);
        taskHeader.setToLocation(locationCode);
        if (!taskHeaderService.updateById(taskHeader)) {
            throw new ServiceException("更新任务头表目标库位失败");
        }
        WCSInfo wcsInfo = new WCSInfo();
        wcsInfo.setLocationCode(locationCode);
        wcsInfo.setPreTask(String.valueOf(preTaskNo));
        return AjaxResult.success().setData(wcsInfo);
    }

    /**
     * 库位筛选
     *
     * @param locationList     库位列表
     * @param locationTypeList 库位类型列表
     * @param roadway          巷道
     * @return
     */
    public String filter(List<Location> locationList, List<LocationType> locationTypeList, String roadway) {
        List<String> codeList = locationTypeList.stream().map(t -> t.getCode()).collect(Collectors.toList());
        List<Location> newLocation = locationList.stream().filter(t -> codeList.contains(t.getLocationType()) && t.getRoadway().equals(roadway)).collect(Collectors.toList());
        if (newLocation.isEmpty()) {
            return null;
        } else {
            return newLocation.get(0).getCode();
        }
    }

    /**
     * 定位规则
     * @return
     */
    @Override
    public String taskPositioning() {
        //物料类别中定位规则为空时,查询入库首选项
        LambdaQueryWrapper<ConfigValue> configValueLambda = Wrappers.lambdaQuery();
        configValueLambda.eq(ConfigValue::getWarehouseCode, ShiroUtils.getWarehouseCode())
                .eq(ConfigValue::getModuleType, "receipt")
                .eq(ConfigValue::getRecordType, "入库首选项");
        ConfigValue configValue = configValueService.getOne(configValueLambda);
        LambdaQueryWrapper<ReceiptPreference> receiptPreferenceLambda = Wrappers.lambdaQuery();
        receiptPreferenceLambda.eq(ReceiptPreference::getCode, configValue.getValue())
                .eq(ReceiptPreference::getWarehouseCode, ShiroUtils.getWarehouseCode());
        ReceiptPreference receiptPreference = receiptPreferenceService.getOne(receiptPreferenceLambda);
        String locatingRule = receiptPreference.getLocationRule();

        //通过定位规则查找自定义sql
        if (StringUtils.isEmpty(locatingRule)) {
            throw new ServiceException("未绑定定位规则");
        }
        LambdaQueryWrapper<FilterConfigDetail> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.eq(FilterConfigDetail::getCode, locatingRule)
                .eq(FilterConfigDetail::getWarehouseCode,ShiroUtils.getWarehouseCode());
        FilterConfigDetail filterConfigDetail = filterConfigDetailService.getOne(lambdaQueryWrapper);
        return filterConfigDetail.getStatement();
    }


    /**
     * 去向分配
     */
    @Override
    public AjaxResult destinationAllocation(WcsTask wcsTask) {

        //1、判断非空字段
        if (StringUtils.isEmpty(wcsTask.getTaskNo())) {
            return AjaxResult.error("任务号为空");
        }
        if (StringUtils.isNull(wcsTask.getLength())) {
            return AjaxResult.error("长为空");
        }
        if (StringUtils.isNull(wcsTask.getWidth())) {
            return AjaxResult.error("宽为空");
        }
        if (StringUtils.isNull(wcsTask.getHeight())) {
            return AjaxResult.error("高为空");
        }
        if (StringUtils.isNull(wcsTask.getWeight())) {
            return AjaxResult.error("重为空");
        }

        //查询满足条件的库位类型
        LambdaQueryWrapper<LocationType> lambdaQueryWrapper = Wrappers.lambdaQuery();
        lambdaQueryWrapper.gt(LocationType::getLength, wcsTask.getLength())
                .gt(LocationType::getWidth, wcsTask.getWidth())
                .gt(LocationType::getHeight, wcsTask.getHeight())
                .gt(LocationType::getMaxWeight, wcsTask.getWidth());
        List<LocationType> locationTypeList = locationTypeService.list(lambdaQueryWrapper);

        if (locationTypeList.isEmpty()) {
            return AjaxResult.error("没有区域可分配");
        }
        List<String> codeList = new ArrayList<>();
        for (LocationType locationType : locationTypeList) {
            codeList.add(locationType.getCode());
        }

        //定位库位List
        List<String> positioningLocationCodeList = null;
        //查询任务明细
        LambdaQueryWrapper<TaskDetail> taskDetailLambda = Wrappers.lambdaQuery();
        taskDetailLambda.eq(TaskDetail::getTaskId, wcsTask.getTaskNo());
        List<TaskDetail> taskDetailList = taskDetailService.list(taskDetailLambda);

        /* 循环查询入库组盘明细*/
        List<ReceiptContainerDetail> receiptContainerDetailList = new ArrayList<>();
        for (TaskDetail taskDetail : taskDetailList) {
            receiptContainerDetailList.add(receiptContainerDetailService.getById(taskDetail.getAllocationId()));
        }
        //去重
        receiptContainerDetailList = receiptContainerDetailList.stream().distinct().collect(Collectors.toList());

        for (ReceiptContainerDetail receiptContainerDetail : receiptContainerDetailList) {
            String locatingRule = this.taskPositioning();

            LambdaQueryWrapper<FilterConfigDetail> filterConfigDetailLambda = Wrappers.lambdaQuery();
            filterConfigDetailLambda.eq(FilterConfigDetail::getCode, locatingRule)
                    .eq(FilterConfigDetail::getWarehouseCode, ShiroUtils.getWarehouseCode());
            FilterConfigDetail filterConfigDetail = filterConfigDetailService.getOne(filterConfigDetailLambda);
            String[] locatingRules = filterConfigDetail.getStatement().split("limit");

            //根据定位规则查询库位编码
            LambdaQueryWrapper<Location> locationLambda = Wrappers.lambdaQuery();
            locationLambda.last(locatingRules[0]);
            List<Location> locationList = locationService.list(locationLambda);
            List<String> locationCodeList = locationTypeList.stream().map(t -> t.getCode()).collect(Collectors.toList());
            List<Location> newLocation = locationList.stream().filter(t -> locationCodeList.contains(t.getLocationType())).collect(Collectors.toList());
            if (!newLocation.isEmpty()) {
                positioningLocationCodeList.add(newLocation.get(0).getCode());
            }

            if (StringUtils.isEmpty(positioningLocationCodeList)) {
                throw new ServiceException("没有区域可分配");
            }
        }

        LambdaQueryWrapper<Location> locationLambdaQueryWrapper = Wrappers.lambdaQuery();
        locationLambdaQueryWrapper.eq(Location::getCode, positioningLocationCodeList.get(0));
        Location location = locationService.getOne(locationLambdaQueryWrapper);
        String destinationArea = location.getRoadway();
        return AjaxResult.success(destinationArea);
    }

}