package com.prolog.eis.service.out.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.eis.common.util.location.LocationConstants;
import com.prolog.eis.constants.base.*;
import com.prolog.eis.constants.cfg.LocationCfgConstants;
import com.prolog.eis.constants.cfg.StationCfgConstants;
import com.prolog.eis.constants.sys.SysParamConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.core.dto.route.AreaLocationCountDto;
import com.prolog.eis.core.model.base.area.WhArea;
import com.prolog.eis.core.model.base.locator.WhLocator;
import com.prolog.eis.core.model.biz.carry.CarryTask;
import com.prolog.eis.core.model.biz.route.ContainerLocation;
import com.prolog.eis.dao.shelves.PalletInfoMapper;
import com.prolog.eis.dto.eis4.*;
import com.prolog.eis.dto.item.ItemSyncVO;
import com.prolog.eis.dto.outbound.ContainerTaskDismantleDto;
import com.prolog.eis.dto.strategy.ContainerInfoDto;
import com.prolog.eis.dto.strategy.OrderDetailDto;
import com.prolog.eis.dto.wms.PrintParam;
import com.prolog.eis.dto.wms.WmsApplePrintDto;
import com.prolog.eis.dto.wms.WmsBindGirdDto;
import com.prolog.eis.dto.wms.WmsOfferBackDto;
import com.prolog.eis.enums.base.BaseStatusEnum;
import com.prolog.eis.enums.base.FullPrintEnum;
import com.prolog.eis.enums.base.SwitchEnum;
import com.prolog.eis.enums.station.StationTypeEnum;
import com.prolog.eis.feign.BaseCommonFeign;
import com.prolog.eis.model.container.*;
import com.prolog.eis.model.out.ContainerTaskDismantle;
import com.prolog.eis.model.outbound.BizOutboundTask;
import com.prolog.eis.model.outbound.BizOutboundTaskDetail;
import com.prolog.eis.model.outbound.PrintScheme;
import com.prolog.eis.model.outbound.PrintTask;
import com.prolog.eis.model.shelves.PalletInfo;
import com.prolog.eis.router.vo.ContainerLocationVo;
import com.prolog.eis.service.container.MergeContainerTaskService;
import com.prolog.eis.service.feign.RouteFeignService;
import com.prolog.eis.service.logic.LogicService;
import com.prolog.eis.service.out.*;
import com.prolog.eis.service.shelves.ItemService;
import com.prolog.eis.service.stationOutbound.StationObDispatchService;
import com.prolog.eis.service.wms.WmsApplePrintService;
import com.prolog.eis.service.wms.WmsBindGirdBackService;
import com.prolog.eis.service.wms.WmsOutRecheckBackService;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.JsonUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zmr
 * @description: 出库任务表-服务实现类
 * @date 2023-07-06 11:36
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class TimeTaskServiceImpl implements TimeTaskService {

    private final BizOutboundTaskService bizOutboundTaskService;
    private final BizOutboundTaskDetailService bizOutboundTaskDetailService;
    private final ContainerTaskService containerTaskService;
    private final ContainerTaskDismantleService containerTaskDismantleService;
    private final LogicService logicService;
    private final ItemService itemService;
    private final ContainerInfoService containerInfoService;
    private final MergeContainerTaskService mergeContainerTaskService;
    private final StationCfgService stationCfgService;
    private final RouteFeignService routeFeignService;
    private final PrintTaskService printTaskService;
    private final PrintSchemeService printSchemeService;
    private final BaseCommonFeign baseCommonFeign;
    private final WmsApplePrintService wmsApplePrintService;
    private final WmsBindGirdBackService wmsBindGirdBackService;
    private final WmsOutRecheckBackService wmsOutRecheckBackService;
    private final StationObDispatchService stationObDispatchService;
    private final RouteFeignService plgFeignRouteService;
    private final LocationCfgService locationCfgService;
    private final PalletInfoMapper palletInfoMapper;
    private final RedisTemplate redisTemplate;

    /**
     * 拆零区调度逻辑
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void dispatch() throws Exception {
        StationOBDispatchDto stationOBDispatchDto = new StationOBDispatchDto();
        List<StationOBContainerDto> containerList = new ArrayList<>();
        List<StationCfg> stationCfgList = stationCfgService.findByMap(MapUtils.put("isLock", 0).getMap());
        //组装任务容器数据(查业务数据)
        List<ContainerTaskDismantleDto> containerTaskList = containerTaskDismantleService.findContainerTaskList(WmsConstants.AGVL);
        assembleContainerData(containerList, containerTaskList, stationCfgList);
        stationOBDispatchDto.setPriorityType1(StationOBPriorityTypeEnum.DESC);
        stationOBDispatchDto.setPriorityType2(StationOBPriorityTypeEnum.DESC);
        stationOBDispatchDto.setPriorityType3(StationOBPriorityTypeEnum.DESC);
        stationOBDispatchDto.setDistancePolicy(2);
        stationOBDispatchDto.setContainerList(containerList);

        //组装区域数据（查route和warehouse）
        List<StationOBAreaDto> areaList = new ArrayList<>();
        assembleAreaData(areaList, stationCfgList, containerList, stationOBDispatchDto);
        stationOBDispatchDto.setAreaList(areaList);

        //调度eis4.0 搬运任务
        log.info(String.format("4.0调度初始参数组装数据：【%s】", JSONObject.toJSONString(stationOBDispatchDto)));

        //调度eis4.0 搬运任务
        List<StationOBCarryTaskDto> obCarryTaskList = stationObDispatchService.dispatch(stationOBDispatchDto);
        if (CollectionUtils.isEmpty(obCarryTaskList)) {
            return;
        }
        //处理数据状态
        doLogicData(containerTaskList, obCarryTaskList, stationCfgList);
        //发送搬运任务
        log.info(String.format("4.0调度发送任务数据：【%s】", JSONArray.toJSONString(obCarryTaskList)));
        List<CarryTask> carryTaskList = new ArrayList<>();
        for (StationOBCarryTaskDto item : obCarryTaskList) {
            CarryTask carryTask = new CarryTask();
            carryTask.setId(StrUtil.uuid());
            carryTask.setPalletNo(item.getContainerNo());
            carryTask.setContainerNo(item.getContainerNo());
            carryTask.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
            carryTask.setEndRegion(item.getTargetAreaNo());
            carryTask.setCreateTime(new Date());
            //判断发送的类型(终点区域是否为站台)
            carryTask.setBusinessType(String.valueOf(BaseTaskTypeConstants.DISMANTLE_OUTBOUND_TYPE));
            Long count = stationCfgList.stream().filter(o -> o.getAreaNo().equals(item.getTargetAreaNo())).count();
            if (count == 0) {
                carryTask.setBusinessType(String.valueOf(BaseTaskTypeConstants.IN_TYPE));
                Criteria criteria = new Criteria(ContainerInfo.class);
                criteria.setRestriction(Restrictions.eq("containerNo", item.getContainerNo()));
                containerInfoService.updateByMap(MapUtils.put("taskType", BaseTaskTypeConstants.DISMANTLE_BACK_TYPE).put("updateTime", LocalDateTime.now()).getMap(), criteria);
            } else {
                Criteria criteria = new Criteria(ContainerInfo.class);
                criteria.setRestriction(Restrictions.eq("containerNo", item.getContainerNo()));
                containerInfoService.updateByMap(MapUtils.put("taskType", BaseTaskTypeConstants.DISMANTLE_OUTBOUND_TYPE).put("updateTime", LocalDateTime.now()).getMap(), criteria);
            }
            carryTask.setTaskRemark("拆零库区出库4.0调度搬运");
            carryTaskList.add(carryTask);
        }
        if (!CollectionUtils.isEmpty(carryTaskList)) {
            log.info(String.format("4.0调度发送任务数据：【%s】", JSONArray.toJSONString(carryTaskList)));
            plgFeignRouteService.createBatchCarry(carryTaskList);
        }
    }

    private void doLogicData(List<ContainerTaskDismantleDto> containerTaskList, List<StationOBCarryTaskDto> obCarryTaskList, List<StationCfg> stationCfgList) throws Exception {
        if (!CollectionUtils.isEmpty(containerTaskList)) {
            Map<String, StationOBCarryTaskDto> doContainerMap = obCarryTaskList.stream().collect(Collectors.toMap(StationOBCarryTaskDto::getContainerNo, o -> o));
            Map<String, List<ContainerTaskDismantleDto>> containerTaskMap = containerTaskList.stream().collect(Collectors.groupingBy(ContainerTaskDismantleDto::getContainerNo));

            //确认当前托盘准备发送的任务 是执行的哪条任务
            List<String> useContainerNos = new ArrayList<>();
            List<Integer> updateDismantleList = new ArrayList<>();
            for (Map.Entry<String, StationOBCarryTaskDto> entry : doContainerMap.entrySet()) {
                useContainerNos.add(entry.getKey());
                if (containerTaskMap.containsKey(entry.getKey())) {
                    //获取托盘的所有任务
                    List<ContainerTaskDismantleDto> dismantleDtos = containerTaskMap.get(entry.getKey());
                    //判断当前待发任务去的零发整还是总拣站台
                    //判断发送的类型(终点区域是否为站台)
                    StationCfg stationCfg = stationCfgList.stream().filter(o -> o.getAreaNo().equals(entry.getValue().getTargetAreaNo())).findFirst().orElse(null);
                    if (stationCfg == null) {
                        continue;
                    }
                    if (stationCfg.getStationType().equals(StationTypeEnum.LFZ_TYPE.getCode())) {
                        //零发整站台
                        List<Integer> tempTaskIdList = dismantleDtos.stream().filter(o -> o.getType() == 1).map(ContainerTaskDismantleDto::getId).collect(Collectors.toList());
                        //修改零发整容器状态
                        updateDismantleList.addAll(tempTaskIdList);
                        ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put("containerNo", entry.getKey()).getMap());
                        if (Objects.equals(containerInfo.getContainerType(), 4)) {
                            PalletInfo palletInfo = palletInfoMapper.findByMap(MapUtils.put("palletNo", containerInfo.getContainerNo()).getMap(), PalletInfo.class).get(0);
                            palletInfo.setStatus(1);
                            palletInfo.setSubArea(stationCfg.getAreaNo());
                            palletInfoMapper.update(palletInfo);
                        }
                    } else {
                        //拆零站台
                        List<Integer> tempTaskIdList = dismantleDtos.stream().filter(o -> o.getType() == 2).map(ContainerTaskDismantleDto::getId).collect(Collectors.toList());
                        //修改拆零容器状态
                        updateDismantleList.addAll(tempTaskIdList);
                        ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put("containerNo", entry.getKey()).getMap());
                        if (Objects.equals(containerInfo.getContainerType(), 4)) {
                            PalletInfo palletInfo = palletInfoMapper.findByMap(MapUtils.put("palletNo", containerInfo.getContainerNo()).getMap(), PalletInfo.class).get(0);
                            palletInfo.setStatus(1);
                            palletInfo.setSubArea(stationCfg.getAreaNo());
                            palletInfoMapper.update(palletInfo);
                        }
                    }
                }
            }
            //已处理的容器任务数据
            if (!CollectionUtils.isEmpty(useContainerNos)) {
                Criteria criteria = new Criteria(ContainerTaskDismantle.class);
                criteria.setRestriction(Restrictions.in("id", updateDismantleList.toArray()));
                containerTaskDismantleService.updateMapByCriteria(MapUtils.put("status", ContainerTaskStatusConstants.START_STATUS).getMap(), criteria);

                criteria = new Criteria(ContainerInfo.class);
                criteria.setRestriction(Restrictions.in("containerNo", useContainerNos.toArray()));
                containerInfoService.updateByMap(MapUtils.put("taskType", BaseTaskTypeConstants.DISMANTLE_OUTBOUND_TYPE).put("updateTime", LocalDateTime.now()).getMap(), criteria);

                criteria = new Criteria(ContainerTask.class);
                criteria.setRestriction(Restrictions.in("containerNo", useContainerNos.toArray()));
                containerTaskService.updateMapByCriteria(MapUtils.put("status", ContainerTaskStatusConstants.START_STATUS).put("updateTime", new Date()).getMap(), criteria);

                List<ContainerTask> containerTasks = containerTaskService.findByCriteria(criteria);
                updateOutTask(containerTasks);
            }
        }
    }


    private void updateOutTask(List<ContainerTask> containerTaskList) throws Exception {
        BizOutboundTaskDetail outTaskDetail = null;
        BizOutboundTask outTask = null;
        Criteria criteria = null;
        for (ContainerTask containerTask : containerTaskList) {
            //判断任务明细是否完成
            criteria = new Criteria(ContainerTask.class);
            criteria.setRestriction(Restrictions.eq("outboundDetailId", containerTask.getOutboundDetailId())
                    .and(Restrictions.lt("status", ContainerTaskStatusConstants.START_STATUS)));
            long count = containerTaskService.findCountByCriteria(criteria);
            if (count == 0) {
                outTaskDetail = bizOutboundTaskDetailService.findById(containerTask.getOutboundDetailId());
                if (outTaskDetail == null) {
                    throw new Exception("出库任务明细不存在，任务ID：" + containerTask.getOutboundDetailId());
                }
                outTask = bizOutboundTaskService.findById(containerTask.getOutboundId());
                if (outTaskDetail.getStatus() < BaseStatusEnum.STATUS_CARRY.getCode() && outTask.getIsBindGrid() == 1) {
                    outTaskDetail.setActQty(outTaskDetail.getPlanQty());
                    outTaskDetail.setStatus(BaseStatusEnum.STATUS_CARRY.getCode());
                    outTaskDetail.setUpdateTime(LocalDateTime.now());
                    bizOutboundTaskDetailService.update(outTaskDetail);
                }
            }
            //判断主任务是否完成
            criteria = new Criteria(BizOutboundTaskDetail.class);
            criteria.setRestriction(Restrictions.eq("outboundId", containerTask.getOutboundId())
                    .and(Restrictions.lt("status", BaseStatusEnum.STATUS_CARRY.getCode())));
            count = bizOutboundTaskDetailService.findCountByCriteria(criteria);
            if (count == 0) {
                outTask = bizOutboundTaskService.findById(containerTask.getOutboundId());
                if (outTask == null) {
                    throw new Exception("出库任务不存在，任务ID：" + containerTask.getOutboundId());
                }
                if (outTask.getStatus() < BaseStatusEnum.STATUS_CARRY.getCode() && outTask.getIsBindGrid() == 1) {
                    outTask.setStatus(BaseStatusEnum.STATUS_CARRY.getCode());
                    outTask.setUpdateTime(LocalDateTime.now());
                    bizOutboundTaskService.update(outTask);
                }
            }
        }
    }

    /**
     * 组装区域数据（查route和warehouse）
     *
     * @param areaList
     * @param stationCfgList
     * @param containerList
     * @param stationOBDispatchDto
     */
    private void assembleAreaData(List<StationOBAreaDto> areaList, List<StationCfg> stationCfgList, List<StationOBContainerDto> containerList, StationOBDispatchDto stationOBDispatchDto) throws Exception {
        List<String> allAreaList = new ArrayList<>();
        //获取库区
        Criteria criteria = new Criteria(LocationCfg.class);
        criteria.setRestriction(Restrictions.in("type", new Integer[]{LocationCfgConstants.AGVL_HJ, LocationCfgConstants.AGVL_TP}));
        List<LocationCfg> locations = locationCfgService.findByCriteria(criteria);
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(locations), "库区未配置");
        //todo 2024/5/15 增加一个拆零总拣缓存区
        allAreaList.add("AGVCACHE01");
        //获取拆零、零发整站台
        List<String> taskSourceAreaNoList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.LFZ_TYPE.getCode()) || o.getStationType().equals(StationTypeEnum.ZJ_SON_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(taskSourceAreaNoList), "站台信息未配置");
        allAreaList.addAll(taskSourceAreaNoList);

        //获取叫料站台
        List<String> stationAreaList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.CL_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
        allAreaList.addAll(stationAreaList);

        List<String> noTaskTargetAreaNoList = locations.stream().map(LocationCfg::getAreaNo).collect(Collectors.toList());
        allAreaList.addAll(noTaskTargetAreaNoList);
        //获取x,y
        List<WhArea> areaByAreaNos = plgFeignRouteService.getAreaByAreaNos(allAreaList);
        Map<String, WhArea> whMap = areaByAreaNos.stream().collect(Collectors.toMap(WhArea::getAreaNo, o -> o));

        final List<ContainerInfo> containerInfoList = containerInfoService.findByMap(null);
        final Map<String, ContainerInfo> containerInfoMap = containerInfoList.stream().collect(Collectors.toMap(ContainerInfo::getContainerNo, o -> o));
        //获取区域到位托盘
        List<ContainerLocation> containerLocationList = plgFeignRouteService.findFreeContainerByAreaNo(allAreaList.stream().collect(Collectors.joining(",")));
        // TODO: 2024/5/15 拆零出库调度修改，拆零站台增加缓存托盘
        getFreeContainer(stationCfgList, containerLocationList);
        Map<String, List<ContainerLocation>> containerMap = containerLocationList.stream().collect(Collectors.groupingBy(ContainerLocation::getCurrentArea));

        //获取到位托盘点位
        List<WhLocator> whLocatorList = plgFeignRouteService.getLocatorByLocation(containerLocationList.stream().map(ContainerLocation::getCurrentLocation).collect(Collectors.toList()));
        Map<String, WhLocator> locatorMap = whLocatorList.stream().collect(Collectors.toMap(WhLocator::getLocationNo, o -> o));

        //获取可用货位
        // TODO: 2024/5/15 拆零出库调度修改，拆零站台增加缓存托盘 
        Map<String, AreaLocationCountDto> locationCountMap = getFreeLocation(allAreaList, stationCfgList);
        /*List<AreaLocationCountDto> areaLocationCountDtoList = plgFeignRouteService.queryAreaLocationCountDtoList(allAreaList);
        Map<String,AreaLocationCountDto> locationCountMap = areaLocationCountDtoList.stream().collect(Collectors.toMap(AreaLocationCountDto::getAreaNo,o->o));
*/
        log.info(String.format("4.0调度route可用货位数：【%s】", JSONObject.toJSONString(locationCountMap)));
        List<StationOBAreaContainerDto> containerDtoList = null;
        StationOBAreaContainerDto stationOBAreaContainerDto = null;
        StationOBAreaDto stationOBAreaDto = null;

        Map<String, List<StationCfg>> map = stationCfgList.stream().collect(Collectors.groupingBy(StationCfg::getAreaNo));
        for (String areaNo : allAreaList) {
            stationOBAreaDto = new StationOBAreaDto();
            try {
                List<StationCfg> stationCfgs = map.get(areaNo);
                if (CollectionUtil.isNotEmpty(stationCfgs)) {
                    StationCfg stationCfg = stationCfgs.get(0);
                    StationOBRangeDto stationOBRangeDto = new StationOBRangeDto();
                    stationOBRangeDto.setMinX(stationCfg.getMinX());
                    stationOBRangeDto.setMaxX(stationCfg.getMaxX());
                    stationOBRangeDto.setMinY(stationCfg.getMinY());
                    stationOBRangeDto.setMaxY(stationCfg.getMaxY());
                    stationOBAreaDto.setRange(stationOBRangeDto);
                }
            } catch (Exception e) {
                log.error("获取库区范围失败：" + e.getMessage(), e);
            }
            stationOBAreaDto.setAreaNo(areaNo);
            stationOBAreaDto.setX(0);
            stationOBAreaDto.setY(0);
            if (whMap.containsKey(areaNo)) {
                stationOBAreaDto.setX(whMap.get(areaNo).getPointX());
                stationOBAreaDto.setY(whMap.get(areaNo).getPointY());
            }
            stationOBAreaDto.setPriority(5);
            if (stationAreaList.contains(areaNo)) {
                stationOBAreaDto.setPriority(1);
            } else if ("AGVCACHE01".equals(areaNo)) {
                stationOBAreaDto.setPriority(6);
            }
            stationOBAreaDto.setTaskSourceAreaNoList(allAreaList.stream().filter(o -> !areaNo.equals(o)).collect(Collectors.toList()));
            if (stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_SON_TYPE.getCode()))
                    .map(StationCfg::getAreaNo).collect(Collectors.toList()).contains(areaNo)) {
                stationOBAreaDto.setCacheAreaNoList(Arrays.asList("AGVCACHE01"));
            }
            long count = taskSourceAreaNoList.stream().filter(o -> o.equals(areaNo)).count();
            stationOBAreaDto.setSendNoTaskContainer(count > 0);

            containerDtoList = new ArrayList<>();
            if (containerMap.containsKey(areaNo)) {
                List<ContainerLocation> containerLocations = containerMap.get(areaNo);
                for (ContainerLocation containerLocation : containerLocations) {
                    stationOBAreaContainerDto = new StationOBAreaContainerDto();
                    stationOBAreaContainerDto.setContainerNo(containerLocation.getContainerNo());
                    // TODO: 2023/9/28  //容器点位
                    stationOBAreaContainerDto.setX(0);
                    stationOBAreaContainerDto.setY(0);
                    if (locatorMap.containsKey(containerLocation.getCurrentLocation())) {
                        stationOBAreaContainerDto.setX(locatorMap.get(containerLocation.getCurrentLocation()).getX());
                        stationOBAreaContainerDto.setY(locatorMap.get(containerLocation.getCurrentLocation()).getY());
                    }
                    stationOBAreaContainerDto.setFinishTask(true);
                    if (containerInfoMap.containsKey(containerLocation.getContainerNo())) {
                        ContainerInfo containerInfo = containerInfoMap.get(containerLocation.getContainerNo());
                        stationOBAreaContainerDto.setFinishTask(Arrays.asList(ContainerTaskTypeConstants.OUTBOUND_RETURN, ContainerTaskTypeConstants.IDLE).contains(containerInfo.getTaskType()));
                    }
                    containerDtoList.add(stationOBAreaContainerDto);
                }
            }
            stationOBAreaDto.setContainerList(containerDtoList);
            stationOBAreaDto.setUseLocatorCount(0);
            stationOBAreaDto.setFreeLocatorCount(0);
            if (locationCountMap.containsKey(areaNo)) {
                stationOBAreaDto.setUseLocatorCount(locationCountMap.get(areaNo).getUseCount());
                stationOBAreaDto.setFreeLocatorCount(locationCountMap.get(areaNo).getFreeCount());
            }
            areaList.add(stationOBAreaDto);
        }

        //托盘回库区域
        stationOBDispatchDto.setNoTaskAreaAction((container -> {
            if (container == null || StringUtils.isEmpty(container.getContainerNo())) {
                return new ArrayList<>();
            }
            ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put("containerNo", container.getContainerNo()).getMap());
            String areaNo = locations.stream().filter(o -> o.getType() == LocationCfgConstants.AGVL_TP).map(LocationCfg::getAreaNo).findFirst().orElse(null);
            if (Integer.parseInt(ContainerTypeConstants.CONTAINER_TYPE_HJ) == containerInfo.getContainerType()) {
                areaNo = locations.stream().filter(o -> o.getType() == LocationCfgConstants.AGVL_HJ).map(LocationCfg::getAreaNo).findFirst().orElse(null);
            }
            return Arrays.asList(areaNo);
        }));
    }

    private void getFreeContainer(List<StationCfg> stationCfgList, List<ContainerLocation> containerLocationList) throws Exception {
        String areaNo = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_TYPE.getCode())).map(StationCfg::getAreaNo).findFirst().orElse(null);
        List<String> sonStationList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_SON_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(sonStationList), "总拣子站台信息未配置");
        List<ContainerLocation> sonContainerLocationList = plgFeignRouteService.findFreeContainerByAreaNo(sonStationList.stream().collect(Collectors.joining(",")));
        if (CollectionUtils.isEmpty(sonContainerLocationList)) {
            return;
        }
        sonContainerLocationList.forEach(value -> {
            value.setCurrentArea(areaNo);
        });
        containerLocationList.addAll(sonContainerLocationList);
    }

    private Map<String, AreaLocationCountDto> getFreeLocation(List<String> allAreaList, List<StationCfg> stationCfgList) throws Exception {
        String areaNo = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_TYPE.getCode())).map(StationCfg::getAreaNo).findFirst().orElse(null);
        List<AreaLocationCountDto> areaLocationCountDtoList = plgFeignRouteService.queryAreaLocationCountDtoList(allAreaList);
        List<String> sonStationList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_SON_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(sonStationList), "总拣子站台信息未配置");
        List<AreaLocationCountDto> sonLocationCountDtoList = plgFeignRouteService.queryAreaLocationCountDtoList(sonStationList);
        int freeTotal = sonLocationCountDtoList.stream().mapToInt(AreaLocationCountDto::getFreeCount).sum();
        int useTotal = sonLocationCountDtoList.stream().mapToInt(AreaLocationCountDto::getUseCount).sum();
        int locatorTotal = sonLocationCountDtoList.stream().mapToInt(AreaLocationCountDto::getLocatorCount).sum();
        AreaLocationCountDto areaLocationCountDto = new AreaLocationCountDto();
        areaLocationCountDto.setAreaNo(areaNo);
        areaLocationCountDto.setLocatorCount(locatorTotal);
        areaLocationCountDto.setFreeCount(freeTotal);
        areaLocationCountDto.setUseCount(useTotal);
        areaLocationCountDtoList.add(areaLocationCountDto);
        Map<String, AreaLocationCountDto> locationCountMap = areaLocationCountDtoList.stream().collect(Collectors.toMap(AreaLocationCountDto::getAreaNo, o -> o));
        return locationCountMap;
    }


    /**
     * //组装任务容器数据(查业务数据)
     *
     * @param containerList
     * @param containerTaskList
     * @param stationCfgList
     */
    private void assembleContainerData(List<StationOBContainerDto> containerList, List<ContainerTaskDismantleDto> containerTaskList, List<StationCfg> stationCfgList) throws Exception {
        if (CollectionUtils.isEmpty(containerTaskList)) {
            return;
        }
        String orderDoneRateCount = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.ORDER_DONE_RATE));

        //获取订单明细
        List<Integer> outboundIds = containerTaskList.stream().map(ContainerTaskDismantleDto::getOutboundId).distinct().collect(Collectors.toList());
        Criteria criteria = new Criteria(BizOutboundTaskDetail.class);
        criteria.restrictionBuilder().in(BizOutboundTaskDetail::getOutboundId, outboundIds).build();
        List<BizOutboundTaskDetail> outboundTaskDetailList = bizOutboundTaskDetailService.findByCriteria(criteria);
        //获取容器任务商品信息
        List<String> itemIds = containerTaskList.stream().map(ContainerTaskDismantleDto::getItemId).distinct().collect(Collectors.toList());
        List<ItemSyncVO> itemSyncVOS = itemService.queryItemMst(itemIds);

        //根据容器号分组
        Map<String, List<ContainerTaskDismantleDto>> containerTaskMap = containerTaskList.stream().collect(Collectors.groupingBy(ContainerTaskDismantleDto::getContainerNo));

        List<ContainerLocationVo> locationByContainerList = routeFeignService.findLocationByContainerList(containerTaskList.stream().map(ContainerTaskDismantleDto::getContainerNo).collect(Collectors.toList()));
        Map<String, List<ContainerLocationVo>> containerMap = locationByContainerList.stream().collect(Collectors.groupingBy(group -> group.getContainerNo()));


        StationOBContainerDto stationOBContainerDto = null;
        List<StationOBContainerTaskDto> taskList = null;
        StationOBContainerTaskDto task = null;
        for (Map.Entry<String, List<ContainerTaskDismantleDto>> entry : containerTaskMap.entrySet()) {
            String containerNo = entry.getKey();
            List<ContainerTaskDismantleDto> tempTask = entry.getValue();

            Set<String> containerTaskSet = tempTask.stream().map(o -> o.getContainerNo() + "-" + o.getType()).collect(Collectors.toSet());

            //查询是否为在途追加的托盘
            ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put("containerNo", containerNo).getMap());
            if (containerInfo.getTaskType() != ContainerTaskTypeConstants.IDLE && containerInfo.getTaskType() != ContainerTaskTypeConstants.OUTBOUND_RETURN) {
                log.info(String.format("发送出库搬运任务：托盘：[%s]正在搬运，等待中", containerNo));
                continue;
            }
            //判断如果当前的托盘为拼托 查有无追加的托盘为多订单整托的
            logicService.updateContainerType(tempTask.get(0).getContainerType(), containerNo);

            stationOBContainerDto = new StationOBContainerDto();
            stationOBContainerDto.setContainerNo(containerNo);


            String WEIGHT_SWITCH = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.WEIGHT_SWITCH));

            if (SwitchEnum.OPEN.getCode().equals(WEIGHT_SWITCH)) {
                List<String> containerItemList = tempTask.stream().map(ContainerTaskDismantleDto::getItemId).distinct().collect(Collectors.toList());
                List<ItemSyncVO> collect = itemSyncVOS.stream().filter(item -> containerItemList.contains(item.getItemId())).collect(Collectors.toList());
//            ItemSyncVO itemSyncVO = collect.stream().max(Comparator.comparing(o -> o.getUomList().get(0).getWeight())).orElseThrow(() -> new Exception(String.format("容器号:%s 未获取到最大重量", containerNo)));
                ItemSyncVO itemSyncVO = collect.stream().max(Comparator.comparing(o -> Objects.isNull(o.getItemIsWeight()) ? 0 : o.getItemIsWeight().intValue()))
                        .orElseThrow(() -> new Exception(String.format("容器号:%s 未获取到最大重量", containerNo)));
//                ItemSyncVO itemSyncVO = collect.stream().max(Comparator.comparing(ItemSyncVO::getItemIsWeight)).orElseThrow(() -> new Exception(String.format("容器号:%s 未获取到最大重量", containerNo)));
                //最大重量优先级
                stationOBContainerDto.setPriority1(Objects.isNull(itemSyncVO.getItemIsWeight()) ? 0 : itemSyncVO.getItemIsWeight().intValue());
//                stationOBContainerDto.setPriority1(itemSyncVO.getUomList().get(0).getWeight().divide(BigDecimal.valueOf(5)).intValue());
            } else {
                stationOBContainerDto.setPriority1(1);
            }

            //计算容器订单成单率数量
            int detailCount = 0;
            List<Integer> outboundIdList = tempTask.stream().map(ContainerTaskDismantleDto::getOutboundId).collect(Collectors.toList());
            Map<Integer, List<BizOutboundTaskDetail>> outboundDetailMap = outboundTaskDetailList.stream().filter(item -> outboundIdList.contains(item.getOutboundId())).collect(Collectors.groupingBy(BizOutboundTaskDetail::getOutboundId));
            for (List<BizOutboundTaskDetail> value : outboundDetailMap.values()) {
                if (value.size() <= Integer.parseInt(orderDoneRateCount)) {
                    detailCount += 1;
                }
            }
            stationOBContainerDto.setBoCi(tempTask.stream().sorted(Comparator.comparing(ContainerTaskDismantleDto::getEisWaveNo)).findFirst().get().getEisWaveNo());
            stationOBContainerDto.setPriority2(detailCount);
            stationOBContainerDto.setPriority3(tempTask.size());
            //计算容器订单剩余条目数量
            long count = outboundTaskDetailList.stream().filter(item -> outboundIdList.contains(item.getOutboundId()) && item.getStatus() < BaseStatusEnum.STATUS_CARRY.getCode()).count();
            stationOBContainerDto.setPriority4((int) count);

            //容器有哪些任务
            taskList = new ArrayList<>();
            for (String key : containerTaskSet) {
                task = new StationOBContainerTaskDto();
                task.setContainerNo(containerNo);
                String[] keyArr = key.split("-");
                //默认拆零
//                task.setPriority(priority);
                //每个任务可去的站台集合
                List<String> stationList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.ZJ_SON_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
                AssertUtils.isNotTrue(CollectionUtils.isEmpty(stationList), "总拣站台未配置");

                String dispatchSendSwitch = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.DISPATCH_SEND_SWITCH));
                if (SwitchEnum.OPEN.getCode().equals(dispatchSendSwitch)) {
                    task.setTaskTargetAreaNoList(stationList);
                }
                if (keyArr[1].equals("1")) {
                    //如果有零发整
//                    task.setPriority(priority - 1);
                    //每个任务可去的站台集合
                    stationList = stationCfgList.stream().filter(o -> o.getStationType().equals(StationTypeEnum.LFZ_TYPE.getCode())).map(StationCfg::getAreaNo).collect(Collectors.toList());
                    AssertUtils.isNotTrue(CollectionUtils.isEmpty(stationList), "零发整站台未配置");
                    task.setTaskTargetAreaNoList(stationList);
                }
                taskList.add(task);
            }
            if (containerInfo.getTaskType() == ContainerTaskTypeConstants.OUTBOUND_RETURN) {
                //判断托盘的当前区域是否为托盘任务要去区域
                Iterator<StationOBContainerTaskDto> iterator = taskList.iterator();
                while (iterator.hasNext()) {
                    StationOBContainerTaskDto stationOBContainerTaskDto = iterator.next();
                    List<String> targetAreaNoList = stationOBContainerTaskDto.getTaskTargetAreaNoList();
                    if (containerMap.containsKey(containerNo) && targetAreaNoList.contains(containerMap.get(containerNo).get(0).getCurrentArea())) {
                        iterator.remove();
                    }
                }
            }
            stationOBContainerDto.setContainerTaskList(taskList);
            if (CollectionUtil.isNotEmpty(taskList)) {
                containerList.add(stationOBContainerDto);
            }
        }
    }

    /**
     * 打印单据定时器（包含 调用WMS 订单绑定格口回告、出库复核结果回告、面单打印回告、全零发整打印）
     */
    @Override
    public void doPrint(PrintTask printTask) {
        //推送打印数据
        try {
            switch (printTask.getType()) {
                case 1:
                    //1面单打印
                    BizOutboundTask bizOutboundTask = bizOutboundTaskService.findById(printTask.getWmsOutTaskId());
                    WmsApplePrintDto wmsApplePrintDto = new WmsApplePrintDto();
                    wmsApplePrintDto.setWarehouseId(bizOutboundTask.getWmsWarehouseId());
                    wmsApplePrintDto.setTaskId(bizOutboundTask.getUpperSystemTaskId());
                    wmsApplePrintDto.setBillNo(bizOutboundTask.getBillNo());
                    wmsApplePrintDto.setEnterpriseId(bizOutboundTask.getEnterpriseId());
                    wmsApplePrintDto.setGridNo(printTask.getGridNo());
                    wmsApplePrintDto.setLabelCount(1);
                    wmsApplePrintDto.setPackFlag(Objects.isNull(bizOutboundTask.getBillCount()) || bizOutboundTask.getBillCount() <= 1 ? 0 : 1);
                    wmsApplePrintService.execute(wmsApplePrintDto);
                    break;
                case 10:
                    //面单打印
                    WmsApplePrintDto data = JSONUtil.toBean(printTask.getPrintData(), WmsApplePrintDto.class);
                    wmsApplePrintService.execute(data);
                    break;
                case 2:
                    //2.拆零订单绑定格口推送
                    BizOutboundTask bizOutboundTask1 = bizOutboundTaskService.findById(printTask.getWmsOutTaskId());
                    WmsBindGirdDto wmsBindGirdDto = new WmsBindGirdDto();
                    wmsBindGirdDto.setMsgId(bizOutboundTask1.getExtend1());
                    wmsBindGirdDto.setWarehouseId(bizOutboundTask1.getWmsWarehouseId());
                    wmsBindGirdDto.setTaskId(bizOutboundTask1.getUpperSystemTaskId());
                    wmsBindGirdDto.setBillNo(bizOutboundTask1.getBillNo());
                    wmsBindGirdDto.setEnterpriseId(bizOutboundTask1.getEnterpriseId());
                    wmsBindGirdDto.setGridNo(Arrays.asList(printTask.getGridNo()));
                    wmsBindGirdBackService.execute(wmsBindGirdDto);
                    break;
                case 3:
                    // 3.复核结果回传
                    WmsOfferBackDto wmsOfferBackDto = JSONArray.parseObject(printTask.getPrintData()).toJavaObject(WmsOfferBackDto.class);
                    Criteria criteria = new Criteria(PrintScheme.class);
                    criteria.setRestriction(Restrictions.eq("printType", 1).and(Restrictions.eq("printState", 0)));
                    criteria.setOrder(Order.newInstance().desc("updateTime"));
                    PrintScheme printScheme = printSchemeService.findByCriteria(criteria).stream().findFirst().orElseThrow(() -> new PrologException("复核结果回传：打印模板数据未配置"));
                    ;
                    wmsOfferBackDto.setPrintUrl(printScheme.getPrintUrl());
                    wmsOutRecheckBackService.execute(wmsOfferBackDto);

                    printScheme.setUpdateTime(new Date());
                    printSchemeService.update(printScheme);
                    break;
                case 5:
                    // 5.零发整面单 清单， 发票 打印
                    List<PrintParam> printList = new ArrayList<PrintParam>();
                    PrintParam printParamParam4 = new PrintParam();
                    printParamParam4.setPrintBillCode(FullPrintEnum.PRINT5.getCode());
                    Map<String, Object> params4 = new HashMap<>();
                    params4.put("billNo", printTask.getPrintData());
                    printParamParam4.setParams(params4);
                    printParamParam4.setUsername(printTask.getExtend1());
                    printList.add(printParamParam4);

                    PrintParam printParamParam5 = new PrintParam();
                    printParamParam5.setPrintBillCode(FullPrintEnum.PRINT2.getCode());
                    Map<String, Object> params5 = new HashMap<>();
                    params5.put("orderNo", printTask.getPrintData());
                    printParamParam5.setParams(params5);
                    printParamParam5.setUsername(printTask.getExtend1());
                    printList.add(printParamParam5);

                    PrintParam printParamParam6 = new PrintParam();
                    printParamParam6.setPrintBillCode(FullPrintEnum.PRINT3.getCode());
                    Map<String, Object> params6 = new HashMap<>();
                    params6.put("billId", printTask.getPrintData());
                    printParamParam6.setParams(params6);
                    printParamParam6.setUsername(printTask.getExtend1());
                    printList.add(printParamParam6);

                    RestMessage<?> result = baseCommonFeign.executePrint(printList);
                    if (!result.isSuccess()) {
                        throw new PrologException("申请打印wms返回失败：" + result.getMessage() + "-->参数：" + JsonUtils.toString(printList));
                    }
                    printTask.setPrintData(JsonUtils.toString(printList));
                    break;
                case 6:
                    BizOutboundTask bizOutboundTask6 = bizOutboundTaskService.findById(printTask.getWmsOutTaskId());
                    List<PrintParam> printParamList6 = new ArrayList<PrintParam>();
                    PrintParam printParamParam7 = new PrintParam();
                    printParamParam7.setPrintBillCode(FullPrintEnum.PRINT4.getCode());
                    Map<String, Object> params7 = new HashMap<>();
                    params7.put("billId", bizOutboundTask6.getBillNo());
                    printParamParam7.setParams(params7);
                    printParamList6.add(printParamParam7);

                    RestMessage<?> restMessage1 = baseCommonFeign.executePrint(printParamList6);
                    if (!restMessage1.isSuccess()) {
                        throw new PrologException("申请打印wms返回失败：" + restMessage1.getMessage() + "-->参数：" + JsonUtils.toString(printParamList6));
                    }
                    printTask.setPrintData(JsonUtils.toString(printParamList6));
                    break;
                case 7:
                    BizOutboundTask bizOutboundTask7 = bizOutboundTaskService.findById(printTask.getWmsOutTaskId());
                    List<PrintParam> printParamList7 = new ArrayList<PrintParam>();
                    PrintParam printParamParam8 = new PrintParam();
                    printParamParam8.setPrintBillCode(FullPrintEnum.PRINT5.getCode());
                    Map<String, Object> params8 = new HashMap<>();
                    params8.put("billId", bizOutboundTask7.getBillNo());
                    printParamParam8.setParams(params8);
                    printParamParam8.setUsername(printTask.getExtend1());
                    printParamList7.add(printParamParam8);

                    RestMessage<?> restMessage2 = baseCommonFeign.executePrint(printParamList7);
                    if (!restMessage2.isSuccess()) {
                        throw new PrologException("申请打印wms返回失败：" + restMessage2.getMessage() + "-->参数：" + JsonUtils.toString(printParamList7));
                    }
                    printTask.setPrintData(JsonUtils.toString(printParamList7));
                    break;
                case 4:
                    BizOutboundTask bizOutboundTask2 = bizOutboundTaskService.findById(printTask.getWmsOutTaskId());
                    List<PrintParam> printParamList = new ArrayList<PrintParam>();
                    List<OrderDetailDto> detailList = bizOutboundTaskDetailService.getByOrderIds(Arrays.asList(bizOutboundTask2.getId()));
                    List<String> itemList = detailList.stream().map(o -> o.getItemId() + "&&" + o.getLotId()).distinct().collect(Collectors.toList());
                    for (String item : itemList) {
                        String[] itemsArray = item.split("&&");
                        PrintParam printParamParam = new PrintParam();
                        printParamParam.setPrintBillCode("imgManage-SYZL-pdf");
                        Map<String, Object> params = new HashMap<>();
                        params.put("batchId", itemsArray[1]);
                        params.put("itemId", itemsArray[0]);
                        printParamParam.setParams(params);
                        printParamList.add(printParamParam);

                        PrintParam printParamParam2 = new PrintParam();
                        printParamParam2.setPrintBillCode("imgManage-ZJBG-pdf");
                        Map<String, Object> params2 = new HashMap<>();
                        params2.put("batchId", itemsArray[1]);
                        params2.put("itemId", itemsArray[0]);
                        printParamParam2.setParams(params2);
                        printParamList.add(printParamParam2);

                        PrintParam printParamParam3 = new PrintParam();
                        printParamParam3.setPrintBillCode("imgManage-GYS-pdf");
                        Map<String, Object> params3 = new HashMap<>();
                        params3.put("batchId", itemsArray[1]);
                        params3.put("itemId", itemsArray[0]);
                        printParamParam3.setParams(params3);
                        printParamList.add(printParamParam3);
                    }


                    PrintParam printParamParam3 = new PrintParam();
                    printParamParam3.setPrintBillCode(FullPrintEnum.PRINT4.getCode());
                    Map<String, Object> params3 = new HashMap<>();
                    params3.put("billId", bizOutboundTask2.getBillNo());
                    printParamParam3.setParams(params3);
                    printParamList.add(printParamParam3);

                    RestMessage<?> restMessage = baseCommonFeign.executePrint(printParamList);
                    if (!restMessage.isSuccess()) {
                        throw new PrologException("申请打印wms返回失败：" + restMessage.getMessage() + "-->参数：" + JsonUtils.toString(printParamList));
                    }
                    printTask.setPrintData(JsonUtils.toString(printParamList));
                    break;
            }
            printTask.setErrorMsg("推送成功");
            printTask.setStatus(1);
        } catch (Exception e) {
            printTask.setStatus(2);
            //面单申请打印失败，不需要重试，后续需要打印手动在接口平台重试
            if (Arrays.asList(1, 10).contains(printTask.getType())) {
                printTask.setStatus(1);
            }
            if (StrUtil.isNotBlank(e.getMessage())) {
                printTask.setErrorMsg(e.getMessage());
            }

        }
        //成功修改打印状态，增加次数
        printTask.setPrintCount(printTask.getPrintCount() + 1);
        printTask.setUpdateTime(new Date());
        printTaskService.update(printTask);
    }

    /**
     * 拆零区盘点/养护库存定位调度
     */
    @Override
    public void createContainerTask() {
        //1 获取所有拆零区盘点/养护新建订单
        List<BizOutboundTask> outboundList = bizOutboundTaskService.getAGVLPdYhOrder();
        if (CollectionUtils.isEmpty(outboundList)) {
            log.info("暂无拆零区盘点/养护订单");
            return;
        }
        //2 获取拆零区所有库存信息
        List<ContainerInfoDto> containerInfoList = containerInfoService.findAGVLContainerInfo();
        if (CollectionUtils.isEmpty(containerInfoList)) {
            log.info("暂无拆零区库存");
            return;
        }
        //3 订单池排序
        outboundList.sort(Comparator.comparing(BizOutboundTask::getPriority).thenComparing(BizOutboundTask::getCreateTime));
        //4 根据物料批次分组
        Map<String, BigDecimal> storeMap =
                containerInfoList.stream().collect(Collectors.toMap(ContainerInfoDto::getBusinessProperty2, ContainerInfoDto::getQty, (k1, k2) -> k1.add(k2)));
        for (BizOutboundTask outboundTask : outboundList) {
            //5 判断此订单详情是否存在对应库存
            if (computeStore(outboundTask, storeMap)) {
                //6 生成容器任务
                createContainerTask(outboundTask, containerInfoList);
                //7 修改订单状态
                handleOrder(outboundTask);
            }
        }
    }

    private void handleOrder(BizOutboundTask outboundTask) {
        List<BizOutboundTaskDetail> bizOutboundTaskDetailList = outboundTask.getSubList();
        bizOutboundTaskDetailList.forEach(k -> {
            k.setStatus(OrderStatusConstants.START_STATUS);
            k.setUpdateTime(LocalDateTime.now());
        });
        bizOutboundTaskDetailService.batchUpdate(bizOutboundTaskDetailList);
        outboundTask.setStatus(OrderStatusConstants.START_STATUS);
        outboundTask.setUpdateTime(LocalDateTime.now());
        bizOutboundTaskService.update(outboundTask);
    }

    private void createContainerTask(BizOutboundTask outboundTask, List<ContainerInfoDto> containerInfoList) {
        Map<String, List<ContainerInfoDto>> itemStore =
                containerInfoList.stream().collect(Collectors.groupingBy(ContainerInfoDto::getBusinessProperty2));
        List<BizOutboundTaskDetail> outboundTaskDetails = outboundTask.getSubList();
        List<ContainerTask> insertContainerTaskList = new ArrayList<>();
        for (BizOutboundTaskDetail outboundTaskDetail : outboundTaskDetails) {
            List<ContainerInfoDto> containerInfoDtoList = itemStore.get(outboundTaskDetail.getBusinessProperty());
            containerInfoDtoList.forEach(item -> {
                ContainerTask containerTask = new ContainerTask();
                containerTask.setContainerNo(item.getContainerNo());
                containerTask.setContainerSubNo(item.getContainerSubNo());
                containerTask.setTaskType(Integer.valueOf(outboundTask.getWorkType()));
                containerTask.setOutboundId(outboundTask.getId());
                containerTask.setOutboundDetailId(outboundTaskDetail.getId());
                containerTask.setContainerType(StrUtil.equals(item.getContainerNo(), item.getContainerSubNo()) ? 1 : 0);
                containerTask.setWaveNo(outboundTask.getWaveNo());
                containerTask.setQty(item.getQty());
                containerTask.setStatus(BaseStatusEnum.STATUS_INIT.getCode());
                containerTask.setCreateTime(LocalDateTime.now());
                containerTask.setWarehouseArea(outboundTask.getWmsLocationCode());
                containerTask.setWmsLocationCode(outboundTask.getWmsLocationCode());
                containerTask.setPriorty(outboundTask.getPriority());
                containerTask.setItemId(item.getItemId());
                containerTask.setLotId(item.getLotId());
                containerTask.setPackId(item.getPackId());
                containerTask.setOwnerId(item.getOwnerId());
                containerTask.setCompanyId(outboundTask.getCompanyId());
                containerTask.setShelvesState(0);
                insertContainerTaskList.add(containerTask);
            });
        }
        if (!insertContainerTaskList.isEmpty()) {
            containerTaskService.saveBatch(insertContainerTaskList);
        }
    }

    private boolean computeStore(BizOutboundTask outboundTask, Map<String, BigDecimal> storeMap) {
        Map<String, BigDecimal> tempMap = storeMap;
        List<BizOutboundTaskDetail> outboundTaskDetailList = outboundTask.getSubList();
        if (CollectionUtil.isEmpty(outboundTaskDetailList)) {
            log.warn("订单id【{}】下无对应订单明细", outboundTask.getId());
            return false;
        }
        for (BizOutboundTaskDetail orderDetail : outboundTaskDetailList) {
            BigDecimal qty = tempMap.get(orderDetail.getBusinessProperty());
            if (Objects.isNull(qty) || qty.compareTo(BigDecimal.ZERO) == 0) {
                log.warn("订单明细【{}】所需的品种【{}】无对应库存", orderDetail.getId(), orderDetail.getBusinessProperty());
                return false;
            } else {
                tempMap.put(orderDetail.getBusinessProperty(), BigDecimal.ZERO);
            }
        }
        storeMap = tempMap;
        return true;
    }

    @Override
    public void mergeContainerToStation() throws Exception {
        Criteria criteria = new Criteria(MergeContainerTask.class);
        criteria.restrictionBuilder().eq(MergeContainerTask::getStatus, BaseStatusEnum.STATUS_INIT.getCode()).build();
        criteria.setOrder(Order.newInstance().asc(MergeContainerTask::getCreateTime));
        List<MergeContainerTask> mergeContainerTaskList = mergeContainerTaskService.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(mergeContainerTaskList)) {
            log.info("暂无合托任务");
            return;
        }
        List<StationCfg> stationCfgList = stationCfgService.findByMap(MapUtils.put("stationType", StationCfgConstants.CL_U).put("taskType", 10).put("isLock", 0).getMap());
        if (CollectionUtil.isEmpty(stationCfgList)) {
            log.info("合托站台无空闲");
            return;
        }
        List<String> targetAreaList = stationCfgList.stream().map(StationCfg::getAreaNo).collect(Collectors.toList());
        AreaLocationCountDto areaLocationCountDto = routeFeignService.queryAreaLocationCountDtoList(targetAreaList).stream().filter(item -> item.getFreeCount() >= 2).collect(Collectors.toList()).stream().findFirst().orElse(null);
        if (Objects.isNull(areaLocationCountDto)) {
            log.info("合托站台无空闲");
            return;
        }
        mergeContainerToStation(mergeContainerTaskList, areaLocationCountDto.getAreaNo());
    }


    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void mergeContainerToStation(List<MergeContainerTask> mergeContainerTaskList, String areaNo) throws Exception {
        MergeContainerTask mergeContainerTask1 = mergeContainerTaskList.get(0);
        MergeContainerTask mergeContainerTask2 = mergeContainerTaskList.stream().filter(item -> !Objects.equals(item.getId(), mergeContainerTask1.getId()) && StrUtil.equals(item.getBillNo(), mergeContainerTask1.getBillNo())).findFirst().orElseThrow(() -> new PrologException(String.format("未找到单号%s合托托盘任务", mergeContainerTask1.getBillNo())));

        //修改状态为开始
        mergeContainerTask1.setStatus(1);
        mergeContainerTask1.setUpdateTime(LocalDateTime.now());
        mergeContainerTask2.setStatus(1);
        mergeContainerTask2.setUpdateTime(LocalDateTime.now());
        mergeContainerTaskService.update(mergeContainerTask1);
        mergeContainerTaskService.update(mergeContainerTask2);

        //修改库存状态为出库中
        Criteria criteria = new Criteria(ContainerInfo.class);
        criteria.restrictionBuilder().in(ContainerInfo::getContainerNo, Arrays.asList(mergeContainerTask1.getContainerNo(), mergeContainerTask2.getContainerNo())).build();
        containerInfoService.updateByMap(MapUtils.put("taskType", ContainerTaskTypeConstants.OUTBOUND).put("updateTime", LocalDateTime.now()).getMap(), criteria);

        //搬运
        List<CarryTask> carryTasks = new ArrayList<>();
        CarryTask carryTask1 = new CarryTask();
        carryTask1.setId(StrUtil.uuid());
        carryTask1.setPalletNo(mergeContainerTask1.getContainerNo());
        carryTask1.setContainerNo(mergeContainerTask1.getContainerNo());
        carryTask1.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
        carryTask1.setEndRegion(areaNo);
        carryTask1.setCreateTime(new Date());
        carryTask1.setBusinessType(String.valueOf(BaseTaskTypeConstants.MERGE_OUT_TYPE));
        carryTask1.setTaskRemark("合托搬运");
        carryTasks.add(carryTask1);
        CarryTask carryTask2 = new CarryTask();
        carryTask2.setId(StrUtil.uuid());
        carryTask2.setPalletNo(mergeContainerTask2.getContainerNo());
        carryTask2.setContainerNo(mergeContainerTask2.getContainerNo());
        carryTask2.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
        carryTask2.setEndRegion(areaNo);
        carryTask2.setCreateTime(new Date());
        carryTask2.setBusinessType(String.valueOf(BaseTaskTypeConstants.MERGE_OUT_TYPE));
        carryTask2.setTaskRemark("合托搬运");
        carryTasks.add(carryTask2);
        routeFeignService.createBatchCarry(carryTasks);
    }
}
