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

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
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.MaterialModelDto;
import com.sw.mes.core.dto.MaterialTypeDto;
import com.sw.mes.core.dto.WMSToWarehouseInputDto;
import com.sw.mes.core.dto.store.WarehouseInputBillDetailBo;
import com.sw.mes.core.dto.wms.*;
import com.sw.mes.core.enums.InputBillTypeEnum;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.ResponsePage;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.EasyExcelUtils;
import com.sw.mes.core.utils.RedisTools;
import com.sw.mes.core.utils.RequestPage;
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.InputBillImportDto;
import com.sw.mes.store.dto.WarehouseInputBillDetailDto;
import com.sw.mes.store.dto.WarehouseInputBillDto;
import com.sw.mes.store.dto.WarehouseInputBillPdaBo;
import com.sw.mes.store.entity.*;
import com.sw.mes.store.enums.InputBillStatusEnum;
import com.sw.mes.store.enums.OutputBillTypeEnum;
import com.sw.mes.store.enums.OutputDestinationEnum;
import com.sw.mes.store.mapper.WarehouseInputBillMapper;
import com.sw.mes.store.service.*;
import com.sw.mes.store.utils.CodeGenUtil;
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.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description TODO
 * @Author wupeng
 * @Date 2023/7/25 14:13
 **/
@Service
public class WarehouseInputBillServiceImpl extends ServiceImpl<WarehouseInputBillMapper, WarehouseInputBill> implements WarehouseInputBillService {

    private static final Logger LOGGER = LoggerFactory.getLogger(WarehouseInputBillServiceImpl.class);

    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private WarehouseInputBillService warehouseInputBillService;

    @Autowired
    private WarehouseInputBillMapper warehouseInputBillMapper;

    @Autowired
    private WarehouseInputBillDetailService inputBillDetailService;

    @Autowired
    private WarehouseInventoryService inventoryService;

    @Autowired
    private WarehouseMaterialService materialService;

    @Autowired
    private WarehouseModelService warehouseModelService;

    @Autowired
    private WarehouseConsumerService warehouseConsumerService;

    @Autowired
    private YbFeignClients ybFeignClients;

    @Autowired
    private WarehouseInputRecordBillService inputRecordBillService;

    @Autowired
    private WarehouseInputRecordBillDetailService inputRecordBillDetailService;

    @Autowired
    private WarehouseOutputBillService warehouseOutputBillService;

    @Autowired
    private WarehouseOutputBillDetailService warehouseOutputBillDetailService;


    /**
     * 保存入库单及其明细
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveInputBill(WarehouseInputBillDto bill) {
        //入库明细
        List<WarehouseInputBillDetailDto> details = bill.getInputBillDetails();
        if (CollectionUtils.isEmpty(details)) {
            throw new BusinessException("入库明细为空，请检查数据！");
        }
        //入库单号
        String billNo = bill.getBillNo();
        billNo = StringUtils.isNotBlank(billNo) ? billNo : CodeGenUtil.genInputBillNo();
        WarehouseInputBill byBillNo = this.getByBillNo(billNo);
        if (byBillNo != null) {
            throw new BusinessException("入库单号【" + billNo + "】已存在，请检查数据！");
        }
        bill.setBillNo(billNo);
        if (ObjectUtils.isEmpty(bill.getCreateTime())) {
            bill.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(bill.getCreateUserName())) {
            bill.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(bill.getCreateUserId())) {
            bill.setCreateUserId(BaseContextHandler.getUserID());
        }
        bill.setStatus(InputBillStatusEnum.待入库.getValue());
        //保存入库单
        WarehouseInputBill inputBill = modelMapper.map(bill, WarehouseInputBill.class);
        inputBill.setId(null);
        warehouseInputBillService.saveOrUpdate(inputBill);
        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();
        List<WarehouseInputBillDetail> inputBillDetails = new ArrayList<>();
        for (WarehouseInputBillDetailDto inputBillDetail : details) {
            Long materialModelId = inputBillDetail.getMaterialModelId();
            String materialModelCode = inputBillDetail.getMaterialModelCode();
            WarehouseMaterial warehouseMaterial = null;
            if (materialModelId != null) {
                warehouseMaterial = materialService.getByMaterialId(materialModelId);
            }
            if (warehouseMaterial == null) {
                warehouseMaterial = materialService.getByMaterialCode(materialModelCode);
            }
            String uniqueCode = inputBillDetail.getUniqueCode();
            String batchNo = inputBillDetail.getBatchNo();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //同一条数据的唯一码和批次号不能相同
                if (uniqueCode.equals(batchNo)) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】和批次号重复，请检查数据重新输入！");
                }
                //校验当前即将入库的明细中唯一码是否重复
                boolean add = uniqueCodeSet.add(uniqueCode);
                //查询是否已存在重复唯一码
                if (!add) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据重新输入！");
                } else {
                    BigDecimal count = inputBillDetail.getCount();
                    //唯一码物料库存只能是 1
                    if (count.compareTo(new BigDecimal(1)) == 1) {
                        throw new BusinessException("唯一码【" + uniqueCode + "】物料入库数量只能为1，请检查数据重新输入！");
                    }
                }
            }
            Long warehouseId = inputBillDetail.getWarehouseId();
            if (bill.getAutoAudit() && (warehouseId == null || warehouseId == 0) && StringUtils.isEmpty(inputBillDetail.getWarehouseCode())) {
                //查询物料模型配置，自动审核的单子可能没有库位信息，则用配置的默认库位
                if (warehouseMaterial == null) {
                    throw new BusinessException("入库物料ID：【" + materialModelId + "】，物料号：【" + materialModelCode + "】未配置线边仓物料模型！");
                }
                inputBillDetail.setWarehouseId(warehouseMaterial.getDefaultLocationId());
                inputBillDetail.setWarehouseName(warehouseMaterial.getDefaultLocation());
                WarehouseModel warehouseModel = warehouseModelService.getById(warehouseMaterial.getDefaultLocationId());
                if (warehouseModel != null) inputBillDetail.setWarehouseCode(warehouseModel.getCode());
            }
            if (null != warehouseId) {
                //找到对应仓库
                WarehouseModel warehouseModel = warehouseModelService.getById(inputBillDetail.getWarehouseId());
                if (warehouseModel != null) {
                    inputBillDetail.setWarehouseId(warehouseModel.getId());
                    inputBillDetail.setWarehouseName(warehouseModel.getName());
                }
            }
            if (StringUtils.isNotBlank(inputBillDetail.getWarehouseCode())) {
                //找到对应仓库
                WarehouseModel warehouseModel = warehouseModelService.findByCode(inputBillDetail.getWarehouseCode());
                if (warehouseModel != null) {
                    inputBillDetail.setWarehouseId(warehouseModel.getId());
                    inputBillDetail.setWarehouseName(warehouseModel.getName());
                }
            }

            inputBillDetail.setInputBillId(inputBill.getId());
            inputBillDetail.setInputBillNo(inputBill.getBillNo());
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateTime())) {
                inputBillDetail.setCreateTime(new Date());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserName())) {
                inputBillDetail.setCreateUserName(BaseContextHandler.getUsername());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserId())) {
                inputBillDetail.setCreateUserId(BaseContextHandler.getUserID());
            }
            inputBillDetail.setType(inputBill.getType());
            inputBillDetail.setStatus(InputBillStatusEnum.待入库.getValue());
            WarehouseInputBillDetail warehouseInputBillDetails = modelMapper.map(inputBillDetail, WarehouseInputBillDetail.class);
            warehouseInputBillDetails.setId(null);
            inputBillDetails.add(warehouseInputBillDetails);
        }
        inputBillDetailService.saveOrUpdateBatch(inputBillDetails);
//        if (inputBill.getType().equals(InputBillTypeEnum.废料入库.getValue())) {
//            try {
//                WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
//                warehouseOutputBill.setType(inputBill.getType().equals(InputBillTypeEnum.余料入库.getValue())
//                        ? OutputBillTypeEnum.余料出库.getValue() : inputBill.getType());
//                warehouseOutputBill.setRemark(inputBill.getRemark());
//                warehouseOutputBill.setDestination(OutputDestinationEnum.车间.getValue());
//                warehouseOutputBill.setAutoAudit(false);
//                warehouseOutputBill.setCreateTime(new Date());
//                warehouseOutputBill.setCreateUserName(BaseContextHandler.getUsername());
//                warehouseOutputBill.setStatus("0");
//                warehouseOutputBill.setBillNo(CodeGenUtil.genOutputBillNo());
//                warehouseOutputBill.setInputBillCode(billNo);
//                inputBillDetails.stream().forEach(dto -> {
//                    WarehouseOutputBillDetail detail = new WarehouseOutputBillDetail();
//                    BeanUtils.copyProperties(dto, detail, "id");
//                    detail.setOutputCount(dto.getCount());
//                    detail.setRequireCount(dto.getCount());
//                    detail.setCreateUserId(BaseContextHandler.getUserID());
//                    detail.setCreateUserName(BaseContextHandler.getUsername());
//                    detail.setCreateTime(new Date());
//                    detail.setType(dto.getType().equals(InputBillTypeEnum.余料入库.getValue())
//                            ? OutputBillTypeEnum.余料出库.getValue() : dto.getType());
//                    detail.setStatus("待出库");
//                    detail.setDestination(OutputDestinationEnum.车间.getValue());
//                    warehouseOutputBill.getOutputBillDetails().add(detail);
//                });
//                warehouseOutputBillService.saveOutputBills(warehouseOutputBill);
//                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
//                List<MesasnDto> mesasnDtos = new ArrayList<>();
//                //组装对应数据
//                MesasnDto mesasnDto = new MesasnDto();
//                mesasnDto.setOrganizationid("JINKO");
//                mesasnDto.setWarehouseid("5041");
//                mesasnDto.setCustomerid("5041");
//                mesasnDto.setDocno(warehouseOutputBill.getBillNo());
//                mesasnDto.setAsntype("CLCPRK");
//                mesasnDto.setAsnstatus("00");
//                mesasnDto.setAsnreferenced("余料入库");
//                mesasnDto.setAsnreferencec("P501");
//                mesasnDto.setAsncreationtime(sdf.format(inputBill.getCreateTime()));
//                mesasnDto.setTraceid(inputBill.getInputBillDetails().get(0).getTraceid());//托盘号
//                mesasnDto.setSerialno(inputBill.getInputBillDetails().get(0).getTraceid());//箱号
//                mesasnDto.setExpectedqty(String.valueOf(inputBill.getInputBillDetails().size()));//组件数量
//                mesasnDto.setLotatt01(sdf.format(new Date()));
//                mesasnDto.setLotatt04(inputBill.getInputBillDetails().get(0).getBatchNo());//入库批次
//                mesasnDto.setLotatt08("Y");//质量状态
////                mesasnDto.setLotatt09();//厂家
//                mesasnDto.setLotatt12(inputBill.getInputBillDetails().get(0).getBatchNo());//生产批次
//                mesasnDto.setLotatt19(inputBill.getInputBillDetails().get(0).getLotatt20());//电阻率
//                mesasnDto.setLotatt20(inputBill.getInputBillDetails().get(0).getMaterialLevel());//等级
//                mesasnDto.setSku(inputBill.getInputBillDetails().get(0).getMaterialModelCode());
//                mesasnDto.setCreatesource("MES");
//                List<MesasnOrderDto> mesasnOrderDtos = new ArrayList<>();
//                inputBill.getInputBillDetails().stream().forEach(detais -> {
//                    MesasnOrderDto mesasnOrderDto = new MesasnOrderDto();
//                    mesasnOrderDto.setSku(detais.getMaterialModelCode());
//                    mesasnOrderDto.setTraceid(detais.getTraceid());
//                    mesasnOrderDto.setSerialno(detais.getSerialNo());
//                    mesasnOrderDto.setExpectedqty(String.valueOf(detais.getCount()));//箱重量
//                    mesasnOrderDto.setLotatt01(sdf.format(new Date()));
//                    mesasnOrderDto.setLotatt04(detais.getBatchNo());//入库批次
////                    mesasnOrderDto.setLotatt09();//厂家
//                    mesasnOrderDto.setLotatt12(detais.getBatchNo());//生产批次
//                    mesasnOrderDto.setLotatt19(detais.getLotatt19());//电阻率
//                    mesasnOrderDto.setLotatt20(detais.getMaterialLevel());//等级
//                    mesasnOrderDto.setDedi07(String.valueOf(detais.getCount()));//长度,整箱长度
//                    mesasnOrderDto.setDedi08(detais.getBatchNo());//批号,MES下线批
//                    mesasnOrderDto.setLotatt08("Y");
//                    mesasnOrderDtos.add(mesasnOrderDto);
//                });
//                mesasnDto.setOrderList(mesasnOrderDtos);
//                mesasnDtos.add(mesasnDto);
//                //发起WMS入库
//                Result result = ybFeignClients.mesasn(mesasnDtos);
//                if (result.getCode() != 200) {
//                    throw new BusinessException("成品MES入库接口，状态码" + result.getCode() + "，反馈信息" + result.getMessage());
//                }
//            } catch (Exception ex) {
//                throw new BusinessException("出库失败->" + ex.getMessage());
//            }
//        }
        if (bill.getAutoAudit()) {
            //如果是自动审核，直接入库
            List<WarehouseInputBillDetail> warehouseInputBillDetail = inputBillDetailService.getByBillId(inputBill.getId());
            inputBill.setInputBillDetails(warehouseInputBillDetail);
            warehouseInputBillService.autoReceiveAtomic(inputBill);
            //保存审核记录及审核明细
            this.saveRecord(inputBill);
        }
    }

    /**
     * 保存入库单及明细，返回入库单号
     *
     * @param bill
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveInputBills(WarehouseInputBillDto bill) {
        //入库明细
        List<WarehouseInputBillDetailDto> details = bill.getInputBillDetails();
        if (CollectionUtils.isEmpty(details)) {
            throw new BusinessException("入库明细为空，请检查数据！");
        }
        //入库单号
        String billNo = bill.getBillNo();
        billNo = StringUtils.isNotBlank(billNo) ? billNo : CodeGenUtil.genInputBillNo();
        WarehouseInputBill byBillNo = this.getByBillNo(billNo);
        if (byBillNo != null) {
            throw new BusinessException("入库单号【" + billNo + "】已存在，请检查数据！");
        }
        bill.setBillNo(billNo);
        if (ObjectUtils.isEmpty(bill.getCreateTime())) {
            bill.setCreateTime(new Date());
        }
        if (ObjectUtils.isEmpty(bill.getCreateUserName())) {
            bill.setCreateUserName(BaseContextHandler.getUsername());
        }
        if (ObjectUtils.isEmpty(bill.getCreateUserId())) {
            bill.setCreateUserId(BaseContextHandler.getUserID());
        }
        bill.setStatus(InputBillStatusEnum.待入库.getValue());
        //保存入库单
        WarehouseInputBill inputBill = modelMapper.map(bill, WarehouseInputBill.class);
        inputBill.setId(null);
        warehouseInputBillService.saveOrUpdate(inputBill);
        //当开启了唯一码，用于判断是否存在相同的唯一码，只要唯一码不同，其他字段可以相同
        Set<String> uniqueCodeSet = new HashSet<>();
        List<WarehouseInputBillDetail> inputBillDetails = new ArrayList<>();
        for (WarehouseInputBillDetailDto inputBillDetail : details) {
            Long materialModelId = inputBillDetail.getMaterialModelId();
            String materialModelCode = inputBillDetail.getMaterialModelCode();
            WarehouseMaterial warehouseMaterial = null;
            if (materialModelId != null) {
                warehouseMaterial = materialService.getByMaterialId(materialModelId);
            }
            if (warehouseMaterial == null) {
                warehouseMaterial = materialService.getByMaterialCode(materialModelCode);
            }
            String uniqueCode = inputBillDetail.getUniqueCode();
            String batchNo = inputBillDetail.getBatchNo();
            if (StringUtils.isNotBlank(uniqueCode)) {
                //同一条数据的唯一码和批次号不能相同
                if (uniqueCode.equals(batchNo)) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】和批次号重复，请检查数据重新输入！");
                }
                //校验当前即将入库的明细中唯一码是否重复
                boolean add = uniqueCodeSet.add(uniqueCode);
                //查询是否已存在重复唯一码
                if (!add) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】重复，请检查数据重新输入！");
                } else {
                    BigDecimal count = inputBillDetail.getCount();
                    //唯一码物料库存只能是 1
                    if (count.compareTo(new BigDecimal(1)) == 1) {
                        throw new BusinessException("唯一码【" + uniqueCode + "】物料入库数量只能为1，请检查数据重新输入！");
                    }
                }
            }
            Long warehouseId = inputBillDetail.getWarehouseId();
            if (bill.getAutoAudit() && (warehouseId == null || warehouseId == 0) && StringUtils.isEmpty(inputBillDetail.getWarehouseCode())) {
                //查询物料模型配置，自动审核的单子可能没有库位信息，则用配置的默认库位
                if (warehouseMaterial == null) {
                    throw new BusinessException("入库物料ID：【" + materialModelId + "】，物料号：【" + materialModelCode + "】未配置线边仓物料模型！");
                }
                inputBillDetail.setWarehouseId(warehouseMaterial.getDefaultLocationId());
                inputBillDetail.setWarehouseName(warehouseMaterial.getDefaultLocation());
                WarehouseModel warehouseModel = warehouseModelService.getById(warehouseMaterial.getDefaultLocationId());
                if (warehouseModel != null) inputBillDetail.setWarehouseCode(warehouseModel.getCode());
            }
            if (null != warehouseId) {
                //找到对应仓库
                WarehouseModel warehouseModel = warehouseModelService.getById(inputBillDetail.getWarehouseId());
                if (warehouseModel != null) {
                    inputBillDetail.setWarehouseId(warehouseModel.getId());
                    inputBillDetail.setWarehouseName(warehouseModel.getName());
                }
            }
            if (StringUtils.isNotBlank(inputBillDetail.getWarehouseCode())) {
                //找到对应仓库
                WarehouseModel warehouseModel = warehouseModelService.findByCode(inputBillDetail.getWarehouseCode());
                if (warehouseModel != null) {
                    inputBillDetail.setWarehouseId(warehouseModel.getId());
                    inputBillDetail.setWarehouseName(warehouseModel.getName());
                }
            }
            inputBillDetail.setInputBillId(inputBill.getId());
            inputBillDetail.setInputBillNo(inputBill.getBillNo());
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateTime())) {
                inputBillDetail.setCreateTime(new Date());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserName())) {
                inputBillDetail.setCreateUserName(BaseContextHandler.getUsername());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserId())) {
                inputBillDetail.setCreateUserId(BaseContextHandler.getUserID());
            }
            inputBillDetail.setType(inputBill.getType());
            inputBillDetail.setStatus(InputBillStatusEnum.待入库.getValue());
            WarehouseInputBillDetail warehouseInputBillDetail = modelMapper.map(inputBillDetail, WarehouseInputBillDetail.class);
            warehouseInputBillDetail.setId(null);
            inputBillDetails.add(warehouseInputBillDetail);
        }
        inputBillDetailService.saveOrUpdateBatch(inputBillDetails);
        if (bill.getAutoAudit()) {
            //如果是自动审核，直接入库
            List<WarehouseInputBillDetail> warehouseInputBillDetail = inputBillDetailService.getByBillId(inputBill.getId());
            inputBill.setInputBillDetails(warehouseInputBillDetail);
            warehouseInputBillService.autoReceiveAtomic(inputBill);
            //保存审核记录及审核明细
            this.saveRecord(inputBill);
        }
        return billNo;
    }

    @Override
    public WarehouseInputBill getByBillNo(String billNo) {
        return warehouseInputBillMapper.getByBillNo(billNo);
    }

    /**
     * 审核入库，原子操作
     **/
    @Override
    public void auditReceiveAtomic(WarehouseInputBill inputBill) {
        RLock lock = RedissonUtils.getRLock(redissonClient, WarehouseConstant.UPDATE_INVENTORY_LOCK_KEY);
        boolean isLock = RedissonUtils.getRLockExpireTime(lock, 2L, 5L);
        //入库单明细入库。防止并发修改库存，加锁
        if (isLock) {
            try {
                lock.lock();
                warehouseInputBillService.auditReceive(inputBill);
            } finally {
                if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
                    lock.unlock();
                }
            }
        } else {
            throw new BusinessException("有其他人正在操作，请稍后再试！");
        }
    }

    @Override
    public void returnMaterialToWMS(WarehouseInputBill inputBill) {
        WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
        warehouseOutputBill.setType(OutputBillTypeEnum.WMS退料.getValue());
        warehouseOutputBill.setRemark(inputBill.getRemark());
        warehouseOutputBill.setDestination(OutputDestinationEnum.车间.getValue());
        warehouseOutputBill.setAutoAudit(false);
        warehouseOutputBill.setCreateTime(new Date());
        warehouseOutputBill.setCreateUserName(BaseContextHandler.getUsername());
        warehouseOutputBill.setStatus("0");
        String inputBillNo = inputBill.getBillNo();
        warehouseOutputBill.setInputBillCode(inputBillNo);
        inputBill.getInputBillDetails().stream().forEach(details -> {
            WarehouseOutputBillDetail detail = new WarehouseOutputBillDetail();
            BeanUtils.copyProperties(details, detail, "id");
            detail.setOutputCount(details.getCount());
            detail.setRequireCount(details.getCount());
            detail.setQuantity(details.getCount());
            detail.setCreateUserId(BaseContextHandler.getUserID());
            detail.setCreateUserName(BaseContextHandler.getUsername());
            detail.setCreateTime(new Date());
            detail.setType(OutputBillTypeEnum.WMS退料.getValue());
            detail.setStatus("待出库");
            detail.setDestination(OutputDestinationEnum.WMS.getValue());
            detail.setTraceid(details.getTraceid());
            detail.setSerialNo(details.getSerialNo());
            warehouseOutputBill.getOutputBillDetails().add(detail);
        });
        warehouseOutputBillService.saveOutputBills(warehouseOutputBill);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        RematDto data = new RematDto();
        RematHeaderDto header = new RematHeaderDto();
        List<RematDetailsDto> details = new ArrayList<RematDetailsDto>();
        header.setCustomerid("5041");
        header.setDocno(warehouseOutputBill.getBillNo());
        header.setAsntype("XBTL");
        header.setCreationtime(sdf.format(new Date()));
        header.setHedi01(String.valueOf(warehouseOutputBill.getCreateUserId()));
        header.setHedi02(warehouseOutputBill.getCreateUserName());
        header.setHedi05(warehouseOutputBill.getOutputBillDetails().get(0).getWarehouseCode());
        data.setHeader(header);
        warehouseOutputBill.getOutputBillDetails().stream().forEach(entity -> {
            RematDetailsDto dto = new RematDetailsDto();
            dto.setLineno(String.valueOf(entity.getId()));
            dto.setCustomerid(entity.getCustomer());
            dto.setSku(entity.getMaterialModelCode());
            dto.setQty(String.valueOf(entity.getOutputCount()));
            dto.setLotatt08("Y");
            if (com.sw.mes.core.utils.StringUtils.isNotEmpty(entity.getTraceid())) {
                dto.setTraceid(entity.getTraceid());
            }
            if (com.sw.mes.core.utils.StringUtils.isNotEmpty(entity.getSerialNo())) {
                dto.setSerialno(entity.getSerialNo());
            }
            details.add(dto);
        });
        data.setDetails(details);
        Result remat = ybFeignClients.remat(data);
        if (remat.getCode() != 200) {
            throw new BusinessException("车间退料入库接口,状态码" + remat.getCode() + "，反馈信息" + remat.getMessage());
        }
    }

    /**
     * 审核入库。审核通过，入库单明细存入库存，更新入库单状态
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void auditReceive(WarehouseInputBill inputBill) {
        WarehouseInputBill warehouseInputBill = this.getByBillNo(inputBill.getBillNo());
        if (warehouseInputBill == null) {
            throw new BusinessException("入库单号：" + inputBill.getBillNo() + "信息为空，请检查数据！");
        }
        String status = warehouseInputBill.getStatus();
        if (!InputBillStatusEnum.待入库.getValue().equals(status)) {
            throw new BusinessException("入库单号：" + inputBill.getBillNo() + "状态不是" + InputBillStatusEnum.待入库.getValue() + "状态，审核失败！");
        }
        //更新库存
        auditAddInventory(inputBill);
        //保存审核记录及审核明细
        this.saveRecord(inputBill);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterAuditInput(inputBill);
    }

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

    /**
     * 无需审核，直接入库
     **/
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void autoReceive(WarehouseInputBill inputBill) {
        autoAddInventory(inputBill);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterAutoInput(inputBill);
    }

    /**
     * 审核-拒收
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result rejectApply(WarehouseInputBill inputBill) {

        String billNo = inputBill.getBillNo();
        if (StringUtils.isBlank(billNo)) {
            return ResultGenerator.fail("单据号不能为空！");
        }
        WarehouseInputBill byBill = this.getByBillNo(billNo);
        if (byBill == null) {
            return ResultGenerator.fail("该单据不存在！");
        }
        String status = byBill.getStatus();
        if (!InputBillStatusEnum.待入库.getValue().equals(status)) {
            return ResultGenerator.fail("该单据已经是【" + status + "】状态，无法拒收！");
        }
        byBill.setRejectReason(inputBill.getRejectReason());
        byBill.setRejectReasonRemark(inputBill.getRejectReasonRemark());
        byBill.setStatus(InputBillStatusEnum.拒收.getValue());
        byBill.setUpdateUserName(BaseContextHandler.getUsername());
        byBill.setUpdateTime(new Date());
        byBill.setUpdateUserId(BaseContextHandler.getUserID());
        //更新入库单状态
        warehouseInputBillService.saveOrUpdate(byBill);
        //更新入库明细状态为"拒收"
        List<WarehouseInputBillDetail> billDetails = inputBillDetailService.getByBillNo(billNo);
        if (billDetails == null || billDetails.size() == 0) {
            return ResultGenerator.fail("该单据明细为空，拒收失败！");
        }
        billDetails.forEach(e -> {
            e.setStatus(InputBillStatusEnum.拒收.getValue());
            e.setUpdateTime(byBill.getUpdateTime());
            e.setUpdateUserId(BaseContextHandler.getUserID());
            e.setUpdateUserName(BaseContextHandler.getUsername());
        });
        inputBillDetailService.saveOrUpdateBatch(billDetails);
//        //保存审核记录
//        this.saveRecord(inputBill);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        inputBill.setStatus(byBill.getStatus());
        warehouseConsumerService.afterInputReject(inputBill);
        return ResultGenerator.success();
    }

    /**
     * 取消入库
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelApply(String billNo) {
        if (StringUtils.isBlank(billNo)) {
            throw new BusinessException("入库单号为空！");
        }
        WarehouseInputBill byBill = warehouseInputBillService.getByBillNo(billNo);
        if (byBill == null) {
            throw new BusinessException("该单据不存在！");
        }
        String status = byBill.getStatus();
        if (!InputBillStatusEnum.待入库.getValue().equals(status)) {
            throw new BusinessException("该单据为【" + status + "】状态，无法操作！");
        }
        byBill.setStatus(InputBillStatusEnum.已取消.getValue());
        byBill.setUpdateTime(new Date());
        byBill.setUpdateUserId(BaseContextHandler.getUserID());
        byBill.setUpdateUserName(BaseContextHandler.getUsername());
        //更新入库单状态
        warehouseInputBillService.saveOrUpdate(byBill);
        //更新入库明细状态
        List<WarehouseInputBillDetail> billDetails = inputBillDetailService.getByBillNo(billNo);
        if (CollectionUtils.isEmpty(billDetails)) {
            throw new BusinessException("该单据明细为空，取消失败！");
        }
        billDetails.forEach(e -> {
            e.setStatus(InputBillStatusEnum.已取消.getValue());
            e.setUpdateTime(byBill.getUpdateTime());
            e.setUpdateUserId(BaseContextHandler.getUserID());
            e.setUpdateUserName(BaseContextHandler.getUsername());
        });
        inputBillDetailService.saveOrUpdateBatch(billDetails);
//        //保存审核记录，为审核通过不需要记录
//        this.saveRecord(byBill);
        //TODO wupeng 此处需要调用其他需要反馈的系统接口
        warehouseConsumerService.afterInputCancel(byBill);
    }

    /**
     * 审核入库，添加库存，更新入库单、入库单明细状态
     **/
    private void auditAddInventory(WarehouseInputBill inputBill) {
        //修改入库单状态
        inputBill.setStatus(InputBillStatusEnum.已入库.getValue());
        inputBill.setUpdateTime(new Date());
        inputBill.setUpdateUserId(BaseContextHandler.getUserID());
        inputBill.setUpdateUserName(BaseContextHandler.getUsername());
        warehouseInputBillService.saveOrUpdate(inputBill);
        //入库明细
        List<WarehouseInputBillDetail> billDetails = inputBill.getInputBillDetails();
        if (CollectionUtils.isEmpty(billDetails)) {
            throw new BusinessException("入库单号：" + inputBill.getBillNo() + "对应的入库明细为空，请检查数据！");
        }
        //修改入库明细状态
        this.updateDetail(billDetails);
        for (WarehouseInputBillDetail billDetail : billDetails) {
            Long warehouseId = billDetail.getWarehouseId();
            if (warehouseId == null || warehouseId == 0) {
                throw new BusinessException("未填写库位信息，请检查数据！");
            }
            WarehouseModel warehouseModel = warehouseModelService.getById(warehouseId);
            if (warehouseModel == null) {
                throw new BusinessException("库位信息不存在，请检查数据！");
            }
            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
                billDetail.setWarehouseCode(warehouseModel.getCode());
            }
            //查询线边仓-物料模型配置表中物料信息
            String uniqueCode = billDetail.getUniqueCode();
            String batchNo = billDetail.getBatchNo();
            if (StringUtils.isNotBlank(uniqueCode)) {
                WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(uniqueCode);
                if (byUniqueCode != null) {
                    throw new BusinessException("已存在相同唯一码【" + uniqueCode + "】库存记录，请重新输入唯一码！");
                }
                BigDecimal count = billDetail.getCount();
                //唯一码物料库存只能是 1
                if (count.compareTo(new BigDecimal(1)) == 1) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】入库数量只能为1，请检查数据！");
                }
                //检查当前数据的唯一码是否是其他数据的批次号，不同数据 的唯一码和批次号都不能相同
                List<WarehouseInventory> byBatchNo = inventoryService.getByBatchNo(uniqueCode);
                if (CollectionUtils.isNotEmpty(byBatchNo)) {
                    throw new BusinessException("当前唯一码【" + uniqueCode + "】与已有的批次号重复，请检查数据！");
                }
            } else {
                Long materialModelId = billDetail.getMaterialModelId();
                String materialModelCode = billDetail.getMaterialModelCode();
                WarehouseMaterial warehouseMaterial = null;
                if (materialModelId != null) {
                    warehouseMaterial = materialService.getByMaterialId(materialModelId);
                }
                if (warehouseMaterial == null) {
                    warehouseMaterial = materialService.getByMaterialCode(materialModelCode);
                }
                if (warehouseMaterial != null && warehouseMaterial.getUniqueCode()) {
                    throw new BusinessException(billDetail.getMaterialModelCode() + "唯一码为空，请检查数据重新输入！");
                }
                //未开启唯一码，开启了批次号。批次号+物料编码+库位 判重
                if (StringUtils.isNotBlank(batchNo)) {
                    List<WarehouseInventory> warehouseInventory = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo, billDetail.getMaterialModelCode(), billDetail.getWarehouseId());
                    warehouseInventory = warehouseInventory.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(warehouseInventory)) {
                        WarehouseInventory inventory = warehouseInventory.get(0);
                        inventory.setQuantity(inventory.getQuantity().add(billDetail.getCount()));
                        inventoryService.updateInventory(inventory, 1);
                        continue;
                    }
                    //检查当前数据的批次号是否是其他数据的唯一码，不同数据 的唯一码和批次号都不能相同
                    WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(batchNo);
                    if (byUniqueCode != null) {
                        throw new BusinessException("当前批次号【" + batchNo + "】与已有的唯一码重复，请检查数据！");
                    }
                } else {
                    //未开启唯一码和批次号，物料+库位判重
                    List<WarehouseInventory> byCodeAndNull = inventoryService.getByMaterialAndBatchNoAndWarehouseId(null, billDetail.getMaterialModelCode(), billDetail.getWarehouseId());
                    byCodeAndNull = byCodeAndNull.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode()) && StringUtils.isBlank(e.getBatchNo())).collect(Collectors.toList());
                    //如果已存在，则更新库存数量，不存在则执行新增操作
                    if (CollectionUtils.isNotEmpty(byCodeAndNull)) {
                        WarehouseInventory inventory = byCodeAndNull.get(0);
                        inventory.setQuantity(inventory.getQuantity().add(billDetail.getCount()));
                        inventoryService.updateInventory(inventory, 1);
                        continue;
                    }
                }
            }
            addInventory(billDetail);
        }
    }

    /**
     * 自动入库，添加库存，更新入库单、入库单明细状态
     **/
    private void autoAddInventory(WarehouseInputBill inputBill) {
        //修改入库单状态
        inputBill.setStatus(InputBillStatusEnum.已入库.getValue());
        inputBill.setUpdateTime(new Date());
        inputBill.setUpdateUserId(BaseContextHandler.getUserID());
        inputBill.setUpdateUserName(BaseContextHandler.getUsername());
        warehouseInputBillService.saveOrUpdate(inputBill);
        //数据库中的入库明细
        List<WarehouseInputBillDetail> billDetails = inputBill.getInputBillDetails();
        if (CollectionUtils.isEmpty(billDetails)) {
            throw new BusinessException("入库单号【" + inputBill.getBillNo() + "】对应的入库明细为空，请检查数据！");
        }
        //修改入库明细状态
        this.updateDetail(billDetails);
        for (WarehouseInputBillDetail billDetail : billDetails) {
//            Long warehouseId = billDetail.getWarehouseId();
//            if ((warehouseId == null || warehouseId == 0) && StringUtils.isEmpty(billDetail.getWarehouseCode())) {
//                throw new BusinessException("未填写库位信息，请检查数据！");
//            }
//            WarehouseModel warehouseModel = warehouseModelService.getById(warehouseId);
//            if (null == warehouseModel) {
//                warehouseModel = warehouseModelService.getCode(billDetail.getWarehouseCode());
//            }
//            if (warehouseModel == null) {
//                throw new BusinessException("库位信息不存在，请检查数据！");
//            }
            if (null == billDetail.getWarehouseId() && StringUtils.isEmpty(billDetail.getWarehouseCode())) {
                throw new BusinessException("库位信息不存在，请检查数据！");
            }
            if (StringUtils.isEmpty(billDetail.getWarehouseCode())) {
                Long warehouseId = billDetail.getWarehouseId();
                if ((warehouseId == null || warehouseId == 0) && StringUtils.isEmpty(billDetail.getWarehouseCode())) {
                    throw new BusinessException("未填写库位信息，请检查数据！");
                }
                WarehouseModel warehouseModel = warehouseModelService.getById(warehouseId);
                billDetail.setWarehouseCode(warehouseModel.getCode());
                if (warehouseModel == null) {
                    throw new BusinessException("库位信息不存在，请检查数据！");
                }
            }
            billDetail.setWarehouseId(billDetail.getWarehouseId());
            billDetail.setWarehouseName(billDetail.getWarehouseName());
            String uniqueCode = billDetail.getUniqueCode();
            String batchNo = billDetail.getBatchNo();
            if (StringUtils.isNotBlank(uniqueCode)) {
                WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(uniqueCode);
                if (byUniqueCode != null) {
                    throw new BusinessException("已存在相同唯一码【" + uniqueCode + "】库存记录，请重新输入唯一码！");
                }
                BigDecimal count = billDetail.getCount();
                //唯一码物料库存只能是 1
                if (count.compareTo(new BigDecimal(1)) == 1) {
                    throw new BusinessException("唯一码【" + uniqueCode + "】入库数量只能为1，请检查数据！");
                }
                //检查当前数据的唯一码是否是其他数据的批次号，不同数据 的唯一码和批次号都不能相同
//                List<WarehouseInventory> byBatchNo = inventoryService.getByBatchNo(batchNo);
//                if (CollectionUtils.isNotEmpty(byBatchNo)) {
//                    throw new BusinessException("当前唯一码【" + uniqueCode + "】与已有的批次号重复，请检查数据！");
//                }
            } else {
                Long materialModelId = billDetail.getMaterialModelId();
                String materialModelCode = billDetail.getMaterialModelCode();
                WarehouseMaterial warehouseMaterial = null;
                if (materialModelId != null) {
                    warehouseMaterial = materialService.getByMaterialId(materialModelId);
                }
                if (warehouseMaterial == null) {
                    warehouseMaterial = materialService.getByMaterialCode(materialModelCode);
                }
                if (warehouseMaterial != null && warehouseMaterial.getUniqueCode()) {
                    throw new BusinessException(billDetail.getMaterialModelCode() + "唯一码为空，请检查数据重新输入！");
                }
                //未开启唯一码，开启了批次号。批次号+物料编码+库位 判重
                if (StringUtils.isNotBlank(batchNo)) {
                    List<WarehouseInventory> warehouseInventory = inventoryService.getByMaterialAndBatchNoAndWarehouseId(batchNo, billDetail.getMaterialModelCode(), billDetail.getWarehouseId());
                    warehouseInventory = warehouseInventory.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode())).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(warehouseInventory)) {
                        WarehouseInventory inventory = warehouseInventory.get(0);
                        inventory.setQuantity(inventory.getQuantity().add(billDetail.getCount()));
                        //更新库存
                        inventoryService.updateInventory(inventory, 1);
                        continue;
                    }
                    //检查当前数据的批次号是否是其他数据的唯一码，不同数据 的唯一码和批次号都不能相同
                    WarehouseInventory byUniqueCode = inventoryService.getByUniqueCode(batchNo);
                    if (byUniqueCode != null) {
                        throw new BusinessException("当前批次号【" + batchNo + "】与已有的唯一码重复，请检查数据！");
                    }
                } else {
                    //未开启唯一码和批次号，物料+库位判重
                    List<WarehouseInventory> byCodeAndNull = inventoryService.getByMaterialAndBatchNoAndWarehouseId(null, billDetail.getMaterialModelCode(), billDetail.getWarehouseId());
                    byCodeAndNull = byCodeAndNull.stream().filter(e -> StringUtils.isBlank(e.getUniqueCode()) && StringUtils.isBlank(e.getBatchNo())).collect(Collectors.toList());
                    //如果已存在，则更新库存数量，不存在则执行新增操作
                    if (CollectionUtils.isNotEmpty(byCodeAndNull)) {
                        WarehouseInventory inventory = byCodeAndNull.get(0);
                        inventory.setQuantity(inventory.getQuantity().add(billDetail.getCount()));
                        //更新库存
                        inventoryService.updateInventory(inventory, 1);
                        continue;
                    }
                }
            }
            //新增库存数据
            addInventory(billDetail);
        }
    }

    private void addInventory(WarehouseInputBillDetail billDetail) {
        WarehouseInventory inventory = new WarehouseInventory();
        BeanUtils.copyProperties(billDetail, inventory, "id");
        inventory.setMaterialModelId(billDetail.getMaterialModelId());
        inventory.setMaterialModelCode(billDetail.getMaterialModelCode());
        inventory.setMaterialModelName(billDetail.getMaterialModelName());
        inventory.setMaterialTypeName(billDetail.getMaterialTypeName());
        inventory.setMaterialCategoryName(billDetail.getMaterialCategoryName());
        inventory.setMaterialLevel(billDetail.getMaterialLevel());
        inventory.setDiameter(billDetail.getDiameter());
        inventory.setUniqueCode(billDetail.getUniqueCode());
        inventory.setBatchNo(billDetail.getBatchNo());
        inventory.setSupplier(billDetail.getSupplier());
        inventory.setSpecification(billDetail.getSpecification());
        inventory.setMaterialTh(billDetail.getMaterialTh());
        inventory.setQuantity(billDetail.getCount());
        inventory.setUnitName(billDetail.getUnitName());
        inventory.setWarehouseId(billDetail.getWarehouseId());
        inventory.setWarehouseName(billDetail.getWarehouseName());
        if (StringUtils.isNotBlank(billDetail.getWarehouseCode())) {
            inventory.setWarehouseCode(billDetail.getWarehouseCode());
        }
        inventory.setReceiveTime(new Date());
        inventory.setReceiveUserId(BaseContextHandler.getUserID());
        inventory.setReceiveUserName(BaseContextHandler.getUsername());
        inventory.setMaterialXh(billDetail.getMaterialTh());
        inventory.setCustomer(billDetail.getCustomer());
        inventory.setTraceid(billDetail.getTraceid());
        inventory.setSerialNo(billDetail.getSerialNo());
//        String lockKey = new String();
//        //唯一码存在
//        if (StringUtils.isNotBlank(inventory.getUniqueCode())) {
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode() + inventory.getUniqueCode();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        } else if (StringUtils.isEmpty(inventory.getUniqueCode()) && StringUtils.isNotBlank(inventory.getBatchNo())) {
//            //唯一码不存在,用批次号
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode() + inventory.getBatchNo();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        }else if(StringUtils.isEmpty(inventory.getUniqueCode()) && StringUtils.isEmpty(inventory.getBatchNo())){
//            WarehouseModel warehouseModel = warehouseModelService.getById(inventory.getWarehouseId());
//            if (StringUtils.isNotBlank(warehouseModel.getCode())) {
//                lockKey = inventory.getMaterialModelCode() + warehouseModel.getCode();
//            } else {
//                throw new BusinessException("未查询到【" + inventory.getWarehouseId() + "】库位信息!");
//            }
//        }
//        RLock lock = RedissonUtils.getRLock(redissonClient, lockKey);
//        boolean isLock = RedissonUtils.getRLockExpireTime(lock, 6L, 6L);
//        if (isLock) {
//            try {
//                lock.lock();
        //查询物料模型配置
        WarehouseMaterial warehouseMaterial = materialService.getByMaterialId(billDetail.getMaterialModelId());
        if (warehouseMaterial != null) {
            inventory.setSafetyStock(warehouseMaterial.getLowerLimit() + "-" + warehouseMaterial.getUpperLimit());
            inventory.setResidenceTime(warehouseMaterial.getResidenceTime());
            inventory.setTimeUnit(warehouseMaterial.getTimeUnit());
            //查询物料的所有库存数据
//                    List<WarehouseInventory> warehouseInventories = inventoryService.getByMaterialCode(inventory.getMaterialModelCode());
//                    for (WarehouseInventory warehouseInventory : warehouseInventories) {
//                        String safetyStock = warehouseInventory.getSafetyStock();
//                        if (StringUtils.isNotBlank(safetyStock)) {
//                            continue;
//                        }
//                        warehouseInventory.setSafetyStock(warehouseMaterial.getLowerLimit() + "-" + warehouseMaterial.getUpperLimit());
//                        warehouseInventory.setResidenceTime(warehouseMaterial.getResidenceTime());
//                        warehouseInventory.setTimeUnit(warehouseMaterial.getTimeUnit());
//                    }
//                    inventoryService.saveOrUpdateBatch(warehouseInventories);
            String safetyStock = warehouseMaterial.getLowerLimit() + "-" + warehouseMaterial.getUpperLimit();
            Integer residenceTime = warehouseMaterial.getResidenceTime();
            String timeUnit = warehouseMaterial.getTimeUnit();
            String materialModelCode = inventory.getMaterialModelCode();
            inventoryService.updateSafetyStockAndResidenceTimeAndTimeUnitByMaterialCode(safetyStock, residenceTime, timeUnit, materialModelCode);
        }
        inventoryService.save(inventory);
//
//            } finally {
//                if (lock != null && lock.isLocked() && lock.isHeldByCurrentThread()) {
//                    lock.unlock();
//                    RedisTools.deleteObject(lockKey);
//                }
//            }
//        } else {
//            throw new BusinessException("有其他人正在操作，请稍后再试！");
//        }
    }

    private void updateDetail(List<WarehouseInputBillDetail> billDetails) {
        billDetails.forEach(billDetail -> {
            billDetail.setStatus(InputBillStatusEnum.已入库.getValue());
            billDetail.setUpdateTime(new Date());
            billDetail.setUpdateUserId(BaseContextHandler.getUserID());
            billDetail.setUpdateUserName(BaseContextHandler.getUsername());
        });
        inputBillDetailService.saveOrUpdateBatch(billDetails);
    }

    @Override
    public List<WarehouseInputBillDetail> findWarehouseInputBillDetailsBySerialNoOrTraceIdOrBatchNo(String code) {
        return inputBillDetailService.findWarehouseInputBillDetailsBySerialNoOrTraceIdOrBatchNo(code);
    }

    @Override
    public List<WarehouseInputBillDetailBo> findWarehouseInputBillDetailsByMaterialCode(String materialCode) {
        return inputBillDetailService.findWarehouseInputBillDetailsByMaterialCode(materialCode);
    }

    @Override
    public void receiveWmsStatus(WMSToWarehouseInputDto warehouseInputDto) {
        WarehouseInputBill inputBill = warehouseInputBillMapper.getByBillNo(warehouseInputDto.getZinbd());
        WarehouseOutputBill outputBill = warehouseOutputBillService.findWarehouseOutputBillByInputBillCode(inputBill.getBillNo());
        if ("S".equals(warehouseInputDto.getZshjg())) {
            warehouseInputBillService.auditReceiveAtomic(inputBill);
            warehouseOutputBillService.auditDeductionAtomic(outputBill);
        }
        if ("C".equals(warehouseInputDto.getZshjg())) {
            warehouseInputBillService.rejectApply(inputBill);
            warehouseOutputBillService.rejectApply(outputBill);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importInputBill(MultipartFile file) throws IOException {
        Object objects = EasyExcelUtils.readExcel(file, new InputBillImportDto(), 1, 1);
        List<InputBillImportDto> inputBillImportDtos = (List<InputBillImportDto>) objects;
        if (inputBillImportDtos.size() > 0) {
            if (CollectionUtils.isEmpty(inputBillImportDtos)) {
                return;
            }
            //同一批次数据的入库单号保证一致，默认取第一条数据的入库单号
            String billNo = inputBillImportDtos.get(0).getBillNo();
            if (StringUtils.isBlank(billNo)) {
                throw new BusinessException("入库单号为空，请检查数据重新上传！");
            }
            WarehouseInputBill byBillNo = this.getByBillNo(billNo);
            if (byBillNo != null) {
                throw new BusinessException("入库单号【" + billNo + "】已存在");
            }
            WarehouseInputBillDto inputBill = new WarehouseInputBillDto();
            inputBill.setBillNo(billNo);
            inputBill.setStatus(InputBillStatusEnum.已入库.getValue());
            inputBill.setType(InputBillTypeEnum.人工导入.getValue());
            inputBill.setRemark("");
            inputBill.setCreateUserId(BaseContextHandler.getUserID());
            inputBill.setCreateUserName(BaseContextHandler.getUsername());
            inputBill.setUpdateUserId(BaseContextHandler.getUserID());
            inputBill.setUpdateUserName(BaseContextHandler.getUsername());
            inputBill.setCreateTime(new Date());
            inputBill.setUpdateTime(new Date());
            inputBill.setRejectReason("");
            inputBill.setRejectReasonRemark("");
            inputBill.setAutoAudit(true);//自动审核入库
            List<WarehouseInputBillDetailDto> inputBillDetails = inputBill.getInputBillDetails();
            for (InputBillImportDto inputBillImportDto : inputBillImportDtos) {
                String materialCode = inputBillImportDto.getMaterialCode();
                //TODO wupeng 此处调用查询物料主数据的接口
                Result<MaterialModelDto> result = ybFeignClients.getMaterialByCode(materialCode);
                MaterialModelDto materialModel = result.getData();
                if (materialModel == null) {
                    throw new BusinessException("【" + materialCode + "】物料主数据不存在，请检查数据！");
                }
                //获取物料配置的默认库位
                LambdaQueryWrapper<WarehouseMaterial> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(WarehouseMaterial::getMaterialCode, materialCode);
                WarehouseMaterial warehouseMaterial = materialService.getOne(queryWrapper);
                if (warehouseMaterial == null) {
                    throw new BusinessException("【" + materialCode + "】未配置线边仓物料模型，无法获取默认库位信息！");
                }
                WarehouseInputBillDetailDto detail = new WarehouseInputBillDetailDto();
                //组装物料明细数据
                detail.setUniqueCode(inputBillImportDto.getUniqueCode());
                detail.setBatchNo(inputBillImportDto.getBatchNo());
                detail.setCount(new BigDecimal(inputBillImportDto.getCount()));
                detail.setMaterialModelId(Long.valueOf(materialModel.getId()));
                detail.setMaterialModelCode(materialModel.getCode());
                detail.setMaterialModelName(materialModel.getName());
                MaterialTypeDto materialTypeDto = materialModel.getMaterialTypeDto();
                if (materialTypeDto == null) {
                    throw new BusinessException("【" + materialCode + "】物料主数据类别不存在，请检查数据！");
                }
                detail.setMaterialTypeName(materialTypeDto.getName());
                //TODO wupeng
//                detail.setMaterialCategoryName(materialModel.getMaterialCategoryName());
//                detail.setMaterialTh(materialModel.getTh());
                detail.setSupplier(materialModel.getSupplier());
//                detail.setUnitName(materialModel.getUnitName());
                detail.setSpecification(materialModel.getSpecification());
                detail.setWarehouseId(warehouseMaterial.getDefaultLocationId());
                detail.setWarehouseName(warehouseMaterial.getDefaultLocation());

                WarehouseModel warehouseModel = warehouseModelService.getById(warehouseMaterial.getDefaultLocationId());
                if (warehouseModel != null) detail.setWarehouseCode(warehouseModel.getCode());

                inputBillDetails.add(detail);
            }
            inputBill.setInputBillDetails(inputBillDetails);
            //保存入库单及其明细
            this.saveInputBill(inputBill);
        }
    }

    /**
     * 保存审核记录及审核明细
     **/
    private void saveRecord(WarehouseInputBill inputBill) {
        //新增审核记录及其明细
        WarehouseInputRecordBill inputRecordBill = modelMapper.map(inputBill, WarehouseInputRecordBill.class);
        inputRecordBill.setId(null);
        String recordBillNo = CodeGenUtil.genInputRecordBillNo();
        inputRecordBill.setRecordBillNo(recordBillNo);
        inputRecordBill.setInputBillNo(inputBill.getBillNo());
        inputRecordBill.setInputBillId(inputBill.getId());
        inputRecordBillService.save(inputRecordBill);
        List<WarehouseInputRecordBillDetail> warehouseInputRecordBillDetails = inputBill.getInputBillDetails().stream().map(inputBillDetail -> {
            WarehouseInputRecordBillDetail warehouseInputRecordBillDetail = modelMapper.map(inputBillDetail, WarehouseInputRecordBillDetail.class);
            warehouseInputRecordBillDetail.setId(null);
            warehouseInputRecordBillDetail.setRecordBillId(inputRecordBill.getId());
            warehouseInputRecordBillDetail.setRecordBillNo(inputRecordBill.getRecordBillNo());
            warehouseInputRecordBillDetail.setInputBillId(inputRecordBill.getInputBillId());
            warehouseInputRecordBillDetail.setInputBillNo(inputRecordBill.getInputBillNo());
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateTime())) {
                warehouseInputRecordBillDetail.setCreateTime(new Date());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserName())) {
                warehouseInputRecordBillDetail.setCreateUserName(BaseContextHandler.getUsername());
            }
            if (ObjectUtils.isEmpty(inputBillDetail.getCreateUserId())) {
                warehouseInputRecordBillDetail.setCreateUserId(BaseContextHandler.getUserID());
            }
            warehouseInputRecordBillDetail.setCount(inputBillDetail.getCount());
            return warehouseInputRecordBillDetail;
        }).collect(Collectors.toList());
        inputRecordBillDetailService.saveBatch(warehouseInputRecordBillDetails);
    }

    @Override
    public Page<WarehouseInputBill> listByPagePda(ServletRequest request, RequestPage requestPage) {
        WarehouseInputBillPdaBo param = new WarehouseInputBillPdaBo();
        param.setSerialNo(request.getParameter("search_LIKE_serialNo"));
        param.setTraceid(request.getParameter("search_LIKE_traceid"));
        param.setBatchNo(request.getParameter("search_IN_batchNo"));
        param.setMaterialModelCode(request.getParameter("search_LIKE_materialModelCode"));
        Page<WarehouseInputBill> warehouseMaterialIPage = warehouseInputBillMapper.listByPagePda(new Page<>(requestPage.getPage(), requestPage.getRows()), param);
        return warehouseMaterialIPage;
    }
}
