package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.shkj.common.core.domain.Result;
import com.shkj.common.utils.DateUtils;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.common.utils.StringUtils;
import com.shkj.wms.bo.BaseContainerCallBo;
import com.shkj.wms.bo.SysStockDetailAddBo;
import com.shkj.wms.bo.SysStockDetailEditBo;
import com.shkj.wms.bo.SysStockDetailQueryBo;
import com.shkj.wms.domain.*;
import com.shkj.wms.enums.LocationPlanTypeEnum;
import com.shkj.wms.enums.PlanStatusEnum;
import com.shkj.wms.mapper.SysStockDetailMapper;
import com.shkj.wms.service.*;
import com.shkj.wms.utils.IntIdUtil;
import com.shkj.wms.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
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 lch
 * @date 2023-05-05
 */
@Slf4j
@Service
public class SysStockDetailServiceImpl extends ServiceImpl<SysStockDetailMapper, SysStockDetail> implements ISysStockDetailService {
    @Autowired
    private IBaseLocationService iBaseLocationService;

    @Autowired
    private ISysStockDetailQrcodeService iSysStockDetailQrcodeService;

    @Autowired
    private IBaseMoldService baseMoldService;

    @Autowired
    private IBaseGoodsDataService iBaseGoodsDataService;

    @Autowired
    private IBusinDataTaskService iBusinDataTaskService;
    @Autowired
    private BaseBarcodesOutServiceImpl baseBarcodesOutService;

    @Autowired
    @Lazy
    private IBusinStockInvService businStockInvService;

    @Autowired
    private IBaseContainerService baseContainerService;

    @Override
    public Result<SysStockDetailVo> queryById(Long id) {
        SysStockDetail db = this.baseMapper.selectById(id);
        SysStockDetailVo vo = BeanUtil.toBean(db, SysStockDetailVo.class);
        return Result.ok().data(vo);
    }


    @Override
    public Result<SysStockDetailVo> queryByLocation(Long locationId) {
        SysStockDetailQueryBo bo = new SysStockDetailQueryBo();
//        bo.setLocationId(locationId);
        List<SysStockDetailVo> detailVos = this.queryList(bo);
        if (detailVos.size() > 0) {
            return Result.ok().data(detailVos.get(0));
        } else {
            return Result.err();
        }
    }

    @Override
    public List<SysStockDetailVo> queryList(SysStockDetailQueryBo bo) {
        LambdaQueryWrapper<SysStockDetail> lqw = Wrappers.lambdaQuery();
//        lqw.eq(bo.getBranchId() != null, SysStockDetail::getBranchId, bo.getBranchId());
//        lqw.eq(bo.getStorageId() != null, SysStockDetail::getStorageId, bo.getStorageId());
//        lqw.eq(bo.getAreaId() != null, SysStockDetail::getAreaId, bo.getAreaId());
//        lqw.eq(bo.getContainerCode() != null, SysStockDetail::getContainerCode, bo.getContainerCode());
//        lqw.eq(bo.getQty() != null, SysStockDetail::getQty, bo.getQty());
//        lqw.eq(bo.getLocationId() != null, SysStockDetail::getLocationId, bo.getLocationId());
//        lqw.eq(bo.getInTime() != null, SysStockDetail::getInTime, bo.getInTime());
//        lqw.eq(bo.getOutTime() != null, SysStockDetail::getOutTime, bo.getOutTime());
        List<SysStockDetailVo> voList = entity2Vo(this.list(lqw));
        return voList;

    }

    /**
     * 实体类转化成视图对象
     *
     * @param collection 实体类集合
     * @return
     */
    private List<SysStockDetailVo> entity2Vo(Collection<SysStockDetail> collection) {
        List<SysStockDetailVo> voList = collection.stream()
                .map(any -> BeanUtil.toBean(any, SysStockDetailVo.class))
                .collect(Collectors.toList());
        if (collection instanceof Page) {
            Page<SysStockDetail> page = (Page<SysStockDetail>) collection;
            Page<SysStockDetailVo> pageVo = new Page<>();
            BeanUtil.copyProperties(page, pageVo);
            pageVo.addAll(voList);
            voList = pageVo;
        }
        return voList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> insertByAddBo(SysStockDetailAddBo bo) {
        SysStockDetail add = BeanUtil.toBean(bo, SysStockDetail.class);
        this.save(add);
        return Result.ok();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> updateByEditBo(SysStockDetailEditBo bo) {
        SysStockDetail one = getById(bo.getId());
        if (one == null) {
            return Result.err().msg("不存在");
        }
        SysStockDetail update = BeanUtil.toBean(bo, SysStockDetail.class);
        this.updateById(update);
        return Result.ok();
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result<Boolean> deleteWithValidById(List<Long> ids, Boolean isValid) {
        LambdaQueryWrapper<SysStockDetail> wrapper = new LambdaQueryWrapper<SysStockDetail>().in(SysStockDetail::getId, ids)
                .eq(SysStockDetail::getBranchId, SecurityUtils.getCurrentBranchId());
        this.remove(wrapper);
        return Result.ok();
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> productDepositDetail(Long locationId, Long containerId, String batch, String isPuch, List<Map<String, String>> goods, Long storageCode) {

        //获取库位上是否有物料信息
        SysStockDetailQueryBo stockDetailQueryBo = new SysStockDetailQueryBo();
        List<SysStockDetailVo> sysStockDetailVos = this.queryList(stockDetailQueryBo);
        if (sysStockDetailVos.size() > 0) {
            return Result.err().msg("该货位已存在库存信息");
        } else {
            for (Map<String, String> good : goods) {
                Result<BaseLocationVo> baseLocationVoResult = iBaseLocationService.queryById(locationId);
                BaseLocationVo locationVo = baseLocationVoResult.getData();
                SysStockDetail sysStockDetail = new SysStockDetail();
                sysStockDetail.setBranchId(locationVo.getBranchId());
                sysStockDetail.setStorageId(storageCode);
                sysStockDetail.setAreaId(locationVo.getAreaId());
//                sysStockDetail.setTunnel(locationVo.getTunnel());
                sysStockDetail.setContainerId(containerId);
                sysStockDetail.setQty(BigDecimal.valueOf(goods.size()));
                sysStockDetail.setLocationId(locationId);
                if (StrUtil.isNotBlank(good.get("goodsNo"))) {
                    sysStockDetail.setMoldNo(good.get("goodsNo"));
                }
                if (StrUtil.isNotBlank(good.get("qrCode"))) {
                    sysStockDetail.setBarcode(good.get("qrCode"));
                }
                this.baseMapper.insert(sysStockDetail);
                String status = "1";
                if ("1".equals(isPuch)) {
                    status = "3";
                }
                //更新库位状态
                iBaseLocationService.changeLocationStatus(locationId, status);

                return iSysStockDetailQrcodeService.depositGoods(sysStockDetail.getId(), goods);
            }
        }
        return Result.ok();
    }

    @Override
    public List<SysStockDetailConVo> StockInquiry(SysStockDetailQueryBo bo) {
        return this.baseMapper.StockInquiry(bo);
    }

    @Override
    public List<SysStockDetailConVo> StockInquiryPda(SysStockDetailQueryBo bo) {
        return this.baseMapper.StockInquiryPda(bo);
    }


    /**
     * 找到空货位 库存表中没有数据、或者有数据并且和当前托盘保持一致
     *
     * @param containerId
     * @param currentBranchId 当前分支id
     * @return {@code StockDetailLocationVo}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StockDetailLocationVo findEmptyLocation(Long containerId, Long currentBranchId) {
        log.info("findEmptyLocation  = {}", containerId);
        List<StockDetailLocationVo> locationVoList = this.baseMapper.findLocation(currentBranchId);
        if (CollectionUtils.isEmpty(locationVoList)) {
            return null;
        }

        // 找空货位是需要找库存表没有记录、或者有记录并且所有的托盘id和当前相等
        locationVoList = locationVoList.stream()
                .filter(x ->
                        CollectionUtils.isEmpty(x.getStockDetailList()) ||
                                x.getStockDetailList().stream().allMatch(y -> Objects.equals(y.getId(), null)) ||
                                x.getStockDetailList().stream().allMatch(y -> Objects.equals(y.getContainerId(), containerId))
                ).collect(Collectors.toList());

        StockDetailLocationVo empty = locationVoList.stream()
                .filter(x -> CollectionUtils.isEmpty(x.getStockDetailList()) ||
                        x.getStockDetailList().stream()
                                .map(y -> (y.getQty() == null ? BigDecimal.ZERO : y.getQty()).add((y.getInQty() == null ? BigDecimal.ZERO : y.getInQty())))
                                .reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(BigDecimal.ZERO) == 0)
                .findFirst().orElse(null);
        return empty;
//        List<StockDetailLocationVo> list = new ArrayList();
//
//
//
//
//        for (StockDetailLocationVo vo : locationVoList) {
//            if (CollectionUtils.isEmpty(vo.getStockDetailList())) {
//                list.add(vo);
//                break;
//            } else if (vo.getStockDetailList().stream()
//                    .map(x -> (x.getQty() == null ? BigDecimal.ZERO : x.getQty()).add((x.getInQty() == null ? BigDecimal.ZERO : x.getInQty())))
//                    .reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(BigDecimal.ZERO) == 0) {
//                list.add(vo);
//                break;
//            }
//            continue;
//        }
////        list = list.stream()
////                .sorted(Comparator.comparing(x -> new BigDecimal(x.getRoute()))).collect(Collectors.toList());
////        if (CollectionUtils.isEmpty(list)) {
////            return null;
////        }
//        return list.get(0);

    }

    /**
     * 呼叫空托盘是库存表必须有数据 而且库存为0
     *
     * @param containerCode 托盘代码
     * @return {@link StockDetailLocationVo}
     */
    @Override
    public StockDetailLocationVo findLocationNotContainerCode(String containerCode) {
        // 呼叫空托盘是库存表必须有数据 而且库存为0
        List<StockDetailLocationVo> locationVoList = this.baseMapper.findLocation(SecurityUtils.getCurrentBranchId());

        locationVoList = locationVoList.stream()
                .filter(x ->
                        CollectionUtils.isNotEmpty(x.getStockDetailList()) &&
                                x.getStockDetailList().stream().allMatch(y -> !Objects.equals(y.getId(), null))
                ).filter(x ->
                        x.getStockDetailList().stream().allMatch(y -> StringUtils.isBlank(containerCode) ||
                                !Objects.equals(y.getContainerCode(), containerCode))
                ).collect(Collectors.toList());

        if (CollectionUtils.isEmpty(locationVoList)) {
            return null;
        }
        StockDetailLocationVo empty = locationVoList.stream()
                .filter(x -> CollectionUtils.isEmpty(x.getStockDetailList()) ||
                        x.getStockDetailList().stream()
                                .map(y -> (y.getQty() == null ? BigDecimal.ZERO : y.getQty()).add((y.getInQty() == null ? BigDecimal.ZERO : y.getInQty())))
                                .reduce(BigDecimal.ZERO, BigDecimal::add).compareTo(BigDecimal.ZERO) == 0)
//                .sorted(Comparator.comparing(x -> x.getHeight()))
                .findFirst().orElse(null);
        if (empty != null) {
            log.info("呼叫的货位id信息 = {}", empty.getId());
            return empty;
        }
        //todo 下面注释是获取模具最小体积的托盘
//        return locationVoList.stream()
//                .sorted(Comparator.comparing(x -> x.getStockDetailList().stream()
//                        .map(y ->
//                                (y.getQty().add(y.getInQty())).multiply(y.getLength().multiply(y.getWidth()).multiply(y.getHeight()))).reduce(BigDecimal.ZERO, BigDecimal::add)
//                ))
//                .findFirst().orElse(null);
        return null;
    }

    @Override
    public StockDetailMoldVo findLocationNotContainerCode(BaseContainerCallBo bo) {
        //查询可用的托盘
        StockDetailMoldVo locationByModqty = this.baseMapper.findLocationByModqty(bo);
        return locationByModqty;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByLocationId(Long locationId) {
        log.info("空货位出库了 需要删除 = {}", locationId);
        LambdaQueryWrapper<SysStockDetail> wrapper = new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getLocationId, locationId)
                .eq(SysStockDetail::getQty, BigDecimal.ZERO)
                .eq(SysStockDetail::getInQty, BigDecimal.ZERO)
                .eq(SysStockDetail::getOutQty, BigDecimal.ZERO);
        remove(wrapper);
    }

    @Override
    public void deleteByContainerCode(Long containerId) {
        LambdaQueryWrapper<SysStockDetail> wrapper = new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getContainerId, containerId)
                .eq(SysStockDetail::getQty, BigDecimal.ZERO)
                .eq(SysStockDetail::getInQty, BigDecimal.ZERO)
                .eq(SysStockDetail::getOutQty, BigDecimal.ZERO);
        remove(wrapper);
    }

    @Override
    public Result<List<SysStockAndInOutVo>> getPutInOutStockQty() {
      return  Result.ok().data(this.baseMapper.getPutInOutStockQty());
    }

    @Override
    public Result<List<SysStockByAreaVo>> getInventoryManagement(){
        List<SysStockAndInOutVo> putInOutStockQtyList = this.baseMapper.getPutInOutStockQty();
        int stockQty =0;
        for (SysStockAndInOutVo sysStockAndInOutVo : putInOutStockQtyList) {
            if (sysStockAndInOutVo.getType().equals("stock")){
                stockQty=sysStockAndInOutVo.getQty();
            }
        }

        List<SysStockByAreaVo> inventoryManagement = this.baseMapper.getInventoryManagement();
        if (stockQty !=0){
            for (SysStockByAreaVo sysStockByAreaVo : inventoryManagement) {
                int qty = sysStockByAreaVo.getQty();
                float ratio =(float)qty / stockQty*100;
                BigDecimal bigDecimal = BigDecimal.valueOf(ratio).setScale(2, BigDecimal.ROUND_HALF_UP);
                sysStockByAreaVo.setRatio(bigDecimal.toString());
            }
        }
        return  Result.ok().data(inventoryManagement);
    }

    @Override
    public Result<List<SysStockWeightByAreaVo>> getInvWeightManagement() {

        List<SysStockWeightByAreaVo> sysStockWeightByAreaVos = this.baseMapper.getInvWeightManagement();
        double weigths = sysStockWeightByAreaVos.stream().mapToDouble(x -> x.getWeight()).sum();
        if (weigths != 0){
            for (SysStockWeightByAreaVo sysStockWeightByAreaVo : sysStockWeightByAreaVos) {
                Double weigth = sysStockWeightByAreaVo.getWeight();
                Double ratio =weigth/weigths*100;
                BigDecimal bigDecimal = BigDecimal.valueOf(ratio).setScale(2, BigDecimal.ROUND_HALF_UP);
                sysStockWeightByAreaVo.setRatio(bigDecimal.toString());
            }
        }

        return Result.ok().data(sysStockWeightByAreaVos);
    }


    @Override
    public Result<List<SysStockByReteVo>> getLocationUsageRate(){
        List<SysStockByReteVo> locationUsageRate = this.baseMapper.getLocationUsageRate();
        int counts =507;

        if (counts>0){
            for (SysStockByReteVo sysStockByReteVo : locationUsageRate) {
                int qty = sysStockByReteVo.getQty();
                float ratio = (float) qty/counts*100;
                BigDecimal bigDecimal = BigDecimal.valueOf(ratio).setScale(2, BigDecimal.ROUND_HALF_UP);
                sysStockByReteVo.setRatio(bigDecimal.toString());
            }
        }
        return Result.ok().data(locationUsageRate);

    }

    @Override
    public Integer getLocationMoldQty(Long locationId) {
        return baseMapper.getLocationMoldQty(locationId);
    }


    /**
     * 入库 或者回库、这里只能找新货位或者跟当前托盘相同的货位
     *
     * @param containerId         托盘id
     * @param baseMoldBarcodeList 基模具条码列表中
     * @param branchId            分支id
     * @param isHigh
     * @return {@link StockDetailLocationVo}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StockDetailLocationVo findLocation(Long containerId, List<BaseMold> baseMoldBarcodeList, Long branchId, boolean isHigh) {
        log.info("findLocation  = {}", containerId);
        //入库根据托盘上模具最大长宽高尺寸来限定能存放的货位，在能存放的货位里按拣货顺序从小到大依次存放。
        List<StockDetailLocationVo> locationVoList = this.baseMapper.findLocation(branchId);
        // 这里只能找新货位或者跟当前托盘相同的货位

        locationVoList = locationVoList.stream()
                .filter(x -> CollectionUtils.isEmpty(x.getStockDetailList()) ||
                                x.getStockDetailList().stream().allMatch(y -> Objects.equals(y.getId(), null)) ||
                                x.getStockDetailList().stream().allMatch(y -> Objects.equals(y.getContainerId(), containerId))
                )
                .collect(Collectors.toList());

        if (isHigh){
            locationVoList = locationVoList.stream().filter(y -> Objects.equals(y.getType(), LocationPlanTypeEnum.HEIGHT.getValue())) .collect(Collectors.toList());
        }
        if (CollectionUtils.isEmpty(locationVoList)) {
            return null;
        }
        List<BaseMold> baseMolds = baseMoldService.listByIds(baseMoldBarcodeList.stream().map(BaseMold::getId).collect(Collectors.toList()));
        // 计算当前要入库的总长宽高   修改为最大的长宽高
        BigDecimal inLength = baseMolds.stream().map(BaseMold::getLength).max(Comparator.comparing(x -> x)).orElse(BigDecimal.ZERO);
        BigDecimal inWidth = baseMolds.stream().map(BaseMold::getWidth).max(Comparator.comparing(x -> x)).orElse(BigDecimal.ZERO);
        BigDecimal inHeight = baseMolds.stream().map(BaseMold::getHeight).max(Comparator.comparing(x -> x)).orElse(BigDecimal.ZERO);
        log.info("入库的长宽高为{} {} {}", inLength, inWidth, inHeight);
        //计算每一个货位对应的总长宽高
        for (StockDetailLocationVo vo : locationVoList) {
            List<StockDetailMoldVo> stockDetailList = vo.getStockDetailList();
            if (stockDetailList.stream().allMatch(y -> Objects.equals(y.getContainerId(), containerId))) {
                log.info("找到原货位了 不需要判断模具的体积 = {}", stockDetailList);
                return vo;
            }
            // 只需要计算货位的长宽高大于入库磨具最大的长宽高即可
            BigDecimal remainLength = vo.getLength();
            BigDecimal remainWidth = vo.getWidth();
            BigDecimal remainHeight = vo.getHeight();
            log.info("货位{} 剩下的长宽高为{} {} {}", vo.getLocationCode(), remainLength, remainWidth, remainHeight);
            if (inLength.compareTo(remainLength) < 1 && inWidth.compareTo(remainWidth) < 1 && inHeight.compareTo(remainHeight) < 1) {
                log.info("货位{}满足入库条件", vo.getLocationCode());
                return vo;
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public  StockDetailLocationVo findLocationByContainer(String containerCode, Long currentBranchId){
        //根据托盘找货位（托盘和库位是一一对应关系）
        log.info("findLocationByContainer  = {}", containerCode);
        StockDetailLocationVo stockDetailLocationVo = this.baseMapper.findLocationByContainer(currentBranchId,containerCode);
        return stockDetailLocationVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addStockByIn(List<BusinOutInPlan> inPlans, StockDetailLocationVo locationVo, boolean isActual) {
        for (BusinOutInPlan inPlan : inPlans) {
            //判断模具信息是否有库存
            SysStockDetail one = this.getOne(new LambdaQueryWrapper<SysStockDetail>().eq(SysStockDetail::getBranchId, inPlan.getBranchId())
                    .eq(inPlan.getMoldId() != null, SysStockDetail::getMoldId, inPlan.getMoldId())
                    .eq(inPlan.getMoldBarcode() != null, SysStockDetail::getBarcode, inPlan.getMoldBarcode())
                    .eq(SysStockDetail::getLocationId, inPlan.getLocationId()));
            if (one == null) {
                //新增
                SysStockDetail detail = new SysStockDetail();
                detail.setBranchId(inPlan.getBranchId());
                detail.setStorageId(locationVo.getStorageId());
                detail.setAreaId(locationVo.getAreaId());
                detail.setMoldNo(inPlan.getMoldNo());
                detail.setMoldId(inPlan.getMoldId());
                detail.setBarcode(inPlan.getMoldBarcode());
                detail.setContainerCode(inPlan.getContainerCode());
                detail.setContainerId(inPlan.getContainerId());
                detail.setQty(isActual ? inPlan.getQty() : BigDecimal.ZERO);
                detail.setLocationId(inPlan.getLocationId());
                detail.setLocationCode(locationVo.getLocationCode());
                detail.setInTime(new Date());
                detail.setInQty(isActual ? BigDecimal.ZERO : inPlan.getQty());
                detail.setOutQty(BigDecimal.ZERO);
                log.info("新增库存数据 = {}", detail);
                this.save(detail);
                iSysStockDetailQrcodeService.addBarcodeStockDetail(detail.getId(), inPlan.getMoldNo(), inPlan.getMoldBarcode());
            } else {
                // 这里只是更新数量 条码是一致的
                log.info("更新库存数据之前 = {}", one);
                one.setQty(isActual ? one.getQty().add(inPlan.getQty()) : one.getQty())
                        .setInQty(isActual ? one.getInQty().subtract(inPlan.getQty()) : one.getInQty().add(inPlan.getQty()));
                //库存为空了重新设置入库时间
                if (one.getQty().subtract(one.getInQty()).compareTo(BigDecimal.ZERO) == 0) {
                    one.setInTime(new Date());
                }
                one.setContainerCode(inPlan.getContainerCode());
                one.setContainerId(inPlan.getContainerId());
                log.info("更新库存数据之后 = {}", one);
                this.updateById(one);
            }
        }
        //可能存在其他的库存托盘没有修改
        List<SysStockDetail> list = this.list(new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getLocationId, locationVo.getId())
                .ne(SysStockDetail::getContainerId, inPlans.get(0).getContainerId()));
        if (CollectionUtils.isNotEmpty(list)) {
            log.info("可能存在其他的库存托盘没有修改 = {}", list);
//            list.forEach(x -> x.setContainerId(inPlans.get(0).getContainerId()).setContainerCode(inPlans.get(0).getContainerCode()));
//            this.updateBatchById(list);
        }
    }

    /**
     * 找到出库货位
     *
     * @param plan 计划
     * @return {@code Result}
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<SysStockDetailVo> findOutLocation(BusinOutInPlan plan) {
        //1.出库就根据他选择的模具从对应库位出，选择模具具体到唯一码。
        List<SysStockDetailVo> outLocation = this.baseMapper.findOutLocation(plan.getMoldBarcode());
        if (CollectionUtils.isEmpty(outLocation)) {
            return Result.err().msg("没有货位上存在编号模具", plan.getMoldBarcode());
        }
        // 根据某种规则进行出库
        SysStockDetailVo vo = outLocation.stream().sorted(Comparator.comparing(x -> x.getQty().subtract(x.getOutQty()))).findFirst().orElse(null);
        return Result.ok().data(vo);
    }

    /**
     * 减少库存
     *
     * @param outPlan  计划
     * @param detailId 位置
     * @param isActual 是否实际出库
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void subtractStockByOut(BusinOutInPlan outPlan, Long detailId, boolean isActual) {
        SysStockDetail one = this.getById(detailId);
        log.info("出库更新库存数据之前 = {}", one);
        one.setQty(isActual ? one.getQty().subtract(BigDecimal.ONE) : one.getQty())
                .setOutQty(isActual ? one.getOutQty().subtract(BigDecimal.ONE) : one.getOutQty().add(BigDecimal.ONE));
        log.info("出库更新库存数据之后 = {}", one);
        this.updateById(one);
    }


    /**
     * 货位调整时选择目的货位下拉框列表
     *
     * @return {@code Result<List<BaseLocation>>}
     */
    @Override
    public Result<List<BaseLocation>> getEmptyLocation() {
        List<BaseLocation> emptyLocation = this.baseMapper.getEmptyLocation(SecurityUtils.getCurrentBranchId());
        return Result.ok().data(emptyLocation);
    }

    /**
     * 盘点更新库存数量
     *
     * @param updList 乌利希期刊指南列表
     * @return {@link Result}
     */
    @Override
    public Result updStockByInv(List<BusinStockInv> updList) {
        Long containerId =0L;
        Long locationId =0L;
        for (BusinStockInv inv : updList) {
            containerId = inv.getContainerId();
            locationId = inv.getLocationId();
            //如果是空托盘点，并且有新增模具时，清空没有模具的数据记录
            LambdaQueryWrapper<SysStockDetail> wrapperCon = new LambdaQueryWrapper<SysStockDetail>().eq(SysStockDetail::getLocationId, locationId)
                    .isNull(SysStockDetail::getBarcode)
                    .last("limit 1");
            SysStockDetail emptyCon = getOne(wrapperCon);
            if (emptyCon != null){
                this.removeById(emptyCon.getId());
            }

            LambdaQueryWrapper<SysStockDetail> wrapper = new LambdaQueryWrapper<SysStockDetail>().eq(SysStockDetail::getLocationId, locationId)
                    .eq(SysStockDetail::getBarcode, inv.getMoldBarcode())
                    .last("limit 1");
            SysStockDetail one = getOne(wrapper);
            /**
             * 1、如果没有库存，说明是新增的，则新增SysStockDetail
             * 2、如果SysStockDetail有数据，并且盘点数量是0，删除数据
             * 3、如果SysStockDetail有数据，并且盘点数据是1，修改数据
             */
            if (one == null) {
                one =new SysStockDetail();
                one.setBarcode(inv.getMoldBarcode());
                one.setMoldId(inv.getMoldId());
                one.setMoldNo(inv.getMoldNo());
                one.setContainerId(containerId);
                BaseContainer baseContainer = baseContainerService.getById(containerId);
                one.setContainerCode(baseContainer.getContainerCode());

                BaseLocation baseLocation = iBaseLocationService.getById(locationId);
                one.setLocationId(inv.getLocationId());
                one.setLocationCode(baseLocation.getLocationCode());
                one.setAreaId(baseLocation.getAreaId());
                one.setBranchId(SecurityUtils.getCurrentBranchId());
                one.setStorageId(8L);
                one.setInTime(DateUtils.getNowDate());
                one.setCreateTime(DateUtils.getNowDate());
                one.setQty(inv.getInvQty());
                one.setInQty(BigDecimal.ZERO);
                one.setOutQty(BigDecimal.ZERO);
                this.save(one);
            }else if ( one !=null && inv.getInvQty().compareTo(BigDecimal.ZERO)==0){
                this.removeById(one.getId());
            }else {
                one.setQty(inv.getInvQty());
                this.updateById(one);
            }
        }

        Map<Long, List<BusinStockInv>> listMap = updList.stream().collect(Collectors.groupingBy(BusinStockInv::getLocationId));
        for (Map.Entry<Long, List<BusinStockInv>> entry : listMap.entrySet()) {
            BusinStockInv businStockInv = entry.getValue().get(0);
            containerId =businStockInv.getContainerId();
            locationId = businStockInv.getLocationId();
            //判断库存表是否还有此托盘的信息，如果没有增加空托盘库存
            List<SysStockDetail> sysStockDetails = this.getByContainerId(containerId);
            if (sysStockDetails.size() ==0){
                SysStockDetail sysStockDetail = new SysStockDetail();
                sysStockDetail.setContainerId(containerId);
                BaseContainer baseContainer = baseContainerService.getById(containerId);
                sysStockDetail.setContainerCode(baseContainer.getContainerCode());
                BaseLocation baseLocation = iBaseLocationService.getById(locationId);
                sysStockDetail.setLocationId(locationId);
                sysStockDetail.setLocationCode(baseLocation.getLocationCode());
                sysStockDetail.setAreaId(baseLocation.getAreaId());
                sysStockDetail.setBranchId(SecurityUtils.getCurrentBranchId());
                sysStockDetail.setStorageId(8L);
                sysStockDetail.setInTime(DateUtils.getNowDate());
                sysStockDetail.setCreateTime(DateUtils.getNowDate());
                sysStockDetail.setQty(BigDecimal.ZERO);
                sysStockDetail.setInQty(BigDecimal.ZERO);
                sysStockDetail.setOutQty(BigDecimal.ZERO);
                this.save(sysStockDetail);
            }
        }
        return Result.ok();
    }

    @Override
    public List<SysStockDetail> getByContainerId(Long containerId) {
        List<SysStockDetail> list = list(new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getContainerId, containerId)
        );
        return list;
    }

    @Override
    public List<SysStockDetail> queryByMoldBarcodeLocationList(List<String> moldBarcodeList) {
        QueryWrapper<SysStockDetail> wrapper = new QueryWrapper<SysStockDetail>();
        wrapper.select("distinct  location_id, barcode,mold_id,mold_no,container_code,container_id,id ")
                .lambda()
                .in(SysStockDetail::getBarcode, moldBarcodeList)
                .orderByAsc(SysStockDetail::getLocationId);
        return this.list(wrapper);
    }

    @Override
    public List<BaseMoldVo> getLocationMoldByLocationCode(String locationCode) {
        return this.baseMapper.getLocationMoldByLocationCode(locationCode);
    }

    public List<SysStockDetail> queryDistinctByMoldBarcodeLocationList(List<String> moldBarcodeList) {
        QueryWrapper<SysStockDetail> wrapper = new QueryWrapper<SysStockDetail>();
        wrapper.select("distinct  location_id, barcode,mold_id,mold_no ")
                .lambda()
                .in(SysStockDetail::getBarcode, moldBarcodeList)
                .orderByAsc(SysStockDetail::getLocationId);
        return this.list(wrapper);
    }




}

