From 6d29f96e94041f3b144755b0cff0e389e54cfbce Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 10 May 2026 21:33:42 +0800 Subject: [PATCH] feat(wms):增加商品信息、SKU 信息 --- yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java | 149 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java | 36 ++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemCategoryMapper.java | 8 ++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java | 40 ++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java | 9 +++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandService.java | 22 ++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java | 18 ++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryService.java | 31 +++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java | 49 ++++++++++++++++++++++++++++++++++++++++++++----- yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java | 25 +++++++++++++++++++++++++ 21 files changed, 1244 insertions(+), 5 deletions(-) create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java create mode 100644 yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java new file mode 100644 index 0000000..a39c132 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java @@ -0,0 +1,149 @@ +package cn.iocoder.yudao.module.wms.controller.admin.md.item; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemRespVO; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemBrandService; +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemCategoryService; +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService; +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT; +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; + +@Tag(name = "管理后台 - WMS 商品") +@RestController +@RequestMapping("/wms/item") +@Validated +public class WmsItemController { + + @Resource + private WmsItemService itemService; + @Resource + private WmsItemCategoryService categoryService; + @Resource + private WmsItemBrandService brandService; + @Resource + private WmsItemSkuService itemSkuService; + + @PostMapping("/create") + @Operation(summary = "创建商品") + @PreAuthorize("@ss.hasPermission('wms:item:create')") + public CommonResult createItem(@Valid @RequestBody WmsItemSaveReqVO createReqVO) { + return success(itemService.createItem(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新商品") + @PreAuthorize("@ss.hasPermission('wms:item:update')") + public CommonResult updateItem(@Valid @RequestBody WmsItemSaveReqVO updateReqVO) { + itemService.updateItem(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除商品") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('wms:item:delete')") + public CommonResult deleteItem(@RequestParam("id") Long id) { + itemService.deleteItem(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得商品") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('wms:item:query')") + public CommonResult getItem(@RequestParam("id") Long id) { + WmsItemDO item = itemService.getItem(id); + return success(buildItemRespVO(item)); + } + + @GetMapping("/page") + @Operation(summary = "获得商品分页") + @PreAuthorize("@ss.hasPermission('wms:item:query')") + public CommonResult> getItemPage(@Valid WmsItemPageReqVO pageReqVO) { + PageResult pageResult = itemService.getItemPage(pageReqVO); + return success(new PageResult<>(buildItemRespVOList(pageResult.getList()), pageResult.getTotal())); + } + + @GetMapping("/simple-list") + @Operation(summary = "获得商品精简列表") + @PreAuthorize("@ss.hasPermission('wms:item:query')") + public CommonResult> getItemSimpleList(@Valid WmsItemPageReqVO pageReqVO) { + List list = itemService.getItemList(pageReqVO); + return success(buildItemRespVOList(list)); + } + + @GetMapping("/export-excel") + @Operation(summary = "导出商品 Excel") + @PreAuthorize("@ss.hasPermission('wms:item:export')") + @ApiAccessLog(operateType = EXPORT) + public void exportItemExcel(@Valid WmsItemPageReqVO pageReqVO, + HttpServletResponse response) throws IOException { + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE); + List list = itemService.getItemPage(pageReqVO).getList(); + ExcelUtils.write(response, "商品.xls", "数据", WmsItemRespVO.class, + buildItemRespVOList(list)); + } + + // ==================== 拼接 VO ==================== + + private WmsItemRespVO buildItemRespVO(WmsItemDO item) { + if (item == null) { + return null; + } + return getFirst(buildItemRespVOList(Collections.singletonList(item))); + } + + private List buildItemRespVOList(List list) { + if (CollUtil.isEmpty(list)) { + return Collections.emptyList(); + } + // 查询关联数据 + Map categoryMap = categoryService.getItemCategoryMap( + convertSet(list, WmsItemDO::getCategoryId)); + Map brandMap = brandService.getItemBrandMap( + convertSet(list, WmsItemDO::getBrandId)); + Map> skuMap = itemSkuService.getItemSkuMultiMap( + convertSet(list, WmsItemDO::getId)); + // 拼接 VO + return BeanUtils.toBean(list, WmsItemRespVO.class, vo -> { + MapUtils.findAndThen(categoryMap, vo.getCategoryId(), category -> + vo.setCategoryName(category.getName())); + MapUtils.findAndThen(brandMap, vo.getBrandId(), brand -> + vo.setBrandName(brand.getName())); + vo.setSkus(BeanUtils.toBean(skuMap.getOrDefault(vo.getId(), Collections.emptyList()), + WmsItemSkuRespVO.class)); + }); + } + +} diff --git a/yudao-module-wms/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..02e720f --- /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,50 @@ +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 = "商品编号", example = "ITEM001") + @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/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/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/mysql/md/item/WmsItemCategoryMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemCategoryMapper.java index 7080ed1..5b95e6e 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemCategoryMapper.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemCategoryMapper.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemC import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO; import org.apache.ibatis.annotations.Mapper; +import java.util.Collection; import java.util.List; /** @@ -29,6 +30,13 @@ public interface WmsItemCategoryMapper extends BaseMapperX { return selectOne(WmsItemCategoryDO::getParentId, parentId, WmsItemCategoryDO::getName, name); } + default List selectListByParentIds(Collection parentIds) { + return selectList(new LambdaQueryWrapperX() + .in(WmsItemCategoryDO::getParentId, parentIds) + .orderByAsc(WmsItemCategoryDO::getSort) + .orderByAsc(WmsItemCategoryDO::getId)); + } + default Long selectCountByParentId(Long parentId) { return selectCount(WmsItemCategoryDO::getParentId, parentId); } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java new file mode 100644 index 0000000..15ab5d1 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.wms.dal.mysql.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.List; + +/** + * WMS 商品 Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface WmsItemMapper extends BaseMapperX { + + default PageResult selectPage(WmsItemPageReqVO reqVO, Collection categoryIds) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(WmsItemDO::getCode, reqVO.getCode()) + .likeIfPresent(WmsItemDO::getName, reqVO.getName()) + .inIfPresent(WmsItemDO::getCategoryId, categoryIds) + .eqIfPresent(WmsItemDO::getBrandId, reqVO.getBrandId()) + .betweenIfPresent(WmsItemDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(WmsItemDO::getId)); + } + + default List selectList(WmsItemPageReqVO reqVO, Collection categoryIds) { + return selectList(new LambdaQueryWrapperX() + .likeIfPresent(WmsItemDO::getCode, reqVO.getCode()) + .likeIfPresent(WmsItemDO::getName, reqVO.getName()) + .inIfPresent(WmsItemDO::getCategoryId, categoryIds) + .eqIfPresent(WmsItemDO::getBrandId, reqVO.getBrandId()) + .betweenIfPresent(WmsItemDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(WmsItemDO::getId)); + } + + default WmsItemDO selectByName(String name) { + return selectOne(WmsItemDO::getName, name); + } + + default Long selectCountByCategoryId(Long categoryId) { + return selectCount(WmsItemDO::getCategoryId, categoryId); + } + + default Long selectCountByBrandId(Long brandId) { + return selectCount(WmsItemDO::getBrandId, brandId); + } + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java new file mode 100644 index 0000000..13248ab --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.wms.dal.mysql.md.item; + +import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; +import org.apache.ibatis.annotations.Mapper; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +/** + * WMS 商品 SKU Mapper + * + * @author 芋道源码 + */ +@Mapper +public interface WmsItemSkuMapper extends BaseMapperX { + + default List selectListByItemId(Long itemId) { + return selectList(new LambdaQueryWrapperX() + .eq(WmsItemSkuDO::getItemId, itemId) + .orderByAsc(WmsItemSkuDO::getId)); + } + + default List selectListByItemIds(Collection itemIds) { + if (CollUtil.isEmpty(itemIds)) { + return Collections.emptyList(); + } + return selectList(new LambdaQueryWrapperX() + .inIfPresent(WmsItemSkuDO::getItemId, itemIds) + .orderByAsc(WmsItemSkuDO::getId)); + } + + default void deleteByItemId(Long itemId) { + delete(WmsItemSkuDO::getItemId, itemId); + } + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java index 363e015..dcf3aea 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java @@ -30,8 +30,17 @@ public interface ErrorCodeConstants { ErrorCode ITEM_CATEGORY_PARENT_ERROR = new ErrorCode(1_060_102_003, "不能设置自己为父商品分类"); ErrorCode ITEM_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_060_102_004, "不能设置自己的子商品分类为父商品分类"); ErrorCode ITEM_CATEGORY_HAS_CHILDREN = new ErrorCode(1_060_102_005, "删除失败!请先删除该分类下的子分类!"); + ErrorCode ITEM_CATEGORY_HAS_ITEM = new ErrorCode(1_060_102_006, "删除失败!分类已被商品使用!"); // ========== WMS 基础数据-商品品牌 1-060-103-000 ========== ErrorCode ITEM_BRAND_NOT_EXISTS = new ErrorCode(1_060_103_000, "商品品牌不存在"); + ErrorCode ITEM_BRAND_HAS_ITEM = new ErrorCode(1_060_103_001, "删除失败!品牌已被商品使用!"); + + // ========== WMS 基础数据-商品 1-060-104-000 ========== + ErrorCode ITEM_NOT_EXISTS = new ErrorCode(1_060_104_000, "商品不存在"); + ErrorCode ITEM_NAME_DUPLICATE = new ErrorCode(1_060_104_001, "商品名称重复"); + ErrorCode ITEM_SKU_REQUIRED = new ErrorCode(1_060_104_002, "至少包含一个商品规格"); + ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复"); + ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在"); } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandService.java index 1400672..9ca393d 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandService.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandService.java @@ -6,7 +6,11 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBran import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * WMS 商品品牌 Service 接口 @@ -68,4 +72,22 @@ public interface WmsItemBrandService { */ List getItemBrandList(); + /** + * 按编号集合获得商品品牌列表 + * + * @param ids 编号集合 + * @return 商品品牌列表 + */ + List getItemBrandList(Collection ids); + + /** + * 按编号集合获得商品品牌 Map + * + * @param ids 编号集合 + * @return 商品品牌 Map + */ + default Map getItemBrandMap(Collection ids) { + return convertMap(getItemBrandList(ids), WmsItemBrandDO::getId); + } + } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java index f81921d..2e30e41 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.wms.service.md.item; +import cn.hutool.core.collection.CollUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandPageReqVO; @@ -10,9 +11,12 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; +import java.util.Collections; import java.util.List; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.ITEM_BRAND_HAS_ITEM; import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.ITEM_BRAND_NOT_EXISTS; /** @@ -26,6 +30,8 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { @Resource private WmsItemBrandMapper brandMapper; + @Resource + private WmsItemService itemService; @Override public Long createItemBrand(WmsItemBrandSaveReqVO createReqVO) { @@ -48,6 +54,10 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { public void deleteItemBrand(Long id) { // 校验存在 validateItemBrandExists(id); + // 校验品牌下不存在商品 + if (itemService.getItemCountByBrandId(id) > 0) { + throw exception(ITEM_BRAND_HAS_ITEM); + } // 删除 brandMapper.deleteById(id); @@ -77,4 +87,12 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { return brandMapper.selectList(); } + @Override + public List getItemBrandList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return brandMapper.selectByIds(ids); + } + } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryService.java index b19be99..a036d7e 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryService.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryService.java @@ -5,7 +5,12 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemC import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO; import jakarta.validation.Valid; +import java.util.Collection; import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; /** * WMS 商品分类 Service 接口 @@ -60,4 +65,30 @@ public interface WmsItemCategoryService { */ List getItemCategoryList(WmsItemCategoryListReqVO listReqVO); + /** + * 按编号集合获得商品分类列表 + * + * @param ids 编号集合 + * @return 商品分类列表 + */ + List getItemCategoryList(Collection ids); + + /** + * 获得指定商品分类及其所有子分类编号集合 + * + * @param id 商品分类编号 + * @return 商品分类编号集合;当 id 为空时,返回 null + */ + Set getSelfAndChildItemCategoryIdList(Long id); + + /** + * 按编号集合获得商品分类 Map + * + * @param ids 编号集合 + * @return 商品分类 Map + */ + default Map getItemCategoryMap(Collection ids) { + return convertMap(getItemCategoryList(ids), WmsItemCategoryDO::getId); + } + } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java index 83ce487..f1f1809 100644 --- a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java @@ -1,5 +1,7 @@ package cn.iocoder.yudao.module.wms.service.md.item; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategoryListReqVO; import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategorySaveReqVO; @@ -9,10 +11,14 @@ import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; -import java.util.Objects; +import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; /** @@ -27,6 +33,9 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @Resource private WmsItemCategoryMapper categoryMapper; + @Resource + private WmsItemService itemService; + @Override public Long createItemCategory(WmsItemCategorySaveReqVO createReqVO) { // 校验数据 @@ -64,7 +73,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { if (id == null) { throw exception(ITEM_CATEGORY_NAME_DUPLICATE); } - if (!Objects.equals(category.getId(), id)) { + if (ObjectUtil.notEqual(category.getId(), id)) { throw exception(ITEM_CATEGORY_NAME_DUPLICATE); } } @@ -74,7 +83,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { return; } // 1. 不能设置自己为父分类 - if (Objects.equals(parentId, id)) { + if (ObjectUtil.equal(parentId, id)) { throw exception(ITEM_CATEGORY_PARENT_ERROR); } // 2. 父分类不存在 @@ -89,7 +98,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { for (int i = 0; i < Short.MAX_VALUE; i++) { // 3.1 校验环路 parentId = parentCategory.getParentId(); - if (Objects.equals(id, parentId)) { + if (ObjectUtil.equal(id, parentId)) { throw exception(ITEM_CATEGORY_PARENT_IS_CHILD); } // 3.2 继续递归上级父分类 @@ -111,7 +120,10 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { if (categoryMapper.selectCountByParentId(id) > 0) { throw exception(ITEM_CATEGORY_HAS_CHILDREN); } - // TODO 商品管理实现后,校验分类下不存在商品后再删除 + // 校验分类下不存在商品 + if (itemService.getItemCountByCategoryId(id) > 0) { + throw exception(ITEM_CATEGORY_HAS_ITEM); + } // 删除 categoryMapper.deleteById(id); @@ -136,4 +148,31 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { return categoryMapper.selectList(listReqVO); } + @Override + public List getItemCategoryList(Collection ids) { + if (CollUtil.isEmpty(ids)) { + return Collections.emptyList(); + } + return categoryMapper.selectByIds(ids); + } + + @Override + public Set getSelfAndChildItemCategoryIdList(Long id) { + if (id == null) { + return null; + } + Set ids = new HashSet<>(); + ids.add(id); + Collection parentIds = Collections.singleton(id); + for (int i = 0; i < Short.MAX_VALUE; i++) { + List children = categoryMapper.selectListByParentIds(parentIds); + if (CollUtil.isEmpty(children)) { + break; + } + ids.addAll(convertSet(children, WmsItemCategoryDO::getId)); + parentIds = convertSet(children, WmsItemCategoryDO::getId); + } + return ids; + } + } diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java new file mode 100644 index 0000000..319f755 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java @@ -0,0 +1,88 @@ +package cn.iocoder.yudao.module.wms.service.md.item; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; +import jakarta.validation.Valid; + +import java.util.List; + +/** + * WMS 商品 Service 接口 + * + * @author 芋道源码 + */ +public interface WmsItemService { + + /** + * 创建商品 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createItem(@Valid WmsItemSaveReqVO createReqVO); + + /** + * 更新商品 + * + * @param updateReqVO 更新信息 + */ + void updateItem(@Valid WmsItemSaveReqVO updateReqVO); + + /** + * 删除商品 + * + * @param id 编号 + */ + void deleteItem(Long id); + + /** + * 校验商品存在 + * + * @param id 编号 + * @return 商品 + */ + WmsItemDO validateItemExists(Long id); + + /** + * 获得商品 + * + * @param id 编号 + * @return 商品 + */ + WmsItemDO getItem(Long id); + + /** + * 获得商品分页 + * + * @param pageReqVO 分页查询 + * @return 商品分页 + */ + PageResult getItemPage(WmsItemPageReqVO pageReqVO); + + /** + * 获得商品列表 + * + * @param pageReqVO 查询条件 + * @return 商品列表 + */ + List getItemList(WmsItemPageReqVO pageReqVO); + + /** + * 获得指定商品分类下的商品数量 + * + * @param categoryId 商品分类编号 + * @return 商品数量 + */ + long getItemCountByCategoryId(Long categoryId); + + /** + * 获得指定商品品牌下的商品数量 + * + * @param brandId 商品品牌编号 + * @return 商品数量 + */ + long getItemCountByBrandId(Long brandId); + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java new file mode 100644 index 0000000..ccb3d48 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java @@ -0,0 +1,147 @@ +package cn.iocoder.yudao.module.wms.service.md.item; + +import cn.hutool.core.util.ObjectUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO; +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemMapper; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; + +/** + * WMS 商品 Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class WmsItemServiceImpl implements WmsItemService { + + @Resource + private WmsItemMapper itemMapper; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private WmsItemCategoryService categoryService; + @Resource + @Lazy // 延迟加载,避免循环依赖 + private WmsItemBrandService brandService; + @Resource + private WmsItemSkuService itemSkuService; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createItem(WmsItemSaveReqVO createReqVO) { + // 校验数据 + validateItemSaveData(createReqVO); + + // 插入商品 + WmsItemDO item = BeanUtils.toBean(createReqVO, WmsItemDO.class); + itemMapper.insert(item); + // 插入 SKU + itemSkuService.createItemSkuList(item.getId(), createReqVO.getSkus()); + return item.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateItem(WmsItemSaveReqVO updateReqVO) { + // 校验存在 + validateItemExists(updateReqVO.getId()); + // 校验数据 + validateItemSaveData(updateReqVO); + + // 更新商品 + WmsItemDO updateObj = BeanUtils.toBean(updateReqVO, WmsItemDO.class); + itemMapper.updateById(updateObj); + // 更新 SKU + itemSkuService.updateItemSkuList(updateReqVO.getId(), updateReqVO.getSkus()); + } + + private void validateItemSaveData(WmsItemSaveReqVO reqVO) { + // 校验商品名称唯一 + validateItemNameUnique(reqVO.getId(), reqVO.getName()); + // 校验商品分类存在 + validateCategoryExists(reqVO.getCategoryId()); + // 校验商品品牌存在 + validateBrandExists(reqVO.getBrandId()); + } + + private void validateItemNameUnique(Long id, String name) { + WmsItemDO item = itemMapper.selectByName(name); + if (item == null) { + return; + } + if (id == null || ObjectUtil.notEqual(item.getId(), id)) { + throw exception(ITEM_NAME_DUPLICATE); + } + } + + private void validateCategoryExists(Long categoryId) { + categoryService.validateItemCategoryExists(categoryId); + } + + private void validateBrandExists(Long brandId) { + if (brandId == null) { + return; + } + brandService.validateItemBrandExists(brandId); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteItem(Long id) { + // 校验存在 + validateItemExists(id); + + // 删除商品和 SKU + itemSkuService.deleteItemSkuListByItemId(id); + itemMapper.deleteById(id); + } + + @Override + public WmsItemDO validateItemExists(Long id) { + WmsItemDO item = itemMapper.selectById(id); + if (item == null) { + throw exception(ITEM_NOT_EXISTS); + } + return item; + } + + @Override + public WmsItemDO getItem(Long id) { + return itemMapper.selectById(id); + } + + @Override + public PageResult getItemPage(WmsItemPageReqVO pageReqVO) { + return itemMapper.selectPage(pageReqVO, + categoryService.getSelfAndChildItemCategoryIdList(pageReqVO.getCategoryId())); + } + + @Override + public List getItemList(WmsItemPageReqVO pageReqVO) { + return itemMapper.selectList(pageReqVO, + categoryService.getSelfAndChildItemCategoryIdList(pageReqVO.getCategoryId())); + } + + @Override + public long getItemCountByCategoryId(Long categoryId) { + return itemMapper.selectCountByCategoryId(categoryId); + } + + @Override + public long getItemCountByBrandId(Long brandId) { + return itemMapper.selectCountByBrandId(brandId); + } + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java new file mode 100644 index 0000000..7fde308 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.wms.service.md.item; + +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; +import jakarta.validation.Valid; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; + +/** + * WMS 商品 SKU Service 接口 + * + * @author 芋道源码 + */ +public interface WmsItemSkuService { + + /** + * 创建商品 SKU 列表 + * + * @param itemId 商品编号 + * @param skus SKU 列表 + */ + void createItemSkuList(Long itemId, @Valid List skus); + + /** + * 更新商品 SKU 列表 + * + * @param itemId 商品编号 + * @param skus SKU 列表 + */ + void updateItemSkuList(Long itemId, @Valid List skus); + + /** + * 按商品编号删除 SKU 列表 + * + * @param itemId 商品编号 + */ + void deleteItemSkuListByItemId(Long itemId); + + /** + * 按商品编号获得 SKU 列表 + * + * @param itemId 商品编号 + * @return SKU 列表 + */ + List getItemSkuList(Long itemId); + + /** + * 按商品编号集合获得 SKU 列表 + * + * @param itemIds 商品编号集合 + * @return SKU 列表 + */ + List getItemSkuList(Collection itemIds); + + /** + * 按商品编号集合获得 SKU MultiMap + * + * @param itemIds 商品编号集合 + * @return 商品编号与 SKU 列表的映射 + */ + default Map> getItemSkuMultiMap(Collection itemIds) { + return convertMultiMap(getItemSkuList(itemIds), WmsItemSkuDO::getItemId); + } + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java new file mode 100644 index 0000000..3a6d003 --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java @@ -0,0 +1,123 @@ +package cn.iocoder.yudao.module.wms.service.md.item; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO; +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO; +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemSkuMapper; +import cn.iocoder.yudao.module.wms.util.WmsUtils; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*; +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; + +/** + * WMS 商品 SKU Service 实现类 + * + * @author 芋道源码 + */ +@Service +@Validated +public class WmsItemSkuServiceImpl implements WmsItemSkuService { + + @Resource + private WmsItemSkuMapper itemSkuMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public void createItemSkuList(Long itemId, List skus) { + validateItemSkuList(skus); + List list = BeanUtils.toBean(skus, WmsItemSkuDO.class, sku -> sku.setItemId(itemId)); + if (CollUtil.isNotEmpty(convertList(list, WmsItemSkuDO::getId))) { + throw exception(ITEM_SKU_NOT_EXISTS); + } + fillEmptyBarCode(list); + itemSkuMapper.insertBatch(list); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateItemSkuList(Long itemId, List skus) { + validateItemSkuList(skus); + + // 第一步,对比新老数据,获得添加、修改、删除的列表 + List oldList = itemSkuMapper.selectListByItemId(itemId); + List newList = BeanUtils.toBean(skus, WmsItemSkuDO.class); + List> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId())); + + // 第二步,批量添加、修改、删除 + if (CollUtil.isNotEmpty(diffList.get(2))) { + // TODO 库存模块实现后,校验商品规格下不存在库存业务数据后再删除 + itemSkuMapper.deleteByIds(convertList(diffList.get(2), WmsItemSkuDO::getId)); + } + if (CollUtil.isNotEmpty(diffList.get(0))) { + if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsItemSkuDO::getId))) { + throw exception(ITEM_SKU_NOT_EXISTS); + } + diffList.get(0).forEach(sku -> sku.setItemId(itemId)); + fillEmptyBarCode(diffList.get(0)); + itemSkuMapper.insertBatch(diffList.get(0)); + } + if (CollUtil.isNotEmpty(diffList.get(1))) { + diffList.get(1).forEach(sku -> sku.setItemId(itemId)); + fillEmptyBarCode(diffList.get(1)); + itemSkuMapper.updateBatch(diffList.get(1)); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void deleteItemSkuListByItemId(Long itemId) { + // TODO 库存模块实现后,校验商品规格下不存在库存业务数据后再删除 + itemSkuMapper.deleteByItemId(itemId); + } + + @Override + public List getItemSkuList(Long itemId) { + return itemSkuMapper.selectListByItemId(itemId); + } + + @Override + public List getItemSkuList(Collection itemIds) { + return itemSkuMapper.selectListByItemIds(itemIds); + } + + private void validateItemSkuList(List skus) { + // 校验至少存在一个商品 SKU + if (CollUtil.isEmpty(skus)) { + throw exception(ITEM_SKU_REQUIRED); + } + // 校验 SKU 名称不重复 + Set names = new HashSet<>(); + for (WmsItemSkuSaveReqVO sku : skus) { + if (!names.add(sku.getName())) { + throw exception(ITEM_SKU_NAME_DUPLICATE, sku.getName()); + } + } + } + + /** + * 填充空的条形码 + * + * @param skus 商品 SKU 列表 + */ + private void fillEmptyBarCode(List skus) { + skus.forEach(sku -> { + if (StrUtil.isBlank(sku.getBarCode())) { + sku.setBarCode(WmsUtils.generateBarCode()); + } + }); + } + +} diff --git a/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java new file mode 100644 index 0000000..917e0cc --- /dev/null +++ b/yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.wms.util; + +import cn.hutool.core.util.RandomUtil; +import lombok.experimental.UtilityClass; + +/** + * WMS 工具类 + * + * @author 芋道源码 + */ +@UtilityClass +public class WmsUtils { + + private static final int BAR_CODE_LENGTH = 8; + + /** + * 生成条码 + * + * @return 条码 + */ + public String generateBarCode() { + return RandomUtil.randomNumbers(BAR_CODE_LENGTH); + } + +} -- libgit2 0.21.4