Commit 6d29f96e94041f3b144755b0cff0e389e54cfbce

Authored by YunaiV
1 parent 22e50bab

feat(wms):增加商品信息、SKU 信息

Showing 21 changed files with 1244 additions and 5 deletions
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/WmsItemController.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
  5 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  6 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  7 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  8 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  9 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  10 +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
  11 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
  12 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemRespVO;
  13 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO;
  14 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO;
  15 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO;
  16 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
  17 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  18 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  19 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemBrandService;
  20 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemCategoryService;
  21 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemService;
  22 +import cn.iocoder.yudao.module.wms.service.md.item.WmsItemSkuService;
  23 +import io.swagger.v3.oas.annotations.Operation;
  24 +import io.swagger.v3.oas.annotations.Parameter;
  25 +import io.swagger.v3.oas.annotations.tags.Tag;
  26 +import jakarta.annotation.Resource;
  27 +import jakarta.servlet.http.HttpServletResponse;
  28 +import jakarta.validation.Valid;
  29 +import org.springframework.security.access.prepost.PreAuthorize;
  30 +import org.springframework.validation.annotation.Validated;
  31 +import org.springframework.web.bind.annotation.*;
  32 +
  33 +import java.io.IOException;
  34 +import java.util.Collections;
  35 +import java.util.List;
  36 +import java.util.Map;
  37 +
  38 +import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
  39 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  40 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  41 +
  42 +@Tag(name = "管理后台 - WMS 商品")
  43 +@RestController
  44 +@RequestMapping("/wms/item")
  45 +@Validated
  46 +public class WmsItemController {
  47 +
  48 + @Resource
  49 + private WmsItemService itemService;
  50 + @Resource
  51 + private WmsItemCategoryService categoryService;
  52 + @Resource
  53 + private WmsItemBrandService brandService;
  54 + @Resource
  55 + private WmsItemSkuService itemSkuService;
  56 +
  57 + @PostMapping("/create")
  58 + @Operation(summary = "创建商品")
  59 + @PreAuthorize("@ss.hasPermission('wms:item:create')")
  60 + public CommonResult<Long> createItem(@Valid @RequestBody WmsItemSaveReqVO createReqVO) {
  61 + return success(itemService.createItem(createReqVO));
  62 + }
  63 +
  64 + @PutMapping("/update")
  65 + @Operation(summary = "更新商品")
  66 + @PreAuthorize("@ss.hasPermission('wms:item:update')")
  67 + public CommonResult<Boolean> updateItem(@Valid @RequestBody WmsItemSaveReqVO updateReqVO) {
  68 + itemService.updateItem(updateReqVO);
  69 + return success(true);
  70 + }
  71 +
  72 + @DeleteMapping("/delete")
  73 + @Operation(summary = "删除商品")
  74 + @Parameter(name = "id", description = "编号", required = true)
  75 + @PreAuthorize("@ss.hasPermission('wms:item:delete')")
  76 + public CommonResult<Boolean> deleteItem(@RequestParam("id") Long id) {
  77 + itemService.deleteItem(id);
  78 + return success(true);
  79 + }
  80 +
  81 + @GetMapping("/get")
  82 + @Operation(summary = "获得商品")
  83 + @Parameter(name = "id", description = "编号", required = true, example = "1024")
  84 + @PreAuthorize("@ss.hasPermission('wms:item:query')")
  85 + public CommonResult<WmsItemRespVO> getItem(@RequestParam("id") Long id) {
  86 + WmsItemDO item = itemService.getItem(id);
  87 + return success(buildItemRespVO(item));
  88 + }
  89 +
  90 + @GetMapping("/page")
  91 + @Operation(summary = "获得商品分页")
  92 + @PreAuthorize("@ss.hasPermission('wms:item:query')")
  93 + public CommonResult<PageResult<WmsItemRespVO>> getItemPage(@Valid WmsItemPageReqVO pageReqVO) {
  94 + PageResult<WmsItemDO> pageResult = itemService.getItemPage(pageReqVO);
  95 + return success(new PageResult<>(buildItemRespVOList(pageResult.getList()), pageResult.getTotal()));
  96 + }
  97 +
  98 + @GetMapping("/simple-list")
  99 + @Operation(summary = "获得商品精简列表")
  100 + @PreAuthorize("@ss.hasPermission('wms:item:query')")
  101 + public CommonResult<List<WmsItemRespVO>> getItemSimpleList(@Valid WmsItemPageReqVO pageReqVO) {
  102 + List<WmsItemDO> list = itemService.getItemList(pageReqVO);
  103 + return success(buildItemRespVOList(list));
  104 + }
  105 +
  106 + @GetMapping("/export-excel")
  107 + @Operation(summary = "导出商品 Excel")
  108 + @PreAuthorize("@ss.hasPermission('wms:item:export')")
  109 + @ApiAccessLog(operateType = EXPORT)
  110 + public void exportItemExcel(@Valid WmsItemPageReqVO pageReqVO,
  111 + HttpServletResponse response) throws IOException {
  112 + pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
  113 + List<WmsItemDO> list = itemService.getItemPage(pageReqVO).getList();
  114 + ExcelUtils.write(response, "商品.xls", "数据", WmsItemRespVO.class,
  115 + buildItemRespVOList(list));
  116 + }
  117 +
  118 + // ==================== 拼接 VO ====================
  119 +
  120 + private WmsItemRespVO buildItemRespVO(WmsItemDO item) {
  121 + if (item == null) {
  122 + return null;
  123 + }
  124 + return getFirst(buildItemRespVOList(Collections.singletonList(item)));
  125 + }
  126 +
  127 + private List<WmsItemRespVO> buildItemRespVOList(List<WmsItemDO> list) {
  128 + if (CollUtil.isEmpty(list)) {
  129 + return Collections.emptyList();
  130 + }
  131 + // 查询关联数据
  132 + Map<Long, WmsItemCategoryDO> categoryMap = categoryService.getItemCategoryMap(
  133 + convertSet(list, WmsItemDO::getCategoryId));
  134 + Map<Long, WmsItemBrandDO> brandMap = brandService.getItemBrandMap(
  135 + convertSet(list, WmsItemDO::getBrandId));
  136 + Map<Long, List<WmsItemSkuDO>> skuMap = itemSkuService.getItemSkuMultiMap(
  137 + convertSet(list, WmsItemDO::getId));
  138 + // 拼接 VO
  139 + return BeanUtils.toBean(list, WmsItemRespVO.class, vo -> {
  140 + MapUtils.findAndThen(categoryMap, vo.getCategoryId(), category ->
  141 + vo.setCategoryName(category.getName()));
  142 + MapUtils.findAndThen(brandMap, vo.getBrandId(), brand ->
  143 + vo.setBrandName(brand.getName()));
  144 + vo.setSkus(BeanUtils.toBean(skuMap.getOrDefault(vo.getId(), Collections.emptyList()),
  145 + WmsItemSkuRespVO.class));
  146 + });
  147 + }
  148 +
  149 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemPageReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageParam;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import lombok.Data;
  6 +import lombok.EqualsAndHashCode;
  7 +import lombok.ToString;
  8 +import org.springframework.format.annotation.DateTimeFormat;
  9 +
  10 +import java.time.LocalDateTime;
  11 +
  12 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
  13 +
  14 +@Schema(description = "管理后台 - WMS 商品分页 Request VO")
  15 +@Data
  16 +@EqualsAndHashCode(callSuper = true)
  17 +@ToString(callSuper = true)
  18 +public class WmsItemPageReqVO extends PageParam {
  19 +
  20 + @Schema(description = "商品编号", example = "ITEM001")
  21 + private String code;
  22 +
  23 + @Schema(description = "商品名称", example = "华为 nova flip")
  24 + private String name;
  25 +
  26 + @Schema(description = "商品分类编号", example = "1024")
  27 + private Long categoryId;
  28 +
  29 + @Schema(description = "商品品牌编号", example = "2048")
  30 + private Long brandId;
  31 +
  32 + @Schema(description = "创建时间")
  33 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  34 + private LocalDateTime[] createTime;
  35 +
  36 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
  2 +
  3 +import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
  4 +import cn.idev.excel.annotation.ExcelProperty;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuRespVO;
  6 +import io.swagger.v3.oas.annotations.media.Schema;
  7 +import lombok.Data;
  8 +
  9 +import java.time.LocalDateTime;
  10 +import java.util.List;
  11 +
  12 +@Schema(description = "管理后台 - WMS 商品 Response VO")
  13 +@Data
  14 +@ExcelIgnoreUnannotated
  15 +public class WmsItemRespVO {
  16 +
  17 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  18 + @ExcelProperty("编号")
  19 + private Long id;
  20 +
  21 + @Schema(description = "商品编号", example = "ITEM001")
  22 + @ExcelProperty("商品编号")
  23 + private String code;
  24 +
  25 + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为 nova flip")
  26 + @ExcelProperty("商品名称")
  27 + private String name;
  28 +
  29 + @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  30 + private Long categoryId;
  31 +
  32 + @Schema(description = "商品分类名称", example = "手机")
  33 + @ExcelProperty("商品分类")
  34 + private String categoryName;
  35 +
  36 + @Schema(description = "单位", example = "台")
  37 + @ExcelProperty("单位")
  38 + private String unit;
  39 +
  40 + @Schema(description = "商品品牌编号", example = "1")
  41 + private Long brandId;
  42 +
  43 + @Schema(description = "商品品牌名称", example = "华为")
  44 + @ExcelProperty("商品品牌")
  45 + private String brandName;
  46 +
  47 + @Schema(description = "备注", example = "备注")
  48 + @ExcelProperty("备注")
  49 + private String remark;
  50 +
  51 + @Schema(description = "规格列表")
  52 + private List<WmsItemSkuRespVO> skus;
  53 +
  54 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  55 + @ExcelProperty("创建时间")
  56 + private LocalDateTime createTime;
  57 +
  58 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/item/WmsItemSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO;
  4 +import io.swagger.v3.oas.annotations.media.Schema;
  5 +import jakarta.validation.Valid;
  6 +import jakarta.validation.constraints.NotBlank;
  7 +import jakarta.validation.constraints.NotEmpty;
  8 +import jakarta.validation.constraints.NotNull;
  9 +import jakarta.validation.constraints.Size;
  10 +import lombok.Data;
  11 +
  12 +import java.util.List;
  13 +
  14 +@Schema(description = "管理后台 - WMS 商品创建/更新 Request VO")
  15 +@Data
  16 +public class WmsItemSaveReqVO {
  17 +
  18 + @Schema(description = "编号", example = "1024")
  19 + private Long id;
  20 +
  21 + @Schema(description = "商品编号", example = "ITEM001")
  22 + @Size(max = 20, message = "商品编号长度不能超过 20 个字符")
  23 + private String code;
  24 +
  25 + @Schema(description = "商品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "华为 nova flip")
  26 + @NotBlank(message = "商品名称不能为空")
  27 + @Size(max = 60, message = "商品名称长度不能超过 60 个字符")
  28 + private String name;
  29 +
  30 + @Schema(description = "商品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  31 + @NotNull(message = "商品分类不能为空")
  32 + private Long categoryId;
  33 +
  34 + @Schema(description = "单位", example = "台")
  35 + @Size(max = 20, message = "单位长度不能超过 20 个字符")
  36 + private String unit;
  37 +
  38 + @Schema(description = "商品品牌编号", example = "1")
  39 + private Long brandId;
  40 +
  41 + @Schema(description = "备注", example = "备注")
  42 + @Size(max = 255, message = "备注长度不能超过 255 个字符")
  43 + private String remark;
  44 +
  45 + @Schema(description = "规格列表")
  46 + @Valid
  47 + @NotEmpty(message = "至少包含一个商品规格")
  48 + private List<WmsItemSkuSaveReqVO> skus;
  49 +
  50 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuRespVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import lombok.Data;
  5 +
  6 +import java.math.BigDecimal;
  7 +import java.time.LocalDateTime;
  8 +
  9 +@Schema(description = "管理后台 - WMS 商品 SKU Response VO")
  10 +@Data
  11 +public class WmsItemSkuRespVO {
  12 +
  13 + @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
  14 + private Long id;
  15 +
  16 + @Schema(description = "规格名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "黑色")
  17 + private String name;
  18 +
  19 + @Schema(description = "商品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
  20 + private Long itemId;
  21 +
  22 + @Schema(description = "商品编码", example = "ITEM001")
  23 + private String itemCode;
  24 +
  25 + @Schema(description = "商品名称", example = "华为 nova flip")
  26 + private String itemName;
  27 +
  28 + @Schema(description = "商品分类编号", example = "1")
  29 + private Long categoryId;
  30 +
  31 + @Schema(description = "商品分类名称", example = "手机")
  32 + private String categoryName;
  33 +
  34 + @Schema(description = "单位", example = "台")
  35 + private String unit;
  36 +
  37 + @Schema(description = "商品品牌编号", example = "1")
  38 + private Long brandId;
  39 +
  40 + @Schema(description = "商品品牌名称", example = "华为")
  41 + private String brandName;
  42 +
  43 + @Schema(description = "条码", example = "690000000001")
  44 + private String barCode;
  45 +
  46 + @Schema(description = "规格编号", example = "SKU001")
  47 + private String code;
  48 +
  49 + @Schema(description = "长,单位 cm", example = "10.0")
  50 + private BigDecimal length;
  51 +
  52 + @Schema(description = "宽,单位 cm", example = "8.0")
  53 + private BigDecimal width;
  54 +
  55 + @Schema(description = "高,单位 cm", example = "1.0")
  56 + private BigDecimal height;
  57 +
  58 + @Schema(description = "毛重,单位 kg", example = "1.000")
  59 + private BigDecimal grossWeight;
  60 +
  61 + @Schema(description = "净重,单位 kg", example = "0.900")
  62 + private BigDecimal netWeight;
  63 +
  64 + @Schema(description = "成本价,单位元", example = "5000.00")
  65 + private BigDecimal costPrice;
  66 +
  67 + @Schema(description = "销售价,单位元", example = "5288.00")
  68 + private BigDecimal sellingPrice;
  69 +
  70 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  71 + private LocalDateTime createTime;
  72 +
  73 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/controller/admin/md/item/vo/sku/WmsItemSkuSaveReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku;
  2 +
  3 +import io.swagger.v3.oas.annotations.media.Schema;
  4 +import jakarta.validation.constraints.DecimalMin;
  5 +import jakarta.validation.constraints.NotBlank;
  6 +import jakarta.validation.constraints.Size;
  7 +import lombok.Data;
  8 +
  9 +import java.math.BigDecimal;
  10 +
  11 +@Schema(description = "管理后台 - WMS 商品 SKU 创建/更新 Request VO")
  12 +@Data
  13 +public class WmsItemSkuSaveReqVO {
  14 +
  15 + @Schema(description = "编号", example = "1024")
  16 + private Long id;
  17 +
  18 + @Schema(description = "规格名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "黑色")
  19 + @NotBlank(message = "规格名称不能为空")
  20 + @Size(max = 255, message = "规格名称长度不能超过 255 个字符")
  21 + private String name;
  22 +
  23 + @Schema(description = "商品编号", example = "1")
  24 + private Long itemId;
  25 +
  26 + @Schema(description = "条码", example = "690000000001")
  27 + @Size(max = 64, message = "条码长度不能超过 64 个字符")
  28 + private String barCode;
  29 +
  30 + @Schema(description = "规格编号", example = "SKU001")
  31 + @Size(max = 64, message = "规格编号长度不能超过 64 个字符")
  32 + private String code;
  33 +
  34 + @Schema(description = "长,单位 cm", example = "10.0")
  35 + @DecimalMin(value = "0", message = "长不能小于 0")
  36 + private BigDecimal length;
  37 +
  38 + @Schema(description = "宽,单位 cm", example = "8.0")
  39 + @DecimalMin(value = "0", message = "宽不能小于 0")
  40 + private BigDecimal width;
  41 +
  42 + @Schema(description = "高,单位 cm", example = "1.0")
  43 + @DecimalMin(value = "0", message = "高不能小于 0")
  44 + private BigDecimal height;
  45 +
  46 + @Schema(description = "毛重,单位 kg", example = "1.000")
  47 + @DecimalMin(value = "0", message = "毛重不能小于 0")
  48 + private BigDecimal grossWeight;
  49 +
  50 + @Schema(description = "净重,单位 kg", example = "0.900")
  51 + @DecimalMin(value = "0", message = "净重不能小于 0")
  52 + private BigDecimal netWeight;
  53 +
  54 + @Schema(description = "成本价,单位元", example = "5000.00")
  55 + @DecimalMin(value = "0", message = "成本价不能小于 0")
  56 + private BigDecimal costPrice;
  57 +
  58 + @Schema(description = "销售价,单位元", example = "5288.00")
  59 + @DecimalMin(value = "0", message = "销售价不能小于 0")
  60 + private BigDecimal sellingPrice;
  61 +
  62 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +/**
  10 + * WMS 商品 DO
  11 + *
  12 + * @author 芋道源码
  13 + */
  14 +@TableName("wms_item")
  15 +@KeySequence("wms_item_seq")
  16 +@Data
  17 +@EqualsAndHashCode(callSuper = true)
  18 +@ToString(callSuper = true)
  19 +@Builder
  20 +@NoArgsConstructor
  21 +@AllArgsConstructor
  22 +public class WmsItemDO extends BaseDO {
  23 +
  24 + /**
  25 + * 主键编号
  26 + */
  27 + @TableId
  28 + private Long id;
  29 + /**
  30 + * 商品编号
  31 + */
  32 + private String code;
  33 + /**
  34 + * 商品名称
  35 + */
  36 + private String name;
  37 + /**
  38 + * 单位
  39 + */
  40 + private String unit;
  41 + /**
  42 + * 商品分类编号
  43 + *
  44 + * 关联 {@link WmsItemCategoryDO#getId()}
  45 + */
  46 + private Long categoryId;
  47 + /**
  48 + * 商品品牌编号
  49 + *
  50 + * 关联 {@link WmsItemBrandDO#getId()}
  51 + */
  52 + private Long brandId;
  53 + /**
  54 + * 备注
  55 + */
  56 + private String remark;
  57 +
  58 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/dataobject/md/item/WmsItemSkuDO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.dataobject.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
  4 +import com.baomidou.mybatisplus.annotation.KeySequence;
  5 +import com.baomidou.mybatisplus.annotation.TableId;
  6 +import com.baomidou.mybatisplus.annotation.TableName;
  7 +import lombok.*;
  8 +
  9 +import java.math.BigDecimal;
  10 +
  11 +/**
  12 + * WMS 商品 SKU DO
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +@TableName("wms_item_sku")
  17 +@KeySequence("wms_item_sku_seq")
  18 +@Data
  19 +@EqualsAndHashCode(callSuper = true)
  20 +@ToString(callSuper = true)
  21 +@Builder
  22 +@NoArgsConstructor
  23 +@AllArgsConstructor
  24 +public class WmsItemSkuDO extends BaseDO {
  25 +
  26 + /**
  27 + * 主键编号
  28 + */
  29 + @TableId
  30 + private Long id;
  31 + /**
  32 + * 规格名称
  33 + */
  34 + private String name;
  35 + /**
  36 + * 商品编号
  37 + *
  38 + * 关联 {@link WmsItemDO#getId()}
  39 + */
  40 + private Long itemId;
  41 + /**
  42 + * 条码
  43 + */
  44 + private String barCode;
  45 + /**
  46 + * 规格编号
  47 + */
  48 + private String code;
  49 +
  50 + /**
  51 + * 长,单位 cm
  52 + */
  53 + private BigDecimal length;
  54 + /**
  55 + * 宽,单位 cm
  56 + */
  57 + private BigDecimal width;
  58 + /**
  59 + * 高,单位 cm
  60 + */
  61 + private BigDecimal height;
  62 +
  63 + /**
  64 + * 毛重,单位 kg
  65 + */
  66 + private BigDecimal grossWeight;
  67 + /**
  68 + * 净重,单位 kg
  69 + */
  70 + private BigDecimal netWeight;
  71 +
  72 + /**
  73 + * 成本价,单位元
  74 + */
  75 + private BigDecimal costPrice;
  76 + /**
  77 + * 销售价,单位元
  78 + */
  79 + private BigDecimal sellingPrice;
  80 +
  81 +}
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 @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemC
6 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO; 6 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
7 import org.apache.ibatis.annotations.Mapper; 7 import org.apache.ibatis.annotations.Mapper;
8 8
  9 +import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
10 11
11 /** 12 /**
@@ -29,6 +30,13 @@ public interface WmsItemCategoryMapper extends BaseMapperX&lt;WmsItemCategoryDO&gt; { @@ -29,6 +30,13 @@ public interface WmsItemCategoryMapper extends BaseMapperX&lt;WmsItemCategoryDO&gt; {
29 return selectOne(WmsItemCategoryDO::getParentId, parentId, WmsItemCategoryDO::getName, name); 30 return selectOne(WmsItemCategoryDO::getParentId, parentId, WmsItemCategoryDO::getName, name);
30 } 31 }
31 32
  33 + default List<WmsItemCategoryDO> selectListByParentIds(Collection<Long> parentIds) {
  34 + return selectList(new LambdaQueryWrapperX<WmsItemCategoryDO>()
  35 + .in(WmsItemCategoryDO::getParentId, parentIds)
  36 + .orderByAsc(WmsItemCategoryDO::getSort)
  37 + .orderByAsc(WmsItemCategoryDO::getId));
  38 + }
  39 +
32 default Long selectCountByParentId(Long parentId) { 40 default Long selectCountByParentId(Long parentId) {
33 return selectCount(WmsItemCategoryDO::getParentId, parentId); 41 return selectCount(WmsItemCategoryDO::getParentId, parentId);
34 } 42 }
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  8 +import org.apache.ibatis.annotations.Mapper;
  9 +
  10 +import java.util.Collection;
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * WMS 商品 Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface WmsItemMapper extends BaseMapperX<WmsItemDO> {
  20 +
  21 + default PageResult<WmsItemDO> selectPage(WmsItemPageReqVO reqVO, Collection<Long> categoryIds) {
  22 + return selectPage(reqVO, new LambdaQueryWrapperX<WmsItemDO>()
  23 + .likeIfPresent(WmsItemDO::getCode, reqVO.getCode())
  24 + .likeIfPresent(WmsItemDO::getName, reqVO.getName())
  25 + .inIfPresent(WmsItemDO::getCategoryId, categoryIds)
  26 + .eqIfPresent(WmsItemDO::getBrandId, reqVO.getBrandId())
  27 + .betweenIfPresent(WmsItemDO::getCreateTime, reqVO.getCreateTime())
  28 + .orderByDesc(WmsItemDO::getId));
  29 + }
  30 +
  31 + default List<WmsItemDO> selectList(WmsItemPageReqVO reqVO, Collection<Long> categoryIds) {
  32 + return selectList(new LambdaQueryWrapperX<WmsItemDO>()
  33 + .likeIfPresent(WmsItemDO::getCode, reqVO.getCode())
  34 + .likeIfPresent(WmsItemDO::getName, reqVO.getName())
  35 + .inIfPresent(WmsItemDO::getCategoryId, categoryIds)
  36 + .eqIfPresent(WmsItemDO::getBrandId, reqVO.getBrandId())
  37 + .betweenIfPresent(WmsItemDO::getCreateTime, reqVO.getCreateTime())
  38 + .orderByDesc(WmsItemDO::getId));
  39 + }
  40 +
  41 + default WmsItemDO selectByName(String name) {
  42 + return selectOne(WmsItemDO::getName, name);
  43 + }
  44 +
  45 + default Long selectCountByCategoryId(Long categoryId) {
  46 + return selectCount(WmsItemDO::getCategoryId, categoryId);
  47 + }
  48 +
  49 + default Long selectCountByBrandId(Long brandId) {
  50 + return selectCount(WmsItemDO::getBrandId, brandId);
  51 + }
  52 +
  53 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/dal/mysql/md/item/WmsItemSkuMapper.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.dal.mysql.md.item;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  7 +import org.apache.ibatis.annotations.Mapper;
  8 +
  9 +import java.util.Collection;
  10 +import java.util.Collections;
  11 +import java.util.List;
  12 +
  13 +/**
  14 + * WMS 商品 SKU Mapper
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +@Mapper
  19 +public interface WmsItemSkuMapper extends BaseMapperX<WmsItemSkuDO> {
  20 +
  21 + default List<WmsItemSkuDO> selectListByItemId(Long itemId) {
  22 + return selectList(new LambdaQueryWrapperX<WmsItemSkuDO>()
  23 + .eq(WmsItemSkuDO::getItemId, itemId)
  24 + .orderByAsc(WmsItemSkuDO::getId));
  25 + }
  26 +
  27 + default List<WmsItemSkuDO> selectListByItemIds(Collection<Long> itemIds) {
  28 + if (CollUtil.isEmpty(itemIds)) {
  29 + return Collections.emptyList();
  30 + }
  31 + return selectList(new LambdaQueryWrapperX<WmsItemSkuDO>()
  32 + .inIfPresent(WmsItemSkuDO::getItemId, itemIds)
  33 + .orderByAsc(WmsItemSkuDO::getId));
  34 + }
  35 +
  36 + default void deleteByItemId(Long itemId) {
  37 + delete(WmsItemSkuDO::getItemId, itemId);
  38 + }
  39 +
  40 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/enums/ErrorCodeConstants.java
@@ -30,8 +30,17 @@ public interface ErrorCodeConstants { @@ -30,8 +30,17 @@ public interface ErrorCodeConstants {
30 ErrorCode ITEM_CATEGORY_PARENT_ERROR = new ErrorCode(1_060_102_003, "不能设置自己为父商品分类"); 30 ErrorCode ITEM_CATEGORY_PARENT_ERROR = new ErrorCode(1_060_102_003, "不能设置自己为父商品分类");
31 ErrorCode ITEM_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_060_102_004, "不能设置自己的子商品分类为父商品分类"); 31 ErrorCode ITEM_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_060_102_004, "不能设置自己的子商品分类为父商品分类");
32 ErrorCode ITEM_CATEGORY_HAS_CHILDREN = new ErrorCode(1_060_102_005, "删除失败!请先删除该分类下的子分类!"); 32 ErrorCode ITEM_CATEGORY_HAS_CHILDREN = new ErrorCode(1_060_102_005, "删除失败!请先删除该分类下的子分类!");
  33 + ErrorCode ITEM_CATEGORY_HAS_ITEM = new ErrorCode(1_060_102_006, "删除失败!分类已被商品使用!");
33 34
34 // ========== WMS 基础数据-商品品牌 1-060-103-000 ========== 35 // ========== WMS 基础数据-商品品牌 1-060-103-000 ==========
35 ErrorCode ITEM_BRAND_NOT_EXISTS = new ErrorCode(1_060_103_000, "商品品牌不存在"); 36 ErrorCode ITEM_BRAND_NOT_EXISTS = new ErrorCode(1_060_103_000, "商品品牌不存在");
  37 + ErrorCode ITEM_BRAND_HAS_ITEM = new ErrorCode(1_060_103_001, "删除失败!品牌已被商品使用!");
  38 +
  39 + // ========== WMS 基础数据-商品 1-060-104-000 ==========
  40 + ErrorCode ITEM_NOT_EXISTS = new ErrorCode(1_060_104_000, "商品不存在");
  41 + ErrorCode ITEM_NAME_DUPLICATE = new ErrorCode(1_060_104_001, "商品名称重复");
  42 + ErrorCode ITEM_SKU_REQUIRED = new ErrorCode(1_060_104_002, "至少包含一个商品规格");
  43 + ErrorCode ITEM_SKU_NAME_DUPLICATE = new ErrorCode(1_060_104_003, "商品规格名称【{}】重复");
  44 + ErrorCode ITEM_SKU_NOT_EXISTS = new ErrorCode(1_060_104_004, "商品规格不存在");
36 45
37 } 46 }
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 @@ -6,7 +6,11 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBran
6 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO; 6 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemBrandDO;
7 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
8 8
  9 +import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
  11 +import java.util.Map;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
10 14
11 /** 15 /**
12 * WMS 商品品牌 Service 接口 16 * WMS 商品品牌 Service 接口
@@ -68,4 +72,22 @@ public interface WmsItemBrandService { @@ -68,4 +72,22 @@ public interface WmsItemBrandService {
68 */ 72 */
69 List<WmsItemBrandDO> getItemBrandList(); 73 List<WmsItemBrandDO> getItemBrandList();
70 74
  75 + /**
  76 + * 按编号集合获得商品品牌列表
  77 + *
  78 + * @param ids 编号集合
  79 + * @return 商品品牌列表
  80 + */
  81 + List<WmsItemBrandDO> getItemBrandList(Collection<Long> ids);
  82 +
  83 + /**
  84 + * 按编号集合获得商品品牌 Map
  85 + *
  86 + * @param ids 编号集合
  87 + * @return 商品品牌 Map
  88 + */
  89 + default Map<Long, WmsItemBrandDO> getItemBrandMap(Collection<Long> ids) {
  90 + return convertMap(getItemBrandList(ids), WmsItemBrandDO::getId);
  91 + }
  92 +
71 } 93 }
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemBrandServiceImpl.java
1 package cn.iocoder.yudao.module.wms.service.md.item; 1 package cn.iocoder.yudao.module.wms.service.md.item;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.pojo.PageResult; 4 import cn.iocoder.yudao.framework.common.pojo.PageResult;
4 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
5 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandPageReqVO; 6 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.brand.WmsItemBrandPageReqVO;
@@ -10,9 +11,12 @@ import jakarta.annotation.Resource; @@ -10,9 +11,12 @@ import jakarta.annotation.Resource;
10 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
11 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
12 13
  14 +import java.util.Collection;
  15 +import java.util.Collections;
13 import java.util.List; 16 import java.util.List;
14 17
15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.ITEM_BRAND_HAS_ITEM;
16 import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.ITEM_BRAND_NOT_EXISTS; 20 import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.ITEM_BRAND_NOT_EXISTS;
17 21
18 /** 22 /**
@@ -26,6 +30,8 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { @@ -26,6 +30,8 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService {
26 30
27 @Resource 31 @Resource
28 private WmsItemBrandMapper brandMapper; 32 private WmsItemBrandMapper brandMapper;
  33 + @Resource
  34 + private WmsItemService itemService;
29 35
30 @Override 36 @Override
31 public Long createItemBrand(WmsItemBrandSaveReqVO createReqVO) { 37 public Long createItemBrand(WmsItemBrandSaveReqVO createReqVO) {
@@ -48,6 +54,10 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { @@ -48,6 +54,10 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService {
48 public void deleteItemBrand(Long id) { 54 public void deleteItemBrand(Long id) {
49 // 校验存在 55 // 校验存在
50 validateItemBrandExists(id); 56 validateItemBrandExists(id);
  57 + // 校验品牌下不存在商品
  58 + if (itemService.getItemCountByBrandId(id) > 0) {
  59 + throw exception(ITEM_BRAND_HAS_ITEM);
  60 + }
51 61
52 // 删除 62 // 删除
53 brandMapper.deleteById(id); 63 brandMapper.deleteById(id);
@@ -77,4 +87,12 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService { @@ -77,4 +87,12 @@ public class WmsItemBrandServiceImpl implements WmsItemBrandService {
77 return brandMapper.selectList(); 87 return brandMapper.selectList();
78 } 88 }
79 89
  90 + @Override
  91 + public List<WmsItemBrandDO> getItemBrandList(Collection<Long> ids) {
  92 + if (CollUtil.isEmpty(ids)) {
  93 + return Collections.emptyList();
  94 + }
  95 + return brandMapper.selectByIds(ids);
  96 + }
  97 +
80 } 98 }
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 @@ -5,7 +5,12 @@ import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemC
5 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO; 5 import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemCategoryDO;
6 import jakarta.validation.Valid; 6 import jakarta.validation.Valid;
7 7
  8 +import java.util.Collection;
8 import java.util.List; 9 import java.util.List;
  10 +import java.util.Map;
  11 +import java.util.Set;
  12 +
  13 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
9 14
10 /** 15 /**
11 * WMS 商品分类 Service 接口 16 * WMS 商品分类 Service 接口
@@ -60,4 +65,30 @@ public interface WmsItemCategoryService { @@ -60,4 +65,30 @@ public interface WmsItemCategoryService {
60 */ 65 */
61 List<WmsItemCategoryDO> getItemCategoryList(WmsItemCategoryListReqVO listReqVO); 66 List<WmsItemCategoryDO> getItemCategoryList(WmsItemCategoryListReqVO listReqVO);
62 67
  68 + /**
  69 + * 按编号集合获得商品分类列表
  70 + *
  71 + * @param ids 编号集合
  72 + * @return 商品分类列表
  73 + */
  74 + List<WmsItemCategoryDO> getItemCategoryList(Collection<Long> ids);
  75 +
  76 + /**
  77 + * 获得指定商品分类及其所有子分类编号集合
  78 + *
  79 + * @param id 商品分类编号
  80 + * @return 商品分类编号集合;当 id 为空时,返回 null
  81 + */
  82 + Set<Long> getSelfAndChildItemCategoryIdList(Long id);
  83 +
  84 + /**
  85 + * 按编号集合获得商品分类 Map
  86 + *
  87 + * @param ids 编号集合
  88 + * @return 商品分类 Map
  89 + */
  90 + default Map<Long, WmsItemCategoryDO> getItemCategoryMap(Collection<Long> ids) {
  91 + return convertMap(getItemCategoryList(ids), WmsItemCategoryDO::getId);
  92 + }
  93 +
63 } 94 }
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemCategoryServiceImpl.java
1 package cn.iocoder.yudao.module.wms.service.md.item; 1 package cn.iocoder.yudao.module.wms.service.md.item;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
3 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
4 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategoryListReqVO; 6 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategoryListReqVO;
5 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategorySaveReqVO; 7 import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.category.WmsItemCategorySaveReqVO;
@@ -9,10 +11,14 @@ import jakarta.annotation.Resource; @@ -9,10 +11,14 @@ import jakarta.annotation.Resource;
9 import org.springframework.stereotype.Service; 11 import org.springframework.stereotype.Service;
10 import org.springframework.validation.annotation.Validated; 12 import org.springframework.validation.annotation.Validated;
11 13
  14 +import java.util.Collection;
  15 +import java.util.Collections;
  16 +import java.util.HashSet;
12 import java.util.List; 17 import java.util.List;
13 -import java.util.Objects; 18 +import java.util.Set;
14 19
15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 20 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
16 import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*; 22 import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
17 23
18 /** 24 /**
@@ -27,6 +33,9 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -27,6 +33,9 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
27 @Resource 33 @Resource
28 private WmsItemCategoryMapper categoryMapper; 34 private WmsItemCategoryMapper categoryMapper;
29 35
  36 + @Resource
  37 + private WmsItemService itemService;
  38 +
30 @Override 39 @Override
31 public Long createItemCategory(WmsItemCategorySaveReqVO createReqVO) { 40 public Long createItemCategory(WmsItemCategorySaveReqVO createReqVO) {
32 // 校验数据 41 // 校验数据
@@ -64,7 +73,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -64,7 +73,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
64 if (id == null) { 73 if (id == null) {
65 throw exception(ITEM_CATEGORY_NAME_DUPLICATE); 74 throw exception(ITEM_CATEGORY_NAME_DUPLICATE);
66 } 75 }
67 - if (!Objects.equals(category.getId(), id)) { 76 + if (ObjectUtil.notEqual(category.getId(), id)) {
68 throw exception(ITEM_CATEGORY_NAME_DUPLICATE); 77 throw exception(ITEM_CATEGORY_NAME_DUPLICATE);
69 } 78 }
70 } 79 }
@@ -74,7 +83,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -74,7 +83,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
74 return; 83 return;
75 } 84 }
76 // 1. 不能设置自己为父分类 85 // 1. 不能设置自己为父分类
77 - if (Objects.equals(parentId, id)) { 86 + if (ObjectUtil.equal(parentId, id)) {
78 throw exception(ITEM_CATEGORY_PARENT_ERROR); 87 throw exception(ITEM_CATEGORY_PARENT_ERROR);
79 } 88 }
80 // 2. 父分类不存在 89 // 2. 父分类不存在
@@ -89,7 +98,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -89,7 +98,7 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
89 for (int i = 0; i < Short.MAX_VALUE; i++) { 98 for (int i = 0; i < Short.MAX_VALUE; i++) {
90 // 3.1 校验环路 99 // 3.1 校验环路
91 parentId = parentCategory.getParentId(); 100 parentId = parentCategory.getParentId();
92 - if (Objects.equals(id, parentId)) { 101 + if (ObjectUtil.equal(id, parentId)) {
93 throw exception(ITEM_CATEGORY_PARENT_IS_CHILD); 102 throw exception(ITEM_CATEGORY_PARENT_IS_CHILD);
94 } 103 }
95 // 3.2 继续递归上级父分类 104 // 3.2 继续递归上级父分类
@@ -111,7 +120,10 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -111,7 +120,10 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
111 if (categoryMapper.selectCountByParentId(id) > 0) { 120 if (categoryMapper.selectCountByParentId(id) > 0) {
112 throw exception(ITEM_CATEGORY_HAS_CHILDREN); 121 throw exception(ITEM_CATEGORY_HAS_CHILDREN);
113 } 122 }
114 - // TODO 商品管理实现后,校验分类下不存在商品后再删除 123 + // 校验分类下不存在商品
  124 + if (itemService.getItemCountByCategoryId(id) > 0) {
  125 + throw exception(ITEM_CATEGORY_HAS_ITEM);
  126 + }
115 127
116 // 删除 128 // 删除
117 categoryMapper.deleteById(id); 129 categoryMapper.deleteById(id);
@@ -136,4 +148,31 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService { @@ -136,4 +148,31 @@ public class WmsItemCategoryServiceImpl implements WmsItemCategoryService {
136 return categoryMapper.selectList(listReqVO); 148 return categoryMapper.selectList(listReqVO);
137 } 149 }
138 150
  151 + @Override
  152 + public List<WmsItemCategoryDO> getItemCategoryList(Collection<Long> ids) {
  153 + if (CollUtil.isEmpty(ids)) {
  154 + return Collections.emptyList();
  155 + }
  156 + return categoryMapper.selectByIds(ids);
  157 + }
  158 +
  159 + @Override
  160 + public Set<Long> getSelfAndChildItemCategoryIdList(Long id) {
  161 + if (id == null) {
  162 + return null;
  163 + }
  164 + Set<Long> ids = new HashSet<>();
  165 + ids.add(id);
  166 + Collection<Long> parentIds = Collections.singleton(id);
  167 + for (int i = 0; i < Short.MAX_VALUE; i++) {
  168 + List<WmsItemCategoryDO> children = categoryMapper.selectListByParentIds(parentIds);
  169 + if (CollUtil.isEmpty(children)) {
  170 + break;
  171 + }
  172 + ids.addAll(convertSet(children, WmsItemCategoryDO::getId));
  173 + parentIds = convertSet(children, WmsItemCategoryDO::getId);
  174 + }
  175 + return ids;
  176 + }
  177 +
139 } 178 }
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
  5 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO;
  6 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  7 +import jakarta.validation.Valid;
  8 +
  9 +import java.util.List;
  10 +
  11 +/**
  12 + * WMS 商品 Service 接口
  13 + *
  14 + * @author 芋道源码
  15 + */
  16 +public interface WmsItemService {
  17 +
  18 + /**
  19 + * 创建商品
  20 + *
  21 + * @param createReqVO 创建信息
  22 + * @return 编号
  23 + */
  24 + Long createItem(@Valid WmsItemSaveReqVO createReqVO);
  25 +
  26 + /**
  27 + * 更新商品
  28 + *
  29 + * @param updateReqVO 更新信息
  30 + */
  31 + void updateItem(@Valid WmsItemSaveReqVO updateReqVO);
  32 +
  33 + /**
  34 + * 删除商品
  35 + *
  36 + * @param id 编号
  37 + */
  38 + void deleteItem(Long id);
  39 +
  40 + /**
  41 + * 校验商品存在
  42 + *
  43 + * @param id 编号
  44 + * @return 商品
  45 + */
  46 + WmsItemDO validateItemExists(Long id);
  47 +
  48 + /**
  49 + * 获得商品
  50 + *
  51 + * @param id 编号
  52 + * @return 商品
  53 + */
  54 + WmsItemDO getItem(Long id);
  55 +
  56 + /**
  57 + * 获得商品分页
  58 + *
  59 + * @param pageReqVO 分页查询
  60 + * @return 商品分页
  61 + */
  62 + PageResult<WmsItemDO> getItemPage(WmsItemPageReqVO pageReqVO);
  63 +
  64 + /**
  65 + * 获得商品列表
  66 + *
  67 + * @param pageReqVO 查询条件
  68 + * @return 商品列表
  69 + */
  70 + List<WmsItemDO> getItemList(WmsItemPageReqVO pageReqVO);
  71 +
  72 + /**
  73 + * 获得指定商品分类下的商品数量
  74 + *
  75 + * @param categoryId 商品分类编号
  76 + * @return 商品数量
  77 + */
  78 + long getItemCountByCategoryId(Long categoryId);
  79 +
  80 + /**
  81 + * 获得指定商品品牌下的商品数量
  82 + *
  83 + * @param brandId 商品品牌编号
  84 + * @return 商品数量
  85 + */
  86 + long getItemCountByBrandId(Long brandId);
  87 +
  88 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.md.item;
  2 +
  3 +import cn.hutool.core.util.ObjectUtil;
  4 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemPageReqVO;
  7 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.item.WmsItemSaveReqVO;
  8 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemDO;
  9 +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemMapper;
  10 +import jakarta.annotation.Resource;
  11 +import org.springframework.context.annotation.Lazy;
  12 +import org.springframework.stereotype.Service;
  13 +import org.springframework.transaction.annotation.Transactional;
  14 +import org.springframework.validation.annotation.Validated;
  15 +
  16 +import java.util.List;
  17 +
  18 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  19 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  20 +
  21 +/**
  22 + * WMS 商品 Service 实现类
  23 + *
  24 + * @author 芋道源码
  25 + */
  26 +@Service
  27 +@Validated
  28 +public class WmsItemServiceImpl implements WmsItemService {
  29 +
  30 + @Resource
  31 + private WmsItemMapper itemMapper;
  32 + @Resource
  33 + @Lazy // 延迟加载,避免循环依赖
  34 + private WmsItemCategoryService categoryService;
  35 + @Resource
  36 + @Lazy // 延迟加载,避免循环依赖
  37 + private WmsItemBrandService brandService;
  38 + @Resource
  39 + private WmsItemSkuService itemSkuService;
  40 +
  41 + @Override
  42 + @Transactional(rollbackFor = Exception.class)
  43 + public Long createItem(WmsItemSaveReqVO createReqVO) {
  44 + // 校验数据
  45 + validateItemSaveData(createReqVO);
  46 +
  47 + // 插入商品
  48 + WmsItemDO item = BeanUtils.toBean(createReqVO, WmsItemDO.class);
  49 + itemMapper.insert(item);
  50 + // 插入 SKU
  51 + itemSkuService.createItemSkuList(item.getId(), createReqVO.getSkus());
  52 + return item.getId();
  53 + }
  54 +
  55 + @Override
  56 + @Transactional(rollbackFor = Exception.class)
  57 + public void updateItem(WmsItemSaveReqVO updateReqVO) {
  58 + // 校验存在
  59 + validateItemExists(updateReqVO.getId());
  60 + // 校验数据
  61 + validateItemSaveData(updateReqVO);
  62 +
  63 + // 更新商品
  64 + WmsItemDO updateObj = BeanUtils.toBean(updateReqVO, WmsItemDO.class);
  65 + itemMapper.updateById(updateObj);
  66 + // 更新 SKU
  67 + itemSkuService.updateItemSkuList(updateReqVO.getId(), updateReqVO.getSkus());
  68 + }
  69 +
  70 + private void validateItemSaveData(WmsItemSaveReqVO reqVO) {
  71 + // 校验商品名称唯一
  72 + validateItemNameUnique(reqVO.getId(), reqVO.getName());
  73 + // 校验商品分类存在
  74 + validateCategoryExists(reqVO.getCategoryId());
  75 + // 校验商品品牌存在
  76 + validateBrandExists(reqVO.getBrandId());
  77 + }
  78 +
  79 + private void validateItemNameUnique(Long id, String name) {
  80 + WmsItemDO item = itemMapper.selectByName(name);
  81 + if (item == null) {
  82 + return;
  83 + }
  84 + if (id == null || ObjectUtil.notEqual(item.getId(), id)) {
  85 + throw exception(ITEM_NAME_DUPLICATE);
  86 + }
  87 + }
  88 +
  89 + private void validateCategoryExists(Long categoryId) {
  90 + categoryService.validateItemCategoryExists(categoryId);
  91 + }
  92 +
  93 + private void validateBrandExists(Long brandId) {
  94 + if (brandId == null) {
  95 + return;
  96 + }
  97 + brandService.validateItemBrandExists(brandId);
  98 + }
  99 +
  100 + @Override
  101 + @Transactional(rollbackFor = Exception.class)
  102 + public void deleteItem(Long id) {
  103 + // 校验存在
  104 + validateItemExists(id);
  105 +
  106 + // 删除商品和 SKU
  107 + itemSkuService.deleteItemSkuListByItemId(id);
  108 + itemMapper.deleteById(id);
  109 + }
  110 +
  111 + @Override
  112 + public WmsItemDO validateItemExists(Long id) {
  113 + WmsItemDO item = itemMapper.selectById(id);
  114 + if (item == null) {
  115 + throw exception(ITEM_NOT_EXISTS);
  116 + }
  117 + return item;
  118 + }
  119 +
  120 + @Override
  121 + public WmsItemDO getItem(Long id) {
  122 + return itemMapper.selectById(id);
  123 + }
  124 +
  125 + @Override
  126 + public PageResult<WmsItemDO> getItemPage(WmsItemPageReqVO pageReqVO) {
  127 + return itemMapper.selectPage(pageReqVO,
  128 + categoryService.getSelfAndChildItemCategoryIdList(pageReqVO.getCategoryId()));
  129 + }
  130 +
  131 + @Override
  132 + public List<WmsItemDO> getItemList(WmsItemPageReqVO pageReqVO) {
  133 + return itemMapper.selectList(pageReqVO,
  134 + categoryService.getSelfAndChildItemCategoryIdList(pageReqVO.getCategoryId()));
  135 + }
  136 +
  137 + @Override
  138 + public long getItemCountByCategoryId(Long categoryId) {
  139 + return itemMapper.selectCountByCategoryId(categoryId);
  140 + }
  141 +
  142 + @Override
  143 + public long getItemCountByBrandId(Long brandId) {
  144 + return itemMapper.selectCountByBrandId(brandId);
  145 + }
  146 +
  147 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.md.item;
  2 +
  3 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO;
  4 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  5 +import jakarta.validation.Valid;
  6 +
  7 +import java.util.Collection;
  8 +import java.util.List;
  9 +import java.util.Map;
  10 +
  11 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap;
  12 +
  13 +/**
  14 + * WMS 商品 SKU Service 接口
  15 + *
  16 + * @author 芋道源码
  17 + */
  18 +public interface WmsItemSkuService {
  19 +
  20 + /**
  21 + * 创建商品 SKU 列表
  22 + *
  23 + * @param itemId 商品编号
  24 + * @param skus SKU 列表
  25 + */
  26 + void createItemSkuList(Long itemId, @Valid List<WmsItemSkuSaveReqVO> skus);
  27 +
  28 + /**
  29 + * 更新商品 SKU 列表
  30 + *
  31 + * @param itemId 商品编号
  32 + * @param skus SKU 列表
  33 + */
  34 + void updateItemSkuList(Long itemId, @Valid List<WmsItemSkuSaveReqVO> skus);
  35 +
  36 + /**
  37 + * 按商品编号删除 SKU 列表
  38 + *
  39 + * @param itemId 商品编号
  40 + */
  41 + void deleteItemSkuListByItemId(Long itemId);
  42 +
  43 + /**
  44 + * 按商品编号获得 SKU 列表
  45 + *
  46 + * @param itemId 商品编号
  47 + * @return SKU 列表
  48 + */
  49 + List<WmsItemSkuDO> getItemSkuList(Long itemId);
  50 +
  51 + /**
  52 + * 按商品编号集合获得 SKU 列表
  53 + *
  54 + * @param itemIds 商品编号集合
  55 + * @return SKU 列表
  56 + */
  57 + List<WmsItemSkuDO> getItemSkuList(Collection<Long> itemIds);
  58 +
  59 + /**
  60 + * 按商品编号集合获得 SKU MultiMap
  61 + *
  62 + * @param itemIds 商品编号集合
  63 + * @return 商品编号与 SKU 列表的映射
  64 + */
  65 + default Map<Long, List<WmsItemSkuDO>> getItemSkuMultiMap(Collection<Long> itemIds) {
  66 + return convertMultiMap(getItemSkuList(itemIds), WmsItemSkuDO::getItemId);
  67 + }
  68 +
  69 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/service/md/item/WmsItemSkuServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.service.md.item;
  2 +
  3 +import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.StrUtil;
  5 +import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
  6 +import cn.iocoder.yudao.module.wms.controller.admin.md.item.vo.sku.WmsItemSkuSaveReqVO;
  7 +import cn.iocoder.yudao.module.wms.dal.dataobject.md.item.WmsItemSkuDO;
  8 +import cn.iocoder.yudao.module.wms.dal.mysql.md.item.WmsItemSkuMapper;
  9 +import cn.iocoder.yudao.module.wms.util.WmsUtils;
  10 +import jakarta.annotation.Resource;
  11 +import org.springframework.stereotype.Service;
  12 +import org.springframework.transaction.annotation.Transactional;
  13 +import org.springframework.validation.annotation.Validated;
  14 +
  15 +import java.util.Collection;
  16 +import java.util.HashSet;
  17 +import java.util.List;
  18 +import java.util.Set;
  19 +
  20 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  21 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.*;
  22 +import static cn.iocoder.yudao.module.wms.enums.ErrorCodeConstants.*;
  23 +
  24 +/**
  25 + * WMS 商品 SKU Service 实现类
  26 + *
  27 + * @author 芋道源码
  28 + */
  29 +@Service
  30 +@Validated
  31 +public class WmsItemSkuServiceImpl implements WmsItemSkuService {
  32 +
  33 + @Resource
  34 + private WmsItemSkuMapper itemSkuMapper;
  35 +
  36 + @Override
  37 + @Transactional(rollbackFor = Exception.class)
  38 + public void createItemSkuList(Long itemId, List<WmsItemSkuSaveReqVO> skus) {
  39 + validateItemSkuList(skus);
  40 + List<WmsItemSkuDO> list = BeanUtils.toBean(skus, WmsItemSkuDO.class, sku -> sku.setItemId(itemId));
  41 + if (CollUtil.isNotEmpty(convertList(list, WmsItemSkuDO::getId))) {
  42 + throw exception(ITEM_SKU_NOT_EXISTS);
  43 + }
  44 + fillEmptyBarCode(list);
  45 + itemSkuMapper.insertBatch(list);
  46 + }
  47 +
  48 + @Override
  49 + @Transactional(rollbackFor = Exception.class)
  50 + public void updateItemSkuList(Long itemId, List<WmsItemSkuSaveReqVO> skus) {
  51 + validateItemSkuList(skus);
  52 +
  53 + // 第一步,对比新老数据,获得添加、修改、删除的列表
  54 + List<WmsItemSkuDO> oldList = itemSkuMapper.selectListByItemId(itemId);
  55 + List<WmsItemSkuDO> newList = BeanUtils.toBean(skus, WmsItemSkuDO.class);
  56 + List<List<WmsItemSkuDO>> diffList = diffList(oldList, newList, // id 不同,就认为是不同的记录
  57 + (oldVal, newVal) -> oldVal.getId().equals(newVal.getId()));
  58 +
  59 + // 第二步,批量添加、修改、删除
  60 + if (CollUtil.isNotEmpty(diffList.get(2))) {
  61 + // TODO 库存模块实现后,校验商品规格下不存在库存业务数据后再删除
  62 + itemSkuMapper.deleteByIds(convertList(diffList.get(2), WmsItemSkuDO::getId));
  63 + }
  64 + if (CollUtil.isNotEmpty(diffList.get(0))) {
  65 + if (CollUtil.isNotEmpty(convertList(diffList.get(0), WmsItemSkuDO::getId))) {
  66 + throw exception(ITEM_SKU_NOT_EXISTS);
  67 + }
  68 + diffList.get(0).forEach(sku -> sku.setItemId(itemId));
  69 + fillEmptyBarCode(diffList.get(0));
  70 + itemSkuMapper.insertBatch(diffList.get(0));
  71 + }
  72 + if (CollUtil.isNotEmpty(diffList.get(1))) {
  73 + diffList.get(1).forEach(sku -> sku.setItemId(itemId));
  74 + fillEmptyBarCode(diffList.get(1));
  75 + itemSkuMapper.updateBatch(diffList.get(1));
  76 + }
  77 + }
  78 +
  79 + @Override
  80 + @Transactional(rollbackFor = Exception.class)
  81 + public void deleteItemSkuListByItemId(Long itemId) {
  82 + // TODO 库存模块实现后,校验商品规格下不存在库存业务数据后再删除
  83 + itemSkuMapper.deleteByItemId(itemId);
  84 + }
  85 +
  86 + @Override
  87 + public List<WmsItemSkuDO> getItemSkuList(Long itemId) {
  88 + return itemSkuMapper.selectListByItemId(itemId);
  89 + }
  90 +
  91 + @Override
  92 + public List<WmsItemSkuDO> getItemSkuList(Collection<Long> itemIds) {
  93 + return itemSkuMapper.selectListByItemIds(itemIds);
  94 + }
  95 +
  96 + private void validateItemSkuList(List<WmsItemSkuSaveReqVO> skus) {
  97 + // 校验至少存在一个商品 SKU
  98 + if (CollUtil.isEmpty(skus)) {
  99 + throw exception(ITEM_SKU_REQUIRED);
  100 + }
  101 + // 校验 SKU 名称不重复
  102 + Set<String> names = new HashSet<>();
  103 + for (WmsItemSkuSaveReqVO sku : skus) {
  104 + if (!names.add(sku.getName())) {
  105 + throw exception(ITEM_SKU_NAME_DUPLICATE, sku.getName());
  106 + }
  107 + }
  108 + }
  109 +
  110 + /**
  111 + * 填充空的条形码
  112 + *
  113 + * @param skus 商品 SKU 列表
  114 + */
  115 + private void fillEmptyBarCode(List<WmsItemSkuDO> skus) {
  116 + skus.forEach(sku -> {
  117 + if (StrUtil.isBlank(sku.getBarCode())) {
  118 + sku.setBarCode(WmsUtils.generateBarCode());
  119 + }
  120 + });
  121 + }
  122 +
  123 +}
yudao-module-wms/src/main/java/cn/iocoder/yudao/module/wms/util/WmsUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.wms.util;
  2 +
  3 +import cn.hutool.core.util.RandomUtil;
  4 +import lombok.experimental.UtilityClass;
  5 +
  6 +/**
  7 + * WMS 工具类
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +@UtilityClass
  12 +public class WmsUtils {
  13 +
  14 + private static final int BAR_CODE_LENGTH = 8;
  15 +
  16 + /**
  17 + * 生成条码
  18 + *
  19 + * @return 条码
  20 + */
  21 + public String generateBarCode() {
  22 + return RandomUtil.randomNumbers(BAR_CODE_LENGTH);
  23 + }
  24 +
  25 +}