|
|
@@ -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;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|