package com.hw.wms.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.hw.common.core.constant.MesConstants;
import com.hw.common.core.constant.SecurityConstants;
import com.hw.common.core.constant.WmsConstants;
import com.hw.common.core.domain.R;
import com.hw.common.core.exception.ServiceException;
import com.hw.common.core.utils.StringUtils;
import com.hw.common.core.utils.uuid.Seq;
import com.hw.common.security.utils.SecurityUtils;
import com.hw.mes.api.RemoteMesService;
import com.hw.mes.api.domain.MesBaseBarcodeInfo;
import com.hw.mes.api.domain.MesBaseMaterialInfo;
import com.hw.mes.api.domain.vo.MesBaseMaterialInfoVo;
import com.hw.wms.config.WmsConfig;
import com.hw.wms.domain.*;
import com.hw.wms.domain.vo.*;
import com.hw.wms.mapper.*;
import com.hw.wms.service.IWmsRawOutstockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 原材料出库记录Service业务层处理
 *
 * @author xs
 * @date 2023-12-20
 */
@Service
public class WmsRawOutstockServiceImpl implements IWmsRawOutstockService {
    @Autowired
    private WmsRawOutstockMapper wmsRawOutstockMapper;

    @Autowired
    private WmsRawOutstockDetailMapper wmsRawOutstockDetailMapper;

    @Autowired
    private WmsRawInstockMapper wmsRawInstockMapper;

    @Autowired
    private WmsRawStockMapper wmsRawStockMapper;

    @Autowired
    private WmsBaseWarehouseMapper wmsBaseWarehouseMapper;

    @Autowired
    private WmsBaseLocationMapper wmsBaseLocationMapper;

    @Autowired
    private WmsConfig wmsConfig;

    @Autowired
    private RemoteMesService remoteMesService;


    /**
     * 查询原材料出库记录
     *
     * @param rawOutstockId 原材料出库记录主键
     * @return 原材料出库记录
     */
    @Override
    public WmsRawOutstock selectWmsRawOutstockByRawOutstockId(Long rawOutstockId) {
        WmsRawOutstock wmsRawOutstock = wmsRawOutstockMapper.selectWmsRawOutstockJoinMaterialById(rawOutstockId);
        WmsRawOutstockDetail queryRawOutstockDetail = new WmsRawOutstockDetail();
        queryRawOutstockDetail.setRawOutstockId(wmsRawOutstock.getRawOutstockId());
        List<WmsRawOutstockDetail> wmsRawOutstockDetailList = wmsRawOutstockDetailMapper.selectWmsRawOutstockDetailList(queryRawOutstockDetail);
        wmsRawOutstock.setWmsRawOutstockDetailList(wmsRawOutstockDetailList);
//        if(wmsRawOutstockDetailList!=null && !wmsRawOutstockDetailList.isEmpty()){
//            Long[] materialIds = wmsRawOutstockDetailList.stream().map(o -> o.getMaterialId()).toArray(Long[]::new);
//            MesBaseMaterialInfoVo mesBaseMaterialInfoVo = new MesBaseMaterialInfoVo();
//            mesBaseMaterialInfoVo.setMaterialIds(materialIds);
//            R<List<MesBaseMaterialInfo>> materialInfosR = remoteMesService.getMaterialsByMaterialIds(mesBaseMaterialInfoVo, SecurityConstants.INNER);
//            if (materialInfosR != null) {
//                List<MesBaseMaterialInfo> materialInfos = materialInfosR.getData();
//
//                Map<Long, MesBaseMaterialInfo> MesBaseMaterialInfoMap = materialInfos.stream()
//                        .collect(Collectors.toMap(MesBaseMaterialInfo::getMaterialId, mesBaseMaterialInfo -> mesBaseMaterialInfo));
//
//                wmsRawOutstockDetailList.forEach(wmsRawOutstockDetail -> {
//                    MesBaseMaterialInfo materialInfo = MesBaseMaterialInfoMap.get(wmsRawOutstockDetail.getMaterialId());
//                    if (materialInfo != null) {
//                        wmsRawOutstockDetail.setMaterialCode(materialInfo.getMaterialCode());
//                        wmsRawOutstockDetail.setMaterialName(materialInfo.getMaterialName());
//                    }
//                });
//            }
//        }

        return wmsRawOutstock;
    }

    /**
     * 查询原材料出库记录
     *
     * @param taskCode 原材料出库记录任务编号
     * @return 原材料出库记录审核返回VO对象
     */
    @Override
    public WmsRawOutstockAuditReturnVo selectWmsRawOutstockByTaskCode(String taskCode) {
        WmsRawOutstock queryRawOutstock = new WmsRawOutstock();
        queryRawOutstock.setTaskCode(taskCode);
//        queryRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_TOAUDIT);
        List<WmsRawOutstock> wmsRawOutstocks = wmsRawOutstockMapper.selectWmsRawOutstockJoinMaterialList(queryRawOutstock);
        WmsRawOutstock wmsRawOutStock = wmsRawOutstocks.get(0);
        WmsRawOutstockAuditReturnVo wmsRawOutstockAuditReturnVo = new WmsRawOutstockAuditReturnVo();
        wmsRawOutstockAuditReturnVo.setWmsRawOutstock(wmsRawOutStock);
        wmsRawOutstockAuditReturnVo.setWmsRawOutstockDetailList(wmsRawOutstocks);
        return wmsRawOutstockAuditReturnVo;
    }

    /**
     * 查询原材料出库记录列表
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 原材料出库记录
     */
    @Override
    public List<WmsRawOutstock> selectWmsRawOutstockList(WmsRawOutstock wmsRawOutstock) {
        return wmsRawOutstockMapper.selectWmsRawOutstockList(wmsRawOutstock);
    }

    /**
     * 新增原材料出库记录
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int insertWmsRawOutstock(WmsRawOutstock wmsRawOutstock) {
        int rows = wmsRawOutstockMapper.insertWmsRawOutstock(wmsRawOutstock);
        insertWmsRawOutstockDetail(wmsRawOutstock);
        return rows;
    }

    /**
     * 修改原材料出库记录
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int updateWmsRawOutstock(WmsRawOutstock wmsRawOutstock) {
        wmsRawOutstockMapper.deleteWmsRawOutstockDetailByRawOutstockId(wmsRawOutstock.getRawOutstockId());
        insertWmsRawOutstockDetail(wmsRawOutstock);
        return wmsRawOutstockMapper.updateWmsRawOutstock(wmsRawOutstock);
    }

    /**
     * 批量删除原材料出库记录
     *
     * @param rawOutstockIds 需要删除的原材料出库记录主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteWmsRawOutstockByRawOutstockIds(Long[] rawOutstockIds) {
        wmsRawOutstockMapper.deleteWmsRawOutstockDetailByRawOutstockIds(rawOutstockIds);
        return wmsRawOutstockMapper.deleteWmsRawOutstockByRawOutstockIds(rawOutstockIds);
    }

    /**
     * 删除原材料出库记录信息
     *
     * @param rawOutstockId 原材料出库记录主键
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteWmsRawOutstockByRawOutstockId(Long rawOutstockId) {
        wmsRawOutstockMapper.deleteWmsRawOutstockDetailByRawOutstockId(rawOutstockId);
        return wmsRawOutstockMapper.deleteWmsRawOutstockByRawOutstockId(rawOutstockId);
    }

    /**
     * 新增原材料出库记录明细信息
     *
     * @param wmsRawOutstock 原材料出库记录对象
     */
    public void insertWmsRawOutstockDetail(WmsRawOutstock wmsRawOutstock) {
        List<WmsRawOutstockDetail> wmsRawOutstockDetailList = wmsRawOutstock.getWmsRawOutstockDetailList();
        Long rawOutstockId = wmsRawOutstock.getRawOutstockId();
        if (StringUtils.isNotNull(wmsRawOutstockDetailList)) {
            List<WmsRawOutstockDetail> list = new ArrayList<WmsRawOutstockDetail>();
            for (WmsRawOutstockDetail wmsRawOutstockDetail : wmsRawOutstockDetailList) {
                wmsRawOutstockDetail.setRawOutstockId(rawOutstockId);
                wmsRawOutstockDetail.setTaskCode(wmsRawOutstock.getTaskCode());
                list.add(wmsRawOutstockDetail);
            }
            if (list.size() > 0) {
                wmsRawOutstockMapper.batchWmsRawOutstockDetail(list);
            }
        }
    }


    /**
     * 审核原材料出库记录
     *
     * @param wmsRawOutstockAuditVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int auditWmsRawOutstock(WmsRawOutstockAuditVo wmsRawOutstockAuditVo) {
        String auditStatus = wmsRawOutstockAuditVo.getAuditStatus();
        String auditReason = wmsRawOutstockAuditVo.getAuditReason();
        String taskCode = wmsRawOutstockAuditVo.getTaskCode();
        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();

        WmsRawOutstock queryRawOutstock = new WmsRawOutstock();
        queryRawOutstock.setTaskCode(taskCode);
        queryRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_TOAUDIT);
        List<WmsRawOutstock> wmsRawOutstocks = wmsRawOutstockMapper.selectWmsRawOutstockList(queryRawOutstock);
        if (wmsRawOutstocks == null || wmsRawOutstocks.isEmpty()) {
            throw new ServiceException("无待审核原材料出库记录");
        }

        //审核不通过，需要有审核意见，并且需要更新库位占用数量(解除之前占用的数量)。
        if (auditStatus.equalsIgnoreCase(WmsConstants.WMS_AUDIT_STATUS_FAIL)) {
            if (StringUtils.isEmpty(auditReason)) {
                throw new ServiceException("请输入审核意见");
            }
            wmsRawOutstocks.forEach(wmsRawOutstock -> {
                String locationCode = wmsRawOutstock.getLocationCode();
                String instockBatch = wmsRawOutstock.getMaterialBatch();
                BigDecimal planAmount = wmsRawOutstock.getOutstockAmount();
                WmsRawStock wmsRawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, instockBatch);
                if (wmsRawStock != null) {
                    BigDecimal occupyAmount = wmsRawStock.getOccupyAmount() == null ?
                            BigDecimal.ZERO : wmsRawStock.getOccupyAmount();
                    if (occupyAmount.compareTo(planAmount) >= 0) {
                        wmsRawStock.setOccupyAmount(occupyAmount.subtract(planAmount));
                        wmsRawStock.setUpdateBy(userName);
                        wmsRawStock.setUpdateDate(currentDate);
                    } else {
                        wmsRawStock.setOccupyAmount(BigDecimal.ZERO);
                        wmsRawStock.setUpdateBy(userName);
                        wmsRawStock.setUpdateDate(currentDate);
                    }
                    wmsRawStockMapper.updateWmsRawStock(wmsRawStock);
                }
            });
        }


        WmsRawOutstock wmsRawOutstock = new WmsRawOutstock();
        wmsRawOutstock.setAuditStatus(auditStatus);
        wmsRawOutstock.setAuditReason(auditReason);
        wmsRawOutstock.setAuditBy(SecurityUtils.getUsername());
        wmsRawOutstock.setAuditDate(new Date());
        wmsRawOutstock.setTaskCode(taskCode);
        int rows = wmsRawOutstockMapper.auditWmsRawOutstockByTaskCode(wmsRawOutstock);

//        JSONObject returnJson = new JSONObject();
//        returnJson.put("auditStatus", auditStatus);


        return rows;

    }

    /**
     * 原材料出库记录明细确认
     *
     * @param wmsRawOutstockConfirmVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int confirmWmsRawOutstock(WmsRawOutstockConfirmVo wmsRawOutstockConfirmVo) {
        Long rawOutstockId = wmsRawOutstockConfirmVo.getRawOutstockDetailId();
        String locationCode = wmsRawOutstockConfirmVo.getLocationCode();
        String materialBarcode = wmsRawOutstockConfirmVo.getInstockBatch();//在此是物料条码，不是批次码
        BigDecimal outstockAmount = wmsRawOutstockConfirmVo.getOutstockAmount();
        if (outstockAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("数量需大于0");
        }

        R<MesBaseBarcodeInfo> baseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        if (baseBarcodeInfoR == null) {
            throw new ServiceException("物料编码有误");
        }
        MesBaseBarcodeInfo baseBarcodeInfo = baseBarcodeInfoR.getData();
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料编码有误");
        }

        String batchFlag = baseBarcodeInfo.getBatchFlag();
        if (!batchFlag.equals(MesConstants.IS_BATCH)) {//如果不是批次
            if (outstockAmount.compareTo(BigDecimal.ONE) != 0) {
                throw new ServiceException("非批次物料数量需等于1");
            }
        }

        String batchCode = baseBarcodeInfo.getBatchCode();

        //todo：后续判断outrequirement
        //判断是否有此出库任务,人工出库的同一个出库记录，同一个库位、同一个物料对应一个明细（agv的有可能是多个）
        WmsRawOutstock queryRawOutstock = new WmsRawOutstock();
        queryRawOutstock.setLocationCode(locationCode);
        queryRawOutstock.setInstockBatch(batchCode);
        queryRawOutstock.setExecuteStatusStr(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE + "," + WmsConstants.WMS_EXECUTE_STATUS_EXECUTING);
        queryRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        queryRawOutstock.setRawOutstockId(rawOutstockId);

        List<WmsRawOutstock> wmsRawOutstocks = wmsRawOutstockMapper.selectWmsRawOutstockList(queryRawOutstock);
        if (wmsRawOutstocks == null || wmsRawOutstocks.isEmpty()) {
            throw new ServiceException("无此出库任务");
        }

        if (wmsRawOutstocks.size() > 1) {
            throw new ServiceException("请选择具体出库任务后点击确认");
        }

        WmsRawOutstock wmsRawOutstock = wmsRawOutstocks.get(0);

        WmsRawOutstockDetail queryRawOutstockDetail = new WmsRawOutstockDetail();
        queryRawOutstockDetail.setRawOutstockId(wmsRawOutstock.getRawOutstockId());
        queryRawOutstockDetail.setLocationCode(locationCode);
        queryRawOutstockDetail.setMaterialBarcode(materialBarcode);
        int rawOutstockDetailCount = wmsRawOutstockDetailMapper.selectCountOfWmsRawOutstockDetail(queryRawOutstockDetail);
        if (rawOutstockDetailCount > 0) {
            throw new ServiceException("此物料已经出库,不能重复出库");
        }

        //todo 判断质检状态
//        if (wmsRawOutstockDetail.getQualityStatus() != null
//                && !wmsRawOutstockDetail.getQualityStatus().equals(WmsConstants.WMS_QUALITY_STATUS_PASS)) {
//            throw new ServiceException("质检通过才能出库");
//        }

        // 判断本次出库数量+已出库数量是否大于计划出库数量
        BigDecimal hadOutstockAmount = wmsRawOutstock.getRealOutstockAmount() == null ? BigDecimal.ZERO : wmsRawOutstock.getRealOutstockAmount();
        BigDecimal planOutstockAmount = wmsRawOutstock.getOutstockAmount();

        BigDecimal updatedOutstockAmount = hadOutstockAmount.add(outstockAmount);
        if (updatedOutstockAmount.compareTo(planOutstockAmount) > 0) {
            throw new ServiceException("出库数量不能大于" + planOutstockAmount.subtract(hadOutstockAmount));
        }

        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();

        wmsRawOutstock.setRealOutstockAmount(updatedOutstockAmount);
        if (updatedOutstockAmount.compareTo(planOutstockAmount) == 0) {//如果已出完
            wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
            wmsRawOutstock.setEndTime(currentDate);
        } else {
            wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_EXECUTING);
            if (wmsRawOutstock.getBeginTime() == null) {
                wmsRawOutstock.setBeginTime(currentDate);
            }
        }
        wmsRawOutstock.setUpdateDate(currentDate);
        wmsRawOutstock.setUpdateBy(userName);
        wmsRawOutstockMapper.updateWmsRawOutstock(wmsRawOutstock);

        insertRawOutstockDetail(wmsRawOutstock, materialBarcode, batchCode, userName, currentDate);

        updateRawStock(locationCode, batchCode, outstockAmount, userName, currentDate);

        return 1;
    }

    public void insertRawOutstockDetail(WmsRawOutstock wmsRawOutstock, String materialBarcode, String batchCode,
                                        String userName, Date currentDate) {
        WmsRawOutstockDetail wmsRawOutstockDetail = new WmsRawOutstockDetail();
        wmsRawOutstockDetail.setRawOutstockId(wmsRawOutstock.getRawOutstockId());
        wmsRawOutstockDetail.setTaskCode(wmsRawOutstock.getTaskCode());
        wmsRawOutstockDetail.setWarehouseId(wmsRawOutstock.getWarehouseId());
        wmsRawOutstockDetail.setLocationCode(wmsRawOutstock.getLocationCode());
        wmsRawOutstockDetail.setMaterialId(wmsRawOutstock.getMaterialId());
        wmsRawOutstockDetail.setMaterialBarcode(materialBarcode);
        wmsRawOutstockDetail.setInstockBatch(batchCode);
        wmsRawOutstockDetail.setPlanAmount(BigDecimal.ONE);
        wmsRawOutstockDetail.setOutstockAmount(BigDecimal.ONE);
        wmsRawOutstockDetail.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
        wmsRawOutstockDetail.setOutstockPerson(userName);
        wmsRawOutstockDetail.setOutstockTime(currentDate);
        wmsRawOutstockDetail.setOutstockWay(WmsConstants.WMS_STOCK_WAY_MANUAL);

        wmsRawOutstockDetailMapper.insertWmsRawOutstockDetail(wmsRawOutstockDetail);

    }


    public void updateRawStock(String locationCode, String batchCode, BigDecimal outstockAmount, String userName, Date currentDate) {
        //更新原材料库存占用数量和总数量
        WmsRawStock wmsRawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, batchCode);
        if (wmsRawStock == null) {
            throw new ServiceException("没找到库存信息");
        } else {
            BigDecimal totalAmount = wmsRawStock.getTotalAmount() == null ? BigDecimal.ZERO : wmsRawStock.getTotalAmount();
            BigDecimal occupyAmount = wmsRawStock.getOccupyAmount() == null ? BigDecimal.ZERO : wmsRawStock.getOccupyAmount();
            BigDecimal updatedOccupyAmount = occupyAmount.subtract(outstockAmount);
            BigDecimal updatedTotalAmount = totalAmount.subtract(outstockAmount);
            updatedOccupyAmount = updatedOccupyAmount.compareTo(BigDecimal.ZERO) >= 0 ? updatedOccupyAmount : BigDecimal.ZERO;
            if (updatedTotalAmount.compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("库存不足");
            }
            if (updatedTotalAmount.compareTo(BigDecimal.ZERO) <= 0) {
                wmsRawStockMapper.deleteWmsRawStockByRawStockId(wmsRawStock.getRawStockId());
            } else {
                wmsRawStock.setOccupyAmount(updatedOccupyAmount);
                wmsRawStock.setTotalAmount(updatedTotalAmount);
                wmsRawStock.setUpdateDate(currentDate);
                wmsRawStock.setUpdateBy(userName);
                wmsRawStockMapper.updateWmsRawStock(wmsRawStock);
            }
        }
    }

    /**
     * 查询原材料出库记录列表，供手持出库使用
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 原材料出库记录列表
     */
    @Override
    public List<WmsRawOutstock> selectAuditPassRawOutstocks(WmsRawOutstock wmsRawOutstock) {
        wmsRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        List<WmsRawOutstock> wmsRawOutstocks = wmsRawOutstockMapper.selectWmsRawOutstockJoinMaterialList(wmsRawOutstock);
        return wmsRawOutstocks;
    }


    /**
     * 更新原材料出库记录的执行状态
     *
     * @param rawOutstockId
     * @param rawOutStockDetailId
     */
    private void updateRawOutstockDetailExecuteStatus(Long rawOutstockId, Long rawOutStockDetailId) {
        WmsRawOutstockDetail queryRawOutstockDetail = new WmsRawOutstockDetail();
        queryRawOutstockDetail.setRawOutstockId(rawOutstockId);
        List<WmsRawOutstockDetail> wmsRawOutstockDetails = wmsRawOutstockDetailMapper.selectWmsRawOutstockDetailList(queryRawOutstockDetail);

        boolean isExecuteFinish = true;
        for (WmsRawOutstockDetail wmsRawOutstockDetail : wmsRawOutstockDetails) {
            if (!wmsRawOutstockDetail.getRawOutstockDetailId().equals(rawOutStockDetailId)
                    && !wmsRawOutstockDetail.getExecuteStatus().equals(WmsConstants.WMS_EXECUTE_STATUS_FINISH)) {
                isExecuteFinish = false;
            }
        }

        if (isExecuteFinish) {
            WmsRawOutstock wmsRawOutstock = wmsRawOutstockMapper.selectWmsRawOutstockByRawOutstockId(rawOutstockId);
            wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
            wmsRawOutstockMapper.updateWmsRawOutstock(wmsRawOutstock);
        }
    }


    /**
     * 申请领料
     * 在申请领料时，不管是否需要审核，都需要锁定库位和修改占用数量（但审核不通过的话需要解锁库位和更新占用数量）
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 结果
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public int applyRawOutstock(WmsRawOutstock wmsRawOutstock) {
        String planCode = wmsRawOutstock.getPlanCode();
        String planDetailCode = wmsRawOutstock.getPlanDetailCode();

        if (StringUtils.isEmpty(planCode)) {
            throw new ServiceException("请选择生产详细信息再领料");
        }

        Long warehouseId = wmsRawOutstock.getWarehouseId();
        List<WmsRawOutstockDetail> rawOutstockDetails = wmsRawOutstock.getWmsRawOutstockDetailList();
        //根据物料ID分组获取总申请数量
//        Map<Long, BigDecimal> rawOutstockDetailMap = rawOutstockDetails.stream()
//                .collect(Collectors.groupingBy(WmsRawOutstockDetail::getMaterialId, HashMap::new, Collectors.reducing(BigDecimal.ZERO, WmsRawOutstockDetail::getPlanAmount, BigDecimal::add)));

        //判断仓库类型，出库记录保存对应操作类型，出库记录明细保存对应出库方式
        WmsBaseWarehouse baseWarehouse = wmsBaseWarehouseMapper.selectWmsBaseWarehouseByWarehouseId(warehouseId);
        String taskType = StringUtils.isEmpty(wmsRawOutstock.getTaskType()) ? WmsConstants.WMS_RAW_OUTSTOCK_TASK_TYPE_PRODUCTION_PICKING
                : wmsRawOutstock.getTaskType();
        String warehouseType = baseWarehouse.getWarehouseType();

        String queryQualityStatus = WmsConstants.WMS_QUALITY_STATUS_PASS;


        List<WmsRawOutstock> toInsertedRawOutstocks = new ArrayList<>();
        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        String taskCode = Seq.getId(Seq.rawOutstockSeqType, Seq.rawOutstockSeqCode);
        //传入的申请领料list遍历
        rawOutstockDetails.forEach(rawOutstockDetail -> {
            BigDecimal planAmount = rawOutstockDetail.getPlanAmount() == null ?
                    BigDecimal.ZERO : rawOutstockDetail.getPlanAmount();//申请数量
            Long materialId = rawOutstockDetail.getMaterialId();
            if (planAmount.compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal realRawStock = BigDecimal.ZERO;//实际库存总量
                WmsRawStock queryRawStock = new WmsRawStock();
                queryRawStock.setWarehouseId(warehouseId);
                queryRawStock.setMaterialId(materialId);
                queryRawStock.setCompleteFlag(WmsConstants.WMS_RAW_STOCK_COMPLETE_FLAY_YES);
//            queryRawStock.setQualityStatus(queryQualityStatus);//todo：先不过滤质检状态
                //TODO:需要先查看wms_raw_stock_occupy，是否有此生产订单的占用明细,有的话需要计算并且更新
                //判断库位和可用数量（总数量减冻结数量和占用数量），按先进先出（按入库时间排序获取）
                List<WmsRawStock> wmsRawStocks = wmsRawStockMapper.selectWmsRawStocks4Apply(queryRawStock);
                if (wmsRawStocks != null && !wmsRawStocks.isEmpty()) {
                    for (WmsRawStock wmsRawStock : wmsRawStocks) {
                        BigDecimal totalAmount = wmsRawStock.getTotalAmount();
                        BigDecimal frozenAmount = wmsRawStock.getFrozenAmount() == null ? BigDecimal.ZERO : wmsRawStock.getFrozenAmount();
                        BigDecimal occupyAmount = wmsRawStock.getOccupyAmount() == null ? BigDecimal.ZERO : wmsRawStock.getOccupyAmount();
                        BigDecimal availableAmount = totalAmount.subtract(frozenAmount).subtract(occupyAmount);
                        realRawStock = realRawStock.add(availableAmount);
                        //可出库数量大于0
                        if (availableAmount.compareTo(BigDecimal.ZERO) > 0) {
                            //如果申请数量大于此库位可出库的数量则继续进行下一库位判断
                            if (planAmount.compareTo(availableAmount) > 0) {
                                //占用数量更改
                                wmsRawStock.setOccupyAmount(occupyAmount.add(availableAmount));
                                wmsRawStock.setUpdateDate(currentDate);
                                wmsRawStock.setUpdateBy(userName);
                                //如果同一个物料有多条记录的处理（最好避免前端可以传多条同一个物料的申请）,
                                //提前更新（主要是更新数量等信息，避免在下一次判断中还使用上次的数量），放在事务中
                                wmsRawStockMapper.updateWmsRawStock(wmsRawStock);

                                //原材料出库记录(有break，以下方法需要写在此处)
                                WmsRawOutstock toInsertedRawOutstock = getWmsRawOutstock(wmsRawStock, baseWarehouse, planCode, planDetailCode, materialId, taskCode, taskType,
                                        planAmount, currentDate, userName);
                                toInsertedRawOutstocks.add(toInsertedRawOutstock);

                                planAmount = planAmount.subtract(availableAmount);
                            } else if (planAmount.compareTo(availableAmount) == 0) {//计划数量等于可出库数量
                                //占用数量更改
                                wmsRawStock.setOccupyAmount(occupyAmount.add(availableAmount));
                                wmsRawStock.setUpdateDate(currentDate);
                                wmsRawStock.setUpdateBy(userName);
                                //如果同一个物料有多条记录的处理,提前更新（主要是更新数量等信息，避免在下一次判断中还使用上次的数量），放在事务中
                                wmsRawStockMapper.updateWmsRawStock(wmsRawStock);

                                //原材料出库记录(有break，以下方法需要写在此处)
                                WmsRawOutstock toInsertedRawOutstock = getWmsRawOutstock(wmsRawStock, baseWarehouse, planCode, planDetailCode, materialId, taskCode, taskType,
                                        planAmount, currentDate, userName);
                                toInsertedRawOutstocks.add(toInsertedRawOutstock);

                                planAmount = BigDecimal.ZERO;
                                break;
                            } else if (planAmount.compareTo(availableAmount) < 0) {
                                //占用数量更改
                                wmsRawStock.setOccupyAmount(occupyAmount.add(planAmount));
                                wmsRawStock.setUpdateDate(currentDate);
                                wmsRawStock.setUpdateBy(userName);
                                //如果同一个物料有多条记录的处理,提前更新（主要是更新数量等信息，避免在下一次判断中还使用上次的数量），放在事务中
                                wmsRawStockMapper.updateWmsRawStock(wmsRawStock);

                                //原材料出库记录(有break，以下方法需要写在此处)
                                WmsRawOutstock toInsertedRawOutstock = getWmsRawOutstock(wmsRawStock, baseWarehouse, planCode, planDetailCode, materialId, taskCode, taskType,
                                        planAmount, currentDate, userName);
                                toInsertedRawOutstocks.add(toInsertedRawOutstock);

                                planAmount = BigDecimal.ZERO;
                                break;
                            }
                        }
                    }
                }

                //以上将申请的数量跟库存数量比对，如果库存数量足够则planAmount减去库存会=0,如果不够则剩余的planAmount会>0
                if (planAmount.compareTo(BigDecimal.ZERO) > 0) {
                    throw new ServiceException("物料名称为[" + rawOutstockDetail.getMaterialName() + "]库存不足，只有" + realRawStock);
                }
            }
        });

        wmsRawOutstockMapper.batchWmsRawOutstock(toInsertedRawOutstocks);

        return 1;
    }


    /**
     * 获取待保存的原材料出库记录
     *
     * @param wmsRawStock
     * @param baseWarehouse
     * @param planCode
     * @param planDetailCode
     * @param materialId
     * @param taskCode
     * @param planAmount
     * @param currentDate
     * @param userName
     * @return
     */
    private WmsRawOutstock getWmsRawOutstock(WmsRawStock wmsRawStock, WmsBaseWarehouse baseWarehouse,
                                             String planCode, String planDetailCode, Long materialId, String taskCode, String taskType,
                                             BigDecimal planAmount, Date currentDate, String userName) {
        //出库要求 （0申请出库，1申请审核出库，2直接出库）
        String outRequirement = baseWarehouse.getOutRequirement();
        String warehouseType = baseWarehouse.getWarehouseType();
        String operationType = WmsConstants.OPERATION_TYPE_MAP.get(warehouseType);

        WmsRawOutstock toInsertedRawOutstock = new WmsRawOutstock();
        toInsertedRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);

        if (warehouseType.equals(WmsConstants.WMS_WAREHOUSE_TYPE_NORMAL)) {//如果是普通仓库，需要校验审核标识
            if (outRequirement.equals(WmsConstants.WMS_WAREHOUSE_OUT_REQUIREMENT_APPLY_AUDIT)) {
                toInsertedRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_TOAUDIT);
            } else {
                toInsertedRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
            }

        } else {
            toInsertedRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        }

        toInsertedRawOutstock.setTaskCode(taskCode);
        toInsertedRawOutstock.setWarehouseId(wmsRawStock.getWarehouseId());
        toInsertedRawOutstock.setLocationCode(wmsRawStock.getLocationCode());
        toInsertedRawOutstock.setStationId(SecurityUtils.getStationId());
        toInsertedRawOutstock.setPalletInfoCode(wmsRawStock.getPalletInfoCode());
        toInsertedRawOutstock.setOperationType(operationType);
        toInsertedRawOutstock.setApplyBy(userName);
        toInsertedRawOutstock.setApplyDate(currentDate);
        toInsertedRawOutstock.setEndStationCode(SecurityUtils.getStationCode());
        toInsertedRawOutstock.setMaterialId(materialId);
        toInsertedRawOutstock.setOutstockAmount(planAmount);
        toInsertedRawOutstock.setPlanCode(planCode);
        toInsertedRawOutstock.setPlanDetailCode(planDetailCode);
        toInsertedRawOutstock.setMaterialBatch(wmsRawStock.getInstockBatch());
        toInsertedRawOutstock.setTaskType(taskType);
        toInsertedRawOutstock.setCreateTime(currentDate);
        toInsertedRawOutstock.setCreateBy(userName);


        return toInsertedRawOutstock;
    }


    public void handleRawOutstock(WmsRawOutstock wmsRawOutstock, WmsBaseWarehouse warehouse,
                                  String userName, Date currentDate, List<WmsRawOutstockDetail> toUpdatedRawOutstockDetails) {
        //出库要求 （0申请出库，1申请审核出库，2直接出库）
        String outRequirement = warehouse.getOutRequirement();
        String warehouseType = warehouse.getWarehouseType();
        String operationType = WmsConstants.OPERATION_TYPE_MAP.get(warehouseType);
        if (warehouseType.equals(WmsConstants.WMS_WAREHOUSE_TYPE_NORMAL)) {
            if (outRequirement.equals(WmsConstants.WMS_WAREHOUSE_OUT_REQUIREMENT_APPLY_AUDIT)) {
                wmsRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_TOAUDIT);
                wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
            } else {
                wmsRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
                wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);
            }

            wmsRawOutstock.setTaskCode(Seq.getId(Seq.rawOutstockSeqType, Seq.rawOutstockSeqCode));
            wmsRawOutstock.setStationId(SecurityUtils.getStationId());

            wmsRawOutstock.setOperationType(operationType);
            wmsRawOutstock.setApplyBy(userName);
            wmsRawOutstock.setApplyDate(currentDate);

            wmsRawOutstockMapper.insertWmsRawOutstock(wmsRawOutstock);
            wmsRawOutstock.setWmsRawOutstockDetailList(toUpdatedRawOutstockDetails);
            insertWmsRawOutstockDetail(wmsRawOutstock);
        } else {
            List<WmsRawOutstock> toInsertedRawOutstocks = new ArrayList<>();
            toUpdatedRawOutstockDetails.forEach(wmsRawOutstockDetail -> {
                WmsRawOutstock toInsertedRawOutstock = new WmsRawOutstock();
                toInsertedRawOutstock.setTaskCode(Seq.getId(Seq.rawOutstockSeqType, Seq.rawOutstockSeqCode));
                toInsertedRawOutstock.setWarehouseId(wmsRawOutstock.getWarehouseId());
                toInsertedRawOutstock.setLocationCode(wmsRawOutstockDetail.getLocationCode());
                toInsertedRawOutstock.setStationId(SecurityUtils.getStationId());
                toInsertedRawOutstock.setPalletInfoCode(wmsRawOutstockDetail.getPalletInfoCode());
                toInsertedRawOutstock.setOperationType(operationType);
                toInsertedRawOutstock.setApplyBy(userName);
                toInsertedRawOutstock.setApplyDate(currentDate);
                toInsertedRawOutstock.setEndStationCode(SecurityUtils.getStationCode());
                toInsertedRawOutstock.setPlanCode(wmsRawOutstock.getPlanCode());
                toInsertedRawOutstock.setPlanDetailCode(wmsRawOutstock.getPlanDetailCode());
                toInsertedRawOutstock.setMaterialBatch(wmsRawOutstockDetail.getInstockBatch());
                toInsertedRawOutstock.setOutstockAmount(wmsRawOutstockDetail.getPlanAmount());
                toInsertedRawOutstock.setTaskType(WmsConstants.WMS_RAW_OUTSTOCK_TASK_TYPE_PRODUCTION_PICKING);
                toInsertedRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
                toInsertedRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
                toInsertedRawOutstocks.add(toInsertedRawOutstock);
            });

            wmsRawOutstockMapper.batchWmsRawOutstock(toInsertedRawOutstocks);
        }

    }

    /**
     * AGV原材料出库
     *
     * @param wmsAgvRawOutstockVo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<WmsWcsVo> applyAgvRawOutstock(WmsAgvRawOutstockVo wmsAgvRawOutstockVo) {
        List<WmsWcsVo> wmsWcsVos = new ArrayList<>();

        Long warehouseId = wmsAgvRawOutstockVo.getWarehouseId();
        Long materialId = wmsAgvRawOutstockVo.getMaterialId();

        WmsBaseWarehouse warehouse = wmsBaseWarehouseMapper.selectWmsBaseWarehouseWithLocationByWarehouseId(warehouseId);
        List<WmsBaseLocation> baseLocations = warehouse.getWmsBaseLocationList();
        Map<String, WmsBaseLocation> baseLocationsMap = baseLocations.stream().collect(Collectors.toMap(WmsBaseLocation::getLocationCode, baseLocation -> baseLocation));

        WmsRawStock queryRawStock = new WmsRawStock();
        queryRawStock.setWarehouseId(warehouseId);
        queryRawStock.setMaterialId(materialId);
        queryRawStock.setCompleteFlag(WmsConstants.WMS_RAW_STOCK_COMPLETE_FLAG_YES);

        List<WmsRawStock> rawStockList = wmsRawStockMapper.selectWmsRawStockInList(queryRawStock);

        Map<String, List<WmsRawStock>> rawStockListMap = rawStockList.stream()
                .collect(Collectors.groupingBy(WmsRawStock::getLocationCode));

        String userName = SecurityUtils.getUsername();
        Date currentDate = new Date();

        //选择出库库位
        WmsBaseLocation outstockLocation = null;//出库库位
        String moveMaterialBarcode = "";
        Long moveMaterialId = null;
        for (WmsRawStock wmsRawStock : rawStockList) {
            BigDecimal occupyAmount = wmsRawStock.getOccupyAmount() == null ? BigDecimal.ZERO : wmsRawStock.getOccupyAmount();
            BigDecimal frozenAmount = wmsRawStock.getFrozenAmount() == null ? BigDecimal.ZERO : wmsRawStock.getFrozenAmount();
            WmsBaseLocation wmsBaseLocation = baseLocationsMap.get(wmsRawStock.getLocationCode());
            //先确认出库库位，可用数量>=1，库位状态是正常的

            if (occupyAmount.compareTo(BigDecimal.ZERO) <= 0 && frozenAmount.compareTo(BigDecimal.ZERO) <= 0
                    && wmsBaseLocation.getLocationStatus().equals(WmsConstants.WMS_BASE_LOCATION_STATUS_NORMAL)
            ) {
                outstockLocation = wmsBaseLocation;
                moveMaterialBarcode = wmsRawStock.getInstockBatch();
                moveMaterialId = wmsRawStock.getMaterialId();
                break;
            }
        }

        if (outstockLocation == null) {
            throw new ServiceException("没有可出库库位");
        }

        Long outstockLocRow = outstockLocation.getLocRow();//出库库位排
        if (outstockLocRow > 1) { //如果是后排
            //先判断对应的前排库位有没有库存，如果没有库存，则锁定库位;如果有库存则需要移库
            Long outstockColumn = outstockLocation.getLocColumn();
            WmsBaseLocation frontLocation = new WmsBaseLocation();//前排库位
            WmsBaseLocation outExcessLocation = null;//出库过度库位
            for (WmsBaseLocation location : baseLocations) {
                String instockFlag = location.getInstockFlag() == null ? "0" : location.getInstockFlag();
                Long instockLocRow = location.getLocRow() == null ? 1L : location.getLocRow();
                if (location.getLocColumn().equals(outstockColumn) && location.getLocRow().equals(1L)) {
                    frontLocation = location;
                }
                //如果是入库过度库位，并且是第一排
                if (instockFlag.equals(WmsConstants.WMS_BASE_LOCATION_INSTOCK_FLAG_YES) && instockLocRow.equals(1L)) {
                    outExcessLocation = location;
                }
            }

            List<WmsRawStock> frontLocationRawStocks = rawStockListMap.get(frontLocation.getLocationCode());
            //如果是后排，则判断前排是否有库存，如果有库存则需要移库，移库还要选择没锁定的，然后锁定
            if (frontLocationRawStocks != null && !frontLocationRawStocks.isEmpty()) {//移库位
                if (outExcessLocation == null) {
                    throw new ServiceException("需设置入库过度库位");
                }

                if (outExcessLocation.getLocationId().equals(frontLocation.getLocationId())) {
                    throw new ServiceException("前排库位为入库过度库位，但是过度库位有库存");
                }

                WmsRawStock forntWmsRawStock = frontLocationRawStocks.get(0);

                //锁入库过度库位
                outExcessLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_AUTO_LOCK);
                outExcessLocation.setInstockFlag(WmsConstants.WMS_BASE_LOCATION_INSTOCK_FLAG_NO);//需设置为非入库过度库位
                outExcessLocation.setUpdateBy(userName);
                outExcessLocation.setUpdateTime(currentDate);
                wmsBaseLocationMapper.updateWmsBaseLocation(outExcessLocation);

                //移库出库任务
                agvRawOutstock(wmsAgvRawOutstockVo, frontLocation, moveMaterialBarcode, moveMaterialId, WmsConstants.WMS_RAW_OUTSTOCK_TASK_TYPE_MOVE,
                        userName, currentDate);
                WmsWcsVo moveOutWcsVo = new WmsWcsVo();
                moveOutWcsVo.setOrderNumer(1);
                wmsWcsVos.add(moveOutWcsVo);

                //移库入库任务
                agvRawInstock(wmsAgvRawOutstockVo, outExcessLocation, moveMaterialBarcode, moveMaterialId,
                        userName, currentDate);
                WmsWcsVo moveInWcsVo = new WmsWcsVo();
                moveInWcsVo.setOrderNumer(2);
                wmsWcsVos.add(moveInWcsVo);

                frontLocation.setInstockFlag(WmsConstants.WMS_BASE_LOCATION_INSTOCK_FLAG_YES);//需设置此库位已入库过度库位
            }

            //锁前排库位（自动锁定的库位可以不用更新库存中的占用数量）
            frontLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_AUTO_LOCK);
            frontLocation.setUpdateBy(userName);
            frontLocation.setUpdateTime(currentDate);
            wmsBaseLocationMapper.updateWmsBaseLocation(frontLocation);

            //锁出库库位
            outstockLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_AUTO_LOCK);
            outstockLocation.setUpdateBy(userName);
            outstockLocation.setUpdateTime(currentDate);

            wmsBaseLocationMapper.updateWmsBaseLocation(outstockLocation);
        }

        WmsRawOutstock agvRawOutstock = agvRawOutstock(wmsAgvRawOutstockVo, outstockLocation, moveMaterialBarcode, moveMaterialId,
                WmsConstants.WMS_RAW_OUTSTOCK_TASK_TYPE_PRODUCTION_PICKING, userName, currentDate);
        WmsWcsVo outWcsVo = new WmsWcsVo();
        outWcsVo.setOrderNumer(3);
        outWcsVo.setTaskId(agvRawOutstock.getRawOutstockId());
        wmsWcsVos.add(outWcsVo);
        return wmsWcsVos;
    }


    private WmsRawOutstock agvRawOutstock(WmsAgvRawOutstockVo wmsAgvRawOutstockVo, WmsBaseLocation oriBaseLocation, String moveMaterialBarcode, Long moveMaterialId,
                                          String taskType, String userName, Date currentDate) {
        WmsRawOutstock rawOutstock = new WmsRawOutstock();
        rawOutstock.setWarehouseId(oriBaseLocation.getWarehouseId());
        rawOutstock.setPlanCode(wmsAgvRawOutstockVo.getPlanCode());
        rawOutstock.setOperationType(WmsConstants.WMS_OPERATION_TYPE_AUTO);
        rawOutstock.setTaskType(taskType);
        rawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        rawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
        rawOutstock.setApplyDate(currentDate);
        rawOutstock.setApplyBy(userName);
        rawOutstock.setCreateBy(userName);
        rawOutstock.setCreateTime(currentDate);

        wmsRawOutstockMapper.insertWmsRawOutstock(rawOutstock);

        WmsRawOutstockDetail rawOutstockDetail = new WmsRawOutstockDetail();
        rawOutstockDetail.setRawOutstockId(rawOutstock.getRawOutstockId());
        rawOutstockDetail.setLocationCode(oriBaseLocation.getLocationCode());
        rawOutstockDetail.setMaterialBarcode(moveMaterialBarcode);
        rawOutstockDetail.setMaterialId(moveMaterialId);
        rawOutstockDetail.setPlanAmount(new BigDecimal(1));//todo： agv数量默认1
        rawOutstockDetail.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
        rawOutstockDetail.setOutstockWay(WmsConstants.WMS_STOCK_WAY_AGV);
        wmsRawOutstockDetailMapper.insertWmsRawOutstockDetail(rawOutstockDetail);

        return rawOutstock;
    }


    private WmsRawInstock agvRawInstock(WmsAgvRawOutstockVo wmsAgvRawOutstockVo, WmsBaseLocation targetBaseLocation, String moveMaterialBarcode, Long moveMaterialId,
                                        String userName, Date currentDate) {
        WmsRawInstock rawInstock = new WmsRawInstock();
        rawInstock.setWarehouseId(wmsAgvRawOutstockVo.getWarehouseId());
        rawInstock.setOperationType(WmsConstants.WMS_OPERATION_TYPE_AUTO);
//        rawInstock.setInstockType(WmsConstants.RAW_INSTOCK_INSTOCK_TYPE_MOVE);
//        rawInstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
//        rawInstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
//        rawInstock.setApplyDate(currentDate);
//        rawInstock.setApplyBy(userName);
//        rawInstock.setCreateBy(userName);
//        rawInstock.setCreateTime(currentDate);
//
//        wmsRawInstockMapper.insertWmsRawInstock(rawInstock);
//
//        WmsRawInstockDetail rawInstockDetail = new WmsRawInstockDetail();
//        rawInstockDetail.setRawInstockId(rawInstock.getRawInstockId());
//        rawInstockDetail.setLocationCode(targetBaseLocation.getLocationCode());
//        rawInstockDetail.setMaterialBarcode(moveMaterialBarcode);
//        rawInstockDetail.setMaterialId(moveMaterialId);
//        rawInstockDetail.setPlanAmount(new BigDecimal(1));//todo： agv数量默认1
//        rawInstockDetail.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
//        rawInstockDetail.setInstockWay(WmsConstants.WMS_STOCK_WAY_AGV);
//        wmsRawInstockDetailMapper.insertWmsRawInstockDetail(rawInstockDetail);

        return rawInstock;
    }


    /**
     * 获取空的库位
     *
     * @param warehouseId
     * @return
     */
    public List<WmsBaseLocation> agvReturnAssignLocations(Long warehouseId) {
        WmsBaseLocation queryLocation = new WmsBaseLocation();
        queryLocation.setWarehouseId(warehouseId);
        List<WmsBaseLocation> baseLocations = wmsBaseLocationMapper.selectEmptyWmsBaseLocationList(queryLocation);
        return baseLocations;
    }


    /**
     * agv拆分后的柜体返库
     *
     * @param wmsAgvRawReturnVo
     */
    public void agvReturn(WmsAgvRawReturnVo wmsAgvRawReturnVo) {
        String materialBarcode = wmsAgvRawReturnVo.getMaterialBarcode();
        String locationCode = wmsAgvRawReturnVo.getLocationCode();

//        WmsConstants.WMS_RAW_STOCK_COMPLETE_FLAG_NO;
    }


    /**
     * 查询原材料出库记录列表,join warehouse
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 原材料出库记录
     */
    @Override
    public List<WmsRawOutstock> selectWmsRawOutstockJoinList(WmsRawOutstock wmsRawOutstock) {
        return wmsRawOutstockMapper.selectWmsRawOutstockJoinList(wmsRawOutstock);
    }


    /**
     * 查询原材料出库记录列表,join warehouse
     *
     * @param wmsRawOutstock 原材料出库记录
     * @return 原材料出库记录
     */
    @Override
    public List<WmsRawOutstock> selectWmsRawOutstockJoinList4Audit(WmsRawOutstock wmsRawOutstock) {
        return wmsRawOutstockMapper.selectWmsRawOutstockJoinList4Audit(wmsRawOutstock);
    }


    /**
     * 组装出库
     *
     * @param wmsAssembleOutstockVo
     * @return
     */
    @Override
    public int assembleOutstock(WmsAssembleOutstockVo wmsAssembleOutstockVo) {
        String materialBarcode = wmsAssembleOutstockVo.getMaterialBarcode();
        R<MesBaseBarcodeInfo> baseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        if (baseBarcodeInfoR == null) {
            throw new ServiceException("物料编码有误");
        }
        MesBaseBarcodeInfo baseBarcodeInfo = baseBarcodeInfoR.getData();
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料编码有误");
        }

        String bindBarcode = baseBarcodeInfo.getBindBarcode();

        WmsRawOutstock queryRawOutstock = new WmsRawOutstock();
        queryRawOutstock.setMaterialBatch(bindBarcode);
        List<WmsRawOutstock> wmsRawOutstocks = wmsRawOutstockMapper.selectWmsRawOutstockList(queryRawOutstock);
        if (wmsRawOutstocks != null && !wmsRawOutstocks.isEmpty()) {
            throw new ServiceException("已经有此物料出库记录");
        }

        WmsRawStock queryRawStock = new WmsRawStock();
        queryRawStock.setInstockBatch(bindBarcode);
        queryRawStock.setCompleteFlag(WmsConstants.WMS_RAW_STOCK_COMPLETE_FLAG_NO);
        List<WmsRawStock> wmsRawStocks = wmsRawStockMapper.selectWmsRawStockInList(queryRawStock);
        if (wmsRawStocks == null || wmsRawStocks.isEmpty()) {
            throw new ServiceException("没找到库存信息");
        }

        WmsRawStock wmsRawStock = wmsRawStocks.get(0); //待agv出库后，wcs更新库存信息（需要删除库存，由于是1个）

        WmsRawOutstock wmsRawOutstock = new WmsRawOutstock();
        wmsRawOutstock.setTaskCode(Seq.getId(Seq.rawOutstockSeqType, Seq.rawOutstockSeqCode));
        wmsRawOutstock.setWarehouseId(wmsRawStock.getWarehouseId());
        wmsRawOutstock.setLocationCode(wmsRawStock.getLocationCode());
        wmsRawOutstock.setOrderId(baseBarcodeInfo.getSaleOrderId());
        wmsRawOutstock.setPlanCode(baseBarcodeInfo.getPlanCode());
        wmsRawOutstock.setPlanDetailCode(baseBarcodeInfo.getPlanDetailCode());
        wmsRawOutstock.setMaterialId(baseBarcodeInfo.getMaterialId());
        wmsRawOutstock.setMaterialBatch(bindBarcode);
        wmsRawOutstock.setPalletInfoCode(baseBarcodeInfo.getPalletInfoCode());//在绑定时需要在条码信息中记录托盘码
        wmsRawOutstock.setOutstockAmount(BigDecimal.ONE);

        wmsRawOutstock.setEndStationCode(wmsConfig.getFifthAssembleStationCode());//目标位置，五楼组装区域 todo 读配置文件获取
        wmsRawOutstock.setOperationType(WmsConstants.WMS_OPERATION_TYPE_AUTO);
        wmsRawOutstock.setTaskType(WmsConstants.WMS_RAW_OUTSTOCK_TASK_TYPE_PRODUCTION_INSTALL);
        wmsRawOutstock.setApplyBy(SecurityUtils.getUsername());
        wmsRawOutstock.setApplyDate(new Date());
        wmsRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);

        wmsRawOutstockMapper.insertWmsRawOutstock(wmsRawOutstock);

        return 1;
    }


    /**
     * 直接出库（适合四楼激光切割工位板材出库）
     *
     * @param wmsRawOutstock
     * @return
     */
    @Transactional
    @Override
    public int directRawOutstock(WmsRawOutstock wmsRawOutstock) {
        //出库要求 （0申请出库，1申请审核出库，2直接出库）
        String materialBarcode = wmsRawOutstock.getMaterialBarcode();
        R<MesBaseBarcodeInfo> baseBarcodeInfoR = remoteMesService.getBarcode(materialBarcode, SecurityConstants.INNER);
        if (baseBarcodeInfoR == null) {
            throw new ServiceException("物料编码有误");
        }
        MesBaseBarcodeInfo baseBarcodeInfo = baseBarcodeInfoR.getData();
        if (baseBarcodeInfo == null) {
            throw new ServiceException("物料编码有误");
        }

        String locationCode = wmsRawOutstock.getLocationCode();
        WmsBaseLocation baseLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(locationCode);
        if (baseLocation == null) {
            throw new ServiceException("库位编码错误");
        }

        BigDecimal outstockAmount = wmsRawOutstock.getOutstockAmount();
        String batchCode = baseBarcodeInfo.getBatchCode();
        String userName = SecurityUtils.getUsername();
        Date currentDate = new Date();

        wmsRawOutstock.setTaskCode(Seq.getId(Seq.rawOutstockSeqType, Seq.rawOutstockSeqCode));
        wmsRawOutstock.setWarehouseId(baseLocation.getWarehouseId());
        wmsRawOutstock.setStationId(SecurityUtils.getStationId());
        wmsRawOutstock.setMaterialId(baseBarcodeInfo.getMaterialId());
        wmsRawOutstock.setMaterialBatch(baseBarcodeInfo.getBatchCode());
        wmsRawOutstock.setRealOutstockAmount(outstockAmount);
        wmsRawOutstock.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
        wmsRawOutstock.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_FINISH);

        wmsRawOutstock.setApplyBy(userName);
        wmsRawOutstock.setApplyDate(currentDate);
        wmsRawOutstockMapper.insertWmsRawOutstock(wmsRawOutstock);

        this.insertRawOutstockDetail(wmsRawOutstock, materialBarcode, batchCode,
                userName, currentDate);

        directOutstockUpdateRawStock(locationCode, batchCode, outstockAmount, userName, currentDate);

        return 1;
    }


    public void directOutstockUpdateRawStock(String locationCode, String batchCode, BigDecimal outstockAmount,
                                             String userName, Date currentDate) {
        WmsRawStock wmsRawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, batchCode);
        if (wmsRawStock == null) {
            throw new ServiceException("没找到库存信息");
        } else {
            BigDecimal totalAmount = wmsRawStock.getTotalAmount() == null ? BigDecimal.ZERO : wmsRawStock.getTotalAmount();
            BigDecimal updatedTotalAmount = totalAmount.subtract(outstockAmount);
            if (updatedTotalAmount.compareTo(BigDecimal.ZERO) < 0) {
                throw new ServiceException("库存不足");
            }
            if (updatedTotalAmount.compareTo(BigDecimal.ZERO) <= 0) {
                wmsRawStockMapper.deleteWmsRawStockByRawStockId(wmsRawStock.getRawStockId());
            } else {
                wmsRawStock.setTotalAmount(updatedTotalAmount);
                wmsRawStock.setUpdateDate(currentDate);
                wmsRawStock.setUpdateBy(userName);
                wmsRawStockMapper.updateWmsRawStock(wmsRawStock);
            }

        }
    }

}
