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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.codingapi.tx.annotation.TxTransaction;
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.area.PortInfoAreaDto;
import com.prolog.eis.core.dto.inboundallot.InboundAllotAreaParamDto;
import com.prolog.eis.core.dto.route.*;
import com.prolog.eis.core.model.base.area.WhArea;
import com.prolog.eis.core.model.biz.route.ContainerLocation;
import com.prolog.eis.dao.container.*;
import com.prolog.eis.dao.inbound.BizInboundTaskDetailHisMapper;
import com.prolog.eis.dao.inbound.BizInboundTaskDetailMapper;
import com.prolog.eis.dao.inbound.BizInboundTaskHisMapper;
import com.prolog.eis.dao.inbound.BizInboundTaskMapper;
import com.prolog.eis.dao.outbound.*;
import com.prolog.eis.dto.contaienr.EmptyContainerInboundDto;
import com.prolog.eis.dto.device.DeviceInfoDto;
import com.prolog.eis.dto.inbound.*;
import com.prolog.eis.dto.item.ItemSyncVO;
import com.prolog.eis.dto.page.InboundOrderReqDto;
import com.prolog.eis.dto.page.InboundOrderRespDto;
import com.prolog.eis.dto.wcs.BcrRequestDto;
import com.prolog.eis.dto.wcs.CallbackLayerDTO;
import com.prolog.eis.dto.wms.WmsTaskFinishDto;
import com.prolog.eis.enums.base.BaseInBoundStatusEnum;
import com.prolog.eis.enums.base.BaseStatusEnum;
import com.prolog.eis.enums.base.BaseTypeEnum;
import com.prolog.eis.enums.station.StationTypeEnum;
import com.prolog.eis.enums.wms.WmsCarryTaskInCode;
import com.prolog.eis.enums.wms.WmsCarryTaskType;
import com.prolog.eis.model.carry.WmsCarryTask;
import com.prolog.eis.model.container.*;
import com.prolog.eis.model.device.DeviceInfo;
import com.prolog.eis.model.inbound.BizInboundTask;
import com.prolog.eis.model.inbound.BizInboundTaskDetail;
import com.prolog.eis.model.inbound.BizInboundTaskDetailHis;
import com.prolog.eis.model.inbound.BizInboundTaskHis;
import com.prolog.eis.model.outbound.*;
import com.prolog.eis.model.shelves.PalletInfo;
import com.prolog.eis.router.dto.AreaTaskDto;
import com.prolog.eis.router.vo.ContainerLocationVo;
import com.prolog.eis.service.carry.WmsCarryTaskService;
import com.prolog.eis.service.container.ContainerInfoService;
import com.prolog.eis.service.container.LocationCfgService;
import com.prolog.eis.service.container.StationCfgService;
import com.prolog.eis.service.device.DeviceInfoService;
import com.prolog.eis.service.feign.DismantleFeignService;
import com.prolog.eis.service.feign.FeignGoodsService;
import com.prolog.eis.service.feign.RouteFeignService;
import com.prolog.eis.service.feign.WarehouseService;
import com.prolog.eis.service.inbound.BizInboundTaskService;
import com.prolog.eis.service.wms.WmsInBackService;
import com.prolog.eis.service.wms.WmsTaskFinishBackService;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.beans.BeanUtils;
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.Restrictions;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.UUIDUtils;
import com.prolog.fx.inf.core.Exception.RetryException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.prolog.eis.constants.base.WmsLocationCodeConstants.WARE_HOSE;

@Slf4j
@Service
public class BizInboundTaskServiceImpl implements BizInboundTaskService {

    @Autowired
    private BizInboundTaskMapper bizInboundTaskMapper;
    @Autowired
    private BizInboundTaskDetailMapper bizInboundTaskDetailMapper;
    @Autowired
    private ContainerInfoService containerInfoService;
    @Autowired
    private ContainerInfoDetailMapper containerInfoDetailMapper;
    @Autowired
    private BizInboundTaskHisMapper inboundTaskHisMapper;
    @Autowired
    private BizInboundTaskDetailHisMapper inboundTaskDetailHisMapper;
    @Autowired
    private WmsInBackService wmsInBackService;
    @Autowired
    private RouteFeignService plgFeignRouteService;
    @Autowired
    private DeviceInfoService deviceInfoService;
    @Autowired
    private LocationCfgService locationCfgService;
    @Autowired
    private WmsCarryTaskService wmsCarryTaskService;
    @Autowired
    private StationCfgService stationCfgService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private DismantleFeignService dismantleFeignService;
    @Autowired
    private ContainerTaskMapper containerTaskMapper;
    @Autowired
    private BizOutboundTaskMapper bizOutboundTaskMapper;
    @Autowired
    private BizOutboundTaskDetailMapper bizOutboundTaskDetailMapper;
    @Autowired
    private WmsTaskFinishBackService wmsTaskFinishBackService;
    @Autowired
    private ContainerTaskHisMapper containerTaskHisMapper;
    @Autowired
    private BizOutboundTaskDetailHisMapper bizOutboundTaskDetailHisMapper;
    @Autowired
    private BizOutboundTaskHisMapper bizOutboundTaskHisMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserTemplate userTemplate;
    @Autowired
    private PalletInfoMapper palletInfoMapper;
    @Autowired
    private OrderLogMapper orderLogMapper;
    @Autowired
    private FeignGoodsService feignGoodsService;
    @Autowired
    private ContainerStoreChangeMapper containerStoreChangeService;

    @Override
    public void emptyContainerInbound(EmptyContainerInboundDto emptyContainerInboundDto) throws Exception {
        // 校验托盘号是否在库内
        InBoundDto inBoundDto = new InBoundDto();
        inBoundDto.setContainerNo(emptyContainerInboundDto.getContainerNo());
        inBoundDto.setWmsLocationCode(WmsCarryTaskInCode.MJZ.getCode());
        checkContainerInfo(inBoundDto);
        BizInboundTask bizInboundTask = new BizInboundTask();
        String taskId = UUIDUtils.generate();
        bizInboundTask.setUpperSystemTaskId(taskId);
        bizInboundTask.setWmsWarehouseId(WARE_HOSE);
        bizInboundTask.setWmsLocationCode(WmsCarryTaskInCode.MJZ.getCode());
        bizInboundTask.setBusinessType("-1");
        bizInboundTask.setWorkType("-1");
        bizInboundTask.setContainerType(ContainerInfoTypeConstants.EMPTY_PALLET_PILE);
        bizInboundTask.setBillNo(taskId);
        bizInboundTask.setContainerNo(emptyContainerInboundDto.getContainerNo());
        bizInboundTask.setStatus(ContainerTaskTypeConstants.IDLE);
        bizInboundTask.setCreateTime(LocalDateTime.now());
        bizInboundTaskMapper.save(bizInboundTask);
        BizInboundTaskDetail bizInboundTaskDetail = new BizInboundTaskDetail();
        bizInboundTaskDetail.setInboundId(bizInboundTask.getId());
        bizInboundTaskDetail.setContainerSubNo(emptyContainerInboundDto.getContainerNo());
        bizInboundTaskDetail.setCreateTime(LocalDateTime.now());
        bizInboundTaskDetail.setQty(new BigDecimal(1));
        bizInboundTaskDetail.setSeqNo(taskId);
        bizInboundTaskDetail.setItemId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setLotId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setOwnerId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setPackId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetailMapper.save(bizInboundTaskDetail);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void wmsInCallBack(BizInboundTask inBoundTask) throws Exception {
        List<BizInboundTaskDetail> bizInboundTaskDetailList = bizInboundTaskDetailMapper.findByMap(MapUtils.put("inboundId", inBoundTask.getId()).getMap(), BizInboundTaskDetail.class);
        Assert.notEmpty(bizInboundTaskDetailList, String.format("未查到id【%s】入库任务明细", inBoundTask.getId()));
        if (!inBoundTask.isEmptyInbound()) {
            WmsInBackReqDto wmsInReqDto = new WmsInBackReqDto();
            wmsInReqDto.setWarehouseId(inBoundTask.getWmsWarehouseId());
            wmsInReqDto.setEnterpriseId(inBoundTask.getEnterpriseId());
            wmsInReqDto.setTaskId(inBoundTask.getBillNo());
            wmsInReqDto.setWmsLocationCode(inBoundTask.getWmsLocationCode());
            wmsInReqDto.setMsgId(inBoundTask.getUpperSystemTaskId());
            wmsInReqDto.setWorkType(inBoundTask.getWorkType());
            wmsInReqDto.setBusinessType(inBoundTask.getBusinessType());
            wmsInReqDto.setContainerNo(inBoundTask.getContainerNo());
            try {
                RestMessage wmsResult = wmsInBackService.execute(wmsInReqDto);
                log.info("入库完成回告wms" + wmsResult);
            } catch (RetryException e) {
                log.warn("入库完成回告wms失败，进入重试：" + e.getMessage());
            }
        }
        toInHistory(inBoundTask, bizInboundTaskDetailList, 30);

    }

    @Override
    public List<BizInboundTask> findByMap(Map map) {
        return bizInboundTaskMapper.findByMap(map, BizInboundTask.class);
    }

    @Override
    public void deleteById(Integer id) {
        bizInboundTaskMapper.deleteById(id, BizInboundTask.class);
    }

    @Override
    public void inboundTimoutToHis(BizInboundTask inBoundTask) {
        List<BizInboundTaskDetail> bizInboundTaskDetailList = bizInboundTaskDetailMapper.findByMap(MapUtils.put("inboundId", inBoundTask.getId()).getMap(), BizInboundTaskDetail.class);
        Assert.notEmpty(bizInboundTaskDetailList, String.format("未查到id【%s】入库任务明细", inBoundTask.getId()));
        toInHistory(inBoundTask, bizInboundTaskDetailList, -10);
    }


    @Override
    public void doInboundCallBack(CarryTaskCallbackDto carryTaskCallbackDto) {

        Criteria criteria = Criteria.forClass(BizInboundTask.class);
        criteria.restrictionBuilder().eq(BizInboundTask::getContainerNo, carryTaskCallbackDto.getContainerNo()).build();
        bizInboundTaskMapper.updateMapByCriteria(MapUtils.put("status", BaseStatusEnum.STATUS_FINISH.getCode()).put("updateTime", LocalDateTime.now()).getMap(), criteria);

        Criteria criteriaDetail = new Criteria(ContainerInfo.class);
        criteriaDetail.setRestriction(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo()));
        containerInfoService.updateMapByCriteria(MapUtils.put("taskType", ContainerTaskTypeConstants.IDLE).put("source", carryTaskCallbackDto.getEndLocation()).put("updateTime", LocalDateTime.now()).getMap(), criteriaDetail);

        PalletInfo palletInfo = palletInfoMapper.findByMap(MapUtils.put("palletNo", carryTaskCallbackDto.getContainerNo()).getMap(), PalletInfo.class).stream().findFirst().orElse(null);
        if (!Objects.isNull(palletInfo)) {
            ContainerInfo containerInfo = containerInfoService.findByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).getMap()).stream().findFirst().orElse(null);
            if (Objects.isNull(containerInfo)) {
                palletInfoMapper.updateMapById(palletInfo.getId(), MapUtils.put("palletType", 0).put("subArea", carryTaskCallbackDto.getEndRegion()).put("angle", 0).getMap(), PalletInfo.class);
            } else {
                palletInfoMapper.updateMapById(palletInfo.getId(), MapUtils.put("subArea", carryTaskCallbackDto.getEndRegion()).put("angle", 0).getMap(), PalletInfo.class);
            }
        }
    }

    @Override
    public BizInboundTask getWmsTask(BcrRequestDto bcrRequestDto) throws Exception {
        Criteria criteria = Criteria.forClass(BizInboundTask.class);
        criteria.restrictionBuilder().eq(BizInboundTask::getContainerNo, bcrRequestDto.getStockId()).build();
        BizInboundTask inboundTask = bizInboundTaskMapper.findByCriteria(criteria).stream().findFirst().orElse(null);
        if (Objects.isNull(inboundTask)) {
            return null;
        }
        Criteria detailCriteria = Criteria.forClass(BizInboundTaskDetail.class);
        detailCriteria.restrictionBuilder().eq(BizInboundTaskDetail::getInboundId, inboundTask.getId()).build();
        List<BizInboundTaskDetail> bizInboundTaskDetails = bizInboundTaskDetailMapper.findByCriteria(detailCriteria);
        inboundTask.setSubList(bizInboundTaskDetails);
        return inboundTask;
    }


    @Override
    public void sendInboundBybestArea(BestAreaDto bestAreaDto, String bestArea) throws Exception {
        plgFeignRouteService.createCarryTask(bestAreaDto.getContainerNo(), null, bestAreaDto.getSourceArea(), bestAreaDto.getSourceLocation(), bestArea, null,
                String.valueOf(BaseTaskTypeConstants.INBOUND_TYPE), 1, "入库", bestAreaDto.getBusinessProperty());
    }

    @Override
    public String findBestInAreaNo(BestAreaDto bestAreaDto) throws Exception {
        String bestArea = findBestAreaByType(bestAreaDto.getContainerNo(), bestAreaDto.getAreaNo(), bestAreaDto.getBusinessProperty(), bestAreaDto.getDeviceHeight());
        return bestArea;
    }

    @Override
    public void updateInboundTaskStatus(BizInboundTask inboundTask) {
        bizInboundTaskMapper.updateInboundStatusById(inboundTask.getId(), BaseStatusEnum.STATUS_STARTED.getCode());
    }

    /**
     * 找最优区域
     *
     * @param stockIdSub       容器号
     * @param targetArea       目标位置
     * @param businessProperty 业务属性
     * @return
     * @throws Exception
     */
    private String findBestArea(String stockIdSub, String targetArea, String businessProperty) throws Exception {
        InboundAllotAreaParamDto inboundAllotAreaParamDto = new InboundAllotAreaParamDto();
        inboundAllotAreaParamDto.setBusinessProperty(businessProperty);
        inboundAllotAreaParamDto.setPortNo(targetArea);
        inboundAllotAreaParamDto.setContainerNo(stockIdSub);
        List<PortInfoAreaDto> portInfoAreaDtos = plgFeignRouteService.getAllotAreaNew(inboundAllotAreaParamDto);

        String targetAreaNo = portInfoAreaDtos.stream().sorted(Comparator.comparing(PortInfoAreaDto::getTaskCount).thenComparing(PortInfoAreaDto::getAreaReserveCount)).findFirst().orElse(null).getAreaNo();
        return targetAreaNo;
    }

    /**
     * 分配最优区域
     *
     * @param stockIdSub       容器号
     * @param targetArea       目标位置
     * @param businessProperty 业务属性
     * @return
     * @throws Exception
     */
    @Override
    public String findBestAreaByType(String stockIdSub, String targetArea, String businessProperty, double deviceHeight) throws Exception {
        InboundAllotAreaParamDto inboundAllotAreaParamDto = new InboundAllotAreaParamDto();
        inboundAllotAreaParamDto.setBusinessProperty(businessProperty);
        inboundAllotAreaParamDto.setHeight(1);
        inboundAllotAreaParamDto.setPortNo(targetArea);
        inboundAllotAreaParamDto.setContainerNo(stockIdSub);
        List<PortInfoAreaDto> portInfoAreaDtos = plgFeignRouteService.getAllotAreaNew(inboundAllotAreaParamDto);
        log.warn("************入库请求route区域************返回数据：" + JSONArray.toJSONString(portInfoAreaDtos));

        List<DeviceInfo> canUseAreaByItemType = deviceInfoService.findCanUseAreaByItemType(deviceHeight, null);
        Assert.isTrue(CollectionUtil.isNotEmpty(canUseAreaByItemType), "可用设备为空");
        List<String> canUseDeviceList = canUseAreaByItemType.stream().map(DeviceInfo::getDeviceNo).collect(Collectors.toList());

        List<PortInfoAreaDto> list = portInfoAreaDtos.stream().filter(x -> canUseDeviceList.contains(x.getAreaNo())).collect(Collectors.toList());
        Assert.isTrue(CollectionUtil.isNotEmpty(list), "项目表【device_info】可用设备【{}】与wh可用区域【{}】不一致", canUseDeviceList, portInfoAreaDtos);

//        final long count = list.stream().filter(item -> item.getCanInCount() > 0).count();
//        Assert.isFalse(count==0, "没有可入区域");

        List<String> areaNoList = list.stream().map(PortInfoAreaDto::getAreaNo).distinct().collect(Collectors.toList());
        List<AreaTaskDto> areaDetail = plgFeignRouteService.getAreaDetail(areaNoList);
        Map<String, AreaTaskDto> map = areaDetail.stream().collect(Collectors.toMap(AreaTaskDto::getAreaNo, o -> o));

        list = list.stream().sorted(Comparator.comparing(PortInfoAreaDto::getCanInCount).reversed()).collect(Collectors.toList());
        List<FindBestAreaDto> resultList = new ArrayList<>();
        list.forEach(item -> {
            resultList.add(FindBestAreaDto.builder()
                    .areaNo(item.getAreaNo())
                    .taskCount(item.getTaskCount())
                    .areaReserveCount(item.getAreaReserveCount())
                    .carCount(map.get(item.getAreaNo()).getCarCount()).build());

        });
        return resultList.stream().sorted(Comparator.comparing(FindBestAreaDto::getTaskCount).thenComparing(FindBestAreaDto::getCarCount, Comparator.reverseOrder()).thenComparing(FindBestAreaDto::getAreaReserveCount, Comparator.reverseOrder())).findFirst().get().getAreaNo();
    }

    /**
     * 按照高度加任务数，找出最优容器
     *
     * @param deviceInfoDtoList
     * @return
     */
    private DeviceInfoDto inboundDistribution(List<DeviceInfoDto> deviceInfoDtoList) {
        List<DeviceInfoDto> canInDeviceInfoList = deviceInfoDtoList.stream().filter(x -> x.getCanInCount() > 0).collect(Collectors.toList());
        if (CollectionUtil.isEmpty(canInDeviceInfoList)) {
            return deviceInfoDtoList.get(0);
        }
        DeviceInfoDto deviceInfoDto = canInDeviceInfoList.stream().sorted(Comparator.comparing(DeviceInfoDto::getHeight).thenComparing(DeviceInfoDto::getTaskCount).thenComparing(DeviceInfoDto::getAreaReserveCount, Comparator.reverseOrder())).findFirst().orElse(null);
        return deviceInfoDto;
    }


    private void toInHistory(BizInboundTask inBoundTask, List<BizInboundTaskDetail> detailList, int status) {
        // 历史表需要提供 到时候调整
        BizInboundTaskHis wmsInTaskHis = new BizInboundTaskHis();
        inBoundTask.setStatus(status);
        inBoundTask.setUpdateTime(LocalDateTime.now());
        BeanUtils.copyProperties(inBoundTask, wmsInTaskHis);
        inboundTaskHisMapper.save(wmsInTaskHis);

        ArrayList<BizInboundTaskDetailHis> taskDetailHis = new ArrayList<>();
        for (BizInboundTaskDetail bizInboundTaskDetail : detailList) {
            BizInboundTaskDetailHis bizInboundTaskDetailHis = new BizInboundTaskDetailHis();
            BeanUtils.copyProperties(bizInboundTaskDetail, bizInboundTaskDetailHis);
            taskDetailHis.add(bizInboundTaskDetailHis);
        }
        inboundTaskDetailHisMapper.saveBatch(taskDetailHis);
        bizInboundTaskMapper.deleteById(inBoundTask.getId(), BizInboundTask.class);
        bizInboundTaskDetailMapper.deleteByMap(MapUtils.put("inboundId", inBoundTask.getId()).getMap(), BizInboundTaskDetail.class);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveInboundTask(List<InBoundDto> inBoundDtos) throws Exception {
        for (InBoundDto inBoundDto : inBoundDtos) {
            if (redisTemplate.hasKey(inBoundDto.getMsgId())) {
                continue;
            } else {
                redisTemplate.opsForValue().set(inBoundDto.getMsgId(), JSON.toJSON(inBoundDto), 3, TimeUnit.MINUTES);
            }
            checkContainerInfo(inBoundDto);
            BizInboundTask bizInboundTask = new BizInboundTask();
            bizInboundTask.setUpperSystemTaskId(inBoundDto.getMsgId());
            bizInboundTask.setEnterpriseId(inBoundDto.getEnterpriseId());
            bizInboundTask.setWmsWarehouseId(inBoundDto.getWarehouseId());
            bizInboundTask.setBillNo(inBoundDto.getTaskId());
            bizInboundTask.setWmsLocationCode(inBoundDto.getWmsLocationCode());
            bizInboundTask.setOriginalLocation(null);
            bizInboundTask.setOriginalArea(StrUtil.isBlank(inBoundDto.getOriginalArea()) ? null : inBoundDto.getOriginalArea());
            bizInboundTask.setTargetArea(inBoundDto.getTargetArea());
            bizInboundTask.setContainerType(ContainerInfoTypeConstants.GOODS_PALLET);
            bizInboundTask.setBusinessType(inBoundDto.getBusinessType());
            bizInboundTask.setWorkType(inBoundDto.getWorkType());
            bizInboundTask.setContainerNo(inBoundDto.getContainerNo());
            bizInboundTask.setStatus(BaseStatusEnum.STATUS_INIT.getCode());
            bizInboundTask.setCreateTime(LocalDateTime.now());
            bizInboundTask.setUpdateTime(LocalDateTime.now());
            bizInboundTaskMapper.save(bizInboundTask);

            saveInboundTaskDetail(bizInboundTask, inBoundDto.getSubList());
        }
    }

    @Override
    public void saveInboundTaskDetail(BizInboundTask inboundTask, List<InBoundSubListDto> inBoundSubList) throws Exception {
        List<BizInboundTaskDetail> list = new ArrayList<>();
        for (InBoundSubListDto dto : inBoundSubList) {
//            goodsInfoService.saveAndGetInboundGoodsInfo(dto.getItemId());
            BizInboundTaskDetail bizInboundTaskDetail = new BizInboundTaskDetail();
            bizInboundTaskDetail.setInboundId(inboundTask.getId());
            bizInboundTaskDetail.setContainerSubNo(inboundTask.getContainerNo());
            bizInboundTaskDetail.setCreateTime(LocalDateTime.now());
            bizInboundTaskDetail.setUpdateTime(LocalDateTime.now());
            bizInboundTaskDetail.setQty(dto.getQty());
            bizInboundTaskDetail.setOwnerId(dto.getOwnerId());
            bizInboundTaskDetail.setItemId(dto.getItemId());
            bizInboundTaskDetail.setLotId(dto.getLotId());
            bizInboundTaskDetail.setSeqNo(dto.getTaskLineId());
            bizInboundTaskDetail.setPackId(dto.getPackId());
            bizInboundTaskDetail.setExtend1(dto.getAttrStr1());
            bizInboundTaskDetail.setExtend2(dto.getAttrStr2());
            bizInboundTaskDetail.setExtend3(dto.getAttrStr3());
            list.add(bizInboundTaskDetail);
        }
        if (CollectionUtil.isEmpty(list)) {
            throw new PrologException(String.format("容器【%s】没有入库任务详情", inboundTask.getContainerNo()));
        }
        bizInboundTaskDetailMapper.saveBatch(list);
    }

    @Override
    public void saveEmptyInboundTaskDetail(BizInboundTask bizInboundTask) {
        BizInboundTaskDetail bizInboundTaskDetail = new BizInboundTaskDetail();
        bizInboundTaskDetail.setInboundId(bizInboundTask.getId());
        bizInboundTaskDetail.setContainerSubNo(bizInboundTask.getContainerNo());
        bizInboundTaskDetail.setCreateTime(LocalDateTime.now());
        bizInboundTaskDetail.setQty(new BigDecimal(1));
        bizInboundTaskDetail.setItemId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setLotId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setOwnerId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetail.setPackId(BasePropertyConstants.EMPTY_PALLET_PILE);
        bizInboundTaskDetailMapper.save(bizInboundTaskDetail);
    }

    public void checkContainerInfo(InBoundDto inBoundDto) throws Exception {

        String containerNo = inBoundDto.getContainerNo();

        List<BizInboundTask> inboundTaskList = bizInboundTaskMapper.findByMap(MapUtils.put("containerNo", containerNo).getMap(), BizInboundTask.class);
        if (CollectionUtil.isNotEmpty(inboundTaskList)) {
            throw new PrologException("载具【" + containerNo + "】已经存在入库任务，请勿重复上架");
        }

        List<WmsCarryTask> wmsCarryTasks = wmsCarryTaskService.findByMap(MapUtils.put("containerNo", containerNo).getMap());
        if (CollectionUtil.isNotEmpty(wmsCarryTasks)) {
            throw new PrologException("载具【" + containerNo + "】已经存在借道任务");
        }

        ContainerInfo containerInfo = containerInfoService.findByMap(MapUtils.put("containerNo", containerNo).getMap()).stream().findFirst().orElse(null);
        if (!Objects.isNull(containerInfo)) {
            throw new PrologException("容器【" + containerNo + "】库存已存在");
        }

        ContainerInfoDetail containerInfoDetail = containerInfoDetailMapper.findByMap(MapUtils.put("containerSubNo", containerNo).getMap(), ContainerInfoDetail.class).stream().findFirst().orElse(null);
        if (!Objects.isNull(containerInfoDetail)) {
            throw new PrologException("容器【" + containerNo + "】已经存在库存，请勿重复上架");
        }

//        List<String> containerList = new ArrayList<>();
//        containerList.add(containerNo);
//        List<ContainerLocation> locList = plgFeignRouteService.findContainerLocationListByContainerList(containerList);
//        if (locList != null && locList.size() > 0) {
//            throw new PrologException(String.format("容器号【%s】已存在于库内", containerNo));
//        }
//        List<LocationCfg> locationCfgList = locationCfgService.findByMap(null);
//        LocationCfg targetAreaCfg = locationCfgList.stream().filter(item -> item.getType() == LocationCfgConstants.EISKQ && item.getWmsAreaNo().equals(inBoundDto.getWmsLocationCode())).findFirst().orElseThrow(() ->
//                new PrologException(String.format("%s库区对应区域未配置", inBoundDto.getWmsLocationCode()))
//        );
//        LocationCfg sourceAreaCfg = locationCfgList.stream().filter(item -> item.getType() == LocationCfgConstants.SJW).findFirst().orElseThrow(() ->
//                new PrologException(String.format("一楼入库收货区域未配置"))
//        );
//        boolean b = plgFeignRouteService.checkDirectionIsReachable(sourceAreaCfg.getAreaNo(), targetAreaCfg.getAreaNo());
//        if (!b) {
//            throw new PrologException("入库区域不可达");
//        }

    }

    @Override
    public InboundCarryTaskDto wmsCarryTaskScan(String containerNo, String locationNo) throws Exception {


        InboundCarryTaskDto inboundCarryTaskDto = new InboundCarryTaskDto();
        inboundCarryTaskDto.setContainerNo(containerNo);
        inboundCarryTaskDto.setLocationNo(locationNo);

        if (StrUtil.isBlank(locationNo)) {
            //地堆出库搬运
            inboundCarryTaskDto.setType(WmsCarryTaskType.DD_OUT_TYPE.getType());
            LocationCfg targetLocation = locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.JHQ).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("1F整托出库集货区未配置"));
            inboundCarryTaskDto.setTargetAreaList(Arrays.asList(MapUtils.put("code", targetLocation.getAreaNo()).put("desc", "一楼整托出库托盘出库区").getMap()));
            inboundCarryTaskDto.setTargetArea(targetLocation.getAreaNo());
            return inboundCarryTaskDto;
        }

        ContainerLocationDto locationInfo = plgFeignRouteService.findContainerInfoByLocationNotCheck(MapUtils.put("locationNo", locationNo).getMap());
        log.info("---->根据点位查询容器信息{}", JSONUtil.toJsonStr(locationInfo));
        if (Objects.nonNull(locationInfo) && StrUtil.isNotBlank(locationInfo.getContainerNo()) && locationInfo.getTaskState() < 30 && !locationInfo.getContainerNo().equals(containerNo)) {
            throw new PrologException("当前点位存在的容器与扫描容器不一致");
        }
//        AssertUtils.isNotTrue(plgFeignRouteService.checkContainer(locationNo), "当前点位已存在容器信息");


        BizInboundTask bizInboundTask = this.findByMap(MapUtils.put("containerNo", containerNo).put("status", ContainerTaskStatusConstants.INIT_STATUS).getMap()).stream().findFirst().orElse(null);
        if (Objects.nonNull(bizInboundTask)) {
            //有入库任务
            inboundCarryTaskDto.setTargetAreaList(WmsCarryTaskInCode.getRkList());
            inboundCarryTaskDto.setType(WmsCarryTaskType.INBOUND_TYPE.getType());
            inboundCarryTaskDto.setTargetArea(bizInboundTask.getWmsLocationCode());
            if (bizInboundTask.getContainerType() == ContainerInfoTypeConstants.EMPTY_PALLET_PILE) {
                inboundCarryTaskDto.setType(WmsCarryTaskType.EMPTY_INBOUND_TYPE.getType());
            } else {
                List<ContainerLocationVo> locationByContainerList = plgFeignRouteService.findLocationByContainerListNoCheck(Arrays.asList(containerNo));
                if (CollectionUtil.isNotEmpty(locationByContainerList) && StrUtil.isNotEmpty(locationByContainerList.get(0).getCurrentArea())) {
                    throw new PrologException("容器存在点位信息");
                }
            }
            return inboundCarryTaskDto;
        }
        WmsCarryTask wmsCarryTask = wmsCarryTaskService.findByMap(MapUtils.put("containerNo", containerNo).put("status", ContainerTaskStatusConstants.INIT_STATUS).getMap()).stream().findFirst().orElse(null);
        if (Objects.nonNull(wmsCarryTask)) {
            //有借道任务
            inboundCarryTaskDto.setTargetAreaList(WmsCarryTaskInCode.getJdList());
            inboundCarryTaskDto.setType(WmsCarryTaskType.INBOUND_TYPE.getType());
            inboundCarryTaskDto.setTargetArea(wmsCarryTask.getTargetArea());
            if (StrUtil.equals(wmsCarryTask.getTargetArea(), WmsCarryTaskInCode.ZYYP.getCode())) {
                inboundCarryTaskDto.setTargetArea(WmsCarryTaskInCode.ZYYPRKJBW.getCode());
            }
            if (StrUtil.equals(wmsCarryTask.getTargetArea(), WmsCarryTaskInCode.WL.getCode())) {
                inboundCarryTaskDto.setTargetArea(WmsCarryTaskInCode.WLRKJBW.getCode());
            }
            return inboundCarryTaskDto;
        }
        //没有任何任务
        //查询当前点位对应的区域信息
        List<LocationCfg> locationCfgList = locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.SJW).getMap());
        List<String> collect = locationCfgList.stream().map(LocationCfg::getAreaNo).collect(Collectors.toList());
        WhArea whArea = warehouseService.batchQueryLocation(Arrays.asList(locationNo)).get(0);
        if (collect.contains(whArea.getAreaNo())) {
            //空托上架绑定
            inboundCarryTaskDto.setType(WmsCarryTaskType.EMPTY_SHELVE_TYPE.getType());
        } else {
            //物料搬运
            inboundCarryTaskDto.setType(WmsCarryTaskType.ITEM_CARRY_TYPE.getType());
            Criteria criteria = new Criteria(StationCfg.class);
            criteria.restrictionBuilder().in(StationCfg::getStationType, StationTypeEnum.wmsOutCarryCode()).build();
            List<Map<String, Object>> targetAreaList = stationCfgService.findByCriteria(criteria).stream().map(item -> {
                return MapUtils.put("code", item.getAreaNo()).put("desc", item.getRemark()).getMap();
            }).collect(Collectors.toList());
            targetAreaList.addAll(Arrays.asList(MapUtils.put("code", "SX01-01").put("desc", "一楼四向库").getMap(), MapUtils.put("code", "AGV01-01").put("desc", "二楼agv整件托盘库").getMap(), MapUtils.put("code", "AGVTP01").put("desc", "拆零托盘库").getMap()
                    , MapUtils.put("code", "AGV02-01").put("desc", "二楼agv整件食品库").getMap(), MapUtils.put("code", "AGV03-01").put("desc", "二楼agv整件器械库").getMap(), MapUtils.put("code", "AGVHJ01").put("desc", "拆零货架库").getMap()));
            inboundCarryTaskDto.setTargetAreaList(targetAreaList);
        }
        return inboundCarryTaskDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void inboundTaskConfirm(InboundCarryTaskDto req) throws Exception {
        AssertUtils.isNotNull(req.getContainerNo(), "容器号不能为空");
        AssertUtils.isNotNull(req.getType(), "任务属性不能为空");
        WmsCarryTaskType wmsCarryTaskType = WmsCarryTaskType.of(req.getType());
        switch (wmsCarryTaskType) {
            case INBOUND_TYPE:
            case EMPTY_INBOUND_TYPE:
                AssertUtils.isNotNull(req.getLocationNo(), "位置号不能为空");
                AssertUtils.isNotNull(req.getTargetArea(), "目标区域不能为空");
                //入库任务
                doInboundTask(req);
                break;
            case ITEM_CARRY_TYPE:
                AssertUtils.isNotNull(req.getLocationNo(), "位置号不能为空");
                AssertUtils.isNotNull(req.getTargetArea(), "目标区域不能为空");
                //直接搬运任务
                itemCarryTask(req);
                break;
            case EMPTY_SHELVE_TYPE:
                AssertUtils.isNotNull(req.getLocationNo(), "位置号不能为空");
                //空托绑定上架位
                plgFeignRouteService.createItemContainer(req.getLocationNo(), req.getContainerNo(), String.valueOf(ContainerInfoTypeConstants.EMPTY_PALLET), BasePropertyConstants.SJ_EMPTY);
                break;
            case AGV_EMPTY_IN_TYPE:
                AssertUtils.isNotNull(req.getLocationNo(), "位置号不能为空");
                createAgvEmptyTask(req);
                break;
            case DD_OUT_TYPE:
                //地堆借道出库
                saveJdTask(req);
                break;
        }
    }

    private void createAgvEmptyTask(InboundCarryTaskDto req) throws Exception {
        LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("type", 4).put("wmsAreaNo", "AGVL").getMap()).stream().findFirst().orElseThrow(() -> new PrologException("agv托盘库未配置"));
        ContainerInfo containerInfo = new ContainerInfo();
        containerInfo.setContainerNo(req.getContainerNo());
        containerInfo.setContainerType(ContainerInfoTypeConstants.EMPTY_PALLET);
        containerInfo.setTaskType(ContainerTaskTypeConstants.INBOUND);
        containerInfo.setIsLock(0);
        containerInfo.setWarehouseArea(WmsCarryTaskInCode.AGVL.getCode());
        containerInfo.setAreaType(Integer.parseInt(WmsCarryTaskInCode.AREA_TYPE.get(WmsCarryTaskInCode.AGVL.getCode()).toString()));
        containerInfo.setCreateTime(LocalDateTime.now());
        containerInfo.setUpdateTime(LocalDateTime.now());
        containerInfoService.save(containerInfo);

        ContainerInfoDetail containerInfoDetail = new ContainerInfoDetail();
        containerInfoDetail.setContainerNo(req.getContainerNo());
        containerInfoDetail.setContainerSubNo(req.getContainerNo());
        containerInfoDetail.setQty(BigDecimal.ONE);
        containerInfoDetail.setIsLock(0);
        containerInfoDetail.setLockQty(BigDecimal.ZERO);
        containerInfoDetail.setItemId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerInfoDetail.setPackId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerInfoDetail.setLotId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerInfoDetail.setOwnerId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerInfoDetail.setCreateTime(LocalDateTime.now());
        containerInfoDetail.setAreaType(containerInfo.getAreaType());
        containerInfoDetailMapper.save(containerInfoDetail);

        ContainerStoreChange containerChange = new ContainerStoreChange();
        containerChange.setTaskType(BaseTypeEnum.INBOUND_TYPE.getCode());
        containerChange.setContainerNo(req.getContainerNo());
        containerChange.setContainerSubNo(req.getContainerNo());
        containerChange.setSoureQty(BigDecimal.ZERO);
        containerChange.setChangeQty(BigDecimal.ONE);
        containerChange.setTargetQty(BigDecimal.ONE);
        containerChange.setItemId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerChange.setLotId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerChange.setPackId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerChange.setRemark("入库");
        containerChange.setOwnerId(BasePropertyConstants.EMPTY_PALLET_PILE);
        containerChange.setCreateTime(LocalDateTime.now());
        containerStoreChangeService.save(containerChange);

        AssertUtils.isNotTrue(!plgFeignRouteService.checkAreaIn(locationCfg.getAreaNo()), "agv拆零托盘库没有空闲货位");

        plgFeignRouteService.createItemContainer(req.getLocationNo(), req.getContainerNo(), String.valueOf(ContainerInfoTypeConstants.EMPTY_PALLET), BasePropertyConstants.SJ_EMPTY);

        WhArea whArea = warehouseService.batchQueryLocation(Arrays.asList(req.getLocationNo())).get(0);

        plgFeignRouteService.createCarryTask(req.getContainerNo(), null, whArea.getAreaNo(), req.getLocationNo(), locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.INBOUND_TYPE), 1, "空托入库搬运", null);


    }

    private void saveJdTask(InboundCarryTaskDto req) {
        List<WmsCarryTask> wmsCarryTaskList = wmsCarryTaskService.findByMap(MapUtils.put("containerNo", req.getContainerNo()).getMap());
        AssertUtils.isNotTrue(CollectionUtil.isNotEmpty(wmsCarryTaskList), String.format("容器%s任务已存在", req.getContainerNo()));

        WmsCarryTask wmsCarryTask = new WmsCarryTask();
        wmsCarryTask.setContainerNo(req.getContainerNo());
        wmsCarryTask.setTargetArea(req.getTargetArea());
        wmsCarryTask.setBusinessType(String.valueOf(WmsConstants.WMS_CARRY_WORK_TYPE_IN));
        wmsCarryTask.setTaskType(WmsConstants.WMS_CARRY_TASK_TYPE_OUT);
        wmsCarryTask.setCreateTime(new Date());
        wmsCarryTask.setPriority(10);
        wmsCarryTask.setOriginalLocation(null);
        wmsCarryTask.setStatus(ContainerTaskStatusConstants.INIT_STATUS);
        wmsCarryTask.setWmsLocationCode(WmsCarryTaskInCode.ZJK01.getCode());
        wmsCarryTaskService.save(wmsCarryTask);
    }

    private void itemCarryTask(InboundCarryTaskDto req) throws Exception {
        //没有入库任务和借道任务，直接发送搬运
        AssertUtils.isNotTrue(!plgFeignRouteService.checkAreaIn(req.getTargetArea()), "此区域目前不可搬运");
//        List<StationCfg> stationCfgList = stationCfgService.findByMap(null);
//        StationCfg targetStation = stationCfgList.stream().filter(item -> Objects.nonNull(item.getWmsAreaNo()) && item.getWmsAreaNo().equals(req.getTargetArea())).findFirst().orElseThrow(() -> new PrologException(String.format("wms目标区域%s未配置", req.getTargetArea())));
        WhArea startArea = warehouseService.batchQueryLocation(Arrays.asList(req.getLocationNo())).get(0);
        AssertUtils.isNotTrue(!plgFeignRouteService.checkDirectionIsReachable(startArea.getAreaNo(), req.getTargetArea()), "此目标区域当前操作不可达");
        ContainerLocationVo containerLocationVo = plgFeignRouteService.findLocationByContainerListNoCheck(Arrays.asList(req.getContainerNo())).stream().findFirst().orElse(null);
        if (Objects.isNull(containerLocationVo)) {
            plgFeignRouteService.createItemContainer(req.getLocationNo(), req.getContainerNo(), "0", "0");
        }
        plgFeignRouteService.createCarryTask(req.getContainerNo(), null, startArea.getAreaNo(), req.getLocationNo(), req.getTargetArea(), null, String.valueOf(BaseTaskTypeConstants.MOVE_TYPE), 1, "库内搬运", null);
    }

    private void doInboundTask(InboundCarryTaskDto req) throws Exception {
        //入库任务或者借道任务
        BizInboundTask bizInboundTask = this.findByMap(MapUtils.put("containerNo", req.getContainerNo()).put("status", ContainerTaskStatusConstants.INIT_STATUS).getMap()).stream().findFirst().orElse(null);
        WmsCarryTask wmsCarryTask = wmsCarryTaskService.findByMap(MapUtils.put("containerNo", req.getContainerNo()).put("status", ContainerTaskStatusConstants.INIT_STATUS).getMap()).stream().findFirst().orElse(null);
        LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.SJW).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("起始点位未配置"));
        Criteria criteria = new Criteria(LocationCfg.class);
        criteria.restrictionBuilder().eq(LocationCfg::getWmsAreaNo, req.getTargetArea()).in(LocationCfg::getType, Arrays.asList(LocationCfgConstants.EISKQ, LocationCfgConstants.WMSKQ)).build();
        LocationCfg targetLocationCfg = locationCfgService.findByCriteria(criteria).stream().findFirst().orElseThrow(() -> new PrologException("库区未配置"));
        AssertUtils.isNotTrue(!plgFeignRouteService.checkDirectionIsReachable(locationCfg.getAreaNo(), targetLocationCfg.getAreaNo()), "此目标区域当前操作不可达");
        if (Objects.nonNull(bizInboundTask)) {
            bizInboundTask.setOriginalArea(locationCfg.getAreaNo());
            bizInboundTask.setOriginalLocation(req.getLocationNo());
            bizInboundTask.setUpdateTime(LocalDateTime.now());
            bizInboundTaskMapper.update(bizInboundTask);
        } else if (Objects.nonNull(wmsCarryTask)) {
            final WmsCarryTaskInCode targetCode = WmsCarryTaskInCode.of(wmsCarryTask.getTargetArea());
            if (!Objects.equals(targetCode, WmsCarryTaskInCode.ZJK01)) {
                if (!plgFeignRouteService.checkAreaIn(targetLocationCfg.getAreaNo())) {
                    throw new PrologException("目标区域没有空闲货位");
                }
            }
            wmsCarryTask.setOriginalArea(locationCfg.getAreaNo());
            wmsCarryTask.setOriginalLocation(req.getLocationNo());
            wmsCarryTask.setUpdateTime(new Date());
            wmsCarryTask.setTargetArea(req.getTargetArea());
            wmsCarryTaskService.update(wmsCarryTask);
        }
    }

    @Override
    public List<BizInboundTask> findByCriteria(Criteria criteria) {
        return bizInboundTaskMapper.findByCriteria(criteria);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void inboundAgvCarryTask(BizInboundTask item) throws Exception {
        WmsCarryTaskInCode wmsCarryTaskInCode = WmsCarryTaskInCode.of(item.getWmsLocationCode());
        switch (wmsCarryTaskInCode) {
            case MJZ:
                //四向库 从上架区域搬运到四项库入库bcr口
                sxkInboundCarryTask(item);
                break;
            case AGVZ:
            case AGVSP:
            case AGVQX:
            case AGVZY:
                //AGV整件药品托盘库 /AGV整件食品托盘库 /AGV整件器械托盘库 /AGV中药饮片库 统一处理
                agvInboundCarryTask(item);
                break;
//            case AGVL:
//                //拆零库
//                sortingInboundCarryTask(item);
//                break;
            default:
                log.warn("无法识别的入库区域");
                break;
        }
    }

    /**
     * AGV整件药品托盘库 /AGV整件食品托盘库 /AGV整件器械托盘库 /AGV中药饮片库 统一处理
     *
     * @param item
     * @param fistStation
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void sortingInboundCarryTask(BizInboundTask item, boolean fistStation) throws Exception {
        //当前托盘正在搬运，忽略本次任务
        List<CarryTaskDto> containerCarry = plgFeignRouteService.getContainerCarry(item.getContainerNo());
        if (CollectionUtil.isNotEmpty(containerCarry)) {
            throw new PrologException("容器正在搬运");
        }
        //校验容器是否在上架站台或库内或补货上架暂存区
        Criteria criteria = new Criteria(LocationCfg.class);
        criteria.restrictionBuilder().in(LocationCfg::getType, Arrays.asList(5, 40, 150)).build();
        List<LocationCfg> locationCfgList = locationCfgService.findByCriteria(criteria);
        LocationCfg cacheAreaCfg = locationCfgList.stream().filter(inner -> Objects.equals(inner.getType(), 150)).findFirst().orElseThrow(() -> new PrologException("拆零上架托盘暂存区未配置"));
        List<String> areaList = locationCfgList.stream().map(LocationCfg::getAreaNo).collect(Collectors.toList());
        //不在库内，等待回库再发送
        ContainerLocation containerLocation = null;
        final List<ContainerLocationVo> locationByContainerList = plgFeignRouteService.findLocationByContainerListNoCheck(Arrays.asList(item.getContainerNo()));
        if (CollectionUtil.isNotEmpty(locationByContainerList) && StrUtil.isNotBlank(locationByContainerList.get(0).getCurrentArea())) {
            containerLocation = plgFeignRouteService.seachLocationNo(item.getContainerNo());
            if (!areaList.contains(containerLocation.getCurrentArea())) {
                throw new PrologException("容器在途中，稍后搬运");
            }
        }
        //根据任务数获取任务数最少的站台（任务数均分）
        Criteria criteriaStation = Criteria.forClass(StationCfg.class);
        criteriaStation.restrictionBuilder()
                .eq(StationCfg::getStationType, StationTypeConstant.STATION_TYP_70)
                .eq(StationCfg::getIsLock, 0)
                .eq(StationCfg::getTaskType, StationCfgConstants.UP).build();
        List<StationCfg> stationCfgList = stationCfgService.findByCriteria(criteriaStation);
        if (CollectionUtil.isEmpty(stationCfgList)) {
            throw new PrologException("拆零上架站台未配置或没有可用");
        }
        //A品上架直接入库到库内
        if (carryToAGVTP(item)) {
            bizInboundTaskMapper.updateMapById(item.getId(), MapUtils.put("status", BaseStatusEnum.STATUS_STARTED.getCode()).put("updateTime", LocalDateTime.now()).put("extend3", BaseConstant.AGVL_INBOUND_TAG).getMap(), BizInboundTask.class);
            return;
        }
        StationCfg stationCfg = null;
        List<String> areaNos = stationCfgList.stream().map(StationCfg::getAreaNo).collect(Collectors.toList());
//        List<ContainerLocation> containerLocationByAreaNos = plgFeignRouteService.findContainerLocationByAreaNos(areaNos);
//        List<ContainerLocation> freeContainerByAreaNo = plgFeignRouteService.findFreeContainerByAreaNo(areaNos.stream().collect(Collectors.joining(",")));
//        List<CarryTask> carryTasks = plgFeignRouteService.findCarryTaskListByEndRegionList(areaNos);
        List<AreaLocationCountDto> areaLocationCountDtos = plgFeignRouteService.queryAreaLocationCountDtoList(areaNos).stream().filter(i -> i.getFreeCount() > 0).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(areaLocationCountDtos)) {
            AreaLocationCountDto areaLocationCountDto = areaLocationCountDtos.stream().sorted(Comparator.comparing(AreaLocationCountDto::getFreeCount).reversed()).findFirst().get();
            stationCfg = stationCfgList.stream().filter(i -> StrUtil.equals(i.getAreaNo(), areaLocationCountDto.getAreaNo())).findFirst().get();
        }
//        for (StationCfg cStationCfg : stationCfgList) {
//            long count = carryTasks.stream().filter(inner -> StrUtil.equals(inner.getEndRegion(), cStationCfg.getAreaNo())).count();
//            long count1 = freeContainerByAreaNo.stream().filter(inner -> StrUtil.equals(inner.getCurrentArea(), cStationCfg.getAreaNo())).count();
//            cStationCfg.setTaskNum(count + count1);
//        }
        String startRegion = null;
        String startLocation = null;
//        StationCfg stationCfg = stationCfgList.stream().sorted(Comparator.comparing(StationCfg::getTaskNum)).findFirst().orElse(null);
        if (fistStation && Objects.nonNull(stationCfg) && plgFeignRouteService.checkAreaIn(stationCfg.getAreaNo())) {
            //找到一个最优站台并且站台有空闲位置
            item.setStatus(BaseStatusEnum.STATUS_STARTED.getCode());
            item.setUpdateTime(LocalDateTime.now());
            item.setExtend1(stationCfg.getId().toString());
            bizInboundTaskMapper.update(item);
            if (CollectionUtil.isEmpty(locationByContainerList) || Objects.isNull(locationByContainerList.get(0))) {
                ItemContainerReqDto itemContainerReqDto = new ItemContainerReqDto();
                itemContainerReqDto.setLocationNo(item.getOriginalLocation());
                itemContainerReqDto.setContainerNo(item.getContainerNo());
                itemContainerReqDto.setContainerType(item.getContainerType().toString());
                itemContainerReqDto.setBusinessProperty(item.getItemContainerBusinessProperty());
                plgFeignRouteService.createItemContainer(itemContainerReqDto);

                startRegion = item.getOriginalArea();
                startLocation = item.getOriginalLocation();
                plgFeignRouteService.createCarryTask(item.getContainerNo(), null, startRegion, startLocation, stationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.AGVL_TYPE), 1, "入拆零库上架站台", item.getItemContainerBusinessProperty());

                AssertUtils.isNotTrue(!dismantleFeignService.callShelves(item), "调用拆零上架呼叫货架失败");
            }else{
                plgFeignRouteService.createCarryTask(item.getContainerNo(), null, startRegion, startLocation, stationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.AGVL_TYPE), 1, "入拆零库上架站台", item.getItemContainerBusinessProperty());
                if (containerLocation == null || !containerLocation.getCurrentArea().contains("SX")) {
                    AssertUtils.isNotTrue(!dismantleFeignService.callShelves(item), "调用拆零上架呼叫货架失败");
                }
            }

        } else if (item.getStatus() == 0 && plgFeignRouteService.checkAreaIn(cacheAreaCfg.getAreaNo())) {
            //站台没有空闲位置并且不在缓存区并且暂存区有空闲位置，搬运到缓存区
            item.setStatus(BaseStatusEnum.STATUS_STARTED.getCode());
            item.setUpdateTime(LocalDateTime.now());
            bizInboundTaskMapper.update(item);
            if (CollectionUtil.isEmpty(locationByContainerList) || Objects.isNull(locationByContainerList.get(0))) {
                ItemContainerReqDto itemContainerReqDto = new ItemContainerReqDto();
                itemContainerReqDto.setLocationNo(item.getOriginalLocation());
                itemContainerReqDto.setContainerNo(item.getContainerNo());
                itemContainerReqDto.setContainerType(item.getContainerType().toString());
                itemContainerReqDto.setBusinessProperty(item.getItemContainerBusinessProperty());
                plgFeignRouteService.createItemContainer(itemContainerReqDto);
                startRegion = item.getOriginalArea();
                startLocation = item.getOriginalLocation();
            }
            plgFeignRouteService.createCarryTask(item.getContainerNo(), null, startRegion, startLocation, cacheAreaCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.CLSJ_ZC_TYPE), 1, "拆零上架搬运至暂存区", item.getItemContainerBusinessProperty());
        }

    }

    private boolean carryToAGVTP(BizInboundTask inboundTask) throws Exception {
        List<BizInboundTaskDetail> bizInboundTaskDetails = inboundTask.getSubList();
        String[] itemIds = bizInboundTaskDetails.stream().map(BizInboundTaskDetail::getItemId).distinct().toArray(String[]::new);
        List<ItemSyncVO> itemSyncVOS = feignGoodsService.queryItemMst(Arrays.asList(itemIds));
        org.springframework.util.Assert.isTrue(CollectionUtil.isNotEmpty(itemSyncVOS), "商品信息查询为空");
        LocationCfg locationCfg = locationCfgService.findOneByMap(MapUtils.put("type", LocationCfgConstants.AGVL_TP).put("wmsAreaNo", WmsCarryTaskInCode.AGVL.getCode()).getMap());

        Map<String, List<BizInboundTaskDetail>> detailsMap = bizInboundTaskDetails.stream().collect(Collectors.groupingBy(group -> group.getItemId() + "-" + group.getLotId()));

        //如果拆零库托盘区有可用货位并且收货托盘只有一个品批且当前物料为A品，直接发到拆零库托盘区的搬运任务
        if (detailsMap.size() == 1 && AbcTypeConstant.TYPE_A.equals(itemSyncVOS.get(0).getAbcType()) && !StrUtil.equals(BizInboundTask.SUPPLY_BUSINESS_TYPE, inboundTask.getBusinessType())) {
            //查询拆零库托盘区有没有可用货位
            DswRequestDto dswRequest = new DswRequestDto();
            dswRequest.setAreaNoList(Arrays.asList(locationCfg.getAreaNo()));
            List<DswAreaDto> dswAreaDtos = plgFeignRouteService.queryDswAreaList(dswRequest);
            int count = 0;
            if (CollectionUtils.isNotEmpty(dswAreaDtos)) {
                DswAreaDto dswAreaDto = dswAreaDtos.get(0);
                count = Objects.isNull(dswAreaDto.getFreeLocatorCount()) ? 0 : dswAreaDto.getFreeLocatorCount() - (Objects.isNull(dswAreaDto.getLeaveLocatorCount()) ? 0 : dswAreaDto.getLeaveLocatorCount());
            }
            if (count > 0) {
                InboundCarryTask(inboundTask, locationCfg, itemSyncVOS.get(0));
                return true;
            }
        }
        return false;
    }

    private void InboundCarryTask(BizInboundTask inboundTask, LocationCfg locationCfg, ItemSyncVO itemSyncVO) throws Exception {
        //创建点位
        final List<ContainerLocationVo> locationByContainerList = plgFeignRouteService.findLocationByContainerListNoCheck(Arrays.asList(inboundTask.getContainerNo()));
        String startRegion = null;
        String startLocation = null;
        if (CollectionUtil.isEmpty(locationByContainerList) || Objects.isNull(locationByContainerList.get(0))) {
            ItemContainerReqDto itemContainerReqDto = new ItemContainerReqDto();
            itemContainerReqDto.setLocationNo(inboundTask.getOriginalLocation());
            itemContainerReqDto.setContainerNo(inboundTask.getContainerNo());
            itemContainerReqDto.setContainerType(inboundTask.getContainerType().toString());
            itemContainerReqDto.setBusinessProperty(inboundTask.getItemContainerBusinessProperty());
            plgFeignRouteService.createItemContainer(itemContainerReqDto);
            startRegion = inboundTask.getOriginalArea();
            startLocation = inboundTask.getOriginalLocation();
        }
        //创建库存
        intoStore(inboundTask, itemSyncVO);
        //6 发送搬运
        plgFeignRouteService.createCarryTask(inboundTask.getContainerNo(), null, startRegion, startLocation, locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.AGVL_TYPE), 1, "入拆零库托盘区", inboundTask.getItemContainerBusinessProperty());
    }

    private void intoStore(BizInboundTask item, ItemSyncVO vo) throws Exception {
        List<ContainerInfo> containerInfos = containerInfoService.findByMap(MapUtils.put("containerNo", item.getContainerNo()).getMap());
        BigDecimal changeQty = BigDecimal.ZERO;
        BigDecimal targetQty = BigDecimal.ZERO;
        if (CollectionUtils.isEmpty(containerInfos)) {
            BizInboundTaskDetail detail = item.getSubList().get(0);
            BigDecimal qty = item.getSubList().stream().map(BizInboundTaskDetail::getQty)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            ContainerInfoDetail containerInfoDetail = new ContainerInfoDetail();
            containerInfoDetail.setContainerNo(item.getContainerNo());
            containerInfoDetail.setContainerSubNo(item.getContainerNo());
            containerInfoDetail.setAreaType(AreaTypeConstant.AGV_CL);
            containerInfoDetail.setItemId(vo.getItemId());
            containerInfoDetail.setLotId(detail.getLotId());
            containerInfoDetail.setOwnerId(detail.getOwnerId());
            containerInfoDetail.setPackId(detail.getPackId());
            containerInfoDetail.setIsLock(0);
            containerInfoDetail.setQty(qty);
            containerInfoDetail.setTaskType(0);
            containerInfoDetail.setLockQty(BigDecimal.ZERO);
            containerInfoDetail.setCreateTime(LocalDateTime.now());
            if (Objects.isNull(vo.getUomList().get(0).getVolume())) {
                throw new PrologException("商品资料volume字段不能为空");
            }
            containerInfoDetail.setSingleVolume(vo.getUomList().get(0).getVolume().divide(vo.getUomList().get(0).getConversionRate(), 2, BigDecimal.ROUND_DOWN));
            containerInfoDetail.setVolume(containerInfoDetail.getSingleVolume().multiply(qty));
            containerInfoDetail.setMaxVolume(vo.getPalletStdQuantity());
            changeQty = changeQty.add(containerInfoDetail.getQty());
            targetQty = targetQty.add(containerInfoDetail.getQty());
            containerInfoDetailMapper.save(containerInfoDetail);

            ContainerInfo containerInfo = new ContainerInfo();
            containerInfo.setContainerNo(item.getContainerNo());
            containerInfo.setContainerType(ContainerInfoTypeConstants.GOODS_PALLET);
            containerInfo.setAreaType(AreaTypeConstant.AGV_CL);
            containerInfo.setIsLock(0);
            containerInfo.setTaskType(ContainerTaskTypeConstants.INBOUND);
            containerInfo.setCreateTime(LocalDateTime.now());
            containerInfo.setWarehouseArea(WmsCarryTaskInCode.AGVL.getCode());
            containerInfoService.save(containerInfo);

            ContainerStoreChange changeChange = new ContainerStoreChange();
            changeChange.setContainerNo(containerInfoDetail.getContainerNo());
            changeChange.setContainerSubNo(containerInfoDetail.getContainerSubNo());
            changeChange.setTaskType(BaseWorkTypeConstants.INBOUND_TYPE);
            changeChange.setSoureQty(containerInfoDetail.getQty());
            changeChange.setChangeQty(changeQty);
            changeChange.setTargetQty(targetQty);
            changeChange.setRemark("入库拆零库托盘区");
            changeChange.setCreateTime(LocalDateTime.now());
            changeChange.setUpdateTime(LocalDateTime.now());
            changeChange.setPackId(containerInfoDetail.getPackId());
            changeChange.setOwnerId(containerInfoDetail.getOwnerId());
            changeChange.setLotId(containerInfoDetail.getLotId());
            changeChange.setItemId(containerInfoDetail.getItemId());
            containerStoreChangeService.save(changeChange);
        }
    }

    //入库agv库区
    private void agvInboundCarryTask(BizInboundTask item) throws Exception {
        //1 查询入库任务区域
        LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.EISKQ).put("wmsAreaNo", item.getWmsLocationCode()).getMap()).stream().findFirst().orElse(null);
        if (Objects.isNull(locationCfg)) {
            log.warn("托盘{}agv入库任务发送失败：对应的区域{}未配置", item.getContainerNo(), item.getWmsLocationCode());
            return;
        }
        //2 检验是否有空闲货位
        if (!plgFeignRouteService.checkAreaIn(locationCfg.getAreaNo())) {
            log.warn("托盘{}agv入库任务发送失败：对应的区域{}无空闲货位", item.getContainerNo(), item.getWmsLocationCode());
            return;
        }
        //3 修改入库单状态为已开始
        this.updateInboundTaskStatus(item);
        //4 创建库存
        containerInfoService.createContainerStore(item);
        //5 创建点位
        ItemContainerReqDto itemContainerReqDto = new ItemContainerReqDto();
        itemContainerReqDto.setLocationNo(item.getOriginalLocation());
        itemContainerReqDto.setContainerNo(item.getContainerNo());
        itemContainerReqDto.setContainerType(item.getContainerType().toString());
        itemContainerReqDto.setBusinessProperty(item.getItemContainerBusinessProperty());
        plgFeignRouteService.createItemContainer(itemContainerReqDto);
        //6 发送搬运
        plgFeignRouteService.createCarryTask(item.getContainerNo(), null, item.getOriginalArea(), item.getOriginalLocation(), locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.INBOUND_TYPE), 1, "agv入库", item.getItemContainerBusinessProperty());
    }

    //入库四项库
    private void sxkInboundCarryTask(BizInboundTask item) throws Exception {
        //1 查询四向库所有空闲并且入库方向的bcr
        LocationCfg locationCfg = locationCfgService.getLocationCfgOccupy(item.getContainerNo());
        if (Objects.isNull(locationCfg)) {
            log.warn("托盘{}四项库入库任务发送失败 无空闲bcr", item.getContainerNo());
            return;
        }
        //2 修改入库单状态为已开始
        this.updateInboundTaskStatus(item);
        //3 创建点位
        plgFeignRouteService.createItemContainer(item.getOriginalLocation(), item.getContainerNo(), item.getContainerType().toString(), item.getItemContainerBusinessProperty());
        //3 发送搬运
        plgFeignRouteService.createCarryTask(item.getContainerNo(), null, item.getOriginalArea(), item.getOriginalLocation(), locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.MOVE_TYPE), 1, "搬运到bcr口", null);
    }

    @Override
    public void doInboundBack(CarryTaskCallbackDto carryTaskCallbackDto) {
        //final ContainerInfo containerInfo = containerInfoService.findByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).getMap()).stream().findFirst().orElseThrow(() -> new PrologException(String.format("容器%s未查询到库存信息", carryTaskCallbackDto.getContainerNo())));
        Criteria criteriaDetail = new Criteria(ContainerInfo.class);
        criteriaDetail.setRestriction(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo()));
        containerInfoService.updateMapByCriteria(MapUtils.put("taskType", ContainerTaskTypeConstants.IDLE).put("updateTime", LocalDateTime.now()).getMap(), criteriaDetail);

        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(Restrictions.and(Restrictions.eq("palletNo", carryTaskCallbackDto.getContainerNo())));
        palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", 0).put("subArea", carryTaskCallbackDto.getEndRegion())
                .put("containerMoveTaskId", null).getMap(), criteria);

        ContainerInfo containerInfo = containerInfoService.findOneByContainerNo(carryTaskCallbackDto.getContainerNo());
        if (Objects.nonNull(containerInfo) && containerInfo.getContainerType() == 4) {
            List<ContainerInfoDetail> containerInfoDetailList = containerInfoDetailMapper.findByMap(MapUtils.put("containerNo", containerInfo.getContainerNo()).getMap(), ContainerInfoDetail.class);
            if (CollectionUtils.isEmpty(containerInfoDetailList)) {
                containerInfoService.deleteById(containerInfo.getId());
                palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils
                        .put("palletType", "0").put("angle", 0).getMap(), criteria);
            }
        }
    }

    @Override
    public List<InboundOrderRespDto> inboundOrderList(InboundOrderReqDto req) {
        return bizInboundTaskMapper.inboundOrderList(req);
    }

    @Override
    public void doAgvInboundCallBack(CarryTaskCallbackDto carryTaskCallbackDto) throws Exception {
        BizInboundTask bizInboundTask = bizInboundTaskMapper.findByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).getMap(), BizInboundTask.class).stream().findFirst().orElse(null);

        Criteria criteria = new Criteria(ContainerTask.class);
        criteria.setRestriction(Restrictions.lt("status", ContainerTaskStatusConstants.IN_PLACE_STATUS)
                .and(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo())));
        List<ContainerTask> containerTaskList = containerTaskMapper.findByCriteria(criteria);
        if (Objects.isNull(bizInboundTask)) {
            inboundReturnCallBack(carryTaskCallbackDto);
        } else if (StrUtil.equals(bizInboundTask.getWorkType(), BizInboundTask.SUPPLY_WORK_TYPE)) {
            if (CollectionUtil.isEmpty(containerTaskList)) {
                throw new PrologException(String.format("托盘【%s】没有容器任务", carryTaskCallbackDto.getContainerNo()));
            }
            List<ContainerTask> containerTasks = containerTaskList.stream().filter(item -> item.getTaskType() == BaseBillTypeConstants.REPLENISH_TYPE).collect(Collectors.toList());
            Criteria criteria1 = new Criteria(ContainerTask.class);
            criteria1.setRestriction(Restrictions.lt("status", ContainerTaskStatusConstants.IN_PLACE_STATUS)
                    .and(Restrictions.eq("taskType", BaseBillTypeConstants.REPLENISH_TYPE))
                    .and(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo())));
            //修改状态为到位
            containerTaskMapper.updateMapByCriteria(MapUtils.put("status", ContainerTaskStatusConstants.IN_PLACE_STATUS).put("finishTime", LocalDateTime.now()).getMap(), criteria1);
            //追加托盘修改逻辑
            addPalletLogic(containerTasks);
            //修改补货上架单数量为 补货出库追加后的最终数量
            BigDecimal qty = containerTasks.stream().map(ContainerTask::getQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            BizInboundTaskDetail bizInboundTaskDetail = bizInboundTaskDetailMapper.findByMap(MapUtils.put("inboundId", bizInboundTask.getId()).getMap(), BizInboundTaskDetail.class).get(0);
            if (qty.compareTo(bizInboundTaskDetail.getQty()) > 0) {
                //有追加的库存数量
                //重新叫货架
                BigDecimal remainQty = qty.subtract(bizInboundTaskDetail.getQty());
                bizInboundTaskDetail.setQty(remainQty);
                bizInboundTask.setSubList(Arrays.asList(bizInboundTaskDetail));
                bizInboundTask.setExtend3(BaseConstant.SUPPLY_APPEND_FLAG);
//                AssertUtils.isTrue(dismantleFeignService.callShelves(bizInboundTask), "呼叫货架失败");
                bizInboundTaskDetail.setQty(qty);
                bizInboundTaskDetailMapper.update(bizInboundTaskDetail);
            }
        } else if (String.valueOf(BaseTaskTypeConstants.INBOUND_TYPE).equals(bizInboundTask.getWorkType())) {
            //入拆零区到位和货架回库到位
            inboundReturnCallBack(carryTaskCallbackDto);
        }
        //拆零上架或拆零补货任务到达上架站台
//        StationCfg stationCfg = stationCfgService.findByMap(MapUtils.put("areaNo", carryTaskCallbackDto.getEndRegion()).getMap()).stream().findFirst().orElse(null);
//        if (Objects.nonNull(bizInboundTask) && Objects.nonNull(stationCfg) && Objects.equals(stationCfg.getStationType(), 70)) {
//            bizInboundTask.setStatus(18);
//            bizInboundTask.setUpdateTime(LocalDateTime.now());
//            bizInboundTask.setExtend1(stationCfg.getId().toString());
//            bizInboundTaskMapper.update(bizInboundTask);
//        }
        List<ContainerTask> replenishContainerTaskList = containerTaskList.stream().filter(item -> item.getTaskType() == BaseBillTypeConstants.REPLENISH_TYPE).collect(Collectors.toList());
        long count1 = containerTaskList.stream().filter(item -> item.getContainerType() > 0).count();
        //补货上架整托直接发往拆零库内的，到位补货出库转历史
        if (CollectionUtil.isNotEmpty(replenishContainerTaskList) && count1 > 0 && Objects.isNull(bizInboundTask) && !replenishContainerTaskList.get(0).getWarehouseArea().equals("AGVL")) {
            //转历史回告
            for (ContainerTask containerTask : replenishContainerTaskList) {
                ContainerTaskHis containerTaskHis = new ContainerTaskHis();
                BeanUtils.copyProperties(containerTask, containerTaskHis);
                containerTaskHisMapper.save(containerTaskHis);
                containerTaskMapper.deleteById(containerTask.getId(), ContainerTask.class);

                final BizOutboundTask outboundTask = bizOutboundTaskMapper.findById(containerTask.getOutboundId(), BizOutboundTask.class);
                final BizOutboundTaskDetail outboundTaskDetail = bizOutboundTaskDetailMapper.findById(containerTask.getOutboundDetailId(), BizOutboundTaskDetail.class);

                wmsTaskFinishBackService.execute(Arrays.asList(WmsTaskFinishDto.builder()
                        .msgId(StrUtil.uuid())
                        .billNo(outboundTask.getBillNo())
                        .containerNo(carryTaskCallbackDto.getContainerNo())
                        .businessType(outboundTask.getBusinessType())
                        .workType(outboundTask.getWorkType())
                        .warehouseId(outboundTask.getWmsWarehouseId())
                        .taskId(outboundTask.getUpperSystemTaskId())
                        .taskLineId(outboundTaskDetail.getSeqNo())
                        .itemId(outboundTaskDetail.getItemId())
                        .lotId(outboundTaskDetail.getLotId())
                        .ownerId(outboundTaskDetail.getOwnerId())
                        .packId(outboundTaskDetail.getPackId())
                        .inventoryQty(containerTask.getQty())
                        .employeeId("eis")
                        .wmsLocationCode(outboundTask.getWmsLocationCode())
                        .lackQty("0")
                        .isLack(1)
                        .build()));
            }

            for (ContainerTask containerTask : replenishContainerTaskList) {
                Integer outboundId = containerTask.getOutboundId();
                List<ContainerTask> containerTasks = containerTaskMapper.findByMap(MapUtils.put("outboundId", outboundId).getMap(), ContainerTask.class);
                if (CollectionUtil.isEmpty(containerTasks)) {
                    List<BizOutboundTaskDetail> bizOutboundTaskDetailList = bizOutboundTaskDetailMapper.findByMap(MapUtils.put("outboundId", outboundId).getMap(), BizOutboundTaskDetail.class);
                    for (BizOutboundTaskDetail bizOutboundTaskDetail : bizOutboundTaskDetailList) {
                        BizOutboundTaskDetailHis bizOutboundTaskDetailHis = new BizOutboundTaskDetailHis();
                        BeanUtils.copyProperties(bizOutboundTaskDetail, bizOutboundTaskDetailHis);
                        bizOutboundTaskDetailHisMapper.save(bizOutboundTaskDetailHis);
                        bizOutboundTaskDetailMapper.deleteById(bizOutboundTaskDetail.getId(), BizOutboundTaskDetail.class);
                    }
                    final BizOutboundTask outboundTask = bizOutboundTaskMapper.findById(outboundId, BizOutboundTask.class);
                    orderLogMapper.save(OrderLog.builder()
                            .orderId(outboundTask.getId().toString())
                            .orderNo(outboundTask.getBillNo())
                            .type("补货完成")
                            .createTime(new Date())
                            .build());

                    BizOutboundTaskHis bizOutboundTaskHis = new BizOutboundTaskHis();
                    BeanUtils.copyProperties(outboundTask, bizOutboundTaskHis);
                    bizOutboundTaskHisMapper.save(bizOutboundTaskHis);
                    bizOutboundTaskMapper.deleteById(outboundId, BizOutboundTask.class);
                }
            }
            List<Integer> collect = replenishContainerTaskList.stream().map(ContainerTask::getId).collect(Collectors.toList());
            //根据此容器号查出对应所有容器任务对应的所有订单
            List<Integer> outboundIds = replenishContainerTaskList.stream().map(ContainerTask::getOutboundId).collect(Collectors.toList());
            //查询此容器对应的所有订单
            Criteria criteria1 = new Criteria(BizOutboundTask.class);
            criteria1.restrictionBuilder().in(BizOutboundTask::getId, outboundIds).build();
            List<BizOutboundTask> bizOutboundTaskList = bizOutboundTaskMapper.findByCriteria(criteria1);
            //查询此容器对应的所有订单 对应的所有容器任务
            Criteria criteria2 = new Criteria(ContainerTask.class);
            criteria2.restrictionBuilder().in(ContainerTask::getOutboundId, outboundIds).build();
            List<ContainerTask> containerTasks = containerTaskMapper.findByCriteria(criteria2);
            //遍历订单查询容器任务是否都上架完成，全部完成转历史和回告wms
            for (BizOutboundTask bizOutboundTask : bizOutboundTaskList) {
                List<ContainerTask> outboundContainerTaskList = containerTasks.stream().filter(item -> Objects.equals(item.getOutboundId(), bizOutboundTask.getId())).collect(Collectors.toList());
                long c = outboundContainerTaskList.stream().filter(item -> item.getShelvesState() != 1).count();
                if (c == 0) {
                    orderLogMapper.save(OrderLog.builder()
                            .orderId(bizOutboundTask.getId().toString())
                            .orderNo(bizOutboundTask.getBillNo())
                            .type("补货完成")
                            .createTime(new Date())
                            .build());
                    //转历史
                    List<BizOutboundTaskDetail> bizOutboundTaskDetailList = bizOutboundTaskDetailMapper.findByMap(MapUtils.put("outboundId", bizOutboundTask.getId()).getMap(), BizOutboundTaskDetail.class);
                    for (BizOutboundTaskDetail bizOutboundTaskDetail : bizOutboundTaskDetailList) {
                        BizOutboundTaskDetailHis bizOutboundTaskDetailHis = new BizOutboundTaskDetailHis();
                        BeanUtil.copyProperties(bizOutboundTaskDetail, bizOutboundTaskDetailHis);
                        bizOutboundTaskDetailHisMapper.save(bizOutboundTaskDetailHis);
                        bizOutboundTaskDetailMapper.deleteById(bizOutboundTaskDetail.getId(), BizOutboundTaskDetail.class);
                    }
                    BizOutboundTaskHis bizOutboundTaskHis = new BizOutboundTaskHis();
                    BeanUtil.copyProperties(bizOutboundTask, bizOutboundTaskHis);
                    bizOutboundTaskHisMapper.save(bizOutboundTaskHis);
                    bizOutboundTaskMapper.deleteById(bizOutboundTask.getId(), BizOutboundTask.class);

                    outboundContainerTaskList = outboundContainerTaskList.stream().filter(item -> !collect.contains(item.getId())).collect(Collectors.toList());
                    for (ContainerTask containerTask : outboundContainerTaskList) {
                        ContainerTaskHis taskHis = new ContainerTaskHis();
                        containerTask.setStatus(ContainerTaskStatusConstants.FINISH_STATUS);
                        containerTask.setUpdateTime(LocalDateTime.now());
                        BeanUtil.copyProperties(containerTask, taskHis);
                        containerTaskHisMapper.save(taskHis);
                        containerTaskMapper.deleteById(containerTask.getId(), ContainerTask.class);
                    }

                }
            }
        }
    }


    @Override
    public void inboundReturnCallBack(CarryTaskCallbackDto carryTaskCallbackDto) throws Exception {
        //入拆零区到位和货架回库
        if (!carryTaskCallbackDto.getEndRegion().contains("CLJL")) {
            Criteria criteriaDetail = new Criteria(ContainerInfo.class);
            criteriaDetail.setRestriction(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo()));
            long count = containerInfoService.updateMapByCriteria(MapUtils.put("taskType", ContainerTaskTypeConstants.IDLE).put("updateTime", LocalDateTime.now()).put("source", carryTaskCallbackDto.getEndLocation()).getMap(), criteriaDetail);
            if (count > 0) {
                //是托盘直接入库到托盘区，任务转历史
                BizInboundTask bizInboundTask = bizInboundTaskMapper.findByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).put("extend3", BaseConstant.AGVL_INBOUND_TAG).getMap(), BizInboundTask.class).stream().findFirst().orElse(null);
                if (ObjectUtil.isNotEmpty(bizInboundTask)) {
                    Criteria criteria = Criteria.forClass(BizInboundTaskDetail.class);
                    criteria.setRestriction(Restrictions.eq("inboundId", bizInboundTask.getId()));
                    bizInboundTaskDetailMapper.updateMapByCriteria(MapUtils.put("detailStatus", BaseStatusEnum.STATUS_FINISH.getCode()).getMap(), criteria);
                    doInboundCallBack(carryTaskCallbackDto);
                }
            }
        }

        List<PalletInfo> palletInfoList = palletInfoMapper.findByMap(null, PalletInfo.class);
        if (palletInfoList.isEmpty()) {
            return;
        }
        palletInfoList = palletInfoList.stream().filter(p -> !StringUtils.isEmpty(p.getContainerMoveTaskId())).collect(Collectors.toList());
        Map<String, PalletInfo> containerInfoMap = palletInfoList.stream().collect(Collectors.toMap(PalletInfo::getContainerMoveTaskId, o -> o));
        PalletInfo palletInfo = null;

        if (StringUtils.isEmpty(carryTaskCallbackDto.getId())) {
            return;
        }
        palletInfo = containerInfoMap.get(carryTaskCallbackDto.getId());
        if (!containerInfoMap.containsKey(carryTaskCallbackDto.getId())) {
            return;
        }
        if (!palletInfo.getPalletNo().equals(carryTaskCallbackDto.getContainerNo())) {
            return;
        }
        Criteria criteriaPallet = Criteria.forClass(PalletInfo.class);
        criteriaPallet.setRestriction(Restrictions.eq("palletNo", carryTaskCallbackDto.getContainerNo()));
        palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", BaseConstant.NO).put("containerMoveTaskId", null)
                .put("updateTime", new Date()).getMap(), criteriaPallet);
    }

    private void addPalletLogic(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.IN_PLACE_STATUS)));
            long count = containerTaskMapper.findCountByCriteria(criteria);
            if (count == 0) {
                outTaskDetail = bizOutboundTaskDetailMapper.findById(containerTask.getOutboundDetailId(), BizOutboundTaskDetail.class);
                if (outTaskDetail == null) {
                    throw new Exception("出库任务明细不存在，任务ID：" + containerTask.getOutboundDetailId());
                }
                if (outTaskDetail.getStatus() < BaseStatusEnum.STATUS_FINISH.getCode()) {
                    outTaskDetail.setActQty(outTaskDetail.getPlanQty());
                    outTaskDetail.setStatus(BaseStatusEnum.STATUS_FINISH.getCode());
                    outTaskDetail.setUpdateTime(LocalDateTime.now());
                    bizOutboundTaskDetailMapper.update(outTaskDetail);
                }
            }
            //判断主任务是否完成
            criteria = new Criteria(BizOutboundTaskDetail.class);
            criteria.setRestriction(Restrictions.eq("outboundId", containerTask.getOutboundId())
                    .and(Restrictions.lt("status", BaseStatusEnum.STATUS_FINISH.getCode())));
            count = bizOutboundTaskDetailMapper.findCountByCriteria(criteria);
            if (count == 0) {
                outTask = bizOutboundTaskMapper.findById(containerTask.getOutboundId(), BizOutboundTask.class);
                if (outTask == null) {
                    throw new Exception("出库任务不存在，任务ID：" + containerTask.getOutboundId());
                }
                if (outTask.getStatus() < BaseStatusEnum.STATUS_FINISH.getCode()) {
                    outTask.setStatus(BaseStatusEnum.STATUS_FINISH.getCode());
                    outTask.setUpdateTime(LocalDateTime.now());
                    bizOutboundTaskMapper.update(outTask);
                }
            }
        }
    }

    @Override
    @Transactional
    public String allocationRoadwayReq(CallbackLayerDTO callbackLayerDTO) throws Exception {
        String reLocationNos = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.SUPPLY_BACK_REASSIGN_LOCATION));
        String bindLocations = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.SUPPLY_BACK_BIND_LOCATION));

        List<String> reLocationList = Arrays.asList(reLocationNos.split(","));
        List<String> bindLocationList = Arrays.asList(bindLocations.split(","));
        //补货回四向库重新分层二次分配点
        if (reLocationList.contains(callbackLayerDTO.getLocationNo())) {
            List<CarryTaskDto> containerCarry = plgFeignRouteService.getContainerCarry(callbackLayerDTO.getContainerNo());
            Assert.notEmpty(containerCarry, String.format("托盘%s未查询到对应搬运任务", callbackLayerDTO.getContainerNo()));
            CarryTaskDto carryTaskDto = containerCarry.get(0);
            if (carryTaskDto.getEndRegion().contains("SX")) {
                return getBestArea();
            }
            // todo 补货小熊新逻辑回退  再修正
            else if (carryTaskDto.getEndRegion().contains("CLSJ")) {
                Criteria criteria = Criteria.forClass(BizInboundTask.class);
                criteria.restrictionBuilder().eq(BizInboundTask::getContainerNo, callbackLayerDTO.getContainerNo()).build();
                BizInboundTask bizInboundTask = bizInboundTaskMapper.findByCriteria(criteria).stream().findFirst()
                        .orElseThrow(() -> new PrologException(String.format("未找到对应托盘【%s】的上架任务", callbackLayerDTO.getContainerNo())));
                List<BizInboundTaskDetail> bizInboundTaskDetails = bizInboundTaskDetailMapper.findByMap(MapUtils.put("inboundId", bizInboundTask.getId()).getMap(), BizInboundTaskDetail.class);
                bizInboundTask.setSubList(bizInboundTaskDetails);
                AssertUtils.isNotTrue(!dismantleFeignService.callShelves(bizInboundTask), "调用拆零上架呼叫货架失败");
            }
        } else if (bindLocationList.contains(callbackLayerDTO.getLocationNo())) {
            LocationCfg locationCfg = locationCfgService.getLocationCfgOccupy(callbackLayerDTO.getContainerNo());
            if (Objects.isNull(locationCfg)) {
                throw new Exception(String.format("托盘{}入库任务发送失败 无空闲bcr", callbackLayerDTO.getContainerNo()));
            }
            return locationCfg.getAreaNo();
        } else {
            //入库重新分层二次分配点
            final List<BizInboundTask> bizInboundTasks = bizInboundTaskMapper.findByMap(MapUtils.put("containerNo", callbackLayerDTO.getContainerNo()).put("status", BaseStatusEnum.STATUS_STARTED.getCode()).getMap(), BizInboundTask.class);
            if (CollectionUtil.isNotEmpty(bizInboundTasks)) {
                LocationCfg locationCfg = locationCfgService.findByMap(MapUtils.put("type", LocationCfgConstants.RCFP).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("二次分配点位未配置"));
                final BizInboundTaskDetail bizInboundTaskDetail = bizInboundTaskDetailMapper.findByMap(MapUtils.put("inboundId", bizInboundTasks.get(0).getId()).getMap(), BizInboundTaskDetail.class).get(0);
                BestAreaDto bestAreaDto = BestAreaDto.builder().containerNo(callbackLayerDTO.getContainerNo())
                        .areaNo(callbackLayerDTO.getLocationNo()).sourceArea(locationCfg.getAreaNo()).deviceHeight(callbackLayerDTO.getHeight())
                        .sourceLocation(callbackLayerDTO.getLocationNo()).businessProperty(bizInboundTaskDetail.getItemId() + "@@" + bizInboundTaskDetail.getLotId()).build();
                String bestInAreaNo = findBestInAreaNo(bestAreaDto);
                return bestInAreaNo;
            }
        }
        return null;
    }

    private String getBestArea() throws Exception {
        List<DeviceInfo> deviceInfoList = deviceInfoService.findCanUseAreaByItemType(1, null);
        List<String> areaNoList = deviceInfoList.stream().map(DeviceInfo::getDeviceNo).collect(Collectors.toList());
        List<AreaLocationCountDto> areaLocationCountDtos = plgFeignRouteService.queryAreaLocationCountDtoList(areaNoList);
        areaLocationCountDtos = areaLocationCountDtos.stream().filter(item -> item.getFreeCount() > 0).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(areaLocationCountDtos)) {
            throw new Exception("没有可用的四向库楼层");
        }
        AreaTaskReqDto ad = new AreaTaskReqDto();
        ad.setAreaNos(areaLocationCountDtos.stream().map(AreaLocationCountDto::getAreaNo).collect(Collectors.toList()));
        Map<String, Integer> sxkTaskByAreaNos = plgFeignRouteService.getSxkTaskByAreaNos(ad);
        areaLocationCountDtos.forEach(item -> item.setLocatorCount(sxkTaskByAreaNos.get(item.getAreaNo())));
        AreaLocationCountDto areaLocationCountDto = areaLocationCountDtos.stream().sorted(Comparator.comparing(AreaLocationCountDto::getLocatorCount).thenComparing(Comparator.comparing(AreaLocationCountDto::getFreeCount, Comparator.reverseOrder()))).findFirst().get();
        return areaLocationCountDto.getAreaNo();
    }

    @Override
    public void hjBack(CarryTaskCallbackDto carryTaskCallbackDto) {
        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(Restrictions.and(Restrictions.eq("palletNo", carryTaskCallbackDto.getContainerNo())));
        palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", 0).put("containerMoveTaskId", null).getMap(), criteria);
    }

    @Override
    public void supplerBack(CarryTaskCallbackDto carryTaskCallbackDto) throws Exception {
        List<String> collect = locationCfgService.findByMap(MapUtils.put("type", 10).getMap()).stream().map(LocationCfg::getLocationNo).collect(Collectors.toList());
        if (collect.contains(carryTaskCallbackDto.getEndLocation())) {
            return;
        }
        Criteria criteriaDetail = new Criteria(ContainerInfo.class);
        criteriaDetail.setRestriction(Restrictions.eq("containerNo", carryTaskCallbackDto.getContainerNo()));
        containerInfoService.updateMapByCriteria(MapUtils.put("taskType", ContainerTaskTypeConstants.IDLE).put("source", carryTaskCallbackDto.getEndLocation()).put("updateTime", LocalDateTime.now()).getMap(), criteriaDetail);
        if (StrUtil.isNotBlank(carryTaskCallbackDto.getExtend1())) {
            WmsInBackReqDto wmsInReqDto = new WmsInBackReqDto();
            wmsInReqDto.setWarehouseId(carryTaskCallbackDto.getExtend2());
            wmsInReqDto.setEnterpriseId(carryTaskCallbackDto.getExtend3());
            wmsInReqDto.setTaskId(carryTaskCallbackDto.getExtend1());
            wmsInReqDto.setWmsLocationCode(WmsCarryTaskInCode.AGVZ.getCode());
            wmsInReqDto.setMsgId(StrUtil.uuid());
            wmsInReqDto.setContainerNo(carryTaskCallbackDto.getContainerNo());
            try {
                RestMessage wmsResult = wmsInBackService.execute(wmsInReqDto);
                log.info("入库完成回告wms" + wmsResult);
            } catch (RetryException e) {
                log.warn("入库完成回告wms失败，进入重试：" + e.getMessage());
            }
        }
    }

    @Override
    public void emptyBack(CarryTaskCallbackDto carryTaskCallbackDto) {
        containerInfoDetailMapper.deleteByMap(MapUtils.put("containerNo", carryTaskCallbackDto.getContainerNo()).getMap(), ContainerInfoDetail.class);
        ContainerInfo containerInfo = containerInfoService.findOneByContainerNo(carryTaskCallbackDto.getContainerNo());
        containerInfo.setContainerType(ContainerInfoTypeConstants.EMPTY_PALLET);
        containerInfo.setTaskType(ContainerTaskTypeConstants.IDLE);
        containerInfo.setUpdateTime(LocalDateTime.now());
        containerInfo.setAreaType(Integer.parseInt(WmsCarryTaskInCode.AREA_TYPE.get(carryTaskCallbackDto.getExtend1()).toString()));
        containerInfo.setWarehouseArea(carryTaskCallbackDto.getExtend1());
        containerInfoService.update(containerInfo);
    }
}

