package com.hw.wms.service.impl;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

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.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.wms.domain.*;
import com.hw.wms.domain.vo.WmsMoveApplyVo;
import com.hw.wms.domain.vo.WmsMoveVo;
import com.hw.wms.mapper.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import com.hw.common.core.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.hw.wms.service.IWmsMoveService;

import javax.annotation.Resource;

/**
 * 移库合库记录Service业务层处理
 *
 * @author xins
 * @date 2024-01-09
 */
@Service
public class WmsMoveServiceImpl implements IWmsMoveService {
    @Autowired
    private WmsMoveMapper wmsMoveMapper;

    @Autowired
    private WmsMoveDetailMapper wmsMoveDetailMapper;

    @Autowired
    private WmsBaseLocationMapper wmsBaseLocationMapper;

    @Autowired
    private WmsBaseWarehouseMapper wmsBaseWarehouseMapper;

    @Autowired
    private WmsRawStockMapper wmsRawStockMapper;

    @Autowired
    private WmsProductStockMapper wmsProductStockMapper;

    @Resource
    private RemoteMesService remoteMesService;

    /**
     * 查询移库合库记录
     *
     * @param moveId 移库合库记录主键
     * @return 移库合库记录
     */
    @Override
    public WmsMove selectWmsMoveByMoveId(Long moveId) {
        return wmsMoveMapper.selectWmsMoveByMoveId(moveId);
    }

    /**
     * 查询移库合库记录列表
     *
     * @param wmsMove 移库合库记录
     * @return 移库合库记录
     */
    @Override
    public List<WmsMove> selectWmsMoveList(WmsMove wmsMove) {
        return wmsMoveMapper.selectWmsMoveList(wmsMove);
    }

    /**
     * 新增移库合库记录
     *
     * @param wmsMove 移库合库记录
     * @return 结果
     */
    @Transactional
    @Override
    public int insertWmsMove(WmsMove wmsMove) {
        int rows = wmsMoveMapper.insertWmsMove(wmsMove);
        insertWmsMoveDetail(wmsMove);
        return rows;
    }

    /**
     * 修改移库合库记录
     *
     * @param wmsMove 移库合库记录
     * @return 结果
     */
    @Transactional
    @Override
    public int updateWmsMove(WmsMove wmsMove) {
        wmsMoveMapper.deleteWmsMoveDetailByMoveId(wmsMove.getMoveId());
        insertWmsMoveDetail(wmsMove);
        return wmsMoveMapper.updateWmsMove(wmsMove);
    }

    /**
     * 批量删除移库合库记录
     *
     * @param moveIds 需要删除的移库合库记录主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsMoveByMoveIds(Long[] moveIds) {
        wmsMoveMapper.deleteWmsMoveDetailByMoveIds(moveIds);
        return wmsMoveMapper.deleteWmsMoveByMoveIds(moveIds);
    }

    /**
     * 删除移库合库记录信息
     *
     * @param moveId 移库合库记录主键
     * @return 结果
     */
    @Transactional
    @Override
    public int deleteWmsMoveByMoveId(Long moveId) {
        wmsMoveMapper.deleteWmsMoveDetailByMoveId(moveId);
        return wmsMoveMapper.deleteWmsMoveByMoveId(moveId);
    }

    /**
     * 新增移库合库记录明细;原材料入库记录对应的明细信息信息
     *
     * @param wmsMove 移库合库记录对象
     */
    public void insertWmsMoveDetail(WmsMove wmsMove) {
        List<WmsMoveDetail> wmsMoveDetailList = wmsMove.getWmsMoveDetailList();
        Long moveId = wmsMove.getMoveId();
        if (StringUtils.isNotNull(wmsMoveDetailList)) {
            List<WmsMoveDetail> list = new ArrayList<WmsMoveDetail>();
            for (WmsMoveDetail wmsMoveDetail : wmsMoveDetailList) {
                wmsMoveDetail.setMoveId(moveId);
                list.add(wmsMoveDetail);
            }
            if (list.size() > 0) {
                wmsMoveMapper.batchWmsMoveDetail(list);
            }
        }
    }


    /**
     * 查询移库合库记录列表，Join warehouse,group
     *
     * @param wmsMove 移库合库记录
     * @return 移库合库记录
     */
    @Override
    public List<WmsMove> selectWmsMoveGroupJoinList(WmsMove wmsMove) {
        return wmsMoveMapper.selectWmsMoveGroupJoinList(wmsMove);
    }


    /**
     * 申请移库
     *
     * @param wmsMoveApplyVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int applyMove(WmsMoveApplyVo wmsMoveApplyVo) {
        String oriLocationCode = wmsMoveApplyVo.getOriLocationCode();
        String targetLocationCode = wmsMoveApplyVo.getTargetLocationCode();
        if (oriLocationCode.equals(targetLocationCode)) {
            throw new ServiceException("原库位与目标库位不能相同");
        }

        WmsBaseLocation oriLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(oriLocationCode);
        if (oriLocation == null) {
            throw new ServiceException("原库位不存在");
        }
        String oriLocationStatus = oriLocation.getLocationStatus();
        if (!oriLocationStatus.equals(WmsConstants.WMS_BASE_LOCATION_STATUS_NORMAL)) {
            throw new ServiceException("原库位已经锁定，不能进行移库");
        }

        WmsBaseLocation targetLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(targetLocationCode);
        if (targetLocation == null) {
            throw new ServiceException("目标库位不存在");
        }

        String targetLocationStatus = targetLocation.getLocationStatus();
        if (!targetLocationStatus.equals(WmsConstants.WMS_BASE_LOCATION_STATUS_NORMAL)) {
            throw new ServiceException("目标库位已经锁定，不能进行移库");
        }

        if (!oriLocation.getWarehouseId().equals(targetLocation.getWarehouseId())) {
            throw new ServiceException("原库位和目标库位需为一个仓库");
        }

        WmsBaseWarehouse baseWareHouse = wmsBaseWarehouseMapper.
                selectWmsBaseWarehouseByWarehouseId(oriLocation.getWarehouseId());
        if (!baseWareHouse.getWarehouseType().equals(WmsConstants.WMS_WAREHOUSE_TYPE_NORMAL)) {
            throw new ServiceException("请选择人工仓库的库位进行移库");
        }

        String warehouseInstockType = baseWareHouse.getWarehouseInstockType();
        List<WmsMove> toInsertedMoves = new ArrayList<>();
        Date currentDate = new Date();
        String userName = SecurityUtils.getUsername();
        if (warehouseInstockType.equals(WmsConstants.WMS_WAREHOUSE_INSTOCK_TYPE_RAW)) {//如果是原材料
            WmsRawStock queryRawStock = new WmsRawStock();
            queryRawStock.setLocationCode(oriLocationCode);
            List<WmsRawStock> wmsRawStocks = wmsRawStockMapper.selectWmsRawStockInList(queryRawStock);
            if (wmsRawStocks == null || wmsRawStocks.isEmpty()) {
                throw new ServiceException("原库位无库存信息，不能进行移库");
            }
            List<WmsRawStock> occupyRawStocks = wmsRawStocks.stream().filter
                            (e -> (e.getOccupyAmount().compareTo(BigDecimal.ZERO) > 0 || e.getFrozenAmount().compareTo(BigDecimal.ZERO) > 0))
                    .collect(Collectors.toList());
            if (occupyRawStocks != null && !occupyRawStocks.isEmpty()) {
                throw new ServiceException("原库位有占用库存信息，不能进行移库");
            }


            WmsRawStock queryTargetRawStock = new WmsRawStock();
            queryTargetRawStock.setLocationCode(targetLocationCode);
            List<WmsRawStock> targetRawStocks = wmsRawStockMapper.selectWmsRawStockInList(queryTargetRawStock);
            //移库时（movetype为1时）目标库位需要是空库位，合库时(movetype为2时)目标库位需要是非空库位
            if (wmsMoveApplyVo.getMoveType().equals(WmsConstants.WMS_MOVEMERGE_TYPE_MOVE)) {
                if (targetRawStocks != null && !targetRawStocks.isEmpty()) {
                    throw new ServiceException("目标库位有库存，不能进行移库");
                }
            } else {
                if (targetRawStocks == null || targetRawStocks.isEmpty()) {
                    throw new ServiceException("目标库位无库存，不能进行合库");
                }
            }

            toInsertedMoves = getMovesByRawStocks(wmsRawStocks, wmsMoveApplyVo, userName, currentDate);
        } else {//如果是成品
            WmsProductStock queryProductStock = new WmsProductStock();
            queryProductStock.setLocationCode(oriLocationCode);
            List<WmsProductStock> productStocks = wmsProductStockMapper.selectWmsProductStockInList(queryProductStock);
            if (productStocks == null || productStocks.isEmpty()) {
                throw new ServiceException("原库位无库存信息，不能进行移库");
            }
            List<WmsProductStock> occupyProductStocks = productStocks.stream().filter
                            (e -> (e.getOccupyAmount().compareTo(BigDecimal.ZERO) > 0 || e.getFrozenAmount().compareTo(BigDecimal.ZERO) > 0))
                    .collect(Collectors.toList());
            if (occupyProductStocks != null && !occupyProductStocks.isEmpty()) {
                throw new ServiceException("原库位有占用库存信息，不能进行移库");
            }

            //目标库位需要是空库位
            WmsProductStock queryTargetProductStock = new WmsProductStock();
            queryTargetProductStock.setLocationCode(targetLocationCode);
            List<WmsProductStock> targetProductStocks = wmsProductStockMapper.selectWmsProductStockInList(queryTargetProductStock);
            if (targetProductStocks != null && !targetProductStocks.isEmpty()) {
                throw new ServiceException("目标库位有库存，不能进行移库");
            }

            toInsertedMoves = getMovesByProductStocks(productStocks, wmsMoveApplyVo, userName, currentDate);
        }

        oriLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_MOVE_LOCK);
        oriLocation.setUpdateTime(currentDate);
        oriLocation.setUpdateBy(userName);
        wmsBaseLocationMapper.updateWmsBaseLocation(oriLocation);

        targetLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_MOVE_LOCK);
        targetLocation.setUpdateTime(currentDate);
        targetLocation.setUpdateBy(userName);
        wmsBaseLocationMapper.updateWmsBaseLocation(targetLocation);

        int rows = wmsMoveMapper.batchWmsMove(toInsertedMoves);

        return rows;
    }

    private List<WmsMove> getMovesByRawStocks(List<WmsRawStock> wmsRawStocks, WmsMoveApplyVo wmsMoveApplyVo,
                                              String userName, Date currentDate) {
        List<WmsMove> wmsMoveList = new ArrayList<>();
        String taskCode = Seq.getId(Seq.wmsMoveSeqType, Seq.wmsMoveSeqCode);
        wmsRawStocks.forEach(wmsRawStock -> {
            WmsMove wmsMove = new WmsMove();
            wmsMove.setInstockBatch(wmsRawStock.getInstockBatch());
            wmsMove.setMaterialId(wmsRawStock.getMaterialId());
            wmsMove.setWarehouseId(wmsRawStock.getWarehouseId());
            wmsMove.setOriLocationCode(wmsMoveApplyVo.getOriLocationCode());
            wmsMove.setTargetLocationCode(wmsMoveApplyVo.getTargetLocationCode());
            wmsMove.setPlanAmount(wmsRawStock.getTotalAmount());
            wmsMove.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_TOEXECUTE);
            wmsMove.setTaskCode(taskCode);
            wmsMove.setOperationType(WmsConstants.WMS_OPERATION_TYPE_MANUAL);
            wmsMove.setMoveWay(WmsConstants.WMS_MOVEMERGE_WAY_MANUAL);
            wmsMove.setMoveType(wmsMoveApplyVo.getMoveType());
            wmsMove.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
            wmsMove.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
            wmsMove.setApplyBy(userName);
            wmsMove.setApplyDate(currentDate);

            wmsMoveList.add(wmsMove);
        });
        return wmsMoveList;
    }

    private List<WmsMove> getMovesByProductStocks(List<WmsProductStock> wmsProductStocks, WmsMoveApplyVo wmsMoveApplyVo,
                                                  String userName, Date currentDate) {
        List<WmsMove> wmsMoveList = new ArrayList<>();
        String taskCode = Seq.getId(Seq.wmsMoveSeqType, Seq.wmsMoveSeqCode);
        wmsProductStocks.forEach(wmsProductStock -> {
            WmsMove wmsMove = new WmsMove();
            wmsMove.setInstockBatch(wmsProductStock.getProductBatch());
            wmsMove.setWarehouseId(wmsProductStock.getWarehouseId());
            wmsMove.setOriLocationCode(wmsMoveApplyVo.getOriLocationCode());
            wmsMove.setTargetLocationCode(wmsMoveApplyVo.getTargetLocationCode());
            wmsMove.setMaterialId(wmsProductStock.getProductId());
            wmsMove.setPlanAmount(wmsProductStock.getTotalAmount());
            wmsMove.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_TOEXECUTE);
            wmsMove.setTaskCode(taskCode);
            wmsMove.setOperationType(WmsConstants.WMS_OPERATION_TYPE_MANUAL);
            wmsMove.setMoveWay(WmsConstants.WMS_MOVEMERGE_WAY_MANUAL);
            wmsMove.setMoveType(wmsMoveApplyVo.getMoveType());
            wmsMove.setAuditStatus(WmsConstants.WMS_AUDIT_STATUS_PASS);
            wmsMove.setExecuteStatus(WmsConstants.WMS_EXECUTE_STATUS_TOEXECUTE);
            wmsMove.setApplyBy(userName);
            wmsMove.setApplyDate(currentDate);

            wmsMoveList.add(wmsMove);
        });
        return wmsMoveList;
    }


    /**
     * 查询移库合库记录列表，Join material,warehouse
     *
     * @param wmsMove 移库合库记录
     * @return 移库合库记录
     */
    @Override
    public List<WmsMove> selectWmsMoveJoinList(WmsMove wmsMove) {
        return wmsMoveMapper.selectWmsMoveJoinList(wmsMove);
    }


    public void batchInsertMoveDetails(List<WmsMoveDetail> wmsMoveDetailList, Long moveId, String userName, Date currentDate) {
        wmsMoveDetailList.forEach(moveDetail -> {
            moveDetail.setMoveId(moveId);
            moveDetail.setCreateBy(userName);
            moveDetail.setCreateDate(currentDate);
        });
        wmsMoveMapper.batchWmsMoveDetail(wmsMoveDetailList);
    }


    /**
     * 获取移库合库记录明细，join material
     *
     * @param wmsMoveDetail
     * @return
     */
    @Override
    public List<WmsMoveDetail> selectWmsMoveDetailJoinList(WmsMoveDetail wmsMoveDetail) {
        return wmsMoveDetailMapper.selectWmsMoveDetailJoinList(wmsMoveDetail);
    }

    /**
     * 人工移库出库
     *
     * @param wmsMoveVo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int moveOutstock(WmsMoveVo wmsMoveVo) {
        String taskCode = wmsMoveVo.getTaskCode();
        String materialBarcode = wmsMoveVo.getMaterialBarcode();
        String locationCode = wmsMoveVo.getLocationCode();
        BigDecimal applyQty = wmsMoveVo.getApplyQty();
        if (applyQty.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("出库数量需大于0");
        }

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

        String batchFlag = baseBarcodeInfo.getBatchFlag();
        if (!batchFlag.equals(MesConstants.IS_BATCH)) {
            if (applyQty.compareTo(BigDecimal.ONE) > 0) {
                throw new ServiceException("出库数量需等于1");
            }
        }

        WmsBaseLocation oriLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(locationCode);
        if (oriLocation == null) {
            throw new ServiceException("库位编码有误");
        }

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

        WmsMove queryMove = new WmsMove();
        queryMove.setTaskCode(taskCode);
//        queryMove.setInstockBatch(batchCode);
        queryMove.setOriLocationCode(locationCode);
        List<WmsMove> wmsMoveList = wmsMoveMapper.selectWmsMoveList(queryMove);
        if (wmsMoveList == null || wmsMoveList.isEmpty()) {
            throw new ServiceException("没有此移库信息");
        }

        WmsMove wmsMove = wmsMoveList.stream().filter(move ->
                move.getInstockBatch().equals(batchCode)).findFirst().get();
        if (wmsMove == null) {
            throw new ServiceException("没有此移库信息");
        }

        String executeStatus = wmsMove.getExecuteStatus();
        if (executeStatus.equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_OUTSTOCK_FINISH)) {
            throw new ServiceException("此批次已移库出库完成，不能再出库");
        }
        if (executeStatus.equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH)) {
            throw new ServiceException("此批次已移库入库完成，不能再出库");
        }

        BigDecimal planAmount = wmsMove.getPlanAmount();
        BigDecimal realOutstockAmount = wmsMove.getRealOutstockAmount();
        BigDecimal updateRealOutstockAmount = realOutstockAmount.add(applyQty);

        if (updateRealOutstockAmount.compareTo(planAmount) > 0) {
            throw new ServiceException("数量不能大于" + planAmount.subtract(realOutstockAmount));
        }

        WmsMoveDetail existedMoveDetail = wmsMoveDetailMapper.selectWmsMoveDetailByMoveIdAndBarCode(wmsMove.getMoveId(), materialBarcode);
        if (existedMoveDetail != null) {
            throw new ServiceException("此物料条码已经出库，不能重复出库");
        }

        String barcodeType = baseBarcodeInfo.getBarcodeType();
        if (barcodeType.equals(MesConstants.MES_BARCODE_TYPE_RAW)) {//如果是原材料
            moveOutUpdateRawStock(locationCode, batchCode, applyQty, userName, currentDate);
        } else {//如果是成品
            moveOutUpdateProductStock(locationCode, batchCode, applyQty, userName, currentDate);
        }

        //插入移库合库明细记录
        insertMoveDetail(wmsMove.getMoveId(), baseBarcodeInfo, applyQty, userName, currentDate);

        //更新移库合库记录，并判断是否解锁库位
        outstockUpdateWmsMove(wmsMove, wmsMoveList, oriLocation, applyQty, userName, currentDate);

        return 1;
    }


    public void insertMoveDetail(Long moveId, MesBaseBarcodeInfo baseBarcodeInfo, BigDecimal applyQty,
                                 String userName, Date currentDate) {
        WmsMoveDetail toInsertedWmsMoveDetail = new WmsMoveDetail();
        toInsertedWmsMoveDetail.setMoveId(moveId);
        toInsertedWmsMoveDetail.setMaterialBarcode(baseBarcodeInfo.getBarcodeInfo());
        toInsertedWmsMoveDetail.setInstockBatch(baseBarcodeInfo.getBatchCode());
        toInsertedWmsMoveDetail.setMaterialId(baseBarcodeInfo.getMaterialId());
        toInsertedWmsMoveDetail.setPlanAmount(applyQty);
        toInsertedWmsMoveDetail.setRealAmount(applyQty);
        toInsertedWmsMoveDetail.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_OUTSTOCK_FINISH);
        toInsertedWmsMoveDetail.setExecutePerson(userName);
        toInsertedWmsMoveDetail.setExecuteTime(currentDate);
        wmsMoveDetailMapper.insertWmsMoveDetail(toInsertedWmsMoveDetail);
    }

    /**
     * 在移库出库时更新移库合库记录，判断是否解锁原库位
     *
     * @param wmsMove
     * @param wmsMoveList
     * @param oriLocation
     * @param applyQty
     * @param userName
     * @param currentDate
     */
    public void outstockUpdateWmsMove(WmsMove wmsMove, List<WmsMove> wmsMoveList, WmsBaseLocation oriLocation,
                                      BigDecimal applyQty, String userName, Date currentDate) {
        BigDecimal planAmount = wmsMove.getPlanAmount();
        BigDecimal realOutstockAmount = wmsMove.getRealOutstockAmount();
        BigDecimal remainingAmount = planAmount.subtract(realOutstockAmount);
        if (applyQty.compareTo(remainingAmount) < 0) {
            wmsMove.setRealOutstockAmount(realOutstockAmount.add(applyQty));
            wmsMove.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_EXECUTING);
        } else {
            wmsMove.setRealOutstockAmount(planAmount);
            wmsMove.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_OUTSTOCK_FINISH);
            boolean allOustocked = true;//用来判断原库位是否都已出库完成
            for (WmsMove move : wmsMoveList) {
                if (!move.getMoveId().equals(wmsMove.getMoveId())) {
                    if (move.getExecuteStatus().equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_TOEXECUTE)
                            || move.getExecuteStatus().equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_EXECUTING)) {
                        allOustocked = false;
                    }
                }
            }

            //如果都已出库完成，解锁库位
            if (allOustocked) {
                oriLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_NORMAL);
                oriLocation.setUpdateBy(userName);
                oriLocation.setUpdateTime(currentDate);
                wmsBaseLocationMapper.updateWmsBaseLocation(oriLocation);
            }
        }

        if (wmsMove.getBeginTime() == null) {
            wmsMove.setBeginTime(currentDate);
        }

        wmsMove.setUpdateDate(currentDate);
        wmsMove.setUpdateBy(userName);
        wmsMoveMapper.updateWmsMove(wmsMove);
    }

    public void moveOutUpdateRawStock(String locationCode, String batchCode, BigDecimal applyQty,
                                      String userName, Date currentDate) {
        WmsRawStock wmsRawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, batchCode);
        if (wmsRawStock == null) {
            throw new ServiceException("原库位无库存信息，不能进行移库");
        }

        BigDecimal totalAmount = wmsRawStock.getTotalAmount() == null ? BigDecimal.ZERO : wmsRawStock.getTotalAmount();
//            BigDecimal occupyAmount = wmsRawStock.getOccupyAmount() == null ? BigDecimal.ZERO : wmsRawStock.getOccupyAmount();//占用的不能移库
//            BigDecimal frozenAmount = wmsRawStock.getFrozenAmount() == null ? BigDecimal.ZERO : wmsRawStock.getFrozenAmount();//冻结的不能移库
//            BigDecimal availableAmount = totalAmount.subtract(occupyAmount).subtract(frozenAmount);
        if (applyQty.compareTo(totalAmount) > 0) {
            throw new ServiceException("移库出库数量不能大于" + totalAmount);
        }

        totalAmount = totalAmount.subtract(applyQty);
        if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
            wmsRawStockMapper.deleteWmsRawStockByRawStockId(wmsRawStock.getRawStockId());
        } else {
            wmsRawStock.setTotalAmount(totalAmount);
            wmsRawStock.setUpdateBy(userName);
            wmsRawStock.setUpdateDate(currentDate);
            wmsRawStockMapper.updateWmsRawStock(wmsRawStock);
        }

    }


    public void moveOutUpdateProductStock(String locationCode, String batchCode, BigDecimal applyQty,
                                          String userName, Date currentDate) {

        WmsProductStock wmsProductStock = wmsProductStockMapper.selectProductStockByBatch(batchCode);
        if (wmsProductStock == null) {
            throw new ServiceException("原库位无库存信息，不能进行移库");
        }

        BigDecimal totalAmount = wmsProductStock.getTotalAmount() == null ? BigDecimal.ZERO : wmsProductStock.getTotalAmount();
//            BigDecimal occupyAmount = wmsProductStock.getOccupyAmount() == null ? BigDecimal.ZERO : wmsProductStock.getOccupyAmount();//占用的不能移库
//            BigDecimal frozenAmount = wmsProductStock.getFrozenAmount() == null ? BigDecimal.ZERO : wmsProductStock.getFrozenAmount();//冻结的不能移库
//            BigDecimal availableAmount = totalAmount.subtract(occupyAmount).subtract(frozenAmount);
        if (applyQty.compareTo(totalAmount) > 0) {
            throw new ServiceException("移库出库数量不能大于" + totalAmount);
        }

        totalAmount = totalAmount.subtract(applyQty);
        if (totalAmount.compareTo(BigDecimal.ZERO) == 0) {
            wmsProductStockMapper.deleteWmsProductStockByProductStockId(wmsProductStock.getProductStockId());
        } else {
            wmsProductStock.setTotalAmount(totalAmount);
            wmsProductStock.setUpdateBy(userName);
            wmsProductStock.setUpdateDate(currentDate);
            wmsProductStockMapper.updateWmsProductStock(wmsProductStock);
        }
    }


    /**
     * 人工移库入库
     *
     * @param wmsMoveVo
     * @return
     */
    public int moveInstock(WmsMoveVo wmsMoveVo) {
        String taskCode = wmsMoveVo.getTaskCode();
        String materialBarcode = wmsMoveVo.getMaterialBarcode();
        String locationCode = wmsMoveVo.getLocationCode();
        BigDecimal applyQty = wmsMoveVo.getApplyQty();
        if (applyQty.compareTo(BigDecimal.ZERO) <= 0) {
            throw new ServiceException("入库数量需大于0");
        }

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

        WmsBaseLocation targetLocation = wmsBaseLocationMapper.selectWmsBaseLocationByLocationCode(locationCode);
        if (targetLocation == null) {
            throw new ServiceException("库位编码有误");
        }

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

        String batchCode = baseBarcodeInfo.getBatchCode();

        WmsMove queryMove = new WmsMove();
        queryMove.setTaskCode(taskCode);
//        queryMove.setInstockBatch(batchCode);
        queryMove.setTargetLocationCode(locationCode);
        List<WmsMove> wmsMoveList = wmsMoveMapper.selectWmsMoveList(queryMove);
        if (wmsMoveList == null || wmsMoveList.isEmpty()) {
            throw new ServiceException("没有此移库信息");
        }

        WmsMove wmsMove = wmsMoveList.stream().filter(move ->
                move.getInstockBatch().equals(batchCode)).findFirst().get();
        if (wmsMove == null) {
            throw new ServiceException("没有此移库信息");
        }

        String executeStatus = wmsMove.getExecuteStatus();
        if (executeStatus.equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH)) {
            throw new ServiceException("此批次已移库入库完成，不能再入库");
        }

        BigDecimal planAmount = wmsMove.getPlanAmount();
        BigDecimal realInstockAmount = wmsMove.getRealInstockAmount();
        BigDecimal updateRealInstockAmount = realInstockAmount.add(applyQty);

        if (updateRealInstockAmount.compareTo(planAmount) > 0) {
            throw new ServiceException("数量不能大于" + planAmount.subtract(realInstockAmount));
        }

        WmsMoveDetail existedMoveDetail = wmsMoveDetailMapper.selectWmsMoveDetailByMoveIdAndBarCode(wmsMove.getMoveId(), materialBarcode);
        if (existedMoveDetail == null) {
            throw new ServiceException("此物料条码还未移库出库，不能移库入库");
        }
        if (existedMoveDetail.getExecuteStatus().equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH)) {
            throw new ServiceException("此物料条码已移库入库，不能重复入库");
        }
        if (!existedMoveDetail.getExecuteStatus().equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_OUTSTOCK_FINISH)) {
            throw new ServiceException("此物料条码还未移库出库，不能移库入库");
        }
        if (existedMoveDetail.getRealAmount().compareTo(applyQty) != 0) {
            throw new ServiceException("数量需等于" + existedMoveDetail.getRealAmount());
        }

        String barcodeType = baseBarcodeInfo.getBarcodeType();
        //更新库存
        if (barcodeType.equals(MesConstants.MES_BARCODE_TYPE_RAW)) {//如果是原材料
            moveInUpdateRawStock(targetLocation, baseBarcodeInfo, applyQty, userName, currentDate);
        } else {//如果是成品
            moveInUpdateProductStock(targetLocation, baseBarcodeInfo, applyQty, userName, currentDate);
        }

        //更新移库合库明细记录
        existedMoveDetail.setRealInstockAmount(applyQty);
        existedMoveDetail.setExecuteEndTime(currentDate);
        existedMoveDetail.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH);
        existedMoveDetail.setUpdateDate(currentDate);
        existedMoveDetail.setUpdateBy(userName);
        existedMoveDetail.setRealInstockAmount(applyQty);
        wmsMoveDetailMapper.updateWmsMoveDetail(existedMoveDetail);

        //更新移库合库记录，并判断是否解锁库位
        instockUpdateWmsMove(wmsMove, wmsMoveList, targetLocation, applyQty, userName, currentDate);

        return 1;
    }


    public void moveInUpdateRawStock(WmsBaseLocation location, MesBaseBarcodeInfo mesBaseBarcodeInfo,
                                     BigDecimal applyQty, String userName, Date currentDate) {
        String batchCode = mesBaseBarcodeInfo.getBatchCode();
        String locationCode = location.getLocationCode();
        WmsRawStock rawStock = wmsRawStockMapper.selectRawStockByLocationAndBatch(locationCode, batchCode);
        if (rawStock != null) {
            rawStock.setTotalAmount(rawStock.getTotalAmount().add(applyQty));
            rawStock.setUpdateDate(currentDate);
            rawStock.setUpdateBy(userName);
            wmsRawStockMapper.updateWmsRawStock(rawStock);
        } else {
            rawStock = new WmsRawStock();
            rawStock.setTotalAmount(applyQty);
            rawStock.setLocationCode(locationCode);
            rawStock.setInstockBatch(mesBaseBarcodeInfo.getBatchCode());
            rawStock.setWarehouseId(location.getWarehouseId());
            rawStock.setWarehouseFloor(location.getWarehouseFloor());
            rawStock.setStockType(WmsConstants.RWA_STOCK_STOCK_TYPE_RAW);
            rawStock.setMaterialId(mesBaseBarcodeInfo.getMaterialId());
            rawStock.setInstockDate(mesBaseBarcodeInfo.getAcceptedDate());//条码中的入库时间
            rawStock.setLastOutstockTime(mesBaseBarcodeInfo.getLastOutstockDate());
//            rawStock.setQualityStatus();
            rawStock.setCompleteFlag(WmsConstants.WMS_RAW_STOCK_COMPLETE_FLAG_YES);
            rawStock.setCreateDate(currentDate);
            rawStock.setCreateBy(userName);
            wmsRawStockMapper.insertWmsRawStock(rawStock);
        }
    }


    public void moveInUpdateProductStock(WmsBaseLocation location, MesBaseBarcodeInfo mesBaseBarcodeInfo,
                                         BigDecimal applyQty, String userName, Date currentDate) {
        String materialBarcode = mesBaseBarcodeInfo.getBarcodeInfo();
        String locationCode = location.getLocationCode();

        WmsProductStock productStock = new WmsProductStock();
        productStock.setTotalAmount(applyQty);
        productStock.setLocationCode(locationCode);
        productStock.setProductBatch(materialBarcode);
        productStock.setWarehouseId(location.getWarehouseId());
        productStock.setWarehouseFloor(location.getWarehouseFloor());
        productStock.setStockType(mesBaseBarcodeInfo.getBarcodeType());
        productStock.setProductId(mesBaseBarcodeInfo.getMaterialId());
        productStock.setInstockDate(mesBaseBarcodeInfo.getAcceptedDate());//条码中的入库时间
        productStock.setPlanCode(mesBaseBarcodeInfo.getPlanCode());
        productStock.setPlanDetailCode(mesBaseBarcodeInfo.getPlanDetailCode());
        productStock.setSaleOrderId(mesBaseBarcodeInfo.getSaleOrderId());
        productStock.setSaleorderCode(mesBaseBarcodeInfo.getSaleorderCode());
//            rawStock.setQualityStatus();
        productStock.setCreateDate(currentDate);
        productStock.setCreateBy(userName);
        wmsProductStockMapper.insertWmsProductStock(productStock);
    }


    /**
     * 在移库入库时更新移库合库记录，判断是否解锁目标库位
     *
     * @param wmsMove
     * @param wmsMoveList
     * @param oriLocation
     * @param applyQty
     * @param userName
     * @param currentDate
     */
    public void instockUpdateWmsMove(WmsMove wmsMove, List<WmsMove> wmsMoveList, WmsBaseLocation targetLocation,
                                     BigDecimal applyQty, String userName, Date currentDate) {
        BigDecimal planAmount = wmsMove.getPlanAmount();
        BigDecimal realInstockAmount = wmsMove.getRealInstockAmount();
        BigDecimal remainingAmount = planAmount.subtract(realInstockAmount);
        if (applyQty.compareTo(remainingAmount) < 0) {
            wmsMove.setRealInstockAmount(realInstockAmount.add(applyQty));
        } else {
            wmsMove.setRealInstockAmount(planAmount);
            wmsMove.setExecuteStatus(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH);
            wmsMove.setEndTime(currentDate);
            boolean allInstocked = true;//用来判断原库位是否都已入库完成
            for (WmsMove move : wmsMoveList) {
                if (!move.getMoveId().equals(wmsMove.getMoveId())) {
                    if (!move.getExecuteStatus().equals(WmsConstants.WMS_MOVE_EXECUTE_STATUS_INSTOCK_FINISH)) {
                        allInstocked = false;
                    }
                }
            }

            //如果都已入库完成，解锁库位
            if (allInstocked) {
                targetLocation.setLocationStatus(WmsConstants.WMS_BASE_LOCATION_STATUS_NORMAL);
                targetLocation.setUpdateBy(userName);
                targetLocation.setUpdateTime(currentDate);
                wmsBaseLocationMapper.updateWmsBaseLocation(targetLocation);
            }
        }

        wmsMove.setUpdateDate(currentDate);
        wmsMove.setUpdateBy(userName);
        wmsMoveMapper.updateWmsMove(wmsMove);
    }
}
