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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.cs.basic.item.model.vo.ItemBarCodeVO;
import com.prolog.cs.basic.item.model.vo.ItemBaseInfoVO;
import com.prolog.eis.aspect.RedissonLock;
import com.prolog.eis.common.util.location.LocationConstants;
import com.prolog.eis.constants.base.BaseTaskTypeConstants;
import com.prolog.eis.constants.base.ContainerTaskTypeConstants;
import com.prolog.eis.constants.base.ContainerTypeConstants;
import com.prolog.eis.constants.cfg.LocationCfgConstants;
import com.prolog.eis.constants.redisKey.RedisKey;
import com.prolog.eis.constants.sys.SysParamConstants;
import com.prolog.eis.constants.wms.WmsConstants;
import com.prolog.eis.core.dto.route.CreateCarryTaskDto;
import com.prolog.eis.core.model.biz.carry.CarryTask;
import com.prolog.eis.core.model.biz.carry.CarryTaskAngle;
import com.prolog.eis.dao.out.BizOutboundTaskDetailDismantleGridMapper;
import com.prolog.eis.dao.out.BizOutboundTaskDismantleSupplyMapper;
import com.prolog.eis.dao.out.OrderLogMapper;
import com.prolog.eis.dao.shelves.PalletInfoMapper;
import com.prolog.eis.dao.shelves.PalletLocationMapper;
import com.prolog.eis.dto.item.ItemSyncVO;
import com.prolog.eis.dto.outbound.SupervisionCodeDto;
import com.prolog.eis.dto.outbound.WaveBindConditionDto;
import com.prolog.eis.dto.page.*;
import com.prolog.eis.dto.wms.*;
import com.prolog.eis.enums.base.BaseStatusEnum;
import com.prolog.eis.enums.base.LayerEnum;
import com.prolog.eis.enums.station.StationTypeEnum;
import com.prolog.eis.enums.wms.WmsCarryTaskInCode;
import com.prolog.eis.model.container.*;
import com.prolog.eis.model.out.BizOutboundTaskDetailDismantle;
import com.prolog.eis.model.out.BizOutboundTaskDetailDismantleGrid;
import com.prolog.eis.model.out.BizOutboundTaskDetailDismantleHis;
import com.prolog.eis.model.out.BizOutboundTaskDismantleSupply;
import com.prolog.eis.model.outbound.*;
import com.prolog.eis.model.shelves.*;
import com.prolog.eis.router.vo.ContainerLocationVo;
import com.prolog.eis.service.container.EmptyContainerTaskService;
import com.prolog.eis.service.container.MergeContainerTaskService;
import com.prolog.eis.service.feign.RouteFeignService;
import com.prolog.eis.service.out.*;
import com.prolog.eis.service.page.PcService;
import com.prolog.eis.service.redis.RedisService;
import com.prolog.eis.service.shelves.*;
import com.prolog.eis.service.wms.WmsContainerStatusUpdateService;
import com.prolog.eis.service.wms.WmsTaskFinishBackService;
import com.prolog.eis.utils.AngleConversionAB;
import com.prolog.eis.utils.MapUtils;
import com.prolog.eis.utils.PrimaryAgvGeneraterUtils;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.core.exception.BizException;
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.dao.util.PageUtils;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.upcloud.base.inventory.model.BatchNumberSync;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
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.stream.Collectors;

/**
 * @desc:
 * @author: zhangJie
 * @date: 2023/9/13 15:03
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PcServiceImpl implements PcService {

    private final AllotmentCfgService allotmentCfgService;
    private final ItemService itemService;
    private final UserTemplate userTemplate;
    private final RedisService redisService;
    private final InventoryService inventoryService;
    private final ContainerTaskService containerTaskService;
    private final ContainerTaskDismantleService containerTaskDismantleService;
    private final BizOutboundTaskDetailService bizOutboundTaskDetailService;
    private final AllotmentTaskRecordService allotmentTaskRecordService;
    private final AllotmentTaskRecordHisService allotmentTaskRecordHisService;
    private final BizOutboundTaskService bizOutboundTaskService;
    private final GridInfoService gridInfoService;
    private final BizOutboundTaskDetailDismantleService bizOutboundTaskDetailDismantleService;
    private final BizOutboundTaskDetailDismantleHisService outboundTaskDetailDismantleHisService;
    private final ContainerInfoDetailService containerInfoDetailService;
    private final ContainerInfoService containerInfoService;
    private final MergeContainerTaskService mergeContainerTaskService;
    private final StationCfgService stationCfgService;
    private final RouteFeignService routeFeignService;
    private final PrintTaskService printTaskService;
    private final LocationCfgService locationCfgService;
    private final PalletLocationMapper palletLocationMapper;
    private final PalletInfoMapper palletInfoMapper;
    private final BizOutboundTaskHisService bizOutboundTaskHisService;
    private final BizOutboundTaskDetailHisService bizOutboundTaskDetailHisService;
    private final ContainerTaskHisService containerTaskHisService;
    private final WmsTaskFinishBackService wmsTaskFinishBackService;
    private final ContainerStoreChangeService containerStoreChangeService;
    private final EmptyContainerTaskService emptyContainerTaskService;
    private final WmsContainerStatusUpdateService wmsContainerStatusUpdateService;
    private final BizOutboundTaskDismantleSupplyMapper outboundTaskDismantleSupplyMapper;
    private final RedisTemplate redisTemplate;
    private final OrderLogMapper orderLogMapper;
    private final BizOutboundTaskDetailDismantleGridMapper outboundTaskDetailDismantleGridMapper;

    @Override
    public Boolean checkAllotment(String stationNo) {
        List<AllotmentCfg> allotmentCfgList = allotmentCfgService.findByMap(MapUtils.put(AllotmentCfg::getStationNo, stationNo).getMap());
        return CollectionUtil.isNotEmpty(allotmentCfgList);
    }

    @Override
    public void cleanAskUser(String code) {
        redisService.existsKey(RedisKey.ALLOTMENT_USER_ITEM + code);
    }

    @Override
    public List<AllotmentOrderDto> allotmentOrderShow(String itemId) throws Exception {
        //1 校验此商品索取人是否一致
//        if (!checkUser(code)) {
//            throw new PrologException("此商品已被其他人员索取");
//        }
        //2 根据条码查询商品信息
//        final ItemBarCodeVO itemBarCodeVO = itemService.queryItemByBarCode(code);
        ItemSyncVO itemBaseInfoVO = itemService.queryItemMst(Arrays.asList(itemId)).stream().findFirst().orElseThrow(() -> new PrologException("未查询到商品信息"));
        List<AllotmentOrderDto> allotmentOrderDtoList = containerTaskDismantleService.findAllotmentOrder(itemBaseInfoVO.getItemId());
        AssertUtils.isNotTrue(CollectionUtil.isEmpty(allotmentOrderDtoList), "没有找到对应出库任务");
        List<BatchNumberSync> batchNumberSync = inventoryService.getBatchNumberSync(ListUtil.toList(allotmentOrderDtoList.stream().map(AllotmentOrderDto::getLotId).collect(Collectors.toList())));
        allotmentOrderDtoList.forEach(item -> {
            BatchNumberSync batchNumber = batchNumberSync.stream().filter(inner -> StrUtil.equals(inner.getBatchId(), item.getLotId())).findFirst().orElseThrow(() -> new PrologException("未查询到批次信息"));
            item.setItemCode(itemBaseInfoVO.getItemCode());
            item.setItemName(itemBaseInfoVO.getItemName());
            item.setLotNo(batchNumber.getManufacturerLotNum());
            item.setCode(itemBaseInfoVO.getPieceBarcode());
        });
        allotmentOrderDtoList = allotmentOrderDtoList.stream().sorted(Comparator.comparing(AllotmentOrderDto::getLotNo)).collect(Collectors.toList());
        return allotmentOrderDtoList;
    }

    @Override
    @RedissonLock(prefixKey = RedisKey.ALLOTMENT_OFFER, key = "#itemId")
    public List<AllotmentOrderDto> allotmentOrder(String itemId, String lotId, Integer outboundId, Integer outboundDetailId, String userId, String code) throws Exception {

        //1 校验此商品索取人是否一致
//        if (!checkUser(req.getCode())) {
//            throw new PrologException("此商品已被其他人员索取");
//        }
        //2 根据条码查询商品信息
//        final ItemBarCodeVO itemBarCodeVO = itemService.queryItemByBarCode(code);
        ItemSyncVO itemBaseInfoVO = itemService.queryItemMst(Arrays.asList(itemId)).stream().findFirst().orElseThrow(() -> new PrologException("未查询到商品信息"));
        //3 查询此商品对应的所有订单
        List<AllotmentOrderDto> allotmentOrderDtoTask = new ArrayList<>();
        List<AllotmentOrderDto> allotmentOrderDtoList = containerTaskDismantleService.findAllotmentOrder(itemBaseInfoVO.getItemId());
        AssertUtils.isNotTrue(CollectionUtil.isEmpty(allotmentOrderDtoList), String.format("商品id:%s没有复核任务或任务已完成", itemBaseInfoVO.getItemId()));
        //4 判断是否有指定客户订单 有指定则按指定订单进行
        if (Objects.nonNull(outboundId)) {
            AllotmentOrderDto allotmentOrderDto = allotmentOrderDtoList.stream().filter(item -> Objects.equals(item.getOutboundId(), outboundId)).findFirst().orElse(null);
            if (Objects.nonNull(allotmentOrderDto)) {
                allotmentOrderDtoList = Arrays.asList(allotmentOrderDto);
            }
        }
        //5 查看是否多批次,多批次全部返回给用户 由他选择一条进行复核，同批次根据规则分配一条进行复核
        Map<String, List<AllotmentOrderDto>> lotOrder = allotmentOrderDtoList.stream().collect(Collectors.groupingBy(AllotmentOrderDto::getLotId));
        if (lotOrder.size() > 1) {
            //多批次
            //判断是否有选择一条数据
            if (Objects.nonNull(outboundDetailId) && StrUtil.isNotBlank(lotId)) {
                AllotmentOrderDto temp = allotmentOrderDtoList.stream().filter(item -> StrUtil.equals(item.getLotId(), lotId) && Objects.equals(outboundDetailId, item.getOutboundDetailId())).findFirst().orElseThrow(() -> new PrologException("未找到选择的数据"));
                allotmentOrderDtoTask.add(temp);
            } else {
                allotmentOrderDtoTask = allotmentOrderDtoList;
            }

        } else {
            //同批次
            setCompletionRate(allotmentOrderDtoList);
            allotmentOrderDtoList = allotmentOrderDtoList.stream().sorted(Comparator.comparing(AllotmentOrderDto::getPriority).thenComparing(AllotmentOrderDto::getWaveNo).thenComparing(AllotmentOrderDto::getCompletionRate)).collect(Collectors.toList());
            allotmentOrderDtoTask.add(allotmentOrderDtoList.get(0));
        }
        List<BatchNumberSync> batchNumberSync = inventoryService.getBatchNumberSync(ListUtil.toList(lotOrder.keySet()));
        //6 组装数据
        allotmentOrderDtoTask.forEach(item -> {
            List<GridInfo> gridInfoList = gridInfoService.findByMap(MapUtils.put(GridInfo::getOrderId, item.getOutboundId()).getMap());
            if (CollectionUtils.isNotEmpty(gridInfoList)) {
                item.setGridNo(gridInfoList.get(0).getGridNo());
            }
            BatchNumberSync batchNumber = batchNumberSync.stream().filter(inner -> StrUtil.equals(inner.getBatchId(), item.getLotId())).findFirst().orElseThrow(() -> new PrologException("未查询到批次信息"));
            item.setItemCode(itemBaseInfoVO.getItemCode());
            item.setItemName(itemBaseInfoVO.getItemName());
            item.setPieceUom(itemBaseInfoVO.getPieceUom());
            item.setItemHealthSuperviseflag(itemBaseInfoVO.getItemHealthSuperviseflag());
            item.setCargoOwnerName(itemBaseInfoVO.getCargoOwnerName());
            item.setCountryOrigin(itemBaseInfoVO.getCargoOwnerName());
            item.setExpireDate(batchNumber.getBatchExpiredDateShow());
            item.setProduceDate(batchNumber.getBatchProductionDateShow());
            item.setLotNo(batchNumber.getManufacturerLotNum());
            item.setItemHealthApprovalNbr(itemBaseInfoVO.getItemHealthApprovalNbr());
            item.setItemHealthListedLicensor(itemBaseInfoVO.getItemHealthListedLicensor());
            item.setSpecification(itemBaseInfoVO.getSpecification());
            item.setManufacturerName(item.getManufacturerName());
            item.setCode(code);
        });
        String autoOffer = String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.AUTO_OFFER));

        // TODO: 2023/9/28 最大计划数量根据商品来配置
        //7 查询计划复核数量
        BigDecimal planOfferQty = itemBaseInfoVO.getIdentifyNum();
        if (Objects.isNull(planOfferQty) || planOfferQty.compareTo(BigDecimal.ZERO) == 0) {
            planOfferQty = new BigDecimal(String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.PLAN_OFFER_QTY)));
        }
        //只有一个批次就分配一条进行复核，判断复核数量是否大于计划复核数量，大于就按照计划复核数量进行
        if (allotmentOrderDtoTask.size() == 1) {
            for (AllotmentOrderDto allotmentOrderDto : allotmentOrderDtoTask) {
                allotmentOrderDto.setAutoOffer(Integer.valueOf(autoOffer));
                if (allotmentOrderDto.getPlanQty().compareTo(planOfferQty) > 0) {
                    allotmentOrderDto.setPlanQty(planOfferQty);
                    allotmentOrderDto.setPlanOfferQty(planOfferQty);
                } else {
                    allotmentOrderDto.setPlanOfferQty(allotmentOrderDto.getPlanQty());
                }

//                BizOutboundTaskDetailDismantle bizOutboundTaskDetailDismantle = bizOutboundTaskDetailDismantleService.findByMap(MapUtils.put(BizOutboundTaskDetailDismantle::getOutboundDetailId, allotmentOrderDto.getOutboundDetailId()).put(BizOutboundTaskDetailDismantle::getType, 2).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("未找到对应拆零任务"));
//                bizOutboundTaskDetailDismantle.setOfferShowQty(bizOutboundTaskDetailDismantle.getOfferShowQty().add(allotmentOrderDto.getPlanQty()));
//                bizOutboundTaskDetailDismantleService.update(bizOutboundTaskDetailDismantle);
            }
        } else {
            allotmentOrderDtoTask = allotmentOrderDtoTask.stream().sorted(Comparator.comparing(AllotmentOrderDto::getLotNo)).collect(Collectors.toList());
        }
        return allotmentOrderDtoTask;
    }

    //计算订单复核完成率
    private void setCompletionRate(List<AllotmentOrderDto> allotmentOrderDtoList) {
        List<Integer> outboundIds = allotmentOrderDtoList.stream().map(AllotmentOrderDto::getOutboundId).distinct().collect(Collectors.toList());
        Criteria criteria = new Criteria(BizOutboundTaskDetailDismantle.class);
        criteria.restrictionBuilder().in(BizOutboundTaskDetailDismantle::getOutboundId, outboundIds).eq(BizOutboundTaskDetailDismantle::getType, 2).build();
        List<BizOutboundTaskDetailDismantle> outboundTaskDetailDismantleList = bizOutboundTaskDetailDismantleService.findByCriteria(criteria);
        Map<Integer, Integer> countMap = new HashMap<>();
        for (BizOutboundTaskDetailDismantle bizOutboundTaskDetailDismantle : outboundTaskDetailDismantleList) {
            if (bizOutboundTaskDetailDismantle.getStatus() < 15) {
                countMap.put(bizOutboundTaskDetailDismantle.getOutboundId(), countMap.getOrDefault(bizOutboundTaskDetailDismantle.getOutboundId(), 0) + 1);
            }
        }
        for (AllotmentOrderDto allotmentOrderDto : allotmentOrderDtoList) {
            allotmentOrderDto.setCompletionRate(countMap.getOrDefault(allotmentOrderDto.getOutboundId(), 0));
        }
    }

    @Override
    public String allotmentConfirmCheck(AllotmentConfirm req) {
        if (req.getItemHealthSuperviseflag() == 0) {
            return null;
        }
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(req.getDrugSupervisionCode()), "监管码不能为空");
        AssertUtils.isNotTrue(new BigDecimal(req.getDrugSupervisionCode().size()).compareTo(req.getPlanQty()) != 0, "监管码数量必须和复核数量一致");
        int size = req.getDrugSupervisionCode().size();
        long count = req.getDrugSupervisionCode().stream().distinct().count();
        AssertUtils.isNotTrue(size != count, "监管码不能重复");
        List<SupervisionCodeDto> supervisionCodeList = bizOutboundTaskDetailService.findSupervisionCode(req.getDrugSupervisionCode());
        if (CollectionUtils.isEmpty(supervisionCodeList)) {
            return "药监码" + StrUtil.join(",", req.getDrugSupervisionCode()) + "无品批信息";
        }
        if (supervisionCodeList.size() < size) {
            List<String> collect = supervisionCodeList.stream().map(SupervisionCodeDto::getCode).collect(Collectors.toList());
            List<String> drugSupervisionCode = req.getDrugSupervisionCode();
            List<String> collect1 = drugSupervisionCode.stream().filter(item -> !collect.contains(item)).collect(Collectors.toList());
            return "药监码" + StrUtil.join(",", collect1) + "无品批信息";
        }
        BizOutboundTaskDetail outboundTaskDetail = bizOutboundTaskDetailService.findById(req.getOutboundDetailId());
        List<String> collect = supervisionCodeList.stream().filter(item -> !StrUtil.equals(item.getItemId(), outboundTaskDetail.getItemId()) || !StrUtil.equals(item.getLotId(), outboundTaskDetail.getLotId())).map(SupervisionCodeDto::getCode).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(collect)) {
            return "药监码" + StrUtil.join(",", collect) + "与实际品批信息不一致";
        }
        return null;
    }

    @Override
    @Transactional
    @RedissonLock(prefixKey = RedisKey.ALLOTMENT_OFFER, key = "#req.outboundId")
    public void allotmentConfirm(AllotmentConfirm req) throws Exception {
        //1 校验
        AllotmentOrderDto allotmentOrderDto = containerTaskDismantleService.findAllotmentOrderDetail(req);
        AssertUtils.isNotNull(allotmentOrderDto, "未查询到对应任务");
        AssertUtils.isNotTrue(req.getPlanQty().compareTo(BigDecimal.ZERO) <= 0, "复核数量必须大于0");
        AssertUtils.isNotTrue(req.getPlanQty().compareTo(allotmentOrderDto.getPlanQty()) > 0, "复核数量已超过任务数量");
        AssertUtils.isNotTrue(req.getPlanQty().compareTo(req.getPlanOfferQty()) > 0, "复核数量不能大于计划复核数量");
        List<AllotmentCfg> allotmentCfgs = allotmentCfgService.findByMap(MapUtils.put(AllotmentCfg::getStationNo, req.getStationNo()).getMap());
        if (CollectionUtils.isEmpty(allotmentCfgs)) {
            throw new PrologException(String.format("无效的供包口%s", req.getStationNo()));
        }
        List<String> drugSupervisionCode = req.getDrugSupervisionCode();
        //2 更新已复核数量
        BizOutboundTaskDetailDismantle bizOutboundTaskDetailDismantle = bizOutboundTaskDetailDismantleService.findByMap(MapUtils.put(BizOutboundTaskDetailDismantle::getOutboundDetailId, req.getOutboundDetailId()).put(BizOutboundTaskDetailDismantle::getType, 2).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("未找到对应拆零任务"));
        bizOutboundTaskDetailDismantle.setOfferQty(bizOutboundTaskDetailDismantle.getOfferQty().add(req.getPlanQty()));
//        bizOutboundTaskDetailDismantle.setOfferShowQty(bizOutboundTaskDetailDismantle.getOfferShowQty().subtract(req.getPlanQty()));
        if (req.getItemHealthSuperviseflag() == 1) {
            AssertUtils.isNotTrue(CollectionUtils.isEmpty(req.getDrugSupervisionCode()), "监管码不能为空");
            AssertUtils.isNotTrue(new BigDecimal(req.getDrugSupervisionCode().size()).compareTo(req.getPlanQty()) != 0, "监管码数量必须和复核数量一致");
            List<String> list = Convert.toList(String.class, bizOutboundTaskDetailDismantle.getDrugSupervisionCode());
            req.getDrugSupervisionCode().addAll(list);
            int size = req.getDrugSupervisionCode().size();
            long count = req.getDrugSupervisionCode().stream().distinct().count();
            AssertUtils.isNotTrue(size != count, "监管码不能重复");
            List<BizOutboundTaskDetailDismantle> bizOutboundTaskDetailDismantleList = bizOutboundTaskDetailDismantleService.findByMap(MapUtils.put(BizOutboundTaskDetailDismantle::getOutboundId, bizOutboundTaskDetailDismantle.getOutboundId()).getMap()).stream().filter(item -> !Objects.equals(item.getId(), bizOutboundTaskDetailDismantle.getId())).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(bizOutboundTaskDetailDismantleList)) {
                List<String> codeList = new ArrayList<>();
                for (BizOutboundTaskDetailDismantle outboundTaskDetailDismantle : bizOutboundTaskDetailDismantleList) {
                    if (StrUtil.isNotBlank(outboundTaskDetailDismantle.getDrugSupervisionCode())) {
                        codeList.addAll(Convert.toList(String.class, outboundTaskDetailDismantle.getDrugSupervisionCode()));
                    }
                }
                codeList.addAll(req.getDrugSupervisionCode());
                size = codeList.size();
                count = codeList.stream().distinct().count();
                AssertUtils.isNotTrue(size != count, "监管码不能重复");
            }
            bizOutboundTaskDetailDismantle.setDrugSupervisionCode(StrUtil.join(",", req.getDrugSupervisionCode()));
        }

        //3 记录供包任务
        BizOutboundTaskDetail outboundTaskDetail = bizOutboundTaskDetailService.findById(req.getOutboundDetailId());
        BizOutboundTask bizOutboundTask = bizOutboundTaskService.findById(outboundTaskDetail.getOutboundId());
        GridInfo gridInfo = gridSplit(bizOutboundTask, outboundTaskDetail, bizOutboundTaskDetailDismantle, req, drugSupervisionCode);

        //4 判断是否全部复核完成 全部完成修改状态
        if (req.getPlanQty().compareTo(allotmentOrderDto.getPlanQty()) == 0) {
            bizOutboundTaskDetailDismantle.setStatus(15);
            outboundTaskDetail.setStatus(BaseStatusEnum.STATUS_OFFER.getCode());
            outboundTaskDetail.setUpdateTime(LocalDateTime.now());
            bizOutboundTaskDetailService.update(outboundTaskDetail);

            WmsOfferBackDetailDto wmsOfferBackDetailDto = WmsOfferBackDetailDto.builder().taskLineId(outboundTaskDetail.getSeqNo()).itemId(outboundTaskDetail.getItemId()).lotId(outboundTaskDetail.getLotId()).ownerId(outboundTaskDetail.getOwnerId()).packId(outboundTaskDetail.getPackId()).qty(bizOutboundTaskDetailDismantle.getOfferQty()).drugSupervisionCode(Convert.toList(String.class, bizOutboundTaskDetailDismantle.getDrugSupervisionCode())).build();
            bizOutboundTaskDetailDismantle.setExtend2(JSONUtil.toJsonStr(wmsOfferBackDetailDto));


            //判断是否复核完成
            List<BizOutboundTaskDetailDismantle> outboundTaskDetailDismantleList = bizOutboundTaskDetailDismantleService.findByMap(MapUtils.put(BizOutboundTaskDetailDismantle::getOutboundId, bizOutboundTask.getId()).put(BizOutboundTaskDetailDismantle::getType, 2).getMap());
            List<BizOutboundTaskDetail> bizOutboundTaskDetailList = bizOutboundTaskDetailService.findByMap(MapUtils.put(BizOutboundTaskDetail::getOutboundId, bizOutboundTask.getId()).put(BizOutboundTaskDetail::getStatus, BaseStatusEnum.STATUS_OFFER.getCode()).getMap());
            if (outboundTaskDetailDismantleList.size() == bizOutboundTaskDetailList.size()) {
                gridInfo.setSupplyFlag(1);
                gridInfo.setUpdateTime(new Date());
                gridInfoService.update(gridInfo);
                bizOutboundTask.setStatus(BaseStatusEnum.STATUS_OFFER.getCode());
                bizOutboundTask.setUpdateTime(LocalDateTime.now());
                bizOutboundTaskService.update(bizOutboundTask);
            }

        }
        bizOutboundTaskDetailDismantleService.update(bizOutboundTaskDetailDismantle);

        List<BizOutboundTaskDismantleSupply> supplyList = outboundTaskDismantleSupplyMapper.findByMap(MapUtils.put(BizOutboundTaskDismantleSupply::getOutboundId, bizOutboundTask.getId()).getMap(), BizOutboundTaskDismantleSupply.class);
        List<BizOutboundTaskDetailDismantle> outboundTaskDetailDismantleList = bizOutboundTaskDetailDismantleService.findByMap(MapUtils.put(BizOutboundTaskDetailDismantle::getOutboundId, bizOutboundTask.getId()).getMap());
        long count = outboundTaskDetailDismantleList.stream().filter(item -> StrUtil.isBlank(item.getExtend2())).count();
        if (count == 0 && CollectionUtils.isEmpty(supplyList)) {
            List<WmsOfferBackDetailDto> wmsOfferBackDetailDtos = new ArrayList<>();
            for (BizOutboundTaskDetailDismantle bizOutboundTaskDetail : outboundTaskDetailDismantleList) {
                WmsOfferBackDetailDto bean = JSONUtil.toBean(bizOutboundTaskDetail.getExtend2(), WmsOfferBackDetailDto.class);
                wmsOfferBackDetailDtos.add(bean);
            }
            //组装回告数据
            WmsOfferBackDto wmsOfferBackDto = WmsOfferBackDto.builder().taskId(bizOutboundTask.getUpperSystemTaskId()).billNo(bizOutboundTask.getBillNo()).enterpriseId(bizOutboundTask.getEnterpriseId()).warehouseId(bizOutboundTask.getWmsWarehouseId()).employeeId(getUserId()).subList(wmsOfferBackDetailDtos).build();
            //保存打印信息
            PrintTask printTask = new PrintTask();
            printTask.setPrintCount(0);
            printTask.setGridNo(null);
            printTask.setCreateTime(new Date());
            printTask.setUpdateTime(new Date());
            printTask.setStatus(0);
            printTask.setWmsOutTaskId(bizOutboundTask.getId());
            printTask.setType(3);
            printTask.setPrintData(JSONUtil.toJsonStr(wmsOfferBackDto));
            printTaskService.save(printTask);

        }
    }

    private GridInfo gridSplit(BizOutboundTask outboundTask, BizOutboundTaskDetail outboundTaskDetail, BizOutboundTaskDetailDismantle outboundTaskDetailDismantle, AllotmentConfirm allotmentConfirm, List<String> drugSupervisionCode) throws Exception {
        //或者配置的单个格口最大体积
        BigDecimal gridMaxVolume = new BigDecimal(String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.GRID_MAX_VOLUME)));
        //1. 查询此订单所有已绑定格口
        List<GridInfo> gridInfoList = gridInfoService.findByMap(MapUtils.put(GridInfo::getOrderId, outboundTask.getId()).getMap());
        Assert.notEmpty(gridInfoList, String.format("此订单%s还未分配格口", outboundTask.getBillNo()));
        //2. 获取最后绑定的格口
        GridInfo gridInfo = gridInfoList.stream().filter(item -> item.getLastFlag() == 1).findFirst().get();
        //3. 计算最小使用体积格口剩余容量
        BigDecimal remainVolume = gridMaxVolume.subtract(gridInfo.getApplyVolume());
        //4. 获取供包商品最小包装体积
        ItemSyncVO itemInfo = itemService.queryItemMst(Arrays.asList(outboundTaskDetail.getItemId())).stream().findFirst().orElseThrow(() -> new PrologException(String.format("商品id%s未查询到商品信息", outboundTaskDetail.getItemId())));
        BigDecimal itemVolume = itemInfo.getUomList().get(0).getVolume().divide(itemInfo.getUomList().get(0).getConversionRate(), 2, BigDecimal.ROUND_DOWN);
        //此次供包的总体积
        BigDecimal itemVolumeSum = itemVolume.multiply(allotmentConfirm.getPlanQty()).setScale(2, BigDecimal.ROUND_DOWN);
        //5. 判断当前格口是否能装下此此复核的所有商品
        if (itemVolumeSum.compareTo(remainVolume) <= 0) {
            saveAllotmentTaskRecord(outboundTaskDetailDismantle, allotmentConfirm, gridInfo.getGridNo(), allotmentConfirm.getPlanQty(), drugSupervisionCode);
            gridInfo.setApplyVolume(gridInfo.getApplyVolume().add(itemVolumeSum));
            gridInfo.setUpdateTime(new Date());
            gridInfoService.update(gridInfo);
            return gridInfo;
        }
        //6. 装不下此次供包所有商品 此格口使用体积设满，重新分配新格口
        gridInfo.setApplyVolume(gridMaxVolume);
        gridInfo.setUpdateTime(new Date());
        gridInfo.setSupplyFlag(1);
        gridInfo.setLastFlag(0);
        gridInfoService.update(gridInfo);
        //分配新格口
        gridInfo = addBestGrid(outboundTask.getId(), gridInfo.getGridNo());
        gridInfo.setOrderId(outboundTask.getId());
        gridInfo.setLastFlag(1);
        gridInfo.setApplyVolume(itemVolumeSum);
        gridInfo.setUpdateTime(new Date());
        gridInfoService.update(gridInfo);

        orderLogMapper.save(OrderLog.builder().orderId(outboundTask.getId().toString()).orderNo(outboundTask.getBillNo()).type("格口绑定").remark("绑定格口号：" + gridInfo.getGridNo()).createTime(new Date()).build());

        saveAllotmentTaskRecord(outboundTaskDetailDismantle, allotmentConfirm, gridInfo.getGridNo(), allotmentConfirm.getPlanQty(), drugSupervisionCode);
        return gridInfo;
    }

    private GridInfo addBestGrid(Integer orderId, String gridNo) {
        Criteria criteria = new Criteria(GridInfo.class);
        criteria.restrictionBuilder().eq(GridInfo::getIsLock, 0).isnull(GridInfo::getOrderId).build();
        List<GridInfo> gridInfoList = gridInfoService.findByCriteria(criteria);
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(gridInfoList), "没有可重新分配的格口");
        gridInfoList = sortBestGridInfoList(gridInfoList, gridNo);
        GridInfo gridInfo = null;
        for (GridInfo item : gridInfoList) {
            if (redisTemplate.opsForValue().setIfAbsent(RedisKey.GRID_BIND_KEY + item.getGridNo(), item.getGridNo())) {
                gridInfo = item;
                break;
            }
        }
        AssertUtils.isNotTrue(Objects.isNull(gridInfo), "没有可重新分配的格口");
        callWmsBind(gridInfo.getGridNo(), orderId);
        return gridInfo;
    }

    private List<GridInfo> sortBestGridInfoList(List<GridInfo> gridInfoList, String curGridNo) {
        int curGridNoNum = Integer.parseInt(curGridNo);
        //所有格口根据当前格口根据相邻距离由近至远排序
        List<GridInfo> sortGridInfoList = gridSort(gridInfoList, curGridNoNum);
        //奇数
        List<GridInfo> oddGridInfoList = new ArrayList<>();
        //偶数
        List<GridInfo> evenGridInfoList = new ArrayList<>();
        //排序的格口进行奇偶分类 顺序保持不变
        sortGridInfoList.forEach(item -> {
            int index = Integer.parseInt(item.getGridNo()) % 2;
            if (index == 0) {
                evenGridInfoList.add(item);
            } else {
                oddGridInfoList.add(item);
            }
        });
        int flag = curGridNoNum % 2;
        //当前格口是偶数则 偶数格口优先
        if (flag == 0) {
            evenGridInfoList.addAll(oddGridInfoList);
            return evenGridInfoList;
        }
        //当前格口是奇数 则奇数格口优先
        oddGridInfoList.addAll(evenGridInfoList);
        return oddGridInfoList;
    }

    private List<GridInfo> gridSort(List<GridInfo> gridInfoList, int curGridNoNum) {
        for (GridInfo gridInfo : gridInfoList) {
            String gridNo = gridInfo.getGridNo();
            int gridNoNum = Integer.parseInt(gridNo);
            gridInfo.setNumber(Math.abs(gridNoNum - curGridNoNum));
        }
        List<GridInfo> collect = gridInfoList.stream().sorted(Comparator.comparing(GridInfo::getNumber)).collect(Collectors.toList());
        return collect;
    }

    private void callWmsBind(String gridNo, Integer orderId) {
        PrintTask printTask = new PrintTask();
        printTask.setPrintCount(0);
        printTask.setGridNo(gridNo);
        printTask.setCreateTime(new Date());
        printTask.setStatus(0);
        printTask.setWmsOutTaskId(orderId);
        printTask.setType(2);
        printTaskService.save(printTask);
    }

    private void saveAllotmentTaskRecord(BizOutboundTaskDetailDismantle outboundTaskDetailDismantle, AllotmentConfirm allotmentConfirm, String gridNo, BigDecimal qty, List<String> drugSupervisionCode) {
        AllotmentTaskRecord allotmentTaskRecord = new AllotmentTaskRecord();
        allotmentTaskRecord.setTaskId(StrUtil.uuid());
        allotmentTaskRecord.setAllotmentNo(allotmentConfirm.getStationNo());
        allotmentTaskRecord.setCreateTime(new Date());
        allotmentTaskRecord.setItemId(allotmentConfirm.getItemId());
        allotmentTaskRecord.setPlanQty(allotmentConfirm.getPlanOfferQty());
        allotmentTaskRecord.setQty(qty);
        allotmentTaskRecord.setOutboundId(outboundTaskDetailDismantle.getOutboundId());
        allotmentTaskRecord.setOutboundDetailId(outboundTaskDetailDismantle.getOutboundDetailId());
        allotmentTaskRecord.setDismantleId(outboundTaskDetailDismantle.getId());
        allotmentTaskRecord.setGirdNo(gridNo);
        allotmentTaskRecord.setAllotmentType(0);
        allotmentTaskRecord.setScanDate(new Date());
        allotmentTaskRecord.setSendStatus(0);
        allotmentTaskRecord.setLogeStatus(0);
        allotmentTaskRecord.setScanStatus(1);
        allotmentTaskRecord.setCode(StrUtil.join(",", drugSupervisionCode));
        allotmentTaskRecord.setReviewerInfo(getUserId());
        allotmentTaskRecordService.save(allotmentTaskRecord);

        BizOutboundTaskDetailDismantleGrid outboundTaskDetailDismantleGrid = new BizOutboundTaskDetailDismantleGrid();
        outboundTaskDetailDismantleGrid.setOutboundId(outboundTaskDetailDismantle.getOutboundId());
        outboundTaskDetailDismantleGrid.setOutboundDetailId(outboundTaskDetailDismantle.getOutboundDetailId());
        outboundTaskDetailDismantleGrid.setOutboundDetailDismantleId(outboundTaskDetailDismantle.getId());
        outboundTaskDetailDismantleGrid.setItemId(allotmentConfirm.getItemId());
        outboundTaskDetailDismantleGrid.setLotId(outboundTaskDetailDismantle.getLotId());
        outboundTaskDetailDismantleGrid.setPackId(outboundTaskDetailDismantle.getPackId());
        outboundTaskDetailDismantleGrid.setOwnerId(outboundTaskDetailDismantle.getOwnerId());
        outboundTaskDetailDismantleGrid.setQty(qty);
        outboundTaskDetailDismantleGrid.setHandOfferQty(BigDecimal.ZERO);
        outboundTaskDetailDismantleGrid.setGridNo(gridNo);
        outboundTaskDetailDismantleGrid.setCreateTime(new Date());
        outboundTaskDetailDismantleGridMapper.save(outboundTaskDetailDismantleGrid);
    }

    public String getUserId() {
        final UserDTO userDTO = userTemplate.getUserDTO();
        if (null != userDTO) {
            return userDTO.getUserBizModel().getEmployeeNo();
        }
        throw new PrologException("获取用户信息为空");
    }

    @Override
    public List<MergeContainerRespDto> mergeContainerList(MergeContainerReqDto req) {
        setItemIds(req);
        double fullVolumeSize = Double.parseDouble(String.valueOf(redisTemplate.opsForValue().get(SysParamConstants.SYSPRE_FIX + SysParamConstants.FULL_VOLUME_SIZE)));

        req.setFullVolumeSize(fullVolumeSize);
        return containerTaskService.mergeContainerList(req);
    }

    @Override
    public List<MergeContainerDetailRespDto> mergeContainerDetail(String id) throws Exception {
        ContainerInfoDetail containerInfoDetail = containerInfoDetailService.findById(Integer.valueOf(id));
        ItemSyncVO itemInfo = itemService.queryItemMst(Arrays.asList(containerInfoDetail.getItemId())).stream().findFirst().orElseThrow(() -> new PrologException("未查询到商品信息"));
        BatchNumberSync batchNumber = inventoryService.getBatchNumberSync(Arrays.asList(String.valueOf(containerInfoDetail.getLotId()))).stream().findFirst().orElseThrow(() -> new PrologException("未查询到批次信息"));
        BigDecimal[] bigDecimals = containerInfoDetail.getQty().divideAndRemainder(itemInfo.getUomList().get(0).getConversionRate());
        return Arrays.asList(MergeContainerDetailRespDto.builder().id(containerInfoDetail.getId()).barCode(itemInfo.getPieceBarcode()).itemCode(itemInfo.getItemCode()).itemName(itemInfo.getItemName()).itemQty(bigDecimals[0]).lotNo(batchNumber.getManufacturerLotNum()).packQty(itemInfo.getUomList().get(0).getConversionRate()).qty(containerInfoDetail.getQty()).scatteredQty(bigDecimals[1]).build());
    }

    private void setItemIds(MergeContainerReqDto req) {
        if (StrUtil.isNotBlank(req.getItemName()) && StrUtil.isNotBlank(req.getBarcode())) {
            List<ItemBaseInfoVO> itemInfoList = itemService.getItemByName(req.getItemName());
            List<ItemSyncVO> itemByBarcode = itemService.getItemByBarcode(req.getBarcode());
            if (CollectionUtils.isEmpty(itemInfoList) && CollectionUtils.isEmpty(itemByBarcode)) {
                req.setItemIds("-1");
            } else if (CollectionUtils.isNotEmpty(itemInfoList) && CollectionUtils.isNotEmpty(itemByBarcode)) {
                List<String> itemIds1 = itemInfoList.stream().map(ItemBaseInfoVO::getItemId).collect(Collectors.toList());
                List<String> itemIds2 = itemByBarcode.stream().map(ItemSyncVO::getItemId).collect(Collectors.toList());
                itemIds1.retainAll(itemIds2);
                req.setItemIds(StrUtil.join(",", itemIds1));
            } else if (CollectionUtils.isNotEmpty(itemInfoList)) {
                List<String> itemIds1 = itemInfoList.stream().map(ItemBaseInfoVO::getItemId).collect(Collectors.toList());
                req.setItemIds(StrUtil.join(",", itemIds1));
            } else if (CollectionUtils.isNotEmpty(itemByBarcode)) {
                List<String> itemIds2 = itemByBarcode.stream().map(ItemSyncVO::getItemId).collect(Collectors.toList());
                req.setItemIds(StrUtil.join(",", itemIds2));
            }
        } else if (StrUtil.isNotBlank(req.getItemName())) {
            List<ItemBaseInfoVO> itemInfoList = itemService.getItemByName(req.getItemName());
            if (CollectionUtils.isEmpty(itemInfoList)) {
                req.setItemIds("-1");
            } else {
                List<String> itemIds = itemInfoList.stream().map(ItemBaseInfoVO::getItemId).collect(Collectors.toList());
                req.setItemIds(StrUtil.join(",", itemIds));
            }
        } else if (StrUtil.isNotBlank(req.getBarcode())) {
            List<ItemSyncVO> itemByBarcode = itemService.getItemByBarcode(req.getBarcode());
            if (CollectionUtils.isEmpty(itemByBarcode)) {
                req.setItemIds("-1");
            } else {
                List<String> itemIds = itemByBarcode.stream().map(ItemSyncVO::getItemId).collect(Collectors.toList());
                req.setItemIds(StrUtil.join(",", itemIds));
            }
        }
    }

    @Override
    public synchronized void mergeContainerReq(String ids) {
        String[] idArr = StrUtil.split(ids, ",");
        String id1 = idArr[0];
        String id2 = idArr[1];
        final ContainerInfoDetail containerInfoDetail1 = containerInfoDetailService.findById(Integer.valueOf(id1));
        final ContainerInfoDetail containerInfoDetail2 = containerInfoDetailService.findById(Integer.valueOf(id2));
        ContainerInfo containerInfo1 = containerInfoService.findOneByMap(MapUtils.put(ContainerInfo::getContainerNo, containerInfoDetail1.getContainerNo()).getMap());
        ContainerInfo containerInfo2 = containerInfoService.findOneByMap(MapUtils.put(ContainerInfo::getContainerNo, containerInfoDetail2.getContainerNo()).getMap());
        AssertUtils.isNotTrue(containerInfo1.getTaskType() != 0 || containerInfo2.getTaskType() != 0, "只有空闲状态的容器才支持合托");
        String property1 = containerInfoDetail1.getItemId() + "&" + containerInfoDetail1.getLotId();
        String property2 = containerInfoDetail2.getItemId() + "&" + containerInfoDetail2.getLotId();
        AssertUtils.isTrue(StrUtil.equals(property1, property2), "只支持同品同批进行合托");

        Criteria criteria = new Criteria(MergeContainerTask.class);
        criteria.restrictionBuilder().in(MergeContainerTask::getContainerNo, Arrays.asList(containerInfoDetail1.getContainerSubNo(), containerInfoDetail2.getContainerSubNo())).build();
        List<MergeContainerTask> mergeContainerTasks = mergeContainerTaskService.findByCriteria(criteria);
        AssertUtils.isTrue(CollectionUtil.isEmpty(mergeContainerTasks), "当前容器已存在合托任务");

        Criteria taskCri = new Criteria(ContainerTask.class);
        taskCri.restrictionBuilder().in(ContainerTask::getContainerNo, Arrays.asList(containerInfo1.getContainerNo(), containerInfo2.getContainerNo())).lt(ContainerTask::getStatus, 3).build();
        final List<ContainerTask> containerTasks = containerTaskService.findByCriteria(taskCri);
        AssertUtils.isNotTrue(CollectionUtil.isNotEmpty(containerTasks), "当前容器正在任务中");

        saveMergeContainerTask(containerInfo1, containerInfo2, containerInfoDetail1, containerInfoDetail2);
    }

    /**
     * 票据提交
     * 1.检测当前订单是否需要票据
     * 2.保存wcs任务表
     *
     * @param req
     */
    @Override
    public void noteConfirm(NoteConfirm req) {
        List<AllotmentCfg> allotmentCfgs = allotmentCfgService.findByMap(MapUtils.put(AllotmentCfg::getStationNo, req.getStationNo()).getMap());
        if (CollectionUtils.isEmpty(allotmentCfgs)) {
            throw new PrologException(String.format("无效的供包口%s", req.getStationNo()));
        }
        BizOutboundTask bizOutboundTask = bizOutboundTaskService.findOneByMap(MapUtils.put(BizOutboundTask::getBillNo, req.getBillNo()).put(BizOutboundTask::getWmsLocationCode, WmsConstants.AGVL).getMap());
        //3 记录供包任务
        List<GridInfo> gridInfoList = gridInfoService.findByMap(MapUtils.put(GridInfo::getOrderId, bizOutboundTask.getId()).getMap());
        Assert.notEmpty(gridInfoList, String.format("此订单%s还未分配格口", bizOutboundTask.getBillNo()));
        AllotmentTaskRecord allotmentTaskRecord = new AllotmentTaskRecord();
        allotmentTaskRecord.setTaskId(StrUtil.uuid());
        allotmentTaskRecord.setAllotmentNo(req.getStationNo());
        allotmentTaskRecord.setCreateTime(new Date());
        allotmentTaskRecord.setPlanQty(new BigDecimal(0));
        allotmentTaskRecord.setQty(new BigDecimal(0));
        allotmentTaskRecord.setOutboundId(bizOutboundTask.getId());
        allotmentTaskRecord.setGirdNo(gridInfoList.stream().filter(item -> Objects.equals(item.getBillFlag(), 1)).findFirst().get().getGridNo());
        allotmentTaskRecord.setAllotmentType(req.getNoteType());
        allotmentTaskRecord.setScanDate(new Date());
        allotmentTaskRecord.setSendStatus(0);
        allotmentTaskRecord.setLogeStatus(0);
        allotmentTaskRecord.setScanStatus(1);
        allotmentTaskRecordService.save(allotmentTaskRecord);
    }

    @Transactional
    public void saveMergeContainerTask(ContainerInfo containerInfo1, ContainerInfo containerInfo2, ContainerInfoDetail containerInfoDetail1, ContainerInfoDetail containerInfoDetail2) {
        final String uuid = StrUtil.uuid();
        MergeContainerTask mergeContainerTask = new MergeContainerTask();
        mergeContainerTask.setBillNo(uuid);
        mergeContainerTask.setContainerNo(containerInfoDetail1.getContainerSubNo());
        mergeContainerTask.setItemId(containerInfoDetail1.getItemId());
        mergeContainerTask.setLotId(containerInfoDetail1.getLotId());
        mergeContainerTask.setStatus(BaseStatusEnum.STATUS_INIT.getCode());
        mergeContainerTask.setCreateTime(LocalDateTime.now());
        mergeContainerTaskService.save(mergeContainerTask);
        MergeContainerTask mergeContainerTask2 = new MergeContainerTask();
        mergeContainerTask2.setBillNo(uuid);
        mergeContainerTask2.setContainerNo(containerInfoDetail2.getContainerSubNo());
        mergeContainerTask2.setItemId(containerInfoDetail2.getItemId());
        mergeContainerTask2.setLotId(containerInfoDetail2.getLotId());
        mergeContainerTask2.setStatus(BaseStatusEnum.STATUS_INIT.getCode());
        mergeContainerTask2.setCreateTime(LocalDateTime.now());
        mergeContainerTaskService.save(mergeContainerTask2);

        //添加临时容器出库任务，防止出库预占此容器的库存
        List<ContainerTask> containerTaskList = new ArrayList<>();
        ContainerTask containerTask1 = new ContainerTask();
        containerTask1.setContainerNo(containerInfo1.getContainerNo());
        containerTask1.setContainerSubNo(containerInfo1.getContainerNo());
        containerTask1.setContainerType(1);
        containerTask1.setOutboundId(-1);
        containerTask1.setWaveNo("-1");
        containerTask1.setCompanyId("-1");
        containerTask1.setOutboundDetailId(-1);
        containerTask1.setItemId(containerInfoDetail1.getItemId());
        containerTask1.setLotId(containerInfoDetail1.getLotId());
        containerTask1.setOwnerId(containerInfoDetail1.getOwnerId());
        containerTask1.setPackId(containerInfoDetail1.getPackId());
        containerTask1.setPickOrderId(-1);
        containerTask1.setTaskType(77);
        containerTask1.setWarehouseArea(containerInfo1.getWarehouseArea());
        containerTask1.setWmsLocationCode(containerInfo1.getWarehouseArea());
        containerTask1.setStatus(1);
        containerTask1.setQty(containerInfoDetail1.getQty());
        containerTask1.setCreateTime(LocalDateTime.now());
        containerTask1.setPriorty(1);
        containerTaskList.add(containerTask1);
        ContainerTask containerTask2 = new ContainerTask();
        containerTask2.setContainerNo(containerInfo2.getContainerNo());
        containerTask2.setContainerSubNo(containerInfo2.getContainerNo());
        containerTask2.setContainerType(1);
        containerTask2.setOutboundId(-1);
        containerTask2.setWaveNo("-1");
        containerTask2.setCompanyId("-1");
        containerTask2.setOutboundDetailId(-1);
        containerTask2.setItemId(containerInfoDetail2.getItemId());
        containerTask2.setLotId(containerInfoDetail2.getLotId());
        containerTask2.setOwnerId(containerInfoDetail2.getOwnerId());
        containerTask2.setPackId(containerInfoDetail2.getPackId());
        containerTask2.setPickOrderId(-1);
        containerTask2.setTaskType(77);
        containerTask2.setWarehouseArea(containerInfo2.getWarehouseArea());
        containerTask2.setWmsLocationCode(containerInfo2.getWarehouseArea());
        containerTask2.setStatus(1);
        containerTask2.setQty(containerInfoDetail2.getQty());
        containerTask2.setCreateTime(LocalDateTime.now());
        containerTask2.setPriorty(1);
        containerTaskList.add(containerTask2);
        containerTaskService.saveBatch(containerTaskList);
    }

    @Override
    public List<StationCfg> pdStationList() {
        Criteria criteria = new Criteria(StationCfg.class);
        criteria.restrictionBuilder().in(StationCfg::getStationType, Arrays.asList(StationTypeEnum.CL_TYPE.getCode(), StationTypeEnum.CLSJ_TYPE.getCode())).eq(StationCfg::getTaskType, 20).eq(StationCfg::getIsLock, 0).build();
        return stationCfgService.findByCriteria(criteria);
    }

    @Override
    public void pdStationCheck(String stationNo) throws Exception {
        StationCfg stationCfg = stationCfgService.findByMap(MapUtils.put(StationCfg::getStationNo, stationNo).getMap()).stream().findFirst().orElseThrow(() -> new PrologException("没有配置此站台"));
        AssertUtils.isNotTrue(stationCfg.getIsLock() == 1, "站台已锁定");
//        AssertUtils.isTrue(routeFeignService.checkAreaIn(stationCfg.getAreaNo()), "此站台没有空闲货位");
    }

    @Override
    @RedissonLock(prefixKey = RedisKey.PD_TASK_GET, key = "#taskType")
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public PdTaskGetRespDto getPdTask(String stationNo, Integer taskType) throws Exception {
        StationCfg stationCfg = stationCfgService.findOneByMap(MapUtils.put(StationCfg::getStationNo, stationNo).getMap());
        //获取任务前先判断此站台是否有已经获取但未完成的任务
        Criteria containerTaskCriExist = new Criteria(ContainerTask.class);
        containerTaskCriExist.restrictionBuilder().eq(ContainerTask::getWmsLocationCode, WmsCarryTaskInCode.AGVL.getCode()).lt(ContainerTask::getStatus, 5).eq(ContainerTask::getTaskType, taskType).eq(ContainerTask::getStationId, stationCfg.getId()).build();
        List<ContainerTask> existContainerTaskList = containerTaskService.findByCriteria(containerTaskCriExist);
        PdTaskGetRespDto pdTaskGetRespDto = new PdTaskGetRespDto();
        if (CollectionUtils.isNotEmpty(existContainerTaskList)) {
            return existTask(pdTaskGetRespDto, existContainerTaskList);
        }
        AssertUtils.isTrue(routeFeignService.checkAreaIn(stationCfg.getAreaNo()), "此站台没有空闲货位");
        //1 查询所有创建状态并且未被站台索取的盘点或养护任务
        Criteria containerTaskCri = new Criteria(ContainerTask.class);
        containerTaskCri.restrictionBuilder().eq(ContainerTask::getWmsLocationCode, WmsCarryTaskInCode.AGVL.getCode()).eq(ContainerTask::getStatus, BaseStatusEnum.STATUS_INIT.getCode()).eq(ContainerTask::getTaskType, taskType).isnull(ContainerTask::getStationId).build();
        List<ContainerTask> containerTaskList = containerTaskService.findByCriteria(containerTaskCri);
        AssertUtils.isNotTrue(CollectionUtils.isEmpty(containerTaskList), "暂无任务");
        //2 任务根据容器号分组
        Map<String, List<ContainerTask>> containerTaskMap = containerTaskList.stream().collect(Collectors.groupingBy(ContainerTask::getContainerNo));
        //校验容器是否存在其他作业任务
        List<String> containerNoList = containerTaskList.stream().map(ContainerTask::getContainerNo).distinct().collect(Collectors.toList());
        Criteria containerInfoCriteria = new Criteria(ContainerInfo.class);
        containerInfoCriteria.restrictionBuilder().in(ContainerInfo::getContainerNo, containerNoList).build();
        List<ContainerInfo> containerInfoList = containerInfoService.findByCriteria(containerInfoCriteria);
        containerInfoList = containerInfoList.stream().filter(item -> item.getTaskType() != 0).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(containerInfoList)) {
            String containerNoStr = StrUtil.join(",", containerInfoList.stream().map(ContainerInfo::getContainerNo).collect(Collectors.toList()));
            throw new PrologException(String.format("容器%s有其他任务作业中，无法获取盘点任务", containerNoStr));
        }
        //3 根据站台货位数找出对应数量的容器
        Integer maxCachePosition = stationCfg.getMaxCachePosition();
        for (Map.Entry<String, List<ContainerTask>> entry : containerTaskMap.entrySet()) {
            if (maxCachePosition == 0) {
                break;
            }
            if (!routeFeignService.checkAreaIn(stationCfg.getAreaNo())) {
                break;
            }
            String containerNo = entry.getKey();
            List<ContainerTask> containerTasks = entry.getValue();
            //任务绑定站台
            List<Integer> updateBindContainerTaskIds = new ArrayList<>();
            updateBindContainerTaskIds.addAll(containerTasks.stream().map(ContainerTask::getId).collect(Collectors.toList()));
            //修改库存状态
            ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put(ContainerInfo::getContainerNo, containerNo).getMap());
            containerInfo.setTaskType(ContainerTaskTypeConstants.OUTBOUND);
            containerInfo.setUpdateTime(LocalDateTime.now());
            containerInfoService.update(containerInfo);
            //搬运
            if (Objects.equals(String.valueOf(containerInfo.getContainerType()), ContainerTypeConstants.CONTAINER_TYPE_LT)) {
                //托盘
                routeFeignService.createCarryTask(containerNo, null, null, null, stationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.MOVE_TYPE), 1, "盘点养护出库", null);
                //取第一个托盘进行盘点养护
                ContainerTask containerTask = containerTasks.get(0);
                if (maxCachePosition == stationCfg.getMaxCachePosition()) {
                    containerTask.setStationLoc(1);
                    setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, null, null);
                } else {
                    containerTask.setStationLoc(2);
                }
                updateBindContainerTaskIds.remove(containerTask.getId());
                containerTask.setStationId(stationCfg.getId());
                containerTaskService.update(containerTask);
            } else {
                //货架
                //当前货架里所有货格任务根据货格进行排序
                containerTasks = containerTasks.stream().sorted(Comparator.comparing(ContainerTask::getContainerSubNo)).collect(Collectors.toList());
                //取第一个货格任务
                ContainerTask containerTask = containerTasks.get(0);
                //查询货架和货格信息
                PalletInfo palletInfo = palletInfoMapper.findByMap((MapUtils.put(PalletInfo::getPalletNo, containerTask.getContainerNo()).getMap()), PalletInfo.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货架信息"));
                PalletLocation palletLocation = palletLocationMapper.findByMap(MapUtils.put(PalletLocation::getPalletLocation, containerTask.getContainerSubNo()).getMap(), PalletLocation.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货格信息"));
                //转换货架角度 转换到当前格这一面
                int palletDir = AngleConversionAB.getDirectionStr(palletLocation.getPlanes(), stationCfg.getAngle());
                //修改货架角度
                Criteria criteria = Criteria.forClass(PalletInfo.class);
                criteria.setRestriction(Restrictions.and(Restrictions.eq("palletNo", containerTask.getContainerNo()), Restrictions.eq("status", 0)));
                final String taskId = StrUtil.uuid();
                final String subArea = palletInfo.getSubArea();
                long l = palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", 1).put("subArea", stationCfg.getAreaNo()).put("containerMoveTaskId", taskId).put("angle", palletDir).put("updateTime", new Date()).getMap(), criteria);
                if (l > 0) {
                    // 调用下发搬运任务的接口（带角度）
                    CreateCarryTaskDto carryTask = this.createCarryTaskWithAngle(taskId, containerTask.getContainerNo(), subArea, null, stationCfg.getAreaNo(), null, containerTask.getTaskType(), "货架去往站台", "", palletDir, LocationConstants.PATH_TASK_TYPE_CARRY, 80, palletLocation.getPlanes());
                    routeFeignService.createTaskWithAngle(carryTask);
                } else {
                    throw new BizException(String.format("货架状态修改失败"));
                }
                //取第一个货格进行盘点养护
                if (maxCachePosition == stationCfg.getMaxCachePosition()) {
                    containerTask.setStationLoc(1);
                    setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, palletLocation.getLayer(), palletLocation.getPlanes());
                } else {
                    containerTask.setStationLoc(2);
                }
                updateBindContainerTaskIds.remove(containerTask.getId());
                containerTask.setStationId(stationCfg.getId());
                containerTaskService.update(containerTask);
            }
            if (CollectionUtils.isNotEmpty(updateBindContainerTaskIds)) {
                Criteria containerTaskUpdateCri = new Criteria(ContainerTask.class);
                containerTaskUpdateCri.restrictionBuilder().in(ContainerTask::getId, updateBindContainerTaskIds).build();
                containerTaskService.updateMapByCriteria(MapUtils.put(ContainerTask::getStationId, stationCfg.getId()).getMap(), containerTaskUpdateCri);
            }
            maxCachePosition--;
        }
        return pdTaskGetRespDto;
    }

    private PdTaskGetRespDto existTask(PdTaskGetRespDto pdTaskGetRespDto, List<ContainerTask> containerTasks) throws Exception {
        containerTasks = containerTasks.stream().sorted(Comparator.comparing(ContainerTask::getContainerSubNo)).collect(Collectors.toList());
        ContainerTask containerTask = containerTasks.get(0);
        if (containerTask.getContainerNo().equals(containerTask.getContainerSubNo())) {
            //托盘
            setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, null, null);
        } else {
            //货架
            //查询货架和货格信息
            PalletLocation palletLocation = palletLocationMapper.findByMap(MapUtils.put(PalletLocation::getPalletLocation, containerTask.getContainerSubNo()).getMap(), PalletLocation.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货格信息"));
            setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, palletLocation.getLayer(), palletLocation.getPlanes());
        }
        return pdTaskGetRespDto;
    }

    private void setPdTaskGetRespDto(PdTaskGetRespDto pdTaskGetRespDto, ContainerTask containerTask, Integer layer, String plans) throws Exception {
        ItemSyncVO itemBaseInfoVO = itemService.queryItemMst(Arrays.asList(containerTask.getItemId())).stream().findFirst().orElseThrow(() -> new PrologException("未查询到商品信息"));
        BatchNumberSync batchNumberSync = inventoryService.getBatchNumberSync(Arrays.asList(containerTask.getLotId())).stream().findFirst().orElseThrow(() -> new PrologException("未查询到批次信息"));
        BizOutboundTask outboundTask = bizOutboundTaskService.findById(containerTask.getOutboundId());
        pdTaskGetRespDto.setItemCode(itemBaseInfoVO.getItemCode());
        pdTaskGetRespDto.setItemName(itemBaseInfoVO.getItemName());
        pdTaskGetRespDto.setCargoOwnerName(itemBaseInfoVO.getCargoOwnerName());
        pdTaskGetRespDto.setLotNo(batchNumberSync.getManufacturerLotNum());
        pdTaskGetRespDto.setSpecification(itemBaseInfoVO.getSpecification());
        pdTaskGetRespDto.setCategory(itemBaseInfoVO.getItemHealthCategory());
        pdTaskGetRespDto.setContainerNo(containerTask.getContainerNo());
        pdTaskGetRespDto.setContainerSubNo(containerTask.getContainerSubNo());
        pdTaskGetRespDto.setLayer(layer);
        pdTaskGetRespDto.setPlans(plans);
        pdTaskGetRespDto.setStation(containerTask.getStationLoc());
        pdTaskGetRespDto.setBarCode(itemBaseInfoVO.getPieceBarcode());
        pdTaskGetRespDto.setQty(Objects.nonNull(outboundTask.getCheckType()) && outboundTask.getCheckType() == 2 ? null : containerTask.getQty());
        pdTaskGetRespDto.setTaskId(containerTask.getId());
        pdTaskGetRespDto.setIsNextTask(1);
    }

    private CreateCarryTaskDto createCarryTaskWithAngle(String taskId, String palletNo, String sourceArea, String sourceLocation, String targetArea, String targetLocation, int businessType, String remark, String businessProperty, Integer angle, int taskType, int priority, String planes) {
        CreateCarryTaskDto createCarryTaskDto = new CreateCarryTaskDto();
        CarryTask carryTask = new CarryTask();
        carryTask.setId(taskId);
        carryTask.setContainerNo(palletNo);
        carryTask.setPalletNo(palletNo);
        carryTask.setTaskType(taskType);
        carryTask.setStartRegion(sourceArea);
        carryTask.setStartLocation(sourceLocation);
        carryTask.setEndRegion(targetArea);
        carryTask.setEndLocation(targetLocation);
        carryTask.setTaskStatus(0);
        carryTask.setPriority(priority);
        carryTask.setBusinessType(String.valueOf(taskType));
        carryTask.setBusinessDescribe(remark);
        carryTask.setBusinessProperty(businessProperty);
        carryTask.setCreateTime(new Date());
        carryTask.setTaskRemark(remark);
        carryTask.setExtend1(planes);
        carryTask.setExtend2("0");

        createCarryTaskDto.setCarryTask(carryTask);
        List<CarryTaskAngle> angleList = new ArrayList<>();
        CarryTaskAngle carryTaskAngle = new CarryTaskAngle();
        carryTaskAngle.setAngle(angle);
        carryTaskAngle.setAreaNo(targetArea);
        carryTaskAngle.setCarryTaskId(taskId);
        angleList.add(carryTaskAngle);

        createCarryTaskDto.setAngleList(angleList);

        return createCarryTaskDto;
    }

    private CarryTask createCarryTask(String taskId, String palletNo, String sourceArea, String sourceLocation, String targetArea, String targetLocation, int taskType, String remark, String businessProperty, String subAreaNo) {
        CarryTask carryTask = new CarryTask();
        carryTask.setId(taskId);
        carryTask.setContainerNo(palletNo);
        carryTask.setPalletNo(palletNo);
        carryTask.setTaskType(LocationConstants.PATH_TASK_TYPE_CARRY);
        carryTask.setStartRegion(sourceArea);
        carryTask.setStartLocation(sourceLocation);
        carryTask.setEndRegion(targetArea);
        carryTask.setEndLocation(targetLocation);
        carryTask.setTaskStatus(0);
        carryTask.setPriority(80);
        carryTask.setSubAreaNo(subAreaNo);
        carryTask.setBusinessType(String.valueOf(taskType));
        carryTask.setBusinessDescribe(remark);
        carryTask.setBusinessProperty(businessProperty);
        carryTask.setCreateTime(new Date());
        carryTask.setTaskRemark(remark);
        return carryTask;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public PdTaskGetRespDto pdTaskConfirm(PdTaskConfirmReqDto req) throws Exception {
        //确认处理
        doFinish(req);
        //自动获取下一条任务
        return getNextTask(req);

    }

    private PdTaskGetRespDto getNextTask(PdTaskConfirmReqDto req) throws Exception {
        //1 查询此站台已索取的所有未开始任务
        StationCfg stationCfg = stationCfgService.findOneByMap(MapUtils.put(StationCfg::getStationNo, req.getStationNo()).getMap());
        Criteria containerTaskCri = new Criteria(ContainerTask.class);
        containerTaskCri.restrictionBuilder().eq(ContainerTask::getWmsLocationCode, WmsCarryTaskInCode.AGVL.getCode()).lt(ContainerTask::getStatus, 5).eq(ContainerTask::getTaskType, req.getTaskType()).eq(ContainerTask::getStationId, stationCfg.getId()).eq(ContainerTask::getContainerNo, req.getContainerNo()).build();
        List<ContainerTask> containerTaskList = containerTaskService.findByCriteria(containerTaskCri);
        //托盘盘点成空托去碟盘机了
        if (req.getToStacker()) {
            return PdTaskGetRespDto.builder().isNextTask(0).build();
        }
        if (CollectionUtils.isEmpty(containerTaskList)) {
            //容器归还
            pdTaskContainerReturn(req.getContainerNo(), req.getStationNo());
            return PdTaskGetRespDto.builder().isNextTask(0).build();
        }
        PdTaskGetRespDto pdTaskGetRespDto = new PdTaskGetRespDto();
        //2 任务根据容器号分组
        Map<String, List<ContainerTask>> containerTaskMap = containerTaskList.stream().collect(Collectors.groupingBy(ContainerTask::getContainerNo));
        //3 获取上次任务的容器任务
        List<ContainerTask> containerTasks = containerTaskMap.get(req.getContainerNo());
        if (CollectionUtils.isNotEmpty(containerTasks)) {
            //此容器还有任务，说明是货架任务 根据货格排序 取第一个货格进行任务
            containerTasks = containerTasks.stream().sorted(Comparator.comparing(ContainerTask::getContainerSubNo)).collect(Collectors.toList());
            final ContainerTask containerTask = containerTasks.get(0);
            //查询货架和货格信息
            PalletInfo palletInfo = palletInfoMapper.findByMap((MapUtils.put(PalletInfo::getPalletNo, containerTask.getContainerNo()).getMap()), PalletInfo.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货架信息"));
            PalletLocation palletLocation = palletLocationMapper.findByMap(MapUtils.put(PalletLocation::getPalletLocation, containerTask.getContainerSubNo()).getMap(), PalletLocation.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货格信息"));
            //判断是否需要换面
            if (!StrUtil.equals(req.getPlanes(), palletLocation.getPlanes())) {
                palletRotate(palletInfo.getPalletNo(), stationCfg.getAreaNo(), palletLocation.getPlanes(), stationCfg.getAngle());
            }
            setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, palletLocation.getLayer(), palletLocation.getPlanes());
        } else {
            //切换成下一个容器任务，一个站台最多两个货位，这里表示最后一个容器任务
            containerTaskList = containerTaskList.stream().sorted(Comparator.comparing(ContainerTask::getContainerSubNo)).collect(Collectors.toList());
            ContainerTask containerTask = containerTaskList.get(0);
            if (containerTask.getContainerNo().equals(containerTask.getContainerSubNo())) {
                //托盘
                setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, null, null);
            } else {
                //货架
                //查询货架和货格信息
                PalletLocation palletLocation = palletLocationMapper.findByMap(MapUtils.put(PalletLocation::getPalletLocation, containerTask.getContainerSubNo()).getMap(), PalletLocation.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货格信息"));
                setPdTaskGetRespDto(pdTaskGetRespDto, containerTask, palletLocation.getLayer(), palletLocation.getPlanes());
            }
        }
        return pdTaskGetRespDto;
    }

    private void palletRotate(String palletNo, String areaNo, String targetPlane, int stationDir) throws Exception {
        Criteria criteria = Criteria.forClass(PalletInfo.class);
        criteria.setRestriction(Restrictions.and(Restrictions.eq("palletNo", palletNo)));
        String taskId = PrimaryAgvGeneraterUtils.getInstance().generaterNextNumber();
        // 调用下发搬运任务的接口（带角度）
        int palletDir = AngleConversionAB.getDirectionStr(targetPlane, stationDir);
        long l = palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", 1).put("subArea", areaNo).put("containerMoveTaskId", taskId).put("angle", palletDir).getMap(), criteria);
        if (l > 0) {
            // 生成搬运任务
            // 任务类型后续统一定
            // 调用下发搬运任务的接口（带角度并执行）
            ContainerLocationVo containerLocationVo = routeFeignService.findLocationByContainerList(Arrays.asList(palletNo)).stream().findFirst().orElseThrow(() -> new PrologException("未查询到容器点位信息"));
            CreateCarryTaskDto carryTask = this.createCarryTaskWithAngle(taskId, palletNo, areaNo, containerLocationVo.getCurrentLocation(), areaNo, containerLocationVo.getCurrentLocation(), LocationConstants.PATH_TASK_TYPE_SPIN_AROUND, "货架原地旋转", "货架原地旋转", palletDir, LocationConstants.PATH_TASK_TYPE_SPIN_AROUND, 99, targetPlane);
            routeFeignService.creatCarryTaskWithAngleAndExecute(carryTask);
        } else {
            throw new BizException(String.format("货架%s状态修改失败:", palletNo));
        }
    }

    private void doFinish(PdTaskConfirmReqDto req) throws Exception {
        req.setToStacker(false);
        final ContainerTask containerTask = containerTaskService.findById(req.getTaskId());
        AssertUtils.isNotTrue(containerTask.getStatus() == 5, "此容器任务已确认");
        final BizOutboundTask bizOutboundTask = bizOutboundTaskService.findById(containerTask.getOutboundId());
        if (req.getTaskType() == 40) {
            //盘点修改库存
            BizOutboundTaskDetail outboundTaskDetail = bizOutboundTaskDetailService.findById(containerTask.getOutboundDetailId());
            final ContainerInfoDetail containerInfoDetail = containerInfoDetailService.findOneByMap(MapUtils.put(ContainerInfoDetail::getContainerSubNo, req.getContainerSubNo()).getMap());
            if (containerInfoDetail.getQty().compareTo(req.getQty()) != 0) {
                if (Objects.nonNull(outboundTaskDetail.getIsCheck()) && outboundTaskDetail.getIsCheck() == 1) {
                    if (StrUtil.equals(containerInfoDetail.getContainerNo(), containerInfoDetail.getContainerSubNo()) && req.getQty().compareTo(BigDecimal.ZERO) == 0) {
                        //托盘盘空需要发往叠盘机
                        req.setToStacker(true);
                    }
                    containerInfoDetail.setIsLock(1);
                    containerInfoDetail.setLockQty(containerInfoDetail.getQty());
                    containerInfoDetail.setUpdateTime(LocalDateTime.now());
                    containerInfoDetailService.update(containerInfoDetail);
                    containerTask.setInvQty(req.getQty());
                } else {
                    final BigDecimal changeQty = req.getQty().subtract(containerInfoDetail.getQty());
                    if (!StrUtil.equals(containerInfoDetail.getContainerNo(), containerInfoDetail.getContainerSubNo())) {
                        //货架
                        if (req.getQty().compareTo(BigDecimal.ZERO) == 0) {
                            containerInfoDetailService.deleteById(containerInfoDetail.getId());
                            List<ContainerInfoDetail> containerInfoDetailList = containerInfoDetailService.findByMap(MapUtils.put(ContainerInfoDetail::getContainerNo, containerInfoDetail.getContainerNo()).getMap());
                            if (CollectionUtils.isEmpty(containerInfoDetailList)) {
                                containerInfoService.deleteByMap(MapUtils.put(ContainerInfo::getContainerNo, containerInfoDetail.getContainerNo()).getMap());
                            }
                        } else {
                            containerInfoDetail.setQty(req.getQty());
                            containerInfoDetail.setUpdateTime(LocalDateTime.now());
                            containerInfoDetail.setVolume(containerInfoDetail.getSingleVolume().multiply(containerInfoDetail.getQty()));
                            containerInfoDetailService.update(containerInfoDetail);
                        }
                    } else {
                        //托盘
                        containerInfoDetail.setQty(req.getQty());
                        containerInfoDetail.setUpdateTime(LocalDateTime.now());
                        containerInfoDetailService.update(containerInfoDetail);
                        if (req.getQty().compareTo(BigDecimal.ZERO) == 0) {
                            req.setToStacker(true);
                            emptyContainerTaskService.save(containerTask.getContainerNo(), LayerEnum.TWO, WmsCarryTaskInCode.AGVL);
                            wmsContainerStatusUpdateService.execute(WmsContainerStatusUpdateDto.builder().containerCode(containerTask.getContainerNo()).enterpriseId(bizOutboundTask.getEnterpriseId()).warehouseId(bizOutboundTask.getWmsWarehouseId()).build());
                        }
                    }

                    containerTask.setInvQty(req.getQty());
                    ContainerStoreChange changeChange = new ContainerStoreChange();
                    changeChange.setContainerNo(containerInfoDetail.getContainerNo());
                    changeChange.setContainerSubNo(containerInfoDetail.getContainerSubNo());
                    changeChange.setTaskType(req.getTaskType());
                    changeChange.setSoureQty(containerInfoDetail.getQty());
                    changeChange.setChangeQty(changeQty);
                    changeChange.setTargetQty(req.getQty());
                    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);
                }
            }
        } else {
            //养护
            WmsTaskFinishDetailDto wmsTaskFinishDetailDto = new WmsTaskFinishDetailDto();
            BeanUtil.copyProperties(req, wmsTaskFinishDetailDto);
            wmsTaskFinishDetailDto.setLocationNo(containerTask.getContainerSubNo());
            wmsTaskFinishDetailDto.setInventoryQty(containerTask.getQty());
            containerTask.setYhResult(JSONUtil.toJsonStr(wmsTaskFinishDetailDto));
        }

        containerTask.setStatus(5);
        containerTask.setUpdateTime(LocalDateTime.now());
        containerTaskService.update(containerTask);
        List<ContainerTask> containerTasks = containerTaskService.findByMap(MapUtils.put(ContainerTask::getOutboundId, containerTask.getOutboundId()).getMap());
        long count = containerTasks.stream().filter(item -> item.getStatus() < 5).count();
        if (count == 0) {
            //此订单全部完成 转历史回告
            BizOutboundTaskHis bizOutboundTaskHis = new BizOutboundTaskHis();
            BeanUtil.copyProperties(bizOutboundTask, bizOutboundTaskHis);
            bizOutboundTaskService.deleteById(bizOutboundTask.getId());
            bizOutboundTaskHisService.save(bizOutboundTaskHis);

            final List<BizOutboundTaskDetail> bizOutboundTaskDetailList = bizOutboundTaskDetailService.findByMap(MapUtils.put(BizOutboundTaskDetail::getOutboundId, containerTask.getOutboundId()).getMap());
            for (BizOutboundTaskDetail bizOutboundTaskDetail : bizOutboundTaskDetailList) {
                BizOutboundTaskDetailHis bizOutboundTaskDetailHis = new BizOutboundTaskDetailHis();
                BeanUtil.copyProperties(bizOutboundTaskDetail, bizOutboundTaskDetailHis);
                bizOutboundTaskDetailService.deleteById(bizOutboundTaskDetail.getId());
                bizOutboundTaskDetailHisService.save(bizOutboundTaskDetailHis);

                List<ContainerTask> collect = containerTasks.stream().filter(item -> Objects.equals(item.getOutboundDetailId(), bizOutboundTaskDetail.getId())).collect(Collectors.toList());
                taskFinishBack(bizOutboundTask, bizOutboundTaskDetail, collect);
            }
            containerTasks.forEach(item -> {
                ContainerTaskHis taskHis = new ContainerTaskHis();
                BeanUtil.copyProperties(item, taskHis);
                containerTaskHisService.save(taskHis);
                containerTaskService.deleteById(item.getId());
            });
        }

    }

    private void taskFinishBack(BizOutboundTask bizOutboundTask, BizOutboundTaskDetail bizOutboundTaskDetail, List<ContainerTask> containerTaskList) throws Exception {
        if (bizOutboundTask.getWorkType().equals("50")) {
            //养护
            List<WmsTaskFinishDetailDto> yhList = new ArrayList<>();
            BigDecimal qty = BigDecimal.ZERO;
            for (ContainerTask containerTask : containerTaskList) {
                String yhResult = containerTask.getYhResult();
                yhList.add(JSONUtil.toBean(yhResult, WmsTaskFinishDetailDto.class));
                qty = qty.add(containerTask.getQty());
            }
            wmsTaskFinishBackService.execute(Arrays.asList(WmsTaskFinishDto.builder().msgId(StrUtil.uuid()).billNo(bizOutboundTask.getBillNo())
//                    .containerNo(containerNo)
                    .businessType(bizOutboundTask.getBusinessType()).workType(bizOutboundTask.getWorkType()).warehouseId(bizOutboundTask.getWmsWarehouseId()).taskId(bizOutboundTask.getUpperSystemTaskId()).taskLineId(bizOutboundTaskDetail.getSeqNo()).itemId(bizOutboundTaskDetail.getItemId()).lotId(bizOutboundTaskDetail.getLotId()).ownerId(bizOutboundTaskDetail.getOwnerId()).packId(bizOutboundTaskDetail.getPackId()).wmsLocationCode(bizOutboundTask.getWmsLocationCode()).inventoryQty(qty).countQty(qty.toString()).employeeId(getUserId()).lackQty("0").isLack(1).itemList(yhList).build()));
        } else {
            //盘点
            BigDecimal totalQty = BigDecimal.ZERO;
            BigDecimal totalInvQty = BigDecimal.ZERO;
            List<WmsTaskFinishDetailDto> wmsTaskFinishDetailDtos = new ArrayList<>();
            for (ContainerTask containerTask : containerTaskList) {
                totalQty = totalQty.add(containerTask.getQty());
                if (Objects.isNull(containerTask.getInvQty())) {
                    totalInvQty = totalInvQty.add(containerTask.getQty());
                } else {
                    totalInvQty = totalInvQty.add(containerTask.getInvQty());
                }
                wmsTaskFinishDetailDtos.add(WmsTaskFinishDetailDto.builder().locationNo(containerTask.getContainerSubNo()).inventoryQty(containerTask.getQty()).confirmQty(Objects.isNull(containerTask.getInvQty()) ? containerTask.getQty() : containerTask.getInvQty()).build());

            }
            wmsTaskFinishBackService.execute(Arrays.asList(WmsTaskFinishDto.builder().msgId(StrUtil.uuid()).billNo(bizOutboundTask.getBillNo()).businessType(bizOutboundTask.getBusinessType()).workType(bizOutboundTask.getWorkType()).warehouseId(bizOutboundTask.getWmsWarehouseId()).taskId(bizOutboundTask.getUpperSystemTaskId()).taskLineId(bizOutboundTaskDetail.getSeqNo()).itemId(bizOutboundTaskDetail.getItemId()).lotId(bizOutboundTaskDetail.getLotId()).ownerId(bizOutboundTaskDetail.getOwnerId()).packId(bizOutboundTaskDetail.getPackId()).wmsLocationCode(bizOutboundTask.getWmsLocationCode()).inventoryQty(totalQty).countQty(totalInvQty.toString()).employeeId(getUserId()).lackQty("0").isLack(1).itemList(wmsTaskFinishDetailDtos).build()));
        }
    }

    @Override
    public List<AllotmentItemInfoDto> scanCodeGetItem(String code) throws Exception {
        List<ItemBarCodeVO> itemList = itemService.queryItemListByBarCode(code);
        Map<String, ItemSyncVO> collect = itemService.queryItemMst(itemList.stream().map(ItemBarCodeVO::getItemId).collect(Collectors.toList())).stream().collect(Collectors.toMap(ItemSyncVO::getItemId, v -> v));
        List<AllotmentItemInfoDto> result = new ArrayList<>();
        for (ItemBarCodeVO item : itemList) {
            result.add(AllotmentItemInfoDto.builder().itemId(item.getItemId()).itemName(item.getItemName()).itemCode(item.getItemCode()).itemSpec(collect.get(item.getItemId()).getSpecification()).build());
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction(rollbackFor = Exception.class)
    public void pdTaskContainerReturn(String containerNo, String stationNo) throws Exception {
        final StationCfg stationCfg = stationCfgService.findOneByMap(MapUtils.put(StationCfg::getStationNo, stationNo).getMap());
        final ContainerInfo containerInfo = containerInfoService.findOneByMap(MapUtils.put(ContainerInfo::getContainerNo, containerNo).getMap());
        ContainerLocationVo containerLocationVo = routeFeignService.findLocationByContainerList(Arrays.asList(containerNo)).stream().findFirst().orElseThrow(() -> new PrologException("未查询到此容器点位信息"));
        AssertUtils.isTrue(StrUtil.equals(containerLocationVo.getCurrentArea(), stationCfg.getAreaNo()), "当前站台没有此容器");

        //修改库存状态为回库
        containerInfo.setTaskType(ContainerTaskTypeConstants.RETURN);
        containerInfo.setUpdateTime(LocalDateTime.now());
        containerInfoService.update(containerInfo);

        //任务解绑
//        final ContainerTask containerTask = containerTaskService.findOneByMap(MapUtils.put(ContainerTask::getContainerNo, containerInfo.getContainerNo()).getMap());
        Criteria c = Criteria.forClass(ContainerTask.class);
        c.setRestriction(Restrictions.and(Restrictions.eq("containerNo", containerNo)));
        containerTaskService.updateMapByCriteria(MapUtils.put(ContainerTask::getStationId, null).getMap(), c);

        int storeType = Objects.equals(String.valueOf(containerInfo.getContainerType()), ContainerTypeConstants.CONTAINER_TYPE_LT) ? LocationCfgConstants.AGVL_TP : LocationCfgConstants.AGVL_HJ;
        LocationCfg locationCfg = locationCfgService.findOneByMap(MapUtils.put(LocationCfg::getType, storeType).put(LocationCfg::getWmsAreaNo, WmsCarryTaskInCode.AGVL.getCode()).getMap());
        if (Objects.equals(String.valueOf(containerInfo.getContainerType()), ContainerTypeConstants.CONTAINER_TYPE_HJ)) {
            PalletInfo palletInfo = palletInfoMapper.findByMap((MapUtils.put(PalletInfo::getPalletNo, containerInfo.getContainerNo()).getMap()), PalletInfo.class).stream().findFirst().orElseThrow(() -> new PrologException("未查询到货架信息"));
            Criteria criteria = Criteria.forClass(PalletInfo.class);
            criteria.setRestriction(Restrictions.and(Restrictions.eq("palletNo", containerInfo.getContainerNo())));
            String taskId = PrimaryAgvGeneraterUtils.getInstance().generaterNextNumber();
            long l = palletInfoMapper.updateMapByCriteria(com.prolog.framework.utils.MapUtils.put("status", 1).put("containerMoveTaskId", taskId).put("subArea", locationCfg.getAreaNo()).getMap(), criteria);
            if (l > 0) {
                CarryTask carryTask = this.createCarryTask(taskId, containerNo, palletInfo.getSubArea(), null, locationCfg.getAreaNo(), null, BaseTaskTypeConstants.IN_TYPE, "货架回库", "", locationCfg.getAreaNo());
                routeFeignService.createBatchCarry(Arrays.asList(carryTask));
            }
        } else {
            //回库
            routeFeignService.createCarryTask(containerNo, null, containerLocationVo.getCurrentArea(), containerLocationVo.getCurrentLocation(), locationCfg.getAreaNo(), null, String.valueOf(BaseTaskTypeConstants.IN_TYPE), 1, "盘点养护回库", null);
        }
    }

    @Override
    public List<AllotmentTaskRecordResultDto> allotmentTaskRecordList(AllotmentTaskRecordReqDto req) throws Exception {
        List<String> itemIds = new ArrayList<>();
        if (StrUtil.isNotBlank(req.getItemId())) {
            itemIds.add(req.getItemId());
        }
        if (StrUtil.isNotBlank(req.getItemName())) {
            List<ItemBaseInfoVO> itemBaseList = itemService.getItemByName(req.getItemName());
            if (CollectionUtils.isNotEmpty(itemBaseList)) {
                List<String> collect = itemBaseList.stream().map(ItemBaseInfoVO::getItemId).collect(Collectors.toList());
                itemIds.addAll(collect);
            } else {
                itemIds.add("空");
            }
        }
        if (StrUtil.isNotBlank(req.getItemCode())) {
            List<ItemBarCodeVO> itemBarCodeVO = itemService.queryItemListAllByBarCode(req.getItemCode());
            if (CollectionUtils.isNotEmpty(itemBarCodeVO)) {
                List<String> collect = itemBarCodeVO.stream().map(ItemBarCodeVO::getItemId).collect(Collectors.toList());
                itemIds.addAll(collect);
            } else {
                itemIds.add("空");
            }
        }
        if (!itemIds.isEmpty()) {
            req.setItemIds(itemIds);
        }
        if (StrUtil.isNotBlank(req.getLotNo())) {
            List<BatchNumberSync> batchNumberSyncList = inventoryService.findByBatchNum(req.getLotNo());
            if (CollectionUtils.isNotEmpty(batchNumberSyncList)) {
                req.setLotIds(batchNumberSyncList.stream().map(BatchNumberSync::getBatchId).distinct().collect(Collectors.toList()));
            } else {
                req.setLotIds(Arrays.asList("空"));
            }
        }
        PageUtils.startPage(req.getPageNum(), req.getPageSize());
        List<AllotmentTaskRecordResultDto> list = allotmentCfgService.allotmentTaskRecordList(req);
        if (CollectionUtils.isNotEmpty(list)) {
            List<ItemSyncVO> itemList = new ArrayList<>();
            List<BatchNumberSync> batchList = new ArrayList<>();
            List<String> itemIdParams = list.stream().filter(item -> StrUtil.isNotBlank(item.getItemId())).map(AllotmentTaskRecordResultDto::getItemId).collect(Collectors.toList());
            List<String> lotIdParams = list.stream().filter(item -> StrUtil.isNotBlank(item.getLotId())).map(AllotmentTaskRecordResultDto::getLotId).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(itemIdParams)) {
                itemList = itemService.queryItemMst(itemIdParams);
            }
            if (CollectionUtils.isNotEmpty(lotIdParams)) {
                batchList = inventoryService.getBatchNumberSync(lotIdParams);
            }
            for (AllotmentTaskRecordResultDto item : list) {
                if (StrUtil.isNotBlank(item.getItemId())) {
                    ItemSyncVO itemSyncVO = itemList.stream().filter(inner -> StrUtil.equals(inner.getItemId(), item.getItemId())).findFirst().orElse(null);
                    if (Objects.nonNull(itemSyncVO)) {
                        item.setItemName(itemSyncVO.getItemName());
                        item.setItemCode(itemSyncVO.getPieceBarcode());
                    }
                }
                if (StrUtil.isNotBlank(item.getLotId())) {
                    BatchNumberSync batchNumberSync = batchList.stream().filter(inner -> StrUtil.equals(inner.getBatchId(), item.getLotId())).findFirst().orElse(null);
                    if (Objects.nonNull(batchNumberSync)) {
                        item.setLotNo(batchNumberSync.getBatchNum());
                    }
                }
            }
        }
        return list;
    }

    @Override
    public List<AllotmentTaskRecordDetailResultDto> allotmentTaskRecordDetail(Integer id) throws Exception {
        AllotmentTaskRecord allotmentTaskRecord = allotmentTaskRecordService.findById(id);
        String itemId = "非商品供包";
        String lotId = "非商品供包";
        String lotNo = "非商品供包";
        String itemName = "非商品供包";
        String itemCode = "非商品供包";
        if (Objects.nonNull(allotmentTaskRecord)) {
            AssertUtils.isNotTrue(StrUtil.isBlank(allotmentTaskRecord.getCode()), "此次供包无药监码");
            BizOutboundTask outboundTask = bizOutboundTaskService.findById(allotmentTaskRecord.getOutboundId());
            if (Objects.nonNull(allotmentTaskRecord.getDismantleId())) {
                BizOutboundTaskDetailDismantle outboundTaskDetailDismantle = bizOutboundTaskDetailDismantleService.findById(allotmentTaskRecord.getDismantleId());
                ItemSyncVO itemSyncVO = itemService.queryItemMst(Arrays.asList(allotmentTaskRecord.getItemId())).stream().findFirst().orElseThrow(() -> new PrologException(String.format("商品id%s未查询到商品信息", allotmentTaskRecord.getItemId())));
                BatchNumberSync batchNumberSync = inventoryService.getBatchNumberSync(Arrays.asList(outboundTaskDetailDismantle.getLotId())).stream().findFirst().orElseThrow(() -> new PrologException(String.format("批次id%s未查询到批次信息", outboundTaskDetailDismantle.getLotId())));
                itemCode = itemSyncVO.getItemCode();
                itemName = itemSyncVO.getItemName();
                lotNo = batchNumberSync.getBatchNum();
                lotId = outboundTaskDetailDismantle.getLotId();
                itemId = outboundTaskDetailDismantle.getItemId();
            }
            List<AllotmentTaskRecordDetailResultDto> result = new ArrayList<>();
            String[] split = allotmentTaskRecord.getCode().split(",");
            for (int i = 0; i < split.length; i++) {
                result.add(AllotmentTaskRecordDetailResultDto.builder().id(allotmentTaskRecord.getId()).billNo(outboundTask.getBillNo()).itemId(itemId).itemCode(itemCode).itemName(itemName).lotId(lotId).lotNo(lotNo).code(split[i]).createTime(allotmentTaskRecord.getCreateTime()).build());
            }
            return result;
        }

        AllotmentTaskRecordHis allotmentTaskRecordHis = allotmentTaskRecordHisService.findOneByMap(MapUtils.put(AllotmentTaskRecordHis::getId, id).getMap());
        if (Objects.isNull(allotmentTaskRecordHis)) {
            throw new PrologException("未查询到供包记录");
        }
        AssertUtils.isNotTrue(StrUtil.isBlank(allotmentTaskRecordHis.getCode()), "此次供包无药监码");

        String billNo = "";
        BizOutboundTask outboundTask = bizOutboundTaskService.findById(allotmentTaskRecordHis.getOutboundId());
        if (Objects.nonNull(outboundTask)) {
            billNo = outboundTask.getBillNo();
        } else {
            List<BizOutboundTaskHis> outboundTaskHisList = bizOutboundTaskHisService.findByMap(MapUtils.put(BizOutboundTaskHis::getId, allotmentTaskRecordHis.getOutboundId()).getMap());
            if (CollectionUtils.isEmpty(outboundTaskHisList)) {
                throw new PrologException("未查询到订单信息");
            }
            billNo = outboundTaskHisList.get(0).getBillNo();
        }

        if (Objects.nonNull(allotmentTaskRecordHis.getDismantleId())) {
            BizOutboundTaskDetailDismantle outboundTaskDetailDismantle = bizOutboundTaskDetailDismantleService.findById(allotmentTaskRecordHis.getDismantleId());
            if (Objects.nonNull(outboundTaskDetailDismantle)) {
                lotId = outboundTaskDetailDismantle.getLotId();
            } else {
                BizOutboundTaskDetailDismantleHis outboundTaskDetailDismantleHis = outboundTaskDetailDismantleHisService.findById(allotmentTaskRecordHis.getDismantleId());
                if (Objects.isNull(outboundTaskDetailDismantleHis)) {
                    throw new PrologException("未查询到订单信息");
                }
                lotId = outboundTaskDetailDismantleHis.getLotId();
            }
            ItemSyncVO itemSyncVO = itemService.queryItemMst(Arrays.asList(allotmentTaskRecordHis.getItemId())).stream().findFirst().orElseThrow(() -> new PrologException(String.format("商品id%s未查询到商品信息", allotmentTaskRecordHis.getItemId())));
            BatchNumberSync batchNumberSync = inventoryService.getBatchNumberSync(Arrays.asList(lotId)).stream().findFirst().orElseThrow(() -> new PrologException("未查询到批次信息"));
            itemCode = itemSyncVO.getItemCode();
            itemName = itemSyncVO.getItemName();
            lotNo = batchNumberSync.getBatchNum();
            itemId = allotmentTaskRecordHis.getItemId();
        }


        List<AllotmentTaskRecordDetailResultDto> result = new ArrayList<>();
        String[] split = allotmentTaskRecordHis.getCode().split(",");
        for (int i = 0; i < split.length; i++) {
            result.add(AllotmentTaskRecordDetailResultDto.builder().id(allotmentTaskRecordHis.getId()).billNo(billNo).itemId(itemId).itemCode(itemCode).itemName(itemName).lotId(lotId).lotNo(lotNo).code(split[i]).createTime(allotmentTaskRecordHis.getCreateTime()).build());
        }
        return result;
    }

    @Override
    public void allotmentTaskRecordSave(Integer id) {
        AllotmentTaskRecord allotmentTaskRecord = allotmentTaskRecordService.findById(id);
        if (Objects.isNull(allotmentTaskRecord)) {
            throw new PrologException("未查询到供包记录");
        }
        if (allotmentTaskRecord.getLogeStatus() == 1) {
            throw new PrologException("此次供包已落格，请勿重复推送");
        }
        BizOutboundTask outboundTask = bizOutboundTaskService.findById(allotmentTaskRecord.getOutboundId());
        if (Objects.isNull(outboundTask)) {
            throw new PrologException("订单已转历史不支持再次供包");
        }
        allotmentTaskRecord.setSendStatus(0);
        allotmentTaskRecord.setLogeStatus(0);
        allotmentTaskRecordService.update(allotmentTaskRecord);
    }

    @Override
    public List<String> allotmentStationList() {
        return allotmentCfgService.findByMap(MapUtils.put(AllotmentCfg::getIsLock, 0).getMap()).stream().map(AllotmentCfg::getStationNo).collect(Collectors.toList());
    }

    @Override
    public List<WaveBindConditionDto> waveBindCondition() {
        Criteria criteria = Criteria.forClass(BizOutboundTask.class);
        criteria.restrictionBuilder().isNotNull(BizOutboundTask::getEisWaveNo).build();
        List<BizOutboundTask> list = bizOutboundTaskService.findByCriteria(criteria);

        List<WaveBindConditionDto> waveBindConditionDtos = new ArrayList<>();
        Map<String, List<BizOutboundTask>> map = list.stream().collect(Collectors.groupingBy(BizOutboundTask::getEisWaveNo));
        map.forEach((k, v) -> {
            WaveBindConditionDto waveBindConditionDto = new WaveBindConditionDto();
            waveBindConditionDto.setWaveNo(k);
            waveBindConditionDto.setOrderNum(v.size());
            long bindOrderNum = v.stream().filter(x -> x.getIsBindGrid().equals(1)).count();
            waveBindConditionDto.setBindOrderNum((int) bindOrderNum);
            Long finishOrderNum = v.stream().filter(x -> x.getStatus().equals(BaseStatusEnum.STATUS_FINISH.getCode())).count();
            waveBindConditionDto.setFinishOrderNum(finishOrderNum.intValue());
            waveBindConditionDto.setUnbindOrderNum(v.size() - (int) bindOrderNum);
            waveBindConditionDtos.add(waveBindConditionDto);
        });
        return waveBindConditionDtos;
    }
}
