From 8ad99e5f72085d14fd56e8faa7aa36701823c8b5 Mon Sep 17 00:00:00 2001
From: liu <2021943741@qq.com>
Date: 星期四, 05 十一月 2026 20:16:23 +0800
Subject: [PATCH] feat(crm): 统一客户团队数据权限并放开开票金额上限

---
 yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java |  232 ++++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 195 insertions(+), 37 deletions(-)

diff --git a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
index 5b23ae4..014708b 100644
--- a/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
+++ b/yudao-module-crm/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java
@@ -6,8 +6,22 @@
 import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
 import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.yudao.module.crm.dal.dataobject.business.CrmBusinessDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contact.CrmContactDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.contract.CrmContractDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.invoice.CrmInvoiceDO;
 import cn.iocoder.yudao.module.crm.dal.dataobject.permission.CrmPermissionDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.quotation.CrmSaleQuotationDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivableDO;
+import cn.iocoder.yudao.module.crm.dal.dataobject.receivable.CrmReceivablePlanDO;
 import cn.iocoder.yudao.module.crm.dal.mysql.business.CrmBusinessMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.contact.CrmContactMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.contract.CrmContractMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.invoice.CrmInvoiceMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.quotation.CrmSaleQuotationMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivableMapper;
+import cn.iocoder.yudao.module.crm.dal.mysql.receivable.CrmReceivablePlanMapper;
 import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum;
 import cn.iocoder.yudao.module.crm.enums.permission.CrmPermissionLevelEnum;
 import cn.iocoder.yudao.module.crm.framework.permission.core.annotations.CrmPermission;
@@ -48,6 +62,20 @@
 
     @Resource
     private CrmBusinessMapper businessMapper;
+    @Resource
+    private CrmContractMapper contractMapper;
+    @Resource
+    private CrmContactMapper contactMapper;
+    @Resource
+    private CrmCustomerMapper customerMapper;
+    @Resource
+    private CrmSaleQuotationMapper quotationMapper;
+    @Resource
+    private CrmReceivableMapper receivableMapper;
+    @Resource
+    private CrmReceivablePlanMapper receivablePlanMapper;
+    @Resource
+    private CrmInvoiceMapper invoiceMapper;
 
     @Before("@annotation(crmPermission)")
     public void doBefore(JoinPoint joinPoint, CrmPermission crmPermission) {
@@ -79,33 +107,37 @@
         if (CrmPermissionUtils.isCrmAdmin()) {
             return;
         }
-        // 鐗规畩锛氭病鏈夋暟鎹潈闄愮殑鎯呭喌锛岄拡瀵� READ 鐨勭壒娈婂鐞�
+        // 2. 鏁版嵁鏈韩鐨勮礋璐d汉锛氱洿鎺ラ�氳繃锛堝吋瀹规潈闄愯褰曠己澶辩殑鍘嗗彶鏁版嵁锛�
+        Long userId = getUserId();
+        if (isRecordOwner(bizType, bizId, userId)) {
+            return;
+        }
+        // 3. 鑱旂郴浜�/鍟嗘満/鍚堝悓/鎶ヤ环/鍥炴/鍥炴璁″垝/寮�绁細缁ф壙鎵�灞炲鎴风殑鏉冮檺
+        //    鏀惧湪銆屾棤鏁版嵁鏉冮檺銆嶅垽鏂箣鍓嶏紝閬垮厤鏉冮檺璁板綍缂哄け鐨勫巻鍙叉暟鎹鑷磋礋璐d汉鏃犳硶鍐欐搷浣�
+        if (validateCustomerPermission(bizType, bizId, userId, permissionLevel)) {
+            return;
+        }
+
+        // 3. 鐗规畩锛氭病鏈夋暟鎹潈闄愮殑鎯呭喌锛岄拡瀵� READ 鐨勭壒娈婂鐞�
         if (CollUtil.isEmpty(bizPermissions)) {
-            // 1.1 鍏捣鏁版嵁锛屽鏋滄病鏈夊洟闃熸垚鍛橈紝澶у涔熷簲璇ユ湁 READ 鏉冮檺鎵嶅
-            if (CrmPermissionLevelEnum.isRead(permissionLevel)) {
+            // 3.1 鐪熸鐨勫叕娴锋暟鎹紙鐖跺鎴蜂篃娌℃湁鍥㈤槦锛夛紝澶у鏈� READ 鏉冮檺锛�
+            //     濡傛灉鐖跺鎴锋湁鍥㈤槦锛屽垯璧颁笂闈㈢户鎵块�昏緫锛岃繖閲屼笉鑳芥斁琛岋紝閬垮厤瓒婃潈璇诲彇
+            if (CrmPermissionLevelEnum.isRead(permissionLevel) && !hasParentCustomerTeam(bizType, bizId)) {
                 return;
             }
             // 娌℃湁鏁版嵁鏉冮檺鐨勬儏鍐典笅瓒呭嚭浜嗚鏉冮檺鐩存帴鎶ラ敊锛岄伩鍏嶅悗闈㈡牎楠岀┖鎸囬拡
             throw exception(CRM_PERMISSION_DENIED, CrmBizTypeEnum.getNameByType(bizType));
-        } else { // 1.2 鏈夋暟鎹潈闄愪絾鏄病鏈夎礋璐d汉鐨勬儏鍐�
+        } else { // 3.2 鏈夋暟鎹潈闄愪絾鏄病鏈夎礋璐d汉鐨勬儏鍐�
             if (!anyMatch(bizPermissions, item -> CrmPermissionLevelEnum.isOwner(item.getLevel()))
                 && CrmPermissionLevelEnum.isRead(permissionLevel)) {
                 return;
             }
         }
 
-        // 2. 鍙�冭檻鑷韩鐨勬潈闄�
-        Long userId = getUserId();
+        // 4. 鍙�冭檻鑷韩鐨勬潈闄�
         CrmPermissionDO userPermission = CollUtil.findOne(bizPermissions, permission -> ObjUtil.equal(permission.getUserId(), userId));
         if (userPermission != null) {
             if (isUserPermissionValid(userPermission, permissionLevel)) {
-                return;
-            }
-        }
-
-        // 3. 鍟嗘満鐗规畩澶勭悊锛氭鏌ュ鎴峰洟闃熸潈闄�
-        if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
-            if (validateBusinessCustomerPermission(bizId, userId, permissionLevel)) {
                 return;
             }
         }
@@ -118,11 +150,9 @@
             if (subordinatePermission != null && isUserPermissionValid(subordinatePermission, permissionLevel)) {
                 return;
             }
-            // 鍟嗘満鐗规畩澶勭悊锛氭鏌ュ鎴峰洟闃熸潈闄愶紙涓嬪睘鐨勶級
-            if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
-                if (validateBusinessCustomerPermission(bizId, subordinateUserId, permissionLevel)) {
-                    return;
-                }
+            // 缁ф壙鎵�灞炲鎴风殑鏉冮檺锛堜笅灞炵殑锛�
+            if (validateCustomerPermission(bizType, bizId, subordinateUserId, permissionLevel)) {
+                return;
             }
         }
 
@@ -133,33 +163,161 @@
     }
 
     /**
-     * 鍟嗘満鐗规畩鏉冮檺鏍¢獙锛氭鏌ョ敤鎴锋槸鍚︽湁璇ュ晢鏈烘墍灞炲鎴风殑鍥㈤槦鏉冮檺
+     * 缁ф壙鎵�灞炲鎴风殑鏉冮檺鏍¢獙锛氬鎴疯礋璐d汉銆佸鎴峰洟闃熸垚鍛�
      *
-     * @param businessId     鍟嗘満缂栧彿
-     * @param userId         鐢ㄦ埛缂栧彿
+     * 閫傜敤浜庯細鑱旂郴浜恒�佸晢鏈恒�佸悎鍚屻�侀攢鍞姤浠枫�佸洖娆俱�佸洖娆捐鍒掋�佸紑绁�
+     *
+     * @param bizType         鏁版嵁绫诲瀷
+     * @param bizId           鏁版嵁缂栧彿
+     * @param userId          鐢ㄦ埛缂栧彿
      * @param permissionLevel 闇�瑕佺殑鏉冮檺绾у埆
      * @return 鏄惁鏈夋潈闄�
      */
-    private boolean validateBusinessCustomerPermission(Long businessId, Long userId, Integer permissionLevel) {
-        // 鑾峰彇鍟嗘満鐨勫鎴稩D
-        CrmBusinessDO business = businessMapper.selectById(businessId);
-        if (business == null || business.getCustomerId() == null) {
+    private boolean validateCustomerPermission(Integer bizType, Long bizId, Long userId, Integer permissionLevel) {
+        // 1. 鑾峰彇鎵�灞炲鎴�
+        Long customerId = getCustomerId(bizType, bizId);
+        if (customerId == null) {
             return false;
         }
-        // 妫�鏌ュ鎴峰洟闃熸潈闄�
-        List<CrmPermissionDO> customerPermissions = crmPermissionService.getPermissionListByBiz(
-                CrmBizTypeEnum.CRM_CUSTOMER.getType(), Collections.singleton(business.getCustomerId()));
-        if (CollUtil.isEmpty(customerPermissions)) {
-            // 瀹㈡埛鍏捣鏁版嵁锛孯EAD 鏉冮檺鏀捐
-            return CrmPermissionLevelEnum.isRead(permissionLevel);
-        }
-        // 妫�鏌ョ敤鎴锋槸鍚︽湁瀹㈡埛鍥㈤槦鐨勬潈闄�
-        CrmPermissionDO userCustomerPermission = CollUtil.findOne(customerPermissions,
-                permission -> ObjUtil.equal(permission.getUserId(), userId));
-        if (userCustomerPermission != null && isUserPermissionValid(userCustomerPermission, permissionLevel)) {
+        CrmCustomerDO customer = customerMapper.selectById(customerId);
+        // 2. 瀹㈡埛璐熻矗浜猴細鐩存帴閫氳繃锛堝吋瀹规潈闄愯〃涓礋璐d汉璁板綍缂哄け/涓嶄竴鑷寸殑鍘嗗彶鏁版嵁锛�
+        if (customer != null && ObjUtil.equal(customer.getOwnerUserId(), userId)) {
             return true;
         }
-        return false;
+        // 3. 妫�鏌ュ鎴峰洟闃熸潈闄�
+        List<CrmPermissionDO> customerPermissions = crmPermissionService.getPermissionListByBiz(
+                CrmBizTypeEnum.CRM_CUSTOMER.getType(), Collections.singleton(customerId));
+        if (CollUtil.isEmpty(customerPermissions)) {
+            // 瀹㈡埛鏈夎礋璐d汉浣嗕笉鏄綋鍓嶇敤鎴凤細涓嶆槸鍏捣锛屼笉鑳芥斁琛�
+            if (customer != null && customer.getOwnerUserId() != null) {
+                return false;
+            }
+            // 鐪熸鐨勫叕娴锋暟鎹紝READ 鏉冮檺鏀捐
+            return CrmPermissionLevelEnum.isRead(permissionLevel);
+        }
+        // 4. 妫�鏌ョ敤鎴锋槸鍚︽湁瀹㈡埛鍥㈤槦鐨勬潈闄�
+        CrmPermissionDO userCustomerPermission = CollUtil.findOne(customerPermissions,
+                permission -> ObjUtil.equal(permission.getUserId(), userId));
+        return userCustomerPermission != null && isUserPermissionValid(userCustomerPermission, permissionLevel);
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁鎵�灞炵殑瀹㈡埛缂栧彿
+     *
+     * @param bizType 鏁版嵁绫诲瀷
+     * @param bizId   鏁版嵁缂栧彿
+     * @return 瀹㈡埛缂栧彿锛屼笉瀛樺湪鏃惰繑鍥� null
+     */
+    private Long getCustomerId(Integer bizType, Long bizId) {
+        if (CrmBizTypeEnum.CRM_CONTACT.getType().equals(bizType)) {
+            CrmContactDO contact = contactMapper.selectById(bizId);
+            return contact == null ? null : contact.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
+            CrmBusinessDO business = businessMapper.selectById(bizId);
+            return business == null ? null : business.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_CONTRACT.getType().equals(bizType)) {
+            CrmContractDO contract = contractMapper.selectById(bizId);
+            return contract == null ? null : contract.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_SALE_QUOTATION.getType().equals(bizType)) {
+            CrmSaleQuotationDO quotation = quotationMapper.selectById(bizId);
+            return quotation == null ? null : quotation.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_RECEIVABLE.getType().equals(bizType)) {
+            CrmReceivableDO receivable = receivableMapper.selectById(bizId);
+            return receivable == null ? null : receivable.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType().equals(bizType)) {
+            CrmReceivablePlanDO plan = receivablePlanMapper.selectById(bizId);
+            return plan == null ? null : plan.getCustomerId();
+        }
+        if (CrmBizTypeEnum.CRM_INVOICE.getType().equals(bizType)) {
+            CrmInvoiceDO invoice = invoiceMapper.selectById(bizId);
+            return invoice == null ? null : invoice.getCustomerId();
+        }
+        return null;
+    }
+
+    /**
+     * 鑾峰彇鏁版嵁鏈韩鐨勮礋璐d汉缂栧彿
+     *
+     * @param bizType 鏁版嵁绫诲瀷
+     * @param bizId   鏁版嵁缂栧彿
+     * @return 璐熻矗浜虹紪鍙凤紝涓嶅瓨鍦ㄦ椂杩斿洖 null
+     */
+    private Long getOwnerUserId(Integer bizType, Long bizId) {
+        if (CrmBizTypeEnum.CRM_CONTACT.getType().equals(bizType)) {
+            CrmContactDO contact = contactMapper.selectById(bizId);
+            return contact == null ? null : contact.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_BUSINESS.getType().equals(bizType)) {
+            CrmBusinessDO business = businessMapper.selectById(bizId);
+            return business == null ? null : business.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_CONTRACT.getType().equals(bizType)) {
+            CrmContractDO contract = contractMapper.selectById(bizId);
+            return contract == null ? null : contract.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_SALE_QUOTATION.getType().equals(bizType)) {
+            CrmSaleQuotationDO quotation = quotationMapper.selectById(bizId);
+            return quotation == null ? null : quotation.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_RECEIVABLE.getType().equals(bizType)) {
+            CrmReceivableDO receivable = receivableMapper.selectById(bizId);
+            return receivable == null ? null : receivable.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_RECEIVABLE_PLAN.getType().equals(bizType)) {
+            CrmReceivablePlanDO plan = receivablePlanMapper.selectById(bizId);
+            return plan == null ? null : plan.getOwnerUserId();
+        }
+        if (CrmBizTypeEnum.CRM_INVOICE.getType().equals(bizType)) {
+            CrmInvoiceDO invoice = invoiceMapper.selectById(bizId);
+            return invoice == null ? null : invoice.getOwnerUserId();
+        }
+        return null;
+    }
+
+    /**
+     * 鍒ゆ柇鐢ㄦ埛鏄惁鏄暟鎹湰韬殑璐熻矗浜�
+     *
+     * 涓嶄緷璧� crm_permission 璁板綍锛屽吋瀹瑰巻鍙叉暟鎹腑鏉冮檺璁板綍缂哄け鐨勬儏鍐�
+     *
+     * @param bizType 鏁版嵁绫诲瀷
+     * @param bizId   鏁版嵁缂栧彿
+     * @param userId  鐢ㄦ埛缂栧彿
+     * @return 鏄惁鏄礋璐d汉
+     */
+    private boolean isRecordOwner(Integer bizType, Long bizId, Long userId) {
+        return userId != null && ObjUtil.equal(getOwnerUserId(bizType, bizId), userId);
+    }
+
+    /**
+     * 鍒ゆ柇瀛愭暟鎹墍灞炲鎴锋槸鍚﹀瓨鍦ㄥ洟闃燂紙璐熻矗浜烘垨鍥㈤槦鎴愬憳锛�
+     *
+     * 鐢ㄤ簬鍖哄垎銆岀湡姝g殑鍏捣鏁版嵁銆嶅拰銆岀埗瀹㈡埛鏈夊洟闃熴�佷絾瀛愭暟鎹湰韬病鏈夋潈闄愯褰曘�嶇殑鍘嗗彶鏁版嵁
+     *
+     * @param bizType 鏁版嵁绫诲瀷
+     * @param bizId   鏁版嵁缂栧彿
+     * @return 鏄惁瀛樺湪瀹㈡埛鍥㈤槦
+     */
+    private boolean hasParentCustomerTeam(Integer bizType, Long bizId) {
+        Long customerId = getCustomerId(bizType, bizId);
+        if (customerId == null) {
+            return false;
+        }
+        // 瀹㈡埛鏈夎礋璐d汉锛岃鏄庝笉鏄叕娴�
+        CrmCustomerDO customer = customerMapper.selectById(customerId);
+        if (customer == null) {
+            return false;
+        }
+        if (customer.getOwnerUserId() != null) {
+            return true;
+        }
+        // 瀹㈡埛娌℃湁璐熻矗浜烘椂锛屾鏌ユ槸鍚︽湁鍥㈤槦鎴愬憳
+        return CollUtil.isNotEmpty(crmPermissionService.getPermissionListByBiz(
+                CrmBizTypeEnum.CRM_CUSTOMER.getType(), Collections.singleton(customerId)));
     }
 
     /**

--
Gitblit v1.9.3