Commit 256280e8ba8ddf38bc732eade38aaf1d7111fe34

Authored by 芋道源码
Committed by GitHub
2 parents 1acee063 9b991488

Merge pull request #1242 from dadiyang/fix/product-delete-reference-check

[BUG] CRM/ERP:产品删除无引用校验——被业务单据引用的产品可被直接软删,留下悬空引用
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/enums/ErrorCodeConstants.java
@@ -81,6 +81,8 @@ public interface ErrorCodeConstants { @@ -81,6 +81,8 @@ public interface ErrorCodeConstants {
81 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在"); 81 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_020_008_000, "产品不存在");
82 ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在"); 82 ErrorCode PRODUCT_NO_EXISTS = new ErrorCode(1_020_008_001, "产品编号已存在");
83 ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用"); 83 ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_020_008_002, "产品【{}】已禁用");
  84 + ErrorCode PRODUCT_DELETE_FAIL_CONTRACT_EXISTS = new ErrorCode(1_020_008_003, "产品已被合同引用,无法删除");
  85 + ErrorCode PRODUCT_DELETE_FAIL_BUSINESS_EXISTS = new ErrorCode(1_020_008_004, "产品已被商机引用,无法删除");
84 86
85 // ========== 产品分类 1_020_009_000 ========== 87 // ========== 产品分类 1_020_009_000 ==========
86 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在"); 88 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_020_009_000, "产品分类不存在");
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java
@@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; @@ -5,8 +5,12 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO; 6 import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
7 import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO; 7 import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductSaveReqVO;
  8 +import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessProductDO;
  9 +import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractProductDO;
8 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO; 10 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO;
9 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO; 11 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductDO;
  12 +import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessProductMapper;
  13 +import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractProductMapper;
10 import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper; 14 import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper;
11 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; 15 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
12 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum; 16 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
@@ -49,6 +53,10 @@ public class CrmProductServiceImpl implements CrmProductService { @@ -49,6 +53,10 @@ public class CrmProductServiceImpl implements CrmProductService {
49 @Resource 53 @Resource
50 private CrmProductCategoryService productCategoryService; 54 private CrmProductCategoryService productCategoryService;
51 @Resource 55 @Resource
  56 + private CrmContractProductMapper contractProductMapper;
  57 + @Resource
  58 + private CrmBusinessProductMapper businessProductMapper;
  59 + @Resource
52 private CrmPermissionService permissionService; 60 private CrmPermissionService permissionService;
53 61
54 @Resource 62 @Resource
@@ -128,6 +136,13 @@ public class CrmProductServiceImpl implements CrmProductService { @@ -128,6 +136,13 @@ public class CrmProductServiceImpl implements CrmProductService {
128 public void deleteProduct(Long id) { 136 public void deleteProduct(Long id) {
129 // 校验存在 137 // 校验存在
130 validateProductExists(id); 138 validateProductExists(id);
  139 + // 校验未被合同/商机引用,避免删除后产生悬空引用
  140 + if (contractProductMapper.selectCount(CrmContractProductDO::getProductId, id) > 0) {
  141 + throw exception(PRODUCT_DELETE_FAIL_CONTRACT_EXISTS);
  142 + }
  143 + if (businessProductMapper.selectCount(CrmBusinessProductDO::getProductId, id) > 0) {
  144 + throw exception(PRODUCT_DELETE_FAIL_BUSINESS_EXISTS);
  145 + }
131 // 删除 146 // 删除
132 productMapper.deleteById(id); 147 productMapper.deleteById(id);
133 } 148 }
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/enums/ErrorCodeConstants.java
@@ -130,6 +130,12 @@ ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_00 @@ -130,6 +130,12 @@ ErrorCode PURCHASE_ORDER_ITEM_RETURN_FAIL_IN_EXCEED = new ErrorCode(1_030_101_00
130 // ========== ERP 产品 1-030-500-000 ========== 130 // ========== ERP 产品 1-030-500-000 ==========
131 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在"); 131 ErrorCode PRODUCT_NOT_EXISTS = new ErrorCode(1_030_500_000, "产品不存在");
132 ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用"); 132 ErrorCode PRODUCT_NOT_ENABLE = new ErrorCode(1_030_500_001, "产品({})未启用");
  133 + ErrorCode PRODUCT_DELETE_FAIL_PURCHASE_ORDER_EXISTS = new ErrorCode(1_030_500_002, "产品已被采购订单引用,无法删除");
  134 + ErrorCode PRODUCT_DELETE_FAIL_PURCHASE_IN_EXISTS = new ErrorCode(1_030_500_003, "产品已被采购入库单引用,无法删除");
  135 + ErrorCode PRODUCT_DELETE_FAIL_PURCHASE_RETURN_EXISTS = new ErrorCode(1_030_500_004, "产品已被采购退货单引用,无法删除");
  136 + ErrorCode PRODUCT_DELETE_FAIL_SALE_ORDER_EXISTS = new ErrorCode(1_030_500_005, "产品已被销售订单引用,无法删除");
  137 + ErrorCode PRODUCT_DELETE_FAIL_SALE_OUT_EXISTS = new ErrorCode(1_030_500_006, "产品已被销售出库单引用,无法删除");
  138 + ErrorCode PRODUCT_DELETE_FAIL_SALE_RETURN_EXISTS = new ErrorCode(1_030_500_007, "产品已被销售退货单引用,无法删除");
133 139
134 // ========== ERP 产品分类 1-030-501-000 ========== 140 // ========== ERP 产品分类 1-030-501-000 ==========
135 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在"); 141 ErrorCode PRODUCT_CATEGORY_NOT_EXISTS = new ErrorCode(1_030_501_000, "产品分类不存在");
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
@@ -11,7 +11,19 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSa @@ -11,7 +11,19 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSa
11 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO; 11 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
12 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO; 12 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
13 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO; 13 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductUnitDO;
  14 +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseInItemDO;
  15 +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
  16 +import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseReturnItemDO;
  17 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOrderItemDO;
  18 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleOutItemDO;
  19 +import cn.iocoder.yudao.module.erp.dal.dataobject.sale.ErpSaleReturnItemDO;
14 import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper; 20 import cn.iocoder.yudao.module.erp.dal.mysql.product.ErpProductMapper;
  21 +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseInItemMapper;
  22 +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseOrderItemMapper;
  23 +import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseReturnItemMapper;
  24 +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOrderItemMapper;
  25 +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleOutItemMapper;
  26 +import cn.iocoder.yudao.module.erp.dal.mysql.sale.ErpSaleReturnItemMapper;
15 import jakarta.annotation.Resource; 27 import jakarta.annotation.Resource;
16 import org.springframework.stereotype.Service; 28 import org.springframework.stereotype.Service;
17 import org.springframework.validation.annotation.Validated; 29 import org.springframework.validation.annotation.Validated;
@@ -38,6 +50,18 @@ public class ErpProductServiceImpl implements ErpProductService { @@ -38,6 +50,18 @@ public class ErpProductServiceImpl implements ErpProductService {
38 private ErpProductCategoryService productCategoryService; 50 private ErpProductCategoryService productCategoryService;
39 @Resource 51 @Resource
40 private ErpProductUnitService productUnitService; 52 private ErpProductUnitService productUnitService;
  53 + @Resource
  54 + private ErpPurchaseOrderItemMapper purchaseOrderItemMapper;
  55 + @Resource
  56 + private ErpPurchaseInItemMapper purchaseInItemMapper;
  57 + @Resource
  58 + private ErpPurchaseReturnItemMapper purchaseReturnItemMapper;
  59 + @Resource
  60 + private ErpSaleOrderItemMapper saleOrderItemMapper;
  61 + @Resource
  62 + private ErpSaleOutItemMapper saleOutItemMapper;
  63 + @Resource
  64 + private ErpSaleReturnItemMapper saleReturnItemMapper;
41 65
42 @Override 66 @Override
43 public Long createProduct(ProductSaveReqVO createReqVO) { 67 public Long createProduct(ProductSaveReqVO createReqVO) {
@@ -63,6 +87,25 @@ public class ErpProductServiceImpl implements ErpProductService { @@ -63,6 +87,25 @@ public class ErpProductServiceImpl implements ErpProductService {
63 public void deleteProduct(Long id) { 87 public void deleteProduct(Long id) {
64 // 校验存在 88 // 校验存在
65 validateProductExists(id); 89 validateProductExists(id);
  90 + // 校验未被任何业务单据明细引用,避免删除后产生悬空引用
  91 + if (purchaseOrderItemMapper.selectCount(ErpPurchaseOrderItemDO::getProductId, id) > 0) {
  92 + throw exception(PRODUCT_DELETE_FAIL_PURCHASE_ORDER_EXISTS);
  93 + }
  94 + if (purchaseInItemMapper.selectCount(ErpPurchaseInItemDO::getProductId, id) > 0) {
  95 + throw exception(PRODUCT_DELETE_FAIL_PURCHASE_IN_EXISTS);
  96 + }
  97 + if (purchaseReturnItemMapper.selectCount(ErpPurchaseReturnItemDO::getProductId, id) > 0) {
  98 + throw exception(PRODUCT_DELETE_FAIL_PURCHASE_RETURN_EXISTS);
  99 + }
  100 + if (saleOrderItemMapper.selectCount(ErpSaleOrderItemDO::getProductId, id) > 0) {
  101 + throw exception(PRODUCT_DELETE_FAIL_SALE_ORDER_EXISTS);
  102 + }
  103 + if (saleOutItemMapper.selectCount(ErpSaleOutItemDO::getProductId, id) > 0) {
  104 + throw exception(PRODUCT_DELETE_FAIL_SALE_OUT_EXISTS);
  105 + }
  106 + if (saleReturnItemMapper.selectCount(ErpSaleReturnItemDO::getProductId, id) > 0) {
  107 + throw exception(PRODUCT_DELETE_FAIL_SALE_RETURN_EXISTS);
  108 + }
66 // 删除 109 // 删除
67 productMapper.deleteById(id); 110 productMapper.deleteById(id);
68 } 111 }