package com.fjhx.wms.service.stock.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.common.constant.SourceConstant;
import com.fjhx.common.utils.Assert;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.item.util.excel.util.ExcelUtil;
import com.fjhx.kd100.entity.company.po.CompanyInfo;
import com.fjhx.kd100.service.company.CompanyInfoService;
import com.fjhx.wms.entity.ArrivalDetailPo;
import com.fjhx.wms.entity.PurchaseDetailPo;
import com.fjhx.wms.entity.arrival.po.ArrivalStockRecords;
import com.fjhx.wms.entity.arrival.po.ArrivalStockRecordsDetails;
import com.fjhx.wms.entity.stock.dto.StockWaitDetailsDto;
import com.fjhx.wms.entity.stock.dto.StockWaitDto;
import com.fjhx.wms.entity.stock.dto.StockWaitSelectDto;
import com.fjhx.wms.entity.stock.emums.JournalType;
import com.fjhx.wms.entity.stock.emums.StockWaitType;
import com.fjhx.wms.entity.stock.po.*;
import com.fjhx.wms.entity.stock.vo.InStockWaitExportExcel;
import com.fjhx.wms.entity.stock.vo.StockWaitDetailsVo;
import com.fjhx.wms.entity.stock.vo.StockWaitVo;
import com.fjhx.wms.entity.warehouse.po.Warehouse;
import com.fjhx.wms.mapper.stock.StockWaitMapper;
import com.fjhx.wms.service.PurService;
import com.fjhx.wms.service.WmsService;
import com.fjhx.wms.service.arrival.ArrivalStockRecordsDetailsService;
import com.fjhx.wms.service.arrival.ArrivalStockRecordsService;
import com.fjhx.wms.service.stock.*;
import com.fjhx.wms.service.warehouse.WarehouseService;
import com.fjhx.wms.utils.CodeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.wrapper.IWrapper;
import com.ruoyi.system.utils.UserUtil;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * <p>
 * 待出入库 服务实现类
 * </p>
 *
 * @author
 * @since 2023-03-22
 */
@DS(SourceConstant.WMS)
@Service
public class StockWaitServiceImpl extends ServiceImpl<StockWaitMapper, StockWait> implements StockWaitService {
    @Autowired
    private ProductInfoService productInfoService;
    @Autowired
    private StockService stockService;
    @Autowired
    private StockJournalService stockJournalService;
    @Autowired
    private StockJournalDetailsService stockJournalDetailsService;
    @Autowired
    private StockWaitDetailsService stockWaitDetailsService;
    @Autowired
    private WarehouseService warehouseService;
    @Autowired
    private ArrivalStockRecordsService arrivalStockRecordsService;
    @Autowired
    private ArrivalStockRecordsDetailsService arrivalStockRecordsDetailsService;
    @Autowired
    private WmsService wmsService;
    @Autowired
    private StockFrozenService stockFrozenService;
    @Autowired
    private PurService purService;
    @Autowired
    private CompanyInfoService companyInfoService;

    @Override
    public Page<StockWaitVo> getPage(StockWaitSelectDto dto) {
        IWrapper<StockWait> wrapper = getWrapper();
        //过滤入库/出库
        wrapper.eq(StockWait::getType, dto.getType());
        wrapper.eq("sw", StockWait::getBusinessType, dto.getBusinessType());
        wrapper.eq(StockWait::getBusinessCode, dto.getKeyword());
        wrapper.orderByDesc("sw", StockWait::getId);
        Page<StockWaitVo> page = this.baseMapper.getPage1(dto.getPage(), wrapper);

        List<StockWaitVo> records = page.getRecords();
        // 赋值产品属性
        productInfoService.attributeAssign(records, StockWaitVo::getProductId, (item, productInfo) -> {
            item.setProductCode(productInfo.getCode());
            item.setProductUnit(productInfo.getUnit());
            item.setProductType(productInfo.getType());
            item.setProductName(productInfo.getName());
            item.setProductSpec(productInfo.getSpec());
        });

        return page;
    }

    @Override
    public Page<StockWaitVo> getPageByWdly(StockWaitSelectDto dto) {
        IWrapper<StockWait> wrapper = getWrapper();
        wrapper.orderByDesc("sw", StockWait::getId);
        //过滤入库/出库
        wrapper.eq("sw", StockWait::getType, dto.getType());
        wrapper.eq("sw", StockWait::getStatus, dto.getStatus());
        wrapper.eq("sw", StockWait::getBusinessType, dto.getBusinessType());

        //关键字搜索
        if(ObjectUtil.isNotEmpty(dto.getKeyword())){
            wrapper.and(q->q
                    .like("sw", StockWait::getBusinessCode,dto.getKeyword())
                    .or().like("lis.code",dto.getKeyword())
                    .or().exists("SELECT swd.stock_wait_id FROM stock_wait_details swd LEFT JOIN bytesailing_item.product_info pi ON swd.product_id = pi.id where ( pi.`name` LIKE CONCAT( '%', {0}, '%' ) OR pi.custom_code LIKE CONCAT( '%', {0}, '%' ))",dto.getKeyword())
            );
        }

        //过滤掉待出入库 已完成/手动结束 的数据
        wrapper.notIn("sw", StockWait::getStatus, 2, 3);

        wrapper.groupBy("sw.id");
        Page<StockWaitVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);

        List<StockWaitVo> records = page.getRecords();
        if (ObjectUtil.isEmpty(records)) {
            return page;
        }

        List<String> logisticsCompanyCodes = records.stream().map(StockWaitVo::getLogisticsCompanyCode).distinct().collect(Collectors.toList());
        //物流公司名称map
        Map<String, String> logisticsCompanyMap = companyInfoService.mapKV(CompanyInfo::getCode, CompanyInfo::getName,
                q -> q.in(CompanyInfo::getCode, logisticsCompanyCodes));

        //赋值操作人
        UserUtil.assignmentNickName(records, StockWaitVo::getCreateUser, StockWaitVo::setOperatorName);
        //赋值仓库名称和id
        List<Long> wids = new ArrayList<>();
        for (StockWaitVo stockWaitVo : records) {
            String victoriatouristJson = stockWaitVo.getVictoriatouristJson();
            if (ObjectUtil.isEmpty(victoriatouristJson)) {
                continue;
            }
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            if (!json.containsKey("receiptWarehouseId")) {
                continue;
            }
            wids.add(json.getLong("receiptWarehouseId"));
        }
        if (ObjectUtil.isEmpty(wids)) {
            return page;
        }
        List<Warehouse> warehouses = warehouseService.listByIds(wids);
        Map<Long, String> warehousesMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, Warehouse::getName));
        for (StockWaitVo stockWaitVo : records) {
            String victoriatouristJson = stockWaitVo.getVictoriatouristJson();
            if (ObjectUtil.isEmpty(victoriatouristJson)) {
                continue;
            }
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            json.put("receiptWarehouseName", warehousesMap.get(json.getLong("receiptWarehouseId")));

            //重新赋值物流信息
            stockWaitVo.setLogisticsCompanyName(logisticsCompanyMap.get(stockWaitVo.getLogisticsCompanyCode()));
            json.put("logisticsCompanyName", stockWaitVo.getLogisticsCompanyName());
            json.put("logisticsCompanyCode", stockWaitVo.getLogisticsCompanyCode());
            json.put("code", stockWaitVo.getLogisticsCode());

            stockWaitVo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }

        return page;
    }

    @Override
    public StockWaitVo detail(Long id) {
        StockWait stockWait = this.getById(id);
        StockWaitVo result = BeanUtil.toBean(stockWait, StockWaitVo.class);

        StockWaitDetails stockWaitDetails = stockWaitDetailsService.getOne(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        ProductInfo byId = productInfoService.getById(stockWaitDetails.getProductId());
        result.setProductName(byId.getName());
        result.setQuantity(stockWaitDetails.getQuantity());
        result.setStockWaitDetailsId(stockWaitDetails.getId());

        //获取明细列表
        List<StockWaitDetails> stockWaitDetailsList = stockWaitDetailsService.list(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        List<StockWaitDetailsVo> stockWaitDetailsVos = BeanUtil.copyToList(stockWaitDetailsList, StockWaitDetailsVo.class);
        //赋值产品信息
        productInfoService.attributeAssign(stockWaitDetailsVos, StockWaitDetailsVo::getProductId, (item, productInfo) -> {
            item.setProductName(productInfo.getName());
        });
        result.setStockWaitDetailsList(stockWaitDetailsVos);

        return result;
    }

    @Override
    public StockWaitVo detailByWdly(Long id) {
        StockWait stockWait = this.getById(id);
        StockWaitVo result = BeanUtil.toBean(stockWait, StockWaitVo.class);
        List<StockWaitDetails> list = stockWaitDetailsService.list(q -> q.eq(StockWaitDetails::getStockWaitId, id));
        List<StockWaitDetailsVo> stockWaitDetailsVos = BeanUtil.copyToList(list, StockWaitDetailsVo.class);
        //根据业务id(到货id)查询采购单明细信息


        //赋值物品信息和采购信息
        List<Long> pids = stockWaitDetailsVos.stream().map(StockWaitDetails::getProductId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(pids)) {
            List<ProductInfo> productInfos = productInfoService.listByIds(pids);
            Map<Long, ProductInfo> productInfoMap = productInfos.stream().collect(Collectors.toMap(ProductInfo::getId, Function.identity()));
            for (StockWaitDetailsVo stockWaitDetails : stockWaitDetailsVos) {
                ProductInfo productInfo = productInfoMap.get(stockWaitDetails.getProductId());
                if (ObjectUtil.isEmpty(productInfo)) {
                    continue;
                }
                stockWaitDetails.setProductName(productInfo.getName());
                stockWaitDetails.setProductCode(productInfo.getCode());
                stockWaitDetails.setProductCustomCode(productInfo.getCustomCode());
                stockWaitDetails.setProductSpec(productInfo.getSpec());
            }
        }
        result.setStockWaitDetailsList(stockWaitDetailsVos);
        //如果是采购退货 赋值采购退货信息
        if (result.getBusinessType() == 4) {
            Object purchaseBackInfo = wmsService.getPurchaseBackInfo(result.getBusinessId());
            result.setPurchaseBackInfo(purchaseBackInfo);
        }

        //到货物流备注
        String victoriatouristJson = stockWait.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        String arrivalRemark = wmsService.getArrivalRemark(json.getLong("deliverGoodsId"));
        result.setArrivalRemark(arrivalRemark);

        return result;
    }

    @DSTransactional
    @Override
    public void add(StockWaitDetailsDto stockWaitDetailsDto) {
        stockWaitDetailsService.add(stockWaitDetailsDto);
    }

    @DSTransactional
    @Override
    public synchronized void addByWdly(StockWaitDto stockWaitDto) {
        List<Stock> stockList = new ArrayList<>();

        List<StockWaitDetails> stockWaitDetailsDtoList = stockWaitDto.getStockWaitDetailsList();
        Map<Long, StockWaitDetails> stockWaitDetailsMap = stockWaitDetailsDtoList.stream().collect(Collectors.toMap(StockWaitDetails::getId, Function.identity()));

        //更新已出入库数量以及待出入库状态
        stockWaitDetailsService.changeStockWaitStatus(stockWaitDto);
        StockWait stockWait = getById(stockWaitDto.getId());

        String victoriatouristJson = stockWait.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        json.put("receiptWarehouseId", stockWaitDto.getWarehouseId());
        stockWait.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        updateById(stockWait);

        //到货物流备注
        Long deliverGoodsId = json.getLong("deliverGoodsId");
        wmsService.editArrivalRemark(deliverGoodsId, stockWaitDto.getArrivalRemark());

        //如果是采购到货 计算结存单价
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(stockWait.getBusinessType())) {
            List<Long> productIds = stockWaitDetailsDtoList.stream().map(StockWaitDetails::getProductId).distinct().collect(Collectors.toList());
            Map<Long, ProductInfo> productInfoMap = productInfoService.mapKEntity(ProductInfo::getId, q -> q.in(ProductInfo::getId, productIds));
            Map<Long, List<Stock>> stockListMap = stockService.mapKGroup(Stock::getProductId, q -> q.in(Stock::getProductId, productIds));

            List<Long> arrIds = stockWaitDetailsDtoList.stream().map(StockWaitDetails::getBusinessDetailsId).distinct().collect(Collectors.toList());
            List<ArrivalDetailPo> arrivalDetailByIds = purService.getArrivalDetailByIds(arrIds);
            Map<Long, ArrivalDetailPo> arrivalDetailMap = arrivalDetailByIds.stream().collect(Collectors.toMap(ArrivalDetailPo::getId, Function.identity()));

            List<Long> purchaseIds = arrivalDetailByIds.stream().map(ArrivalDetailPo::getPurchaseDetailId).distinct().collect(Collectors.toList());
            List<PurchaseDetailPo> purchaseDetailByIds = purService.getPurchaseDetailByIds(purchaseIds);
            Map<Long, PurchaseDetailPo> purchaseDetailMap = purchaseDetailByIds.stream().collect(Collectors.toMap(PurchaseDetailPo::getId, Function.identity()));

            List<ProductInfo> productInfoList = new ArrayList<>();
            for (StockWaitDetails stockWaitDetails : stockWaitDetailsDtoList) {
                //入库数量为0直接跳过
                if (ObjectUtil.isEmpty(stockWaitDetails.getQuantity()) || stockWaitDetails.getQuantity().compareTo(BigDecimal.ZERO) == 0) {
                    continue;
                }

                ProductInfo productInfo = productInfoMap.get(stockWaitDetails.getProductId());

                //获取所有仓库的该商品库存数量
                List<Stock> stockList1 = stockListMap.getOrDefault(stockWaitDetails.getProductId(), new ArrayList<>());
                BigDecimal quantity = stockList1.stream().map(Stock::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);

                ArrivalDetailPo arrivalDetailPo = arrivalDetailMap.get(stockWaitDetails.getBusinessDetailsId());
                PurchaseDetailPo purchaseDetailPo = purchaseDetailMap.get(arrivalDetailPo.getPurchaseDetailId());

                //计算结存单价（库存数量*结存单价+入库数量*入库单价）/(库存数量+入库数量)
                BigDecimal unitPrice = productInfo.getUnitPrice();
                unitPrice = ObjectUtil.isNotEmpty(unitPrice) ? unitPrice : BigDecimal.ZERO;
                BigDecimal multiply = quantity.multiply(unitPrice);
                BigDecimal multiply1 = stockWaitDetails.getQuantity().multiply(purchaseDetailPo.getPrice());
                BigDecimal add = multiply.add(multiply1);
                BigDecimal add1 = quantity.add(stockWaitDetails.getQuantity());
                BigDecimal divide = add.divide(add1, 4, BigDecimal.ROUND_HALF_DOWN);

                productInfo.setUnitPrice(divide);
                productInfoList.add(productInfo);
            }

            productInfoService.updateBatchById(productInfoList);
        }


        //创建出入库记录
        Integer businessType = stockWait.getBusinessType();
        StockJournal stockJournal = new StockJournal();
        stockJournal.setOpType(stockWait.getType());
        stockJournal.setType(getStockJournalType(businessType));
        stockJournal.setCode(stockWait.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
        stockJournal.setWarehouseId(stockWaitDto.getWarehouseId());
        stockJournal.setBusinessId(stockWaitDto.getId());
        stockJournal.setLinkCode(stockWait.getBusinessCode());
        //保存出入库记录
        stockJournalService.save(stockJournal);

        List<StockJournalDetails> stockJournalDetailsList = new ArrayList<>();

        List<ArrivalStockRecordsDetails> arrivalStockRecordsDetailsList = new ArrayList<>();


        //操作库存
        List<Long> swdIds = stockWaitDetailsDtoList.stream().map(StockWaitDetails::getId).collect(Collectors.toList());
        Map<Long, StockWaitDetails> oldStockWaitDetailsMap = stockWaitDetailsService.mapKEntity(StockWaitDetails::getId, q -> q.in(StockWaitDetails::getId, swdIds));
        for (StockWaitDetails waitDetails : stockWaitDetailsDtoList) {
            StockWaitDetails temp = oldStockWaitDetailsMap.get(waitDetails.getId());
            Stock stock = new Stock();
            stock.setQuantity(waitDetails.getQuantity());
            stock.setProductId(temp.getProductId());
            stockList.add(stock);

            StockJournalDetails stockJournalDetails = new StockJournalDetails();
            stockJournalDetails.setId(IdWorker.getId());
            stockJournalDetails.setBusinessDetailsId(waitDetails.getId());
            stockJournalDetails.setQuantity(waitDetails.getQuantity());
            stockJournalDetails.setProductId(temp.getProductId());
            stockJournalDetails.setStockJournalId(stockJournal.getId());
            stockJournalDetailsList.add(stockJournalDetails);

            ArrivalStockRecordsDetails arrivalStockRecordsDetails = new ArrivalStockRecordsDetails();
            arrivalStockRecordsDetails.setStockJournalDetailsId(stockJournalDetails.getId());
            arrivalStockRecordsDetails.setProductInfoId(waitDetails.getProductId());
            arrivalStockRecordsDetails.setQuantity(waitDetails.getQuantity());
            arrivalStockRecordsDetails.setQualityQuantity(BigDecimal.ZERO);
            arrivalStockRecordsDetails.setBusinessDetailsId(waitDetails.getId());
            arrivalStockRecordsDetailsList.add(arrivalStockRecordsDetails);
        }


        //库存操作类型
        Integer opType = -1;
        //到货入库
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType() == businessType) {
            opType = 3;
        }
        //退货出库
        if (StockWaitType.BACK_OUT.getDetailType() == businessType) {
            opType = 4;
        }
        //销售订单出库
        if (StockWaitType.SALE_ORDER_OUT.getDetailType() == businessType) {
            opType = 2;
        }


        stockService.ModifyInventory(stockJournal.getId(), opType, stockList, stockWaitDto.getWarehouseId());
        //保存出入库明细
        stockJournalDetailsService.saveBatch(stockJournalDetailsList);

        //如果是采购到货 创建待质检记录
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            //创建采购到货入库记录
            ArrivalStockRecords arrivalStockRecords = new ArrivalStockRecords();
            arrivalStockRecords.setStockWaitId(stockWait.getId());
            arrivalStockRecords.setWarehouseId(stockWaitDto.getWarehouseId());
            arrivalStockRecords.setQualityStatus(0);
            arrivalStockRecords.setArrivalCode(json.getString("arrivalCode"));//设置到货编码
            arrivalStockRecords.setStockJournalId(stockJournal.getId());
            arrivalStockRecordsService.save(arrivalStockRecords);
            //创建入库明细
            arrivalStockRecordsDetailsList.forEach(item -> item.setArrivalStockRecordsId(arrivalStockRecords.getId()));
            arrivalStockRecordsDetailsService.saveBatch(arrivalStockRecordsDetailsList);
        }
        //如果是采购到货修改到货状态
        if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            purService.updatePurchaseArrivalStatus(stockWait.getBusinessId());
        }

        //销售订单出库
        if (StockWaitType.SALE_ORDER_OUT.getDetailType().equals(businessType)) {
            wmsService.outbounds(stockWaitDto);
        }

        //生产任务待出库
        if (StockWaitType.PRODUCTION_TASK_OUT.getDetailType().equals(businessType)) {
            for (StockWaitDetails stockWaitDetailsDto : stockWaitDetailsDtoList) {
                StockWaitDetails stockWaitDetails = stockWaitDetailsMap.get(stockWaitDetailsDto.getId());
                //减少冻结库存
                StockFrozen stockFrozen = stockFrozenService.getOne(q -> q.eq(StockFrozen::getProductId, stockWaitDetails.getProductId()));
                BigDecimal subtract = stockFrozen.getFrozenQuantity().subtract(stockWaitDetailsDto.getQuantity());
                stockFrozen.setFrozenQuantity(subtract);
                stockFrozenService.updateById(stockFrozen);
            }
        }
    }

    @Override
    public void edit(StockWaitDto stockWaitDto) {
        this.updateById(stockWaitDto);
    }

    @Override
    public void delete(Long id) {
        this.removeById(id);
    }

    /**
     * 根据待出入库业务类型获取对应的出入库记录类型
     */
    @Override
    public Integer getStockJournalType(int businessType) {
        if (StockWaitType.BORDER_OF_LINE_IN.getDetailType().equals(businessType)) {
            //线边回仓库
            return JournalType.BORDER_OF_LINE_IN.getDetailType();
        } else if (StockWaitType.COMPLETION_IN.getDetailType().equals(businessType)) {
            //完工入库
            return JournalType.COMPLETION_IN.getDetailType();
        } else if (StockWaitType.PURCHASE_ARRIVAL_IN.getDetailType().equals(businessType)) {
            //采购到货
            return JournalType.PURCHASE_ARRIVAL_IN.getDetailType();
        } else if (StockWaitType.BACK_OUT.getDetailType().equals(businessType)) {
            //退货出货
            return JournalType.BACK_OUT.getDetailType();
        } else if (StockWaitType.SALE_ORDER_OUT.getDetailType().equals(businessType)) {
            //销售订单出库
            return JournalType.SALES_OUT.getDetailType();
        } else if (StockWaitType.PRODUCTION_TASK_OUT.getDetailType().equals(businessType)) {
            //生产任务待出库
            return JournalType.PRODUCTION_TASK_OUT.getDetailType();
        } else {
            throw new ServiceException("未知待出入库业务类型");
        }
    }

    /**
     * 结束入库
     */
    @DSTransactional
    @Override
    public void endInStock(Long id) {
        StockWait stockWait = getById(id);
        Assert.notEmpty(stockWait, "无法查询到待入库信息");
        stockWait.setStatus(3);//设置状态为结束
        updateById(stockWait);
        Long purchaseId = null;
        if (stockWait.getBusinessType() == 3) {
            purchaseId = stockWait.getBusinessId();
        }
        wmsService.addEndInStockAbnormal(stockWait, purchaseId);
    }

    @Override
    public List<StockWaitDetailsVo> getStockWaitList(IWrapper<Object> wrapper) {
        return baseMapper.getStockWaitList(wrapper);
    }

    /**
     * 待入库导出excel
     */
    @Override
    public void inStockWaitExportExcel(HttpServletResponse httpServletResponse, List<Long> ids) {
        List<InStockWaitExportExcel> stockWaitList = baseMapper.getInStockWaitExportExcel(IWrapper.getWrapper()
                .eq("sw.type", 1)
                .in("sw.id", ids)
        );
        //赋值业务来源
        stockWaitList.forEach(item -> item.setBusinessType(StockWaitType.getEnum(item.getBusinessType())));

        //导出Excel
        ExcelUtil.export(httpServletResponse, stockWaitList, InStockWaitExportExcel.class);
    }

    /**
     * 待出库 excel导入出库
     */
    @DSTransactional
    void outStockWaitImportExcel(MultipartFile file, StockWaitDto stockWaitDto) {
        Assert.notEmpty(stockWaitDto.getBusinessType(), "业务类型不能为空");

        List<OutStockWaitImportExcelBo> list = new ArrayList<>();
        Assert.notEmpty(list, "Excel文档为空请检查");

        List<String> linkCodes = list.stream().map(OutStockWaitImportExcelBo::getLinkCode).distinct().collect(Collectors.toList());
        List<StockWait> stockWaitList = this.list(q -> q.in(StockWait::getBusinessCode, linkCodes));

        long count = stockWaitList.stream().map(StockWait::getBusinessType).distinct().count();
        if (count > 1) {
            throw new ServiceException("文档中的数据存在多种业务类型 请检查");
        }

        if (stockWaitList.size() < linkCodes.size()) {
            List<String> newLinkCodes = stockWaitList.stream().map(StockWait::getBusinessCode).distinct().collect(Collectors.toList());
            List<String> difference = linkCodes.stream().filter(element -> !newLinkCodes.contains(element)).collect(Collectors.toList());
            String differenceStr = difference.stream().collect(Collectors.joining(","));
            throw new ServiceException("文档存在未知单号：" + differenceStr);
        }

        //赋值产品id
        List<String> productCodes = list.stream().map(OutStockWaitImportExcelBo::getProductCode).distinct().collect(Collectors.toList());
        Map<String, Long> productInfoMap = productInfoService.mapKV(ProductInfo::getCustomCode, ProductInfo::getId,
                q -> q.in(ProductInfo::getCustomCode, productCodes));
        for (OutStockWaitImportExcelBo outStockWaitImportExcelBo : list) {
            String productCode = outStockWaitImportExcelBo.getProductCode();
            Long productId = productInfoMap.get(productCode);
            if (ObjectUtil.isEmpty(productId)) {
                throw new ServiceException("该产品不存在：" + productCode);
            }
            outStockWaitImportExcelBo.setProductId(productId);
        }

        //操作出库
        Map<String, List<OutStockWaitImportExcelBo>> excelMap = list.stream().collect(Collectors.groupingBy(OutStockWaitImportExcelBo::getLinkCode));
        for (StockWait stockWait : stockWaitList) {
            //查询明细信息
            List<OutStockWaitImportExcelBo> outStockWaitImportExcelBos = excelMap.get(stockWait.getBusinessCode());
            List<Long> productIds = outStockWaitImportExcelBos.stream().map(OutStockWaitImportExcelBo::getProductId).distinct().collect(Collectors.toList());

            Map<Long, StockWaitDetails> stockWaitDetailsMap = stockWaitDetailsService.mapKEntity(StockWaitDetails::getProductId, q -> q
                    .eq(StockWaitDetails::getStockWaitId, stockWait.getId())
                    .eq(StockWaitDetails::getProductId, productIds)
            );

            for (OutStockWaitImportExcelBo outStockWaitImportExcelBo : outStockWaitImportExcelBos) {
                StockWaitDetails stockWaitDetails = stockWaitDetailsMap.get(outStockWaitImportExcelBo);
                outStockWaitImportExcelBo.setStockWaitDetailId(stockWaitDetails.getId());
            }

            //数据预处理
            stockWaitDto.setBusinessType(stockWait.getBusinessType());
            List<StockWaitDetails> stockWaitDetailsList = new ArrayList<>();
            for (OutStockWaitImportExcelBo outStockWaitImportExcelBo : outStockWaitImportExcelBos) {
                StockWaitDetails stockWaitDetails = new StockWaitDetails();
                stockWaitDetails.setId(outStockWaitImportExcelBo.getStockWaitDetailId());
                stockWaitDetails.setProductId(outStockWaitImportExcelBo.getProductId());
                stockWaitDetails.setQuantity(outStockWaitImportExcelBo.getOutQuantity());
                stockWaitDetails.setStockWaitId(stockWait.getId());
                stockWaitDetailsList.add(stockWaitDetails);
            }
            stockWaitDto.setStockWaitDetailsList(stockWaitDetailsList);

            if (StockWaitType.SALE_ORDER_OUT.getDetailType().equals(stockWait.getBusinessType())) {
                //销售订单
                addByWdly(stockWaitDto);
            } else if (StockWaitType.JD_ORDER_OUT.getDetailType().equals(stockWait.getBusinessType())) {
                //京东订单
                wmsService.jdOrderOutbound(stockWaitDto);
            } else if (StockWaitType.BACK_OUT.getDetailType().equals(stockWait.getBusinessType())) {
                //采购退货
                wmsService.purchaseBackOutbound(stockWaitDto);
            } else {
                throw new ServiceException("存在未知业务的数据！");
            }
        }
    }

    @Getter
    @Setter
    class OutStockWaitImportExcelBo {
        /**
         * 产品id
         */
        private Long productId;
        /**
         * 待出库明细id
         */
        private Long stockWaitDetailId;

        @ExcelProperty("关联单号")
        private String linkCode;
        @ExcelProperty("物品编码")
        private String productCode;
        @ExcelProperty("出库数量")
        private BigDecimal outQuantity;
    }

}
