package com.sw.mes.store.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.context.BaseContextHandler;
import com.sw.mes.core.dto.ProductModelDto;
import com.sw.mes.core.dto.SeedGroupBracketDetailsDto;
import com.sw.mes.core.dto.SeedGroupBracketDto;
import com.sw.mes.core.dto.store.WarehouseOutputBillDetailBo;
import com.sw.mes.core.dto.wms.MesasnDto;
import com.sw.mes.core.dto.wms.MesasnOrderDto;
import com.sw.mes.core.enums.SeedStoreStatusEnum;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.CodeSenderUtils;
import com.sw.mes.core.utils.RedisTools;
import com.sw.mes.redis.server.RedissonUtils;
import com.sw.mes.store.api.interfaces.consumer.WarehouseConsumerService;
import com.sw.mes.store.constants.WarehouseConstant;
import com.sw.mes.store.dto.WmsOutputBillDto;
import com.sw.mes.store.entity.*;
import com.sw.mes.store.enums.InputBillStatusEnum;
import com.sw.mes.store.enums.OutputBillStatusEnum;
import com.sw.mes.store.enums.OutputBillTypeEnum;
import com.sw.mes.store.mapper.WarehouseOutputBillMapper;
import com.sw.mes.store.service.*;
import com.sw.mes.store.utils.CodeGenUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.modelmapper.ModelMapper;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import springfox.documentation.spring.web.json.Json;

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


/**
 * @Author wupeng
 * @Description 出库单
 * @Date 20:35 2023/8/2
 * @Param
 * @return
 **/
@Service
@Slf4j
public class WarehouseOutputBillServiceImpl extends ServiceImpl<WarehouseOutputBillMapper, WarehouseOutputBill> implements WarehouseOutputBillService {
    private static final Logger LOGGER = LoggerFactory.getLogger(WarehouseOutputBillServiceImpl.class);

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private WarehouseOutputBillMapper outputBillMapper;

    @Autowired
    private WarehouseOutputBillService warehouseOutputBillService;

    @Autowired
    private WarehouseOutputBillDetailService detailService;

    @Autowired
    private WarehouseInventoryService inventoryService;

    @Autowired
    private WarehouseConsumerService warehouseConsumerService;

    @Autowired
    private WarehouseOutputRecordBillService outputRecordBillService;

    @Autowired
    private WarehouseOutputRecordBillDetailService outputRecordBillDetailService;

    @Autowired
    private WarehouseMaterialService warehouseMaterialService;

    @Autowired
    private WarehouseModelService warehouseModelService;

    @Autowired
    private YbFeignClients ybFeignClients;

    /**
     * 保存出库单及其明细，待出库状态
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOutputBill(WarehouseOutputBill outputBill) {
        List<WarehouseOutputBillDetail> outputBillDetails = outputBill.getOutputBillDetails();
        if (CollectionUtils.isEmpty(outputBillDetails)) {
            throw new BusinessException("出库明细为空，请检查数据！");
        }
        //出库单号
        String billNo = outputBill.getBillNo();
        billNo = StringUtils.isNotBlank(billNo) ? billNo : CodeGenUtil.genOutputBillNo();
        outputBill.setBillNo(billNo);
        outputBill.setStatus(OutputBillStatusEnum.待出库.getValue());
        if (ObjectUtils.isEmpty(outputBill.getCreateTime())) {
            outputBill.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserName())) {
            outputBill.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserId())) {
            outputBill.setCreateUserId(BaseContextHandler.getUserID());
        }
        warehouseOutputBillService.saveOrUpdate(outputBill);

        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();

        //保存明细
        for (WarehouseOutputBillDetail outputBillDetail : outputBillDetails) {
            //String uniqueCode = outputBillDetail.getUniqueCode();
            //fix 验证手动录入的唯一码即可
            String manualUniqueCode = outputBillDetail.getManualUniqueCode();
            if (StringUtils.isNotBlank(manualUniqueCode)) {
                //校验当前即将出库的明细中唯一码是否重复
                if (!uniqueCodeSet.add(manualUniqueCode)) {
                    throw new BusinessException("唯一码【" + manualUniqueCode + "】重复，请检查数据！");
                }
            }
            outputBillDetail.setOutputBillId(outputBill.getId());
            outputBillDetail.setOutputBillNo(outputBill.getBillNo());
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateTime())) {
                outputBillDetail.setCreateTime(new Date());
            }
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateUserName())) {
                outputBillDetail.setCreateUserName(BaseContextHandler.getUsername());
            }
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateUserId())) {
                outputBillDetail.setCreateUserId(BaseContextHandler.getUserID());
            }
            outputBillDetail.setType(outputBill.getType());
            outputBillDetail.setDestination(outputBill.getDestination());
            outputBillDetail.setStatus(OutputBillStatusEnum.待出库.getValue());
            //如果库位id和库存编码都没有 则给物料默认库位
            if (null == outputBillDetail.getWarehouseId() && StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseMaterial materialByMaterialCode = warehouseMaterialService.getMaterialByMaterialCode(outputBillDetail.getMaterialModelCode());
                if (ObjectUtils.isNotEmpty(materialByMaterialCode)) {
                    outputBillDetail.setWarehouseId(materialByMaterialCode.getDefaultLocationId());
                    outputBillDetail.setWarehouseName(materialByMaterialCode.getDefaultLocation());
                    outputBillDetail.setWarehouseCode(materialByMaterialCode.getDefaultLocationCode());
                }
            }
            if (null == outputBillDetail.getWarehouseId() && !StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getCode(outputBillDetail.getWarehouseCode());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    outputBillDetail.setWarehouseId(warehouseModel.getId());
                    outputBillDetail.setWarehouseName(warehouseModel.getCode());
                    outputBillDetail.setWarehouseCode(warehouseModel.getName());
                }
            }
            if (null != outputBillDetail.getWarehouseId() && StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getById(outputBillDetail.getWarehouseId());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    outputBillDetail.setWarehouseId(warehouseModel.getId());
                    outputBillDetail.setWarehouseName(warehouseModel.getCode());
                    outputBillDetail.setWarehouseCode(warehouseModel.getName());
                }
            }
        }
        detailService.saveOrUpdateBatch(outputBillDetails);
        if (outputBill.getType().equals(OutputBillTypeEnum.籽晶出库.getValue())
                || outputBill.getType().equals(OutputBillTypeEnum.半成品出库.getValue())) {
            outputBill.setAutoAudit(false);
        }
        //如果是自动出库，无需审核，直接扣减库存
        if (outputBill.getAutoAudit()) {
            warehouseOutputBillService.autoDeductionAtomic(outputBill);
        }
    }

    @Override
    public Result wmsInitiate(List<WarehouseOutputBillDetail> outputBillDetails, String outputBillNo, String type) {
        List<MesasnDto> mesasnDtos = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        //查询对应的主数据
        Result<ProductModelDto> productModelDtoByCode = ybFeignClients.findProductModelDtoByCode(outputBillDetails.get(0).getMaterialModelCode());
        //组装对应数据
        MesasnDto mesasnDto = new MesasnDto();
        mesasnDto.setOrganizationid("JINKO");
        mesasnDto.setWarehouseid("5041");
        mesasnDto.setCustomerid("5041");
        mesasnDto.setDocno(outputBillNo);
        mesasnDto.setAsntype("CLCPRK");
        mesasnDto.setAsnstatus("00");
        List<String> warehouseCodes = outputBillDetails.stream().map(entity -> {
            return entity.getWarehouseCode();
        }).collect(Collectors.toList());
        List<String> distinctWarehouseCode = warehouseCodes.stream().distinct().collect(Collectors.toList());
        if (distinctWarehouseCode.size() > 1) {
            throw new BusinessException("出库明细需保证库位保证一致,请检查数据!");
        }
        if (type.equals(OutputBillTypeEnum.籽晶出库.getValue())) {
            mesasnDto.setAsnreferenced("籽晶组托入库");
            mesasnDto.setAsnreferencec(outputBillDetails.get(0).getWarehouseCode());
        }
        if (type.equals(OutputBillTypeEnum.半成品出库.getValue())) {
            mesasnDto.setAsnreferenced("余料入库");
            mesasnDto.setAsnreferencec(outputBillDetails.get(0).getWarehouseCode());
        }
        mesasnDto.setAsnreferencea(outputBillNo);
        mesasnDto.setAsnreferenceb("5041");//车间编号
        mesasnDto.setAsncreationtime(sdf.format(new Date()));
        mesasnDto.setTraceid(CodeSenderUtils.getNumber(4));//托盘号
        mesasnDto.setSerialno(mesasnDto.getTraceid());//箱号
        mesasnDto.setSku(outputBillDetails.get(0).getMaterialModelCode());//物料编码
        List<Double> collect = outputBillDetails.stream().map(entity -> {
            return Double.valueOf(String.valueOf(entity.getRequireCount()));
        }).collect(Collectors.toList());
        double sum = collect.stream().mapToDouble(Double::doubleValue).sum();
        mesasnDto.setExpectedqty(String.valueOf(sum));
        mesasnDto.setLotatt01(sdf.format(new Date()));
        mesasnDto.setLotatt04(outputBillDetails.get(0).getBatchNo());//入库批次
        mesasnDto.setLotatt08("N");//质量状态
        mesasnDto.setLotatt09("5041");//厂家
        mesasnDto.setLotatt10("5041");//供应商
        mesasnDto.setLotatt12(outputBillDetails.get(0).getBatchNo());//生产批次
        ProductModelDto productModelDto = new ProductModelDto();
        if (productModelDtoByCode.getCode().equals(200) && null != productModelDtoByCode.getData()) {
            productModelDto = productModelDtoByCode.getData();
        }
        if (ObjectUtils.isNotEmpty(productModelDto)) {
            mesasnDto.setLotatt19(productModelDto.getResistivity());//电阻率
            mesasnDto.setLotatt20(productModelDto.getProductGrade());//等级
        }
        mesasnDto.setCreatesource("MES");
        List<MesasnOrderDto> mesasnOrderDtos = new ArrayList<>();
        outputBillDetails.forEach(details -> {
            MesasnOrderDto mesasnOrderDto = new MesasnOrderDto();
            mesasnOrderDto.setSku(details.getMaterialModelCode());
            if (type.equals(OutputBillTypeEnum.籽晶出库.getValue())) {
                mesasnOrderDto.setLotatt04(details.getBatchNo());//入库批次
                mesasnOrderDto.setLotatt12(details.getBatchNo());//生产批次
                mesasnOrderDto.setDedi08(details.getBatchNo());//批号,MES下线批
            }
            if (type.equals(OutputBillTypeEnum.半成品出库.getValue())) {
                mesasnOrderDto.setLotatt04(details.getCrystalNo());//入库批次
                mesasnOrderDto.setLotatt12(details.getCrystalNo());//生产批次
                mesasnOrderDto.setDedi08(details.getCrystalNo());//批号,MES下线批
            }
            mesasnOrderDto.setTraceid(mesasnDto.getTraceid());
            String number = CodeSenderUtils.getNumber(4);
            mesasnOrderDto.setSerialno(mesasnDto.getCustomerid() + details.getMaterialModelCode() + number.substring(2, number.length()));
            mesasnOrderDto.setExpectedqty(String.valueOf(details.getRequireCount()));//箱重量
            mesasnOrderDto.setLotatt01(sdf.format(new Date()));
            mesasnOrderDto.setLotatt03(sdf.format(new Date()));
            mesasnOrderDto.setLotatt05("5041");
            mesasnOrderDto.setLotatt08("N");//质量状态
            mesasnOrderDto.setLotatt09("5041");//厂家
            mesasnOrderDto.setDedi06("0");
            mesasnOrderDto.setDedi07("");//长度,整箱长度
            mesasnOrderDto.setLotatt19(mesasnDto.getLotatt19());//电阻率
            mesasnOrderDto.setLotatt20(mesasnDto.getLotatt20());//等级
            mesasnOrderDtos.add(mesasnOrderDto);
        });
        mesasnDto.setOrderList(mesasnOrderDtos);
        mesasnDtos.add(mesasnDto);
        //发起WMS入库
        Result result = ybFeignClients.mesasn(mesasnDtos);
        if (!result.getCode().equals(200)) {
            log.info("发起入库失败,失败原因" + JSON.toJSONString(result));
            return ResultGenerator.fail("发起WMS入库失败,失败原因:" + result.getMessage());
        }
        if (type.equals(OutputBillTypeEnum.半成品出库.getValue())) {
            outputBillDetails.stream().forEach(entity -> {
                entity.setTraceid(mesasnDto.getTraceid());
                detailService.saveOrUpdate(entity);
            });
        }
        return ResultGenerator.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveOutputBills(WarehouseOutputBill outputBill) {
        List<WarehouseOutputBillDetail> outputBillDetails = outputBill.getOutputBillDetails();
        if (CollectionUtils.isEmpty(outputBillDetails)) {
            throw new BusinessException("出库明细为空，请检查数据！");
        }
        //出库单号
        String billNo = outputBill.getBillNo();
        billNo = StringUtils.isNotBlank(billNo) ? billNo : CodeGenUtil.genOutputBillNo();
        outputBill.setBillNo(billNo);
        outputBill.setStatus(OutputBillStatusEnum.待出库.getValue());
        if (ObjectUtils.isEmpty(outputBill.getCreateTime())) {
            outputBill.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserName())) {
            outputBill.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserId())) {
            outputBill.setCreateUserId(BaseContextHandler.getUserID());
        }
        warehouseOutputBillService.saveOrUpdate(outputBill);

        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();

        //保存明细
        for (WarehouseOutputBillDetail outputBillDetail : outputBillDetails) {
            String uniqueCode = outputBillDetail.getUniqueCode();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //校验当前即将出库的明细中唯一码是否重复
                if (!uniqueCodeSet.add(uniqueCode)) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据！");
                }
            }
            outputBillDetail.setOutputBillId(outputBill.getId());
            outputBillDetail.setOutputBillNo(outputBill.getBillNo());
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateTime())) {
                outputBillDetail.setCreateTime(new Date());
            }
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateUserName())) {
                outputBillDetail.setCreateUserName(BaseContextHandler.getUsername());
            }
            if (ObjectUtils.isEmpty(outputBillDetail.getCreateUserId())) {
                outputBillDetail.setCreateUserId(BaseContextHandler.getUserID());
            }
            outputBillDetail.setType(outputBill.getType());
            outputBillDetail.setDestination(outputBill.getDestination());
            outputBillDetail.setStatus(OutputBillStatusEnum.待出库.getValue());
            //如果库位id和库存编码都没有 则给物料默认库位
            if (null == outputBillDetail.getWarehouseId() && StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseMaterial materialByMaterialCode = warehouseMaterialService.getMaterialByMaterialCode(outputBillDetail.getMaterialModelCode());
                if (ObjectUtils.isNotEmpty(materialByMaterialCode)) {
                    outputBillDetail.setWarehouseId(materialByMaterialCode.getDefaultLocationId());
                    outputBillDetail.setWarehouseName(materialByMaterialCode.getDefaultLocation());
                    outputBillDetail.setWarehouseCode(materialByMaterialCode.getDefaultLocationCode());
                }
            }
            if (null == outputBillDetail.getWarehouseId() && !StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getCode(outputBillDetail.getWarehouseCode());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    outputBillDetail.setWarehouseId(warehouseModel.getId());
                    outputBillDetail.setWarehouseName(warehouseModel.getCode());
                    outputBillDetail.setWarehouseCode(warehouseModel.getName());
                }
            }
            if (null != outputBillDetail.getWarehouseId() && StringUtils.isEmpty(outputBillDetail.getWarehouseCode())) {
                WarehouseModel warehouseModel = warehouseModelService.getById(outputBillDetail.getWarehouseId());
                if (ObjectUtils.isNotEmpty(warehouseModel)) {
                    outputBillDetail.setWarehouseId(warehouseModel.getId());
                    outputBillDetail.setWarehouseName(warehouseModel.getCode());
                    outputBillDetail.setWarehouseCode(warehouseModel.getName());
                }
            }
        }
        detailService.saveOrUpdateBatch(outputBillDetails);
        //如果是自动出库，无需审核，直接扣减库存
        if (outputBill.getAutoAudit()) {
            warehouseOutputBillService.autoDeductionAtomic(outputBill);
        }
        return billNo;
    }

    /**
     * 出库审核通过，扣减库存
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auditDeduction(WarehouseOutputBill outputBill) {
        WarehouseOutputBill byBillNo = this.getByBillNo(outputBill.getBillNo());
        if (byBillNo == null) {
            throw new BusinessException("出库单号【" + outputBill.getBillNo() + "】信息为空，请检查数据！");
        }
        String status = byBillNo.getStatus();
        if (!OutputBillStatusEnum.待出库.getValue().equals(status) && !OutputBillStatusEnum.待入库.getValue().equals(status)) {
            throw new BusinessException("出库单号【" + outputBill.getBillNo() + "】状态不是【待出库】状态，审核失败！");
        }
        if (!outputBill.getType().equals(OutputBillTypeEnum.WMS退料)) {

            auditDeductionInventory(outputBill);
            //TODO wupeng 此处需要调用其他需要反馈的系统接口
            warehouseConsumerService.afterAuditOutput(outputBill);
        } else {
            //WMS退料需要等返回成功之后才会操作库存
            warehouseConsumerService.afterAuditOutput(outputBill);
        }

    }

    @Override
    public void statusReception(WmsOutputBillDto dto) {
        WarehouseOutputBill outputBill = outputBillMapper.getByBillNo(dto.getBillNo());
        if (dto.getStatus().equals("接收")) {
            warehouseOutputBillService.auditDeductionAtomic(outputBill);
        } else {
            warehouseOutputBillService.rejectApply(outputBill);
        }
    }


    @Override
    public void auditDeductionAtomic(WarehouseOutputBill outputBill) {
        RLock lock = RedissonUtils.getRLock(redissonClient, WarehouseConstant.UPDATE_INVENTORY_LOCK_KEY);
        boolean isLock = RedissonUtils.getRLockExpireTime(lock, 6L, 6L);
        //出库单明细出库。防止并发修改库存，加锁
        if (isLock) {
            try {
                lock.lock();
                warehouseOutputBillService.auditDeduction(outputBill);
            } finally {
                if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        } else {
            throw new BusinessException("有其他人正在操作，请稍后再试！");
        }
    }

    /**
     * 直接出库，无需审核通过，原子扣减库存
     **/
    @Override
    public void autoDeductionAtomic(WarehouseOutputBill outputBill) {
//        RLock lock = RedissonUtils.getRLock(redissonClient, WarehouseConstant.UPDATE_INVENTORY_LOCK_KEY);
//        boolean isLock = RedissonUtils.getRLockExpireTime(lock, 6L, 5L);
//        //出库单单明细出库。防止并发修改库存，加锁
//        if (isLock) {
//            try {
//                lock.lock();
//                warehouseOutputBillService.autoDeduction(outputBill);
//            } finally {
//                if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
//                    lock.unlock();
//                }
//            }
//        } else {
//            throw new BusinessException("有其他人正在操作，请稍后再试！");
//        }
        warehouseOutputBillService.autoDeduction(outputBill);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void autoDeduction(WarehouseOutputBill outputBill) {
        /**
         * 直接出库无需审核，且非手动创建的出库单，要自动扣减库存，则没有审核过程中选择具体物料库存的步骤，也就没有唯一码、批次号、库位等信息，只有物料编码和需求量
         * 假如某个物料有多条库存数据，则自动扣减时，是不知道扣减哪个库存数据的。
         * 此时，采用随机扣减的原则
         **/
        WarehouseOutputBill byBillNo = this.getByBillNo(outputBill.getBillNo());
        if (byBillNo == null) {
            throw new BusinessException("出库单号【" + outputBill.getBillNo() + "】信息为空，自动出库失败！");
        }
        autoDeductionInventory(outputBill);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterAutoOutput(outputBill);
    }

    /**
     * 取消出库申请
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelApply(String billNo) {
        if (StringUtils.isBlank(billNo)) {
            throw new BusinessException("出库单号为空！");
        }
        WarehouseOutputBill byBill = warehouseOutputBillService.getByBillNo(billNo);
        if (byBill == null) {
            throw new BusinessException("该单据不存在！");
        }
        String status = byBill.getStatus();
        if (!OutputBillStatusEnum.待出库.getValue().equals(status)) {
            throw new BusinessException("该单据状态为【" + status + "】，无法取消！");
        }
        byBill.setStatus(InputBillStatusEnum.已取消.getValue());
        byBill.setUpdateUserName(BaseContextHandler.getUsername());
        byBill.setUpdateUserId(BaseContextHandler.getUserID());
        byBill.setUpdateTime(new Date());
        //更新出库单状态
        warehouseOutputBillService.saveOrUpdate(byBill);
        //更新出库明细状态
        List<WarehouseOutputBillDetail> billDetails = detailService.getByBillNo(billNo);
        if (billDetails == null || billDetails.size() == 0) {
            throw new BusinessException("该单据明细为空，取消失败！");
        }
        billDetails.forEach(e -> {
            e.setStatus(OutputBillStatusEnum.已取消.getValue());
            e.setUpdateUserName(BaseContextHandler.getUsername());
            e.setUpdateUserId(BaseContextHandler.getUserID());
            e.setUpdateTime(byBill.getUpdateTime());
        });
        detailService.saveOrUpdateBatch(billDetails);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterOutputCancel(byBill);
    }

    /**
     * 拒绝出库
     **/
    @Override
    public void rejectApply(WarehouseOutputBill outputBill) {
        String billNo = outputBill.getBillNo();
        if (StringUtils.isBlank(billNo)) {
            throw new BusinessException("单据号不能为空！");
        }
        WarehouseOutputBill byBillNo = this.getByBillNo(billNo);
        if (byBillNo == null) {
            throw new BusinessException("该单据不存在！");
        }
        List<WarehouseOutputBillDetail> billDetails = detailService.getByBillNo(billNo);
        if (billDetails == null || billDetails.size() == 0) {
            throw new BusinessException("该单据明细为空，拒收失败！");
        }
        String status = byBillNo.getStatus();
        if (!OutputBillStatusEnum.待出库.getValue().equals(status) && !OutputBillStatusEnum.待入库.getValue().equals(status)) {
            throw new BusinessException("该单据已经是【" + status + "】状态，无法拒收！");
        }
        byBillNo.setStatus(InputBillStatusEnum.拒收.getValue());
        byBillNo.setUpdateUserName(BaseContextHandler.getUsername());
        byBillNo.setUpdateUserId(BaseContextHandler.getUserID());
        byBillNo.setUpdateTime(new Date());
        //更新入库单状态
        warehouseOutputBillService.saveOrUpdate(byBillNo);
        //更新入库明细状态
        billDetails.forEach(e -> {
            e.setStatus(byBillNo.getStatus());
            e.setUpdateUserName(BaseContextHandler.getUsername());
            e.setUpdateUserId(BaseContextHandler.getUserID());
            e.setUpdateTime(byBillNo.getUpdateTime());
        });
        detailService.saveOrUpdateBatch(billDetails);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterOutputReject(byBillNo);
    }

    @Override
    public WarehouseOutputBill getByBillNo(String billNo) {
        return outputBillMapper.getByBillNo(billNo);
    }

    /**
     * 审核扣减库存，更新出库单、出库单明细状态
     **/
    private void auditDeductionInventory(WarehouseOutputBill outputBill) {
        //修改出库单状态为 已出库
        this.updateOutputBill(outputBill, OutputBillStatusEnum.已出库);
        //保存审核记录单
        WarehouseOutputRecordBill warehouseOutputRecordBill = this.saveRecordBill(outputBill);
        //数据库中的出库明细，即出库申请单的申请明细
        List<WarehouseOutputBillDetail> outputBillDetails = detailService.getByBillId(outputBill.getId());
        outputBillDetails.stream().forEach(entity -> {
            Optional<WarehouseOutputBillDetail> detail = outputBill.getOutputBillDetails().stream().filter(details -> entity.getId().equals(details.getId())).findFirst();
            if (detail.isPresent()) {
                entity.setManualUniqueCode(detail.get().getManualUniqueCode());
                entity.setUniqueCode(detail.get().getUniqueCode());
            }
        });
        if (CollectionUtils.isEmpty(outputBillDetails)) {
            throw new BusinessException("出库明细为空，请检查数据");
        }
        //更新物料明细状态
        this.updateDetail(outputBillDetails, OutputBillStatusEnum.已出库);
        //前端传递的真正审核的明细，需要审核的单据，申请明细和审核明细可能是不一样的，一条申请单明细可能需要多个库位出库，就会产生多条审核明细
        List<WarehouseOutputBillDetail> outputBillDetailsDtos = outputBill.getOutputBillDetails();
        //审核明细
        for (WarehouseOutputBillDetail billDetail : outputBillDetailsDtos) {
            String lockKey = new String();
            if (StringUtils.isNotBlank(billDetail.getUniqueCode())) {
                lockKey = "STORE" + "-inventory-" + billDetail.getUniqueCode();
            } else {
                lockKey = "STORE" + "-inventory-" + billDetail.getMaterialModelCode() + "-"
                        + billDetail.getBatchNo() + "-" + billDetail.getWarehouseId();
            }
            RLock lock = RedissonUtils.getRLock(redissonClient, lockKey);
            boolean isLock = RedissonUtils.getRLockExpireTime(lock, 4L, 6L);
            if (isLock) {
                try {
                    lock.lock();
                    String materialModelCode = billDetail.getMaterialModelCode();
                    if (StringUtils.isBlank(materialModelCode)) {
                        throw new BusinessException("出库的物料编码为空，请检查数据");
                    }
                    Long warehouseId = billDetail.getWarehouseId();
                    if (warehouseId == null || warehouseId == 0) {
                        throw new BusinessException("出库明细的库位信息为空，请检查数据");
                    }
                    String uniqueCode = billDetail.getUniqueCode();
                    String batchNo = billDetail.getBatchNo();
                    BigDecimal outputCount = billDetail.getOutputCount(); //审核出库时，出库人填写的真实要出库的数量
                    BigDecimal requireCount = billDetail.getRequireCount(); //需求数量，是创建出库单时，需要的数量
                    if (outputCount == null || outputCount.compareTo(new BigDecimal("0")) == 0) {
                        //如果出库数量为空，则默认出库数量为需求数量(正常情况下，二者是相等的)
                        outputCount = requireCount;
                    }
                    if (requireCount == null || requireCount.compareTo(new BigDecimal("0")) == 0) {
                        requireCount = outputCount;
                    }
                    if (StringUtils.isNotBlank(uniqueCode)) {
                        WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(uniqueCode);
                        log.info("原始库存对象" + JSON.toJSONString(byUniqueCode));
                        if (byUniqueCode == null) {
                            throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                        }
                        //唯一码物料库存只能是 1
                        if (outputCount.compareTo(new BigDecimal("1")) != 0) { //出库数量是不是1
                            throw new BusinessException("唯一码【" + uniqueCode + "】物料出库数量只能为1，请检查数据！");
                        }
                        BigDecimal lockQuantity = byUniqueCode.getLockQuantity() == null ? new BigDecimal("0") : byUniqueCode.getLockQuantity();
                        BigDecimal quantity = byUniqueCode.getQuantity();
                        //剩余库存为1时可以出库，扣减库存为0，并删除该条库存数据
                        if (billDetail.isLockInventory()) {
                            if (quantity.compareTo(new BigDecimal("1")) != 0) {
                                throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                            }
                            byUniqueCode.setQuantity(new BigDecimal("0"));
                            byUniqueCode.setDel(true);
                            byUniqueCode.setLockQuantity(new BigDecimal("0"));
                        } else {
                            //剩余库存为1时可以出库，扣减库存为0，并删除该条库存数据
                            BigDecimal remain = quantity.subtract(lockQuantity);
                            if (remain.compareTo(new BigDecimal("1")) != 0) {
                                throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                            }
                            byUniqueCode.setQuantity(new BigDecimal("0"));
                            byUniqueCode.setDel(true);
                        }
                        inventoryService.updateInventory(byUniqueCode, 2);
                    } else {
                        //根据 唯一码为空、批次号、物料、库位  查询物料库存数据
                        List<WarehouseInventory> warehouseInventory = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo, billDetail.getMaterialModelCode(), billDetail.getWarehouseId());
                        warehouseInventory = warehouseInventory.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                        if (CollectionUtils.isEmpty(warehouseInventory)) {
                            throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存数据不存在，请检查数据！");
                        }
                        WarehouseInventory inventory = warehouseInventory.get(0);
                        log.info("原始库存对象" + JSON.toJSONString(inventory));
                        if (billDetail.isLockInventory()) {
                            BigDecimal quantity = inventory.getQuantity();
                            BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
//                        BigDecimal remain = quantity.subtract(lockQuantity);
                            if (outputCount.compareTo(quantity) == 1) {
                                //出库数量大于库存数量
                                throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存不足，请检查数据！");
                            }
                            //出库数量小于库存数量，出库成功，更新库存
                            quantity = quantity.subtract(outputCount);
                            if (quantity.compareTo(new BigDecimal("0")) == 0) {
                                inventory.setDel(true);
                            }
                            inventory.setQuantity(quantity);
                            if (lockQuantity.compareTo(billDetail.getRequireCount()) < 0) {
                                //出库数量大于库存数量
                                throw new BusinessException("出库需求数量大于锁定数量，请检查数据");
                            }
                            BigDecimal lockNumber = lockQuantity.subtract(billDetail.getRequireCount());
                            inventory.setLockQuantity(lockNumber);
                        } else {
                            BigDecimal quantity = inventory.getQuantity();
                            BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
                            BigDecimal remain = quantity.subtract(lockQuantity);
                            if (outputCount.compareTo(remain) == 1) {
                                //出库数量大于库存数量
                                throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存不足，请检查数据！");
                            }
                            //出库数量小于库存数量，出库成功，更新库存
                            quantity = quantity.subtract(outputCount);
                            if (quantity.compareTo(new BigDecimal("0")) == 0) {
                                inventory.setDel(true);
                            }
                            inventory.setQuantity(quantity);
                        }
                        inventoryService.updateInventory(inventory, 2);
                    }
                    //新增审核记录明细
                    this.saveRecordBillDetail(warehouseOutputRecordBill, billDetail, requireCount, outputCount, null, OutputBillStatusEnum.已出库);
                } finally {
                    if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                        RedisTools.deleteObject(lockKey);
                    }
                }
            } else {
                throw new BusinessException("有其他人正在操作，请稍后再试！");
            }
        }
    }

    /**
     * 自动扣减库存，更新出库单、出库单明细状态
     **/
    private void autoDeductionInventory(WarehouseOutputBill outputBill) {
        //修改出库单状态为 已出库
        this.updateOutputBill(outputBill, OutputBillStatusEnum.已出库);
        //保存审核记录单
        WarehouseOutputRecordBill warehouseOutputRecordBill = this.saveRecordBill(outputBill);
        //数据库中的出库明细，即出库申请单的申请明细
//        List<WarehouseOutputBillDetail> outputBillDetails = detailService.getByBillId(outputBill.getId());
        List<WarehouseOutputBillDetail> outputBillDetails = outputBill.getOutputBillDetails();
        outputBillDetails.stream().forEach(entity -> {
            Optional<WarehouseOutputBillDetail> detail = outputBill.getOutputBillDetails().stream().filter(details -> entity.getId().equals(details.getId())).findFirst();
            if (detail.isPresent()) {
                entity.setManualUniqueCode(detail.get().getManualUniqueCode());
                entity.setUniqueCode(detail.get().getUniqueCode());
            }
        });
        if (CollectionUtils.isEmpty(outputBillDetails)) {
            throw new BusinessException("出库明细为空，请检查数据");
        }
        //更新物料明细状态
        this.updateDetail(outputBillDetails, OutputBillStatusEnum.已出库);
        for (WarehouseOutputBillDetail billDetail : outputBillDetails) {
            String lockKey = new String();
            if (StringUtils.isNotBlank(billDetail.getUniqueCode())) {
                lockKey = "STORE" + "-inventory-" + billDetail.getUniqueCode();
            } else {
                lockKey = "STORE" + "-inventory-" + billDetail.getMaterialModelCode() + "-"
                        + billDetail.getBatchNo() + "-" + billDetail.getWarehouseId();
            }
            RLock lock = RedissonUtils.getRLock(redissonClient, lockKey);
            boolean isLock = RedissonUtils.getRLockExpireTime(lock, 4L, 6L);
            if (isLock) {
                try {
                    lock.lock();
                    String materialModelCode = billDetail.getMaterialModelCode();
                    if (StringUtils.isBlank(materialModelCode)) {
                        throw new BusinessException("出库的物料编码为空，请检查数据");
                    }
                    String uniqueCode = billDetail.getUniqueCode();
                    String batchNo = billDetail.getBatchNo();
                    BigDecimal outputCount = billDetail.getOutputCount(); //审核出库时，出库人填写的真实要出库的数量
                    BigDecimal requireCount = billDetail.getRequireCount(); //需求数量，是创建出库单时，需要的数量
                    if (outputCount == null || outputCount.compareTo(new BigDecimal("0")) == 0) {
                        //如果出库数量为空，则默认出库数量为需求数量(正常情况下，二者是相等的)
                        outputCount = requireCount;
                    }
                    if (requireCount == null || requireCount.compareTo(new BigDecimal("0")) == 0) {
                        requireCount = outputCount;
                    }
                    if (StringUtils.isNotBlank(uniqueCode)) {
                        WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(uniqueCode);
                        log.info("原始库存对象" + JSON.toJSONString(byUniqueCode));
                        if (byUniqueCode == null) {
                            throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                        }
                        //唯一码物料库存只能是 1
                        if (outputCount.compareTo(new BigDecimal("1")) != 0) { //出库数量是不是1
                            throw new BusinessException("唯一码【" + uniqueCode + "】物料出库数量只能为1，请检查数据！");
                        }
                        BigDecimal lockQuantity = byUniqueCode.getLockQuantity() == null ? new BigDecimal("0") : byUniqueCode.getLockQuantity();
                        BigDecimal quantity = byUniqueCode.getQuantity();
                        //剩余库存为1时可以出库，扣减库存为0，并删除该条库存数据
                        if (billDetail.isLockInventory()) {
                            if (quantity.compareTo(new BigDecimal("1")) != 0) {
                                throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                            }
                            byUniqueCode.setQuantity(new BigDecimal("0"));
                            byUniqueCode.setDel(true);
                            byUniqueCode.setLockQuantity(new BigDecimal("0"));
                        } else {
                            //剩余库存为1时可以出库，扣减库存为0，并删除该条库存数据
                            BigDecimal remain = quantity.subtract(lockQuantity);
                            if (remain.compareTo(new BigDecimal("1")) != 0) {
                                throw new BusinessException("唯一码【" + uniqueCode + "】对应的物料库存不足，请重新选择！");
                            }
                            byUniqueCode.setQuantity(new BigDecimal("0"));
                            byUniqueCode.setDel(true);
                        }
                        inventoryService.updateInventory(byUniqueCode, 2);
                        //新增审核明细
                        this.saveRecordBillDetail(warehouseOutputRecordBill, billDetail, requireCount, outputCount, byUniqueCode, OutputBillStatusEnum.已出库);
                    } else {
                        Long warehouseId = billDetail.getWarehouseId();
                        if (warehouseId != null && warehouseId != 0) {
                            List<WarehouseInventory> warehouseInventories = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo, materialModelCode, warehouseId);
                            warehouseInventories = warehouseInventories.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                            if (CollectionUtils.isEmpty(warehouseInventories)) {
                                throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存数据不存在，请检查数据！");
                            }
                            WarehouseInventory inventory = warehouseInventories.get(0);
                            log.info("原始库存对象" + JSON.toJSONString(inventory));
                            if (billDetail.isLockInventory()) {
                                BigDecimal quantity = inventory.getQuantity();
                                BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
//                        BigDecimal remain = quantity.subtract(lockQuantity);
                                if (outputCount.compareTo(quantity) == 1) {
                                    //出库数量大于库存数量
                                    throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存不足，请检查数据！");
                                }
                                //出库数量小于库存数量，出库成功，更新库存
                                quantity = quantity.subtract(outputCount);
                                if (quantity.compareTo(new BigDecimal("0")) == 0) {
                                    inventory.setDel(true);
                                }
                                inventory.setQuantity(quantity);
                                if (lockQuantity.compareTo(billDetail.getRequireCount()) < 0) {
                                    //出库数量大于库存数量
                                    throw new BusinessException("出库需求数量大于锁定数量，请检查数据");
                                }
                                BigDecimal lockNumber = lockQuantity.subtract(billDetail.getRequireCount());
                                inventory.setLockQuantity(lockNumber);
                            } else {
                                BigDecimal quantity = inventory.getQuantity();
                                BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
                                BigDecimal remain = quantity.subtract(lockQuantity);
                                if (outputCount.compareTo(remain) == 1) {
                                    //出库数量大于库存数量
                                    throw new BusinessException("批次号【" + batchNo + "】，物料名称【" + billDetail.getMaterialModelCode() + "】，库位名称【" + billDetail.getWarehouseCode() + "】对应的库存不足，请检查数据！");
                                }
                                //出库数量小于库存数量，出库成功，更新库存
                                quantity = quantity.subtract(outputCount);
                                if (quantity.compareTo(new BigDecimal("0")) == 0) {
                                    inventory.setDel(true);
                                }
                                inventory.setQuantity(quantity);
                            }
                            inventoryService.updateInventory(inventory, 2);
                            //新增审核明细
                            this.saveRecordBillDetail(warehouseOutputRecordBill, billDetail, requireCount, outputCount, inventory, OutputBillStatusEnum.已出库);
                        } else {
                            //当出库明细中未填写库位信息，则存在多条库存数据时，随机扣减库存，此时会产生多条审核记录明细
                            List<WarehouseInventory> inventories = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo, materialModelCode, billDetail.getWarehouseId());
                            inventories = inventories.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                            if (CollectionUtils.isEmpty(inventories)) {
                                throw new BusinessException("物料编码【" + materialModelCode + "】暂无库存记录，请检查数据！");
                            }
                            BigDecimal stillNeeded = outputCount; //还需要的出库数量
                            for (int i = 0; i < inventories.size(); i++) {
                                if (stillNeeded.compareTo(new BigDecimal("0")) == 0) {
                                    break;
                                }
                                WarehouseInventory inventory = inventories.get(i);
                                BigDecimal quantity = inventory.getQuantity();
                                BigDecimal lockQuantity = inventory.getLockQuantity() == null ? new BigDecimal("0") : inventory.getLockQuantity();
                                BigDecimal remain = quantity.subtract(lockQuantity); //剩余库存
                                BigDecimal truthOutputCount = outputCount;
                                if (remain.compareTo(stillNeeded) == -1) {
                                    //如果库存数量小于需求数量，删除当前扣完的库存数据，继续扣减下一个库存
                                    quantity = lockQuantity;
                                    stillNeeded = outputCount.subtract(remain);
                                    truthOutputCount = remain;
                                } else {
                                    //如果剩余库存数量大于或等于需求数量，更新库存
                                    quantity = quantity.subtract(stillNeeded);
                                    truthOutputCount = stillNeeded;
                                    stillNeeded = new BigDecimal("0");
                                }
                                if (quantity.compareTo(new BigDecimal("0")) == 0) {
                                    inventory.setDel(true);
                                }
                                inventory.setQuantity(quantity);
                                inventoryService.updateInventory(inventory, 2);
                                //随机扣减库存，如果扣减了多个库位的库存，应该保存多条审核明细
                                this.saveRecordBillDetail(warehouseOutputRecordBill, billDetail, requireCount, truthOutputCount, inventory, OutputBillStatusEnum.已出库);
                            }
                            if (stillNeeded.compareTo(new BigDecimal("0")) == 1) {
                                throw new BusinessException("物料编码【" + materialModelCode + "】库存不足，请检查数据！");
                            }
                        }
                    }
                } finally {
                    if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                        lock.unlock();
                        RedisTools.deleteObject(lockKey);
                    }
                }
            } else {
                throw new BusinessException("有其他人正在操作，请稍后再试！");
            }
        }
    }

    private void updateOutputBill(WarehouseOutputBill outputBill, OutputBillStatusEnum statusEnum) {
        outputBill.setStatus(statusEnum.getValue());
        outputBill.setUpdateTime(new Date());
        outputBill.setUpdateUserId(BaseContextHandler.getUserID());
        outputBill.setUpdateUserName(BaseContextHandler.getUsername());
        warehouseOutputBillService.saveOrUpdate(outputBill);
    }

    @Override
    public List<WarehouseOutputBillDetailBo> findWarehouseOutputBillDetailByMaterialCode(String materialCode) {
        return detailService.findWarehouseOutputBillDetailByMaterialCode(materialCode);
    }

    @Override
    public WarehouseOutputBill findWarehouseOutputBillByCode(String outputBillNo) {
        WarehouseOutputBill warehouseOutputBill = outputBillMapper.getByBillNo(outputBillNo);
        List<WarehouseOutputBillDetail> details = detailService.getByBillNo(outputBillNo);
        warehouseOutputBill.setOutputBillDetails(details);
        return warehouseOutputBill;
    }

    @Override
    public WarehouseOutputBill findWarehouseOutputBillByInputBillCode(String inputBillCode) {
        WarehouseOutputBill outputBill = outputBillMapper.findWarehouseOutputBillByInputBillCode(inputBillCode);
        if (ObjectUtils.isNotEmpty(outputBill)) {
            List<WarehouseOutputBillDetail> details = detailService.getByBillId(outputBill.getId());
            outputBill.setOutputBillDetails(details);
        }
        return outputBill;
    }

    private void updateDetail(List<WarehouseOutputBillDetail> outputBillDetails, OutputBillStatusEnum statusEnum) {
        outputBillDetails.forEach(billDetail -> {
            billDetail.setStatus(statusEnum.getValue());
            billDetail.setUpdateTime(new Date());
            billDetail.setUpdateUserId(BaseContextHandler.getUserID());
            billDetail.setUpdateUserName(BaseContextHandler.getUsername());
            billDetail.setManualUniqueCode(billDetail.getManualUniqueCode());
            billDetail.setUniqueCode(billDetail.getUniqueCode());
        });
        detailService.saveOrUpdateBatch(outputBillDetails);
    }

    private WarehouseOutputRecordBill saveRecordBill(WarehouseOutputBill outputBill) {
        WarehouseOutputRecordBill outputRecordBill = modelMapper.map(outputBill, WarehouseOutputRecordBill.class);
        outputRecordBill.setId(null);
        outputRecordBill.setRecordBillNo(CodeGenUtil.genOutputRecordBillNo());
        outputRecordBill.setOutputBillId(outputBill.getId());
        outputRecordBill.setOutputBillNo(outputBill.getBillNo());
        if (ObjectUtils.isEmpty(outputBill.getCreateTime())) {
            outputRecordBill.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserName())) {
            outputRecordBill.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(outputBill.getCreateUserId())) {
            outputRecordBill.setCreateUserId(BaseContextHandler.getUserID());
        }
        outputRecordBillService.saveOrUpdate(outputRecordBill);
        return outputRecordBill;
    }

    private void saveRecordBillDetail(WarehouseOutputRecordBill outputRecordBill, WarehouseOutputBillDetail outputBillDetail,
                                      BigDecimal requireCount, BigDecimal outputCount, WarehouseInventory inventory, OutputBillStatusEnum statusEnum) {
        WarehouseOutputRecordBillDetail outputRecordBillDetail = modelMapper.map(outputBillDetail, WarehouseOutputRecordBillDetail.class);
        outputRecordBillDetail.setId(null);
        outputRecordBillDetail.setRecordBillNo(outputRecordBill.getRecordBillNo());
        outputRecordBillDetail.setRecordBillId(outputRecordBill.getId());
        outputRecordBillDetail.setOutputBillId(outputBillDetail.getOutputBillId());
        outputRecordBillDetail.setOutputBillNo(outputBillDetail.getOutputBillNo());
        outputRecordBillDetail.setRequireCount(requireCount);
        outputRecordBillDetail.setOutputCount(outputCount);
        outputBillDetail.setOutputCount(outputCount);
        outputRecordBillDetail.setDestination(outputRecordBill.getDestination());
        if (inventory != null) {
            outputRecordBillDetail.setWarehouseId(inventory.getWarehouseId());
            outputRecordBillDetail.setWarehouseName(inventory.getWarehouseName());
            outputRecordBillDetail.setWarehouseCode(inventory.getWarehouseCode());
        }
        outputRecordBillDetail.setStatus(statusEnum.getValue());
        if (ObjectUtils.isEmpty(outputRecordBill.getCreateTime())) {
            outputRecordBillDetail.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(outputRecordBill.getCreateUserName())) {
            outputRecordBillDetail.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(outputRecordBill.getCreateUserId())) {
            outputRecordBillDetail.setCreateUserId(BaseContextHandler.getUserID());
        }
        if (StringUtils.isNotBlank(outputBillDetail.getManualUniqueCode())) {
            outputRecordBillDetail.setManualUniqueCode(outputBillDetail.getManualUniqueCode());
        }
        outputRecordBillDetailService.saveOrUpdate(outputRecordBillDetail);
    }

}