فهرست منبع

贸易合同物流合同数据权限

chenxiaofei 2 ماه پیش
والد
کامیت
048131ef42

+ 165 - 111
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractLogisticsService.java

@@ -63,7 +63,6 @@ import com.sckw.transport.api.model.vo.WayContaractbillOrderVo;
 import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.collections4.MapUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.jetbrains.annotations.NotNull;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -126,12 +125,12 @@ public class KwcContractLogisticsService {
     @DubboReference(version = "1.0.0", group = "design", check = false)
     private GoodsInfoService goodsInfoService;
 
-    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
-    private TradeOrderInfoService tradeOrderInfoService;
-
     @DubboReference(version = "1.0.0", group = "design", check = false)
     private TransportRemoteService transportRemoteService;
 
+    @DubboReference(version = "1.0.0", group = "design", check = false, timeout = 8000)
+    private TradeOrderInfoService tradeOrderInfoService;
+
     //销售合同
     @Value(value = "${jumpUrl.saleSendContract}")
     private String saleSendContract;
@@ -1113,21 +1112,10 @@ public class KwcContractLogisticsService {
         if (CollectionUtils.isEmpty(contractIdList) && CollectionUtils.isNotEmpty(entIdList)){
             return PageDataResult.empty(req.getPageNum(),req.getPageSize());
         }
-        // 获取当前用户的数据权限配置
         DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
-        // 如果存在数据权限且需要过滤,则执行权限过滤逻辑
-        if (perm != null && perm.needFilter()) {
-            // 根据合同ID列表及查询条件获取物流合同列表
-            List<KwcContractLogistics> permissionSource = kwcContractLogisticsRepository.queryList(contractIdList,
-                    req.getContractNo(), req.getContractName(), req.getStatus());
-            // 根据数据权限规则过滤合同列表
-            permissionSource = filterLogisticsContractsByPermission(permissionSource, perm);
-            // 如果过滤后无数据,直接返回空分页结果
-            if (CollectionUtils.isEmpty(permissionSource)) {
-                return PageDataResult.empty(req.getPageNum(), req.getPageSize());
-            }
-            // 将过滤后的合同ID重新赋值给contractIdList,用于后续的分页查询
-            contractIdList = permissionSource.stream().map(KwcContractLogistics::getId).collect(Collectors.toSet());
+        contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
+        if (CollectionUtils.isEmpty(contractIdList)) {
+            return PageDataResult.empty(req.getPageNum(), req.getPageSize());
         }
 
         IPage<KwcContractLogistics> page =kwcContractLogisticsRepository.queryByPage(req.getPageNum(),req.getPageSize(),
@@ -1746,10 +1734,17 @@ public class KwcContractLogisticsService {
         }
 
 
-        List<KwcContractLogistics> contractLogistics = kwcContractLogisticsRepository.queryList(contractIdList,req.getContractNo(),req.getContractName(),req.getStatus());
-        // 应用数据权限过滤:获取当前用户的数据权限配置,并对物流合同列表进行过滤(个人数据权限与企业层级数据权限为并集关系)
         DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
-        contractLogistics = filterLogisticsContractsByPermission(contractLogistics, perm);
+        contractIdList = applyDataPermissionToLogisticsContractIds(contractIdList, perm);
+        if (CollectionUtils.isEmpty(contractIdList)) {
+            Map<Integer, List<KwcContractLogistics>> emptyMap = new HashMap<>();
+            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
+                    .map(x -> getContractStatusCount(x, emptyMap))
+                    .collect(Collectors.toList());
+            contractStatusCountResp.setContractStatusInfo(statusCounts);
+            return contractStatusCountResp;
+        }
+        List<KwcContractLogistics> contractLogistics = kwcContractLogisticsRepository.queryList(contractIdList,req.getContractNo(),req.getContractName(),req.getStatus());
 
         // 如果过滤后无数据,则返回各状态计数均为0的结果
         if (CollectionUtils.isEmpty(contractLogistics)){
@@ -1814,152 +1809,211 @@ public class KwcContractLogisticsService {
 
 
     /**
-     * 获取当前用户的数据权限配置
+     * 根据数据权限过滤物流合同ID集合。
      * <p>
-     * 通过远程服务获取当前登录用户的数据权限过滤条件,包括可见企业ID、个人数据权限开关等。
-     * 如果获取失败,记录警告日志并返回null,后续逻辑将跳过权限过滤。
+     * 处理逻辑:
+     * 1. 如果无需过滤或输入为空,直接返回。
+     * 2. 如果不是全部可见(即有企业范围限制),则通过物流合同关联的企业ID进行过滤,只保留当前用户可见企业下的合同。
+     * 3. 如果开启了个人数据权限,进一步过滤,只保留销售员为当前用户的合同(通过运单->贸易订单->贸易合同链路关联)。
      * </p>
      *
-     * @return 数据权限DTO,如果获取失败则返回null
+     * @param contractIdList 待过滤的物流合同ID集合
+     * @param perm           数据权限DTO
+     * @return 过滤后的物流合同ID集合
      */
-    private DataPermissionDTO fetchDataPermissionForCurrentUser() {
-        try {
-            DataPermissionFilterReqDto reqDto = new DataPermissionFilterReqDto();
-            reqDto.setUserId(LoginUserHolder.getUserId());
-            reqDto.setRoleId(LoginUserHolder.getCurrentRoleId());
-            reqDto.setManager(LoginUserHolder.isManager());
-            return dataPermissionFeignService.getDataPermissionFilter(reqDto);
-        } catch (Exception e) {
-            log.warn("获取物流合同数据权限失败,跳过权限过滤: {}", e.getMessage());
-            return null;
+    private Set<Long> applyDataPermissionToLogisticsContractIds(Set<Long> contractIdList, DataPermissionDTO perm) {
+        // 1. 基础校验:如果权限对象为空、不需要过滤或合同ID列表为空,直接返回原列表
+        if (perm == null || !perm.needFilter() || CollectionUtils.isEmpty(contractIdList)) {
+            return contractIdList;
         }
+
+        log.debug("开始应用物流合同数据权限过滤, 初始合同数量: {}, 用户ID: {}", contractIdList.size(), perm.getUserId());
+
+        // 2. 企业范围过滤:如果不是全部可见,则根据可见企业ID过滤合同
+        if (!perm.isAllVisible()) {
+            if (CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
+                log.debug("无可见企业权限,清空合同列表");
+                contractIdList.clear();
+                return contractIdList;
+            }
+            
+            // 查询可见企业下的所有物流合同单位
+            List<KwcContractLogisticsUnit> permUnits =
+                    kwcContractLogisticsUnitRepository.queryByEntIds(new ArrayList<>(perm.getVisibleEntIds()), null);
+            
+            // 提取这些单位关联的合同ID
+            Set<Long> entScopeContractIds = permUnits.stream()
+                    .map(KwcContractLogisticsUnit::getContractId)
+                    .filter(Objects::nonNull)
+                    .collect(Collectors.toSet());
+            
+            // 取交集:只保留在可见企业范围内的合同
+            int beforeSize = contractIdList.size();
+            contractIdList.retainAll(entScopeContractIds);
+            log.debug("企业范围过滤完成, 过滤前: {}, 过滤后: {}", beforeSize, contractIdList.size());
+        }
+
+        // 如果经过企业范围过滤后列表为空,直接返回
+        if (CollectionUtils.isEmpty(contractIdList)) {
+            return contractIdList;
+        }
+
+        // 3. 个人数据权限过滤:如果开启,需进一步校验销售员身份
+        if (perm.isPersonalDataEnabled()) {
+            Long uid = perm.getUserId();
+            if (uid == null) {
+                log.warn("个人数据权限开启但用户ID为空,清空合同列表");
+                contractIdList.clear();
+                return contractIdList;
+            }
+            
+            log.debug("开启个人数据权限过滤, 校验销售员ID: {}", uid);
+            // 通过关联的贸易合同销售员进行过滤
+            Set<Long> salesMatched = retainLogisticsContractIdsByLinkedTradeSalesman(contractIdList, uid);
+            
+            // 更新原列表为过滤后的结果
+            contractIdList.clear();
+            contractIdList.addAll(salesMatched);
+            log.debug("个人数据权限过滤完成, 最终合同数量: {}", contractIdList.size());
+        }
+        
+        return contractIdList;
     }
 
     /**
-     * 根据数据权限过滤物流合同列表
+     * 根据关联的贸易合同销售员过滤物流合同ID。
      * <p>
-     * 过滤逻辑:
-     * 1. 通过物流合同ID查询关联的运单子单信息,获取贸易订单ID。
-     * 2. 通过贸易订单ID查询关联的交易合同ID。
-     * 3. 根据交易合同ID查询交易合同详情。
-     * 4. 结合数据权限配置(可见企业ID、个人数据权限),判断当前用户是否有权限查看该物流合同。
-     *    - 若非全部可见,则检查交易合同所属企业是否在可见企业列表中。
-     *    - 若启用个人数据权限,则检查交易合同的销售员是否为当前用户。
-     *    - 只有当至少一个关联的交易合同满足权限要求时,该物流合同才会被保留。
+     * 关联链路:物流合同 -> 运单 (RWaybillSubOrderVo) -> 贸易订单ID -> 贸易订单详情 (TradeOrderContractVo) -> 贸易合同ID -> 贸易合同实体 (KwcContractTrade) -> 销售员ID
      * </p>
      *
-     * @param records 待过滤的物流合同列表
-     * @param perm    数据权限配置
-     * @return 过滤后的物流合同列表
+     * @param logContractIds 物流合同ID集合
+     * @param salesmanUserId 销售员用户ID
+     * @return 符合销售员权限的物流合同ID集合
      */
-    private List<KwcContractLogistics> filterLogisticsContractsByPermission(List<KwcContractLogistics> records, DataPermissionDTO perm) {
-        // 如果记录为空、权限对象为空或不需要过滤,直接返回原列表
-        if (CollectionUtils.isEmpty(records) || perm == null || !perm.needFilter()) {
-            return records;
+    private Set<Long> retainLogisticsContractIdsByLinkedTradeSalesman(Set<Long> logContractIds, Long salesmanUserId) {
+        if (CollectionUtils.isEmpty(logContractIds) || salesmanUserId == null) {
+            return Collections.emptySet();
         }
 
-        // 1. 提取所有物流合同ID
-        Set<Long> logContractIds = records.stream().map(KwcContractLogistics::getId).collect(Collectors.toSet());
+        log.debug("开始解析物流合同关联的贸易销售员, 物流合同数: {}", logContractIds.size());
 
-        // 2. 查询关联的运单子单信息
+        // 1. 查询物流合同关联的运单信息
         List<RWaybillSubOrderVo> orderLinks = transportRemoteService.queryWaybillOrderByLogContractIds(logContractIds);
         if (CollectionUtils.isEmpty(orderLinks)) {
-            return Collections.emptyList();
+            log.debug("未找到关联的运单信息");
+            return Collections.emptySet();
         }
 
-        // 3. 提取贸易订单ID
+        // 2. 从运单中提取贸易订单ID (tradeId)
         Set<Long> tradeOrderIds = orderLinks.stream()
                 .map(RWaybillSubOrderVo::getTradeId)
                 .filter(Objects::nonNull)
                 .collect(Collectors.toSet());
+        
         if (CollectionUtils.isEmpty(tradeOrderIds)) {
-            return Collections.emptyList();
+            log.debug("运单中未包含有效的贸易订单ID");
+            return Collections.emptySet();
         }
 
-        // 4. 查询贸易订单关联的交易合同信息
+        // 3. 批量查询贸易订单详情,获取贸易订单与贸易合同的映射关系
         List<TradeOrderContractVo> tradeOrderContracts = tradeOrderInfoService.queryTradeOrderIds(tradeOrderIds);
         if (CollectionUtils.isEmpty(tradeOrderContracts)) {
-            return Collections.emptyList();
+            log.debug("未找到对应的贸易订单详情");
+            return Collections.emptySet();
         }
 
-        // 5. 构建物流合同ID到交易合同ID集合的映射关系
-        Map<Long, Set<Long>> logContractIdTradeContractIdsMap = buildLogContractTradeContractIdsMap(orderLinks, tradeOrderContracts);
-        if (MapUtils.isEmpty(logContractIdTradeContractIdsMap)) {
-            return Collections.emptyList();
+        // 4. 构建 物流合同ID -> 贸易合同ID集合 的映射
+        Map<Long, Set<Long>> logToTradeContractIds = buildLogContractTradeContractIdsMap(orderLinks, tradeOrderContracts);
+        if (logToTradeContractIds.isEmpty()) {
+            log.debug("未能建立物流合同到贸易合同的映射");
+            return Collections.emptySet();
         }
 
-        // 6. 收集所有相关的交易合同ID
-        Set<Long> tradeContractIds = logContractIdTradeContractIdsMap.values().stream()
+        // 5. 收集所有涉及的贸易合同ID
+        Set<Long> tradeContractIds = logToTradeContractIds.values().stream()
                 .flatMap(Collection::stream)
                 .collect(Collectors.toSet());
 
-        // 7. 批量查询交易合同详情,并构建ID到对象的映射
-        Map<Long, KwcContractTrade> tradeContractMap = kwcContractTradeRepository.findByContractIds(tradeContractIds).stream()
+        // 6. 批量查询贸易合同实体,构建 ID -> 实体 的映射,以便获取销售员ID
+        Map<Long, KwcContractTrade> tradeMap = kwcContractTradeRepository.findByContractIds(tradeContractIds).stream()
                 .collect(Collectors.toMap(KwcContractTrade::getId, Function.identity(), (a, b) -> a));
 
-        // 8. 根据权限规则过滤物流合同
-        return records.stream().filter(record -> {
-            // 获取当前物流合同关联的所有交易合同ID
-            Set<Long> relationTradeContractIds = logContractIdTradeContractIdsMap.get(record.getId());
-            if (CollectionUtils.isEmpty(relationTradeContractIds)) {
-                return false;
+        // 7. 遍历物流合同,检查其关联的贸易合同中是否有指定销售员
+        Set<Long> result = new HashSet<>();
+        for (Long logId : logContractIds) {
+            Set<Long> relTradeContractIds = logToTradeContractIds.get(logId);
+            if (CollectionUtils.isEmpty(relTradeContractIds)) {
+                continue;
             }
-
-            // 只要有一个关联的交易合同满足权限要求,则该物流合同可见
-            return relationTradeContractIds.stream()
-                    .map(tradeContractMap::get)
+            
+            // 只要有一个关联的贸易合同的销售员是指定用户,则该物流合同可见
+            boolean ok = relTradeContractIds.stream()
+                    .map(tradeMap::get)
                     .filter(Objects::nonNull)
-                    .anyMatch(contract -> {
-                        // 校验企业权限
-                        boolean entOk = true;
-                        if (!perm.isAllVisible()) {
-                            if (CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
-                                entOk = false;
-                            } else {
-                                entOk = contract.getEntId() != null && perm.getVisibleEntIds().contains(contract.getEntId());
-                            }
-                        }
-
-                        // 校验个人数据权限(销售员权限)
-                        boolean salesOk = true;
-                        if (perm.isPersonalDataEnabled()) {
-                            salesOk = perm.getUserId() != null && perm.getUserId().equals(contract.getSalesmanId());
-                        }
-
-                        return entOk && salesOk;
-                    });
-        }).collect(Collectors.toList());
+                    .anyMatch(t -> salesmanUserId.equals(t.getSalesmanId()));
+            
+            if (ok) {
+                result.add(logId);
+            }
+        }
+        
+        log.debug("销售员权限过滤结束, 匹配到的物流合同数: {}", result.size());
+        return result;
     }
 
     /**
-     * 构建物流合同ID与关联的交易合同ID集合的映射关系
+     * 构建物流合同ID到贸易合同ID集合的映射关系。
      *
-     * @param orderLinks         运单子单信息列表,包含物流合同ID和贸易订单ID
-     * @param tradeOrderContracts 贸易订单与交易合同关联信息列表
-     * @return Map<物流合同ID, 交易合同ID集合>
+     * @param orderLinks         运单列表
+     * @param tradeOrderContracts 贸易订单与合同关联列表
+     * @return Map<物流合同ID, Set<贸易合同ID>>
      */
     private Map<Long, Set<Long>> buildLogContractTradeContractIdsMap(List<RWaybillSubOrderVo> orderLinks,
                                                                      List<TradeOrderContractVo> tradeOrderContracts) {
-        // 构建贸易订单ID到交易合同ID的映射关系,过滤掉无效数据
-        Map<Long, Long> tradeOrderIdTradeContractIdMap = tradeOrderContracts.stream()
+        // 构建 贸易订单ID -> 贸易合同ID 的映射
+        Map<Long, Long> tradeOrderIdToContractId = tradeOrderContracts.stream()
                 .filter(item -> item.getTOrderId() != null && item.getContractId() != null)
                 .collect(Collectors.toMap(TradeOrderContractVo::getTOrderId, TradeOrderContractVo::getContractId, (a, b) -> a));
 
-        // 初始化结果Map,key为物流合同ID,value为关联的交易合同ID集合
         Map<Long, Set<Long>> result = new HashMap<>();
-        for (RWaybillSubOrderVo orderLink : orderLinks) {
-            // 跳过物流合同ID或贸易订单ID为空的数据
-            if (orderLink.getLogContractId() == null || orderLink.getTradeId() == null) {
+        for (RWaybillSubOrderVo link : orderLinks) {
+            if (link.getLogContractId() == null || link.getTradeId() == null) {
                 continue;
             }
-            // 获取贸易订单对应的交易合同ID
-            Long tradeContractId = tradeOrderIdTradeContractIdMap.get(orderLink.getTradeId());
+            
+            // 获取运单关联的贸易订单对应的贸易合同ID
+            Long tradeContractId = tradeOrderIdToContractId.get(link.getTradeId());
             if (tradeContractId == null) {
                 continue;
             }
-            // 将交易合同ID添加到对应物流合同ID的集合中
-            result.computeIfAbsent(orderLink.getLogContractId(), key -> new HashSet<>()).add(tradeContractId);
+            
+            // 将贸易合同ID加入该物流合同对应的集合中
+            result.computeIfAbsent(link.getLogContractId(), k -> new HashSet<>()).add(tradeContractId);
         }
+        
+        log.debug("构建物流合同-贸易合同映射完成, 映射数量: {}", result.size());
         return result;
     }
+
+    /**
+     * 获取当前用户的数据权限配置
+     * <p>
+     * 通过远程服务获取当前登录用户的数据权限过滤条件,包括可见企业ID、个人数据权限开关等。
+     * 如果获取失败,记录警告日志并返回null,后续逻辑将跳过权限过滤。
+     * </p>
+     *
+     * @return 数据权限DTO,如果获取失败则返回null
+     */
+    private DataPermissionDTO fetchDataPermissionForCurrentUser() {
+        try {
+            DataPermissionFilterReqDto reqDto = new DataPermissionFilterReqDto();
+            reqDto.setUserId(LoginUserHolder.getUserId());
+            reqDto.setRoleId(LoginUserHolder.getCurrentRoleId());
+            reqDto.setManager(LoginUserHolder.isManager());
+            return dataPermissionFeignService.getDataPermissionFilter(reqDto);
+        } catch (Exception e) {
+            log.warn("获取物流合同数据权限失败,跳过权限过滤: {}", e.getMessage());
+            return null;
+        }
+    }
 }

+ 66 - 12
sckw-modules/sckw-contract/src/main/java/com/sckw/contract/service/operateService/KwcContractTradeService.java

@@ -1679,6 +1679,7 @@ public class KwcContractTradeService {
         if (org.apache.commons.collections4.CollectionUtils.isEmpty(records)) {
             return Collections.emptyList();
         }
+        // 数据权限:企业按 kwc_contract_trade_unit;与销售员条件见 filterTradeContractsByPermission
         DataPermissionDTO perm = fetchDataPermissionForCurrentUser();
         records = filterTradeContractsByPermission(records, perm);
         if (org.apache.commons.collections4.CollectionUtils.isEmpty(records)) {
@@ -2332,6 +2333,16 @@ public class KwcContractTradeService {
 
         // List<KwcContractTrade> kwcContractTrades = kwcContractTradeRepository.queryTradeListByPageList(LoginUserHolder.getEntId());
 
+        if (CollectionUtils.isEmpty(kwcContractTrades)) {
+            Map<Integer, List<KwcContractTrade>> statusAndLogOrdersMap = new HashMap<>();
+            List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
+                    .map(x -> getContractStatusCount(x, statusAndLogOrdersMap))
+                    .collect(Collectors.toList());
+            contractStatusCountResp.setContractStatusInfo(statusCounts);
+            return contractStatusCountResp;
+        }
+        DataPermissionDTO dataPerm = fetchDataPermissionForCurrentUser();
+        kwcContractTrades = filterTradeContractsByPermission(kwcContractTrades, dataPerm);
         if (CollectionUtils.isEmpty(kwcContractTrades)) {
             Map<Integer, List<KwcContractTrade>> statusAndLogOrdersMap = new HashMap<>();
             List<ContractStatusCountResp.ContractStatusCount> statusCounts = statusEnums.stream()
@@ -2685,41 +2696,84 @@ public class KwcContractTradeService {
         }
     }
 
+
     /**
-     * 根据数据权限过滤贸易合同列表
+     * 数据权限过滤({@link #queryTradeListByPage}、{@link #countQueryTradeListByPage}、{@link #queryTradeContractStatusCount} 共用)。
+     * <p>
+     * 与 {@link DataPermissionDTO} 一致:开启个人数据权限时,条件为「角色已勾选企业范围」与「本人为合同销售员」同时满足(AND)。
+     * 企业范围:按 {@code kwc_contract_trade_unit} 中采购/销售等企业的 {@code ent_id} 是否与 {@code visibleEntIds} 有交集;
+     * 个人范围:{@code salesman_id} 等于当前用户。未配置企业限制(全部可见)且未开个人权限时不收缩。
+     * </p>
      *
-     * @param records 待过滤的合同列表
-     * @param perm    数据权限配置
-     * @return 过滤后的合同列表
+     * @param records 待过滤的贸易合同列表
+     * @param perm    当前用户的数据权限配置对象
+     * @return 过滤后的贸易合同列表
      */
     private List<KwcContractTrade> filterTradeContractsByPermission(List<KwcContractTrade> records, DataPermissionDTO perm) {
         // 如果记录为空、权限配置为空或不需要过滤,直接返回原列表
         if (CollectionUtils.isEmpty(records) || perm == null || !perm.needFilter()) {
             return records;
         }
-        return records.stream().filter(record -> {
-            // 校验企业权限
+
+        log.debug("开始执行贸易合同数据权限过滤,原始记录数: {}, 用户ID: {}", records.size(), perm.getUserId());
+
+        // 提取所有合同ID
+        Set<Long> contractIds = records.stream()
+                .map(KwcContractTrade::getId)
+                .filter(Objects::nonNull)
+                .collect(Collectors.toSet());
+
+        // 构建合同ID与关联企业ID集合的映射关系
+        Map<Long, Set<Long>> contractIdEntIdsMap = Collections.emptyMap();
+        if (CollectionUtils.isNotEmpty(contractIds)) {
+            List<KwcContractTradeUnit> tradeUnits = kwcContractTradeUnitRepository.queryByContractIds(contractIds);
+            if (CollectionUtils.isNotEmpty(tradeUnits)) {
+                contractIdEntIdsMap = tradeUnits.stream()
+                        .filter(unit -> unit.getContractId() != null && unit.getEntId() != null)
+                        .collect(Collectors.groupingBy(KwcContractTradeUnit::getContractId,
+                                Collectors.mapping(KwcContractTradeUnit::getEntId, Collectors.toSet())));
+            }
+        }
+
+        Map<Long, Set<Long>> finalContractIdEntIdsMap = contractIdEntIdsMap;
+
+        // 执行过滤逻辑
+        List<KwcContractTrade> filteredRecords = records.stream().filter(record -> {
+            // 1. 校验企业权限
             boolean entOk = true;
             if (!perm.isAllVisible()) {
-                // 如果不是所有可见,检查可见企业ID列表
+                // 如果不是所有企业可见,检查可见企业ID列表
                 if (CollectionUtils.isEmpty(perm.getVisibleEntIds())) {
                     entOk = false;
+                    log.debug("合同ID: {} 过滤原因: 非全可见且无可见企业权限", record.getId());
                 } else {
-                    // 检查当前合同所属企业是否在可见列表中
-                    entOk = record.getEntId() != null && perm.getVisibleEntIds().contains(record.getEntId());
+                    // 检查当前合同关联的企业中,是否有任意一个在用户的可见企业列表中
+                    Set<Long> relationEntIds = finalContractIdEntIdsMap.get(record.getId());
+                    entOk = CollectionUtils.isNotEmpty(relationEntIds)
+                            && relationEntIds.stream().anyMatch(perm.getVisibleEntIds()::contains);
+                    if (!entOk) {
+                        log.debug("合同ID: {} 过滤原因: 关联企业不在可见列表中", record.getId());
+                    }
                 }
             }
 
-            // 校验销售人员个人数据权限
+            // 2. 校验销售人员个人数据权限
             boolean salesOk = true;
             if (perm.isPersonalDataEnabled()) {
                 // 如果开启了个人数据权限,检查当前用户是否为该合同的销售人员
-                salesOk = perm.getUserId() != null && perm.getUserId().equals(record.getSalesmanId());
+                salesOk = perm.getUserId() != null && Objects.equals(perm.getUserId(), record.getSalesmanId());
+                if (!salesOk) {
+                    log.debug("合同ID: {} 过滤原因: 非本人销售数据 (当前用户: {}, 销售员: {})",
+                            record.getId(), perm.getUserId(), record.getSalesmanId());
+                }
             }
 
-            // 同时满足企业权限和销售人员权限
+            // 同时满足企业权限和销售人员权限才保留
             return entOk && salesOk;
         }).collect(Collectors.toList());
+
+        log.debug("贸易合同数据权限过滤完成,过滤后记录数: {}", filteredRecords.size());
+        return filteredRecords;
     }
 }