Commit 9f3b274ba9fa0e1637301a7573ac65e979c468a5

Authored by YunaiV
1 parent 13fd48ee

[BUG] CRM/ERP:产品删除无引用校验——被业务单据引用的产品可被直接软删,留下悬空引用 #1242

Showing 18 changed files with 145 additions and 38 deletions
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessService.java
... ... @@ -165,6 +165,14 @@ public interface CrmBusinessService {
165 165 Long getBusinessCountByCustomerId(Long customerId);
166 166  
167 167 /**
  168 + * 获得引用指定产品的商机产品数量
  169 + *
  170 + * @param productId 产品编号
  171 + * @return 数量
  172 + */
  173 + Long getBusinessProductCountByProductId(Long productId);
  174 +
  175 + /**
168 176 * 获得使用指定商机状态组的商机数量
169 177 *
170 178 * @param statusTypeId 商机状态组编号
... ...
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/business/CrmBusinessServiceImpl.java
... ... @@ -376,6 +376,11 @@ public class CrmBusinessServiceImpl implements CrmBusinessService {
376 376 }
377 377  
378 378 @Override
  379 + public Long getBusinessProductCountByProductId(Long productId) {
  380 + return businessProductMapper.selectCount(CrmBusinessProductDO::getProductId, productId);
  381 + }
  382 +
  383 + @Override
379 384 public Long getBusinessCountByStatusTypeId(Long statusTypeId) {
380 385 return businessMapper.selectCountByStatusTypeId(statusTypeId);
381 386 }
... ...
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractService.java
... ... @@ -178,6 +178,14 @@ public interface CrmContractService {
178 178 List<CrmContractProductDO> getContractProductListByContractId(Long contactId);
179 179  
180 180 /**
  181 + * 获得引用指定产品的合同产品数量
  182 + *
  183 + * @param productId 产品编号
  184 + * @return 数量
  185 + */
  186 + Long getContractProductCountByProductId(Long productId);
  187 +
  188 + /**
181 189 * 获得待审核合同数量
182 190 *
183 191 * @param userId 用户编号
... ...
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/contract/CrmContractServiceImpl.java
... ... @@ -395,6 +395,11 @@ public class CrmContractServiceImpl implements CrmContractService {
395 395 }
396 396  
397 397 @Override
  398 + public Long getContractProductCountByProductId(Long productId) {
  399 + return contractProductMapper.selectCount(CrmContractProductDO::getProductId, productId);
  400 + }
  401 +
  402 + @Override
398 403 public Long getAuditContractCount(Long userId) {
399 404 return contractMapper.selectCountByAudit(userId);
400 405 }
... ...
yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/service/product/CrmProductServiceImpl.java
... ... @@ -5,17 +5,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
6 6 import cn.iocoder.yudao.module.crm.controller.admin.product.vo.product.CrmProductPageReqVO;
7 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;
10 8 import cn.iocoder.yudao.module.crm.dal.dataobject.product.CrmProductCategoryDO;
11 9 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;
14 10 import cn.iocoder.yudao.module.crm.dal.mysql.product.CrmProductMapper;
15 11 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
16 12 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
17 13 import cn.iocoder.yudao.module.crm.enums.product.CrmProductStatusEnum;
18 14 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
  15 +import cn.iocoder.yudao.module.crm.service.business.CrmBusinessService;
  16 +import cn.iocoder.yudao.module.crm.service.contract.CrmContractService;
19 17 import cn.iocoder.yudao.module.crm.service.permission.CrmPermissionService;
20 18 import cn.iocoder.yudao.module.crm.service.permission.bo.CrmPermissionCreateReqBO;
21 19 import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
... ... @@ -23,6 +21,7 @@ import com.mzt.logapi.context.LogRecordContext;
23 21 import com.mzt.logapi.service.impl.DiffParseFunction;
24 22 import com.mzt.logapi.starter.annotation.LogRecord;
25 23 import jakarta.annotation.Resource;
  24 +import org.springframework.context.annotation.Lazy;
26 25 import org.springframework.stereotype.Service;
27 26 import org.springframework.transaction.annotation.Transactional;
28 27 import org.springframework.validation.annotation.Validated;
... ... @@ -53,9 +52,11 @@ public class CrmProductServiceImpl implements CrmProductService {
53 52 @Resource
54 53 private CrmProductCategoryService productCategoryService;
55 54 @Resource
56   - private CrmContractProductMapper contractProductMapper;
  55 + @Lazy // 延迟加载,避免循环依赖
  56 + private CrmContractService contractService;
57 57 @Resource
58   - private CrmBusinessProductMapper businessProductMapper;
  58 + @Lazy // 延迟加载,避免循环依赖
  59 + private CrmBusinessService businessService;
59 60 @Resource
60 61 private CrmPermissionService permissionService;
61 62  
... ... @@ -137,12 +138,13 @@ public class CrmProductServiceImpl implements CrmProductService {
137 138 // 校验存在
138 139 validateProductExists(id);
139 140 // 校验未被合同/商机引用,避免删除后产生悬空引用
140   - if (contractProductMapper.selectCount(CrmContractProductDO::getProductId, id) > 0) {
  141 + if (contractService.getContractProductCountByProductId(id) > 0) {
141 142 throw exception(PRODUCT_DELETE_FAIL_CONTRACT_EXISTS);
142 143 }
143   - if (businessProductMapper.selectCount(CrmBusinessProductDO::getProductId, id) > 0) {
  144 + if (businessService.getBusinessProductCountByProductId(id) > 0) {
144 145 throw exception(PRODUCT_DELETE_FAIL_BUSINESS_EXISTS);
145 146 }
  147 +
146 148 // 删除
147 149 productMapper.deleteById(id);
148 150 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/product/ErpProductServiceImpl.java
... ... @@ -11,20 +11,15 @@ import cn.iocoder.yudao.module.erp.controller.admin.product.vo.product.ProductSa
11 11 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductCategoryDO;
12 12 import cn.iocoder.yudao.module.erp.dal.dataobject.product.ErpProductDO;
13 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;
20 14 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 cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseInService;
  16 +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseOrderService;
  17 +import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchaseReturnService;
  18 +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOrderService;
  19 +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleOutService;
  20 +import cn.iocoder.yudao.module.erp.service.sale.ErpSaleReturnService;
27 21 import jakarta.annotation.Resource;
  22 +import org.springframework.context.annotation.Lazy;
28 23 import org.springframework.stereotype.Service;
29 24 import org.springframework.validation.annotation.Validated;
30 25  
... ... @@ -51,17 +46,23 @@ public class ErpProductServiceImpl implements ErpProductService {
51 46 @Resource
52 47 private ErpProductUnitService productUnitService;
53 48 @Resource
54   - private ErpPurchaseOrderItemMapper purchaseOrderItemMapper;
  49 + @Lazy // 延迟加载,避免循环依赖
  50 + private ErpPurchaseOrderService purchaseOrderService;
55 51 @Resource
56   - private ErpPurchaseInItemMapper purchaseInItemMapper;
  52 + @Lazy // 延迟加载,避免循环依赖
  53 + private ErpPurchaseInService purchaseInService;
57 54 @Resource
58   - private ErpPurchaseReturnItemMapper purchaseReturnItemMapper;
  55 + @Lazy // 延迟加载,避免循环依赖
  56 + private ErpPurchaseReturnService purchaseReturnService;
59 57 @Resource
60   - private ErpSaleOrderItemMapper saleOrderItemMapper;
  58 + @Lazy // 延迟加载,避免循环依赖
  59 + private ErpSaleOrderService saleOrderService;
61 60 @Resource
62   - private ErpSaleOutItemMapper saleOutItemMapper;
  61 + @Lazy // 延迟加载,避免循环依赖
  62 + private ErpSaleOutService saleOutService;
63 63 @Resource
64   - private ErpSaleReturnItemMapper saleReturnItemMapper;
  64 + @Lazy // 延迟加载,避免循环依赖
  65 + private ErpSaleReturnService saleReturnService;
65 66  
66 67 @Override
67 68 public Long createProduct(ProductSaveReqVO createReqVO) {
... ... @@ -88,22 +89,22 @@ public class ErpProductServiceImpl implements ErpProductService {
88 89 // 校验存在
89 90 validateProductExists(id);
90 91 // 校验未被任何业务单据明细引用,避免删除后产生悬空引用
91   - if (purchaseOrderItemMapper.selectCount(ErpPurchaseOrderItemDO::getProductId, id) > 0) {
  92 + if (purchaseOrderService.getPurchaseOrderItemCountByProductId(id) > 0) {
92 93 throw exception(PRODUCT_DELETE_FAIL_PURCHASE_ORDER_EXISTS);
93 94 }
94   - if (purchaseInItemMapper.selectCount(ErpPurchaseInItemDO::getProductId, id) > 0) {
  95 + if (purchaseInService.getPurchaseInItemCountByProductId(id) > 0) {
95 96 throw exception(PRODUCT_DELETE_FAIL_PURCHASE_IN_EXISTS);
96 97 }
97   - if (purchaseReturnItemMapper.selectCount(ErpPurchaseReturnItemDO::getProductId, id) > 0) {
  98 + if (purchaseReturnService.getPurchaseReturnItemCountByProductId(id) > 0) {
98 99 throw exception(PRODUCT_DELETE_FAIL_PURCHASE_RETURN_EXISTS);
99 100 }
100   - if (saleOrderItemMapper.selectCount(ErpSaleOrderItemDO::getProductId, id) > 0) {
  101 + if (saleOrderService.getSaleOrderItemCountByProductId(id) > 0) {
101 102 throw exception(PRODUCT_DELETE_FAIL_SALE_ORDER_EXISTS);
102 103 }
103   - if (saleOutItemMapper.selectCount(ErpSaleOutItemDO::getProductId, id) > 0) {
  104 + if (saleOutService.getSaleOutItemCountByProductId(id) > 0) {
104 105 throw exception(PRODUCT_DELETE_FAIL_SALE_OUT_EXISTS);
105 106 }
106   - if (saleReturnItemMapper.selectCount(ErpSaleReturnItemDO::getProductId, id) > 0) {
  107 + if (saleReturnService.getSaleReturnItemCountByProductId(id) > 0) {
107 108 throw exception(PRODUCT_DELETE_FAIL_SALE_RETURN_EXISTS);
108 109 }
109 110 // 删除
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInService.java
... ... @@ -98,4 +98,12 @@ public interface ErpPurchaseInService {
98 98 */
99 99 List<ErpPurchaseInItemDO> getPurchaseInItemListByInIds(Collection<Long> inIds);
100 100  
101   -}
102 101 \ No newline at end of file
  102 + /**
  103 + * 获得引用指定产品的采购入库项数量
  104 + *
  105 + * @param productId 产品编号
  106 + * @return 数量
  107 + */
  108 + Long getPurchaseInItemCountByProductId(Long productId);
  109 +
  110 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseInServiceImpl.java
... ... @@ -323,4 +323,9 @@ public class ErpPurchaseInServiceImpl implements ErpPurchaseInService {
323 323 return purchaseInItemMapper.selectListByInIds(inIds);
324 324 }
325 325  
  326 + @Override
  327 + public Long getPurchaseInItemCountByProductId(Long productId) {
  328 + return purchaseInItemMapper.selectCount(ErpPurchaseInItemDO::getProductId, productId);
  329 + }
  330 +
326 331 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderService.java
... ... @@ -107,4 +107,12 @@ public interface ErpPurchaseOrderService {
107 107 */
108 108 List<ErpPurchaseOrderItemDO> getPurchaseOrderItemListByOrderIds(Collection<Long> orderIds);
109 109  
110   -}
111 110 \ No newline at end of file
  111 + /**
  112 + * 获得引用指定产品的采购订单项数量
  113 + *
  114 + * @param productId 产品编号
  115 + * @return 数量
  116 + */
  117 + Long getPurchaseOrderItemCountByProductId(Long productId);
  118 +
  119 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseOrderServiceImpl.java
... ... @@ -292,4 +292,9 @@ public class ErpPurchaseOrderServiceImpl implements ErpPurchaseOrderService {
292 292 return purchaseOrderItemMapper.selectListByOrderIds(orderIds);
293 293 }
294 294  
  295 + @Override
  296 + public Long getPurchaseOrderItemCountByProductId(Long productId) {
  297 + return purchaseOrderItemMapper.selectCount(ErpPurchaseOrderItemDO::getProductId, productId);
  298 + }
  299 +
295 300 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnService.java
... ... @@ -98,4 +98,12 @@ public interface ErpPurchaseReturnService {
98 98 */
99 99 List<ErpPurchaseReturnItemDO> getPurchaseReturnItemListByReturnIds(Collection<Long> returnIds);
100 100  
101   -}
102 101 \ No newline at end of file
  102 + /**
  103 + * 获得引用指定产品的采购退货项数量
  104 + *
  105 + * @param productId 产品编号
  106 + * @return 数量
  107 + */
  108 + Long getPurchaseReturnItemCountByProductId(Long productId);
  109 +
  110 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/purchase/ErpPurchaseReturnServiceImpl.java
... ... @@ -301,4 +301,9 @@ public class ErpPurchaseReturnServiceImpl implements ErpPurchaseReturnService {
301 301 return purchaseReturnItemMapper.selectListByReturnIds(returnIds);
302 302 }
303 303  
  304 + @Override
  305 + public Long getPurchaseReturnItemCountByProductId(Long productId) {
  306 + return purchaseReturnItemMapper.selectCount(ErpPurchaseReturnItemDO::getProductId, productId);
  307 + }
  308 +
304 309 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderService.java
... ... @@ -107,4 +107,12 @@ public interface ErpSaleOrderService {
107 107 */
108 108 List<ErpSaleOrderItemDO> getSaleOrderItemListByOrderIds(Collection<Long> orderIds);
109 109  
110   -}
111 110 \ No newline at end of file
  111 + /**
  112 + * 获得引用指定产品的销售订单项数量
  113 + *
  114 + * @param productId 产品编号
  115 + * @return 数量
  116 + */
  117 + Long getSaleOrderItemCountByProductId(Long productId);
  118 +
  119 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOrderServiceImpl.java
... ... @@ -304,4 +304,9 @@ public class ErpSaleOrderServiceImpl implements ErpSaleOrderService {
304 304 return saleOrderItemMapper.selectListByOrderIds(orderIds);
305 305 }
306 306  
  307 + @Override
  308 + public Long getSaleOrderItemCountByProductId(Long productId) {
  309 + return saleOrderItemMapper.selectCount(ErpSaleOrderItemDO::getProductId, productId);
  310 + }
  311 +
307 312 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutService.java
... ... @@ -99,4 +99,12 @@ public interface ErpSaleOutService {
99 99 List<ErpSaleOutItemDO> getSaleOutItemListByOutIds(Collection<Long> outIds);
100 100  
101 101  
102   -}
103 102 \ No newline at end of file
  103 + /**
  104 + * 获得引用指定产品的销售出库项数量
  105 + *
  106 + * @param productId 产品编号
  107 + * @return 数量
  108 + */
  109 + Long getSaleOutItemCountByProductId(Long productId);
  110 +
  111 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleOutServiceImpl.java
... ... @@ -313,4 +313,9 @@ public class ErpSaleOutServiceImpl implements ErpSaleOutService {
313 313 return saleOutItemMapper.selectListByOutIds(outIds);
314 314 }
315 315  
  316 + @Override
  317 + public Long getSaleOutItemCountByProductId(Long productId) {
  318 + return saleOutItemMapper.selectCount(ErpSaleOutItemDO::getProductId, productId);
  319 + }
  320 +
316 321 }
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnService.java
... ... @@ -98,4 +98,12 @@ public interface ErpSaleReturnService {
98 98 */
99 99 List<ErpSaleReturnItemDO> getSaleReturnItemListByReturnIds(Collection<Long> returnIds);
100 100  
101   -}
102 101 \ No newline at end of file
  102 + /**
  103 + * 获得引用指定产品的销售退货项数量
  104 + *
  105 + * @param productId 产品编号
  106 + * @return 数量
  107 + */
  108 + Long getSaleReturnItemCountByProductId(Long productId);
  109 +
  110 +}
... ...
yudao-module-erp/src/main/java/cn/iocoder/yudao/module/erp/service/sale/ErpSaleReturnServiceImpl.java
... ... @@ -313,4 +313,9 @@ public class ErpSaleReturnServiceImpl implements ErpSaleReturnService {
313 313 return saleReturnItemMapper.selectListByReturnIds(returnIds);
314 314 }
315 315  
  316 + @Override
  317 + public Long getSaleReturnItemCountByProductId(Long productId) {
  318 + return saleReturnItemMapper.selectCount(ErpSaleReturnItemDO::getProductId, productId);
  319 + }
  320 +
316 321 }
... ...