|
|
@@ -94,6 +94,7 @@ import java.util.*;
|
|
|
import java.util.concurrent.*;
|
|
|
import java.util.concurrent.atomic.AtomicReference;
|
|
|
import java.util.function.Function;
|
|
|
+import java.util.function.Supplier;
|
|
|
import java.util.stream.Collectors;
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
@@ -180,6 +181,14 @@ public class KwtWaybillOrderV1Service {
|
|
|
private KwtLogisticsOrderAddressRepository kwtLogisticsOrderAddressRepository;
|
|
|
// 定义超时时间常量
|
|
|
private static final long PARALLEL_TIMEOUT_SECONDS = 60;
|
|
|
+ /**
|
|
|
+ * 供应商企业类型。
|
|
|
+ */
|
|
|
+ private static final int SUPPLIER_ENT_TYPE = 1;
|
|
|
+ /**
|
|
|
+ * 代理商企业类型。
|
|
|
+ */
|
|
|
+ private static final int SUPPLY_AGENT_ENT_TYPE = 4;
|
|
|
/**
|
|
|
* @param params 请求参数
|
|
|
* @desc 统计
|
|
|
@@ -3605,12 +3614,39 @@ public class KwtWaybillOrderV1Service {
|
|
|
return logOrderIds;
|
|
|
}
|
|
|
entIds.add(entId);
|
|
|
+ // 获取当前用户基于代理关系可见的企业ID范围(包含自身及关联代理企业)
|
|
|
+ Set<Long> currentUserScopeEntIds = getCurrentUserProxyScopeEntIds();
|
|
|
+ log.debug("获取当前用户代理范围企业ID完成,数量: {}", CollectionUtils.isEmpty(currentUserScopeEntIds) ? 0 : currentUserScopeEntIds.size());
|
|
|
+
|
|
|
+ // 将代理范围企业ID加入查询条件集合,确保数据权限覆盖
|
|
|
+ if (CollectionUtils.isNotEmpty(currentUserScopeEntIds)) {
|
|
|
+ entIds.addAll(currentUserScopeEntIds);
|
|
|
+ log.debug("已将代理范围企业ID加入查询集合,当前企业ID集合总数: {}", entIds.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ // 如果企业ID集合不为空,根据企业ID、托运方/承运方ID过滤物流订单ID
|
|
|
if (CollectionUtils.isNotEmpty(entIds)) {
|
|
|
- Set<Long> orderIdsByEnt = getLogOrderIdsByEntIds(entIds,req.getConsignorId(),req.getCarrierId(),entId);
|
|
|
- log.debug("根据企业ID查询到物流订单ID数量: {}", orderIdsByEnt.size());
|
|
|
+ log.debug("开始根据企业ID集合查询物流订单ID,企业ID集合: {}, 托运方ID: {}, 承运方ID: {}",
|
|
|
+ entIds, req.getConsignorId(), req.getCarrierId());
|
|
|
+
|
|
|
+ Set<Long> orderIdsByEnt = getLogOrderIdsByEntIds(
|
|
|
+ entIds,
|
|
|
+ req.getConsignorId(),
|
|
|
+ req.getCarrierId(),
|
|
|
+ entId,
|
|
|
+ currentUserScopeEntIds
|
|
|
+ );
|
|
|
+
|
|
|
+ log.debug("根据企业ID及角色权限过滤后,获取到的物流订单ID数量: {}", orderIdsByEnt.size());
|
|
|
+
|
|
|
if (CollectionUtils.isNotEmpty(orderIdsByEnt)) {
|
|
|
logOrderIds.addAll(orderIdsByEnt);
|
|
|
+ log.debug("已将过滤后的物流订单ID加入结果集,当前物流订单ID总数: {}", logOrderIds.size());
|
|
|
+ } else {
|
|
|
+ log.debug("根据企业ID未查询到任何物流订单ID");
|
|
|
}
|
|
|
+ } else {
|
|
|
+ log.debug("企业ID集合为空,跳过基于企业的物流订单ID查询");
|
|
|
}
|
|
|
|
|
|
// 如果指定了物流订单号,根据订单号查询
|
|
|
@@ -3863,16 +3899,192 @@ public class KwtWaybillOrderV1Service {
|
|
|
return finalResult;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取当前用户基于代理关系可见的企业ID范围。
|
|
|
+ * <p>
|
|
|
+ * 逻辑说明:
|
|
|
+ * 1. 获取当前登录用户的所属企业ID。
|
|
|
+ * 2. 查询该企业的类型信息。
|
|
|
+ * 3. 根据企业类型构建可见范围:
|
|
|
+ * - 若为供应商(SUPPLIER_ENT_TYPE):可见自身及所有关联的代理企业。
|
|
|
+ * - 若为代理商(SUPPLY_AGENT_ENT_TYPE):仅可见自身。
|
|
|
+ * - 其他类型:返回空集合(无特殊代理权限)。
|
|
|
+ * 4. 异常处理:若查询失败,为保证业务连续性,默认返回当前企业ID,避免数据完全不可见。
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @return 可见企业ID集合
|
|
|
+ */
|
|
|
+ private Set<Long> getCurrentUserProxyScopeEntIds() {
|
|
|
+ // 获取当前登录用户的企业ID
|
|
|
+ Long currentEntId = LoginUserHolder.getEntId();
|
|
|
+
|
|
|
+ // 校验企业ID是否存在
|
|
|
+ if (Objects.isNull(currentEntId)) {
|
|
|
+ log.warn("运单代理关系过滤失败,当前登录企业ID为空");
|
|
|
+ return Collections.emptySet();
|
|
|
+ }
|
|
|
+
|
|
|
+ log.debug("开始获取当前用户代理范围企业ID,currentEntId: {}", currentEntId);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 查询当前企业的类型信息
|
|
|
+ List<EntTypeResDto> entTypeList = remoteSystemService.queryEntTypeByIds(Collections.singleton(currentEntId));
|
|
|
+ log.debug("查询到企业类型信息数量: {}", CollectionUtils.isEmpty(entTypeList) ? 0 : entTypeList.size());
|
|
|
+
|
|
|
+ // 根据企业类型和代理关系构建可见企业ID集合
|
|
|
+ Set<Long> proxyScopeEntIds = buildProxyScopeEntIds(currentEntId, entTypeList,
|
|
|
+ () -> {
|
|
|
+ log.debug("当前企业为供应商,开始查询关联的代理企业ID");
|
|
|
+ List<Long> proxyEntIds = remoteContractService.queryProxyEntIdsBySupplyId(currentEntId);
|
|
|
+ log.debug("查询到关联代理企业ID数量: {}", CollectionUtils.isEmpty(proxyEntIds) ? 0 : proxyEntIds.size());
|
|
|
+ return proxyEntIds;
|
|
|
+ });
|
|
|
+
|
|
|
+ log.info("获取当前用户代理范围企业ID完成,currentEntId: {}, 结果数量: {}", currentEntId, proxyScopeEntIds.size());
|
|
|
+ return proxyScopeEntIds;
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 记录异常日志,防止因远程服务调用失败导致主流程中断
|
|
|
+ log.error("运单代理关系过滤范围查询失败,currentEntId={}", currentEntId, e);
|
|
|
+ // 降级策略:返回当前企业ID,确保至少能看到本企业数据
|
|
|
+ return Collections.singleton(currentEntId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据当前企业ID和企业类型,构建代理关系可见的企业ID范围集合。
|
|
|
+ * <p>
|
|
|
+ * 业务逻辑说明:
|
|
|
+ * 1. 如果当前企业是供应商(SUPPLIER_ENT_TYPE):
|
|
|
+ * - 可见范围包含:自身企业ID + 所有关联的代理企业ID。
|
|
|
+ * - 通过 proxySupplier 懒加载获取关联的代理企业列表,避免不必要的远程调用。
|
|
|
+ * 2. 如果当前企业是代理商(SUPPLY_AGENT_ENT_TYPE):
|
|
|
+ * - 可见范围仅包含:自身企业ID。
|
|
|
+ * 3. 其他类型或异常情况:
|
|
|
+ * - 返回空集合或仅包含自身的集合(取决于具体实现,此处非供应商/代理商返回空或仅自身,根据上下文通常代理商只看自己)。
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param currentEntId 当前登录用户所属的企业ID
|
|
|
+ * @param entTypeList 企业类型信息列表,用于判断当前企业的角色(供应商或代理商)
|
|
|
+ * @param proxySupplier 用于获取供应商关联代理企业ID的函数式接口,仅在确认为供应商时执行
|
|
|
+ * @return 可见的企业ID集合,保持插入顺序
|
|
|
+ */
|
|
|
+ static Set<Long> buildProxyScopeEntIds(Long currentEntId, List<EntTypeResDto> entTypeList,
|
|
|
+ Supplier<List<Long>> proxySupplier) {
|
|
|
+ // 参数校验:如果企业ID为空或类型列表为空,直接返回空集合,避免后续空指针异常
|
|
|
+ if (Objects.isNull(currentEntId) || CollectionUtils.isEmpty(entTypeList)) {
|
|
|
+ log.debug("构建代理范围企业ID失败:currentEntId为null或entTypeList为空");
|
|
|
+ return Collections.emptySet();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 使用 LinkedHashSet 保持元素插入顺序,首先加入当前企业ID(如果需要)
|
|
|
+ Set<Long> scopeEntIds = new LinkedHashSet<>();
|
|
|
+
|
|
|
+ // 判断当前企业是否为供应商类型
|
|
|
+ if (hasEnterpriseType(entTypeList, currentEntId, SUPPLIER_ENT_TYPE)) {
|
|
|
+ log.debug("当前企业[{}]为供应商类型,开始构建可见企业范围", currentEntId);
|
|
|
+ // 供应商可见自身
|
|
|
+ scopeEntIds.add(currentEntId);
|
|
|
+
|
|
|
+ // 如果提供了代理企业查询函数,则获取关联的代理企业
|
|
|
+ if (Objects.nonNull(proxySupplier)) {
|
|
|
+ try {
|
|
|
+ List<Long> proxyEntIds = proxySupplier.get();
|
|
|
+ if (CollectionUtils.isNotEmpty(proxyEntIds)) {
|
|
|
+ // 过滤掉可能的null值,并添加到可见范围中
|
|
|
+ Set<Long> validProxyIds = proxyEntIds.stream()
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+ scopeEntIds.addAll(validProxyIds);
|
|
|
+ log.debug("供应商[{}]关联的代理企业数量: {}", currentEntId, validProxyIds.size());
|
|
|
+ } else {
|
|
|
+ log.debug("供应商[{}]未查询到关联的代理企业", currentEntId);
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 捕获异常,防止因远程服务调用失败导致主流程中断,记录日志
|
|
|
+ log.error("获取供应商[{}]关联代理企业失败", currentEntId, e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 供应商逻辑处理完毕,直接返回结果
|
|
|
+ return scopeEntIds;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 判断当前企业是否为代理商类型
|
|
|
+ if (hasEnterpriseType(entTypeList, currentEntId, SUPPLY_AGENT_ENT_TYPE)) {
|
|
|
+ log.debug("当前企业[{}]为代理商类型,可见范围仅包含自身", currentEntId);
|
|
|
+ // 代理商仅可见自身
|
|
|
+ scopeEntIds.add(currentEntId);
|
|
|
+ } else {
|
|
|
+ log.debug("当前企业[{}]既不是供应商也不是代理商,可见范围为空", currentEntId);
|
|
|
+ }
|
|
|
+
|
|
|
+ return scopeEntIds;
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
- * 根据企业ID集合获取物流订单ID集合
|
|
|
+ * 判断指定企业是否具备指定企业类型。
|
|
|
+ * <p>
|
|
|
+ * 该方法用于校验给定的企业ID在提供的企业类型列表中,是否存在匹配的目标企业类型。
|
|
|
+ * 主要用于构建代理关系可见范围时的类型判断逻辑(如区分供应商与代理商)。
|
|
|
+ * </p>
|
|
|
+ *
|
|
|
+ * @param entTypeList 企业类型信息列表,包含企业ID与类型的映射关系
|
|
|
+ * @param entId 待校验的企业ID
|
|
|
+ * @param entType 目标企业类型代码(如:1-供应商,4-代理商)
|
|
|
+ * @return true-该企业具备指定类型;false-不具备或参数无效
|
|
|
*/
|
|
|
- private Set<Long> getLogOrderIdsByEntIds(Set<Long> entIds,String consignorId,String carrierId,Long entId) {
|
|
|
+ static boolean hasEnterpriseType(List<EntTypeResDto> entTypeList, Long entId, Integer entType) {
|
|
|
+ // 1. 基础参数校验:若企业ID、目标类型为空,或类型列表为空,直接返回false
|
|
|
+ if (Objects.isNull(entId) || Objects.isNull(entType) || CollectionUtils.isEmpty(entTypeList)) {
|
|
|
+ log.debug("判断企业类型失败:参数无效,entId={}, entType={}, listSize={}",
|
|
|
+ entId, entType, entTypeList == null ? 0 : entTypeList.size());
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 流式处理查找匹配项
|
|
|
+ boolean result = entTypeList.stream()
|
|
|
+ .filter(Objects::nonNull) // 过滤列表中的空对象,防止NPE
|
|
|
+ .filter(item -> Objects.equals(item.getEntId(), entId)) // 筛选出指定企业ID的记录
|
|
|
+ .anyMatch(item -> Objects.equals(item.getType(), entType)); // 判断是否存在匹配的目标类型
|
|
|
+
|
|
|
+ // 3. 记录调试日志,便于追踪权限过滤逻辑
|
|
|
+ log.debug("判断企业类型结果:entId={}, targetEntType={}, result={}", entId, entType, result);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据企业ID集合获取物流订单ID集合。
|
|
|
+ *
|
|
|
+ * @param entIds 企业ID集合
|
|
|
+ * @param consignorId 托运企业ID
|
|
|
+ * @param carrierId 承运企业ID
|
|
|
+ * @param entId 当前登录企业ID
|
|
|
+ * @param currentUserScopeEntIds 当前用户代理关系可见企业ID集合
|
|
|
+ * @return 物流订单ID集合
|
|
|
+ */
|
|
|
+ private Set<Long> getLogOrderIdsByEntIds(Set<Long> entIds, String consignorId, String carrierId,
|
|
|
+ Long entId, Set<Long> currentUserScopeEntIds) {
|
|
|
List<KwtLogisticsOrderUnit> unitList = kwtLogisticsOrderUnitRepository.queryByEntIds(entIds);
|
|
|
if (CollectionUtils.isEmpty(unitList)) {
|
|
|
return Collections.emptySet();
|
|
|
}
|
|
|
- Set<Long> logOrderIds = unitList.stream().filter(x->Objects.equals(x.getEntId(),entId))
|
|
|
- .map(KwtLogisticsOrderUnit::getLOrderId).collect(Collectors.toSet());
|
|
|
+ // 确定当前用户可见的企业ID范围:如果代理关系查询结果为空,则默认仅包含当前登录企业ID,确保数据权限过滤的有效性
|
|
|
+ Set<Long> finalCurrentUserScopeEntIds = CollectionUtils.isNotEmpty(currentUserScopeEntIds)
|
|
|
+ ? currentUserScopeEntIds : Collections.singleton(entId);
|
|
|
+
|
|
|
+ log.debug("开始根据企业权限过滤物流订单单位,可见企业ID集合: {}, 待过滤单位数量: {}",
|
|
|
+ finalCurrentUserScopeEntIds, unitList.size());
|
|
|
+
|
|
|
+ // 过滤出属于当前用户可见企业范围内的物流订单单位,并提取对应的物流订单ID集合
|
|
|
+ Set<Long> logOrderIds = unitList.stream()
|
|
|
+ .filter(unit -> finalCurrentUserScopeEntIds.contains(unit.getEntId()))
|
|
|
+ .map(KwtLogisticsOrderUnit::getLOrderId)
|
|
|
+ .collect(Collectors.toSet());
|
|
|
+
|
|
|
+ log.debug("企业权限过滤完成,最终获取到的物流订单ID数量: {}", logOrderIds.size());
|
|
|
|
|
|
|
|
|
if (StringUtils.isNotBlank(consignorId)){
|