package com.prolog.cs.biz.outbound.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.github.pagehelper.PageHelper;
import com.prolog.cs.basic.common.model.BaseBizFile;
import com.prolog.cs.basic.common.model.BaseCommonDict;
import com.prolog.cs.basic.common.model.vo.BaseBizFileQueryVO;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.item.model.vo.ItemMstQueryVO;
import com.prolog.cs.basic.item.model.vo.ItemMstVO2;
import com.prolog.cs.basic.item.model.vo.WaveItemInfoVO;
import com.prolog.cs.basic.warehouse.model.BaseWmsWarehouseLocator;
import com.prolog.cs.basic.warehouse.model.vo.ContainerQueryVO;
import com.prolog.cs.basic.warehouse.model.vo.WarehouseLocatorBasicInfo;
import com.prolog.cs.biz.control.model.vo.LocatorQueryVO;
import com.prolog.cs.biz.inbound.dto.IsSuperviseDTO;
import com.prolog.cs.biz.outbound.Application;
import com.prolog.cs.biz.outbound.dao.*;
import com.prolog.cs.biz.outbound.funcflow.BarCodeFunc;
import com.prolog.cs.biz.outbound.model.*;
import com.prolog.cs.biz.outbound.model.dto.*;
import com.prolog.cs.biz.outbound.model.entity.*;
import com.prolog.cs.biz.outbound.model.vo.OuterCheckPickUpVO;
import com.prolog.cs.biz.outbound.model.vo.check.OuterCheckGainVO;
import com.prolog.cs.biz.outbound.resource.*;
import com.prolog.cs.biz.outbound.service.*;
import com.prolog.cs.biz.outbound.service.strategy.StrategySelector;
import com.prolog.cs.biz.outbound.utils.IntegrationUtil;
import com.prolog.cs.platform.power.model.Employee;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.common.print.PrintData;
import com.prolog.framework.bz.common.print.ReportData;
import com.prolog.framework.bz.core.collection.ValidList;
import com.prolog.framework.bz.core.model.ModelUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.lock.DistributedLock;
import com.prolog.framework.utils.*;
import com.prolog.function.annotation.Flow;
import com.prolog.function.annotation.FuncImpl;
import com.prolog.upcloud.base.inventory.dto.InstockItemInfo;
import com.prolog.upcloud.base.inventory.vo.BatchNumberListVO;
import com.prolog.upcloud.base.inventory.vo.InvStockOut;
import com.prolog.upcloud.base.inventory.vo.InvStockOutDetail;
import com.prolog.upcloud.base.strategy.model.BusinessControl;
import com.prolog.upcloud.base.wh.operate.vo.WmsAdjustAddVO;
import com.prolog.upcloud.base.wh.operate.vo.WmsMoveDetailVO;
import com.prolog.upcloud.base.wh.operate.vo.WmsMoveSaveVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cglib.beans.BeanMap;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

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

/**
 * @author zzz
 * @desc 外复核
 * @date 2022/1/4
 */
@Service
public class BarCodeServiceImpl implements BarCodeService {

    private static Logger log = LoggerFactory.getLogger(BarCodeServiceImpl.class);

    @Autowired
    private PickTaskHMapper pickTaskHMapper;

    @Autowired
    private BarcodeHMapper barcodeHMapper;

    @Autowired
    private BarcodeDMapper barcodeDMapper;

    @Autowired
    private PickUpRecordMapper pickUpRecordMapper;

    @Autowired
    private WaveBillMapper billMapper;

    @Autowired
    private WaveBillDMapper billdMapper;

    @Autowired
    private InventoryResource invClient;

    @Autowired
    private InBoundClient inBoundClient;

    @Autowired
    private WorkStageService workStageService;

    @Autowired
    private WaveStorageMapper storageMapper;

    @Autowired
    private PickTaskService pickTaskService;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private UserTemplate userTemplate;

    @Autowired
    protected DistributedLock distributedLock;

    @Autowired
    private OmsDoBillHMapper omsDoBillHMapper;

    @Autowired
    private PostBackErpService postBackErpService;

    // 业务参数配置内/外复核回传ERP by Huanglh 20220112
    @Autowired
    private StrategySelector strategySelector;

    @Autowired
    private StrategyResource strategyResource;

    @Autowired
    private WarehouseResource warehouseResource;

    @Autowired
    private WaveBillMapper waveBillMapper;

    @Autowired
    private PickTaskDMapper pickTaskDMapper;

    @Autowired
    private WaveBillDMapper waveBillDMapper;

    @Autowired
    private ControlResource controlResource;

    @Autowired
    private OperateResource operateResource;

    @Autowired
    private SaleRedRecordMapper saleRedRecordMapper;

    @Autowired
    private WorkStageRuntimeMapper workStageRuntimeMapper;

    @Autowired
    private CommonClient commonClient;

    private static Logger logger = LoggerFactory.getLogger(Application.class);

    @Autowired
    private OutcomingRecordHMapper outcomingRecordHMapper;

    @Autowired
    private OutcomingRecordDMapper outcomingRecordDMapper;

    @Autowired
    private IntegrationUtil integrationUtil;

    @Value("${oms.outComingRecordBack}")
    private String outComingRecordBack;

    @Autowired
    private PickTaskServiceImpl pickTaskServiceImpl;

    @Autowired
    private OrderOutboundStatusBackService orderOutboundStatusBackService;

    BarCodeFunc.invStockConfirm invStockConfirm;
    BarCodeFunc.updateOuterCheck updateOuterCheck;

    @PostConstruct
    public void init(){
        invStockConfirm = this::invStockConfirm;
        updateOuterCheck = this::updateOuterCheck;
    }

    @Override
    public Integer outerCheckGain(List<OuterCheckGainVO> vos) {
        if(vos == null || vos.size() <= 0){
            throw new ParameterException("入参不能为空");
        }

        String warehouseId = vos.get(0).getWarehouseId();
        String operatorCode = vos.get(0).getOperatorCode();
        String bldgId = vos.get(0).getBldgId();
        if (StringUtils.isBlank(warehouseId))
            throw new ParameterException("仓库id不能为空");
        if (StringUtils.isBlank(operatorCode))
            throw new ParameterException("工号不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        Employee employee = pickTaskService.getEmployee(operatorCode, enterpriseId);
        if (employee == null)
            throw new BizException("该员工信息未找到！");

        HashMap<OuterCheckGainVO, List<OuterCheckGainVO>> map = vos.stream()
                .collect(groupingBy(item -> new OuterCheckGainVO(
                                item.getSrcBillCode(),
                                item.getBarcode()
                        ),
                        HashMap::new, toList()));

        //外复核最大索取订单数
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"OUT_CHECK_TASK_NUM"}, warehouseId, null, enterpriseId, bldgId);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> result = restMessage.getData();
            if (result.containsKey("OUT_CHECK_TASK_NUM")) {
                Integer count = Integer.valueOf(result.get("OUT_CHECK_TASK_NUM").getRegValue());
                if(map.entrySet().size() > count){
                    throw new BizException("超过外复核索取最大订单数");
                }
            }else {
                throw new BizException("外复核索取最大订单数未配置");
            }
        }

        int result = 0;
        for (Map.Entry<OuterCheckGainVO, List<OuterCheckGainVO>> entry : map.entrySet()) {
            String barcode = entry.getKey().getBarcode();
            String srcBillCode = entry.getKey().getSrcBillCode();
            if (StringUtils.isBlank(barcode) && StringUtils.isBlank(srcBillCode))
                throw new ParameterException("条码/订单编号不能为空");
            //获取员工作业库区编码集合
//        List<String> areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", "BULK_PICKING");
            List<WaveBillDODTO> list = pickTaskHMapper.getPickTaskHOut(bldgId, srcBillCode, barcode, enterpriseId, warehouseId);
            if (list.size() > 0) {
                Date date = new Date();
                for (WaveBillDODTO dto : list) {
                    if (dto.getCheckStatus() == null)
                        throw new BizException("订单复核未完成,无法索取！");
                    if (dto.getCheckStatus() != null && !"0".equals(dto.getCheckStatus()))
                        throw new BizException("订单已被索取或确认！");
                    barcodeHMapper.updateMapById(dto.getBarcodeId(), MapUtils.put("checkStatus", "1").put("checkerId", employee.getUserId()).put("checkerNo", operatorCode).put("checkerName", employee.getLocname()).put("checkTime", date).put("checkTime", date).getMap(), BarcodeHDO.class);
                }
            } else {
                throw new BizException("未索取到任务！");
            }
            pickTaskHMapper.updateFlowStatus("6", srcBillCode, warehouseId);
            log.info("外复核索取成功，订单编号：{}", srcBillCode);
            result += list.size();
        }
        return result;
    }

//    /**
//     * 外复核-索取任务
//     *
//     * @param barcode
//     * @param srcBillCodes
//     * @param operatorCode
//     * @param warehouseId
//     * @return
//     */
//    @Flow(name = "外复核索取", category = "出库/复核管理/外复核/外复核索取", index = 0, description = "1.更新外复核主表状态为1"
//            + "\n2.更新拣货明细表流程状态为6")
//    @Override
//    @Transactional
//    public Integer outerCheckGain(String bldgId, String barcode, String srcBillCodes, String operatorCode, String warehouseId) {
//        if (StringUtils.isBlank(warehouseId))
//            throw new ParameterException("仓库id不能为空");
//        if (StringUtils.isBlank(operatorCode))
//            throw new ParameterException("工号不能为空");
//        if (StringUtils.isBlank(barcode) && StringUtils.isBlank(srcBillCodes))
//            throw new ParameterException("条码/订单编号不能为空");
//        UserDTO userDTO = userTemplate.getUserDTO();
//        String enterpriseId = userDTO.getEnterpriseId();
//        Employee employee = pickTaskService.getEmployee(operatorCode, enterpriseId);
//        if (employee == null)
//            throw new BizException("该员工信息未找到！");
//        String[] srcBillCodeArr = srcBillCodes.split(",");
//        //外复核最大索取订单数
//        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"OUT_CHECK_TASK_NUM"}, warehouseId, null, enterpriseId, bldgId);
//        if (restMessage.isSuccess() && restMessage.getData() != null) {
//            Map<String, BusinessControl> result = restMessage.getData();
//            if (result.containsKey("OUT_CHECK_TASK_NUM")) {
//                Integer count = Integer.valueOf(result.get("OUT_CHECK_TASK_NUM").getRegValue());
//                if(srcBillCodeArr.length > count){
//                    throw new BizException("超过外复核索取最大订单数");
//                }
//            }else {
//                throw new BizException("外复核索取最大订单数未配置");
//            }
//        }
//        int result = 0;
//        for (String srcBillCode : srcBillCodeArr) {
//            //获取员工作业库区编码集合
////        List<String> areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", "BULK_PICKING");
//            List<WaveBillDODTO> list = pickTaskHMapper.getPickTaskHOut(bldgId, srcBillCode, barcode, enterpriseId, warehouseId);
//            if (list.size() > 0) {
//                Date date = new Date();
//                for (WaveBillDODTO dto : list) {
//                    if (dto.getCheckStatus() == null)
//                        throw new BizException("订单复核未完成,无法索取！");
//                    if (dto.getCheckStatus() != null && !"0".equals(dto.getCheckStatus()))
//                        throw new BizException("订单已被索取或确认！");
//                    barcodeHMapper.updateMapById(dto.getBarcodeId(), MapUtils.put("checkStatus", "1").put("checkerId", employee.getUserId()).put("checkerNo", operatorCode).put("checkerName", employee.getLocname()).put("checkTime", date).put("checkTime", date).getMap(), BarcodeHDO.class);
//                }
//            } else {
//                throw new BizException("未索取到任务！");
//            }
//            pickTaskHMapper.updateFlowStatus("6", srcBillCode, warehouseId);
//            log.info("外复核索取成功，订单编号：{}", srcBillCode);
//            result += list.size();
//        }
//
//        return result;
//    }

    /**
     * 外复核-复核确认
     *
     * @param srcCodes
     */
    @Flow(name = "外复核确认", category = "出库/复核管理/外复核/外复核确认", index = 0, description = "1.更新外复核主表"
            + "\n2.更新拣货主表状态为10"
            + "\n3.更新拣货明细表流程状态为7"
            + "\n4.调用扣减库存接口"
            + "\n5.回传ERP")
    @Override
    @Transactional
    @TxTransaction
    public void outerCheckConfirm(List<String> srcCodes, String operatorCode, String warehouseId, String bldgId) {
        if (srcCodes == null || srcCodes.size() == 0)
            throw new ParameterException("id不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        Employee employee = pickTaskService.getEmployee(operatorCode, enterpriseId);
        try {
            // 更新状态
            Map<String,List<String>> map = updateOuterCheck.updateOuterCheck(srcCodes,operatorCode,warehouseId,bldgId,enterpriseId,employee);
            // 扣减库存
            invStockConfirm.invStockConfirm(srcCodes, map.get("omsBillIds"), warehouseId);
        } catch (Exception e) {
            log.error("外复核复核，订单编号：{}", JSON.toJSONString(srcCodes),e);
            throw new PrologException("外复核错误：" + e.getMessage());
        }
    }

    /**
     * 外复核-复核冲红
     *
     * @param params
     */
    @Flow(name = "外复核冲红", category = "出库/复核管理/外复核/外复核冲红", index = 0, description = "1.冲红校验"
            + "\n2.冲红数量校验"
            + "\n3.冲红数量移到盘点库")
    @Override
    @Transactional
    @TxTransaction
    public void outerCheckRed(Map<String ,Object> params) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        //List<String> srcCodes = (List<String>)params.get("srcCodes");
        String barcodeDId = (String) params.get("barcodeDId");
        String warehouseId = (String)params.get("warehouseId");
        String bldgId = (String)params.get("bldgId");
        String redQty = params.get("redQty").toString();
        String sourceQty = "0";
        if(ObjectUtils.isNotNull(params.get("qty"))){
            sourceQty  = params.get("qty").toString();
        }
        String reason = (String)params.get("reason");
        String redDoMethod = (String)params.get("redDoMethod");
        String pickTaskDId = "";
        if(params.get("pickTaskDId")!=null){
            pickTaskDId = params.get("pickTaskDId").toString();
        }
        String point = "2";
        //业务参数配置/出库回传ERP节点 1:内复核回传  2:外复核回传
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"OUT_BACK_ERP_POINT"}, warehouseId, null, enterpriseId, null);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> result = restMessage.getData();
            if (result.containsKey("OUT_BACK_ERP_POINT")) {
                point = String.valueOf(result.get("OUT_BACK_ERP_POINT").getRegValue());
            }else {
                throw new BizException("出库回传ERP节点未配置");
            }
        }
        if(point.equals("1")){
            throw new BizException("订单已回传ERP不能冲红");
        }
        //for (String srcCode : srcCodes) {
            //List<BarcodeHDO> list = barcodeHMapper.findByMap(MapUtils.put("billGroupId", srcCode).put("enterpriseId", enterpriseId).put("warehouseId", warehouseId).put("bldgId", bldgId).getMap(), BarcodeHDO.class);
        BarCodeDDO barCodeDDO = barcodeDMapper.findById(barcodeDId, BarCodeDDO.class);
        if (barCodeDDO!=null) {
            if(!StringUtils.isBlank(redDoMethod)&&redDoMethod.equals("1")){
                String locatorId = null;//盘点库货位id
                //转移到盘点库
                RestMessage<String> rest =  warehouseResource.getLocatorIdByCategory("PDK", warehouseId);
                if (!rest.isSuccess() || rest.getData()==null){
                    throw new PrologException("查询盘点库货位出错,或货位为空:"+rest.getMessage());
                }
                locatorId = rest.getData();
                ValidList<InvStockOut> validList = new ValidList<>();
                InvStockOut invStockOut = new InvStockOut();

                validList.add(invStockOut);
                List<InvStockOutDetail> details = new ArrayList<>();
                //List<BarCodeDDO> barCodeDDOList = barcodeDMapper.findByMap(MapUtils.put("barcodeId", list.get(0).getId()).getMap(), BarCodeDDO.class);
                BarcodeHDO byId1 = barcodeHMapper.findById(barCodeDDO.getBarcodeId(), BarcodeHDO.class);
                String srcCode = byId1.getBillGroupId();
                List<PickTaskD> redPickTaskDList = new ArrayList<>();
                if(StringUtils.isEmpty(pickTaskDId)){
                    String barcodePcs = params.get("barcodePcs").toString();
                    //如果pickTaskDId为空  就是RF红冲  红冲数量为件数
                    //如果是拼箱红冲
                    if(byId1.getType().equals("0")){
                        List<PickTaskD> pickTaskDList = pickTaskDMapper.findByMap(MapUtils.put("barcodeDId", barCodeDDO.getId()).getMap(), PickTaskD.class);
                        if(Integer.parseInt(redQty)>1){
                            throw new BizException("冲红数量不能大于实际数量");
                        }
                        pickTaskDList.stream().forEach(x->{
                            //原红冲数量
                            BigDecimal saleRedQty = x.getSaleRedQty()==null?BigDecimal.ZERO:x.getSaleRedQty();
                            x.setRedQty(x.getQty().subtract(saleRedQty));
                        });
                        redPickTaskDList.addAll(pickTaskDList);
                        barCodeDDO.setCheckStatus("5");
                        barcodeDMapper.update(barCodeDDO);
                    }else{
                        //如果是整件红冲
                        PickTaskD pickTaskD = pickTaskDMapper.findById(barCodeDDO.getWmsPickTaskDId(), PickTaskD.class);
                        //剩余红冲件数
                        BigDecimal remainQty = new BigDecimal(redQty);
                        if (pickTaskD != null) {
                            //原红冲数量
                            BigDecimal saleRedQty = pickTaskD.getSaleRedQty()==null?BigDecimal.ZERO:pickTaskD.getSaleRedQty();
                            //实际数量
//                            BigDecimal qty = pickTaskD.getQty().subtract(saleRedQty);
                            List<WaveStorageDO> storageDOS = storageMapper.getStorageByPickTaskDId(pickTaskD.getPickTaskDId());
                            WaveStorageDO waveStorageDO = storageDOS.get(0);
                            WaveBillDDO billid = waveBillDMapper.findById(waveStorageDO.getBillDId(), WaveBillDDO.class);
                            BigDecimal conversionRate = billid.getConversionRate();
                            //实际件数
                           // BigDecimal uomQty = qty.divide(conversionRate);
                            //条码件数
                            BigDecimal uomQty = new BigDecimal(barcodePcs);
                            pickTaskD.setRedQty(remainQty.multiply(conversionRate));
                            redPickTaskDList.add(pickTaskD);
                            if(new BigDecimal(redQty).compareTo(uomQty)>0){
                                throw new BizException("冲红数量不能大于实际数量");
                            }
                            if(new BigDecimal(redQty).compareTo(uomQty)==0){
                                barCodeDDO.setCheckStatus("5");
                                barcodeDMapper.update(barCodeDDO);
                            }
                        }
                    }
                }else{
                    //PC红冲
                    PickTaskD byId = pickTaskDMapper.findById(pickTaskDId, PickTaskD.class);
                    BigDecimal saleRedQty = byId.getSaleRedQty()==null?BigDecimal.ZERO:byId.getSaleRedQty();
                    if(StringUtils.isEmpty(sourceQty)){
                        barCodeDDO.setQty(BigDecimal.ZERO);
                    }else{
                        barCodeDDO.setQty(new BigDecimal(sourceQty));
                    }
                    if(new BigDecimal(redQty).compareTo(barCodeDDO.getQty())>0){
                        throw new BizException("冲红数量不能大于实际数量");
                    }
                    byId.setRedQty(new BigDecimal(redQty));
                    redPickTaskDList.add(byId);
                    if(new BigDecimal(redQty).compareTo(barCodeDDO.getQty())==0){
                        barCodeDDO.setCheckStatus("5");
                        barcodeDMapper.update(barCodeDDO);
                    }
                }
                List<WmsAdjustAddVO> adjustAddVOList = new ArrayList<>();
                for (PickTaskD pickTaskD : redPickTaskDList) {
                    List<WaveStorageDO> storageDOS = storageMapper.getStorageByPickTaskDId(pickTaskD.getPickTaskDId());
                    if (storageDOS.size() != 1) {
                        throw new PrologException("找不到对应的库存预占信息");
                    }
                    InvStockOutDetail detail = new InvStockOutDetail();
                    details.add(detail);
                    invStockOut.setDetails(details);

                    invStockOut.setBillId(srcCode);
                    invStockOut.setLineBillId(pickTaskD.getPickTaskDId());
                    invStockOut.setWarehouseId(warehouseId);
                    WaveStorageDO waveStorageDO = storageDOS.get(0);
                    WaveBillDDO billid = waveBillDMapper.findById(waveStorageDO.getBillDId(), WaveBillDDO.class);
                    detail.setBatchId(waveStorageDO.getBatchId());
                    detail.setQuantity(pickTaskD.getRedQty());
                    detail.setLocatorId(locatorId);
                    detail.setSubStatus("1");
                    detail.setStatus("1");
                    if(locatorId != null){
                        detail.setExtParams(MapUtils.put("adjustType","2").put("takeLocatorId",locatorId).getMap());
                    }
                    //增加盘点库库存
                    invClient.redAdjustStock(validList);
                    //移入货位通过商品货位限定查询
                    WaveBillDO bill = billMapper.findById(waveStorageDO.getBillId(), WaveBillDO.class);
                    //外复核冲红
                    SaleRedRecord saleRedRecord = new SaleRedRecord();
                    saleRedRecord.setSrcLineId(billid.getSrcLineId());
                    saleRedRecord.setBillDId(billid.getId());
                    saleRedRecord.setBillId(billid.getBillId());
                    saleRedRecord.setCheckerName(userDTO.getNickname());
                    saleRedRecord.setSrcId(billid.getMergedBillId());
                    saleRedRecord.setQty(pickTaskD.getRedQty());
                    saleRedRecord.setWarehouseId(warehouseId);
                    saleRedRecord.setType(2);
                    saleRedRecord.setReason(reason);
                    saleRedRecord.setPickTaskDId(pickTaskD.getPickTaskDId());
                    ModelUtils.setBaseInfo(saleRedRecord, ModelUtils.OpType.INSERT, userDTO);
                    saleRedRecordMapper.save(saleRedRecord);

                    //生成无计划损益单
                    // 无计划损溢VO
                    WmsAdjustAddVO wmsAdjustAddVO = new WmsAdjustAddVO();
                    wmsAdjustAddVO.setDcId(waveStorageDO.getBldgId());
                    wmsAdjustAddVO.setWarehouseId(waveStorageDO.getWarehouseId());
                    wmsAdjustAddVO.setCargoOwnerId(bill.getConsignorId());
                    wmsAdjustAddVO.setWhLocatorId(locatorId);
                    wmsAdjustAddVO.setItemId(billid.getItemId());
                    wmsAdjustAddVO.setBatchId(waveStorageDO.getBatchId());
                    wmsAdjustAddVO.setProductionDate(waveStorageDO.getProductionDate());
                    wmsAdjustAddVO.setBatchExpiredDate(waveStorageDO.getExpiredDate());
                    wmsAdjustAddVO.setQuantity(pickTaskD.getRedQty());
                    wmsAdjustAddVO.setConversionRate(billid.getConversionRate());
                    wmsAdjustAddVO.setBatchNum(waveStorageDO.getBatchNum());
                    wmsAdjustAddVO.setUom(billid.getCaseUom());
                    wmsAdjustAddVO.setStockStatus(billid.getStockStatus());
                    wmsAdjustAddVO.setAdjustType("1"); // 无计划盘点
                    wmsAdjustAddVO.setManufacturerLotNum(billid.getManufacturerLotNum());
                    wmsAdjustAddVO.setPieceQuantity(pickTaskD.getRedQty()); // 损溢数量
                    wmsAdjustAddVO.setPieceAccount(pickTaskD.getRedQty());
                    wmsAdjustAddVO.setPieceAccountFact(BigDecimal.ZERO);
                    wmsAdjustAddVO.setType(1); // 数量调整
                    wmsAdjustAddVO.setIsAdd(0); // 是否是是新增账存(0否1是)
                    wmsAdjustAddVO.setAdjustHeaderId(srcCode);
                    wmsAdjustAddVO.setAutoBillNum(bill.getSrcCode());
                    adjustAddVOList.add(wmsAdjustAddVO);

                    //更新pick_task_d的红冲数量 外复核
                    pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("saleRedQty", pickTaskD.getSaleRedQty() == null ? pickTaskD.getRedQty() : pickTaskD.getSaleRedQty().add(pickTaskD.getRedQty()).toString()).getMap(), PickTaskD.class);
                }

                if (CollectionUtil.isNotEmpty(adjustAddVOList)) {
                    for (WmsAdjustAddVO wmsAdjustAddVO:adjustAddVOList) {
                        RestMessage<?> restAdjust = operateResource.saveAdjust(wmsAdjustAddVO);
                        if (null == restAdjust || !restAdjust.isSuccess()){
                            throw new BizException("生成无计划损溢失败！" + JSONObject.toJSONString(restAdjust) + "参数 = " + JSONObject.toJSONString(wmsAdjustAddVO));
                        }
                    }
                }
                List<BarCodeDDO> barcodeIds = barcodeDMapper.findByMap(MapUtils.put("barcodeId", byId1.getId()).getMap(), BarCodeDDO.class);
                boolean allMatch = barcodeIds.stream().allMatch(x -> x.getCheckStatus().equals("5"));
                if(allMatch){
                    byId1.setCheckStatus("5");
                    barcodeHMapper.update(byId1);
                    barcodeHMapper.updatePickTaskHStatus(byId1.getBarcode(), warehouseId, enterpriseId);
                    pickTaskHMapper.updateFlowStatus("7", byId1.getBillGroupId(), warehouseId);
                    //查询是否所有明细复核完
                    List<BarcodeHDO> billGroupId = barcodeHMapper.findByMap(MapUtils.put("billGroupId", byId1.getBillGroupId()).getMap(), BarcodeHDO.class);
                    boolean allMatch1 = billGroupId.stream().allMatch(x -> x.getCheckStatus().equals("5"));
                    if(point.equals("2")){
                        if(allMatch1){
                            List<String> omsBillIds = new ArrayList<>();
                            omsBillIds.add(byId1.getBillGroupId());
                            postBackErpByTable(omsBillIds);
                        }
                    }
                }
            }
        }
    }

    @Override
    @Transactional
    @TxTransaction
    public List<ReportData> outerCheckConfirmMove(List<String> srcCodes, String operatorCode, String warehouseId, String bldgId,Map<String,String> codesMap) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        List<ReportData> moveDatas = new ArrayList<>();
        for (String srcCode : srcCodes) {
            List<BarcodeHDO> list = barcodeHMapper.findByMap(MapUtils.put("billGroupId", srcCode).put("enterpriseId", enterpriseId).put("warehouseId", warehouseId).put("bldgId", bldgId).getMap(), BarcodeHDO.class);
            if (list.size() > 0) {
                String locatorId = null;//盘点库货位id
                //转移到盘点库
                RestMessage<String> rest =  warehouseResource.getLocatorIdByCategory("XN-PDK", warehouseId);
                if (!rest.isSuccess() || rest.getData()==null){
                    throw new PrologException("查询盘点库货位出错,或货位为空:"+rest.getMessage());
                }
                locatorId = rest.getData();
                //根据查询盘点库货位信息
                RestMessage<List<WarehouseLocatorBasicInfo>> locationBasicInfos = warehouseResource.getLocationBasicInfos(new String[]{locatorId});
                if(locationBasicInfos.getData()==null||!locationBasicInfos.isSuccess()){
                    throw new BizException("查询货位信息失败");
                }
                WarehouseLocatorBasicInfo locatorBasicInfo = locationBasicInfos.getData().get(0);
                ValidList<InvStockOut> validList = new ValidList<>();
                InvStockOut invStockOut = new InvStockOut();

                validList.add(invStockOut);
                List<InvStockOutDetail> details = new ArrayList<>();
                List<PickTaskD> pickTaskDList = new ArrayList<>();
                List<BarCodeDDO> barCodeDDOList = barcodeDMapper.findByMap(MapUtils.put("barcodeId", list.get(0).getId()).getMap(), BarCodeDDO.class);
                for (BarCodeDDO barCodeDDO : barCodeDDOList) {
                    if(StringUtils.isEmpty(barCodeDDO.getWmsPickTaskDId())){
                        pickTaskDList = pickTaskDMapper.findByMap(MapUtils.put("barcodeDId", barCodeDDO.getId()).getMap(), PickTaskD.class);
                    }else{
                        pickTaskDList = pickTaskDMapper.findByMap(MapUtils.put("pickTaskDId", barCodeDDO.getWmsPickTaskDId()).getMap(), PickTaskD.class);
                    }
                }
                WmsMoveSaveVO moveSaveVO = new WmsMoveSaveVO();
                List<WaveBillDO> waveBillDOS = waveBillMapper.findByMap(MapUtils.put("billGroupId", srcCode).getMap(), WaveBillDO.class);
                WaveBillDO billDO = null;
                if(waveBillDOS.size()>0){
                    billDO = waveBillDOS.get(0);
                    moveSaveVO.setCargoOwnerId(billDO.getConsignorId());
                }else{
                    throw new BizException("查询订单信息失败");
                }
                moveSaveVO.setWarehouseId(warehouseId);
                moveSaveVO.setMoveInBldg(bldgId);
                moveSaveVO.setMoveOutBldg(bldgId);
                moveSaveVO.setWarehouseWorkerId(userDTO.getId());
                List<WmsMoveDetailVO> moveDetails = new ArrayList<>();
                List<Map<String,Object>> queryVOList = new ArrayList<>();
                List<WaveItemInfoVO> waveItemInfoList = new ArrayList<>();
                for (PickTaskD pickTaskD : pickTaskDList) {
                    List<WaveStorageDO> storageDOS = storageMapper.getStorageByPickTaskDId(pickTaskD.getPickTaskDId());
                    if (storageDOS.size() != 1) {
                        throw new PrologException("找不到对应的库存预占信息");
                    }
                    InvStockOutDetail detail = new InvStockOutDetail();
                    details.add(detail);
                    invStockOut.setDetails(details);

                    invStockOut.setBillId(srcCode);
                    invStockOut.setLineBillId(pickTaskD.getPickTaskDId());
                    invStockOut.setWarehouseId(warehouseId);
                    WaveStorageDO waveStorageDO = storageDOS.get(0);
                    detail.setBatchId(waveStorageDO.getBatchId());
                    detail.setQuantity(pickTaskD.getCheckQty().compareTo(BigDecimal.ZERO)==0?pickTaskD.getPickQty():pickTaskD.getCheckQty());
                    detail.setLocatorId(locatorId);
                    detail.setSubStatus("1");
                    detail.setStatus("1");
                    if(locatorId != null){
                        detail.setExtParams(MapUtils.put("adjustType","2").put("takeLocatorId",locatorId).getMap());
                    }
                    //移入货位通过商品货位限定查询
                    WaveBillDDO billid = waveBillDMapper.findById(waveStorageDO.getBillDId(), WaveBillDDO.class);
                    LocatorQueryVO vo = new LocatorQueryVO();
                    vo.setRefId(pickTaskD.getPickTaskDId());
                    vo.setEnterpriseId(pickTaskD.getEnterpriseId());
                    String mtlOwnerId = moveSaveVO.getCargoOwnerId();
                    // Step2: 组装查询货位的条件
                    InstockItemInfo info = new InstockItemInfo();
                    Map<String, String> collect = null;
                    String itemId = waveStorageDO.getItemId();
                    String rcvHeaderId = pickTaskD.getPickTaskId();
                    String rcvLineId = pickTaskD.getPickTaskDId();
                    BigDecimal pieceQty = pickTaskD.getQty();
                    BigDecimal conversionRate = billid.getConversionRate();
                    //获取批次信息
                    RestMessage<List<BatchNumberListVO>> batchNumberBasicInfo = invClient.getBatchNumberBasicInfo(new String[]{waveStorageDO.getBatchId()});
                    if(!batchNumberBasicInfo.isSuccess()||batchNumberBasicInfo.getData()==null){
                        throw new BizException("获取批次信息失败");
                    }
                    BatchNumberListVO batchNumberListVO = batchNumberBasicInfo.getData().get(0);
                    String vendorBatchNum = batchNumberListVO.getBatchNum();
                    String manufacturerLotNum = batchNumberListVO.getManufacturerLotNum();
                    String categoryId = billid.getItemCategoryCode();
                    Date batchExpiredDate = batchNumberListVO.getBatchExpiredDate();
                    Date batchProductionDate = batchNumberListVO.getBatchProductionDate();
                    if (ObjectUtils.isNull(batchExpiredDate) || ObjectUtils.isNull(batchProductionDate))
                        throw new ParameterException("请检查自己的批次生产日期和批次有效期!");
                    String productionPlace = batchNumberListVO.getProductionPlace();

                    RestMessage<List<WaveItemInfoVO>> waveItemInfo = itemClient.getWaveItemInfo(Arrays.asList(billid.getItemId()));
                    if(waveItemInfo.getData()==null||!waveItemInfo.isSuccess()){
                        throw new BizException("查询商品信息失败");
                    }
                    List<WaveItemInfoVO> itemData = waveItemInfo.getData();
                    waveItemInfoList.addAll(itemData);
                    WaveItemInfoVO waveItemInfoVO = itemData.stream().filter(t -> t.getItemId().equals(billid.getItemId())).findFirst().orElse(null);
                    String whAreaCategoryCode2 = "";
                    if(billid.getIsCaseOrPiece()==1){
                        if(billid.getOddPieceQty().compareTo(BigDecimal.ZERO)==0&&billid.getTotalPcs()>0){
                            whAreaCategoryCode2 = "ZJK";
                        }
                        if(billid.getOddPieceQty().compareTo(BigDecimal.ZERO)>0&&billid.getTotalPcs()==0){
                            whAreaCategoryCode2 = "LHK";
                        }
                    }else{
                        whAreaCategoryCode2 = "ZJK";
                    }
                    info.setRcvId(rcvHeaderId);
                    info.setRcvLineId(rcvLineId);
                    info.setWarehouseCategoryCode(whAreaCategoryCode2);
                    info.setEnterpriseId(enterpriseId);
                    info.setBatchExpiredDate(batchExpiredDate);
                    info.setBatchProductionDate(batchProductionDate);
                    info.setCargoOwnerId(mtlOwnerId);
                    info.setItemId(itemId);
                    info.setManufacturerLotNum(manufacturerLotNum);
                    info.setProductionPlace(productionPlace);
                    info.setVendorBatchNum(vendorBatchNum);
                    info.setWarehouseId(warehouseId);
                    info.setItemPieceQty(pieceQty);
                    info.setShelfLifeDays(batchNumberListVO.getShelfLifeDays());

                    String storeTempture = "常温";
                    if(waveItemInfoVO!=null){
                        storeTempture = waveItemInfoVO.getStoreTemperature();
                    }
                    info.setStoreTemperature(storeTempture);

                    info.setConversionRate(conversionRate);
                    info.setContainerCode("N/A");
                    info.setItemCategoryCode(categoryId);


                    String batchId = waveStorageDO.getBatchId();

                    // 库存状态
                    info.setStockStatus("1");

                    info.setRcvLineId(rcvLineId);
                    info.setRcvId(rcvHeaderId);
                    info.setBatchId(batchId);
                    Map<String, Object> map = BeanUtil.beanToMap(vo);
                    map.put("itemInfo",BeanUtil.beanToMap(info));
                    //vo.setItemInfo(info);
                    queryVOList.add(map);
                }
                //增加盘点库库存
                RestMessage restMessage = invClient.redAdjustStock(validList);
                RestMessage<Map<String, BaseWmsWarehouseLocator>> recommendLocatoror = null;
                try {
                    logger.info("-------开始调用远程寻货位操作!--入参数:" + JSONObject.toJSONString(queryVOList));
                    recommendLocatoror = controlResource.getRecommendLocatoror(queryVOList);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new BizException(String.format("远程调用库位推荐失败!错误原因->%s", e.getMessage()));
                }
                Map<String, BaseWmsWarehouseLocator> data = null;
                if (!ObjectUtils.isNull(recommendLocatoror) && recommendLocatoror.isSuccess()) {
                    data = recommendLocatoror.getData();
                    if (ObjectUtils.isNull(data))
                        throw new BizException(String.format("推荐数据为空!请重试!"));
                    // 看是否有数据
                    int row = 0;
                    for (Map.Entry<String, BaseWmsWarehouseLocator> entry : data.entrySet()) {
                        row++;
                        BaseWmsWarehouseLocator value = entry.getValue();
                        String key = entry.getKey();
                        if (ObjectUtils.isNull(value)) {
                            logger.info(String.format("第[%d]行数据,来源任务id(上架任务)[%s]的推荐货位为空!", row, key));
                        }
                    }
                    logger.info("-------寻货位成功!");
                    // 需要更新的上架任务
                    for (PickTaskD pickTaskD : pickTaskDList) {
                        List<WaveStorageDO> storageDOS = storageMapper.getStorageByPickTaskDId(pickTaskD.getPickTaskDId());
                        //生成移库单
                        WmsMoveDetailVO x = new WmsMoveDetailVO();
                        x.setOutwarehouseAreaCategory(locatorBasicInfo.getWarehouseAreaCategory());
                        x.setOutContainerCode("N/A");
                        x.setInContainerCode("N/A");
                        x.setBatchId(storageDOS.get(0).getBatchId());
                        x.setItemId(storageDOS.get(0).getItemId());
                        x.setOutLocatorId(locatorId);
                        x.setOutStockStatus("1");
                        x.setInStockStatus("1");

                        WaveItemInfoVO itemInfo = null;
                        Optional<WaveItemInfoVO> itemOptional = waveItemInfoList.stream().filter(item -> x.getItemId().equals(item.getItemId())).findFirst();
                        if (itemOptional.isPresent()) {
                            itemInfo = itemOptional.get();
                            BigDecimal oddPieceQuantity = pickTaskD.getCheckQty().compareTo(BigDecimal.ZERO)==0?pickTaskD.getPickQty():pickTaskD.getCheckQty();
                            BigDecimal[] bigDecimals = oddPieceQuantity.divideAndRemainder(itemInfo.getCaseConversionRate());
                            x.setCaseConversionRate(itemInfo.getCaseConversionRate());
                            x.setCaseQuantity(bigDecimals[0]);
                            x.setUom(itemInfo.getCaseUom());
                            x.setOddPieceQuantity(bigDecimals[1]);
                        }
                        String refId = pickTaskD.getPickTaskDId();
                        BaseWmsWarehouseLocator baseWmsWarehouseLocator = data.get(refId);
                        if (ObjectUtils.isNull(baseWmsWarehouseLocator)){
                            throw new BizException("货位推荐失败");
                        }
                        x.setInLocatorId(baseWmsWarehouseLocator.getWarehouseLocatorId());
                        x.setInwarehouseAreaCategory(baseWmsWarehouseLocator.getWarehouseAreaCategoryCode());
                        moveDetails.add(x);
                    }
                }
                moveSaveVO.setMoveDetails(moveDetails);

                System.out.println(JSONObject.toJSONString(moveSaveVO));
                //调用库内服务生成移库单
                RestMessage<List<ReportData>> moveRestMessage = operateResource.addMoveBackPrint(moveSaveVO);
                if(moveRestMessage.getData()==null||!moveRestMessage.isSuccess() ){
                    throw new BizException("生成移库单失败");
                }
                List<ReportData> reportData = moveRestMessage.getData();
                reportData.stream().forEach(x->{
                    String codes = codesMap.get(srcCode);
                    x.getHead().put("stageCodes",codes);
                });
                moveDatas.addAll(reportData);
            }
        }
        return moveDatas;
    }


    /**
     * 更新状态
     * @param srcCodes
     * @param operatorCode
     * @param warehouseId
     * @param bldgId
     * @param enterpriseId
     * @param employee
     * @return
     */
    @FuncImpl(name = "更新状态", func = BarCodeFunc.updateOuterCheck.class, description = "更新状态")
    public Map<String,List<String>> updateOuterCheck(List<String> srcCodes, String operatorCode, String warehouseId, String bldgId,String enterpriseId,Employee employee){
        Map<String,List<String>> map = new HashMap<>();
        List<String> omsBillIds = new ArrayList<>();
        List<String> billGroupIds = new ArrayList<>();
        Date date = new Date();
        for (String srcCode : srcCodes) {
            List<WaveBillDO> waveBillDOS = billMapper.findByMap(MapUtils.put("srcId", srcCode).put("warehouseId", warehouseId).getMap(), WaveBillDO.class);
            if (CollUtil.isNotEmpty(waveBillDOS)) {
                for (WaveBillDO waveBillDO:waveBillDOS) {
                    List<WaveStorageDO> waveStorageDOList = storageMapper.findByMap(MapUtils.put("waveId", waveBillDO.getWaveId()).getMap(), WaveStorageDO.class);
                    if (CollUtil.isNotEmpty(waveStorageDOList)) {
                        for (WaveStorageDO waveStorageDO:waveStorageDOList) {
                            List<PickTaskD> dList = pickTaskDMapper.findByMap(MapUtils.put("waveStorageId", waveStorageDO.getId()).getMap(),PickTaskD.class);
                            if (CollUtil.isNotEmpty(dList)) {
                                List<String> containerCodeList = dList.stream().map(PickTaskD::getContainerCode).distinct().collect(Collectors.toList());
                                if (CollUtil.isNotEmpty(containerCodeList)) {
                                    // 释放容器
                                    for (String containerCode:containerCodeList) {
                                        ContainerQueryVO containerQueryVO = new ContainerQueryVO();
                                        containerQueryVO.setContainerCode(containerCode);
                                        containerQueryVO.setWarehouseId(warehouseId);
                                        warehouseResource.release(containerQueryVO);
                                    }
                                }
                            }
                        }
                    }
                }
            }

//            List<WaveBillDO> waveBillDOS = billMapper.findByMap(MapUtils.put("srcCode", srcCode).put("warehouseId", warehouseId).getMap(), WaveBillDO.class);
//            if(waveBillDOS == null || waveBillDOS.size() <= 0){
//                throw new BizException("查询波次订单信息失败");
//            }
//            List<WaveBillDDO> waveBillDDOS = billdMapper.findByMap(MapUtils.put("billId", waveBillDOS.get(0).getId()).getMap(), WaveBillDDO.class);
//            if(waveBillDDOS == null || waveBillDDOS.size() <= 0){
//                throw new BizException("查询波次订单明细信息失败");
//            }
//
            List<BarcodeHDO> list = barcodeHMapper.findByMap(MapUtils.put("billGroupId", srcCode).put("enterpriseId", enterpriseId).put("warehouseId", warehouseId).put("bldgId", bldgId).getMap(), BarcodeHDO.class);
            if (list.size() > 0) {
                List<String> barcodeIds = new ArrayList<>();
                for (BarcodeHDO barcodeHDO : list) {
                    barcodeIds.add(barcodeHDO.getId());
                    barcodeHMapper.updateMapById(barcodeHDO.getId(), MapUtils.put("checkStatus", "5").put("checkerId", employee.getUserId()).put("checkerNo", operatorCode).put("checkerName", employee.getLocname()).put("checkTime2", date).getMap(), BarcodeHDO.class);
                    barcodeHMapper.updatePickTaskHStatus(barcodeHDO.getBarcode(), warehouseId, enterpriseId);
                }
                String billGroupId = list.get(0).getBillGroupId();
                //根据合单号srcCode 查询 未外复核确认数量，为 0 条则，根据合单号srcCode 查询 来源单号集合回传erp
                Criteria crt = Criteria.forClass(BarcodeHDO.class);
                Restriction r1 = Restrictions.eq("billGroupId", billGroupId);
                Restriction r2 = Restrictions.or(Restrictions.isnull("checkStatus"), Restrictions.in("checkStatus", new String[]{"0", "1"}));
                Restriction r3 = Restrictions.eq("enterpriseId", enterpriseId);
                Restriction r4 = Restrictions.notIn("id", barcodeIds.toArray(new String[barcodeIds.size()]));
                crt.setRestriction(Restrictions.and(r1, r2, r3, r4));
                long count = barcodeHMapper.findCountByCriteria(crt);
                if (count == 0) {
                    List<String> billIds = barcodeHMapper.getOmsBillIds(billGroupId, enterpriseId);
                    if (billIds.size() > 0) {
                        //@TODO 释放集货区
                        //workStageService.releaseWorkStage(billGroupId);
                        omsBillIds.addAll(billIds);
                        billGroupIds.add(billGroupId);
                    }
                }
                pickTaskHMapper.updateFlowStatus("7", billGroupId, warehouseId);
            }
        }
        map.put("omsBillIds",omsBillIds);
        map.put("billGroupIds",billGroupIds);
        return map;
    }

    /**
     * 外复核-查询已索取任务主表
     *
     * @param warehouseId
     * @param operatorCode
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<WaveBillDODTO> getOuterCheckH(String bldgId, String warehouseId, String operatorCode, String srcCode, String barcode, Integer pageNum, Integer pageSize) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        if(StringUtils.isBlank(operatorCode))
            operatorCode = userDTO.getUserBizModel().getEmployeeNo();
        PageHelper.startPage(pageNum, pageSize);
        List<WaveBillDODTO> list = pickTaskHMapper.getOuterCheckH(srcCode, barcode, bldgId, warehouseId, operatorCode);
        this.setErpSrcCode(list,enterpriseId);
        return PageUtils.getPage(list);
    }

    public void setErpSrcCode(List<WaveBillDODTO> list,String enterpriseId){
        if(list.size()>0){
            for (WaveBillDODTO waveBillDODTO : list) {
                if(waveBillDODTO.getIsMerged() != null && waveBillDODTO.getIsMerged()>0){
                    List<String> billNos = barcodeHMapper.getOmsBillNos(waveBillDODTO.getSrcCode(), enterpriseId);
                    waveBillDODTO.setErpSrcCode(billNos.stream().collect(Collectors.joining(",")));
                }
            }
        }
    }

    /**
     * 外复核-查询待索取任务主表
     *
     * @param type        类型：0/null-外复核 1-自提外复核
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<WaveBillDODTO> getUnOuterCheckH(String barcode,String srcCode,Integer type, String bldgId, String warehouseId, Integer pageNum, Integer pageSize) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(pageNum, pageSize);
        List<WaveBillDODTO> list = pickTaskHMapper.getUnOuterCheckH(barcode,srcCode,type, bldgId, warehouseId, enterpriseId);
        this.setErpSrcCode(list,enterpriseId);
        return PageUtils.getPage(list);
    }

    /**
     * 外复核-查询待索取任务主表或部分冲红任务
     *
     * @param type        类型：0/null-外复核 1-自提外复核
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<WaveBillDODTO> getUnOuterCheckH2(String barcode,String srcCode,Integer type, String bldgId, String warehouseId,String partlyRed,String billtypeGroup, Integer pageNum, Integer pageSize) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(pageNum, pageSize);
//        if(StringUtils.isEmpty(partlyRed)){
//            partlyRed = "0";
//        }
        partlyRed = "";
        List<WaveBillDODTO> list = pickTaskHMapper.getUnOuterCheckH2(barcode,srcCode,type, bldgId, warehouseId,partlyRed,billtypeGroup, enterpriseId);
        this.setErpSrcCode(list,enterpriseId);
        return PageUtils.getPage(list);
    }

    /**
     * 外复核-草单
     *
     * @param bldgId
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<WaveBillDODTO> getOuterCheckHOrder(String srcCode,String bldgId, String warehouseId, Integer pageNum, Integer pageSize) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(pageNum, pageSize);
        List<WaveBillDODTO> list = pickTaskHMapper.getOuterCheckHOrder(srcCode,bldgId, warehouseId, enterpriseId);
        this.setErpSrcCode(list,enterpriseId);
        return PageUtils.getPage(list);
    }

    /**
     * 根据订单号查询条码主表
     *
     * @param srcCode
     * @param warehouseId
     * @param bldgId
     * @return
     */
    @Override
    public List<BarcodeHDO> getBarcodeHList(String srcCode, String warehouseId, String bldgId) {
        AssertUtils.isNotBlank(srcCode, "订单编号不能为空");
        AssertUtils.isNotBlank(warehouseId, "仓id不能为空");
        AssertUtils.isNotBlank(bldgId, "建筑物id不能为空");
        return pickTaskHMapper.getBarcodeHList(srcCode, warehouseId, bldgId);
    }

    /**
     * 外复核-查询商品明细表
     *
     * @param srcCode
     * @return
     */
    @Override
    public List<OuterCheckDDTO> getOuterCheckD(String srcCode, String warehouseId, String bldgId) {
        AssertUtils.isNotBlank(srcCode, "订单编号不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        OmsDoBillHDO byId = omsDoBillHMapper.findById(srcCode, OmsDoBillHDO.class);
        List<OuterCheckDDTO> list = pickTaskHMapper.getOuterCheckD(srcCode,enterpriseId,warehouseId,bldgId);
        for (int i = 0; i < list.size(); i++) {//内复核过来数据，不扫描监管码
            OuterCheckDDTO outerCheckDDTO = list.get(i);
            if(outerCheckDDTO !=null && outerCheckDDTO.getLclNo()!=null && outerCheckDDTO.getLclNo().compareTo(BigDecimal.ZERO)>0){
                outerCheckDDTO.setIsSupervise(0);
            }
            outerCheckDDTO.setShipperId(byId.getShipperid());
        }
        isSupervisePc(list,3);
        //拼装商品明细字段值
        this.packageItem(list);
        return list;
    }

    /**
     * 自提出库外复核-复核确认
     *
     * @param vo
     */
    @Override
    @Transactional
    @TxTransaction
    public void outerCheckConfirmSelf(OuterCheckPickUpVO vo) {
        if (StringUtils.isBlank(vo.getSrcCode()))
            throw new ParameterException("订单号不能为空！");
        if (StringUtils.isBlank(vo.getOperatorCode()))
            throw new ParameterException("员工号不能为空！");
        if (StringUtils.isBlank(vo.getPhotoId()))
            throw new ParameterException("照片id不能为空！");
        if (StringUtils.isBlank(vo.getShipperCard()))
            throw new ParameterException("身份证号不能为空！");
        String srcCode = vo.getSrcCode();
        List<OmsDoBillHDO> omsDoBillHDOList =omsDoBillHMapper.findByMap(MapUtils.put("billno",srcCode).put("branchid",vo.getWarehouseId()).getMap(),OmsDoBillHDO.class);
        if(omsDoBillHDOList.size()>0 && !StringUtils.isBlank(omsDoBillHDOList.get(0).getAttrStr6())){
            if(omsDoBillHDOList.get(0).getAttrStr6().indexOf(vo.getShipperCard())<0)
                throw new ParameterException("收货人身份证号码不正确!");
        }else{
            throw new ParameterException("订单信息-收货人身份证号码为空!");
        }
        UserDTO userDTO = userTemplate.getUserDTO();
        String operatorId = userDTO.getId();
        String operatorCode = vo.getOperatorCode();
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        String enterpriseId = userDTO.getEnterpriseId();
        String point = "2";
        //业务参数配置/出库回传ERP节点 1:内复核回传  2:外复核回传
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"OUT_BACK_ERP_POINT"}, vo.getWarehouseId(), null, enterpriseId, null);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> result = restMessage.getData();
            if (result.containsKey("OUT_BACK_ERP_POINT")) {
                point = String.valueOf(result.get("OUT_BACK_ERP_POINT").getRegValue());
            }else {
                throw new BizException("出库回传ERP节点未配置");
            }
        }
        try {
            Date date = new Date();
            List<BarcodeHDO> list = barcodeHMapper.findByMap(MapUtils.put("billGroupId", srcCode).put("checkStatus", "0").put("enterpriseId", enterpriseId).put("warehouseId", vo.getWarehouseId()).put("bldgId", vo.getBldgId()).getMap(), BarcodeHDO.class);
            if (list.size() > 0) {
                List<String> barcodeIds = new ArrayList<>();
                for (BarcodeHDO barcodeHDO : list) {
                    barcodeIds.add(barcodeHDO.getId());
                    barcodeHMapper.updateMapById(barcodeHDO.getId(), MapUtils.put("checkStatus", "5").put("checkerId", operatorId).put("checkerNo", operatorCode).put("checkerName", operatorName).put("checkTime", date).put("checkTime2", date).getMap(), BarcodeHDO.class);
                    barcodeHMapper.updatePickTaskHStatus(barcodeHDO.getBarcode(), vo.getWarehouseId(), enterpriseId);
                }
                PickUpRecord pickUpRecord = new PickUpRecord();
                pickUpRecord.setBldgId(vo.getBldgId());
                pickUpRecord.setBldgName(list.get(0).getBldgName());
                pickUpRecord.setWarehouseId(vo.getWarehouseId());
                pickUpRecord.setEnterpriseId(enterpriseId);
                pickUpRecord.setShipperName(vo.getShipperName());
                pickUpRecord.setShipperCard(vo.getShipperCard());
                pickUpRecord.setPickUpDate(vo.getPickUpDate());
                pickUpRecord.setPhotoId(vo.getPhotoId());
                pickUpRecord.setSrcCode(vo.getSrcCode());
                pickUpRecord.setRemarks(vo.getRemarks());
                pickUpRecord.setStatus("0");
                pickUpRecord.setCreator(operatorId);
                pickUpRecord.setCreatorName(operatorName);
                pickUpRecord.setGmtCreate(date);
                pickUpRecordMapper.save(pickUpRecord);

                List<String> srcCodes = new ArrayList<>();
                srcCodes.add(srcCode);
                //根据合单号srcCode 查询 未外复核确认数量，为 0 条则，根据合单号srcCode 查询 来源单号集合回传erp
                Criteria crt = Criteria.forClass(BarcodeHDO.class);
                Restriction r1 = Restrictions.eq("billGroupId", srcCode);
                Restriction r2 = Restrictions.or(Restrictions.isnull("checkStatus"), Restrictions.in("checkStatus", new String[]{"0", "1"}));
                Restriction r3 = Restrictions.eq("enterpriseId", enterpriseId);
                Restriction r4 = Restrictions.notIn("id", barcodeIds.toArray(new String[barcodeIds.size()]));
                crt.setRestriction(Restrictions.and(r1, r2, r3, r4));
                long count = barcodeHMapper.findCountByCriteria(crt);
                if (count == 0) {
                    List<String> billIds = barcodeHMapper.getOmsBillIds(srcCode, enterpriseId);
                    if (billIds.size() > 0) {
                        //@TODO 释放集货区
                        workStageService.releaseWorkStage(srcCode);
                        invStockConfirm.invStockConfirm(srcCodes, billIds,vo.getWarehouseId());
                    }
                }
                pickTaskHMapper.updateFlowStatus("7",srcCode,vo.getWarehouseId());
            } else {
                throw new BizException("未找到对应提货数据");
            }
        } catch (Exception e) {
            throw new BizException("执行失败!"+e.getMessage());
        }
    }

    /**
     * 打印外复核草单
     *
     * @param srcCodes
     * @param warehouseId
     * @return
     */
    @Override
    @Transactional
    public List<PrintData> printOuterPaperSlip(List<String> srcCodes, String warehouseId, String warehouseName) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        List<PrintData> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (String srcCode : srcCodes) {
            List<OuterCheckItemDTO> list = pickTaskHMapper.getOuterCheckItem(srcCode, warehouseId, enterpriseId);
            if (list.size() > 0) {
                Map<String, Object> head = new HashMap<>();
                List<Map<String, Object>> tables = new ArrayList<>();
                ReportData reportData = new ReportData();
                BigDecimal uomQty = BigDecimal.ZERO;
                BigDecimal totalQty = BigDecimal.ZERO;
                int i = 1;
                List<OuterCheckItemDTO> collect1 = list.stream().filter(x -> x.getType().equals("1")).collect(toList());
                for (OuterCheckItemDTO itemDTO : collect1) {
                    itemDTO.setNum(i);
                    uomQty = uomQty.add(itemDTO.getUomQty()!=null?itemDTO.getUomQty():BigDecimal.ZERO);
                    totalQty = totalQty.add(itemDTO.getQty()!=null?itemDTO.getQty():BigDecimal.ZERO);
                    if (itemDTO.getUom() == null)
                        itemDTO.setUom("");
                    if (itemDTO.getManufacturerLotNum() == null)
                        itemDTO.setManufacturerLotNum("");
                    if (itemDTO.getWarehouseName() == null && warehouseName!=null)
                        itemDTO.setWarehouseName(warehouseName);
                    if (itemDTO.getLclNo() == null) {
                        itemDTO.setLclNo("-");
                    }
                    Map beanMap = JSON.parseObject(JSON.toJSONString(itemDTO),Map.class);
                    tables.add(beanMap);
                    i++;
                }
                reportData.setTable(tables);
                OuterCheckHeadDTO dto = pickTaskHMapper.getOuterCheckHead(srcCode, warehouseId, enterpriseId);
                List<WorkStageRuntimeDO> byMap = workStageRuntimeMapper.findByMap(MapUtils.put("billGroupId", srcCode).put("enterpriseId", enterpriseId).getMap(), WorkStageRuntimeDO.class);
                head.put("stageCode","");   //暂存区
                if(byMap.size()>0){
                    List<String> collect = byMap.stream().map(x -> x.getStageCode()).collect(Collectors.toList());
                    head.put("stageCode",String.join(",",collect));
                }
                Map<String, List<OuterCheckItemDTO>> itemsKey = list.stream().filter(x -> !StringUtils.isEmpty(x.getBarcodeDId())).collect(groupingBy(OuterCheckItemDTO::getBarcodeDId));
                Set<String> keys = itemsKey.keySet();
                BigDecimal totalOddQty =new BigDecimal(String.valueOf(keys.size()));
                head.put("count",1);
                head.put("total",1);
                head.put("totalCaseQty", uomQty);
                head.put("totalOddQty", totalOddQty); //零货拼箱整合
                totalQty = uomQty.add(totalOddQty);
                head.put("totalQty", totalQty);
                head.put("customerAddress", dto.getCustomerAddress());
                head.put("pickWay", dto.getArrivalMode());
                head.put("fhUser", dto.getCreateby());
                head.put("paymentType", dto.getPaymentType());
                head.put("fpBillNo", dto.getBillGroupId());
                head.put("branchcode",dto.getBranchcode());
                head.put("branchname",dto.getBranchname());
                switch (dto.getBillType()) {
                    case "1":
                        head.put("billType", "销售出库");
                        break;
                    case "2":
                        head.put("billType", "采购退货");
                        break;
                    case "3":
                        head.put("billType", "调拨出库");
                        break;
                    case "4":
                        head.put("billType", "移库出库");
                        break;
                    case "5":
                        head.put("billType", "调账出库");
                        break;
                    case "6":
                        head.put("billType", "越库出库");
                        break;
                    case "7":
                        head.put("billType", "直调出库");
                        break;
                    case "8":
                        head.put("billType", "代管出库");
                        break;
                    case "9":
                        head.put("billType", "待检出库");
                        break;
                    default:
                        head.put("billType", "正常销售");
                }
                if (StringUtils.isBlank(dto.getCarrierName())) {
                    head.put("carrier", "");
                } else {
                    head.put("carrier", dto.getCarrierName());
                }
                head.put("cargoOwner", dto.getConsignorName());
                head.put("customer", dto.getShipperName());
                head.put("customerCode",dto.getShipperCode());
                head.put("drawer", dto.getCreateby());
                List<String> billIds = barcodeHMapper.getOmsBillIds(srcCode, enterpriseId);

                List<BarcodeHDO> billGroupId = barcodeHMapper.findByMap(MapUtils.put("billGroupId", srcCode).getMap(), BarcodeHDO.class);
                head.put("lclNo","");
                String shipBillNo = dto.getShipBillNo();
                head.put("shipBillNo",StringUtils.isEmpty(dto.getShipBillNo())?"":dto.getShipBillNo().substring(shipBillNo.length()-4,shipBillNo.length())); //货号：运单号后4位
                if(billGroupId.size()>0){
                    List<String> collect = billGroupId.stream().map(x -> x.getLclNo()!=null?x.getLclNo().toString():"").collect(toList());
                    head.put("lclNo",String.join(",",collect));
                }
                head.put("erpBillNo", billIds.stream().collect(Collectors.joining(",")));

                head.put("bizUser", dto.getSalespersonName());//业务员
                if (dto.getSaleBranchname() != null) {
                    head.put("orgName", dto.getSaleBranchname());
                } else {
                    head.put("orgName", "");
                }
                head.put("remark",dto.getRemark());
                head.put("custPerson",dto.getCustPerson());
                head.put("custPersonTel",dto.getCustPersonTel());
                head.put("createdate",sdf.format(dto.getCreatedate()!=null?dto.getCreatedate():new Date()));
                head.put("createBy",userDTO.getNickname());
                reportData.setHead(head);
                reportDatas.add(reportData);
            }
        }
        printData.setData(reportDatas);
        printDataList.add(printData);
        return printDataList;
    }

    /**
     * 打印外复核报告单
     *
     * @param srcCodes
     * @param warehouseId
     * @return
     */
    @Override
    @Transactional
    public List<PrintData> printReportPaperSlip(List<String> srcCodes, String warehouseId, String warehouseName,List<String> itemLots) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        List<PrintData> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (String srcCode : srcCodes) {
            List<OuterCheckItemDTO> list = pickTaskHMapper.getOuterCheckItem(srcCode, warehouseId, enterpriseId);
            if (list.size() > 0) {
                //根据商品批号分组
                Map<String, List<OuterCheckItemDTO>> collect1 = list.stream().collect(Collectors.groupingBy(OuterCheckItemDTO::getItemLot));
                OuterCheckHeadDTO dto = pickTaskHMapper.getOuterCheckHead(srcCode, warehouseId, enterpriseId);
                Set<Map.Entry<String, List<OuterCheckItemDTO>>> entries = collect1.entrySet();
                for (Map.Entry<String, List<OuterCheckItemDTO>> entry : entries) {
                    String itemLot = entry.getKey();
                    if(itemLots.size()>0){
                        if(!itemLots.contains(itemLot)){
                            continue;
                        }
                    }
                    //根据商品批号级别去查询报告单图片
                    List<OuterCheckItemDTO> value = entry.getValue();
                    for (OuterCheckItemDTO outerCheckItemDTO : value) {
                        BaseBizFileQueryVO queryVO = new BaseBizFileQueryVO();
                        queryVO.setBizId(itemLot);
                        queryVO.setCode(outerCheckItemDTO.getItemId());
                        queryVO.setName(outerCheckItemDTO.getManufacturerLotNum()!=null?value.get(0).getManufacturerLotNum():"");
                        RestMessage<List<BaseBizFile>> all = commonClient.findAll(queryVO.getBizId(),queryVO.getCode(),queryVO.getName());
                        if(all.isSuccess()&&all.getData()!=null){
                            List<BaseBizFile> data = all.getData();
                            for (BaseBizFile file : data) {
                                Map<String, Object> head = new HashMap<>();
                                List<Map<String, Object>> tables = new ArrayList<>();
                                ReportData reportData = new ReportData();
                                head.put("lotNo","");
                                if(value.size()>0){
                                    head.put("lotNo",value.get(0).getManufacturerLotNum()!=null?value.get(0).getManufacturerLotNum():"");
                                }
                                head.put("fpBillNo", dto.getBillGroupId());
                                head.put("customer", dto.getShipperName());
                                head.put("fileUrl",file.getFileUrl());
                                reportData.setHead(head);
                                reportData.setTable(tables);
                                reportDatas.add(reportData);
                            }
                        }
                    }
                }
            }
        }
        printData.setData(reportDatas);
        printDataList.add(printData);
        return printDataList;
    }

    /**
     * 打印外复核出库清单，特殊订单
     *
     * @param srcCodes
     * @param warehouseId
     * @return
     */
    @Override
    @Transactional
    public List<PrintData> printDeliveryOuter(List<String> srcCodes, String warehouseId, String warehouseName) {
        List<PrintData> printDataList = new ArrayList<>();
        List<ReportData> reportDatas = new ArrayList<>();
        //出库清单
        PrintData printData1 = new PrintData();
        List<ReportData> reportDatas1 = new ArrayList<>();
        //特殊订单
        PrintData printData2 = new PrintData();
        List<ReportData> reportDatas2 = new ArrayList<>();
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        printData1.setPrintName("");
        printData2.setPrintName("");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (String srcCode : srcCodes) {
            List<OuterCheckItemDTO> list = pickTaskHMapper.getDeliveryOuterItemH(srcCode, warehouseId, enterpriseId);
            Set<String> collect = list.stream().map(x -> x.getItemId()).collect(Collectors.toSet());
            RestMessage<List<BaseMtlItemMst>> listByIds = itemClient.getListByIds(collect);
            if(!listByIds.isSuccess()||listByIds.getData()==null){
                throw new BizException("商品信息查询失败");
            }
            List<BaseMtlItemMst> itemMstList = listByIds.getData();
            if(list.size()>0){
                Map<String, Object> head = new HashMap<>();
                List<Map<String, Object>> tables = new ArrayList<>();
                ReportData reportData = new ReportData();
                BigDecimal totalPrice = BigDecimal.ZERO;
                for (OuterCheckItemDTO itemDTO : list) {
                    totalPrice = totalPrice.add(itemDTO.getPayamount()!=null?itemDTO.getPayamount():BigDecimal.ZERO);
                    if (itemDTO.getUom() == null)
                        itemDTO.setUom("");
                    if (itemDTO.getWarehouseName() == null && warehouseName!=null)
                        itemDTO.setWarehouseName(warehouseName);
                    if (itemDTO.getManufacturerLotNum() == null)
                        itemDTO.setManufacturerLotNum("");
                    if (itemDTO.getLclNo() == null) {
                        itemDTO.setLclNo("-");
                    }
                    BaseMtlItemMst itemMst = itemMstList.stream().filter(x -> x.getItemId().equals(itemDTO.getItemId())).findFirst().orElse(null);
                    Map beanMap = JSON.parseObject(JSON.toJSONString(itemDTO),Map.class);
                    if(itemMst!=null){
                        beanMap.put("registNo",itemMst.getBaseMtlItemHealth().getItemHealthRegisterNbr());
                        beanMap.put("approvalNumber",itemMst.getBaseMtlItemHealth().getItemHealthApprovalNbr());
                        beanMap.put("storeTemperature",itemMst.getBaseMtlItemWms().getStoreTemperature());
                    }
                    tables.add(beanMap);
                }
                reportData.setTable(tables);
                List<OuterCheckHeadDTO> dtoList = pickTaskHMapper.getDeliveryOuterHeadH(srcCode, warehouseId, enterpriseId);
                OuterCheckHeadDTO dto = dtoList.get(0);
                if(!StringUtils.isEmpty(dto.getShipBillNo())){
                    String shipBillNo = dto.getShipBillNo();
                    dto.setShipBillNo(StringUtils.isEmpty(shipBillNo)?"":shipBillNo.substring(shipBillNo.length()-3,shipBillNo.length()));
                }
                head = JSON.parseObject(JSON.toJSONString(dto),Map.class);
                head.put("totalPrice",totalPrice);
                head.put("remarkNo","");
                head.put("refBillno",dto.getBillGroupId());
                head.put("fare","");
                head.put("createdate",DateUtils.format(dto.getCreatedate(),"yyyy-MM-dd"));
                reportData.setHead(head);
                reportDatas.add(reportData);
            }
        }
        if(reportDatas.size()>0){
            String[] billTypes = reportDatas.stream().map(x -> x.getHead().get("billType")).distinct().toArray(String[]::new);
            RestMessage<List<BaseCommonDict>> doBillType = commonClient.getDictBasicListByCodes("do_bill_type", billTypes);
            if(!doBillType.isSuccess()||doBillType.getData()==null){
                throw new BizException("获取单据类型信息失败");
            }
            List<BaseCommonDict> commonDicts = doBillType.getData();
            reportDatas.stream().forEach(x->{
                String billType = x.getHead().get("billType").toString();
                BaseCommonDict baseCommonDict = commonDicts.stream().filter(d -> d.getDictCode().equals(billType)).findFirst().orElse(null);
                if(!StringUtils.isEmpty(baseCommonDict.getAttr1())){
                    if(baseCommonDict.getAttr1().equals("1")){
                        reportDatas1.add(x);
                    }
                    if(baseCommonDict.getAttr1().equals("2")){
                        reportDatas2.add(x);
                    }
                }else{
                    reportDatas1.add(x);
                }
                int size = x.getTable().size();
                x.getHead().put("count",Math.floor(size/4)+1);
                x.getHead().put("total",Math.floor(size/4)+1);
            });
        }
        if(reportDatas1.size()>0){
            printData1.setData(reportDatas1);
            printData1.setTempType("出库清单");
            printDataList.add(printData1);
        }
        if(reportDatas2.size()>0){
            printData2.setData(reportDatas2);
            printData2.setTempType("特殊出库单");
            printDataList.add(printData2);
        }
        return printDataList;
    }

    /**
     * 打印外复核单
     *
     * @param srcCodes
     * @param warehouseId
     * @return
     */
    @Flow(name = "打印", category = "出库/复核管理/外复核/打印", index = 0, description = "打印")
    @Override
    @Transactional
    public List<PrintData> printOuterPaperSlipH(List<String> srcCodes, String warehouseId,String warehouseName) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        List<PrintData> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        for (String srcCode : srcCodes) {
            List<OuterCheckItemDTO> list = pickTaskHMapper.getOuterCheckItemH(srcCode, warehouseId, enterpriseId);
            if (list.size() > 0) {
                Map<String, Object> head = new HashMap<>();
                List<Map<String, Object>> tables = new ArrayList<>();
                ReportData reportData = new ReportData();
                BigDecimal uomQty = BigDecimal.ZERO;
                BigDecimal pxQty = BigDecimal.ZERO;
                int i = 1;
                for (OuterCheckItemDTO itemDTO : list) {
                    itemDTO.setNum(i);
                    uomQty = uomQty.add(itemDTO.getUomQty());
                    if (itemDTO.getUom() == null)
                        itemDTO.setUom("");
                    if (itemDTO.getWarehouseName() == null && warehouseName!=null)
                        itemDTO.setWarehouseName(warehouseName);
                    if (itemDTO.getManufacturerLotNum() == null)
                        itemDTO.setManufacturerLotNum("");
                    if (itemDTO.getLclNo() == null) {
                        itemDTO.setLclNo("-");
                    } else {
                        BigDecimal lclNo = new BigDecimal(itemDTO.getLclNo());
                        if (lclNo.compareTo(pxQty) > 0)
                            pxQty = lclNo;
                    }
                    BeanMap beanMap = BeanMap.create(itemDTO);
                    tables.add(beanMap);
                    i++;
                }
                reportData.setTable(tables);
                List<OuterCheckHeadDTO> dtoList = pickTaskHMapper.getOuterCheckHeadH(srcCode, warehouseId, enterpriseId);
                OuterCheckHeadDTO dto = dtoList.get(0);
                head.put("zxQty", uomQty);//整箱合计
                head.put("pxQty", pxQty);//拼箱合计
                head.put("totalCaseQty", uomQty.add(pxQty));//总箱数
                head.put("customerAddress", dto.getCustomerAddress());
                head.put("pickWay", dto.getArrivalMode());
                if (dto.getCheckerName() != null) {
                    head.put("fhUser", dto.getCheckerName());
                } else {
                    head.put("fhUser", "");
                }
                head.put("route", dto.getLineName());
                switch (dto.getBillType()) {
                    case "1":
                        head.put("billType", "销售出库");
                        break;
                    case "2":
                        head.put("billType", "采购退货");
                        break;
                    case "3":
                        head.put("billType", "调拨出库");
                        break;
                    case "4":
                        head.put("billType", "移库出库");
                        break;
                    case "5":
                        head.put("billType", "调账出库");
                        break;
                    case "6":
                        head.put("billType", "越库出库");
                        break;
                    case "7":
                        head.put("billType", "直调出库");
                        break;
                    case "8":
                        head.put("billType", "代管出库");
                        break;
                    case "9":
                        head.put("billType", "待检出库");
                        break;
                    default:
                        head.put("billType", "正常销售");
                }
                head.put("area", String.format("%s---%s", dto.getStageCodeMin(), dto.getStageCodeMax()));
                head.put("fpBillNo", dto.getBillGroupId());
                if (StringUtils.isBlank(dto.getCarrierName())) {
                    head.put("carrier", "");
                } else {
                    head.put("carrier", dto.getCarrierName());
                }
                head.put("paymentType", dto.getPaymentType());
                head.put("cargoOwner", dto.getConsignorName());
                head.put("customer", dto.getShipperName());
                head.put("drawer", dto.getCreateby());
                List<String> billNos = barcodeHMapper.getOmsBillNos(srcCode, enterpriseId);
                head.put("erpBillNo", billNos.stream().collect(Collectors.joining(",")));
                head.put("bizUser", dto.getSalespersonName());//业务员
                if (dto.getSaleBranchname() != null) {
                    head.put("orgName", dto.getSaleBranchname());
                } else {
                    head.put("orgName", "");
                }
                reportData.setHead(head);
                reportDatas.add(reportData);
            }
        }
        printData.setData(reportDatas);
        printDataList.add(printData);
        return printDataList;
    }

    private void isSupervisePc(List<? extends IsSuperviseDTO> list, int stage) {
        if(list==null || list.size()==0){
            return;
        }
        try {
            RestMessage<List<? extends IsSuperviseDTO>> rest=inBoundClient.isSupervise(list,stage);//阶段：0=入库质检 1=PC拣货 2=PC内复核 3=PC外复核 4=补录 5=PDA拣货 6=PDA内复核 7=PDA外复核
            if (rest.isSuccess() && rest.getData()!=null && rest.getData().size()==list.size()){
                for (int i = 0; i < rest.getData().size(); i++) {
                    BeanUtils.copyProperties(rest.getData().get(i), list.get(i));
                }
            }
        } catch (Exception e) {
            log.error("调用监管码接口异常",e);
        }
    }

    //拼装商品明细字段值
    public void packageItem(List<OuterCheckDDTO> list){
        if(list.size()>0){
            ItemMstQueryVO vo = new ItemMstQueryVO();
            Set<String> itemIds = new HashSet<>();
            for (OuterCheckDDTO outerCheckDDTO : list) {
                itemIds.add(outerCheckDDTO.getItemId());
            }
            vo.setItemIds(itemIds);
            RestMessage<Page<ItemMstVO2>> restMessage = itemClient.pagebyRelated(vo);
            if(!restMessage.isSuccess())
                throw new PrologException("调用查询商品接口出错！"+restMessage.getMessage());
            List<ItemMstVO2> itemList = restMessage.getData().getList();
            if(itemList.size()>0) {
                Map<String, ItemMstVO2> map = new HashMap<>();
                map = itemList.stream().collect(Collectors.toMap(ItemMstVO2::getItemId, a -> a, (key1, key2) -> key1));
                for (OuterCheckDDTO outerCheckDDTO : list) {
                    if(map.containsKey(outerCheckDDTO.getItemId())) {
                        ItemMstVO2 item = map.get(outerCheckDDTO.getItemId());
                        outerCheckDDTO.setItemHealthIsDouble(item.getItemHealthIsDouble());
                        outerCheckDDTO.setItemHealthApprovalNbr(item.getItemHealthApprovalNbr());
                        outerCheckDDTO.setIsCaseOrPiece(item.getIsCaseOrPiece());
                        outerCheckDDTO.setItemHealthSuperviseflag(item.getItemHealthSuperviseflag());
                        outerCheckDDTO.setIsBacteria(item.getIsBacteria());
                        outerCheckDDTO.setIsDelegate(item.getIsDelegate());
                        outerCheckDDTO.setIsHosted(item.getIsHosted());
                        outerCheckDDTO.setItemHealthCategoryCode(item.getItemHealthCategoryCode());
                        outerCheckDDTO.setManufacturerName(item.getManufacturerName());
                        outerCheckDDTO.setItemHealthListedLicensor(item.getItemHealthListedLicensor());
                        outerCheckDDTO.setItemHealthProduceLicense(item.getItemHealthProduceLicense());
                        outerCheckDDTO.setItemHealthRegisterNbr(item.getItemHealthRegisterNbr());
                        outerCheckDDTO.setItemHealthRecordNbr(item.getItemHealthRecordNbr());
                        outerCheckDDTO.setVolume(item.getVolume());
                        outerCheckDDTO.setWeight(item.getWeight());
                    }
                }
            }
        }
    }

    /**
     * 扣减库存,并回传ERP
     * @param srcCodes
     * @param omsBillIds
     * @param warehouseId
     */
    @Transactional
    @FuncImpl(name = "扣减库存,并回传ERP", func = BarCodeFunc.invStockConfirm.class, description = "扣减库存,并回传ERP")
    public void invStockConfirm(List<String> srcCodes,List<String> omsBillIds, String warehouseId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String point = "2";
        //业务参数配置/出库回传ERP节点 1:内复核回传  2:外复核回传
        RestMessage<Map<String, BusinessControl>> restMessageCode = strategyResource.getControlByCodes(new String[]{"OUT_BACK_ERP_POINT"}, warehouseId, null, enterpriseId, null);
        if (restMessageCode.isSuccess() && restMessageCode.getData() != null) {
            Map<String, BusinessControl> result = restMessageCode.getData();
            if (result.containsKey("OUT_BACK_ERP_POINT")) {
                point = String.valueOf(result.get("OUT_BACK_ERP_POINT").getRegValue());
            }else {
                throw new BizException("出库回传ERP节点未配置");
            }
        }
        if(point.equals("2")){
            //@TODO 扣减库存
            log.info("开始扣减库存");
//            InvStockCheckOut invStockCheck = new InvStockCheckOut();
//            List<String> billdIdList = billMapper.getBillDIdList(srcCodes,null,warehouseId);
//            if(billdIdList.size()>0){
//                invStockCheck.setLineBillIds(billdIdList.toArray(new String[billdIdList.size()]));
//                RestMessage restMessage = invClient.outStockCheck(invStockCheck);
//                if (!restMessage.isSuccess()) {
//                    throw new BizException("扣减库存失败: " + restMessage.getMessage()+
//                            String.format("，入参为：[仓库：%s][订单编号：%s]", warehouseId,srcCodes.toString()));
//                }
//                log.info("扣减库存成功");
//            }
            //回传ERP
            logger.info("出库回传参数：{}",srcCodes);
            List<String> omsBillIdDbs = new ArrayList<>();
            for (String srcCode : srcCodes) {
                List<String> billIds = barcodeHMapper.getOmsBillIds(srcCode, enterpriseId);
                if (billIds.size() > 0) {
                    //@TODO 释放集货区
                    //workStageService.releaseWorkStage(srcCode);
                    omsBillIdDbs.addAll(billIds);
                }
            }
            postBackErpByTable(omsBillIdDbs);
        }else{
            //回传拼箱数据到oms(改为定时任务回传)
            //postBackErpService.postBackOmsPackingData(srcCodes);
        }
        //回传ERP
        // pickTaskService.saveOutcomingRecord(omsBillIds);

        // 外复核需要判断两个业务配置参数
//        IStrategyHandle strategyHandle = strategySelector.selectHandle(Arrays.asList(
//          STRATEGY_CODE.POST_BACK_ERP__IN_CHECK__ON,
//          STRATEGY_CODE.POST_BACK_ERP__MQ__ON), warehouseId, "out");
//        strategyHandle.execute(omsBillIds, "外复核 回传ERP，rabbitmq发送消息失败！", srcCodes, warehouseId);
    }

    public void postBackErpByTable(List<String> omsBillIds) {
        log.info("出库回传erp参数：{}",omsBillIds);
        if (ObjectUtils.isNull(omsBillIds)) {
            log.warn("回传ERP传入OmsBillId列表为空");
            return;
//            throw new ParameterException("回传ERP需传入OmsBillId列表");
        }
        String[] ids = omsBillIds.toArray(new String[omsBillIds.size()]);
        Criteria crtH = Criteria.forClass(OutcomingRecordH.class);
        Criteria crtD = Criteria.forClass(OutcomingRecordD.class);
        crtH.setRestriction(Restrictions.in("billid", ids));
        crtD.setRestriction(Restrictions.in("billid", ids));
        outcomingRecordHMapper.deleteByCriteria(crtH);
        outcomingRecordDMapper.deleteByCriteria(crtD);
        for (String omsBillId : omsBillIds) {
            List<OutcomingRecordH> listH = outcomingRecordHMapper.getH(omsBillId);
            if (listH.size() > 0) {
                outcomingRecordHMapper.saveBatch(listH);
            }
            List<OutcomingRecordD> listD = outcomingRecordHMapper.getD(omsBillId);
            if (CollUtil.isNotEmpty(listD)) {
                List<String> lineIds = listD.stream().map(OutcomingRecordD::getLineId).distinct().collect(Collectors.toList());
                List<OutcomingRecordD> saveRecordDList = new ArrayList<>();
                if (lineIds.size() > 0) {
                    for (String lineId:lineIds) {
                        // 先找批号不为空的
                        OutcomingRecordD outcomingRecordD = listD.stream().filter(d -> d.getLineId().equals(lineId) && !StringUtils.isBlank(d.getLotNo())).findFirst().orElse(null);
                        if (null == outcomingRecordD) {
                            OutcomingRecordD recordD = listD.stream().filter(d -> d.getLineId().equals(lineId)).findFirst().orElse(null);
                            saveRecordDList.add(recordD);
                        } else {
                            saveRecordDList.add(outcomingRecordD);
                        }
                    }
                }
                if (CollUtil.isNotEmpty(saveRecordDList)) {
                    outcomingRecordDMapper.saveBatch(saveRecordDList);
                }
            }
            // 根据billId回传状态至OMS
            orderOutboundStatusBackService.sendOutboundOrderStatusOms(omsBillId, "", "", "", "", "60", BigDecimal.ZERO);
        }
        // 调用接口平台回传OMS
        try {
            if (StringUtils.isEmpty(outComingRecordBack)) {
                throw new BizException("请求路径配置为空");
            }
            String url = outComingRecordBack;
            log.info("调用OMS接口URL:{}", JSONUtil.toJsonStr(url));
            List<OutcomingRecordHDto> backList = pickTaskServiceImpl.queryOutboundDataToOms(omsBillIds);
            log.info("调用OMS接口入参:{}", JSONUtil.toJsonStr(backList));
            String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
            JSONObject parse = JSONObject.parseObject(result);
            log.info("调用OMS接口返回参数:{}",parse);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 外复核确认后回写ERP中间库
     * @param srcCodes 确认行
     * @param warehouseId
     * @param enterpriseId
     */
    public void reportToErp(List<String> srcCodes, String warehouseId, String enterpriseId){
        List<Map<String, Object>> toErpParams = new ArrayList<>();
        //通过srcCode查询oms订单信息并进行回传
        List<OmsDoBillHDO> billHDOS = barcodeHMapper.listOmsBill(srcCodes, enterpriseId, warehouseId);
        for (OmsDoBillHDO hdo : billHDOS) {
            if (CollUtil.isNotEmpty(hdo.getOmsDoBillDDOList())) {
                List<OmsDoBillDDO> billDDOS = hdo.getOmsDoBillDDOList();
                for (OmsDoBillDDO ddo : billDDOS) {
                    //通过订单明细行id查询波次订单
                    List<WaveBillDDO> waveBillDOList = billdMapper.findByMap(Collections.singletonMap("srcLineId", ddo.getLineid()), WaveBillDDO.class);
                    if (CollUtil.isEmpty(waveBillDOList)){
                        continue;
                    }
                    for (WaveBillDDO waveBillDDO : waveBillDOList) {
                        Map<String, Object> toErpParam = new HashMap<>();
                        toErpParam.put("djbh", hdo.getRefBillid());
                        toErpParam.put("dwid", hdo.getAttrStr1());
                        toErpParam.put("rq", hdo.getAttrDte1());
                        toErpParam.put("ry_ywy", hdo.getSalespersonName());
                        toErpParam.put("thfs", hdo.getArrivalMode());
                        toErpParam.put("khbz", hdo.getCusRemark());
                        toErpParam.put("ddlx", hdo.getRefBilltype());
                        toErpParam.put("yzid", hdo.getAttrStr2());
                        toErpParam.put("dj_sort", ddo.getSeqno());
                        toErpParam.put("spid", ddo.getItemid());
                        toErpParam.put("is_end", "否");
                        toErpParam.put("djz", "");
                        toErpParam.put("sl", waveBillDDO.getPieceQty());
                        toErpParam.put("js", waveBillDDO.getUomQty());
                        toErpParam.put("lss", waveBillDDO.getOddPieceQty());
                        toErpParam.put("ph", waveBillDDO.getManufacturerLotNum());
                        toErpParams.add(toErpParam);
                    }
                }
            }
        }
        JSONObject object = integrationUtil.askIntegration("/siyuan/v1/outbound/dobill/outreport", Collections.singletonMap("list", toErpParams));
        if (!object.getString("success").equals("true")){
            throw new BizException("回写失败！");
        }
    }

}
