瀏覽代碼

✨ ERP:完成 product 信息、分类、单位的实现

YunaiV 1 年之前
父節點
當前提交
a36ae0c469
共有 18 個文件被更改,包括 255 次插入54 次删除
  1. 3 0
      yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java
  2. 20 9
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java
  3. 31 4
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java
  4. 9 0
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java
  5. 7 3
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java
  6. 5 4
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java
  7. 0 9
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java
  8. 3 2
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java
  9. 3 0
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java
  10. 2 2
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java
  11. 8 0
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java
  12. 10 1
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java
  13. 24 2
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java
  14. 18 3
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java
  15. 16 0
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java
  16. 10 0
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
  17. 34 2
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java
  18. 52 13
      yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java

+ 3 - 0
yudao-module-erp/yudao-module-erp-api/src/main/java/cn/iocoder/yudao/module/erp/ErrorCodeConstants.java

@@ -19,8 +19,11 @@ public interface ErrorCodeConstants {
     ErrorCode PRODUCT_CATEGORY_PARENT_ERROR = new ErrorCode(1_030_501_003, "不能设置自己为父产品分类");
     ErrorCode PRODUCT_CATEGORY_NAME_DUPLICATE = new ErrorCode(1_030_501_004, "已经存在该分类名称的产品分类");
     ErrorCode PRODUCT_CATEGORY_PARENT_IS_CHILD = new ErrorCode(1_030_501_005, "不能设置自己的子分类为父分类");
+    ErrorCode PRODUCT_CATEGORY_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该分类,无法删除");
 
     // ========== ERP 产品单位 1-030-502-000 ==========
     ErrorCode PRODUCT_UNIT_NOT_EXISTS = new ErrorCode(1_030_502_000, "产品单位不存在");
+    ErrorCode PRODUCT_UNIT_NAME_DUPLICATE = new ErrorCode(1_030_502_001, "已存在该名字的产品单位");
+    ErrorCode PRODUCT_UNIT_EXITS_PRODUCT = new ErrorCode(1_030_502_002, "存在产品使用该单位,无法删除");
 
 }

+ 20 - 9
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductCategoryController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
@@ -23,6 +24,7 @@ import java.io.IOException;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Tag(name = "管理后台 - ERP 产品分类")
@@ -35,14 +37,14 @@ public class ErpProductCategoryController {
     private ErpProductCategoryService productCategoryService;
 
     @PostMapping("/create")
-    @Operation(summary = "创建ERP 产品分类")
+    @Operation(summary = "创建产品分类")
     @PreAuthorize("@ss.hasPermission('erp:product-category:create')")
     public CommonResult<Long> createProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO createReqVO) {
         return success(productCategoryService.createProductCategory(createReqVO));
     }
 
     @PutMapping("/update")
-    @Operation(summary = "更新ERP 产品分类")
+    @Operation(summary = "更新产品分类")
     @PreAuthorize("@ss.hasPermission('erp:product-category:update')")
     public CommonResult<Boolean> updateProductCategory(@Valid @RequestBody ErpProductCategorySaveReqVO updateReqVO) {
         productCategoryService.updateProductCategory(updateReqVO);
@@ -50,7 +52,7 @@ public class ErpProductCategoryController {
     }
 
     @DeleteMapping("/delete")
-    @Operation(summary = "删除ERP 产品分类")
+    @Operation(summary = "删除产品分类")
     @Parameter(name = "id", description = "编号", required = true)
     @PreAuthorize("@ss.hasPermission('erp:product-category:delete')")
     public CommonResult<Boolean> deleteProductCategory(@RequestParam("id") Long id) {
@@ -59,31 +61,40 @@ public class ErpProductCategoryController {
     }
 
     @GetMapping("/get")
-    @Operation(summary = "获得ERP 产品分类")
+    @Operation(summary = "获得产品分类")
     @Parameter(name = "id", description = "编号", required = true, example = "1024")
     @PreAuthorize("@ss.hasPermission('erp:product-category:query')")
     public CommonResult<ErpProductCategoryRespVO> getProductCategory(@RequestParam("id") Long id) {
-        ErpProductCategoryDO productCategory = productCategoryService.getProductCategory(id);
-        return success(BeanUtils.toBean(productCategory, ErpProductCategoryRespVO.class));
+        ErpProductCategoryDO category = productCategoryService.getProductCategory(id);
+        return success(BeanUtils.toBean(category, ErpProductCategoryRespVO.class));
     }
 
     @GetMapping("/list")
-    @Operation(summary = "获得ERP 产品分类列表")
+    @Operation(summary = "获得产品分类列表")
     @PreAuthorize("@ss.hasPermission('erp:product-category:query')")
     public CommonResult<List<ErpProductCategoryRespVO>> getProductCategoryList(@Valid ErpProductCategoryListReqVO listReqVO) {
         List<ErpProductCategoryDO> list = productCategoryService.getProductCategoryList(listReqVO);
         return success(BeanUtils.toBean(list, ErpProductCategoryRespVO.class));
     }
 
+    @GetMapping("/simple-list")
+    @Operation(summary = "获得产品分类精简列表", description = "只包含被开启的分类,主要用于前端的下拉选项")
+    public CommonResult<List<ErpProductCategoryRespVO>> getProductCategorySimpleList() {
+        List<ErpProductCategoryDO> list = productCategoryService.getProductCategoryList(
+                new ErpProductCategoryListReqVO().setStatus(CommonStatusEnum.ENABLE.getStatus()));
+        return success(convertList(list, category -> new ErpProductCategoryRespVO()
+                .setId(category.getId()).setName(category.getName()).setParentId(category.getParentId())));
+    }
+
     @GetMapping("/export-excel")
-    @Operation(summary = "导出ERP 产品分类 Excel")
+    @Operation(summary = "导出产品分类 Excel")
     @PreAuthorize("@ss.hasPermission('erp:product-category:export')")
     @OperateLog(type = EXPORT)
     public void exportProductCategoryExcel(@Valid ErpProductCategoryListReqVO listReqVO,
               HttpServletResponse response) throws IOException {
         List<ErpProductCategoryDO> list = productCategoryService.getProductCategoryList(listReqVO);
         // 导出 Excel
-        ExcelUtils.write(response, "ERP 产品分类.xls", "数据", ErpProductCategoryRespVO.class,
+        ExcelUtils.write(response, "产品分类.xls", "数据", ErpProductCategoryRespVO.class,
                         BeanUtils.toBean(list, ErpProductCategoryRespVO.class));
     }
 

+ 31 - 4
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductController.java

@@ -1,16 +1,22 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product;
 
+import cn.hutool.core.collection.CollUtil;
 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.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductPageReqVO;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductRespVO;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSaveReqVO;
+import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
+import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
+import cn.iocoder.yudao.module.erp.service.product.ErpProductCategoryService;
 import cn.iocoder.yudao.module.erp.service.product.ErpProductService;
+import cn.iocoder.yudao.module.erp.service.product.ErpProductUnitService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -22,9 +28,10 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import java.io.IOException;
-import java.util.List;
+import java.util.Map;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Tag(name = "管理后台 - ERP 产品")
@@ -35,6 +42,10 @@ public class ErpProductController {
 
     @Resource
     private ErpProductService productService;
+    @Resource
+    private ErpProductCategoryService productCategoryService;
+    @Resource
+    private ErpProductUnitService productUnitService;
 
     @PostMapping("/create")
     @Operation(summary = "创建产品")
@@ -74,7 +85,7 @@ public class ErpProductController {
     @PreAuthorize("@ss.hasPermission('erp:product:query')")
     public CommonResult<PageResult<ProductRespVO>> getProductPage(@Valid ProductPageReqVO pageReqVO) {
         PageResult<ErpProductDO> pageResult = productService.getProductPage(pageReqVO);
-        return success(BeanUtils.toBean(pageResult, ProductRespVO.class));
+        return success(buildProductDetailPage(pageResult));
     }
 
     @GetMapping("/export-excel")
@@ -84,10 +95,26 @@ public class ErpProductController {
     public void exportProductExcel(@Valid ProductPageReqVO pageReqVO,
               HttpServletResponse response) throws IOException {
         pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
-        List<ErpProductDO> list = productService.getProductPage(pageReqVO).getList();
+        PageResult<ErpProductDO> pageResult = productService.getProductPage(pageReqVO);
         // 导出 Excel
         ExcelUtils.write(response, "产品.xls", "数据", ProductRespVO.class,
-                        BeanUtils.toBean(list, ProductRespVO.class));
+                        buildProductDetailPage(pageResult).getList());
+    }
+
+    private PageResult<ProductRespVO> buildProductDetailPage(PageResult<ErpProductDO> pageResult) {
+        if (CollUtil.isEmpty(pageResult.getList())) {
+            return PageResult.empty(pageResult.getTotal());
+        }
+        Map<Long, ErpProductCategoryDO> categoryMap = productCategoryService.getProductCategoryMap(
+                convertSet(pageResult.getList(), ErpProductDO::getCategoryId));
+        Map<Long, ErpProductUnitDO> unitMap = productUnitService.getProductUnitMap(
+                convertSet(pageResult.getList(), ErpProductDO::getUnitId));
+        return BeanUtils.toBean(pageResult, ProductRespVO.class, product -> {
+            MapUtils.findAndThen(categoryMap, product.getCategoryId(),
+                    category -> product.setCategoryName(category.getName()));
+            MapUtils.findAndThen(unitMap, product.getUnitId(),
+                    unit -> product.setUnitName(unit.getName()));
+        });
     }
 
 }

+ 9 - 0
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/ErpProductUnitController.java

@@ -1,5 +1,6 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageParam;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
@@ -25,6 +26,7 @@ import java.io.IOException;
 import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
 
 @Tag(name = "管理后台 - ERP 产品单位")
@@ -77,6 +79,13 @@ public class ErpProductUnitController {
         return success(BeanUtils.toBean(pageResult, ErpProductUnitRespVO.class));
     }
 
+    @GetMapping("/simple-list")
+    @Operation(summary = "获得产品单位精简列表", description = "只包含被开启的单位,主要用于前端的下拉选项")
+    public CommonResult<List<ErpProductUnitRespVO>> getProductUnitSimpleList() {
+        List<ErpProductUnitDO> list = productUnitService.getProductUnitListByStatus(CommonStatusEnum.ENABLE.getStatus());
+        return success(convertList(list, unit -> new ErpProductUnitRespVO().setId(unit.getId()).setName(unit.getName())));
+    }
+
     @GetMapping("/export-excel")
     @Operation(summary = "导出产品单位 Excel")
     @PreAuthorize("@ss.hasPermission('erp:product-unit:export')")

+ 7 - 3
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductRespVO.java

@@ -26,12 +26,16 @@ public class ProductRespVO {
     private String barCode;
 
     @Schema(description = "产品分类编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11161")
-    @ExcelProperty("产品分类编号")
     private Long categoryId;
+    @Schema(description = "产品分类", requiredMode = Schema.RequiredMode.REQUIRED, example = "水果")
+    @ExcelProperty("产品分类")
+    private String categoryName;
 
     @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869")
-    @ExcelProperty("单位编号")
-    private Integer unitId;
+    private Long unitId;
+    @Schema(description = "单位", requiredMode = Schema.RequiredMode.REQUIRED, example = "个")
+    @ExcelProperty("单位")
+    private String unitName;
 
     @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @ExcelProperty("产品状态")

+ 5 - 4
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/product/ProductSaveReqVO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product.vo.product;
 
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import java.util.*;
-import jakarta.validation.constraints.*;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
 import java.math.BigDecimal;
 
 @Schema(description = "管理后台 - ERP 产品新增/修改 Request VO")
@@ -27,7 +28,7 @@ public class ProductSaveReqVO {
 
     @Schema(description = "单位编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "8869")
     @NotNull(message = "单位编号不能为空")
-    private Integer unitId;
+    private Long unitId;
 
     @Schema(description = "产品状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
     @NotNull(message = "产品状态不能为空")

+ 0 - 9
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitPageReqVO.java

@@ -5,11 +5,6 @@ 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 = "管理后台 - ERP 产品单位分页 Request VO")
 @Data
@@ -23,8 +18,4 @@ public class ErpProductUnitPageReqVO extends PageParam {
     @Schema(description = "单位状态", example = "1")
     private Integer status;
 
-    @Schema(description = "创建时间")
-    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
-    private LocalDateTime[] createTime;
-
 }

+ 3 - 2
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitRespVO.java

@@ -1,9 +1,10 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit;
 
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
 import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
 import com.alibaba.excel.annotation.ExcelProperty;
 import io.swagger.v3.oas.annotations.media.Schema;
-import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
 import java.time.LocalDateTime;
@@ -23,7 +24,7 @@ public class ErpProductUnitRespVO {
 
     @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @ExcelProperty("单位状态")
-    @NotNull(message = "分类排序不能为空")
+    @DictFormat(DictTypeConstants.COMMON_STATUS)
     private Integer status;
 
     @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)

+ 3 - 0
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/controller/admin/product/vo/unit/ErpProductUnitSaveReqVO.java

@@ -1,5 +1,7 @@
 package cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit;
 
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
@@ -18,6 +20,7 @@ public class ErpProductUnitSaveReqVO {
 
     @Schema(description = "单位状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "单位状态不能为空")
+    @InEnum(CommonStatusEnum.class)
     private Integer status;
 
 }

+ 2 - 2
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/dataobject/product/ErpProductDO.java

@@ -45,9 +45,9 @@ public class ErpProductDO extends BaseDO {
     /**
      * 单位编号
      *
-     * TODO 芋艿,关联
+     * 关联 {@link ErpProductUnitDO#getId()}
      */
-    private Integer unitId;
+    private Long unitId;
     /**
      * 产品状态
      *

+ 8 - 0
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductMapper.java

@@ -23,4 +23,12 @@ public interface ErpProductMapper extends BaseMapperX<ErpProductDO> {
                 .orderByDesc(ErpProductDO::getId));
     }
 
+    default Long selectCountByCategoryId(Long categoryId) {
+        return selectCount(ErpProductDO::getCategoryId, categoryId);
+    }
+
+    default Long selectCountByUnitId(Long unitId) {
+        return selectCount(ErpProductDO::getUnitId, unitId);
+    }
+
 }

+ 10 - 1
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/dal/mysql/product/ErpProductUnitMapper.java

@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUn
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.List;
+
 /**
  * ERP 产品单位 Mapper
  *
@@ -19,8 +21,15 @@ public interface ErpProductUnitMapper extends BaseMapperX<ErpProductUnitDO> {
         return selectPage(reqVO, new LambdaQueryWrapperX<ErpProductUnitDO>()
                 .likeIfPresent(ErpProductUnitDO::getName, reqVO.getName())
                 .eqIfPresent(ErpProductUnitDO::getStatus, reqVO.getStatus())
-                .betweenIfPresent(ErpProductUnitDO::getCreateTime, reqVO.getCreateTime())
                 .orderByDesc(ErpProductUnitDO::getId));
     }
 
+    default ErpProductUnitDO selectByName(String name) {
+        return selectOne(ErpProductUnitDO::getName, name);
+    }
+
+    default List<ErpProductUnitDO> selectListByStatus(Integer status) {
+        return selectList(ErpProductUnitDO::getStatus, status);
+    }
+
 }

+ 24 - 2
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryService.java

@@ -5,7 +5,11 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProdu
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
 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;
 
 /**
  * ERP 产品分类 Service 接口
@@ -40,7 +44,7 @@ public interface ErpProductCategoryService {
      * 获得产品分类
      *
      * @param id 编号
-     * @return ERP 产品分类
+     * @return 产品分类
      */
     ErpProductCategoryDO getProductCategory(Long id);
 
@@ -48,8 +52,26 @@ public interface ErpProductCategoryService {
      * 获得产品分类列表
      *
      * @param listReqVO 查询条件
-     * @return ERP 产品分类列表
+     * @return 产品分类列表
      */
     List<ErpProductCategoryDO> getProductCategoryList(ErpProductCategoryListReqVO listReqVO);
 
+    /**
+     * 获得产品分类列表
+     *
+     * @param ids 编号数组
+     * @return 产品分类列表
+     */
+    List<ErpProductCategoryDO> getProductCategoryList(Collection<Long> ids);
+
+    /**
+     * 获得产品分类 Map
+     *
+     * @param ids 编号数组
+     * @return 产品分类 Map
+     */
+    default Map<Long, ErpProductCategoryDO> getProductCategoryMap(Collection<Long> ids) {
+        return convertMap(getProductCategoryList(ids), ErpProductCategoryDO::getId);
+    }
+
 }

+ 18 - 3
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductCategoryServiceImpl.java

@@ -6,9 +6,11 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.category.ErpProdu
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
 import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductCategoryMapper;
 import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
 
@@ -27,6 +29,10 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService
     @Resource
     private ErpProductCategoryMapper productCategoryMapper;
 
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private ErpProductService productService;
+
     @Override
     public Long createProductCategory(ErpProductCategorySaveReqVO createReqVO) {
         // 校验父分类编号的有效性
@@ -57,13 +63,17 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService
 
     @Override
     public void deleteProductCategory(Long id) {
-        // 校验存在
+        // 1.1 校验存在
         validateProductCategoryExists(id);
-        // 校验是否有子产品分类
+        // 1.2 校验是否有子产品分类
         if (productCategoryMapper.selectCountByParentId(id) > 0) {
             throw exception(PRODUCT_CATEGORY_EXITS_CHILDREN);
         }
-        // 删除
+        // 1.3 校验是否有产品
+        if (productService.getProductCountByCategoryId(id) > 0) {
+            throw exception(PRODUCT_CATEGORY_EXITS_PRODUCT);
+        }
+        // 2. 删除
         productCategoryMapper.deleteById(id);
     }
 
@@ -131,4 +141,9 @@ public class ErpProductCategoryServiceImpl implements ErpProductCategoryService
         return productCategoryMapper.selectList(listReqVO);
     }
 
+    @Override
+    public List<ErpProductCategoryDO> getProductCategoryList(Collection<Long> ids) {
+        return productCategoryMapper.selectBatchIds(ids);
+    }
+
 }

+ 16 - 0
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductService.java

@@ -51,4 +51,20 @@ public interface ErpProductService {
      */
     PageResult<ErpProductDO> getProductPage(ProductPageReqVO pageReqVO);
 
+    /**
+     * 基于产品分类编号,获得产品数量
+     *
+     * @param categoryId 产品分类编号
+     * @return 产品数量
+     */
+    Long getProductCountByCategoryId(Long categoryId);
+
+    /**
+     * 基于产品单位编号,获得产品数量
+     *
+     * @param unitId 产品单位编号
+     * @return 产品数量
+     */
+    Long getProductCountByUnitId(Long unitId);
+
 }

+ 10 - 0
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java

@@ -69,4 +69,14 @@ public class ErpProductServiceImpl implements ErpProductService {
         return productMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public Long getProductCountByCategoryId(Long categoryId) {
+        return productMapper.selectCountByCategoryId(categoryId);
+    }
+
+    @Override
+    public Long getProductCountByUnitId(Long unitId) {
+        return productMapper.selectCountByUnitId(unitId);
+    }
+
 }

+ 34 - 2
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitService.java

@@ -1,10 +1,16 @@
 package cn.iocoder.yudao.module.erp.service.product;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO;
-import jakarta.validation.*;
 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
+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;
 
 /**
  * ERP 产品单位 Service 接口
@@ -51,4 +57,30 @@ public interface ErpProductUnitService {
      */
     PageResult<ErpProductUnitDO> getProductUnitPage(ErpProductUnitPageReqVO pageReqVO);
 
+    /**
+     * 获得指定状态的产品单位列表
+     *
+     * @param status 状态
+     * @return 产品单位列表
+     */
+    List<ErpProductUnitDO> getProductUnitListByStatus(Integer status);
+
+    /**
+     * 获得产品单位列表
+     *
+     * @param ids 编号数组
+     * @return 产品单位列表
+     */
+    List<ErpProductUnitDO> getProductUnitList(Collection<Long> ids);
+
+    /**
+     * 获得产品单位 Map
+     *
+     * @param ids 编号数组
+     * @return 产品单位 Map
+     */
+    default Map<Long, ErpProductUnitDO> getProductUnitMap(Collection<Long> ids) {
+        return convertMap(getProductUnitList(ids), ErpProductUnitDO::getId);
+    }
+
 }

+ 52 - 13
yudao-module-erp/yudao-module-erp-biz/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductUnitServiceImpl.java

@@ -1,19 +1,22 @@
 package cn.iocoder.yudao.module.erp.service.product;
 
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitPageReqVO;
 import cn.iocoder.yudao.module.erp.controller.admin.product.vo.unit.ErpProductUnitSaveReqVO;
-import org.springframework.stereotype.Service;
+import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
+import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper;
+import com.google.common.annotations.VisibleForTesting;
 import jakarta.annotation.Resource;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
-import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
-import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
-
-import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductUnitMapper;
+import java.util.Collection;
+import java.util.List;
 
 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
-import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.PRODUCT_UNIT_NOT_EXISTS;
+import static cn.iocoder.yudao.module.erp.ErrorCodeConstants.*;
 
 /**
  * ERP 产品单位 Service 实现类
@@ -27,29 +30,55 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService {
     @Resource
     private ErpProductUnitMapper productUnitMapper;
 
+    @Resource
+    @Lazy // 延迟加载,避免循环依赖
+    private ErpProductService productService;
+
     @Override
     public Long createProductUnit(ErpProductUnitSaveReqVO createReqVO) {
-        // 插入
+        // 1. 校验名字唯一
+        validateProductUnitNameUnique(null, createReqVO.getName());
+        // 2. 插入
         ErpProductUnitDO unit = BeanUtils.toBean(createReqVO, ErpProductUnitDO.class);
         productUnitMapper.insert(unit);
-        // 返回
         return unit.getId();
     }
 
     @Override
     public void updateProductUnit(ErpProductUnitSaveReqVO updateReqVO) {
-        // 校验存在
+        // 1.1 校验存在
         validateProductUnitExists(updateReqVO.getId());
-        // 更新
+        // 1.2 校验名字唯一
+        validateProductUnitNameUnique(updateReqVO.getId(), updateReqVO.getName());
+        // 2. 更新
         ErpProductUnitDO updateObj = BeanUtils.toBean(updateReqVO, ErpProductUnitDO.class);
         productUnitMapper.updateById(updateObj);
     }
 
+    @VisibleForTesting
+    void validateProductUnitNameUnique(Long id, String name) {
+        ErpProductUnitDO unit = productUnitMapper.selectByName(name);
+        if (unit == null) {
+            return;
+        }
+        // 如果 id 为空,说明不用比较是否为相同 id 的字典类型
+        if (id == null) {
+            throw exception(PRODUCT_UNIT_NAME_DUPLICATE);
+        }
+        if (!unit.getId().equals(id)) {
+            throw exception(PRODUCT_UNIT_NAME_DUPLICATE);
+        }
+    }
+
     @Override
     public void deleteProductUnit(Long id) {
-        // 校验存在
+        // 1.1 校验存在
         validateProductUnitExists(id);
-        // 删除
+        // 1.2 校验商品是否使用
+        if (productService.getProductCountByUnitId(id) > 0) {
+            throw exception(PRODUCT_UNIT_EXITS_PRODUCT);
+        }
+        // 2. 删除
         productUnitMapper.deleteById(id);
     }
 
@@ -69,4 +98,14 @@ public class ErpProductUnitServiceImpl implements ErpProductUnitService {
         return productUnitMapper.selectPage(pageReqVO);
     }
 
+    @Override
+    public List<ErpProductUnitDO> getProductUnitListByStatus(Integer status) {
+        return productUnitMapper.selectListByStatus(status);
+    }
+
+    @Override
+    public List<ErpProductUnitDO> getProductUnitList(Collection<Long> ids) {
+         return productUnitMapper.selectBatchIds(ids);
+    }
+
 }