diff --git a/.image/common/ruoyi-vue-pro-biz.png b/.image/common/ruoyi-vue-pro-biz.png
index 42dc849b5..355491963 100644
Binary files a/.image/common/ruoyi-vue-pro-biz.png and b/.image/common/ruoyi-vue-pro-biz.png differ
diff --git a/.image/common/wms-feature.png b/.image/common/wms-feature.png
new file mode 100644
index 000000000..0d7790b18
Binary files /dev/null and b/.image/common/wms-feature.png differ
diff --git a/.image/common/wms-preview.png b/.image/common/wms-preview.png
new file mode 100644
index 000000000..31c5187d9
Binary files /dev/null and b/.image/common/wms-preview.png differ
diff --git a/README.md b/README.md
index 65d5aafdc..de82d9613 100644
--- a/README.md
+++ b/README.md
@@ -31,8 +31,8 @@
| 【完整版】[yudao-cloud](https://gitee.com/zhijiantianya/yudao-cloud) | [`master`](https://gitee.com/zhijiantianya/yudao-cloud/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/zhijiantianya/yudao-cloud/tree/master-jdk17/) 分支 |
| 【精简版】[yudao-cloud-mini](https://gitee.com/yudaocode/yudao-cloud-mini) | [`master`](https://gitee.com/yudaocode/yudao-cloud-mini/tree/master/) 分支 | [`master-jdk17`](https://gitee.com/yudaocode/yudao-cloud-mini/tree/master-jdk17/) 分支 |
-* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP、MES、AI 大模型、IoT 物联网 等功能
-* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP、MES、AI 大模型、IoT 物联网 等功能
+* 【完整版】:包括系统功能、基础设施、会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP、WMS、MES、AI 大模型、IoT 物联网 等功能
+* 【精简版】:只包括系统功能、基础设施功能,不包括会员中心、数据报表、工作流程、商城系统、微信公众号、CRM、ERP、WMS、MES、AI 大模型、IoT 物联网 等功能
可参考 [《迁移文档》](https://cloud.iocoder.cn/migrate-module/) ,只需要 5-10 分钟,即可将【完整版】按需迁移到【精简版】
@@ -115,7 +115,7 @@
* 通用模块(必选):系统功能、基础设施
* 通用模块(可选):工作流程、支付系统、数据报表、会员中心
-* 业务系统(按需):ERP 系统、CRM 系统、MES 系统、商城系统、微信公众号、AI 大模型、IoT 物联网
+* 业务系统(按需):Mall 电子商城、OA 办公自动化、ERP 企业资源计划系统、WMS 仓库管理系统、CRM 客户关系管理、CMS 内容管理系统、MES 执行制造系统、AI 大模型平台、IoT 物联网系统、IM 即时通讯系统、Mobile 手机移动端、Report 数据大屏
> 友情提示:本项目基于 RuoYi-Vue 修改,**重构优化**后端的代码,**美化**前端的界面。
>
@@ -273,6 +273,14 @@

+### WMS 系统
+
+演示地址:
+
+
+
+
+
### CRM 系统
演示地址:
@@ -321,6 +329,7 @@
| `yudao-module-erp` | ERP 系统的 Module 模块 |
| `yudao-module-crm` | CRM 系统的 Module 模块 |
| `yudao-module-mes` | MES 系统的 Module 模块 |
+| `yudao-module-wms` | WMS 系统的 Module 模块 |
| `yudao-module-ai` | AI 大模型的 Module 模块 |
| `yudao-module-iot` | IoT 物联网的 Module 模块 |
| `yudao-module-mp` | 微信公众号的 Module 模块 |
diff --git a/pom.xml b/pom.xml
index 6cb303544..db439782e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -26,6 +26,7 @@
yudao-module-crm
yudao-module-iot
yudao-module-mes
+ yudao-module-wms
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
index 6c01b9497..517fd603e 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/banner/core/BannerApplicationRunner.java
@@ -37,8 +37,14 @@ public class BannerApplicationRunner implements ApplicationRunner {
System.out.println("[商城系统 yudao-module-mall 教程][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
// ERP 系统
System.out.println("[ERP 系统 yudao-module-erp - 教程][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
+ // WMS 仓库管理系统
+ System.out.println("[WMS 仓库管理系统 yudao-module-wms - 教程][参考 https://cloud.iocoder.cn/wms/build/ 开启]");
// CRM 系统
System.out.println("[CRM 系统 yudao-module-crm - 教程][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
+ // MES 系统
+ System.out.println("[MES 系统 yudao-module-mes - 教程][参考 https://cloud.iocoder.cn/mes/build/ 开启]");
+ // IM 即时通讯
+ System.out.println("[IM 即时通讯 yudao-module-im - 教程][参考 https://cloud.iocoder.cn/im/build/ 开启]");
// 微信公众号
System.out.println("[微信公众号 yudao-module-mp 教程][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
// 支付平台
diff --git a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
index 156d7e04a..33cb31e5b 100644
--- a/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
+++ b/yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/web/core/handler/GlobalExceptionHandler.java
@@ -410,25 +410,43 @@ public class GlobalExceptionHandler {
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
"[ERP 系统 yudao-module-erp - 表结构未导入][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
}
- // 6. CRM 系统
+ // 6. WMS 仓库管理系统
+ if (message.contains("wms_")) {
+ log.error("[WMS 仓库管理系统 yudao-module-wms - 表结构未导入][参考 https://cloud.iocoder.cn/wms/build/ 开启]");
+ return CommonResult.error(NOT_IMPLEMENTED.getCode(),
+ "[WMS 仓库管理系统 yudao-module-wms - 表结构未导入][参考 https://cloud.iocoder.cn/wms/build/ 开启]");
+ }
+ // 7. CRM 系统
if (message.contains("crm_")) {
log.error("[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
"[CRM 系统 yudao-module-crm - 表结构未导入][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
}
- // 7. 支付平台
+ // 8. MES 系统
+ if (message.contains("mes_")) {
+ log.error("[MES 系统 yudao-module-mes - 表结构未导入][参考 https://cloud.iocoder.cn/mes/build/ 开启]");
+ return CommonResult.error(NOT_IMPLEMENTED.getCode(),
+ "[MES 系统 yudao-module-mes - 表结构未导入][参考 https://cloud.iocoder.cn/mes/build/ 开启]");
+ }
+ // 9. IM 即时通讯
+ if (message.contains("im_")) {
+ log.error("[IM 即时通讯 yudao-module-im - 表结构未导入][参考 https://cloud.iocoder.cn/im/build/ 开启]");
+ return CommonResult.error(NOT_IMPLEMENTED.getCode(),
+ "[IM 即时通讯 yudao-module-im - 表结构未导入][参考 https://cloud.iocoder.cn/im/build/ 开启]");
+ }
+ // 10. 支付平台
if (message.contains("pay_")) {
log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
"[支付模块 yudao-module-pay - 表结构未导入][参考 https://cloud.iocoder.cn/pay/build/ 开启]");
}
- // 8. AI 大模型
+ // 11. AI 大模型
if (message.contains("ai_")) {
log.error("[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
"[AI 大模型 yudao-module-ai - 表结构未导入][参考 https://cloud.iocoder.cn/ai/build/ 开启]");
}
- // 9. IoT 物联网
+ // 12. IoT 物联网
if (message.contains("iot_")) {
log.error("[IoT 物联网 yudao-module-iot - 表结构未导入][参考 https://doc.iocoder.cn/iot/build/ 开启]");
return CommonResult.error(NOT_IMPLEMENTED.getCode(),
diff --git a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java
index 3933ef262..a9ecd0bdc 100644
--- a/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java
+++ b/yudao-gateway/src/main/java/cn/iocoder/yudao/gateway/util/BannerApplicationRunner.java
@@ -39,8 +39,14 @@ public class BannerApplicationRunner implements ApplicationRunner {
System.out.println("[商城系统 yudao-module-mall 教程][参考 https://cloud.iocoder.cn/mall/build/ 开启]");
// ERP 系统
System.out.println("[ERP 系统 yudao-module-erp - 教程][参考 https://cloud.iocoder.cn/erp/build/ 开启]");
+ // WMS 仓库管理系统
+ System.out.println("[WMS 仓库管理系统 yudao-module-wms - 教程][参考 https://cloud.iocoder.cn/wms/build/ 开启]");
// CRM 系统
System.out.println("[CRM 系统 yudao-module-crm - 教程][参考 https://cloud.iocoder.cn/crm/build/ 开启]");
+ // MES 系统
+ System.out.println("[MES 系统 yudao-module-mes - 教程][参考 https://cloud.iocoder.cn/mes/build/ 开启]");
+ // IM 即时通讯
+ System.out.println("[IM 即时通讯 yudao-module-im - 教程][参考 https://cloud.iocoder.cn/im/build/ 开启]");
// 微信公众号
System.out.println("[微信公众号 yudao-module-mp 教程][参考 https://cloud.iocoder.cn/mp/build/ 开启]");
// 支付平台
diff --git a/yudao-module-wms/pom.xml b/yudao-module-wms/pom.xml
new file mode 100644
index 000000000..6e3ee5fcb
--- /dev/null
+++ b/yudao-module-wms/pom.xml
@@ -0,0 +1,24 @@
+
+
+
+ cn.iocoder.cloud
+ yudao
+ ${revision}
+
+
+ yudao-module-wms-api
+ yudao-module-wms-server
+
+ 4.0.0
+ yudao-module-wms
+ pom
+
+ ${project.artifactId}
+
+ wms 模块下,仓库管理系统(Warehouse Management System)。
+ 例如说:仓库、物料、库存、入库、出库、移库、盘库等等
+
+
+
diff --git a/yudao-module-wms/yudao-module-wms-api/pom.xml b/yudao-module-wms/yudao-module-wms-api/pom.xml
new file mode 100644
index 000000000..91f1914ff
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/pom.xml
@@ -0,0 +1,33 @@
+
+
+
+ cn.iocoder.cloud
+ yudao-module-wms
+ ${revision}
+
+ 4.0.0
+ yudao-module-wms-api
+ jar
+
+ ${project.artifactId}
+
+ wms 模块 API,暴露给其它模块调用
+
+
+
+
+ cn.iocoder.cloud
+ yudao-common
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ true
+
+
+
+
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ApiConstants.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ApiConstants.java
new file mode 100644
index 000000000..c374a4f8d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ApiConstants.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.wms.enums;
+
+import cn.iocoder.yudao.framework.common.enums.RpcConstants;
+
+/**
+ * API 相关的枚举
+ *
+ * @author 芋道源码
+ */
+public class ApiConstants {
+
+ /**
+ * 服务名
+ *
+ * 注意,需要保证和 spring.application.name 保持一致
+ */
+ public static final String NAME = "wms-server";
+
+ public static final String PREFIX = RpcConstants.RPC_API_PREFIX + "/wms";
+
+ public static final String VERSION = "1.0.0";
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
new file mode 100644
index 000000000..e854bc530
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/DictTypeConstants.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.wms.enums;
+
+/**
+ * WMS 字典类型常量
+ *
+ * @author 芋道源码
+ */
+public interface DictTypeConstants {
+
+ String MERCHANT_TYPE = "merchant_type";
+ String ORDER_STATUS = "wms_order_status";
+ String ORDER_TYPE = "wms_order_type";
+ String RECEIPT_ORDER_TYPE = "wms_receipt_order_type";
+ String SHIPMENT_ORDER_TYPE = "wms_shipment_order_type";
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
new file mode 100644
index 000000000..217562741
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.wms.enums;
+
+import cn.iocoder.yudao.framework.common.exception.ErrorCode;
+
+/**
+ * WMS 错误码枚举类
+ *
+ * wms 系统,使用 1-060-000-000 段
+ */
+public interface ErrorCodeConstants {
+
+ // ========== WMS 基础数据-仓库 1-060-100-000 ==========
+ ErrorCode WAREHOUSE_NOT_EXISTS = new ErrorCode(1_060_100_000, "仓库不存在");
+ ErrorCode WAREHOUSE_NAME_DUPLICATE = new ErrorCode(1_060_100_001, "仓库名称重复");
+ ErrorCode WAREHOUSE_CODE_DUPLICATE = new ErrorCode(1_060_100_002, "仓库编号重复");
+ ErrorCode WAREHOUSE_HAS_ORDER = new ErrorCode(1_060_100_004, "删除失败!仓库已被{}使用!");
+ ErrorCode WAREHOUSE_HAS_INVENTORY = new ErrorCode(1_060_100_005, "删除失败!仓库已存在库存余额!");
+
+ // ========== WMS 基础数据-商品分类 1-060-102-000 ==========
+ ErrorCode ITEM_CATEGORY_NOT_EXISTS = new ErrorCode(1_060_102_000, "商品分类不存在");
+ ErrorCode ITEM_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_060_102_001, "商品分类名称重复");
+ ErrorCode ITEM_CATEGORY_PARENT_NOT_EXISTS = new ErrorCode(1_060_102_002, "父商品分类不存在");
+ ErrorCode ITEM_CATEGORY_PARENT_ERROR = new ErrorCode(1_060_102_003, "不能设置自己为父商品分类");
+ ErrorCode ITEM_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_060_102_004, "不能设置自己的子商品分类为父商品分类");
+ ErrorCode ITEM_CATEGORY_HAS_CHILDREN = new ErrorCode(1_060_102_005, "删除失败!请先删除该分类下的子分类!");
+ ErrorCode ITEM_CATEGORY_HAS_ITEM = new ErrorCode(1_060_102_006, "删除失败!分类已被商品使用!");
+ ErrorCode ITEM_CATEGORY_CODE_DUPLICATE = new ErrorCode(1_060_102_007, "商品分类编号重复");
+
+ // ========== WMS 基础数据-商品品牌 1-060-103-000 ==========
+ ErrorCode ITEM_BRAND_NOT_EXISTS = new ErrorCode(1_060_103_000, "商品品牌不存在");
+ ErrorCode ITEM_BRAND_HAS_ITEM = new ErrorCode(1_060_103_001, "删除失败!品牌已被商品使用!");
+ ErrorCode ITEM_BRAND_CODE_DUPLICATE = new ErrorCode(1_060_103_002, "商品品牌编号重复");
+ ErrorCode ITEM_BRAND_NAME_DUPLICATE = new ErrorCode(1_060_103_003, "商品品牌名称重复");
+
+ // ========== WMS 基础数据-商品 1-060-104-000 ==========
+ ErrorCode ITEM_NOT_EXISTS = new ErrorCode(1_060_104_000, "商品不存在");
+ ErrorCode ITEM_NAME_DUPLICATE = new ErrorCode(1_060_104_001, "商品名称重复");
+ ErrorCode ITEM_CODE_DUPLICATE = new ErrorCode(1_060_104_007, "商品编号重复");
+ ErrorCode ITEM_SKU_REQUIRED = new ErrorCode(1_060_104_002, "至少包含一个商品规格");
+ ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复");
+ ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在");
+ ErrorCode ITEM_SKU_HAS_INVENTORY = new ErrorCode(1_060_104_005, "删除失败!商品规格【{}】已被库存业务使用!");
+ ErrorCode ITEM_SKU_HAS_ORDER = new ErrorCode(1_060_104_006, "删除失败!商品规格【{}】已被{}使用!");
+
+ // ========== WMS 基础数据-往来企业 1-060-105-000 ==========
+ ErrorCode MERCHANT_NOT_EXISTS = new ErrorCode(1_060_105_000, "往来企业不存在");
+ ErrorCode MERCHANT_NOT_SUPPLIER = new ErrorCode(1_060_105_001, "往来企业必须是供应商或客户/供应商类型");
+ ErrorCode MERCHANT_NOT_CUSTOMER = new ErrorCode(1_060_105_002, "往来企业必须是客户或客户/供应商类型");
+ ErrorCode MERCHANT_HAS_ORDER = new ErrorCode(1_060_105_003, "删除失败!往来企业已被{}使用!");
+ ErrorCode MERCHANT_CODE_DUPLICATE = new ErrorCode(1_060_105_004, "往来企业编号重复");
+ ErrorCode MERCHANT_NAME_DUPLICATE = new ErrorCode(1_060_105_005, "往来企业名称重复");
+
+ // ========== WMS 入库单 1-060-200-000 ==========
+ ErrorCode RECEIPT_ORDER_NOT_EXISTS = new ErrorCode(1_060_200_000, "入库单不存在");
+ ErrorCode RECEIPT_ORDER_NO_DUPLICATE = new ErrorCode(1_060_200_001, "入库单号重复");
+ ErrorCode RECEIPT_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_200_002, "入库单状态不是草稿,不能操作");
+ ErrorCode RECEIPT_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_200_003, "入库单至少包含一条明细");
+ ErrorCode RECEIPT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_200_005, "入库单状态不是草稿或已作废,不能删除");
+ ErrorCode RECEIPT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_200_007, "入库单明细不存在");
+
+ // ========== WMS 出库单 1-060-201-000 ==========
+ ErrorCode SHIPMENT_ORDER_NOT_EXISTS = new ErrorCode(1_060_201_000, "出库单不存在");
+ ErrorCode SHIPMENT_ORDER_NO_DUPLICATE = new ErrorCode(1_060_201_001, "出库单号重复");
+ ErrorCode SHIPMENT_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_201_002, "出库单状态不是草稿,不能操作");
+ ErrorCode SHIPMENT_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_201_003, "出库单至少包含一条明细");
+ ErrorCode SHIPMENT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_201_005, "出库单状态不是草稿或已作废,不能删除");
+ ErrorCode SHIPMENT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_201_007, "出库单明细不存在");
+
+ // ========== WMS 移库单 1-060-202-000 ==========
+ ErrorCode MOVEMENT_ORDER_NOT_EXISTS = new ErrorCode(1_060_202_000, "移库单不存在");
+ ErrorCode MOVEMENT_ORDER_NO_DUPLICATE = new ErrorCode(1_060_202_001, "移库单号重复");
+ ErrorCode MOVEMENT_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_202_002, "移库单状态不是草稿,不能操作");
+ ErrorCode MOVEMENT_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_202_003, "移库单至少包含一条明细");
+ ErrorCode MOVEMENT_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_202_005, "移库单状态不是草稿或已作废,不能删除");
+ ErrorCode MOVEMENT_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_202_006, "移库单明细不存在");
+ ErrorCode MOVEMENT_ORDER_WAREHOUSE_SAME = new ErrorCode(1_060_202_007, "来源仓库和目标仓库不能相同");
+
+ // ========== WMS 盘库单 1-060-203-000 ==========
+ ErrorCode CHECK_ORDER_NOT_EXISTS = new ErrorCode(1_060_203_000, "盘库单不存在");
+ ErrorCode CHECK_ORDER_NO_DUPLICATE = new ErrorCode(1_060_203_001, "盘库单号重复");
+ ErrorCode CHECK_ORDER_STATUS_NOT_PREPARE = new ErrorCode(1_060_203_002, "盘库单状态不是草稿,不能操作");
+ ErrorCode CHECK_ORDER_DETAIL_REQUIRED = new ErrorCode(1_060_203_003, "盘库单至少包含一条明细");
+ ErrorCode CHECK_ORDER_STATUS_NOT_DELETABLE = new ErrorCode(1_060_203_005, "盘库单状态不是草稿或已作废,不能删除");
+ ErrorCode CHECK_ORDER_DETAIL_NOT_EXISTS = new ErrorCode(1_060_203_006, "盘库单明细不存在");
+ ErrorCode CHECK_ORDER_INVENTORY_CHANGED = new ErrorCode(1_060_203_007, "盘库单库存已变化,请重新加载库存后再完成");
+
+ // ========== WMS 库存 1-060-300-000 ==========
+ ErrorCode INVENTORY_QUANTITY_NOT_ENOUGH = new ErrorCode(1_060_300_000,
+ "库存不足,商品:{},商品规格:{},仓库:{},当前库存:{},变更数量:{}");
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/md/WmsMerchantTypeEnum.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/md/WmsMerchantTypeEnum.java
new file mode 100644
index 000000000..b6924e4c1
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/md/WmsMerchantTypeEnum.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.wms.enums.md;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * WMS 往来企业类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum WmsMerchantTypeEnum implements ArrayValuable {
+
+ CUSTOMER(1, "客户"),
+ SUPPLIER(2, "供应商"),
+ CUSTOMER_SUPPLIER(3, "客户/供应商");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsMerchantTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderStatusEnum.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderStatusEnum.java
new file mode 100644
index 000000000..065655bda
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderStatusEnum.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.wms.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * WMS 单据状态枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum WmsOrderStatusEnum implements ArrayValuable {
+
+ PREPARE(0, "草稿"),
+ FINISHED(4, "已完成"),
+ CANCELED(5, "已作废");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsOrderStatusEnum::getStatus)
+ .toArray(Integer[]::new);
+
+ /**
+ * 状态
+ */
+ private final Integer status;
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeConstants.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeConstants.java
new file mode 100644
index 000000000..3f9017d1d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeConstants.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.wms.enums.order;
+
+/**
+ * WMS 单据业务类型常量
+ *
+ * 集中管理业务类型枚举的编号,按业务域分段。
+ * 各枚举类引用此处常量,避免硬编码数字。(也避免冲突!!!)
+ *
+ * @author 芋道源码
+ */
+public final class WmsOrderTypeConstants {
+
+ private WmsOrderTypeConstants() {}
+
+ // ========== 入库单类型 [100, 200) ==========
+
+ public static final int RECEIPT_PRODUCTION = 100; // 生产入库:WmsReceiptOrderDO
+ public static final int RECEIPT_PURCHASE = 101; // 采购入库:WmsReceiptOrderDO
+ public static final int RECEIPT_RETURN = 102; // 退货入库:WmsReceiptOrderDO
+ public static final int RECEIPT_GIVE_BACK = 103; // 归还入库:WmsReceiptOrderDO
+
+ // ========== 出库单类型 [200, 300) ==========
+
+ public static final int SHIPMENT_RETURN = 200; // 退货出库:WmsShipmentOrderDO
+ public static final int SHIPMENT_SALE = 201; // 销售出库:WmsShipmentOrderDO
+ public static final int SHIPMENT_PRODUCTION = 202; // 生产出库:WmsShipmentOrderDO
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeEnum.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeEnum.java
new file mode 100644
index 000000000..701f7137b
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsOrderTypeEnum.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.wms.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * WMS 单据类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum WmsOrderTypeEnum implements ArrayValuable {
+
+ RECEIPT(1, "入库单"),
+ SHIPMENT(2, "出库单"),
+ MOVEMENT(3, "移库单"),
+ CHECK(4, "盘库单");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsOrderTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsReceiptOrderTypeEnum.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsReceiptOrderTypeEnum.java
new file mode 100644
index 000000000..1ac21f49b
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsReceiptOrderTypeEnum.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.wms.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * WMS 入库单类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum WmsReceiptOrderTypeEnum implements ArrayValuable {
+
+ PRODUCTION(WmsOrderTypeConstants.RECEIPT_PRODUCTION, "生产入库"),
+ PURCHASE(WmsOrderTypeConstants.RECEIPT_PURCHASE, "采购入库"),
+ RETURN(WmsOrderTypeConstants.RECEIPT_RETURN, "退货入库"),
+ GIVE_BACK(WmsOrderTypeConstants.RECEIPT_GIVE_BACK, "归还入库");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsReceiptOrderTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsShipmentOrderTypeEnum.java b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsShipmentOrderTypeEnum.java
new file mode 100644
index 000000000..79545f12e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-api/src/main/java/cn/iocoder/yudao/module/wms/enums/order/WmsShipmentOrderTypeEnum.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.wms.enums.order;
+
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * WMS 出库单类型枚举
+ *
+ * @author 芋道源码
+ */
+@Getter
+@AllArgsConstructor
+public enum WmsShipmentOrderTypeEnum implements ArrayValuable {
+
+ RETURN(WmsOrderTypeConstants.SHIPMENT_RETURN, "退货出库"),
+ SALE(WmsOrderTypeConstants.SHIPMENT_SALE, "销售出库"),
+ PRODUCTION(WmsOrderTypeConstants.SHIPMENT_PRODUCTION, "生产出库");
+
+ public static final Integer[] ARRAYS = Arrays.stream(values()).map(WmsShipmentOrderTypeEnum::getType).toArray(Integer[]::new);
+
+ /**
+ * 类型
+ */
+ private final Integer type;
+ /**
+ * 名称
+ */
+ private final String name;
+
+ @Override
+ public Integer[] array() {
+ return ARRAYS;
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/Dockerfile b/yudao-module-wms/yudao-module-wms-server/Dockerfile
new file mode 100644
index 000000000..200c60fae
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/Dockerfile
@@ -0,0 +1,19 @@
+## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
+## 感谢复旦核博士的建议!灰子哥,牛皮!
+FROM eclipse-temurin:21-jre
+
+## 创建目录,并使用它作为工作目录
+RUN mkdir -p /yudao-module-wms-server
+WORKDIR /yudao-module-wms-server
+## 将后端项目的 Jar 文件,复制到镜像中
+COPY ./target/yudao-module-wms-server.jar app.jar
+
+## 设置 TZ 时区
+## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
+ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m"
+
+## 暴露后端项目的 48092 端口
+EXPOSE 48092
+
+## 启动后端项目
+CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
diff --git a/yudao-module-wms/yudao-module-wms-server/pom.xml b/yudao-module-wms/yudao-module-wms-server/pom.xml
new file mode 100644
index 000000000..07590d70e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/pom.xml
@@ -0,0 +1,124 @@
+
+
+
+ cn.iocoder.cloud
+ yudao-module-wms
+ ${revision}
+
+ 4.0.0
+ yudao-module-wms-server
+
+ ${project.artifactId}
+
+ wms 模块下,仓库管理系统(Warehouse Management System)。
+ 例如说:仓库、物料、库存、入库、出库、移库、盘库等等
+
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-env
+
+
+
+
+ cn.iocoder.cloud
+ yudao-module-system-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-wms-api
+ ${revision}
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-tenant
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-security
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-mybatis
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-redis
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-rpc
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-excel
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-monitor
+
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-test
+
+
+
+
+
+
+ ${project.artifactId}
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/WmsServerApplication.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/WmsServerApplication.java
new file mode 100644
index 000000000..a5ba71599
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/WmsServerApplication.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.wms;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * 项目的启动类
+ *
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ *
+ * @author 芋道源码
+ */
+@SpringBootApplication
+public class WmsServerApplication {
+
+ public static void main(String[] args) {
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+
+ SpringApplication.run(WmsServerApplication.class, args);
+
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/WmsHomeStatisticsController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/WmsHomeStatisticsController.java
new file mode 100644
index 000000000..e9cbbef78
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/WmsHomeStatisticsController.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.wms.controller.admin.home;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.wms.controller.admin.home.vo.WmsHomeInventorySummaryRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.home.vo.WmsHomeOrderSummaryRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.home.vo.WmsHomeOrderTrendRespVO;
+import cn.iocoder.yudao.module.wms.service.home.WmsHomeStatisticsService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.constraints.Max;
+import jakarta.validation.constraints.Min;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - WMS 首页统计")
+@RestController
+@RequestMapping("/wms/home-statistics")
+@Validated
+public class WmsHomeStatisticsController {
+
+ @Resource
+ private WmsHomeStatisticsService homeStatisticsService;
+
+ @GetMapping("/order-summary")
+ @Operation(summary = "获得首页单据汇总统计")
+ @Parameter(name = "warehouseId", description = "仓库编号", example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:home:query')")
+ public CommonResult> getOrderSummary(
+ @RequestParam(value = "warehouseId", required = false) Long warehouseId) {
+ return success(homeStatisticsService.getOrderSummary(warehouseId));
+ }
+
+ @GetMapping("/order-trend")
+ @Operation(summary = "获得首页单据趋势")
+ @Parameter(name = "days", description = "天数", example = "7")
+ @PreAuthorize("@ss.hasPermission('wms:home:query')")
+ public CommonResult> getOrderTrend(
+ @RequestParam(value = "days", defaultValue = "7") @Min(1) @Max(90) Integer days,
+ @RequestParam(value = "warehouseId", required = false) Long warehouseId) {
+ return success(homeStatisticsService.getOrderTrend(days, warehouseId));
+ }
+
+ @GetMapping("/inventory-summary")
+ @Operation(summary = "获得首页库存汇总统计")
+ @Parameter(name = "warehouseId", description = "仓库编号", example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:home:query')")
+ public CommonResult getInventorySummary(
+ @RequestParam(value = "warehouseId", required = false) Long warehouseId,
+ @RequestParam(value = "goodsLimit", defaultValue = "5") @Min(1) @Max(20) Integer goodsLimit,
+ @RequestParam(value = "warehouseLimit", defaultValue = "8") @Min(1) @Max(20) Integer warehouseLimit) {
+ return success(homeStatisticsService.getInventorySummary(warehouseId, goodsLimit, warehouseLimit));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeInventorySummaryRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeInventorySummaryRespVO.java
new file mode 100644
index 000000000..18bb5c3e8
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeInventorySummaryRespVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.wms.controller.admin.home.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 首页库存汇总统计 Response VO")
+@Data
+public class WmsHomeInventorySummaryRespVO {
+
+ @Schema(description = "总库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000.00")
+ private BigDecimal totalQuantity;
+
+ @Schema(description = "商品库存占比列表")
+ private List goodsShareList;
+
+ @Schema(description = "仓库库存分布列表")
+ private List warehouseDistributionList;
+
+ @Schema(description = "管理后台 - WMS 首页商品库存排行 Response VO")
+ @Data
+ public static class ItemRank {
+
+ @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "A4 复印纸")
+ private String name;
+
+ @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ }
+
+ @Schema(description = "管理后台 - WMS 首页仓库库存排行 Response VO")
+ @Data
+ public static class WarehouseRank {
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海仓")
+ private String name;
+
+ @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderStatusRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderStatusRespVO.java
new file mode 100644
index 000000000..91b0fea11
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderStatusRespVO.java
@@ -0,0 +1,16 @@
+package cn.iocoder.yudao.module.wms.controller.admin.home.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 首页单据状态统计 Response VO")
+@Data
+public class WmsHomeOrderStatusRespVO {
+
+ @Schema(description = "状态值", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status;
+
+ @Schema(description = "单据数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
+ private Long count;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderSummaryRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderSummaryRespVO.java
new file mode 100644
index 000000000..adb34dede
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderSummaryRespVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.wms.controller.admin.home.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 首页单据汇总统计 Response VO")
+@Data
+public class WmsHomeOrderSummaryRespVO {
+
+ @Schema(description = "单据类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer type;
+
+ @Schema(description = "单据总数", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
+ private Long total;
+
+ @Schema(description = "状态分布")
+ private List statuses;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderTrendRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderTrendRespVO.java
new file mode 100644
index 000000000..3ebb477e7
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/home/vo/WmsHomeOrderTrendRespVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.wms.controller.admin.home.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 首页单据趋势 Response VO")
+@Data
+public class WmsHomeOrderTrendRespVO {
+
+ @Schema(description = "时间", requiredMode = Schema.RequiredMode.REQUIRED, example = "1778169600000")
+ private LocalDateTime time;
+
+ @Schema(description = "入库单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "12")
+ private Long receiptCount;
+
+ @Schema(description = "出库单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "8")
+ private Long shipmentCount;
+
+ @Schema(description = "移库单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "3")
+ private Long movementCount;
+
+ @Schema(description = "盘库单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ private Long checkCount;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryController.java
new file mode 100644
index 000000000..5142e05f8
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryController.java
@@ -0,0 +1,87 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryListReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.WmsInventoryRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - WMS 库存统计")
+@RestController
+@RequestMapping("/wms/inventory")
+@Validated
+public class WmsInventoryController {
+
+ @Resource
+ private WmsInventoryService inventoryService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得库存统计分页")
+ @PreAuthorize("@ss.hasPermission('wms:inventory:query')")
+ public CommonResult> getInventoryPage(@Valid WmsInventoryPageReqVO pageReqVO) {
+ PageResult pageResult = inventoryService.getInventoryPage(pageReqVO);
+ return success(new PageResult<>(buildInventoryRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得库存统计列表")
+ @PreAuthorize("@ss.hasPermission('wms:inventory:query')")
+ public CommonResult> getInventoryList(@Valid WmsInventoryListReqVO listReqVO) {
+ List list = inventoryService.getInventoryList(listReqVO);
+ return success(buildInventoryRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildInventoryRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsInventoryDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsInventoryDO::getWarehouseId));
+ return BeanUtils.toBean(list, WmsInventoryRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryHistoryController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryHistoryController.java
new file mode 100644
index 000000000..c7530bfaa
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/WmsInventoryHistoryController.java
@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.history.WmsInventoryHistoryPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.history.WmsInventoryHistoryRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryHistoryDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.service.inventory.WmsInventoryHistoryService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - WMS 库存流水")
+@RestController
+@RequestMapping("/wms/inventory-history")
+@Validated
+public class WmsInventoryHistoryController {
+
+ @Resource
+ private WmsInventoryHistoryService inventoryHistoryService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得库存流水分页")
+ @PreAuthorize("@ss.hasPermission('wms:inventory-history:query')")
+ public CommonResult> getInventoryHistoryPage(
+ @Valid WmsInventoryHistoryPageReqVO pageReqVO) {
+ PageResult pageResult = inventoryHistoryService.getInventoryHistoryPage(pageReqVO);
+ return success(new PageResult<>(buildInventoryHistoryRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildInventoryHistoryRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsInventoryHistoryDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsInventoryHistoryDO::getWarehouseId));
+ return BeanUtils.toBean(list, WmsInventoryHistoryRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryListReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryListReqVO.java
new file mode 100644
index 000000000..e3deb8cb2
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryListReqVO.java
@@ -0,0 +1,15 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 库存统计列表 Request VO")
+@Data
+public class WmsInventoryListReqVO {
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "仓库编号不能为空")
+ private Long warehouseId;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryPageReqVO.java
new file mode 100644
index 000000000..4917a1e62
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryPageReqVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - WMS 库存统计分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsInventoryPageReqVO extends PageParam {
+
+ /**
+ * 按仓库维度统计
+ */
+ public static final String TYPE_WAREHOUSE = "warehouse";
+
+ /**
+ * 按商品维度统计
+ */
+ public static final String TYPE_ITEM = "item";
+
+ @Schema(description = "统计维度", requiredMode = Schema.RequiredMode.REQUIRED, example = "warehouse")
+ @NotBlank(message = "统计维度不能为空")
+ private String type;
+
+ @Schema(description = "商品编号", example = "ITEM001")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品 SKU 编号", example = "1024")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU001")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", example = "2048")
+ private Long warehouseId;
+
+ @Schema(description = "最小库存数量", example = "0.01")
+ private BigDecimal minQuantity;
+
+ @Schema(description = "是否只查询正库存", example = "true")
+ private Boolean onlyPositiveQuantity;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryRespVO.java
new file mode 100644
index 000000000..c5c3d34ec
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/WmsInventoryRespVO.java
@@ -0,0 +1,44 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 库存统计 Response VO")
+@Data
+public class WmsInventoryRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long itemId;
+ @Schema(description = "商品编码", example = "ITEM001")
+ private String itemCode;
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
+ private Long skuId;
+ @Schema(description = "规格编号", example = "SKU001")
+ private String skuCode;
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8192")
+ private Long warehouseId;
+ @Schema(description = "仓库名称", example = "成品仓")
+ private String warehouseName;
+
+ @Schema(description = "库存数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryPageReqVO.java
new file mode 100644
index 000000000..23b42bcd5
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryPageReqVO.java
@@ -0,0 +1,48 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.history;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 库存流水分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsInventoryHistoryPageReqVO extends PageParam {
+
+ @Schema(description = "商品编号", example = "ITEM001")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品 SKU 编号", example = "1024")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU001")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", example = "2048")
+ private Long warehouseId;
+
+ @Schema(description = "单据号", example = "RK202605110001")
+ private String orderNo;
+
+ @Schema(description = "单据类型", example = "1")
+ private Integer orderType;
+
+ @Schema(description = "操作时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryRespVO.java
new file mode 100644
index 000000000..87c87251a
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/inventory/vo/history/WmsInventoryHistoryRespVO.java
@@ -0,0 +1,59 @@
+package cn.iocoder.yudao.module.wms.controller.admin.inventory.vo.history;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 库存流水 Response VO")
+@Data
+public class WmsInventoryHistoryRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long itemId;
+ @Schema(description = "商品编码", example = "ITEM001")
+ private String itemCode;
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4096")
+ private Long skuId;
+ @Schema(description = "规格编号", example = "SKU001")
+ private String skuCode;
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8192")
+ private Long warehouseId;
+ @Schema(description = "仓库名称", example = "成品仓")
+ private String warehouseName;
+
+ @Schema(description = "库存变化数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10.00")
+ private BigDecimal quantity;
+ @Schema(description = "变化前库存数量", example = "90.00")
+ private BigDecimal beforeQuantity;
+ @Schema(description = "变化后库存数量", example = "100.00")
+ private BigDecimal afterQuantity;
+ @Schema(description = "单价", example = "1000.00")
+ private BigDecimal price;
+ @Schema(description = "库存变化金额", example = "10000.00")
+ private BigDecimal totalPrice;
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+ @Schema(description = "单据编号", example = "1024")
+ private Long orderId;
+ @Schema(description = "单据号", example = "RK202605110001")
+ private String orderNo;
+ @Schema(description = "单据类型", example = "1")
+ private Integer orderType;
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemBrandController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemBrandController.java
new file mode 100644
index 000000000..6094e1150
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemBrandController.java
@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemBrandService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - WMS 商品品牌")
+@RestController
+@RequestMapping("/wms/item-brand")
+@Validated
+public class WmsItemBrandController {
+
+ @Resource
+ private WmsItemBrandService brandService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建商品品牌")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:create')")
+ public CommonResult createItemBrand(@Valid @RequestBody WmsItemBrandSaveReqVO createReqVO) {
+ return success(brandService.createItemBrand(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新商品品牌")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:update')")
+ public CommonResult updateItemBrand(@Valid @RequestBody WmsItemBrandSaveReqVO updateReqVO) {
+ brandService.updateItemBrand(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除商品品牌")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:delete')")
+ public CommonResult deleteItemBrand(@RequestParam("id") Long id) {
+ brandService.deleteItemBrand(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得商品品牌")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:query')")
+ public CommonResult getItemBrand(@RequestParam("id") Long id) {
+ WmsItemBrandDO brand = brandService.getItemBrand(id);
+ return success(BeanUtils.toBean(brand, WmsItemBrandRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得商品品牌分页")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:query')")
+ public CommonResult> getItemBrandPage(@Valid WmsItemBrandPageReqVO pageReqVO) {
+ PageResult pageResult = brandService.getItemBrandPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, WmsItemBrandRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得商品品牌精简列表", description = "主要用于前端下拉")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:query')")
+ public CommonResult> getItemBrandSimpleList() {
+ List list = brandService.getItemBrandList();
+ return success(BeanUtils.toBean(list, WmsItemBrandRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出商品品牌 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:item-brand:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportItemBrandExcel(@Valid WmsItemBrandPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = brandService.getItemBrandPage(pageReqVO).getList();
+ ExcelUtils.write(response, "商品品牌.xls", "数据", WmsItemBrandRespVO.class,
+ BeanUtils.toBean(list, WmsItemBrandRespVO.class));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemCategoryController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemCategoryController.java
new file mode 100644
index 000000000..d30edfa24
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemCategoryController.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategoryListReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategoryRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategorySaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemCategoryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - WMS 商品分类")
+@RestController
+@RequestMapping("/wms/item-category")
+@Validated
+public class WmsItemCategoryController {
+
+ @Resource
+ private WmsItemCategoryService categoryService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建商品分类")
+ @PreAuthorize("@ss.hasPermission('wms:item-category:create')")
+ public CommonResult createItemCategory(@Valid @RequestBody WmsItemCategorySaveReqVO createReqVO) {
+ return success(categoryService.createItemCategory(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新商品分类")
+ @PreAuthorize("@ss.hasPermission('wms:item-category:update')")
+ public CommonResult updateItemCategory(@Valid @RequestBody WmsItemCategorySaveReqVO updateReqVO) {
+ categoryService.updateItemCategory(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除商品分类")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:item-category:delete')")
+ public CommonResult deleteItemCategory(@RequestParam("id") Long id) {
+ categoryService.deleteItemCategory(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得商品分类")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:item-category:query')")
+ public CommonResult getItemCategory(@RequestParam("id") Long id) {
+ WmsItemCategoryDO category = categoryService.getItemCategory(id);
+ return success(BeanUtils.toBean(category, WmsItemCategoryRespVO.class));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得商品分类列表")
+ @PreAuthorize("@ss.hasPermission('wms:item-category:query')")
+ public CommonResult> getItemCategoryList(@Valid WmsItemCategoryListReqVO listReqVO) {
+ List list = categoryService.getItemCategoryList(listReqVO);
+ return success(BeanUtils.toBean(list, WmsItemCategoryRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得商品分类精简列表", description = "主要用于前端下拉")
+ @PreAuthorize("@ss.hasPermission('wms:item-category:query')")
+ public CommonResult> getItemCategorySimpleList() {
+ List list = categoryService.getItemCategoryList(new WmsItemCategoryListReqVO());
+ return success(BeanUtils.toBean(list, WmsItemCategoryRespVO.class));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java
new file mode 100644
index 000000000..86a8592fc
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java
@@ -0,0 +1,150 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemListReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemBrandService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemCategoryService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
+
+@Tag(name = "管理后台 - WMS 商品")
+@RestController
+@RequestMapping("/wms/item")
+@Validated
+public class WmsItemController {
+
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemCategoryService categoryService;
+ @Resource
+ private WmsItemBrandService brandService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建商品")
+ @PreAuthorize("@ss.hasPermission('wms:item:create')")
+ public CommonResult createItem(@Valid @RequestBody WmsItemSaveReqVO createReqVO) {
+ return success(itemService.createItem(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新商品")
+ @PreAuthorize("@ss.hasPermission('wms:item:update')")
+ public CommonResult updateItem(@Valid @RequestBody WmsItemSaveReqVO updateReqVO) {
+ itemService.updateItem(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除商品")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:item:delete')")
+ public CommonResult deleteItem(@RequestParam("id") Long id) {
+ itemService.deleteItem(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得商品")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:item:query')")
+ public CommonResult getItem(@RequestParam("id") Long id) {
+ WmsItemDO item = itemService.getItem(id);
+ return success(buildItemRespVO(item));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得商品分页")
+ @PreAuthorize("@ss.hasPermission('wms:item:query')")
+ public CommonResult> getItemPage(@Valid WmsItemPageReqVO pageReqVO) {
+ PageResult pageResult = itemService.getItemPage(pageReqVO);
+ return success(new PageResult<>(buildItemRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得商品精简列表")
+ @PreAuthorize("@ss.hasPermission('wms:item:query')")
+ public CommonResult> getItemSimpleList(@Valid WmsItemListReqVO listReqVO) {
+ List list = itemService.getItemList(listReqVO);
+ return success(buildItemRespVOList(list));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出商品 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:item:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportItemExcel(@Valid WmsItemPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = itemService.getItemPage(pageReqVO).getList();
+ ExcelUtils.write(response, "商品.xls", "数据", WmsItemRespVO.class,
+ buildItemRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private WmsItemRespVO buildItemRespVO(WmsItemDO item) {
+ if (item == null) {
+ return null;
+ }
+ return getFirst(buildItemRespVOList(Collections.singletonList(item)));
+ }
+
+ private List buildItemRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map categoryMap = categoryService.getItemCategoryMap(
+ convertSet(list, WmsItemDO::getCategoryId));
+ Map brandMap = brandService.getItemBrandMap(
+ convertSet(list, WmsItemDO::getBrandId));
+ Map> skuMap = itemSkuService.getItemSkuMultiMap(
+ convertSet(list, WmsItemDO::getId));
+ // 拼接 VO
+ return BeanUtils.toBean(list, WmsItemRespVO.class, vo -> {
+ MapUtils.findAndThen(categoryMap, vo.getCategoryId(), category ->
+ vo.setCategoryName(category.getName()));
+ MapUtils.findAndThen(brandMap, vo.getBrandId(), brand ->
+ vo.setBrandName(brand.getName()));
+ vo.setSkus(BeanUtils.toBean(skuMap.getOrDefault(vo.getId(), Collections.emptyList()),
+ WmsItemSkuRespVO.class));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemSkuController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemSkuController.java
new file mode 100644
index 000000000..5ece6f3ba
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemSkuController.java
@@ -0,0 +1,89 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemBrandService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemCategoryService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+/**
+ * WMS 商品 SKU Controller。
+ *
+ * SKU 维度的查询入口:弹窗 / 选择器场景使用,按 SKU 一行展开,支持商品 / 品牌 / 分类多表联查筛选。
+ * 复用商品权限 {@code wms:item:query},不单独建权限点(lite 也是商品/SKU 共用 {@code wms:item:list})。
+ *
+ *
SKU 的新增 / 修改 / 删除仍随商品弹窗一并维护,不在本 Controller 暴露。
+ */
+@Tag(name = "管理后台 - WMS 商品 SKU")
+@RestController
+@RequestMapping("/wms/item-sku")
+@Validated
+public class WmsItemSkuController {
+
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemCategoryService categoryService;
+ @Resource
+ private WmsItemBrandService brandService;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得商品 SKU 分页", description = "按 SKU 维度分页,支持商品 / 品牌 / 分类多表联查筛选")
+ @PreAuthorize("@ss.hasPermission('wms:item:query')")
+ public CommonResult> getItemSkuPage(@Valid WmsItemSkuPageReqVO pageReqVO) {
+ PageResult pageResult = itemSkuService.getItemSkuPage(pageReqVO);
+ return success(new PageResult<>(buildItemSkuRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildItemSkuRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map itemMap = itemService.getItemMap(convertSet(list, WmsItemSkuDO::getItemId));
+ Map categoryMap = categoryService.getItemCategoryMap(
+ convertSet(itemMap.values(), WmsItemDO::getCategoryId));
+ Map brandMap = brandService.getItemBrandMap(
+ convertSet(itemMap.values(), WmsItemDO::getBrandId));
+ // 拼接 VO
+ return BeanUtils.toBean(list, WmsItemSkuRespVO.class, vo -> MapUtils.findAndThen(itemMap, vo.getItemId(), item -> {
+ vo.setItemCode(item.getCode()).setItemName(item.getName()).setUnit(item.getUnit())
+ .setCategoryId(item.getCategoryId()).setBrandId(item.getBrandId());
+ MapUtils.findAndThen(categoryMap, item.getCategoryId(), category ->
+ vo.setCategoryName(category.getName()));
+ MapUtils.findAndThen(brandMap, item.getBrandId(), brand ->
+ vo.setBrandName(brand.getName()));
+ }));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandPageReqVO.java
new file mode 100644
index 000000000..0e2d74525
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandPageReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - WMS 商品品牌分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsItemBrandPageReqVO extends PageParam {
+
+ @Schema(description = "品牌编号", example = "B00000001")
+ private String code;
+
+ @Schema(description = "品牌名称", example = "华为")
+ private String name;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandRespVO.java
new file mode 100644
index 000000000..bc68efe24
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandRespVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 商品品牌 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsItemBrandRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @ExcelProperty("编号")
+ private Long id;
+
+ @Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "B00000001")
+ @ExcelProperty("品牌编号")
+ private String code;
+
+ @Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为")
+ @ExcelProperty("品牌名称")
+ private String name;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandSaveReqVO.java
new file mode 100644
index 000000000..7090cf30d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandSaveReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 商品品牌新增/修改 Request VO")
+@Data
+public class WmsItemBrandSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "品牌编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "B00000001")
+ @NotEmpty(message = "品牌编号不能为空")
+ @Size(max = 20, message = "品牌编号长度不能超过 20 个字符")
+ private String code;
+
+ @Schema(description = "品牌名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为")
+ @NotEmpty(message = "品牌名称不能为空")
+ @Size(max = 30, message = "品牌名称长度不能超过 30 个字符")
+ private String name;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryListReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryListReqVO.java
new file mode 100644
index 000000000..274cad45f
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryListReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 商品分类列表 Request VO")
+@Data
+public class WmsItemCategoryListReqVO {
+
+ @Schema(description = "父级编号", example = "1")
+ private Long parentId;
+
+ @Schema(description = "分类编号", example = "C00000001")
+ private String code;
+
+ @Schema(description = "分类名称", example = "原料")
+ private String name;
+
+ @Schema(description = "状态", example = "0")
+ @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
+ private Integer status;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryRespVO.java
new file mode 100644
index 000000000..d629b989a
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryRespVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 商品分类 Response VO")
+@Data
+public class WmsItemCategoryRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Long parentId;
+
+ @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "C00000001")
+ private String code;
+
+ @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原料")
+ private String name;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Integer sort;
+
+ @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ private Integer status;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategorySaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategorySaveReqVO.java
new file mode 100644
index 000000000..8d0df2254
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategorySaveReqVO.java
@@ -0,0 +1,41 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 商品分类新增/修改 Request VO")
+@Data
+public class WmsItemCategorySaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "父级编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "父级编号不能为空")
+ private Long parentId;
+
+ @Schema(description = "分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "C00000001")
+ @NotEmpty(message = "分类编号不能为空")
+ @Size(max = 20, message = "分类编号长度不能超过 20 个字符")
+ private String code;
+
+ @Schema(description = "分类名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原料")
+ @NotEmpty(message = "分类名称不能为空")
+ @Size(max = 30, message = "分类名称长度不能超过 30 个字符")
+ private String name;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "排序不能为空")
+ private Integer sort;
+
+ @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "状态不能为空")
+ @InEnum(value = CommonStatusEnum.class, message = "状态必须是 {value}")
+ private Integer status;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
new file mode 100644
index 000000000..8dde808fe
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 商品列表 Request VO")
+@Data
+public class WmsItemListReqVO {
+
+ @Schema(description = "商品编号", example = "ITEM001")
+ private String code;
+
+ @Schema(description = "商品名称", example = "华为 nova flip")
+ private String name;
+
+ @Schema(description = "商品分类编号", example = "1024")
+ private Long categoryId;
+
+ @Schema(description = "商品品牌编号", example = "2048")
+ private Long brandId;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
new file mode 100644
index 000000000..5ae42c396
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 商品分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsItemPageReqVO extends PageParam {
+
+ @Schema(description = "商品编号", example = "ITEM001")
+ private String code;
+
+ @Schema(description = "商品名称", example = "华为 nova flip")
+ private String name;
+
+ @Schema(description = "商品分类编号", example = "1024")
+ private Long categoryId;
+
+ @Schema(description = "商品品牌编号", example = "2048")
+ private Long brandId;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java
new file mode 100644
index 000000000..d4e74167c
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 商品 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsItemRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @ExcelProperty("编号")
+ private Long id;
+
+ @Schema(description = "商品编号", example = "ITEM001")
+ @ExcelProperty("商品编号")
+ private String code;
+
+ @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为 nova flip")
+ @ExcelProperty("商品名称")
+ private String name;
+
+ @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long categoryId;
+
+ @Schema(description = "商品分类名称", example = "手机")
+ @ExcelProperty("商品分类")
+ private String categoryName;
+
+ @Schema(description = "单位", example = "台")
+ @ExcelProperty("单位")
+ private String unit;
+
+ @Schema(description = "商品品牌编号", example = "1")
+ private Long brandId;
+
+ @Schema(description = "商品品牌名称", example = "华为")
+ @ExcelProperty("商品品牌")
+ private String brandName;
+
+ @Schema(description = "备注", example = "备注")
+ @ExcelProperty("备注")
+ private String remark;
+
+ @Schema(description = "规格列表")
+ private List skus;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
new file mode 100644
index 000000000..6b8cadf1e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
@@ -0,0 +1,51 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
+
+import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 商品创建/更新 Request VO")
+@Data
+public class WmsItemSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "ITEM001")
+ @NotBlank(message = "商品编号不能为空")
+ @Size(max = 20, message = "商品编号长度不能超过 20 个字符")
+ private String code;
+
+ @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为 nova flip")
+ @NotBlank(message = "商品名称不能为空")
+ @Size(max = 60, message = "商品名称长度不能超过 60 个字符")
+ private String name;
+
+ @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "商品分类不能为空")
+ private Long categoryId;
+
+ @Schema(description = "单位", example = "台")
+ @Size(max = 20, message = "单位长度不能超过 20 个字符")
+ private String unit;
+
+ @Schema(description = "商品品牌编号", example = "1")
+ private Long brandId;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+ @Schema(description = "规格列表")
+ @Valid
+ @NotEmpty(message = "至少包含一个商品规格")
+ private List skus;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuPageReqVO.java
new file mode 100644
index 000000000..c091ea84e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuPageReqVO.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - WMS 商品 SKU 分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsItemSkuPageReqVO extends PageParam {
+
+ @Schema(description = "商品编号", example = "I00000001")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "华为 nova flip")
+ private String itemName;
+
+ @Schema(description = "商品分类编号", example = "1")
+ private Long categoryId;
+
+ @Schema(description = "商品品牌编号", example = "1")
+ private Long brandId;
+
+ @Schema(description = "规格编号", example = "S00000001")
+ private String code;
+
+ @Schema(description = "规格名称", example = "黑色")
+ private String name;
+
+ @Schema(description = "条码", example = "12345678")
+ private String barCode;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java
new file mode 100644
index 000000000..8bd57aa6a
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java
@@ -0,0 +1,73 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 商品 SKU Response VO")
+@Data
+public class WmsItemSkuRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "规格名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "黑色")
+ private String name;
+
+ @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long itemId;
+
+ @Schema(description = "商品编码", example = "ITEM001")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "华为 nova flip")
+ private String itemName;
+
+ @Schema(description = "商品分类编号", example = "1")
+ private Long categoryId;
+
+ @Schema(description = "商品分类名称", example = "手机")
+ private String categoryName;
+
+ @Schema(description = "单位", example = "台")
+ private String unit;
+
+ @Schema(description = "商品品牌编号", example = "1")
+ private Long brandId;
+
+ @Schema(description = "商品品牌名称", example = "华为")
+ private String brandName;
+
+ @Schema(description = "条码", example = "690000000001")
+ private String barCode;
+
+ @Schema(description = "规格编号", example = "SKU001")
+ private String code;
+
+ @Schema(description = "长,单位 cm", example = "10.0")
+ private BigDecimal length;
+
+ @Schema(description = "宽,单位 cm", example = "8.0")
+ private BigDecimal width;
+
+ @Schema(description = "高,单位 cm", example = "1.0")
+ private BigDecimal height;
+
+ @Schema(description = "毛重,单位 kg", example = "1.000")
+ private BigDecimal grossWeight;
+
+ @Schema(description = "净重,单位 kg", example = "0.900")
+ private BigDecimal netWeight;
+
+ @Schema(description = "成本价,单位元", example = "5000.00")
+ private BigDecimal costPrice;
+
+ @Schema(description = "销售价,单位元", example = "5288.00")
+ private BigDecimal sellingPrice;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java
new file mode 100644
index 000000000..1a79dcbdc
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java
@@ -0,0 +1,62 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - WMS 商品 SKU 创建/更新 Request VO")
+@Data
+public class WmsItemSkuSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "规格名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "黑色")
+ @NotBlank(message = "规格名称不能为空")
+ @Size(max = 255, message = "规格名称长度不能超过 255 个字符")
+ private String name;
+
+ @Schema(description = "商品编号", example = "1")
+ private Long itemId;
+
+ @Schema(description = "条码", example = "690000000001")
+ @Size(max = 64, message = "条码长度不能超过 64 个字符")
+ private String barCode;
+
+ @Schema(description = "规格编号", example = "SKU001")
+ @Size(max = 64, message = "规格编号长度不能超过 64 个字符")
+ private String code;
+
+ @Schema(description = "长,单位 cm", example = "10.0")
+ @DecimalMin(value = "0", message = "长不能小于 0")
+ private BigDecimal length;
+
+ @Schema(description = "宽,单位 cm", example = "8.0")
+ @DecimalMin(value = "0", message = "宽不能小于 0")
+ private BigDecimal width;
+
+ @Schema(description = "高,单位 cm", example = "1.0")
+ @DecimalMin(value = "0", message = "高不能小于 0")
+ private BigDecimal height;
+
+ @Schema(description = "毛重,单位 kg", example = "1.000")
+ @DecimalMin(value = "0", message = "毛重不能小于 0")
+ private BigDecimal grossWeight;
+
+ @Schema(description = "净重,单位 kg", example = "0.900")
+ @DecimalMin(value = "0", message = "净重不能小于 0")
+ private BigDecimal netWeight;
+
+ @Schema(description = "成本价,单位元", example = "5000.00")
+ @DecimalMin(value = "0", message = "成本价不能小于 0")
+ private BigDecimal costPrice;
+
+ @Schema(description = "销售价,单位元", example = "5288.00")
+ @DecimalMin(value = "0", message = "销售价不能小于 0")
+ private BigDecimal sellingPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/WmsMerchantController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/WmsMerchantController.java
new file mode 100644
index 000000000..897f6351c
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/WmsMerchantController.java
@@ -0,0 +1,101 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.merchant;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantListReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo.WmsMerchantSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
+import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - WMS 往来企业")
+@RestController
+@RequestMapping("/wms/merchant")
+@Validated
+public class WmsMerchantController {
+
+ @Resource
+ private WmsMerchantService merchantService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建往来企业")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:create')")
+ public CommonResult createMerchant(@Valid @RequestBody WmsMerchantSaveReqVO createReqVO) {
+ return success(merchantService.createMerchant(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新往来企业")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:update')")
+ public CommonResult updateMerchant(@Valid @RequestBody WmsMerchantSaveReqVO updateReqVO) {
+ merchantService.updateMerchant(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除往来企业")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:merchant:delete')")
+ public CommonResult deleteMerchant(@RequestParam("id") Long id) {
+ merchantService.deleteMerchant(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得往来企业")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:query')")
+ public CommonResult getMerchant(@RequestParam("id") Long id) {
+ WmsMerchantDO merchant = merchantService.getMerchant(id);
+ return success(BeanUtils.toBean(merchant, WmsMerchantRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得往来企业分页")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:query')")
+ public CommonResult> getMerchantPage(@Valid WmsMerchantPageReqVO pageReqVO) {
+ PageResult pageResult = merchantService.getMerchantPage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, WmsMerchantRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得往来企业精简列表", description = "主要用于前端下拉")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:query')")
+ public CommonResult> getMerchantSimpleList(@Valid WmsMerchantListReqVO listReqVO) {
+ List list = merchantService.getMerchantList(listReqVO);
+ return success(BeanUtils.toBean(list, WmsMerchantRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出往来企业 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:merchant:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportMerchantExcel(@Valid WmsMerchantPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = merchantService.getMerchantPage(pageReqVO).getList();
+ ExcelUtils.write(response, "往来企业.xls", "数据", WmsMerchantRespVO.class,
+ BeanUtils.toBean(list, WmsMerchantRespVO.class));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantListReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantListReqVO.java
new file mode 100644
index 000000000..287a1bcc7
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantListReqVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 往来企业列表 Request VO")
+@Data
+public class WmsMerchantListReqVO {
+
+ @Schema(description = "往来企业编号", example = "MER001")
+ private String code;
+
+ @Schema(description = "往来企业名称", example = "华为")
+ private String name;
+
+ @Schema(description = "往来企业类型", example = "2")
+ @InEnum(value = WmsMerchantTypeEnum.class, message = "往来企业类型必须是 {value}")
+ private Integer type;
+
+ @Schema(description = "往来企业类型数组", example = "2,3")
+ @InEnum(value = WmsMerchantTypeEnum.class, message = "往来企业类型必须是 {value}")
+ private List types;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantPageReqVO.java
new file mode 100644
index 000000000..eb71ab00b
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantPageReqVO.java
@@ -0,0 +1,33 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 往来企业分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsMerchantPageReqVO extends PageParam {
+
+ @Schema(description = "往来企业编号", example = "MER001")
+ private String code;
+
+ @Schema(description = "往来企业名称", example = "华为")
+ private String name;
+
+ @Schema(description = "往来企业类型", example = "2")
+ @InEnum(value = WmsMerchantTypeEnum.class, message = "往来企业类型必须是 {value}")
+ private Integer type;
+
+ @Schema(description = "往来企业类型数组", example = "2,3")
+ @InEnum(value = WmsMerchantTypeEnum.class, message = "往来企业类型必须是 {value}")
+ private List types;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantRespVO.java
new file mode 100644
index 000000000..c88c8765e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantRespVO.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 往来企业 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsMerchantRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @ExcelProperty("编号")
+ private Long id;
+
+ @Schema(description = "往来企业编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "MER001")
+ @ExcelProperty("往来企业编号")
+ private String code;
+
+ @Schema(description = "往来企业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为")
+ @ExcelProperty("往来企业名称")
+ private String name;
+
+ @Schema(description = "往来企业类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @ExcelProperty(value = "往来企业类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.MERCHANT_TYPE)
+ private Integer type;
+
+ @Schema(description = "级别", example = "A")
+ @ExcelProperty("级别")
+ private String level;
+
+ @Schema(description = "开户行", example = "招商银行")
+ private String bankName;
+
+ @Schema(description = "银行账户", example = "6225888888888888")
+ private String bankAccount;
+
+ @Schema(description = "地址", example = "深圳市南山区")
+ private String address;
+
+ @Schema(description = "手机号", example = "15601691300")
+ private String mobile;
+
+ @Schema(description = "座机号", example = "0755-88888888")
+ private String telephone;
+
+ @Schema(description = "联系人", example = "王五")
+ @ExcelProperty("联系人")
+ private String contact;
+
+ @Schema(description = "Email", example = "wms@example.com")
+ private String email;
+
+ @Schema(description = "备注", example = "备注")
+ @ExcelProperty("备注")
+ private String remark;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantSaveReqVO.java
new file mode 100644
index 000000000..5803a1d32
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantSaveReqVO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.merchant.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 往来企业创建/更新 Request VO")
+@Data
+public class WmsMerchantSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "往来企业编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "MER001")
+ @NotBlank(message = "往来企业编号不能为空")
+ @Size(max = 20, message = "往来企业编号长度不能超过 20 个字符")
+ private String code;
+
+ @Schema(description = "往来企业名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为")
+ @NotBlank(message = "往来企业名称不能为空")
+ @Size(max = 60, message = "往来企业名称长度不能超过 60 个字符")
+ private String name;
+
+ @Schema(description = "往来企业类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "往来企业类型不能为空")
+ @InEnum(value = WmsMerchantTypeEnum.class, message = "往来企业类型必须是 {value}")
+ private Integer type;
+
+ @Schema(description = "级别", example = "A")
+ @Size(max = 10, message = "级别长度不能超过 10 个字符")
+ private String level;
+
+ @Schema(description = "开户行", example = "招商银行")
+ @Size(max = 255, message = "开户行长度不能超过 255 个字符")
+ private String bankName;
+
+ @Schema(description = "银行账户", example = "6225888888888888")
+ @Size(max = 40, message = "银行账户长度不能超过 40 个字符")
+ private String bankAccount;
+
+ @Schema(description = "地址", example = "深圳市南山区")
+ @Size(max = 200, message = "地址长度不能超过 200 个字符")
+ private String address;
+
+ @Schema(description = "手机号", example = "15601691300")
+ @Size(max = 13, message = "手机号长度不能超过 13 个字符")
+ private String mobile;
+
+ @Schema(description = "座机号", example = "0755-88888888")
+ @Size(max = 13, message = "座机号长度不能超过 13 个字符")
+ private String telephone;
+
+ @Schema(description = "联系人", example = "王五")
+ @Size(max = 30, message = "联系人长度不能超过 30 个字符")
+ private String contact;
+
+ @Schema(description = "Email", example = "wms@example.com")
+ @Size(max = 50, message = "Email 长度不能超过 50 个字符")
+ private String email;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/WmsWarehouseController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/WmsWarehouseController.java
new file mode 100644
index 000000000..fcb198137
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/WmsWarehouseController.java
@@ -0,0 +1,100 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.warehouse;
+
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo.WmsWarehousePageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo.WmsWarehouseRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo.WmsWarehouseSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - WMS 仓库")
+@RestController
+@RequestMapping("/wms/warehouse")
+@Validated
+public class WmsWarehouseController {
+
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建仓库")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:create')")
+ public CommonResult createWarehouse(@Valid @RequestBody WmsWarehouseSaveReqVO createReqVO) {
+ return success(warehouseService.createWarehouse(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新仓库")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:update')")
+ public CommonResult updateWarehouse(@Valid @RequestBody WmsWarehouseSaveReqVO updateReqVO) {
+ warehouseService.updateWarehouse(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除仓库")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:delete')")
+ public CommonResult deleteWarehouse(@RequestParam("id") Long id) {
+ warehouseService.deleteWarehouse(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得仓库")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:query')")
+ public CommonResult getWarehouse(@RequestParam("id") Long id) {
+ WmsWarehouseDO warehouse = warehouseService.getWarehouse(id);
+ return success(BeanUtils.toBean(warehouse, WmsWarehouseRespVO.class));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得仓库分页")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:query')")
+ public CommonResult> getWarehousePage(@Valid WmsWarehousePageReqVO pageReqVO) {
+ PageResult pageResult = warehouseService.getWarehousePage(pageReqVO);
+ return success(BeanUtils.toBean(pageResult, WmsWarehouseRespVO.class));
+ }
+
+ @GetMapping("/simple-list")
+ @Operation(summary = "获得仓库精简列表", description = "主要用于前端下拉")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:query')")
+ public CommonResult> getWarehouseSimpleList() {
+ List list = warehouseService.getWarehouseList();
+ return success(BeanUtils.toBean(list, WmsWarehouseRespVO.class));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出仓库 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:warehouse:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportWarehouseExcel(@Valid WmsWarehousePageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = warehouseService.getWarehousePage(pageReqVO).getList();
+ ExcelUtils.write(response, "仓库.xls", "数据", WmsWarehouseRespVO.class,
+ BeanUtils.toBean(list, WmsWarehouseRespVO.class));
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehousePageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehousePageReqVO.java
new file mode 100644
index 000000000..43fcf5ca6
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehousePageReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - WMS 仓库分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsWarehousePageReqVO extends PageParam {
+
+ @Schema(description = "仓库编号", example = "WH001")
+ private String code;
+
+ @Schema(description = "仓库名称", example = "原料仓")
+ private String name;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseRespVO.java
new file mode 100644
index 000000000..67c16bf95
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseRespVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 仓库 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsWarehouseRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @ExcelProperty("编号")
+ private Long id;
+
+ @Schema(description = "仓库编号", example = "WH001")
+ @ExcelProperty("仓库编号")
+ private String code;
+
+ @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原料仓")
+ @ExcelProperty("仓库名称")
+ private String name;
+
+ @Schema(description = "备注", example = "备注")
+ @ExcelProperty("备注")
+ private String remark;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @ExcelProperty("排序")
+ private Integer sort;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseSaveReqVO.java
new file mode 100644
index 000000000..cb2da871b
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseSaveReqVO.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.wms.controller.admin.md.warehouse.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+@Schema(description = "管理后台 - WMS 仓库新增/修改 Request VO")
+@Data
+public class WmsWarehouseSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "WH001")
+ @NotEmpty(message = "仓库编号不能为空")
+ @Size(max = 20, message = "仓库编号长度不能超过 20 个字符")
+ private String code;
+
+ @Schema(description = "仓库名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "原料仓")
+ @NotEmpty(message = "仓库名称不能为空")
+ private String name;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "排序不能为空")
+ private Integer sort;
+
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java
new file mode 100644
index 000000000..9c0cd0944
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java
@@ -0,0 +1,198 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order.WmsCheckOrderSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService;
+import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - WMS 盘库单")
+@RestController
+@RequestMapping("/wms/check-order")
+@Validated
+public class WmsCheckOrderController {
+
+ @Resource
+ private WmsCheckOrderService checkOrderService;
+ @Resource
+ private WmsCheckOrderDetailService checkOrderDetailService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建盘库单")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:create')")
+ public CommonResult createCheckOrder(@Valid @RequestBody WmsCheckOrderSaveReqVO createReqVO) {
+ return success(checkOrderService.createCheckOrder(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新盘库单")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:update')")
+ public CommonResult updateCheckOrder(@Valid @RequestBody WmsCheckOrderSaveReqVO updateReqVO) {
+ checkOrderService.updateCheckOrder(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除盘库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:check-order:delete')")
+ public CommonResult deleteCheckOrder(@RequestParam("id") Long id) {
+ checkOrderService.deleteCheckOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/complete")
+ @Operation(summary = "完成盘库")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:check-order:complete')")
+ public CommonResult completeCheckOrder(@RequestParam("id") Long id) {
+ checkOrderService.completeCheckOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/cancel")
+ @Operation(summary = "作废盘库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:check-order:cancel')")
+ public CommonResult cancelCheckOrder(@RequestParam("id") Long id) {
+ checkOrderService.cancelCheckOrder(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得盘库单")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
+ public CommonResult getCheckOrder(@RequestParam("id") Long id) {
+ WmsCheckOrderDO order = checkOrderService.getCheckOrder(id);
+ if (order == null) {
+ return success(null);
+ }
+ // 获得盘库单的明细列表
+ List detailList = checkOrderDetailService.getCheckOrderDetailList(id);
+ // 拼接结果返回
+ WmsCheckOrderRespVO respVO = buildCheckOrderRespVO(order)
+ .setDetails(buildCheckOrderDetailRespVOList(detailList));
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得盘库单分页")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
+ public CommonResult> getCheckOrderPage(@Valid WmsCheckOrderPageReqVO pageReqVO) {
+ PageResult pageResult = checkOrderService.getCheckOrderPage(pageReqVO);
+ return success(new PageResult<>(buildCheckOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出盘库单 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportCheckOrderExcel(@Valid WmsCheckOrderPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = checkOrderService.getCheckOrderPage(pageReqVO).getList();
+ ExcelUtils.write(response, "盘库单.xls", "数据", WmsCheckOrderRespVO.class,
+ buildCheckOrderRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private WmsCheckOrderRespVO buildCheckOrderRespVO(WmsCheckOrderDO order) {
+ if (order == null) {
+ return null;
+ }
+ List list = buildCheckOrderRespVOList(Collections.singletonList(order));
+ return CollUtil.getFirst(list);
+ }
+
+ private List buildCheckOrderRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的仓库、用户等数据
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSet(list, WmsCheckOrderDO::getWarehouseId));
+ Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
+ order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsCheckOrderRespVO.class, vo -> {
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
+ });
+ }
+
+ private Long parseUserId(String userId) {
+ return NumberUtil.parseLong(userId, null);
+ }
+
+ private List buildCheckOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商品、SKU、仓库等数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsCheckOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsCheckOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsCheckOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java
new file mode 100644
index 000000000..25198254f
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.check.WmsCheckOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.check.WmsCheckOrderDetailService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - WMS 盘库单明细")
+@RestController
+@RequestMapping("/wms/check-order-detail")
+@Validated
+public class WmsCheckOrderDetailController {
+
+ @Resource
+ private WmsCheckOrderDetailService checkOrderDetailService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/list-by-order-id")
+ @Operation(summary = "获得盘库单明细列表")
+ @Parameter(name = "orderId", description = "盘库单编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:check-order:query')")
+ public CommonResult> getCheckOrderDetailListByOrderId(
+ @RequestParam("orderId") Long orderId) {
+ List list = checkOrderDetailService.getCheckOrderDetailList(orderId);
+ return success(buildCheckOrderDetailRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildCheckOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsCheckOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsCheckOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsCheckOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java
new file mode 100644
index 000000000..399caa3f9
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 盘库单明细 Response VO")
+@Data
+public class WmsCheckOrderDetailRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "盘库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long orderId;
+
+ @Schema(description = "商品编号", example = "2048")
+ private Long itemId;
+
+ @Schema(description = "商品编号", example = "SPU-APPLE")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ private String warehouseName;
+
+ @Schema(description = "库存编号", example = "1024")
+ private Long inventoryId;
+
+ @Schema(description = "入库时间")
+ private LocalDateTime receiptTime;
+
+ @Schema(description = "账面数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ @Schema(description = "实盘数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "98.00")
+ private BigDecimal checkQuantity;
+
+ @Schema(description = "单价", example = "1000.00")
+ private BigDecimal price;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java
new file mode 100644
index 000000000..709ddba9d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 盘库单明细保存 Request VO")
+@Data
+public class WmsCheckOrderDetailSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "SKU 不能为空")
+ private Long skuId;
+
+ @Schema(description = "库存编号", example = "1024")
+ private Long inventoryId;
+
+ @Schema(description = "入库时间")
+ private LocalDateTime receiptTime;
+
+ @Schema(description = "账面数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @NotNull(message = "账面数量不能为空")
+ @DecimalMin(value = "0", message = "账面数量不能小于 0")
+ private BigDecimal quantity;
+
+ @Schema(description = "实盘数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "98.00")
+ @NotNull(message = "实盘数量不能为空")
+ @DecimalMin(value = "0", message = "实盘数量不能小于 0")
+ private BigDecimal checkQuantity;
+
+ @Schema(description = "单价", example = "1000.00")
+ @DecimalMin(value = "0", message = "单价不能小于 0")
+ private BigDecimal price;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java
new file mode 100644
index 000000000..2182fc69b
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java
@@ -0,0 +1,69 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 盘库单分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsCheckOrderPageReqVO extends PageParam {
+
+ @Schema(description = "盘库单号", example = "PK202605110001")
+ private String no;
+
+ @Schema(description = "单据状态", example = "0")
+ @InEnum(WmsOrderStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "仓库编号", example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "单据日期")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] orderTime;
+
+ @Schema(description = "最小盈亏数量", example = "-10.00")
+ private BigDecimal totalQuantityMin;
+
+ @Schema(description = "最大盈亏数量", example = "100.00")
+ private BigDecimal totalQuantityMax;
+
+ @Schema(description = "最小总金额", example = "1.00")
+ private BigDecimal totalPriceMin;
+
+ @Schema(description = "最大总金额", example = "1000.00")
+ private BigDecimal totalPriceMax;
+
+ @Schema(description = "最小实际金额", example = "1.00")
+ private BigDecimal actualPriceMin;
+
+ @Schema(description = "最大实际金额", example = "1000.00")
+ private BigDecimal actualPriceMax;
+
+ @Schema(description = "创建用户", example = "1")
+ private String creator;
+
+ @Schema(description = "更新用户", example = "1")
+ private String updater;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "更新时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] updateTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java
new file mode 100644
index 000000000..962de8235
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java
@@ -0,0 +1,79 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 盘库单 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsCheckOrderRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "盘库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PK202605110001")
+ @ExcelProperty("盘库单号")
+ private String no;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("单据日期")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "盘库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @ExcelProperty(value = "盘库状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.ORDER_STATUS)
+ private Integer status;
+
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ @ExcelProperty("仓库")
+ private String warehouseName;
+
+ @Schema(description = "盈亏数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @ExcelProperty("盈亏数量")
+ private BigDecimal totalQuantity;
+
+ @Schema(description = "总金额(账面金额)", example = "1000.00")
+ @ExcelProperty("总金额")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "实际金额", example = "980.00")
+ @ExcelProperty("实际金额")
+ private BigDecimal actualPrice;
+
+ @Schema(description = "盘库明细")
+ private List details;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "创建者", example = "1")
+ private String creator;
+ @Schema(description = "创建者名称", example = "芋道")
+ private String creatorName;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+ @Schema(description = "更新者", example = "1")
+ private String updater;
+ @Schema(description = "更新者名称", example = "芋道")
+ private String updaterName;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java
new file mode 100644
index 000000000..21660ce87
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.order;
+
+import cn.iocoder.yudao.module.wms.controller.admin.order.check.vo.detail.WmsCheckOrderDetailSaveReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 盘库单保存 Request VO")
+@Data
+public class WmsCheckOrderSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "盘库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "PK202605110001")
+ @NotBlank(message = "盘库单号不能为空")
+ @Size(max = 64, message = "盘库单号长度不能超过 64 个字符")
+ private String no;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "单据日期不能为空")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "仓库不能为空")
+ private Long warehouseId;
+
+ @Schema(description = "盘库明细")
+ @Valid
+ private List details;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java
new file mode 100644
index 000000000..d993392b9
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java
@@ -0,0 +1,206 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order.WmsMovementOrderSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService;
+import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - WMS 移库单")
+@RestController
+@RequestMapping("/wms/movement-order")
+@Validated
+public class WmsMovementOrderController {
+
+ @Resource
+ private WmsMovementOrderService movementOrderService;
+ @Resource
+ private WmsMovementOrderDetailService movementOrderDetailService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建移库单")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:create')")
+ public CommonResult createMovementOrder(@Valid @RequestBody WmsMovementOrderSaveReqVO createReqVO) {
+ return success(movementOrderService.createMovementOrder(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新移库单")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:update')")
+ public CommonResult updateMovementOrder(@Valid @RequestBody WmsMovementOrderSaveReqVO updateReqVO) {
+ movementOrderService.updateMovementOrder(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除移库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:delete')")
+ public CommonResult deleteMovementOrder(@RequestParam("id") Long id) {
+ movementOrderService.deleteMovementOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/complete")
+ @Operation(summary = "完成移库")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:complete')")
+ public CommonResult completeMovementOrder(@RequestParam("id") Long id) {
+ movementOrderService.completeMovementOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/cancel")
+ @Operation(summary = "作废移库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:cancel')")
+ public CommonResult cancelMovementOrder(@RequestParam("id") Long id) {
+ movementOrderService.cancelMovementOrder(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得移库单")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
+ public CommonResult getMovementOrder(@RequestParam("id") Long id) {
+ WmsMovementOrderDO order = movementOrderService.getMovementOrder(id);
+ if (order == null) {
+ return success(null);
+ }
+ // 获得移库单的明细列表
+ List detailList = movementOrderDetailService.getMovementOrderDetailList(id);
+ // 拼接结果返回
+ WmsMovementOrderRespVO respVO = buildMovementOrderRespVO(order)
+ .setDetails(buildMovementOrderDetailRespVOList(detailList));
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得移库单分页")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
+ public CommonResult> getMovementOrderPage(
+ @Valid WmsMovementOrderPageReqVO pageReqVO) {
+ PageResult pageResult = movementOrderService.getMovementOrderPage(pageReqVO);
+ return success(new PageResult<>(buildMovementOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出移库单 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportMovementOrderExcel(@Valid WmsMovementOrderPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = movementOrderService.getMovementOrderPage(pageReqVO).getList();
+ ExcelUtils.write(response, "移库单.xls", "数据", WmsMovementOrderRespVO.class,
+ buildMovementOrderRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private WmsMovementOrderRespVO buildMovementOrderRespVO(WmsMovementOrderDO order) {
+ if (order == null) {
+ return null;
+ }
+ List list = buildMovementOrderRespVOList(Collections.singletonList(order));
+ return CollUtil.getFirst(list);
+ }
+
+ private List buildMovementOrderRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的仓库、用户等数据
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
+ order -> Stream.of(order.getSourceWarehouseId(), order.getTargetWarehouseId())));
+ Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
+ order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsMovementOrderRespVO.class, vo -> {
+ MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
+ warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
+ warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
+ });
+ }
+
+ private Long parseUserId(String userId) {
+ return NumberUtil.parseLong(userId, null);
+ }
+
+ private List buildMovementOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商品、SKU、仓库等数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsMovementOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
+ detail -> Stream.of(detail.getSourceWarehouseId(), detail.getTargetWarehouseId())));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsMovementOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
+ warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
+ warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java
new file mode 100644
index 000000000..092a367fd
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java
@@ -0,0 +1,86 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.movement.WmsMovementOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.movement.WmsMovementOrderDetailService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - WMS 移库单明细")
+@RestController
+@RequestMapping("/wms/movement-order-detail")
+@Validated
+public class WmsMovementOrderDetailController {
+
+ @Resource
+ private WmsMovementOrderDetailService movementOrderDetailService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/list-by-order-id")
+ @Operation(summary = "获得移库单明细列表")
+ @Parameter(name = "orderId", description = "移库单编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:movement-order:query')")
+ public CommonResult> getMovementOrderDetailListByOrderId(
+ @RequestParam("orderId") Long orderId) {
+ List list = movementOrderDetailService.getMovementOrderDetailList(orderId);
+ return success(buildMovementOrderDetailRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildMovementOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsMovementOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSetByFlatMap(list,
+ detail -> Stream.of(detail.getSourceWarehouseId(), detail.getTargetWarehouseId())));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsMovementOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getSourceWarehouseId(),
+ warehouse -> vo.setSourceWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(warehouseMap, vo.getTargetWarehouseId(),
+ warehouse -> vo.setTargetWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java
new file mode 100644
index 000000000..513653460
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java
@@ -0,0 +1,64 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 移库单明细 Response VO")
+@Data
+public class WmsMovementOrderDetailRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "移库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long orderId;
+
+ @Schema(description = "商品编号", example = "2048")
+ private Long itemId;
+
+ @Schema(description = "商品编号", example = "SPU-APPLE")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long sourceWarehouseId;
+
+ @Schema(description = "来源仓库名称", example = "北京仓")
+ private String sourceWarehouseName;
+
+ @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long targetWarehouseId;
+
+ @Schema(description = "目标仓库名称", example = "上海仓")
+ private String targetWarehouseName;
+
+ @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "100.00")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1000.00")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java
new file mode 100644
index 000000000..28b412edf
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - WMS 移库单明细保存 Request VO")
+@Data
+public class WmsMovementOrderDetailSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "SKU 不能为空")
+ private Long skuId;
+
+ @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @NotNull(message = "移库数量不能为空")
+ @DecimalMin(value = "0", inclusive = false, message = "移库数量必须大于 0")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "100.00")
+ @DecimalMin(value = "0", message = "单价不能小于 0")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1000.00")
+ @DecimalMin(value = "0", message = "行金额不能小于 0")
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java
new file mode 100644
index 000000000..c59bc113a
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java
@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 移库单分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsMovementOrderPageReqVO extends PageParam {
+
+ @Schema(description = "移库单号", example = "YK202605110001")
+ private String no;
+
+ @Schema(description = "单据状态", example = "0")
+ @InEnum(WmsOrderStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "来源仓库编号", example = "1024")
+ private Long sourceWarehouseId;
+
+ @Schema(description = "目标仓库编号", example = "2048")
+ private Long targetWarehouseId;
+
+ @Schema(description = "单据日期")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] orderTime;
+
+ @Schema(description = "最小数量", example = "1.00")
+ private BigDecimal totalQuantityMin;
+
+ @Schema(description = "最大数量", example = "100.00")
+ private BigDecimal totalQuantityMax;
+
+ @Schema(description = "最小总金额", example = "1.00")
+ private BigDecimal totalPriceMin;
+
+ @Schema(description = "最大总金额", example = "1000.00")
+ private BigDecimal totalPriceMax;
+
+ @Schema(description = "创建用户", example = "1")
+ private String creator;
+
+ @Schema(description = "更新用户", example = "1")
+ private String updater;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "更新时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] updateTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java
new file mode 100644
index 000000000..ecad02e05
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 移库单 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsMovementOrderRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "移库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "YK202605110001")
+ @ExcelProperty("移库单号")
+ private String no;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("单据日期")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "移库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @ExcelProperty(value = "移库状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.ORDER_STATUS)
+ private Integer status;
+
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+ @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long sourceWarehouseId;
+
+ @Schema(description = "来源仓库名称", example = "北京仓")
+ @ExcelProperty("来源仓库")
+ private String sourceWarehouseName;
+
+ @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long targetWarehouseId;
+
+ @Schema(description = "目标仓库名称", example = "上海仓")
+ @ExcelProperty("目标仓库")
+ private String targetWarehouseName;
+
+ @Schema(description = "移库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @ExcelProperty("移库数量")
+ private BigDecimal totalQuantity;
+
+ @Schema(description = "总金额", example = "1000.00")
+ @ExcelProperty("总金额")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "移库明细")
+ private List details;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "创建者", example = "1")
+ private String creator;
+ @Schema(description = "创建者名称", example = "芋道")
+ private String creatorName;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+ @Schema(description = "更新者", example = "1")
+ private String updater;
+ @Schema(description = "更新者名称", example = "芋道")
+ private String updaterName;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java
new file mode 100644
index 000000000..982d30dff
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.order;
+
+import cn.iocoder.yudao.module.wms.controller.admin.order.movement.vo.detail.WmsMovementOrderDetailSaveReqVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 移库单保存 Request VO")
+@Data
+public class WmsMovementOrderSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "移库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "YK202605110001")
+ @NotBlank(message = "移库单号不能为空")
+ @Size(max = 64, message = "移库单号长度不能超过 64 个字符")
+ private String no;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "单据日期不能为空")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+ @Schema(description = "来源仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "来源仓库不能为空")
+ private Long sourceWarehouseId;
+
+ @Schema(description = "目标仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "目标仓库不能为空")
+ private Long targetWarehouseId;
+
+ @Schema(description = "移库明细")
+ @Valid
+ private List details;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java
new file mode 100644
index 000000000..c1a2fe6d4
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java
@@ -0,0 +1,204 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order.WmsReceiptOrderSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderDetailService;
+import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - WMS 入库单")
+@RestController
+@RequestMapping("/wms/receipt-order")
+@Validated
+public class WmsReceiptOrderController {
+
+ @Resource
+ private WmsReceiptOrderService receiptOrderService;
+ @Resource
+ private WmsReceiptOrderDetailService receiptOrderDetailService;
+ @Resource
+ private WmsMerchantService merchantService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建入库单")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:create')")
+ public CommonResult createReceiptOrder(@Valid @RequestBody WmsReceiptOrderSaveReqVO createReqVO) {
+ return success(receiptOrderService.createReceiptOrder(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新入库单")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:update')")
+ public CommonResult updateReceiptOrder(@Valid @RequestBody WmsReceiptOrderSaveReqVO updateReqVO) {
+ receiptOrderService.updateReceiptOrder(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除入库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:delete')")
+ public CommonResult deleteReceiptOrder(@RequestParam("id") Long id) {
+ receiptOrderService.deleteReceiptOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/complete")
+ @Operation(summary = "完成入库")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:complete')")
+ public CommonResult completeReceiptOrder(@RequestParam("id") Long id) {
+ receiptOrderService.completeReceiptOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/cancel")
+ @Operation(summary = "作废入库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:cancel')")
+ public CommonResult cancelReceiptOrder(@RequestParam("id") Long id) {
+ receiptOrderService.cancelReceiptOrder(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得入库单")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
+ public CommonResult getReceiptOrder(@RequestParam("id") Long id) {
+ WmsReceiptOrderDO order = receiptOrderService.getReceiptOrder(id);
+ if (order == null) {
+ return success(null);
+ }
+ // 获得入库单的明细列表
+ List detailList = receiptOrderDetailService.getReceiptOrderDetailList(id);
+ // 拼接结果返回
+ WmsReceiptOrderRespVO respVO = buildReceiptOrderRespVO(order)
+ .setDetails(buildReceiptOrderDetailRespVOList(detailList));
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得入库单分页")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
+ public CommonResult> getReceiptOrderPage(@Valid WmsReceiptOrderPageReqVO pageReqVO) {
+ PageResult pageResult = receiptOrderService.getReceiptOrderPage(pageReqVO);
+ return success(new PageResult<>(buildReceiptOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出入库单 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportReceiptOrderExcel(@Valid WmsReceiptOrderPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = receiptOrderService.getReceiptOrderPage(pageReqVO).getList();
+ ExcelUtils.write(response, "入库单.xls", "数据", WmsReceiptOrderRespVO.class,
+ buildReceiptOrderRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private WmsReceiptOrderRespVO buildReceiptOrderRespVO(WmsReceiptOrderDO order) {
+ if (order == null) {
+ return null;
+ }
+ List list = buildReceiptOrderRespVOList(Collections.singletonList(order));
+ return CollUtil.getFirst(list);
+ }
+
+ private List buildReceiptOrderRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商户、仓库、用户等数据
+ Map merchantMap = merchantService.getMerchantMap(convertSet(list, WmsReceiptOrderDO::getMerchantId));
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSet(list, WmsReceiptOrderDO::getWarehouseId));
+ Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
+ order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsReceiptOrderRespVO.class, vo -> {
+ MapUtils.findAndThen(merchantMap, vo.getMerchantId(), merchant -> vo.setMerchantName(merchant.getName()));
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
+ });
+ }
+
+ private Long parseUserId(String userId) {
+ return NumberUtil.parseLong(userId, null);
+ }
+
+ private List buildReceiptOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商品、SKU、仓库等数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsReceiptOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsReceiptOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsReceiptOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java
new file mode 100644
index 000000000..d443feb2f
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt.WmsReceiptOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.receipt.WmsReceiptOrderDetailService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - WMS 入库单明细")
+@RestController
+@RequestMapping("/wms/receipt-order-detail")
+@Validated
+public class WmsReceiptOrderDetailController {
+
+ @Resource
+ private WmsReceiptOrderDetailService receiptOrderDetailService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/list-by-order-id")
+ @Operation(summary = "获得入库单明细列表")
+ @Parameter(name = "orderId", description = "入库单编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:receipt-order:query')")
+ public CommonResult> getReceiptOrderDetailListByOrderId(
+ @RequestParam("orderId") Long orderId) {
+ List list = receiptOrderDetailService.getReceiptOrderDetailList(orderId);
+ return success(buildReceiptOrderDetailRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildReceiptOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsReceiptOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsReceiptOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsReceiptOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java
new file mode 100644
index 000000000..4c72b9324
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 入库单明细 Response VO")
+@Data
+public class WmsReceiptOrderDetailRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "入库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long orderId;
+
+ @Schema(description = "商品编号", example = "2048")
+ private Long itemId;
+
+ @Schema(description = "商品编号", example = "SPU-APPLE")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ private String warehouseName;
+
+ @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "1000.00")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1500.00")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java
new file mode 100644
index 000000000..a74cc905d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - WMS 入库单明细保存 Request VO")
+@Data
+public class WmsReceiptOrderDetailSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "SKU 不能为空")
+ private Long skuId;
+
+ @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @NotNull(message = "入库数量不能为空")
+ @DecimalMin(value = "0", inclusive = false, message = "入库数量必须大于 0")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "1000.00")
+ @DecimalMin(value = "0", message = "单价不能小于 0")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1500.00")
+ @DecimalMin(value = "0", message = "行金额不能小于 0")
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java
new file mode 100644
index 000000000..351d15004
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java
@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 入库单分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsReceiptOrderPageReqVO extends PageParam {
+
+ @Schema(description = "入库单号", example = "RK202605110001")
+ private String no;
+
+ @Schema(description = "单据状态", example = "0")
+ @InEnum(WmsOrderStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "仓库编号", example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "供应商编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "单据日期")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] orderTime;
+
+ @Schema(description = "最小数量", example = "1.00")
+ private BigDecimal totalQuantityMin;
+
+ @Schema(description = "最大数量", example = "100.00")
+ private BigDecimal totalQuantityMax;
+
+ @Schema(description = "最小总金额", example = "1.00")
+ private BigDecimal totalPriceMin;
+
+ @Schema(description = "最大总金额", example = "1000.00")
+ private BigDecimal totalPriceMax;
+
+ @Schema(description = "入库类型", example = "101")
+ @InEnum(WmsReceiptOrderTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "业务单号", example = "PO202605110001")
+ private String bizOrderNo;
+
+ @Schema(description = "创建用户", example = "1")
+ private String creator;
+
+ @Schema(description = "更新用户", example = "1")
+ private String updater;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "更新时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] updateTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java
new file mode 100644
index 000000000..24d3b0449
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail.WmsReceiptOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 入库单 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsReceiptOrderRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "RK202605110001")
+ @ExcelProperty("入库单号")
+ private String no;
+
+ @Schema(description = "入库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "101")
+ @ExcelProperty(value = "入库类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.RECEIPT_ORDER_TYPE)
+ private Integer type;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("单据日期")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "入库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @ExcelProperty(value = "入库状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.ORDER_STATUS)
+ private Integer status;
+
+ @Schema(description = "业务单号", example = "PO202605110001")
+ @ExcelProperty("业务单号")
+ private String bizOrderNo;
+
+ @Schema(description = "供应商编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "供应商名称", example = "某某公司")
+ @ExcelProperty("供应商")
+ private String merchantName;
+
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ @ExcelProperty("仓库")
+ private String warehouseName;
+
+ @Schema(description = "入库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @ExcelProperty("入库数量")
+ private BigDecimal totalQuantity;
+
+ @Schema(description = "总金额", example = "1000.00")
+ @ExcelProperty("总金额")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "入库明细")
+ private List details;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "创建者", example = "1")
+ private String creator;
+ @Schema(description = "创建者名称", example = "芋道")
+ private String creatorName;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+ @Schema(description = "更新者", example = "1")
+ private String updater;
+ @Schema(description = "更新者名称", example = "芋道")
+ private String updaterName;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java
new file mode 100644
index 000000000..b8619fc41
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.order;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.controller.admin.order.receipt.vo.detail.WmsReceiptOrderDetailSaveReqVO;
+import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 入库单保存 Request VO")
+@Data
+public class WmsReceiptOrderSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "入库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "RK202605110001")
+ @NotBlank(message = "入库单号不能为空")
+ @Size(max = 64, message = "入库单号长度不能超过 64 个字符")
+ private String no;
+
+ @Schema(description = "入库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "101")
+ @NotNull(message = "入库类型不能为空")
+ @InEnum(WmsReceiptOrderTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "单据日期不能为空")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "业务单号", example = "PO202605110001")
+ @Size(max = 64, message = "业务单号长度不能超过 64 个字符")
+ private String bizOrderNo;
+
+ @Schema(description = "供应商编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "仓库不能为空")
+ private Long warehouseId;
+
+ @Schema(description = "入库明细")
+ @Valid
+ private List details;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderController.java
new file mode 100644
index 000000000..65e9153fb
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderController.java
@@ -0,0 +1,204 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
+import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail.WmsShipmentOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order.WmsShipmentOrderPageReqVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order.WmsShipmentOrderRespVO;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order.WmsShipmentOrderSaveReqVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.shipment.WmsShipmentOrderDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.shipment.WmsShipmentOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.merchant.WmsMerchantService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderDetailService;
+import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.Valid;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSetByFlatMap;
+
+@Tag(name = "管理后台 - WMS 出库单")
+@RestController
+@RequestMapping("/wms/shipment-order")
+@Validated
+public class WmsShipmentOrderController {
+
+ @Resource
+ private WmsShipmentOrderService shipmentOrderService;
+ @Resource
+ private WmsShipmentOrderDetailService shipmentOrderDetailService;
+ @Resource
+ private WmsMerchantService merchantService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+
+ @Resource
+ private AdminUserApi adminUserApi;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建出库单")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:create')")
+ public CommonResult createShipmentOrder(@Valid @RequestBody WmsShipmentOrderSaveReqVO createReqVO) {
+ return success(shipmentOrderService.createShipmentOrder(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新出库单")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:update')")
+ public CommonResult updateShipmentOrder(@Valid @RequestBody WmsShipmentOrderSaveReqVO updateReqVO) {
+ shipmentOrderService.updateShipmentOrder(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除出库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:delete')")
+ public CommonResult deleteShipmentOrder(@RequestParam("id") Long id) {
+ shipmentOrderService.deleteShipmentOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/complete")
+ @Operation(summary = "完成出库")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:complete')")
+ public CommonResult completeShipmentOrder(@RequestParam("id") Long id) {
+ shipmentOrderService.completeShipmentOrder(id);
+ return success(true);
+ }
+
+ @PutMapping("/cancel")
+ @Operation(summary = "作废出库单")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:cancel')")
+ public CommonResult cancelShipmentOrder(@RequestParam("id") Long id) {
+ shipmentOrderService.cancelShipmentOrder(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得出库单")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:query')")
+ public CommonResult getShipmentOrder(@RequestParam("id") Long id) {
+ WmsShipmentOrderDO order = shipmentOrderService.getShipmentOrder(id);
+ if (order == null) {
+ return success(null);
+ }
+ // 获得出库单的明细列表
+ List detailList = shipmentOrderDetailService.getShipmentOrderDetailList(id);
+ // 拼接结果返回
+ WmsShipmentOrderRespVO respVO = buildShipmentOrderRespVO(order)
+ .setDetails(buildShipmentOrderDetailRespVOList(detailList));
+ return success(respVO);
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得出库单分页")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:query')")
+ public CommonResult> getShipmentOrderPage(@Valid WmsShipmentOrderPageReqVO pageReqVO) {
+ PageResult pageResult = shipmentOrderService.getShipmentOrderPage(pageReqVO);
+ return success(new PageResult<>(buildShipmentOrderRespVOList(pageResult.getList()), pageResult.getTotal()));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出出库单 Excel")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:export')")
+ @ApiAccessLog(operateType = EXPORT)
+ public void exportShipmentOrderExcel(@Valid WmsShipmentOrderPageReqVO pageReqVO,
+ HttpServletResponse response) throws IOException {
+ pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+ List list = shipmentOrderService.getShipmentOrderPage(pageReqVO).getList();
+ ExcelUtils.write(response, "出库单.xls", "数据", WmsShipmentOrderRespVO.class,
+ buildShipmentOrderRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private WmsShipmentOrderRespVO buildShipmentOrderRespVO(WmsShipmentOrderDO order) {
+ if (order == null) {
+ return null;
+ }
+ List list = buildShipmentOrderRespVOList(Collections.singletonList(order));
+ return CollUtil.getFirst(list);
+ }
+
+ private List buildShipmentOrderRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商户、仓库、用户等数据
+ Map merchantMap = merchantService.getMerchantMap(convertSet(list, WmsShipmentOrderDO::getMerchantId));
+ Map warehouseMap = warehouseService.getWarehouseMap(convertSet(list, WmsShipmentOrderDO::getWarehouseId));
+ Map userMap = adminUserApi.getUserMap(convertSetByFlatMap(list,
+ order -> Stream.of(parseUserId(order.getCreator()), parseUserId(order.getUpdater()))));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsShipmentOrderRespVO.class, vo -> {
+ MapUtils.findAndThen(merchantMap, vo.getMerchantId(), merchant -> vo.setMerchantName(merchant.getName()));
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getCreator()), user -> vo.setCreatorName(user.getNickname()));
+ MapUtils.findAndThen(userMap, parseUserId(vo.getUpdater()), user -> vo.setUpdaterName(user.getNickname()));
+ });
+ }
+
+ private Long parseUserId(String userId) {
+ return NumberUtil.parseLong(userId, null);
+ }
+
+ private List buildShipmentOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 获取相关的商品、SKU、仓库等数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsShipmentOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsShipmentOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsShipmentOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderDetailController.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderDetailController.java
new file mode 100644
index 000000000..f9cd14dd7
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderDetailController.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail.WmsShipmentOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.order.shipment.WmsShipmentOrderDetailDO;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
+import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
+import cn.iocoder.yudao.module.wms.service.md.warehouse.WmsWarehouseService;
+import cn.iocoder.yudao.module.wms.service.order.shipment.WmsShipmentOrderDetailService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - WMS 出库单明细")
+@RestController
+@RequestMapping("/wms/shipment-order-detail")
+@Validated
+public class WmsShipmentOrderDetailController {
+
+ @Resource
+ private WmsShipmentOrderDetailService shipmentOrderDetailService;
+ @Resource
+ private WmsItemService itemService;
+ @Resource
+ private WmsItemSkuService itemSkuService;
+ @Resource
+ private WmsWarehouseService warehouseService;
+
+ @GetMapping("/list-by-order-id")
+ @Operation(summary = "获得出库单明细列表")
+ @Parameter(name = "orderId", description = "出库单编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('wms:shipment-order:query')")
+ public CommonResult> getShipmentOrderDetailListByOrderId(
+ @RequestParam("orderId") Long orderId) {
+ List list = shipmentOrderDetailService.getShipmentOrderDetailList(orderId);
+ return success(buildShipmentOrderDetailRespVOList(list));
+ }
+
+ // ==================== 拼接 VO ====================
+
+ private List buildShipmentOrderDetailRespVOList(List list) {
+ if (CollUtil.isEmpty(list)) {
+ return Collections.emptyList();
+ }
+ // 查询关联数据
+ Map skuMap = itemSkuService.getItemSkuMap(convertSet(list, WmsShipmentOrderDetailDO::getSkuId));
+ Map itemMap = itemService.getItemMap(convertSet(skuMap.values(), WmsItemSkuDO::getItemId));
+ Map warehouseMap = warehouseService.getWarehouseMap(
+ convertSet(list, WmsShipmentOrderDetailDO::getWarehouseId));
+ // 拼接数据
+ return BeanUtils.toBean(list, WmsShipmentOrderDetailRespVO.class, vo -> {
+ MapUtils.findAndThen(skuMap, vo.getSkuId(), sku -> {
+ vo.setSkuCode(sku.getCode()).setSkuName(sku.getName()).setItemId(sku.getItemId());
+ MapUtils.findAndThen(itemMap, sku.getItemId(), item -> vo.setItemCode(item.getCode())
+ .setItemName(item.getName()).setUnit(item.getUnit()));
+ });
+ MapUtils.findAndThen(warehouseMap, vo.getWarehouseId(), warehouse -> vo.setWarehouseName(warehouse.getName()));
+ });
+ }
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailRespVO.java
new file mode 100644
index 000000000..80e9538c1
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailRespVO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - WMS 出库单明细 Response VO")
+@Data
+public class WmsShipmentOrderDetailRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "出库单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long orderId;
+
+ @Schema(description = "商品编号", example = "2048")
+ private Long itemId;
+
+ @Schema(description = "商品编号", example = "SPU-APPLE")
+ private String itemCode;
+
+ @Schema(description = "商品名称", example = "红富士苹果")
+ private String itemName;
+
+ @Schema(description = "商品单位", example = "箱")
+ private String unit;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ private Long skuId;
+
+ @Schema(description = "规格编号", example = "SKU-APPLE-10KG")
+ private String skuCode;
+
+ @Schema(description = "规格名称", example = "10kg 箱装")
+ private String skuName;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ private String warehouseName;
+
+ @Schema(description = "出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "100.00")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1000.00")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailSaveReqVO.java
new file mode 100644
index 000000000..be8a8baeb
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailSaveReqVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.math.BigDecimal;
+
+@Schema(description = "管理后台 - WMS 出库单明细保存 Request VO")
+@Data
+public class WmsShipmentOrderDetailSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2048")
+ @NotNull(message = "SKU 不能为空")
+ private Long skuId;
+
+ @Schema(description = "出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @NotNull(message = "出库数量不能为空")
+ @DecimalMin(value = "0", inclusive = false, message = "出库数量必须大于 0")
+ private BigDecimal quantity;
+
+ @Schema(description = "单价", example = "100.00")
+ @DecimalMin(value = "0", message = "单价不能小于 0")
+ private BigDecimal price;
+
+ @Schema(description = "行金额", example = "1000.00")
+ @DecimalMin(value = "0", message = "行金额不能小于 0")
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderPageReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderPageReqVO.java
new file mode 100644
index 000000000..2a9f058ba
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderPageReqVO.java
@@ -0,0 +1,74 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsOrderStatusEnum;
+import cn.iocoder.yudao.module.wms.enums.order.WmsShipmentOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - WMS 出库单分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class WmsShipmentOrderPageReqVO extends PageParam {
+
+ @Schema(description = "出库单号", example = "CK202605110001")
+ private String no;
+
+ @Schema(description = "单据状态", example = "0")
+ @InEnum(WmsOrderStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "仓库编号", example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "客户编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "单据日期")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] orderTime;
+
+ @Schema(description = "最小数量", example = "1.00")
+ private BigDecimal totalQuantityMin;
+
+ @Schema(description = "最大数量", example = "100.00")
+ private BigDecimal totalQuantityMax;
+
+ @Schema(description = "最小总金额", example = "1.00")
+ private BigDecimal totalPriceMin;
+
+ @Schema(description = "最大总金额", example = "1000.00")
+ private BigDecimal totalPriceMax;
+
+ @Schema(description = "出库类型", example = "201")
+ @InEnum(WmsShipmentOrderTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "业务单号", example = "SO202605110001")
+ private String bizOrderNo;
+
+ @Schema(description = "创建用户", example = "1")
+ private String creator;
+
+ @Schema(description = "更新用户", example = "1")
+ private String updater;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "更新时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] updateTime;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderRespVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderRespVO.java
new file mode 100644
index 000000000..b391c1d5e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderRespVO.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail.WmsShipmentOrderDetailRespVO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 出库单 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class WmsShipmentOrderRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "CK202605110001")
+ @ExcelProperty("出库单号")
+ private String no;
+
+ @Schema(description = "出库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "201")
+ @ExcelProperty(value = "出库类型", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.SHIPMENT_ORDER_TYPE)
+ private Integer type;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("单据日期")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "出库状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @ExcelProperty(value = "出库状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.ORDER_STATUS)
+ private Integer status;
+
+ @Schema(description = "业务单号", example = "SO202605110001")
+ @ExcelProperty("业务单号")
+ private String bizOrderNo;
+
+ @Schema(description = "客户编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "客户名称", example = "某某公司")
+ @ExcelProperty("客户")
+ private String merchantName;
+
+ @Schema(description = "备注", example = "备注")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long warehouseId;
+
+ @Schema(description = "仓库名称", example = "北京仓")
+ @ExcelProperty("仓库")
+ private String warehouseName;
+
+ @Schema(description = "出库数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "100.00")
+ @ExcelProperty("出库数量")
+ private BigDecimal totalQuantity;
+
+ @Schema(description = "总金额", example = "1000.00")
+ @ExcelProperty("总金额")
+ private BigDecimal totalPrice;
+
+ @Schema(description = "出库明细")
+ private List details;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+ @Schema(description = "创建者", example = "1")
+ private String creator;
+ @Schema(description = "创建者名称", example = "芋道")
+ private String creatorName;
+
+ @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime updateTime;
+
+ @Schema(description = "更新者", example = "1")
+ private String updater;
+ @Schema(description = "更新者名称", example = "芋道")
+ private String updaterName;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderSaveReqVO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderSaveReqVO.java
new file mode 100644
index 000000000..232b92dc0
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderSaveReqVO.java
@@ -0,0 +1,56 @@
+package cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.order;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.wms.controller.admin.order.shipment.vo.detail.WmsShipmentOrderDetailSaveReqVO;
+import cn.iocoder.yudao.module.wms.enums.order.WmsShipmentOrderTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - WMS 出库单保存 Request VO")
+@Data
+public class WmsShipmentOrderSaveReqVO {
+
+ @Schema(description = "编号", example = "1024")
+ private Long id;
+
+ @Schema(description = "出库单号", requiredMode = Schema.RequiredMode.REQUIRED, example = "CK202605110001")
+ @NotBlank(message = "出库单号不能为空")
+ @Size(max = 64, message = "出库单号长度不能超过 64 个字符")
+ private String no;
+
+ @Schema(description = "出库类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "201")
+ @NotNull(message = "出库类型不能为空")
+ @InEnum(WmsShipmentOrderTypeEnum.class)
+ private Integer type;
+
+ @Schema(description = "单据日期", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "单据日期不能为空")
+ private LocalDateTime orderTime;
+
+ @Schema(description = "业务单号", example = "SO202605110001")
+ @Size(max = 64, message = "业务单号长度不能超过 64 个字符")
+ private String bizOrderNo;
+
+ @Schema(description = "客户编号", example = "1024")
+ private Long merchantId;
+
+ @Schema(description = "备注", example = "备注")
+ @Size(max = 255, message = "备注长度不能超过 255 个字符")
+ private String remark;
+
+ @Schema(description = "仓库编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "仓库不能为空")
+ private Long warehouseId;
+
+ @Schema(description = "出库明细")
+ @Valid
+ private List details;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/package-info.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/package-info.java
new file mode 100644
index 000000000..7f2a55f59
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * WMS 管理后台 API
+ */
+package cn.iocoder.yudao.module.wms.controller.admin;
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/package-info.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/package-info.java
new file mode 100644
index 000000000..c75d9df62
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/controller/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * 提供 RESTful API 给前端:
+ * 1. admin 包:提供给管理后台 yudao-ui-admin 前端项目
+ * 2. app 包:提供给用户 APP yudao-ui-app 前端项目,它的 Controller 和 VO 都要添加 App 前缀,用于和管理后台进行区分
+ */
+package cn.iocoder.yudao.module.wms.controller;
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryDO.java
new file mode 100644
index 000000000..577af728d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryDO.java
@@ -0,0 +1,54 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.inventory;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 库存 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_inventory")
+@KeySequence("wms_inventory_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsInventoryDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+ /**
+ * 库存数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 备注
+ */
+ private String remark;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryHistoryDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryHistoryDO.java
new file mode 100644
index 000000000..224940ade
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryHistoryDO.java
@@ -0,0 +1,94 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.inventory;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.enums.order.WmsOrderTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 库存流水 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_inventory_history")
+@KeySequence("wms_inventory_history_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsInventoryHistoryDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+
+ // ========= 库存维度相关字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+ /**
+ * 库存变化数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 变化前库存数量
+ */
+ private BigDecimal beforeQuantity;
+ /**
+ * 变化后库存数量
+ */
+ private BigDecimal afterQuantity;
+
+ // ========= 单价备注相关字段 =========
+
+ /**
+ * 单价
+ */
+ private BigDecimal price;
+ /**
+ * 库存变化金额
+ */
+ private BigDecimal totalPrice;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ // ========= 来源单据相关字段 =========
+
+ /**
+ * 单据编号
+ */
+ private Long orderId;
+ /**
+ * 单据号
+ */
+ private String orderNo;
+ /**
+ * 单据类型
+ *
+ * 枚举 {@link WmsOrderTypeEnum#getType()}
+ */
+ private Integer orderType;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemBrandDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemBrandDO.java
new file mode 100644
index 000000000..ab41e05f0
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemBrandDO.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * WMS 商品品牌 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_item_brand")
+@KeySequence("wms_item_brand_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsItemBrandDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 品牌编号
+ */
+ private String code;
+ /**
+ * 品牌名称
+ */
+ private String name;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemCategoryDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemCategoryDO.java
new file mode 100644
index 000000000..ded92281e
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemCategoryDO.java
@@ -0,0 +1,60 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * WMS 商品分类 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_item_category")
+@KeySequence("wms_item_category_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsItemCategoryDO extends BaseDO {
+
+ /**
+ * 父级编号 - 根节点
+ */
+ public static final Long PARENT_ID_ROOT = 0L;
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 父级编号
+ *
+ * 关联 {@link #id}
+ */
+ private Long parentId;
+ /**
+ * 分类编号
+ */
+ private String code;
+ /**
+ * 分类名称
+ */
+ private String name;
+ /**
+ * 排序
+ */
+ private Integer sort;
+ /**
+ * 状态
+ *
+ * 枚举 {@link CommonStatusEnum}
+ */
+ private Integer status;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java
new file mode 100644
index 000000000..9a14d3ac2
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java
@@ -0,0 +1,58 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * WMS 商品 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_item")
+@KeySequence("wms_item_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsItemDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 商品编号
+ */
+ private String code;
+ /**
+ * 商品名称
+ */
+ private String name;
+ /**
+ * 单位
+ */
+ private String unit;
+ /**
+ * 商品分类编号
+ *
+ * 关联 {@link WmsItemCategoryDO#getId()}
+ */
+ private Long categoryId;
+ /**
+ * 商品品牌编号
+ *
+ * 关联 {@link WmsItemBrandDO#getId()}
+ */
+ private Long brandId;
+ /**
+ * 备注
+ */
+ private String remark;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
new file mode 100644
index 000000000..7236b4928
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 商品 SKU DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_item_sku")
+@KeySequence("wms_item_sku_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsItemSkuDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 规格名称
+ */
+ private String name;
+ /**
+ * 商品编号
+ *
+ * 关联 {@link WmsItemDO#getId()}
+ */
+ private Long itemId;
+ /**
+ * 条码
+ */
+ private String barCode;
+ /**
+ * 规格编号
+ */
+ private String code;
+
+ /**
+ * 长,单位 cm
+ */
+ private BigDecimal length;
+ /**
+ * 宽,单位 cm
+ */
+ private BigDecimal width;
+ /**
+ * 高,单位 cm
+ */
+ private BigDecimal height;
+
+ /**
+ * 毛重,单位 kg
+ */
+ private BigDecimal grossWeight;
+ /**
+ * 净重,单位 kg
+ */
+ private BigDecimal netWeight;
+
+ /**
+ * 成本价,单位元
+ */
+ private BigDecimal costPrice;
+ /**
+ * 销售价,单位元
+ */
+ private BigDecimal sellingPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/merchant/WmsMerchantDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/merchant/WmsMerchantDO.java
new file mode 100644
index 000000000..60b4c4dbf
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/merchant/WmsMerchantDO.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.enums.md.WmsMerchantTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * WMS 往来企业 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_merchant")
+@KeySequence("wms_merchant_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsMerchantDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 往来企业编号
+ */
+ private String code;
+ /**
+ * 往来企业名称
+ */
+ private String name;
+ /**
+ * 往来企业类型
+ *
+ * 枚举 {@link WmsMerchantTypeEnum}
+ */
+ private Integer type;
+ /**
+ * 级别
+ */
+ private String level;
+ /**
+ * 开户行
+ */
+ private String bankName;
+ /**
+ * 银行账户
+ */
+ private String bankAccount;
+ /**
+ * 地址
+ */
+ private String address;
+ /**
+ * 手机号
+ */
+ private String mobile;
+ /**
+ * 座机号
+ */
+ private String telephone;
+ /**
+ * 联系人
+ */
+ private String contact;
+ /**
+ * Email
+ */
+ private String email;
+ /**
+ * 备注
+ */
+ private String remark;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/warehouse/WmsWarehouseDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/warehouse/WmsWarehouseDO.java
new file mode 100644
index 000000000..e73c1123a
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/warehouse/WmsWarehouseDO.java
@@ -0,0 +1,46 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+/**
+ * WMS 仓库 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_warehouse")
+@KeySequence("wms_warehouse_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsWarehouseDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 仓库编号
+ */
+ private String code;
+ /**
+ * 名称
+ */
+ private String name;
+ /**
+ * 备注
+ */
+ private String remark;
+ /**
+ * 排序
+ */
+ private Integer sort;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java
new file mode 100644
index 000000000..7ebe50a74
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java
@@ -0,0 +1,77 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.check;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * WMS 盘库单 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_check_order")
+@KeySequence("wms_check_order_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsCheckOrderDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 盘库单号
+ */
+ private String no;
+ /**
+ * 单据日期
+ */
+ private LocalDateTime orderTime;
+ /**
+ * 盘库状态
+ *
+ * 字典 {@link DictTypeConstants#ORDER_STATUS}
+ */
+ private Integer status;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+
+ // ========= 汇总金额字段 =========
+
+ /**
+ * 盈亏数量(实盘数量 - 账面数量)
+ */
+ private BigDecimal totalQuantity;
+ /**
+ * 总金额(账面数量 * 单价)
+ */
+ private BigDecimal totalPrice;
+ /**
+ * 实际金额(实盘数量 * 单价)
+ */
+ private BigDecimal actualPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java
new file mode 100644
index 000000000..56f35539f
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java
@@ -0,0 +1,85 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.check;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.inventory.WmsInventoryDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * WMS 盘库单明细 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_check_order_detail")
+@KeySequence("wms_check_order_detail_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsCheckOrderDetailDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ // ========= 单据商品字段 =========
+
+ /**
+ * 盘库单编号
+ *
+ * 关联 {@link WmsCheckOrderDO#getId()}
+ */
+ private Long orderId;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+ /**
+ * 库存编号
+ *
+ * 关联 {@link WmsInventoryDO#getId()}
+ */
+ private Long inventoryId;
+
+ /**
+ * 入库时间
+ */
+ private LocalDateTime receiptTime;
+
+ // ========= 数量金额字段 =========
+
+ /**
+ * 账面数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 实盘数量
+ */
+ private BigDecimal checkQuantity;
+ /**
+ * 单价
+ */
+ private BigDecimal price;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java
new file mode 100644
index 000000000..628640991
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java
@@ -0,0 +1,82 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.movement;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * WMS 移库单 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_movement_order")
+@KeySequence("wms_movement_order_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsMovementOrderDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 移库单号
+ */
+ private String no;
+ /**
+ * 单据日期
+ */
+ private LocalDateTime orderTime;
+ /**
+ * 移库状态
+ *
+ * 字典 {@link DictTypeConstants#ORDER_STATUS}
+ */
+ private Integer status;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ // ========= 来源仓库字段 =========
+
+ /**
+ * 来源仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long sourceWarehouseId;
+
+ // ========= 目标仓库字段 =========
+
+ /**
+ * 目标仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long targetWarehouseId;
+
+ // ========= 汇总金额字段 =========
+
+ /**
+ * 总数量
+ */
+ private BigDecimal totalQuantity;
+ /**
+ * 总金额
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java
new file mode 100644
index 000000000..e9e9d2f24
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java
@@ -0,0 +1,81 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.movement;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 移库单明细 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_movement_order_detail")
+@KeySequence("wms_movement_order_detail_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsMovementOrderDetailDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ // ========= 单据商品字段 =========
+
+ /**
+ * 移库单编号
+ *
+ * 关联 {@link WmsMovementOrderDO#getId()}
+ */
+ private Long orderId;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+
+ // ========= 来源仓库字段 =========
+
+ /**
+ * 来源仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long sourceWarehouseId;
+
+ // ========= 目标仓库字段 =========
+
+ /**
+ * 目标仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long targetWarehouseId;
+
+ // ========= 数量金额字段 =========
+
+ /**
+ * 移库数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 单价
+ */
+ private BigDecimal price;
+ /**
+ * 行金额(数量 * 单价)
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java
new file mode 100644
index 000000000..86458cfbb
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import cn.iocoder.yudao.module.wms.enums.order.WmsReceiptOrderTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * WMS 入库单 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_receipt_order")
+@KeySequence("wms_receipt_order_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsReceiptOrderDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 入库单号
+ */
+ private String no;
+ /**
+ * 入库类型
+ *
+ * 枚举 {@link WmsReceiptOrderTypeEnum}
+ * 字典 {@link DictTypeConstants#RECEIPT_ORDER_TYPE}
+ */
+ private Integer type;
+ /**
+ * 单据日期
+ */
+ private LocalDateTime orderTime;
+ /**
+ * 入库状态
+ *
+ * 字典 {@link DictTypeConstants#ORDER_STATUS}
+ */
+ private Integer status;
+ /**
+ * 业务订单号
+ */
+ private String bizOrderNo;
+ /**
+ * 供应商编号
+ *
+ * 关联 {@link WmsMerchantDO#getId()}
+ */
+ private Long merchantId;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+
+ // ========= 汇总金额字段 =========
+
+ /**
+ * 总数量
+ */
+ private BigDecimal totalQuantity;
+ /**
+ * 总金额
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDetailDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDetailDO.java
new file mode 100644
index 000000000..6920d369d
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDetailDO.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.receipt;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 入库单明细 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_receipt_order_detail")
+@KeySequence("wms_receipt_order_detail_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsReceiptOrderDetailDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ // ========= 单据商品字段 =========
+
+ /**
+ * 入库单编号
+ *
+ * 关联 {@link WmsReceiptOrderDO#getId()}
+ */
+ private Long orderId;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+
+ // ========= 数量金额字段 =========
+
+ /**
+ * 入库数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 单价
+ */
+ private BigDecimal price;
+ /**
+ * 行金额(数量 * 单价)
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDO.java
new file mode 100644
index 000000000..d2e3e4ac2
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDO.java
@@ -0,0 +1,92 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.shipment;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.merchant.WmsMerchantDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import cn.iocoder.yudao.module.wms.enums.DictTypeConstants;
+import cn.iocoder.yudao.module.wms.enums.order.WmsShipmentOrderTypeEnum;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * WMS 出库单 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_shipment_order")
+@KeySequence("wms_shipment_order_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsShipmentOrderDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ /**
+ * 出库单号
+ */
+ private String no;
+ /**
+ * 出库类型
+ *
+ * 枚举 {@link WmsShipmentOrderTypeEnum}
+ * 字典 {@link DictTypeConstants#SHIPMENT_ORDER_TYPE}
+ */
+ private Integer type;
+ /**
+ * 单据日期
+ */
+ private LocalDateTime orderTime;
+ /**
+ * 出库状态
+ *
+ * 字典 {@link DictTypeConstants#ORDER_STATUS}
+ */
+ private Integer status;
+ /**
+ * 业务订单号
+ */
+ private String bizOrderNo;
+ /**
+ * 客户编号
+ *
+ * 关联 {@link WmsMerchantDO#getId()}
+ */
+ private Long merchantId;
+ /**
+ * 备注
+ */
+ private String remark;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+
+ // ========= 汇总金额字段 =========
+
+ /**
+ * 总数量
+ */
+ private BigDecimal totalQuantity;
+ /**
+ * 总金额
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDetailDO.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDetailDO.java
new file mode 100644
index 000000000..fdcb67e45
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDetailDO.java
@@ -0,0 +1,72 @@
+package cn.iocoder.yudao.module.wms.dal.dataobject.order.shipment;
+
+import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
+import cn.iocoder.yudao.module.wms.dal.dataobject.md.warehouse.WmsWarehouseDO;
+import com.baomidou.mybatisplus.annotation.KeySequence;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.*;
+
+import java.math.BigDecimal;
+
+/**
+ * WMS 出库单明细 DO
+ *
+ * @author 芋道源码
+ */
+@TableName("wms_shipment_order_detail")
+@KeySequence("wms_shipment_order_detail_seq")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class WmsShipmentOrderDetailDO extends BaseDO {
+
+ /**
+ * 主键编号
+ */
+ @TableId
+ private Long id;
+ // ========= 单据商品字段 =========
+
+ /**
+ * 出库单编号
+ *
+ * 关联 {@link WmsShipmentOrderDO#getId()}
+ */
+ private Long orderId;
+ /**
+ * 商品 SKU 编号
+ *
+ * 关联 {@link WmsItemSkuDO#getId()}
+ */
+ private Long skuId;
+
+ // ========= 仓库字段 =========
+
+ /**
+ * 仓库编号
+ *
+ * 关联 {@link WmsWarehouseDO#getId()}
+ */
+ private Long warehouseId;
+
+ // ========= 数量金额字段 =========
+
+ /**
+ * 出库数量
+ */
+ private BigDecimal quantity;
+ /**
+ * 单价
+ */
+ private BigDecimal price;
+ /**
+ * 行金额(数量 * 单价)
+ */
+ private BigDecimal totalPrice;
+
+}
diff --git a/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/home/WmsHomeStatisticsMapper.java b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/home/WmsHomeStatisticsMapper.java
new file mode 100644
index 000000000..b752e42d4
--- /dev/null
+++ b/yudao-module-wms/yudao-module-wms-server/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/home/WmsHomeStatisticsMapper.java
@@ -0,0 +1,67 @@
+package cn.iocoder.yudao.module.wms.dal.mysql.home;
+
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * WMS 首页统计 Mapper
+ *
+ * @author 芋道源码
+ */
+@Mapper
+public interface WmsHomeStatisticsMapper {
+
+ /**
+ * 按单据类型和状态统计单据数量
+ *
+ * @param warehouseId 仓库编号
+ * @return [{ "orderType": 1, "status": 0, "count": 5 }, ...]
+ */
+ List