yzc 1 год назад
Родитель
Сommit
6456329237

+ 9 - 1
hx-wms/src/main/java/com/fjhx/wms/controller/stock/StockController.java

@@ -12,6 +12,10 @@ import com.fjhx.wms.entity.stock.dto.StockDto;
 import com.ruoyi.common.core.domain.BaseSelectDto;
 import com.fjhx.wms.service.stock.StockService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
 
 
 /**
@@ -19,7 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
  * 库存 前端控制器
  * </p>
  *
- * @author 
+ * @author
  * @since 2023-03-20
  */
 @DS(SourceConstant.WMS)
@@ -125,5 +129,9 @@ public class StockController {
         stockService.qualifiedToDefective(stock);
     }
 
+	@PostMapping("/excelExport")
+	public void excelExport(@RequestBody StockSelectDto dto, HttpServletResponse httpServletResponse) {
+		stockService.excelExport(dto, httpServletResponse);
+	}
 
 }

+ 43 - 0
hx-wms/src/main/java/com/fjhx/wms/entity/stock/bo/StockExcelBo.java

@@ -0,0 +1,43 @@
+package com.fjhx.wms.entity.stock.bo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.annotation.write.style.ColumnWidth;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+@Getter
+@Setter
+public class StockExcelBo {
+	@ColumnWidth(20)
+	@ExcelProperty("仓库名称")
+	private String warehouseName;
+	@ColumnWidth(20)
+	@ExcelProperty("物品类型")
+	private String productDefinitionName;
+	@ColumnWidth(35)
+	@ExcelProperty("所属分类")
+	private String productClassifyNames;
+	@ColumnWidth(20)
+	@ExcelProperty("物品编码")
+	private String productCode;
+	@ColumnWidth(35)
+	@ExcelProperty("物品名称")
+	private String productName;
+	@ColumnWidth(20)
+	@ExcelProperty("规格型号")
+	private String productSpec;
+	@ColumnWidth(10)
+	@ExcelProperty("单位")
+	private String productUnit;
+	@ColumnWidth(15)
+	@ExcelProperty("安全库存")
+	private Integer stockThreshold;
+	@ColumnWidth(15)
+	@ExcelProperty("库存数量")
+	private BigDecimal quantity;
+	@ColumnWidth(20)
+	@ExcelProperty("加权成本单价")
+	private BigDecimal unitPrice;
+}

+ 4 - 0
hx-wms/src/main/java/com/fjhx/wms/entity/stock/vo/StockVo.java

@@ -71,6 +71,10 @@ public class StockVo extends Stock {
      * 产品定义
      */
     private Integer productDefinition;
+    /**
+     * 产品定义名称
+     */
+    private String productDefinitionName;
 
     /**
      * 产品spu名称

+ 4 - 0
hx-wms/src/main/java/com/fjhx/wms/mapper/stock/StockMapper.java

@@ -8,6 +8,8 @@ import com.fjhx.wms.entity.stock.vo.StockVo;
 import com.ruoyi.common.utils.wrapper.IWrapper;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.List;
+
 
 /**
  * <p>
@@ -24,6 +26,8 @@ public interface StockMapper extends BaseMapper<Stock> {
      */
     Page<StockVo> getPage(@Param("page") Page<Object> page, @Param("ew") IWrapper<Stock> wrapper);
 
+    List<StockVo> getList(@Param("ew") IWrapper<Stock> wrapper);
+
     Page<StockVo> pageByProduct(@Param("page") Page<Object> page, @Param("ew") IWrapper<Stock> wrapper);
 
     Page<StockVo> pageByProductSpu(@Param("page") Page<Object> page, @Param("ew") IWrapper<Stock> wrapper);

+ 7 - 0
hx-wms/src/main/java/com/fjhx/wms/service/stock/StockService.java

@@ -9,7 +9,9 @@ import com.fjhx.wms.entity.stock.po.Stock;
 import com.fjhx.wms.entity.stock.vo.StockTotalVo;
 import com.fjhx.wms.entity.stock.vo.StockVo;
 import com.ruoyi.common.core.service.BaseService;
+import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.http.HttpServletResponse;
 import java.math.BigDecimal;
 import java.util.List;
 
@@ -108,4 +110,9 @@ public interface StockService extends BaseService<Stock> {
      * 获取可用库存
      */
     BigDecimal getAvailableStockQuantity(Long productId);
+
+    /**
+     * 库存查询Excel导出
+     */
+    void excelExport(StockSelectDto dto, HttpServletResponse httpServletResponse);
 }

+ 671 - 641
hx-wms/src/main/java/com/fjhx/wms/service/stock/impl/StockServiceImpl.java

@@ -13,8 +13,10 @@ 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.item.util.excel.util.ExcelUtil;
 import com.fjhx.wms.entity.purchase.po.PurchaseDetailPo;
 import com.fjhx.wms.entity.stock.bo.InOutBo;
+import com.fjhx.wms.entity.stock.bo.StockExcelBo;
 import com.fjhx.wms.entity.stock.dto.StockDto;
 import com.fjhx.wms.entity.stock.dto.StockSelectDto;
 import com.fjhx.wms.entity.stock.emums.InOutType;
@@ -38,6 +40,7 @@ import com.ruoyi.common.utils.wrapper.IWrapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.servlet.http.HttpServletResponse;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
@@ -56,650 +59,677 @@ import java.util.stream.Collectors;
  */
 @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;
-
-    @Autowired
-    private StockWaitDetailsService stockWaitDetailsService;
-    @Autowired
-    private StockWaitService stockWaitService;
-    @Autowired
-    private MyWmsService myWmsService;
-
-    @Override
-    public Page<StockVo> getPage(StockSelectDto dto) {
-        IWrapper<Stock> wrapper = getWrapper();
-        wrapper.eq(Stock::getWarehouseId, dto.getId());
+	@Autowired
+	StockJournalService stockJournalService;
+	@Autowired
+	StockJournalDetailsService stockJournalDetailsService;
+	@Autowired
+	ProductInfoService productInfoService;
+	@Autowired
+	ProductClassifyService productClassifyService;
+	@Autowired
+	WarehouseService warehouseService;
+
+	@Autowired
+	private StockWaitDetailsService stockWaitDetailsService;
+	@Autowired
+	private StockWaitService stockWaitService;
+	@Autowired
+	private MyWmsService myWmsService;
+
+
+	private IWrapper<Stock> getConnWrapper(StockSelectDto dto) {
+		IWrapper<Stock> wrapper = getWrapper();
+		wrapper.eq(Stock::getWarehouseId, dto.getId());
+		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)
+					.or().like(ProductInfo::getSpec, 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());
+
+		//库存阈值过滤
+		if (ObjectUtil.isNotEmpty(dto.getIsStockThreshold()) && dto.getIsStockThreshold() == 1) {
+			wrapper.isNotNull("pi.stock_threshold");
+			wrapper.ne("pi.stock_threshold", "");
+			wrapper.ltSql("s.quantity", "stock_threshold");
+		}
+
+		wrapper.orderByDesc("s", Stock::getId);
+		return wrapper;
+	}
+
+	@Override
+	public Page<StockVo> getPage(StockSelectDto dto) {
+		IWrapper<Stock> wrapper = getConnWrapper(dto);
+
+		Page<StockVo> page = this.baseMapper.getPage(dto.getPage(), wrapper);
+		List<StockVo> stockVos = page.getRecords();
+
+		setListInfo(stockVos);
+
+		return page;
+	}
+
+	private void setListInfo(List<StockVo> stockVos) {
+		//赋值产品信息
+		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());
+		});
+	}
+
+	/**
+	 * 库存头部统计 目前只有阈值部分
+	 */
+	@Override
+	public StockTotalVo getHeadStatistic(StockSelectDto dto) {
+		IWrapper<Stock> wrapper = IWrapper.getWrapper();
+		wrapper.isNotNull("pi.stock_threshold");
+		wrapper.ne("pi.stock_threshold", "");
+		wrapper.ltSql("IFNULL(s.quantity,0)", "pi.stock_threshold");
+		return baseMapper.getHeadStatistic(wrapper);
+	}
+
+	/**
+	 * 维多利亚 按仓库库存查询
+	 */
+	@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)
-                    .or().like(ProductInfo::getSpec, 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());
-
-        //库存阈值过滤
-        if (ObjectUtil.isNotEmpty(dto.getIsStockThreshold()) && dto.getIsStockThreshold() == 1) {
-            wrapper.isNotNull("pi.stock_threshold");
-            wrapper.ne("pi.stock_threshold", "");
-            wrapper.ltSql("s.quantity", "stock_threshold");
-        }
-
-        wrapper.orderByDesc("s", Stock::getId);
-
-        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 StockTotalVo getHeadStatistic(StockSelectDto dto) {
-        IWrapper<Stock> wrapper = IWrapper.getWrapper();
-        wrapper.isNotNull("pi.stock_threshold");
-        wrapper.ne("pi.stock_threshold", "");
-        wrapper.ltSql("IFNULL(s.quantity,0)", "pi.stock_threshold");
-        return baseMapper.getHeadStatistic(wrapper);
-    }
-
-    /**
-     * 维多利亚 按仓库库存查询
-     */
-    @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);
+		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) {
-        manualInOrOutStock(stockDto);
-    }
-
-    @Override
-    @DSTransactional
-    public void edit(StockDto stockDto) {
-        manualInOrOutStock(stockDto);
-    }
-
-    /**
-     * 手动出入库
-     */
-    @DSTransactional
-    private synchronized void manualInOrOutStock(StockDto stockDto){
-        //获取操作类型
-        JournalType journalType = stockDto.getType() == 1 ? JournalType.MANUAL_IN : JournalType.MANUAL_OUT;
-
-        //创建出入库记录
-        StockJournal stockJournal = new StockJournal();
-        stockJournal.setOpType(stockDto.getType());
-        stockJournal.setType(journalType.getDetailType());
-        stockJournal.setCode(stockDto.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
-        stockJournal.setWarehouseId(stockDto.getWarehouseId());
-
-        stockJournal.setWorkOrderId(stockDto.getWorkOrderId());
-
-        stockJournal.setBusinessId(stockDto.getBusinessId());
-        stockJournal.setExWarehousePerson(stockDto.getExWarehousePerson());
-        stockJournal.setReceivingPerson(stockDto.getReceivingPerson());
-        //保存出入库记录
-        stockJournalService.save(stockJournal);
-        List<StockDto> list = stockDto.getList();
-
-        //解析扫码部分数据
-        List<Long> scanIds = list.stream().map(StockDto::getPurchaseDetailId).distinct().collect(Collectors.toList());
-        List<PurchaseDetailPo> purchaseDetailList = myWmsService.getPurchaseDetailList(scanIds);
-        Map<Long, BigDecimal> purchaseDetailMap = purchaseDetailList
-                .stream().collect(Collectors.toMap(PurchaseDetailPo::getId,PurchaseDetailPo::getPrice));
-
-        List<StockJournalDetails> stockJournalDetailsList = new ArrayList<>();
-        for (StockDto stock : list) {
-            //如果有采购明细id就获取采购单价,要不然单价为空(自动计算)
-            BigDecimal price = purchaseDetailMap.getOrDefault(stock.getPurchaseDetailId(),null);
-
-            //创建出入库明细
-            StockJournalDetails stockJournalDetails = stockWaitService.calculateUnitPrice(journalType.getType(), stock.getProductId(), stockDto.getWarehouseId(), stock.getQuantity(), 0, price);
-
-            stockJournalDetails.setStockJournalId(stockJournal.getId());
-            stockJournalDetails.setProductId(stock.getProductId());
-            stockJournalDetails.setQuantity(stock.getQuantity());
-            stockJournalDetails.setBusinessDetailsId(stock.getId());
-
-            stockJournalDetails.setPurchaseDetailId(stock.getPurchaseDetailId());
-            stockJournalDetails.setIsScan(stock.getIsScan());
-
-            stockJournalDetailsList.add(stockJournalDetails);
-        }
-        //操作库存
-        List<InOutBo> inOutBos = BeanUtil.copyToList(list, InOutBo.class);
-        changeStock(inOutBos, stockDto.getWarehouseId(), journalType);
-
-        //保存出入库明细
-        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);
-    }
-
-    /**
-     * 改变库存数量
-     */
-    @Override
-    public 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);//调仓入库
+			}
+		}
+		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) {
+		manualInOrOutStock(stockDto);
+	}
+
+	@Override
+	@DSTransactional
+	public void edit(StockDto stockDto) {
+		manualInOrOutStock(stockDto);
+	}
+
+	/**
+	 * 手动出入库
+	 */
+	@DSTransactional
+	private synchronized void manualInOrOutStock(StockDto stockDto) {
+		//获取操作类型
+		JournalType journalType = stockDto.getType() == 1 ? JournalType.MANUAL_IN : JournalType.MANUAL_OUT;
+
+		//创建出入库记录
+		StockJournal stockJournal = new StockJournal();
+		stockJournal.setOpType(stockDto.getType());
+		stockJournal.setType(journalType.getDetailType());
+		stockJournal.setCode(stockDto.getType() == 1 ? CodeEnum.SIN_CODE.getCode() : CodeEnum.SOUT_CODE.getCode());
+		stockJournal.setWarehouseId(stockDto.getWarehouseId());
+
+		stockJournal.setWorkOrderId(stockDto.getWorkOrderId());
+
+		stockJournal.setBusinessId(stockDto.getBusinessId());
+		stockJournal.setExWarehousePerson(stockDto.getExWarehousePerson());
+		stockJournal.setReceivingPerson(stockDto.getReceivingPerson());
+		//保存出入库记录
+		stockJournalService.save(stockJournal);
+		List<StockDto> list = stockDto.getList();
+
+		//解析扫码部分数据
+		List<Long> scanIds = list.stream().map(StockDto::getPurchaseDetailId).distinct().collect(Collectors.toList());
+		List<PurchaseDetailPo> purchaseDetailList = myWmsService.getPurchaseDetailList(scanIds);
+		Map<Long, BigDecimal> purchaseDetailMap = purchaseDetailList
+				.stream().collect(Collectors.toMap(PurchaseDetailPo::getId, PurchaseDetailPo::getPrice));
+
+		List<StockJournalDetails> stockJournalDetailsList = new ArrayList<>();
+		for (StockDto stock : list) {
+			//如果有采购明细id就获取采购单价,要不然单价为空(自动计算)
+			BigDecimal price = purchaseDetailMap.getOrDefault(stock.getPurchaseDetailId(), null);
+
+			//创建出入库明细
+			StockJournalDetails stockJournalDetails = stockWaitService.calculateUnitPrice(journalType.getType(), stock.getProductId(), stockDto.getWarehouseId(), stock.getQuantity(), 0, price);
+
+			stockJournalDetails.setStockJournalId(stockJournal.getId());
+			stockJournalDetails.setProductId(stock.getProductId());
+			stockJournalDetails.setQuantity(stock.getQuantity());
+			stockJournalDetails.setBusinessDetailsId(stock.getId());
+
+			stockJournalDetails.setPurchaseDetailId(stock.getPurchaseDetailId());
+			stockJournalDetails.setIsScan(stock.getIsScan());
+
+			stockJournalDetailsList.add(stockJournalDetails);
+		}
+		//操作库存
+		List<InOutBo> inOutBos = BeanUtil.copyToList(list, InOutBo.class);
+		changeStock(inOutBos, stockDto.getWarehouseId(), journalType);
+
+		//保存出入库明细
+		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);
+	}
+
+	/**
+	 * 改变库存数量
+	 */
+	@Override
+	public 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);//调仓出库
+				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);
-    }
-
-    /**
-     * 获取可用库存
-     */
-    @Override
-    public BigDecimal getAvailableStockQuantity(Long productId) {
-        //查询库存
-        List<Stock> stockList = this.list(q -> q.eq(Stock::getProductId, productId));
-        BigDecimal stockQuantityCount = stockList.stream().map(Stock::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
-        //查询待出库库存
-        List<StockWaitDetailsVo> stockWaitDetailsVos = stockWaitDetailsService.getList(IWrapper.<StockWaitDetails>getWrapper()
-                .eq(StockWaitDetails::getProductId, productId)
-                .eq("sw.type", 2)
-        );
-        BigDecimal stockWaitQuantityCount = stockWaitDetailsVos.stream().map(StockWaitDetails::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
-        BigDecimal receiptQuantityCount = stockWaitDetailsVos.stream().map(StockWaitDetails::getReceiptQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
-        //计算待出库数量
-        BigDecimal waitQuantity = stockWaitQuantityCount.subtract(receiptQuantityCount);
-        //计算可用库存
-        BigDecimal availableQuantity = stockQuantityCount.subtract(waitQuantity);
-        return availableQuantity;
-    }
+				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);
+	}
+
+	/**
+	 * 获取可用库存
+	 */
+	@Override
+	public BigDecimal getAvailableStockQuantity(Long productId) {
+		//查询库存
+		List<Stock> stockList = this.list(q -> q.eq(Stock::getProductId, productId));
+		BigDecimal stockQuantityCount = stockList.stream().map(Stock::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
+		//查询待出库库存
+		List<StockWaitDetailsVo> stockWaitDetailsVos = stockWaitDetailsService.getList(IWrapper.<StockWaitDetails>getWrapper()
+				.eq(StockWaitDetails::getProductId, productId)
+				.eq("sw.type", 2)
+		);
+		BigDecimal stockWaitQuantityCount = stockWaitDetailsVos.stream().map(StockWaitDetails::getQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
+		BigDecimal receiptQuantityCount = stockWaitDetailsVos.stream().map(StockWaitDetails::getReceiptQuantity).reduce(BigDecimal.ZERO, BigDecimal::add);
+		//计算待出库数量
+		BigDecimal waitQuantity = stockWaitQuantityCount.subtract(receiptQuantityCount);
+		//计算可用库存
+		BigDecimal availableQuantity = stockQuantityCount.subtract(waitQuantity);
+		return availableQuantity;
+	}
+
+	@Override
+	public void excelExport(StockSelectDto dto, HttpServletResponse httpServletResponse) {
+		IWrapper<Stock> connWrapper = getConnWrapper(dto);
+		List<StockVo> list = baseMapper.getList(connWrapper);
+		setListInfo(list);
+		for (StockVo stockVo : list) {
+			if(ObjectUtil.equals(stockVo.getProductDefinition(),1)){
+				stockVo.setProductDefinitionName("产品");
+			}else{
+				stockVo.setProductDefinitionName("物料");
+			}
+		}
+		List<StockExcelBo> stockVos = BeanUtil.copyToList(list, StockExcelBo.class);
+		ExcelUtil.export(httpServletResponse, stockVos, StockExcelBo.class);
+	}
 
 }

+ 9 - 1
hx-wms/src/main/resources/mapper/stock/StockMapper.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.fjhx.wms.mapper.stock.StockMapper">
-    <select id="getPage" resultType="com.fjhx.wms.entity.stock.vo.StockVo">
+    <sql id="listSql">
         SELECT s.id,
                pi.definition,
                s.warehouse_id,
@@ -16,8 +16,16 @@
                pi.stock_threshold
         FROM stock s
                  LEFT JOIN bytesailing_item.product_info pi ON s.product_id = pi.id
+    </sql>
+    <select id="getPage" resultType="com.fjhx.wms.entity.stock.vo.StockVo">
+       <include refid="listSql"></include>
             ${ew.customSqlSegment}
     </select>
+    <select id="getList" resultType="com.fjhx.wms.entity.stock.vo.StockVo">
+        <include refid="listSql"></include>
+        ${ew.customSqlSegment}
+    </select>
+
     <select id="pageByProduct" resultType="com.fjhx.wms.entity.stock.vo.StockVo">
         SELECT
             s.id,