package com.zt.plat.module.qms.resource.material.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zt.plat.framework.common.exception.ServiceException;
import com.zt.plat.framework.common.pojo.PageResult;
import com.zt.plat.framework.common.util.object.BeanUtils;
import com.zt.plat.module.qms.core.code.SequenceUtil;
import com.zt.plat.module.qms.enums.AdjustType;
import com.zt.plat.module.qms.enums.LockType;
import com.zt.plat.module.qms.resource.material.constant.MaterialConstants;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchPageReqVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchRespVO;
import com.zt.plat.module.qms.resource.material.controller.vo.MaterialBatchSaveReqVO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialBatchDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialLifecycleDetailDO;
import com.zt.plat.module.qms.resource.material.dal.dataobject.MaterialProductDO;
import com.zt.plat.module.qms.resource.material.dal.mapper.MaterialBatchMapper;
import com.zt.plat.module.qms.resource.material.enums.MaterialAcceptStatus;
import com.zt.plat.module.qms.resource.material.enums.MaterialBatchGongType;
import com.zt.plat.module.qms.resource.material.enums.MaterialFlowType;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.qms.enums.ErrorCodeConstants.*;

/**
 * 物料批次 Service 实现类
 *
 * @author 后台管理
 */
@Service
@Validated
public class MaterialBatchServiceImpl implements MaterialBatchService {

    @Resource
    private MaterialBatchMapper materialBatchMapper;
    @Autowired
    private SequenceUtil sequenceUtil;

    @Autowired
    private MaterialProductService materialProductService;

    @Autowired
    private MaterialLifecycleDetailService materialLifecycleDetailService;

    @Override
    public MaterialBatchRespVO createMaterialBatch(MaterialBatchSaveReqVO createReqVO) {
        // 插入
        MaterialBatchDO mtrlBat = BeanUtils.toBean(createReqVO, MaterialBatchDO.class);
        mtrlBat.setAcceptanceStatus(MaterialAcceptStatus.not_accepted.name());
        // 批次编号
        mtrlBat.setBatchNo(sequenceUtil.genCode(MaterialConstants.SEQUENCE_BATCH_KEY));

        mtrlBat.setParentId(0L);
        mtrlBat.setInitialQuantity(mtrlBat.getInboundQuantity());
        materialBatchMapper.insert(mtrlBat);

        // 返回
        return BeanUtils.toBean(mtrlBat, MaterialBatchRespVO.class);
    }

    @Override
    public void updateMaterialBatch(MaterialBatchSaveReqVO updateReqVO) {
        // 校验存在
        Long reqId = updateReqVO.getId();
        MaterialBatchDO batchDO = materialBatchMapper.selectById(reqId);
        if (batchDO == null) throw exception(MATERIAL_BATCH_NOT_EXISTS);
        // 已经提交的不可修改
        if (batchDO.getSubmitStatus() == 1) throw new ServiceException(1_032_160_000, "批次已经提交，不可修改");

        // 更新
        MaterialBatchDO updateObj = BeanUtils.toBean(updateReqVO, MaterialBatchDO.class);
        materialBatchMapper.updateById(updateObj);
    }

    @Override
    public void deleteMaterialBatch(Long id) {

        MaterialBatchDO batchDO = materialBatchMapper.selectById(id);
        if (batchDO == null) throw exception(MATERIAL_BATCH_NOT_EXISTS);
        if (batchDO.getSubmitStatus() == 1)
            throw new ServiceException(1_032_160_000, "批次已经提交，不可删除");

        // 删除
        materialBatchMapper.deleteById(id);
    }

    @Transactional
    @Override
        public void deleteMaterialBatchListByIds(List<Long> ids) {
        // 校验存在
        List<MaterialBatchDO> list = materialBatchMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_BATCH_NOT_EXISTS);
        }
        // 存在已经提交的批次时，不可删除
        for (MaterialBatchDO batch : list) {
            if (batch.getSubmitStatus() == 1)
                throw new ServiceException(1_032_160_000, "存在已经提交的批次，不可删除");
        }
        // 删除
        materialBatchMapper.deleteByIds(ids);
        }

    private void validateMaterialBatchExists(List<Long> ids) {
        List<MaterialBatchDO> list = materialBatchMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(MATERIAL_BATCH_NOT_EXISTS);
        }
    }

    private void validateMaterialBatchExists(Long id) {
        if (materialBatchMapper.selectById(id) == null) {
            throw exception(MATERIAL_BATCH_NOT_EXISTS);
        }
    }

    @Override
    public MaterialBatchDO getMaterialBatch(Long id) {
        return materialBatchMapper.selectById(id);
    }

    @Override
    public PageResult<MaterialBatchDO> getMaterialBatchPage(MaterialBatchPageReqVO pageReqVO) {
        return materialBatchMapper.selectPage(pageReqVO);
    }

    /**
     * 批次工段拆分
     * 
     */
    @Transactional
    @Override
    public List<MaterialBatchRespVO> assignMaterialBatchGongduan(List<MaterialBatchSaveReqVO> createReqVOs) {
        // 是否已经拆分过
        Long batId = createReqVOs.get(0).getParentId();

        // 1. 所属的批次需要是同一个
        Set<Long> pIds = createReqVOs.stream().map(MaterialBatchSaveReqVO::getParentId).collect(Collectors.toSet());
        if (pIds.size() > 1) throw exception(GONGDUAN_BELONG_MATERIAL_BATCH_NOT_EQUAL);

        // 2. 拆分后的数量要相等
        MaterialBatchDO mtrlBat = materialBatchMapper.selectById(batId);
        if (mtrlBat == null) throw exception(MATERIAL_BATCH_NOT_EXISTS);
        if (mtrlBat.getSubmitStatus() == 1) throw new ServiceException(1_032_160_000, "批次已经提交，不可修改");
        BigDecimal total = BigDecimal.valueOf(0);
        for (MaterialBatchSaveReqVO batAsn : createReqVOs) {
            total = total.add(batAsn.getInboundQuantity());
        }
        if (total.compareTo(mtrlBat.getInboundQuantity()) != 0)
            throw exception(GONGDUAN_QUANTITY_MATERIAL_BATCH_NOT_EQUAL);
        // 修改工段
        boolean exists = materialBatchMapper.exists(Wrappers.lambdaQuery(MaterialBatchDO.class)
                .eq(MaterialBatchDO::getParentId, batId));
        if (exists) {
            // 删除之前的拆分数据
            materialBatchMapper.delete(Wrappers.lambdaQuery(MaterialBatchDO.class)
                    .eq(MaterialBatchDO::getParentId, batId));
        }

        // 3. 保存工段
        List<MaterialBatchDO> gongEts = createReqVOs.stream().map(batAsn -> {
            MaterialBatchDO bean = BeanUtils.toBean(batAsn, MaterialBatchDO.class);
            bean.setProductId(mtrlBat.getProductId()).setBatchNo(mtrlBat.getBatchNo())
                    .setInitialQuantity(bean.getInboundQuantity())
                    .setAcceptanceStatus(MaterialAcceptStatus.not_accepted.name());
            return bean;
        }).toList();
        materialBatchMapper.insertBatch(gongEts);

        return gongEts.stream().map(
                gong -> BeanUtils.toBean(gong, MaterialBatchRespVO.class)
        ).toList();
    }


    @Override
    public List<MaterialBatchDO> getGongduanListByBatIds(List<Long> batIds) {

        return materialBatchMapper.selectList(Wrappers.lambdaQuery(MaterialBatchDO.class)
                .in(MaterialBatchDO::getParentId, batIds)
                .ne(MaterialBatchDO::getParentId, 0));
    }

    @Transactional
    @Override
    public Boolean submitMaterialBatch(Long id) {
        MaterialBatchDO batchDO = materialBatchMapper.selectById(id);
        if (batchDO == null) throw exception(MATERIAL_BATCH_NOT_EXISTS);
        if (batchDO.getSubmitStatus() == 1) throw new ServiceException(1_032_160_000, "批次已经提交过");
        List<MaterialBatchDO> gongduans = this.getGongduanListByBatIds(Collections.singletonList(id));
        if (CollUtil.isEmpty(gongduans)) throw new ServiceException(1_032_160_000, "批次还未拆分，不可提交");
        // 批次存在锁定数量时不可提交
        if (batchDO.getLockQuantity().compareTo(BigDecimal.ZERO) > 0)
            throw new ServiceException(1_032_160_000, String.format("批次存在锁定数量【%s】，不可提交", batchDO.getLockQuantity()));
        // 批次可用数量可能存在变更，需要再次校验数量一致性
        BigDecimal gongTotalInbQuantity = BigDecimal.ZERO;
        for (MaterialBatchDO gongduan : gongduans) {
            gongTotalInbQuantity = gongTotalInbQuantity.add(gongduan.getInboundQuantity());
        }
        if (batchDO.getInboundQuantity().compareTo(gongTotalInbQuantity) != 0)
            throw exception(GONGDUAN_QUANTITY_MATERIAL_BATCH_NOT_EQUAL);
        batchDO.setSubmitStatus(1).setSubmitDate(LocalDateTime.now());
        materialBatchMapper.updateById(batchDO);
        // 提交工段
        MaterialBatchDO updateBatch = new MaterialBatchDO().setSubmitStatus(1).setSubmitDate(LocalDateTime.now());
        materialBatchMapper.update(updateBatch, Wrappers.lambdaQuery(MaterialBatchDO.class)
                .eq(MaterialBatchDO::getParentId, id));
        return true;
    }

    @Override
    public List<MaterialBatchDO> getGongduanListByGongIds(List<Long> gongIds) {

        return materialBatchMapper.selectList(Wrappers.lambdaQuery(MaterialBatchDO.class)
                .in(MaterialBatchDO::getId, gongIds)
                .ne(MaterialBatchDO::getParentId, 0));
    }

    @Override
    public void updateMaterialBatchInbEndQty(MaterialBatchDO gongDO) {
        materialBatchMapper.updateById(gongDO);
    }

    @Override
    public void updateMaterialBatchAcceptStatusByLfcId(Long lfcId, String status) {
        List<MaterialLifecycleDetailDO> detailList = materialLifecycleDetailService.getDetailListByLfcId(lfcId);
        if (CollUtil.isEmpty(detailList)) return;
        List<Long> gongIds = detailList.stream().map(MaterialLifecycleDetailDO::getBatchGongduanId).toList();
        if (CollUtil.isEmpty(gongIds)) return;
        MaterialBatchDO updateEntity = new MaterialBatchDO().setAcceptanceStatus(status);
        materialBatchMapper.update(updateEntity, Wrappers.lambdaQuery(MaterialBatchDO.class)
                .in(MaterialBatchDO::getId, gongIds));
    }

    @Override
    public List<MaterialBatchDO> getBatchListByBatchIds(List<Long> batchIds) {

        return materialBatchMapper.selectList(Wrappers.lambdaQuery(MaterialBatchDO.class)
                .in(MaterialBatchDO::getId, batchIds)
                .eq(MaterialBatchDO::getParentId, 0));
    }

    @Override
    public void updateBatchReturnExchangeCount(List<MaterialLifecycleDetailDO> batches, AdjustType adjustType) {
        List<Long> batIds = batches.stream().map(MaterialLifecycleDetailDO::getBatchId).toList();
        List<MaterialBatchDO> batchDOS = getBatchListByBatchIds(batIds);
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatchId = batches.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchId, Function.identity()));
        adjustBatchOrGongReturnExchangeCount(adjustType, batchDOS, lifecycleDetailDOMapByBatchId);
        materialBatchMapper.updateBatch(batchDOS);
    }

    @Override
    public void updateGongduanReturnExchangeCount(List<MaterialLifecycleDetailDO> gongs, AdjustType adjustType) {
        List<Long> gongIds = gongs.stream().map(MaterialLifecycleDetailDO::getBatchGongduanId).toList();
        List<MaterialBatchDO> gongDOS = getGongduanListByGongIds(gongIds);
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByGongId = gongs.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchGongduanId, Function.identity()));
        // 调整工段退换货数量
        adjustBatchOrGongReturnExchangeCount(adjustType, gongDOS, lifecycleDetailDOMapByGongId);
        materialBatchMapper.updateBatch(gongDOS);
        // 调整批次的退换货数量
        List<Long> batIds = gongDOS.stream().map(MaterialBatchDO::getParentId).toList();
        List<MaterialBatchDO> batDOS = getBatchListByBatchIds(batIds);
        if (CollUtil.isEmpty(batDOS)) return;
        Map<Long, Long> batIdMapByGongId = gongDOS.stream().collect(Collectors.toMap(MaterialBatchDO::getId, MaterialBatchDO::getParentId));
        for (MaterialLifecycleDetailDO gong : gongs) {
            gong.setBatchId(batIdMapByGongId.get(gong.getBatchGongduanId()));
        }
        Map<Long, List<MaterialLifecycleDetailDO>> detailGroupByBatId = gongs.stream().collect(Collectors.groupingBy(MaterialLifecycleDetailDO::getBatchId));
        List<MaterialLifecycleDetailDO> batches = batIds.stream().map(batId -> {
            List<MaterialLifecycleDetailDO> detailDOS = detailGroupByBatId.get(batId);
            BigDecimal influenceCount = detailDOS.stream().map(MaterialLifecycleDetailDO::getInfluenceCount).reduce(BigDecimal.ZERO, BigDecimal::add);
            return new MaterialLifecycleDetailDO().setBatchId(batId).setInfluenceCount(influenceCount);
        }).toList();
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatId = batches.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchId, Function.identity()));
        adjustBatchOrGongReturnExchangeCount(adjustType, batDOS, lifecycleDetailDOMapByBatId);
        materialBatchMapper.updateBatch(batDOS);

    }

    @Override
    public List<MaterialBatchDO> getListByIds(List<Long> ids) {
        return materialBatchMapper.selectByIds(ids);
    }

    @Override
    public void lockBatchReturnExchangeCount(List<MaterialLifecycleDetailDO> batches, LockType lockType) {
        List<Long> batIds = batches.stream().map(MaterialLifecycleDetailDO::getBatchId).toList();
        List<MaterialBatchDO> batchDOS = getBatchListByBatchIds(batIds);
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatchId = batches.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchId, Function.identity()));
        lockBatchOrGongReturnExchangeCount(lockType, batchDOS, lifecycleDetailDOMapByBatchId);
        materialBatchMapper.updateBatch(batchDOS);
    }

    @Override
    public void lockGongduanReturnExchangeCount(List<MaterialLifecycleDetailDO> gongs, LockType lockType) {
        List<Long> gongIds = gongs.stream().map(MaterialLifecycleDetailDO::getBatchGongduanId).toList();
        List<MaterialBatchDO> gongDOS = getGongduanListByGongIds(gongIds);
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByGongId = gongs.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchGongduanId, Function.identity()));
        // 调整工段锁定数量
        lockBatchOrGongReturnExchangeCount(lockType, gongDOS, lifecycleDetailDOMapByGongId);
        materialBatchMapper.updateBatch(gongDOS);
        // 调整批次锁定数量
        List<Long> batIds = gongDOS.stream().map(MaterialBatchDO::getParentId).toList();
        List<MaterialBatchDO> batDOS = getBatchListByBatchIds(batIds);
        if (CollUtil.isEmpty(batDOS)) return;
        Map<Long, Long> batIdMapByGongId = gongDOS.stream().collect(Collectors.toMap(MaterialBatchDO::getId, MaterialBatchDO::getParentId));
        for (MaterialLifecycleDetailDO gong : gongs) {
            gong.setBatchId(batIdMapByGongId.get(gong.getBatchGongduanId()));
        }
        Map<Long, List<MaterialLifecycleDetailDO>> detailGroupByBatId = gongs.stream().collect(Collectors.groupingBy(MaterialLifecycleDetailDO::getBatchId));
        List<MaterialLifecycleDetailDO> batches = batIds.stream().map(batId -> {
            List<MaterialLifecycleDetailDO> detailDOS = detailGroupByBatId.get(batId);
            BigDecimal influenceCount = detailDOS.stream().map(MaterialLifecycleDetailDO::getInfluenceCount).reduce(BigDecimal.ZERO, BigDecimal::add);
            return new MaterialLifecycleDetailDO().setBatchId(batId).setInfluenceCount(influenceCount);
        }).toList();
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatId = batches.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchId, Function.identity()));
        lockBatchOrGongReturnExchangeCount(lockType, batDOS, lifecycleDetailDOMapByBatId);
        materialBatchMapper.updateBatch(batDOS);
    }

    @Override
    public PageResult<MaterialBatchRespVO> getBatchGongPageWithPdtInfo(MaterialBatchPageReqVO pageReqVO) {
        // 分为 批次分页、验收、入库、退换货
        Long pdtId = pageReqVO.getProductId();
        PageResult<MaterialBatchRespVO> pageResult;
        if (pdtId == null) {
            pageResult = materialBatchMapper.selectPageWithPdtInfo(pageReqVO, List.of());
        } else {
            List<MaterialProductDO> mtrlDos = materialProductService.getMaterialProductsByLikeIdPath(pdtId);
            if (CollUtil.isEmpty(mtrlDos)) {
                pageResult = materialBatchMapper.selectPageWithPdtInfo(pageReqVO, List.of());
            } else {
                List<Long> pdtIds = mtrlDos.stream().map(MaterialProductDO::getId).toList();
                pageResult = materialBatchMapper.selectPageWithPdtInfo(pageReqVO, pdtIds);
            }
        }
        // 查全部
        if (StrUtil.isEmpty(pageReqVO.getDataType())) {
            List<MaterialBatchRespVO> respVOS = pageResult.getList();
            if (CollUtil.isNotEmpty(respVOS)) {
                List<Long> batIds = respVOS.stream().map(MaterialBatchRespVO::getId).toList();
                List<MaterialBatchDO> gongs = materialBatchMapper.selectList(Wrappers.lambdaQuery(MaterialBatchDO.class)
                        .in(MaterialBatchDO::getParentId, batIds));
                if (CollUtil.isNotEmpty(gongs)) {
                    List<MaterialBatchRespVO> gongRespVOs = gongs.stream().map(gong -> BeanUtils.toBean(gong, MaterialBatchRespVO.class)).toList();
                    respVOS.addAll(gongRespVOs);
                    pageResult.setList(respVOS);
                }
            }
        }

        // 需要组装children
        if (!MaterialBatchGongType.gong.name().equals(pageReqVO.getDataType()) && pageReqVO.getChildren()) {
            List<MaterialBatchRespVO> voList = pageResult.getList();
            if (CollUtil.isNotEmpty(voList)) {
                List<MaterialBatchRespVO> treeVos = this.listTransTree(voList, 0L);
                for (MaterialBatchRespVO batch : treeVos) {
                    List<MaterialBatchRespVO> children = batch.getChildren();
                    if (CollUtil.isEmpty(children)) continue;
                    children.forEach(child ->
                            batch.setInboundEndQuantity(batch.getInboundEndQuantity().add(child.getInboundEndQuantity()))
                    );
                }
                pageResult.setList(treeVos);
            }
        }

        return pageResult;
    }

    @Override
    public void lockBatchVerifyCalibrateCount(List<MaterialLifecycleDetailDO> batches, LockType lockType) {
        List<Long> batIds = batches.stream().map(MaterialLifecycleDetailDO::getBatchId).toList();
        List<MaterialBatchDO> batchDOS = getBatchListByBatchIds(batIds);
        Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatchId = batches.stream().collect(Collectors.toMap(MaterialLifecycleDetailDO::getBatchId, Function.identity()));
        for (MaterialBatchDO batchDO : batchDOS) {
            MaterialLifecycleDetailDO detailDO = lifecycleDetailDOMapByBatchId.get(batchDO.getId());
            BigDecimal influenceCount = detailDO.getInfluenceCount();
            switch (lockType) {
                case lock -> {
                    BigDecimal lockQuantity = batchDO.getLockQuantity().add(influenceCount);
                    if (lockQuantity.compareTo(batchDO.getInboundQuantity()) > 0)
                        throw new ServiceException(1_032_160_000, "检定数量大于可用数量");
                    batchDO.setLockQuantity(lockQuantity);
                }
                case unlock -> batchDO.setLockQuantity(batchDO.getLockQuantity().subtract(influenceCount));
            }
        }
        materialBatchMapper.updateBatch(batchDOS);
    }

    private void lockBatchOrGongReturnExchangeCount(LockType lockType, List<MaterialBatchDO> batchOrGongDOS, Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatOrGongId) {
        for (MaterialBatchDO batOrGong : batchOrGongDOS) {
            MaterialLifecycleDetailDO detailDO = lifecycleDetailDOMapByBatOrGongId.get(batOrGong.getId());
            BigDecimal influenceCount = detailDO.getInfluenceCount();
            switch (lockType) {
                case lock -> {
                    BigDecimal lockQuantity = batOrGong.getLockQuantity().add(influenceCount);
                    if (lockQuantity.compareTo(batOrGong.getInboundQuantity()) > 0)
                        throw new ServiceException(1_032_160_000, "退换货数量大于可用数量");
                    batOrGong.setLockQuantity(lockQuantity);
                }
                case unlock -> batOrGong.setLockQuantity(batOrGong.getLockQuantity().subtract(influenceCount));
            }
        }
    }

    private void adjustBatchOrGongReturnExchangeCount(AdjustType adjustType, List<MaterialBatchDO> batchOrGongDOS, Map<Long, MaterialLifecycleDetailDO> lifecycleDetailDOMapByBatOrGongId) {
        for (MaterialBatchDO batOrGong : batchOrGongDOS) {
            MaterialLifecycleDetailDO detailDO = lifecycleDetailDOMapByBatOrGongId.get(batOrGong.getId());
            String businessType = detailDO.getBusinessType();
            BigDecimal influenceCount = detailDO.getInfluenceCount();
            if (MaterialFlowType.return_material.getName().equals(businessType)) {
                BigDecimal returnQuantity = adjustType == AdjustType.add ? batOrGong.getReturnQuantity().add(influenceCount)
                        : batOrGong.getReturnQuantity().subtract(influenceCount);
                batOrGong.setReturnQuantity(returnQuantity);
            } else if (MaterialFlowType.exchange_material.getName().equals(businessType)) {
                BigDecimal replaceQuantity = adjustType == AdjustType.add ? batOrGong.getReplaceQuantity().add(influenceCount)
                        : batOrGong.getReplaceQuantity().subtract(influenceCount);
                batOrGong.setReplaceQuantity(replaceQuantity);
                batOrGong.setInboundQuantity(batOrGong.getInboundQuantity().subtract(replaceQuantity));
            }
            BigDecimal inboundQuantity = adjustType == AdjustType.add ? batOrGong.getInboundQuantity().subtract(influenceCount)
                    : batOrGong.getInboundQuantity().add(influenceCount);
            if (inboundQuantity.compareTo(BigDecimal.ZERO) < 0)
                throw new ServiceException(1_032_160_000, " 退换货数量大于可用数量");
            if (inboundQuantity.compareTo(batOrGong.getInitialQuantity()) > 0)
                throw new ServiceException(1_032_160_000, "批次数量不能大于初始数量");

            batOrGong.setInboundQuantity(inboundQuantity);
        }
    }

    /**
     * 组装物料批次树
     *
     */
    private List<MaterialBatchRespVO> listTransTree(List<MaterialBatchRespVO> voList, Long parentId) {

        // 获取父级节点
        List<MaterialBatchRespVO> parentVOs = voList.stream().filter(vo ->
                vo.getParentId().equals(parentId)).collect(Collectors.toList());
        // 设置响应的子节点
        parentVOs.forEach(vo -> vo.setChildren(listTransTree(voList, vo.getId())));

        return parentVOs;
    }

}