🐛 业务部门可见合同与业务数据,并补齐异常处置单测依赖

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-29 16:22:52 +08:00
parent b5c26609ea
commit 717f50a52c
13 changed files with 119 additions and 29 deletions
@@ -263,9 +263,12 @@ public class ContractChangeServiceImpl extends BaseServiceImpl<ContractChangeMap
} else if (!Objects.equals(contractChange.getAllDept(), 1)) {
Long currentDeptId = TransportBusinessSupport.currentDeptId("合同变更");
Long currentUserId = AuthUtil.getUserId();
queryWrapper.and(wrapper -> wrapper.eq(ContractChange::getOrganizationId, currentDeptId)
.or().eq(ContractChange::getCreateUser, currentUserId)
.or().eq(ContractChange::getHandlerUserId, currentUserId));
queryWrapper.and(wrapper -> {
wrapper.eq(ContractChange::getOrganizationId, currentDeptId)
.or().eq(ContractChange::getCreateUser, currentUserId)
.or().eq(ContractChange::getHandlerUserId, currentUserId);
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(contractChange.getOrganizationId())) {
queryWrapper.eq(ContractChange::getOrganizationId, contractChange.getOrganizationId());
}
@@ -451,7 +454,8 @@ public class ContractChangeServiceImpl extends BaseServiceImpl<ContractChangeMap
return true;
}
Long currentDeptId = TransportBusinessSupport.currentDeptId("合同变更");
return currentDeptId != null && Objects.equals(contractChange.getOrganizationId(), currentDeptId);
return currentDeptId != null && (Objects.equals(contractChange.getOrganizationId(), currentDeptId)
|| TransportBusinessSupport.isProjectOwnedByBusinessDept(contractChange.getProjectId(), currentDeptId));
}
private void fillReadonly(ContractChangeVO contractChangeVO) {
@@ -610,9 +610,12 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
} else if (!Objects.equals(contractManage.getAllDept(), 1)) {
Long currentDeptId = TransportBusinessSupport.currentDeptId("合同管理");
Long currentUserId = AuthUtil.getUserId();
queryWrapper.and(wrapper -> wrapper.eq(ContractManage::getOrganizationId, currentDeptId)
.or().eq(ContractManage::getCreateUser, currentUserId)
.or().eq(ContractManage::getHandlerUserId, currentUserId));
queryWrapper.and(wrapper -> {
wrapper.eq(ContractManage::getOrganizationId, currentDeptId)
.or().eq(ContractManage::getCreateUser, currentUserId)
.or().eq(ContractManage::getHandlerUserId, currentUserId);
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(contractManage.getOrganizationId())) {
queryWrapper.eq(ContractManage::getOrganizationId, contractManage.getOrganizationId());
}
@@ -1473,7 +1476,8 @@ public class ContractManageServiceImpl extends BaseServiceImpl<ContractManageMap
Long currentUserId = AuthUtil.getUserId();
return Objects.equals(contractManage.getOrganizationId(), currentDeptId)
|| Objects.equals(contractManage.getCreateUser(), currentUserId)
|| Objects.equals(contractManage.getHandlerUserId(), currentUserId);
|| Objects.equals(contractManage.getHandlerUserId(), currentUserId)
|| TransportBusinessSupport.isProjectOwnedByBusinessDept(contractManage.getProjectId(), currentDeptId);
}
}
@@ -674,7 +674,11 @@ public class LoadingManageServiceImpl extends BaseServiceImpl<LoadingManageMappe
TransportBusinessSupport.validateAllDept(loadingManage.getAllDept(), "配载管理");
LambdaQueryWrapper<LoadingManage> queryWrapper = Wrappers.<LoadingManage>lambdaQuery().eq(LoadingManage::getIsDeleted, 0);
if (!Objects.equals(loadingManage.getAllDept(), 1)) {
queryWrapper.eq(LoadingManage::getDeptId, TransportBusinessSupport.currentDeptId("配载管理"));
Long currentDeptId = TransportBusinessSupport.currentDeptId("配载管理");
queryWrapper.and(wrapper -> {
wrapper.eq(LoadingManage::getDeptId, currentDeptId);
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(loadingManage.getDeptId())) {
queryWrapper.eq(LoadingManage::getDeptId, loadingManage.getDeptId());
}
@@ -195,7 +195,11 @@ public class ShippingTemplateServiceImpl extends BaseServiceImpl<ShippingTemplat
TransportBusinessSupport.validateAllDept(shippingTemplate.getAllDept(), "发货模板");
LambdaQueryWrapper<ShippingTemplate> queryWrapper = Wrappers.<ShippingTemplate>lambdaQuery().eq(ShippingTemplate::getIsDeleted, 0);
if (!Objects.equals(shippingTemplate.getAllDept(), 1)) {
queryWrapper.eq(ShippingTemplate::getDeptId, TransportBusinessSupport.currentDeptId("发货模板"));
Long currentDeptId = TransportBusinessSupport.currentDeptId("发货模板");
queryWrapper.and(wrapper -> {
wrapper.eq(ShippingTemplate::getDeptId, currentDeptId);
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(shippingTemplate.getDeptId())) {
queryWrapper.eq(ShippingTemplate::getDeptId, shippingTemplate.getDeptId());
}
@@ -190,7 +190,11 @@ public class TemporaryCreditLimitServiceImpl extends BaseServiceImpl<TemporaryCr
queryWrapper.eq(TemporaryCreditLimit::getApplyDeptId, temporaryCreditLimit.getApplyDeptId());
}
} else if (!Objects.equals(temporaryCreditLimit.getAllDept(), 1)) {
queryWrapper.eq(TemporaryCreditLimit::getApplyDeptId, TransportBusinessSupport.currentDeptId("临时额度管理"));
Long currentDeptId = TransportBusinessSupport.currentDeptId("临时额度管理");
queryWrapper.and(wrapper -> {
wrapper.eq(TemporaryCreditLimit::getApplyDeptId, currentDeptId);
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(temporaryCreditLimit.getApplyDeptId())) {
queryWrapper.eq(TemporaryCreditLimit::getApplyDeptId, temporaryCreditLimit.getApplyDeptId());
}
@@ -701,9 +701,12 @@ public class TransportPlanServiceImpl extends BaseServiceImpl<TransportPlanMappe
LambdaQueryWrapper<TransportPlan> queryWrapper = Wrappers.<TransportPlan>lambdaQuery().eq(TransportPlan::getIsDeleted, 0);
if (!Objects.equals(transportPlan.getAllDept(), 1)) {
Long currentDeptId = TransportBusinessSupport.currentDeptId("运输计划");
// dept_id 为空的历史数据按创建组织归入当前组织
queryWrapper.and(wrapper -> wrapper.eq(TransportPlan::getDeptId, currentDeptId)
.or(item -> item.isNull(TransportPlan::getDeptId).eq(TransportPlan::getCreateDept, currentDeptId)));
// dept_id 为空的历史数据按创建组织归入当前组织;业务部门可见其项目下的计划
queryWrapper.and(wrapper -> {
wrapper.eq(TransportPlan::getDeptId, currentDeptId)
.or(item -> item.isNull(TransportPlan::getDeptId).eq(TransportPlan::getCreateDept, currentDeptId));
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, List.of(currentDeptId));
});
} else if (Func.isNotEmpty(transportPlan.getDeptId())) {
queryWrapper.eq(TransportPlan::getDeptId, transportPlan.getDeptId());
}
@@ -1331,11 +1331,14 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
List<Long> deptIdList = TransportBusinessSupport.resolveDeptFilterIds(
waybill.getAllDept(), waybill.getDeptId(), "运单管理", TransportBusinessSupport.MENU_WAYBILL_MANAGE);
if (Func.isNotEmpty(deptIdList)) {
if (deptIdList.size() == 1) {
queryWrapper.eq(Waybill::getDeptId, deptIdList.get(0));
} else {
queryWrapper.in(Waybill::getDeptId, deptIdList);
}
queryWrapper.and(wrapper -> {
if (deptIdList.size() == 1) {
wrapper.eq(Waybill::getDeptId, deptIdList.get(0));
} else {
wrapper.in(Waybill::getDeptId, deptIdList);
}
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, deptIdList);
});
}
if (TransportBusinessSupport.isOwnCreateScope(TransportBusinessSupport.MENU_WAYBILL_MANAGE)) {
queryWrapper.eq(Waybill::getCreateUser, AuthUtil.getUserId());
@@ -1820,14 +1823,18 @@ public class WaybillServiceImpl extends BaseServiceImpl<WaybillMapper, Waybill>
private LambdaQueryWrapper<Waybill> buildQuery(WaybillVO waybill) {
LambdaQueryWrapper<Waybill> queryWrapper = Wrappers.<Waybill>lambdaQuery().eq(Waybill::getIsDeleted, 0);
// 与常用线路等模块一致:超管默认不按组织过滤;普通用户 allDept!=1 时强制当前组织
// 同时放行「所属项目业务部门」落在可见组织内的数据
List<Long> deptIdList = TransportBusinessSupport.resolveDeptFilterIds(
waybill.getAllDept(), waybill.getDeptId(), "运单管理", TransportBusinessSupport.MENU_WAYBILL_MANAGE);
if (Func.isNotEmpty(deptIdList)) {
if (deptIdList.size() == 1) {
queryWrapper.eq(Waybill::getDeptId, deptIdList.get(0));
} else {
queryWrapper.in(Waybill::getDeptId, deptIdList);
}
queryWrapper.and(wrapper -> {
if (deptIdList.size() == 1) {
wrapper.eq(Waybill::getDeptId, deptIdList.get(0));
} else {
wrapper.in(Waybill::getDeptId, deptIdList);
}
TransportBusinessSupport.orProjectVisibleByBusinessDept(wrapper, deptIdList);
});
}
if (TransportBusinessSupport.isOwnCreateScope(TransportBusinessSupport.MENU_WAYBILL_MANAGE)) {
queryWrapper.eq(Waybill::getCreateUser, AuthUtil.getUserId());
@@ -23,23 +23,30 @@
package org.springblade.transport.support;
import com.baomidou.mybatisplus.core.conditions.AbstractWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.system.cache.RoleDataScopeCache;
import org.springblade.system.cache.SysCache;
import org.springblade.system.pojo.entity.Dept;
import org.springblade.system.pojo.vo.RoleDataScopeVO;
import org.springblade.transport.mapper.ProjectApplyMapper;
import org.springblade.transport.pojo.entity.ProjectApply;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 运输业务公共校验支持
@@ -234,6 +241,51 @@ public final class TransportBusinessSupport {
}
}
/**
* 列表可见范围 OR:所属项目的业务部门落在指定组织内。
* <p>
* 与项目立项「本部门可见 business_dept_id」对齐,使合同/运单等业务数据
* 在负责部门(organizationId/deptId)不是当前组织时,业务部门用户仍可看到。
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public static void orProjectVisibleByBusinessDept(AbstractWrapper<?, ?, ?> wrapper, Collection<Long> deptIds) {
if (wrapper == null || Func.isEmpty(deptIds)) {
return;
}
List<Long> ids = deptIds.stream().filter(Objects::nonNull).filter(id -> id > 0).distinct().toList();
if (ids.isEmpty()) {
return;
}
if (ids.size() == 1) {
wrapper.or().apply(
"project_id IN (SELECT id FROM blade_project_apply WHERE is_deleted = 0 AND business_dept_id = {0})",
ids.get(0));
return;
}
String inList = ids.stream().map(String::valueOf).collect(Collectors.joining(","));
wrapper.or().apply(
"project_id IN (SELECT id FROM blade_project_apply WHERE is_deleted = 0 AND business_dept_id IN ("
+ inList + "))");
}
/**
* 判断项目是否归属指定业务部门(用于详情只读/可操作判定)。
*/
public static boolean isProjectOwnedByBusinessDept(Long projectId, Long deptId) {
if (Func.isEmpty(projectId) || Func.isEmpty(deptId) || deptId <= 0) {
return false;
}
ProjectApplyMapper projectApplyMapper = SpringUtil.getBean(ProjectApplyMapper.class);
if (projectApplyMapper == null) {
return false;
}
Long count = projectApplyMapper.selectCount(Wrappers.<ProjectApply>lambdaQuery()
.eq(ProjectApply::getId, projectId)
.eq(ProjectApply::getBusinessDeptId, deptId)
.eq(ProjectApply::getIsDeleted, 0));
return count != null && count > 0;
}
/**
* 解析列表组织筛选 ID。
*
@@ -19,6 +19,7 @@ import org.springblade.transport.pojo.entity.LoadingManage;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.vo.ExceptionDisposalVO;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IMaintenanceRecordService;
import org.springblade.transport.service.IWaybillService;
import java.lang.reflect.Field;
@@ -86,7 +87,8 @@ class ExceptionDisposalDetailPayloadTest {
loadingManageMapper = mock(LoadingManageMapper.class);
service = new ExceptionDisposalServiceImpl(
followRecordMapper, waybillService, mock(IDriverWaybillService.class),
mock(org.springblade.transport.support.MpUserDataScopeSupport.class), loadingManageMapper);
mock(org.springblade.transport.support.MpUserDataScopeSupport.class), loadingManageMapper,
mock(IMaintenanceRecordService.class));
inject("baseMapper", disposalMapper);
}
@@ -20,6 +20,7 @@ import org.springblade.transport.pojo.entity.ExceptionDisposal;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.pojo.vo.ExceptionDisposalVO;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IMaintenanceRecordService;
import org.springblade.transport.service.IWaybillService;
import java.lang.reflect.Field;
@@ -73,7 +74,8 @@ class ExceptionDisposalListQueryTest {
waybillService,
mock(IDriverWaybillService.class),
scopeSupport,
loadingManageMapper);
loadingManageMapper,
mock(IMaintenanceRecordService.class));
inject("baseMapper", disposalMapper);
when(disposalMapper.selectPage(any(), any())).thenReturn(new Page<ExceptionDisposal>(1, 10));
}
@@ -21,6 +21,7 @@ import org.springblade.transport.pojo.entity.ExceptionDisposal;
import org.springblade.transport.pojo.entity.ExceptionDisposalFollowRecord;
import org.springblade.transport.pojo.vo.ExceptionDisposalVO;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IMaintenanceRecordService;
import org.springblade.transport.service.IWaybillService;
import java.lang.reflect.Field;
@@ -69,7 +70,7 @@ class ExceptionDisposalRejectRevokeTest {
service = new ExceptionDisposalServiceImpl(
followRecordMapper, mock(IWaybillService.class), mock(IDriverWaybillService.class),
mock(org.springblade.transport.support.MpUserDataScopeSupport.class),
mock(LoadingManageMapper.class));
mock(LoadingManageMapper.class), mock(IMaintenanceRecordService.class));
inject("baseMapper", disposalMapper);
when(disposalMapper.updateById(any(ExceptionDisposal.class))).thenReturn(1);
when(followRecordMapper.insert(any(ExceptionDisposalFollowRecord.class))).thenReturn(1);
@@ -19,6 +19,7 @@ import org.springblade.transport.mapper.LoadingManageMapper;
import org.springblade.transport.pojo.entity.ExceptionDisposal;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IMaintenanceRecordService;
import org.springblade.transport.service.IWaybillService;
import java.lang.reflect.Field;
@@ -74,7 +75,7 @@ class ExceptionDisposalReportGateTest {
service = new ExceptionDisposalServiceImpl(
mock(ExceptionDisposalFollowRecordMapper.class), waybillService, driverWaybillService,
mock(org.springblade.transport.support.MpUserDataScopeSupport.class),
mock(LoadingManageMapper.class));
mock(LoadingManageMapper.class), mock(IMaintenanceRecordService.class));
inject("baseMapper", disposalMapper);
when(waybillService.getById(WAYBILL_ID)).thenReturn(waybill());
@@ -23,6 +23,7 @@ import org.springblade.transport.pojo.entity.ExceptionDisposalFollowRecord;
import org.springblade.transport.pojo.entity.LoadingManage;
import org.springblade.transport.pojo.entity.Waybill;
import org.springblade.transport.service.IDriverWaybillService;
import org.springblade.transport.service.IMaintenanceRecordService;
import org.springblade.transport.service.IWaybillService;
import java.lang.reflect.Field;
@@ -88,7 +89,8 @@ class ExceptionDisposalRouteAdjustTest {
loadingManageMapper = mock(LoadingManageMapper.class);
service = new ExceptionDisposalServiceImpl(
followRecordMapper, waybillService, mock(IDriverWaybillService.class),
mock(org.springblade.transport.support.MpUserDataScopeSupport.class), loadingManageMapper);
mock(org.springblade.transport.support.MpUserDataScopeSupport.class), loadingManageMapper,
mock(IMaintenanceRecordService.class));
inject("baseMapper", disposalMapper);
when(disposalMapper.updateById(any(ExceptionDisposal.class))).thenReturn(1);
when(followRecordMapper.insert(any(ExceptionDisposalFollowRecord.class))).thenReturn(1);