Commit 144963d07edb9672e7cfba944c1735e408a9d639

Authored by YunaiV
1 parent ccaae667

feat(wms):优化 inventory 的实现

yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/inventory/WmsInventoryMapper.java
... ... @@ -35,6 +35,30 @@ public interface WmsInventoryMapper extends BaseMapperX<WmsInventoryDO> {
35 35 return selectJoinPage(reqVO, WmsInventoryDO.class, query);
36 36 }
37 37  
  38 + default PageResult<WmsInventoryDO> selectPageGroupByWarehouse(WmsInventoryPageReqVO reqVO) {
  39 + MPJLambdaWrapperX<WmsInventoryDO> query = new MPJLambdaWrapperX<WmsInventoryDO>()
  40 + .selectMin(WmsInventoryDO::getId, WmsInventoryDO::getId)
  41 + .selectAs(WmsInventoryDO::getWarehouseId, WmsInventoryDO::getWarehouseId)
  42 + .selectAs("0", WmsInventoryDO::getAreaId)
  43 + .selectAs(WmsInventoryDO::getSkuId, WmsInventoryDO::getSkuId)
  44 + .selectSum(WmsInventoryDO::getQuantity, WmsInventoryDO::getQuantity)
  45 + .innerJoin(WmsItemSkuDO.class, WmsItemSkuDO::getId, WmsInventoryDO::getSkuId)
  46 + .innerJoin(WmsItemDO.class, WmsItemDO::getId, WmsItemSkuDO::getItemId)
  47 + .likeIfPresent(WmsItemDO::getCode, reqVO.getItemCode())
  48 + .likeIfPresent(WmsItemDO::getName, reqVO.getItemName())
  49 + .eqIfPresent(WmsInventoryDO::getSkuId, reqVO.getSkuId())
  50 + .likeIfPresent(WmsItemSkuDO::getCode, reqVO.getSkuCode())
  51 + .likeIfPresent(WmsItemSkuDO::getName, reqVO.getSkuName())
  52 + .eqIfPresent(WmsInventoryDO::getWarehouseId, reqVO.getWarehouseId());
  53 + query.groupBy(WmsInventoryDO::getWarehouseId, WmsInventoryDO::getSkuId);
  54 + if (reqVO.getMinQuantity() != null) {
  55 + query.having("SUM(t.quantity) >= {0}", reqVO.getMinQuantity());
  56 + }
  57 + query.orderByAsc(WmsInventoryDO::getWarehouseId)
  58 + .orderByAsc(WmsInventoryDO::getSkuId);
  59 + return selectJoinPage(reqVO, WmsInventoryDO.class, query);
  60 + }
  61 +
38 62 default Long selectCountBySkuId(Long skuId) {
39 63 return selectCount(WmsInventoryDO::getSkuId, skuId);
40 64 }
... ...
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImpl.java
1 1 package cn.iocoder.yudao.module.wms.service.inventory;
2 2  
  3 +import cn.hutool.core.util.StrUtil;
3 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 5 import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
5 6 import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
... ... @@ -22,6 +23,9 @@ public class WmsInventoryServiceImpl implements WmsInventoryService {
22 23  
23 24 @Override
24 25 public PageResult<WmsInventoryDO> getInventoryPage(WmsInventoryPageReqVO pageReqVO) {
  26 + if (StrUtil.equals(WmsInventoryPageReqVO.TYPE_WAREHOUSE, pageReqVO.getType())) {
  27 + return inventoryMapper.selectPageGroupByWarehouse(pageReqVO);
  28 + }
25 29 return inventoryMapper.selectPage(pageReqVO);
26 30 }
27 31  
... ...
yudao-module-wms/src/test/java/cn/iocoder/yudao/module/wms/service/inventory/WmsInventoryServiceImplTest.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.inventory;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  9 +import cn.iocoder.yudao.module.wms.dal.mysql.inventory.WmsInventoryMapper;
  10 +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemMapper;
  11 +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemSkuMapper;
  12 +import jakarta.annotation.Resource;
  13 +import org.junit.jupiter.api.Test;
  14 +import org.springframework.context.annotation.Import;
  15 +
  16 +import java.math.BigDecimal;
  17 +
  18 +import static org.junit.jupiter.api.Assertions.assertEquals;
  19 +
  20 +@Import(WmsInventoryServiceImpl.class)
  21 +public class WmsInventoryServiceImplTest extends BaseDbUnitTest {
  22 +
  23 + @Resource
  24 + private WmsInventoryServiceImpl inventoryService;
  25 +
  26 + @Resource
  27 + private WmsInventoryMapper inventoryMapper;
  28 + @Resource
  29 + private WmsItemMapper itemMapper;
  30 + @Resource
  31 + private WmsItemSkuMapper skuMapper;
  32 +
  33 + @Test
  34 + public void testGetInventoryPage_groupByWarehouse() {
  35 + // mock 数据
  36 + WmsItemDO item = createItem("ITEM-001", "红富士苹果");
  37 + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装");
  38 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "2.00"));
  39 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1002L, "3.00"));
  40 + inventoryMapper.insert(createInventory(sku.getId(), 200L, 1001L, "5.00"));
  41 + // 准备参数
  42 + WmsInventoryPageReqVO reqVO = new WmsInventoryPageReqVO();
  43 + reqVO.setType(WmsInventoryPageReqVO.TYPE_WAREHOUSE);
  44 + reqVO.setWarehouseId(100L);
  45 + reqVO.setAreaId(1001L); // 仓库维度不按库区过滤
  46 +
  47 + // 调用
  48 + PageResult<WmsInventoryDO> pageResult = inventoryService.getInventoryPage(reqVO);
  49 + // 断言
  50 + assertEquals(1, pageResult.getTotal());
  51 + assertEquals(1, pageResult.getList().size());
  52 + WmsInventoryDO inventory = pageResult.getList().get(0);
  53 + assertEquals(100L, inventory.getWarehouseId());
  54 + assertEquals(0L, inventory.getAreaId());
  55 + assertEquals(sku.getId(), inventory.getSkuId());
  56 + assertEquals(0, new BigDecimal("5.00").compareTo(inventory.getQuantity()));
  57 + }
  58 +
  59 + @Test
  60 + public void testGetInventoryPage_groupByWarehouse_minQuantity() {
  61 + // mock 数据
  62 + WmsItemDO item = createItem("ITEM-001", "红富士苹果");
  63 + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装");
  64 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "2.00"));
  65 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1002L, "3.00"));
  66 + // 准备参数
  67 + WmsInventoryPageReqVO reqVO = new WmsInventoryPageReqVO();
  68 + reqVO.setType(WmsInventoryPageReqVO.TYPE_WAREHOUSE);
  69 + reqVO.setMinQuantity(new BigDecimal("6.00"));
  70 +
  71 + // 调用
  72 + PageResult<WmsInventoryDO> pageResult = inventoryService.getInventoryPage(reqVO);
  73 + // 断言
  74 + assertEquals(0, pageResult.getTotal());
  75 + assertEquals(0, pageResult.getList().size());
  76 + }
  77 +
  78 + @Test
  79 + public void testGetInventoryPage_area() {
  80 + // mock 数据
  81 + WmsItemDO item = createItem("ITEM-001", "红富士苹果");
  82 + WmsItemSkuDO sku = createSku(item.getId(), "SKU-001", "10kg 箱装");
  83 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1001L, "2.00"));
  84 + inventoryMapper.insert(createInventory(sku.getId(), 100L, 1002L, "3.00"));
  85 + // 准备参数
  86 + WmsInventoryPageReqVO reqVO = new WmsInventoryPageReqVO();
  87 + reqVO.setType(WmsInventoryPageReqVO.TYPE_AREA);
  88 + reqVO.setWarehouseId(100L);
  89 +
  90 + // 调用
  91 + PageResult<WmsInventoryDO> pageResult = inventoryService.getInventoryPage(reqVO);
  92 + // 断言
  93 + assertEquals(2, pageResult.getTotal());
  94 + assertEquals(2, pageResult.getList().size());
  95 + }
  96 +
  97 + private WmsItemDO createItem(String code, String name) {
  98 + WmsItemDO item = WmsItemDO.builder()
  99 + .code(code)
  100 + .name(name)
  101 + .unit("箱")
  102 + .categoryId(1L)
  103 + .build();
  104 + itemMapper.insert(item);
  105 + return item;
  106 + }
  107 +
  108 + private WmsItemSkuDO createSku(Long itemId, String code, String name) {
  109 + WmsItemSkuDO sku = WmsItemSkuDO.builder()
  110 + .itemId(itemId)
  111 + .code(code)
  112 + .name(name)
  113 + .barCode("69010001")
  114 + .build();
  115 + skuMapper.insert(sku);
  116 + return sku;
  117 + }
  118 +
  119 + private static WmsInventoryDO createInventory(Long skuId, Long warehouseId, Long areaId, String quantity) {
  120 + return WmsInventoryDO.builder()
  121 + .skuId(skuId)
  122 + .warehouseId(warehouseId)
  123 + .areaId(areaId)
  124 + .quantity(new BigDecimal(quantity))
  125 + .build();
  126 + }
  127 +
  128 +}
... ...
yudao-module-wms/src/test/resources/application-unit-test.yaml 0 → 100644
  1 +spring:
  2 + main:
  3 + lazy-initialization: true # 开启懒加载,加快速度
  4 + banner-mode: off # 单元测试,禁用 Banner
  5 +
  6 +--- #################### 数据库相关配置 ####################
  7 +
  8 +spring:
  9 + datasource:
  10 + name: ruoyi-vue-pro
  11 + url: jdbc:h2:mem:testdb;MODE=MYSQL;DATABASE_TO_UPPER=false;NON_KEYWORDS=value; # MODE 使用 MySQL 模式;DATABASE_TO_UPPER 配置表和字段使用小写
  12 + driver-class-name: org.h2.Driver
  13 + username: sa
  14 + password:
  15 + druid:
  16 + async-init: true # 单元测试,异步初始化 Druid 连接池,提升启动速度
  17 + initial-size: 1 # 单元测试,配置为 1,提升启动速度
  18 + sql:
  19 + init:
  20 + schema-locations: classpath:/sql/create_tables.sql
  21 +
  22 + data:
  23 + redis:
  24 + host: 127.0.0.1 # 地址
  25 + port: 16379 # 端口(单元测试,使用 16379 端口)
  26 + database: 0 # 数据库索引
  27 +
  28 +mybatis:
  29 + lazy-initialization: true # 单元测试,设置 MyBatis Mapper 延迟加载,加速每个单元测试
  30 +
  31 +--- #################### 芋道相关配置 ####################
  32 +
  33 +yudao:
  34 + info:
  35 + base-package: cn.iocoder.yudao.module
... ...
yudao-module-wms/src/test/resources/sql/clean.sql 0 → 100644
  1 +DELETE FROM "wms_inventory";
  2 +DELETE FROM "wms_item_sku";
  3 +DELETE FROM "wms_item";
... ...
yudao-module-wms/src/test/resources/sql/create_tables.sql 0 → 100644
  1 +CREATE TABLE IF NOT EXISTS "wms_item" (
  2 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  3 + "code" varchar(20) NOT NULL,
  4 + "name" varchar(60) NOT NULL,
  5 + "unit" varchar(20) DEFAULT NULL,
  6 + "category_id" bigint NOT NULL,
  7 + "brand_id" bigint DEFAULT NULL,
  8 + "remark" varchar(255) DEFAULT NULL,
  9 + "creator" varchar(64) DEFAULT '',
  10 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  11 + "updater" varchar(64) DEFAULT '',
  12 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  13 + "deleted" bit NOT NULL DEFAULT FALSE,
  14 + "tenant_id" bigint NOT NULL DEFAULT '0',
  15 + PRIMARY KEY ("id")
  16 +) COMMENT 'WMS 商品表';
  17 +
  18 +CREATE TABLE IF NOT EXISTS "wms_item_sku" (
  19 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  20 + "name" varchar(255) NOT NULL,
  21 + "item_id" bigint NOT NULL,
  22 + "bar_code" varchar(64) DEFAULT NULL,
  23 + "code" varchar(64) DEFAULT NULL,
  24 + "length" decimal(24, 6) DEFAULT NULL,
  25 + "width" decimal(24, 6) DEFAULT NULL,
  26 + "height" decimal(24, 6) DEFAULT NULL,
  27 + "gross_weight" decimal(24, 6) DEFAULT NULL,
  28 + "net_weight" decimal(24, 6) DEFAULT NULL,
  29 + "cost_price" decimal(24, 6) DEFAULT NULL,
  30 + "selling_price" decimal(24, 6) DEFAULT NULL,
  31 + "creator" varchar(64) DEFAULT '',
  32 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  33 + "updater" varchar(64) DEFAULT '',
  34 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  35 + "deleted" bit NOT NULL DEFAULT FALSE,
  36 + "tenant_id" bigint NOT NULL DEFAULT '0',
  37 + PRIMARY KEY ("id")
  38 +) COMMENT 'WMS 商品 SKU 表';
  39 +
  40 +CREATE TABLE IF NOT EXISTS "wms_inventory" (
  41 + "id" bigint NOT NULL GENERATED BY DEFAULT AS IDENTITY,
  42 + "sku_id" bigint NOT NULL,
  43 + "warehouse_id" bigint NOT NULL,
  44 + "area_id" bigint NOT NULL DEFAULT '0',
  45 + "quantity" decimal(24, 6) NOT NULL DEFAULT '0',
  46 + "remark" varchar(255) DEFAULT NULL,
  47 + "creator" varchar(64) DEFAULT '',
  48 + "create_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  49 + "updater" varchar(64) DEFAULT '',
  50 + "update_time" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  51 + "deleted" bit NOT NULL DEFAULT FALSE,
  52 + "tenant_id" bigint NOT NULL DEFAULT '0',
  53 + PRIMARY KEY ("id")
  54 +) COMMENT 'WMS 库存表';
... ...