> 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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemSkuController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemSkuController.java
new file mode 100644
index 0000000..5ece6f3
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandPageReqVO.java
new file mode 100644
index 0000000..0e2d745
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandRespVO.java
new file mode 100644
index 0000000..bc68efe
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/brand/WmsItemBrandSaveReqVO.java
new file mode 100644
index 0000000..7090cf3
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryListReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryListReqVO.java
new file mode 100644
index 0000000..274cad4
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategoryRespVO.java
new file mode 100644
index 0000000..d629b98
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategorySaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/category/WmsItemCategorySaveReqVO.java
new file mode 100644
index 0000000..8d0df22
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemListReqVO.java
new file mode 100644
index 0000000..8dde808
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java
new file mode 100644
index 0000000..5ae42c3
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java
new file mode 100644
index 0000000..d4e7416
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java
new file mode 100644
index 0000000..6b8cadf
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuPageReqVO.java
new file mode 100644
index 0000000..c091ea8
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java
new file mode 100644
index 0000000..8bd57aa
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java
new file mode 100644
index 0000000..1a79dcb
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/WmsMerchantController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/WmsMerchantController.java
new file mode 100644
index 0000000..897f635
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantListReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantListReqVO.java
new file mode 100644
index 0000000..287a1bc
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantPageReqVO.java
new file mode 100644
index 0000000..eb71ab0
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantRespVO.java
new file mode 100644
index 0000000..c88c876
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/merchant/vo/WmsMerchantSaveReqVO.java
new file mode 100644
index 0000000..5803a1d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/WmsWarehouseController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/WmsWarehouseController.java
new file mode 100644
index 0000000..fcb1981
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehousePageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehousePageReqVO.java
new file mode 100644
index 0000000..43fcf5c
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseRespVO.java
new file mode 100644
index 0000000..67c16bf
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/warehouse/vo/WmsWarehouseSaveReqVO.java
new file mode 100644
index 0000000..cb2da87
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderController.java
new file mode 100644
index 0000000..9c0cd09
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/WmsCheckOrderDetailController.java
new file mode 100644
index 0000000..2519825
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailRespVO.java
new file mode 100644
index 0000000..399caa3
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/detail/WmsCheckOrderDetailSaveReqVO.java
new file mode 100644
index 0000000..709ddba
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderPageReqVO.java
new file mode 100644
index 0000000..2182fc6
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderRespVO.java
new file mode 100644
index 0000000..962de82
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/check/vo/order/WmsCheckOrderSaveReqVO.java
new file mode 100644
index 0000000..21660ce
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderController.java
new file mode 100644
index 0000000..d993392
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/WmsMovementOrderDetailController.java
new file mode 100644
index 0000000..092a367
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailRespVO.java
new file mode 100644
index 0000000..5136534
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/detail/WmsMovementOrderDetailSaveReqVO.java
new file mode 100644
index 0000000..28b412e
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderPageReqVO.java
new file mode 100644
index 0000000..c59bc11
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderRespVO.java
new file mode 100644
index 0000000..ecad02e
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/movement/vo/order/WmsMovementOrderSaveReqVO.java
new file mode 100644
index 0000000..982d30d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderController.java
new file mode 100644
index 0000000..c1a2fe6
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/WmsReceiptOrderDetailController.java
new file mode 100644
index 0000000..d443feb
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailRespVO.java
new file mode 100644
index 0000000..4c72b93
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/detail/WmsReceiptOrderDetailSaveReqVO.java
new file mode 100644
index 0000000..a74cc90
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderPageReqVO.java
new file mode 100644
index 0000000..351d150
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderRespVO.java
new file mode 100644
index 0000000..24d3b04
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/receipt/vo/order/WmsReceiptOrderSaveReqVO.java
new file mode 100644
index 0000000..b8619fc
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderController.java
new file mode 100644
index 0000000..65e9153
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderDetailController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/WmsShipmentOrderDetailController.java
new file mode 100644
index 0000000..f9cd14d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailRespVO.java
new file mode 100644
index 0000000..80e9538
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/detail/WmsShipmentOrderDetailSaveReqVO.java
new file mode 100644
index 0000000..be8a8ba
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderPageReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderPageReqVO.java
new file mode 100644
index 0000000..2a9f058
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderRespVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderRespVO.java
new file mode 100644
index 0000000..b391c1d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderSaveReqVO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/order/shipment/vo/order/WmsShipmentOrderSaveReqVO.java
new file mode 100644
index 0000000..232b92d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/package-info.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/package-info.java
new file mode 100644
index 0000000..7f2a55f
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/controller/package-info.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/package-info.java
new file mode 100644
index 0000000..c75d9df
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryDO.java
new file mode 100644
index 0000000..577af72
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryHistoryDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/inventory/WmsInventoryHistoryDO.java
new file mode 100644
index 0000000..224940a
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemBrandDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemBrandDO.java
new file mode 100644
index 0000000..ab41e05
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemCategoryDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemCategoryDO.java
new file mode 100644
index 0000000..ded9228
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java
new file mode 100644
index 0000000..9a14d3a
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java
new file mode 100644
index 0000000..7236b49
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/merchant/WmsMerchantDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/merchant/WmsMerchantDO.java
new file mode 100644
index 0000000..60b4c4d
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/warehouse/WmsWarehouseDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/warehouse/WmsWarehouseDO.java
new file mode 100644
index 0000000..e73c112
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDO.java
new file mode 100644
index 0000000..7ebe50a
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/check/WmsCheckOrderDetailDO.java
new file mode 100644
index 0000000..56f3553
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDO.java
new file mode 100644
index 0000000..6286409
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/movement/WmsMovementOrderDetailDO.java
new file mode 100644
index 0000000..e9e9d2f
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDO.java
new file mode 100644
index 0000000..86458cf
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDetailDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/receipt/WmsReceiptOrderDetailDO.java
new file mode 100644
index 0000000..6920d36
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDO.java
new file mode 100644
index 0000000..d2e3e4a
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDetailDO.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/order/shipment/WmsShipmentOrderDetailDO.java
new file mode 100644
index 0000000..fdcb67e
--- /dev/null
+++ b/yudao-module-wms/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/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/home/WmsHomeStatisticsMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/home/WmsHomeStatisticsMapper.java
new file mode 100644
index 0000000..b752e42
--- /dev/null
+++ b/yudao-module-wms/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