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

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjhx.item.entity.product.po.ProductClassify;
import com.fjhx.item.entity.product.po.ProductInfo;
import com.fjhx.item.service.product.ProductClassifyService;
import com.fjhx.item.service.product.ProductInfoService;
import com.fjhx.wms.entity.stock.bo.InOutBo;
import com.fjhx.wms.entity.stock.dto.StockDto;
import com.fjhx.wms.entity.stock.dto.StockJournalDetailsDto;
import com.fjhx.wms.entity.stock.dto.StockSelectDto;
import com.fjhx.wms.entity.stock.emums.InOutType;
import com.fjhx.wms.entity.stock.emums.JournalType;
import com.fjhx.wms.entity.stock.po.Stock;
import com.fjhx.wms.entity.stock.po.StockJournal;
import com.fjhx.wms.entity.stock.po.StockJournalDetails;
import com.fjhx.wms.entity.stock.vo.StockVo;
import com.fjhx.wms.entity.warehouse.po.Warehouse;
import com.fjhx.wms.mapper.stock.StockMapper;
import com.fjhx.wms.service.stock.StockJournalDetailsService;
import com.fjhx.wms.service.stock.StockJournalService;
import com.fjhx.wms.service.stock.StockService;
import com.fjhx.wms.service.warehouse.WarehouseService;
import com.fjhx.wms.utils.CodeEnum;
import com.ruoyi.common.core.domain.BaseIdPo;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.wrapper.IWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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-20
 */
@Service
public class StockServiceImpl extends ServiceImpl<StockMapper, Stock> implements StockService {
    @Autowired
    StockJournalService stockJournalService;
    @Autowired
    StockJournalDetailsService stockJournalDetailsService;
    @Autowired
    ProductInfoService productInfoService;
    @Autowired
    ProductClassifyService productClassifyService;
    @Autowired
    WarehouseService warehouseService;

    @Override
    public Page<StockVo> getPage(StockSelectDto dto) {
        IWrapper<Stock> wrapper = getWrapper();
        wrapper.orderByDesc("s", Stock::getId);
        wrapper.eq(Stock::getWarehouseId, dto.getId());
//        wrapper.like(Stock::getQuantity, dto.getKeyword());
        String keyword = dto.getKeyword();
        if (ObjectUtil.isNotEmpty(keyword)) {
            //根据 库存数量 产品自定义编码 产品名称 过滤
            List<Long> productIds = productInfoService.listObject(ProductInfo::getId,
                    q -> q.like(ProductInfo::getCustomCode, keyword).or().like(ProductInfo::getName, keyword));
            wrapper.and(q -> q.like(Stock::getQuantity, keyword).or().in(Stock::getProductId, productIds));
        }
        wrapper.in(Stock::getProductId, dto.getProductIds());
        wrapper.eq("pi.definition", dto.getDefinition());

        Page<StockVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
        List<StockVo> stockVos = page.getRecords();
        //赋值产品信息
        productInfoService.attributeAssign(stockVos, StockVo::getProductId, (item, productInfo) -> {
            item.setProductCode(productInfo.getCode());
            item.setProductUnit(productInfo.getUnit());
            item.setProductType(productInfo.getType());
            item.setProductName(productInfo.getName());
            item.setProductSpec(productInfo.getSpec());
            item.setProductClassifyId(productInfo.getProductClassifyId());
            item.setProductDefinition(productInfo.getDefinition());
            item.setProductCustomCode(productInfo.getCustomCode());
            //赋值结存单价
//            item.setUnitPrice(productInfo.getUnitPrice());
        });
        //赋值产品分类
        productClassifyService.attributeAssign(stockVos, StockVo::getProductClassifyId, (item, productClassify) -> {
            item.setProductClassifyName(productClassify.getName());
        });
        //赋值产品分类树
        List<ProductClassify> productClassifyList = productClassifyService.list();
        Map<Long, ProductClassify> productClassifyMap = productClassifyList.stream().collect(Collectors.toMap(BaseIdPo::getId, Function.identity()));
        for (StockVo stockVo : stockVos) {
            Long productClassifyId = stockVo.getProductClassifyId();
            ProductClassify productClassify = productClassifyMap.get(productClassifyId);
            if (productClassify == null) {
                continue;
            }
            List<String> classifyNameGroup = new ArrayList<>();

            while (productClassify != null) {
                classifyNameGroup.add(0, productClassify.getName());
                productClassify = productClassifyMap.get(productClassify.getParentId());
            }
            stockVo.setProductClassifyNameGroup(classifyNameGroup);
            stockVo.setProductClassifyNames(classifyNameGroup.stream().collect(Collectors.joining(" / ")));
        }

        //赋值仓库名称
        warehouseService.attributeAssign(stockVos, StockVo::getWarehouseId, (item, warehouse) -> {
            item.setWarehouseName(warehouse.getName());
        });
        return page;
    }

    /**
     * 维多利亚 按仓库库存查询
     */
    @Override
    public Page<StockVo> pageByWarehouse(StockSelectDto dto) {
        Page<StockVo> page = getPage(dto);
        List<StockVo> stockVos = page.getRecords();

        //获取产品id列表
        List<Long> productIds = stockVos.stream().map(Stock::getProductId).collect(Collectors.toList());
        if (ObjectUtil.isNotEmpty(productIds)) {
            //赋值产品名称
            productInfoService.attributeAssign(stockVos, StockVo::getProductId, (item, productInfo) -> {
                //赋值维多利亚扩展产品信息
                String victoriatouristJson = item.getVictoriatouristJson();
                JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
                json.put("code", productInfo.getCode());
                json.put("spec", productInfo.getSpec());
                json.put("unit", productInfo.getUnit());
                json.put("customCode", productInfo.getCustomCode());

                BigDecimal frozenQuantity = json.getBigDecimal("frozenQuantity");
                frozenQuantity = ObjectUtil.isEmpty(frozenQuantity) ? BigDecimal.ZERO : frozenQuantity;
                json.put("frozenQuantity", frozenQuantity);
                BigDecimal defectiveQuantity = json.getBigDecimal("defectiveQuantity");
                defectiveQuantity = ObjectUtil.isEmpty(defectiveQuantity) ? BigDecimal.ZERO : defectiveQuantity;
                json.put("defectiveQuantity", defectiveQuantity);
                item.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
            });
        }

        //维多利亚扩展
        List<Long> warehouseIds = new ArrayList<>();
        for (StockVo stockVo : stockVos) {
            String victoriatouristJson = stockVo.getVictoriatouristJson();
            if (ObjectUtil.isNotEmpty(victoriatouristJson)) {
                JSONObject json = JSONObject.parseObject(victoriatouristJson);
                //遍历仓库id
                warehouseIds.add(json.getLong("warehouseId"));
            }
        }
        //如果仓库id列表为空直接返回
        if (ObjectUtil.isEmpty(warehouseIds)) {
            return page;
        }
        List<Warehouse> warehouses = warehouseService.listByIds(warehouseIds);
        Map<Long, String> warehouseMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, Warehouse::getName));
        for (StockVo stockVo : stockVos) {
            String victoriatouristJson = stockVo.getVictoriatouristJson();
            JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
            String warehouseName = warehouseMap.get(json.getLong("warehouseId"));
            json.put("warehouseName", warehouseName);
            stockVo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }
        return page;
    }

    @Override
    public Page<StockVo> pageByProduct(StockSelectDto dto) {
        IWrapper<Stock> wrapper = getWrapper();
        wrapper.orderByDesc("s", Stock::getId);
        wrapper.eq(Stock::getWarehouseId, dto.getId());
//        wrapper.like(Stock::getQuantity, dto.getKeyword());
        String keyword = dto.getKeyword();
        if (ObjectUtil.isNotEmpty(keyword)) {
            //根据 库存数量 产品自定义编码 产品名称 过滤
            List<Long> productIds = productInfoService.listObject(ProductInfo::getId,
                    q -> q.like(ProductInfo::getCustomCode, keyword).or().like(ProductInfo::getName, keyword));
            wrapper.and(q -> q.like(Stock::getQuantity, keyword).or().in(Stock::getProductId, productIds));
        }
        wrapper.eq("pi.definition", dto.getDefinition());
        wrapper.groupBy("s.product_id");
        Page<StockVo> page = this.baseMapper.pageByProduct(dto.getPage(), wrapper);
        List<StockVo> stockVos = page.getRecords();

        //赋值冻结库存和次品库存
        for (StockVo stockVo : stockVos) {
            JSONObject json = new JSONObject();
            BigDecimal frozenQuantity = stockVo.getFrozenQuantity();
            frozenQuantity = frozenQuantity == null ? BigDecimal.ZERO : frozenQuantity;
            json.put("frozenQuantity", frozenQuantity);
            BigDecimal defectiveQuantity = stockVo.getDefectiveQuantity();
            defectiveQuantity = defectiveQuantity == null ? BigDecimal.ZERO : defectiveQuantity;
            json.put("defectiveQuantity", defectiveQuantity);
            stockVo.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        }

        //赋值产品名称
        productInfoService.attributeAssign(stockVos, StockVo::getProductId, (item, productInfo) -> {
            item.setType(productInfo.getType());
            item.setProductName(productInfo.getName());
            item.setProductCode(productInfo.getCode());
            item.setProductUnit(productInfo.getUnit());
            item.setProductType(productInfo.getType());
            item.setProductSpec(productInfo.getSpec());
            item.setProductClassifyId(productInfo.getProductClassifyId());
            item.setProductDefinition(productInfo.getDefinition());
            item.setProductCustomCode(productInfo.getCustomCode());

            //赋值维多利亚扩展产品信息
            String victoriatouristJson = item.getVictoriatouristJson();
            JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
            json.put("code", productInfo.getCode());
            json.put("spec", productInfo.getSpec());
            json.put("unit", productInfo.getUnit());

            BigDecimal frozenQuantity = json.getBigDecimal("frozenQuantity");
            frozenQuantity = ObjectUtil.isEmpty(frozenQuantity) ? BigDecimal.ZERO : frozenQuantity;
            json.put("frozenQuantity", frozenQuantity);
            BigDecimal defectiveQuantity = json.getBigDecimal("defectiveQuantity");
            defectiveQuantity = ObjectUtil.isEmpty(defectiveQuantity) ? BigDecimal.ZERO : defectiveQuantity;
            json.put("defectiveQuantity", defectiveQuantity);
            item.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        });

        //赋值产品分类
        productClassifyService.attributeAssign(stockVos, StockVo::getProductClassifyId, (item, productClassify) -> {
            item.setProductClassifyName(productClassify.getName());
        });

        //赋值仓库名称
        warehouseService.attributeAssign(stockVos, StockVo::getWarehouseId, (item, warehouse) -> {
            item.setWarehouseName(warehouse.getName());
        });

        return page;
    }

    @Override
    public Page<StockVo> pageByProductSpu(StockSelectDto dto) {
        IWrapper<Stock> wrapper = getWrapper();
        wrapper.eq(Stock::getWarehouseId, dto.getId());
        wrapper.like(Stock::getQuantity, dto.getKeyword());
        wrapper.eq("pi.definition", dto.getDefinition());
        wrapper.isNotNull("ps.id");
        wrapper.groupBy("ps.id");
        wrapper.orderByDesc("s", Stock::getId);
        Page<StockVo> page = this.baseMapper.pageByProductSpu(dto.getPage(), wrapper);
        //赋值关联产品数
        List<StockVo> records = page.getRecords();
        List<Long> spuids = records.stream().map(StockVo::getProductSpuId).collect(Collectors.toList());
        if (ObjectUtil.isEmpty(spuids)) {
            return page;
        }
        List<ProductInfo> productInfoList = productInfoService.list(q -> q.in(ProductInfo::getProductSpuId, spuids));
        Map<Long, List<ProductInfo>> productInfoMap = productInfoList.stream().collect(Collectors.groupingBy(ProductInfo::getProductSpuId));
        for (StockVo record : records) {
            List<ProductInfo> productInfoList1 = productInfoMap.get(record.getProductSpuId());
            record.setLinkProductQuantity(BigDecimal.valueOf(productInfoList1.size()));
            record.setCombinationQuantity(0l);
        }
        //赋值可组合数量
        List<Long> linkProductIds = new ArrayList<>();
        for (StockVo record : records) {
            String victoriatouristJson = record.getVictoriatouristJson();
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            if (json.getInteger("combination") != 1) {
                continue;
            }
            JSONArray productCombinationList = json.getJSONArray("productCombinationList");
            for (int i = 0; i < productCombinationList.size(); i++) {
                JSONObject item = productCombinationList.getJSONObject(i);
                Long linkProductId = item.getLong("linkProductId");
                linkProductIds.add(linkProductId);
//                BigDecimal linkQuantity = item.getBigDecimal("linkQuantity");
            }
        }
        if (ObjectUtil.isEmpty(linkProductIds)) {
            return page;
        }
        //查询关联产品库存
        List<Stock> list = list(q -> q.in(Stock::getProductId, linkProductIds));
        Map<Long, BigDecimal> stockMap = list.stream().collect(Collectors.toMap(Stock::getProductId, Stock::getQuantity));
        for (StockVo record : records) {
            String victoriatouristJson = record.getVictoriatouristJson();
            JSONObject json = JSONObject.parseObject(victoriatouristJson);
            if (json.getInteger("combination") != 1) {
                continue;
            }
            JSONArray productCombinationList = json.getJSONArray("productCombinationList");

            Long min = -1l;
            for (int i = 0; i < productCombinationList.size(); i++) {
                JSONObject item = productCombinationList.getJSONObject(i);
                Long linkProductId = item.getLong("linkProductId");
                BigDecimal linkQuantity = item.getBigDecimal("linkQuantity");

                BigDecimal stockQuantity = stockMap.getOrDefault(linkProductId, BigDecimal.ZERO);

                BigDecimal divide = stockQuantity.divide(linkQuantity, 0, BigDecimal.ROUND_DOWN);

                //计算最小值
                if (min == -1) {
                    min = divide.longValue();
                } else if (divide.intValue() < min) {
                    min = divide.longValue();
                }
            }
            record.setCombinationQuantity(min);
        }
        return page;
    }

    @Override
    public Stock detail(StockDto dto) {
        return getOne(q -> q.eq(Stock::getWarehouseId, dto.getWarehouseId()).eq(Stock::getProductId, dto.getProductId()));
    }

    @Override
    @DSTransactional
    public void add(StockDto stockDto) {
        //创建出入库记录
        StockJournal stockJournal = new StockJournal();
        stockJournal.setOpType(stockDto.getType());
        stockJournal.setType(stockDto.getType());
        stockJournal.setCode(stockDto.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
        stockJournal.setWarehouseId(stockDto.getWarehouseId());
        stockJournal.setBusinessId(stockDto.getBusinessId());
        //保存出入库记录
        stockJournalService.save(stockJournal);
        List<Stock> list = stockDto.getList();
        List<StockJournalDetails> stockJournalDetailsList = new ArrayList<>();
        for (Stock stock : list) {
            //创建出入库明细
            StockJournalDetails stockJournalDetails = new StockJournalDetailsDto();
            stockJournalDetails.setStockJournalId(stockJournal.getId());
            stockJournalDetails.setProductId(stock.getProductId());
            stockJournalDetails.setQuantity(stock.getQuantity());
            stockJournalDetails.setBusinessDetailsId(stock.getId());
            stockJournalDetailsList.add(stockJournalDetails);
        }
        //操作库存
        ModifyInventory(1, stockDto.getList(), stockDto.getWarehouseId());
        //保存出入库明细
        stockJournalDetailsService.saveBatch(stockJournalDetailsList);
    }

    @Override
    @DSTransactional
    public void edit(StockDto stockDto) {
        //创建出入库记录
        StockJournal stockJournal = new StockJournal();
        stockJournal.setOpType(stockDto.getType());
        stockJournal.setCode(stockDto.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
        stockJournal.setType(stockDto.getType());
        stockJournal.setWarehouseId(stockDto.getWarehouseId());
        stockJournal.setBusinessId(stockDto.getBusinessId());
        //保存出入库记录
        stockJournalService.save(stockJournal);
        //操作库存
        List<Stock> list = stockDto.getList();
        List<StockJournalDetails> stockJournalDetailsList = new ArrayList<>();
        for (Stock stock : list) {
            //创建出入库明细
            StockJournalDetails stockJournalDetails = new StockJournalDetailsDto();
            stockJournalDetails.setStockJournalId(stockJournal.getId());
            stockJournalDetails.setProductId(stock.getProductId());
            stockJournalDetails.setQuantity(stock.getQuantity());
            stockJournalDetails.setBusinessDetailsId(stock.getId());
            stockJournalDetailsList.add(stockJournalDetails);
        }
        ModifyInventory(2, stockDto.getList(), stockDto.getWarehouseId());
        //保存出入库明细
        stockJournalDetailsService.saveBatch(stockJournalDetailsList);
    }

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

    /**
     * 操作库存通用方法
     *
     * @param type 1入库 2出库 3维多利亚冻结库存入库 4维多利亚待出库次品库存
     */
    @Override
    public synchronized void ModifyInventory(int type, List<Stock> list, Long warehouseId) {
        List<Stock> data = new ArrayList<>();

        //获取现有库存
        List<Long> productIds = list.stream().map(Stock::getProductId).collect(Collectors.toList());
        List<Stock> stockList = list(q -> q.in(Stock::getProductId, productIds).eq(Stock::getWarehouseId, warehouseId));
        Map<Long, Stock> stockMap = stockList.stream().collect(Collectors.groupingBy(Stock::getProductId,
                Collectors.collectingAndThen(Collectors.toList(), value -> value.get(0))));

        for (Stock stock : list) {
            //忽略操作数量为0的记录 避免出现出入库记录为0的条目
            if (BigDecimal.ZERO.compareTo(stock.getQuantity()) == 0) {
                continue;
            }

            Stock oldStocks = stockMap.get(stock.getProductId());
            //如果库存不存在 就创建一条空库存
            if (ObjectUtil.isEmpty(oldStocks)) {
                oldStocks = new Stock();
                oldStocks.setProductId(stock.getProductId());
                oldStocks.setWarehouseId(warehouseId);
                oldStocks.setQuantity(BigDecimal.ZERO);
            }

            if (type == 1) {
                //入库库存相加
                BigDecimal quantity = oldStocks.getQuantity().add(stock.getQuantity());
                oldStocks.setQuantity(quantity);
            } else if (type == 2) {
                //出库库存相减
                ProductInfo productInfo = productInfoService.getById(stock.getProductId());
                if (productInfo == null) {
                    throw new ServiceException("产品id：" + stock.getProductId() + "不存在");
                }
                BigDecimal quantity = oldStocks.getQuantity().subtract(stock.getQuantity());
                if (quantity.compareTo(BigDecimal.ZERO) < 0) {
                    throw new ServiceException("以下商品库存不足，无法出库：" + productInfo.getName());
                }
                oldStocks.setQuantity(quantity);
            } else if (type == 3) {
                //维多利亚待入库增加冻结库存
                String victoriatouristJson = oldStocks.getVictoriatouristJson();
                JSONObject json = ObjectUtil.isEmpty(victoriatouristJson) ? new JSONObject() : JSONObject.parseObject(victoriatouristJson);
                BigDecimal frozenQuantity = json.getBigDecimal("frozenQuantity");
                frozenQuantity = frozenQuantity == null ? BigDecimal.ZERO : frozenQuantity;
                frozenQuantity = frozenQuantity.add(stock.getQuantity());
                json.put("frozenQuantity", frozenQuantity);
                oldStocks.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
            } else if (type == 4) {
                //维多利亚待出库操作次品库存
                String victoriatouristJson = oldStocks.getVictoriatouristJson();
                JSONObject json = ObjectUtil.isEmpty(victoriatouristJson) ? new JSONObject() : JSONObject.parseObject(victoriatouristJson);
                BigDecimal defectiveQuantity = json.getBigDecimal("defectiveQuantity");
                defectiveQuantity = defectiveQuantity == null ? BigDecimal.ZERO : defectiveQuantity;
                defectiveQuantity = defectiveQuantity.subtract(stock.getQuantity());
                if (defectiveQuantity.compareTo(BigDecimal.ZERO) < 0) {
                    ProductInfo productInfo = productInfoService.getById(stock.getProductId());
                    if (productInfo == null) {
                        throw new ServiceException("产品id：" + stock.getProductId() + "不存在");
                    }
                    throw new ServiceException("以下商品次品库存不足，无法出库：" + productInfo.getName());
                }
                json.put("defectiveQuantity", defectiveQuantity);
                oldStocks.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
            } else {
                throw new ServiceException("未知库存操作类型");
            }
            data.add(oldStocks);

        }
        //操作库存
        saveOrUpdateBatch(data);
    }

    /**
     * 次品转良品
     */
    @Override
    public void defectiveToQualified(Stock stock) {
        if (ObjectUtil.isEmpty(stock.getId())) {
            throw new ServiceException("库存id不能为空");
        }
        if (ObjectUtil.isEmpty(stock.getQuantity())) {
            throw new ServiceException("要转换的数量不能为空");
        }
        Stock stock1 = getById(stock.getId());
        String victoriatouristJson = stock1.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        BigDecimal quantity = stock1.getQuantity();
        BigDecimal defectiveQuantity = ObjectUtil.isNotEmpty(json.getBigDecimal("defectiveQuantity")) ? json.getBigDecimal("defectiveQuantity") : BigDecimal.ZERO;
        if (defectiveQuantity.compareTo(BigDecimal.ZERO) == 0) {
            throw new ServiceException("库存不足，无法转换");
        }
        stock1.setQuantity(quantity.add(stock.getQuantity()));
        json.put("defectiveQuantity", defectiveQuantity.subtract(stock.getQuantity()));
        stock1.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        updateById(stock1);
    }

    @Override
    public void inOut(List<? extends InOutBo> list, Long warehouseId, JournalType journalType, Long businessId) {

        // 改变库存数量
        changeStock(list, warehouseId, journalType);

        // 增加出入库记录
        Long journalId = addJournal(warehouseId, journalType, businessId);

        // 添加出入库明细
        addJournalDetails(list, journalId);

    }

    /**
     * 良品转次品
     */
    @Override
    public void qualifiedToDefective(Stock stock) {
        if (ObjectUtil.isEmpty(stock.getId())) {
            throw new ServiceException("库存id不能为空");
        }
        if (ObjectUtil.isEmpty(stock.getQuantity())) {
            throw new ServiceException("要转换的数量不能为空");
        }
        Stock stock1 = getById(stock.getId());
        String victoriatouristJson = stock1.getVictoriatouristJson();
        JSONObject json = ObjectUtil.isNotEmpty(victoriatouristJson) ? JSONObject.parseObject(victoriatouristJson) : new JSONObject();
        BigDecimal quantity = stock1.getQuantity();
        BigDecimal defectiveQuantity = ObjectUtil.isNotEmpty(json.getBigDecimal("defectiveQuantity")) ? json.getBigDecimal("defectiveQuantity") : BigDecimal.ZERO;
        if (quantity.compareTo(BigDecimal.ZERO) == 0) {
            throw new ServiceException("库存不足，无法转换");
        }
        stock1.setQuantity(quantity.subtract(stock.getQuantity()));
        json.put("defectiveQuantity", defectiveQuantity.add(stock.getQuantity()));
        stock1.setVictoriatouristJson(JSONObject.toJSONString(json, JSONWriter.Feature.WriteLongAsString));
        updateById(stock1);
    }

    /**
     * 改变库存数量
     */
    private synchronized void changeStock(List<? extends InOutBo> list, Long warehouseId, JournalType journalType) {

        Map<Long, BigDecimal> map = list.stream().collect(Collectors.toMap(
                InOutBo::getProductId,
                InOutBo::getQuantity,
                BigDecimal::add
        ));

        if (journalType.getType().equals(InOutType.IN)) {
            map.forEach((productId, quantity) -> {
                Stock stock = getOne(q -> q.eq(Stock::getProductId, productId).eq(Stock::getWarehouseId, warehouseId));

                if (stock == null) {
                    stock = new Stock();
                    stock.setWarehouseId(warehouseId);
                    stock.setProductId(productId);
                    stock.setQuantity(quantity);
                    save(stock);
                } else {
                    Long stockId = stock.getId();
                    update(q -> q
                            .eq(BaseIdPo::getId, stockId)
                            .setSql("quantity = quantity + " + quantity)
                    );
                }
            });
        } else {
            map.forEach((productId, quantity) -> {
                boolean update = update(q -> q
                        .setSql("quantity = quantity - '" + quantity + "'")
                        .eq(Stock::getProductId, productId)
                        .eq(Stock::getWarehouseId, warehouseId)
                        .apply("quantity - {0} >= 0", quantity)
                );

                if (!update) {
                    ProductInfo productInfo = productInfoService.getById(productId);
                    if (productInfo == null) {
                        throw new ServiceException("产品id：" + productId + "不存在");
                    }

                    String err = "产品 {} 库存不足，出库失败";
                    throw new ServiceException(StrUtil.format(err, productInfo.getName()));
                }
            });
        }
    }

    /**
     * 添加出入库记录
     */
    private Long addJournal(Long warehouseId, JournalType journalType, Long businessId) {
        StockJournal stockJournal = new StockJournal();
        stockJournal.setType(journalType.getDetailType());
        switch (journalType.getDetailType()) {
            case 1:
                stockJournal.setOpType(1);//入库
                stockJournal.setCode(CodeEnum.SIN_CODE.getCode());
                break;
            case 2:
                stockJournal.setOpType(2);//出库
                stockJournal.setCode(CodeEnum.SOUT_CODE.getCode());
                break;
            case 3:
                stockJournal.setOpType(1);//调仓入库
//                stockJournal.setCode(CodeEnum.STOCK_TRANSFER.getCode());//调仓入库
                break;
            case 11:
                stockJournal.setOpType(2);//调仓出库
//                stockJournal.setCode(CodeEnum.STOCK_TRANSFER.getCode());//调仓出库
                break;

        }
        stockJournal.setBusinessId(businessId);
        stockJournal.setWarehouseId(warehouseId);
        stockJournalService.save(stockJournal);
        return stockJournal.getId();
    }

    /**
     * 添加出入库明细
     */
    private void addJournalDetails(List<? extends InOutBo> list, Long journalId) {
        List<StockJournalDetails> journalDetailsList = list.stream().map(item -> {
            StockJournalDetails stockJournalDetails = new StockJournalDetails();
            stockJournalDetails.setStockJournalId(journalId);
            stockJournalDetails.setProductId(item.getProductId());
            stockJournalDetails.setQuantity(item.getQuantity());
            return stockJournalDetails;
        }).collect(Collectors.toList());
        stockJournalDetailsService.saveBatch(journalDetailsList);
    }

}
