feat: 支持审批步骤绑定部门与多对象
- 新增审批对象关联表和存量数据迁移 - 支持用户、角色、部门多选及办理权限匹配 - 完善部门状态与批量管理交互
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
package tech.easyflow.admin.controller.system;
|
||||
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.MockedStatic;
|
||||
import org.testng.annotations.Test;
|
||||
import tech.easyflow.approval.mapper.ApprovalFlowScopeMapper;
|
||||
import tech.easyflow.approval.mapper.ApprovalFlowStepAssigneeMapper;
|
||||
import tech.easyflow.common.constant.Constants;
|
||||
import tech.easyflow.common.constant.enums.EnumDataStatus;
|
||||
import tech.easyflow.common.domain.Result;
|
||||
import tech.easyflow.common.entity.LoginAccount;
|
||||
import tech.easyflow.common.satoken.util.SaTokenUtil;
|
||||
import tech.easyflow.system.entity.SysDept;
|
||||
import tech.easyflow.system.mapper.SysDeptMapper;
|
||||
import tech.easyflow.system.service.SysAccountService;
|
||||
import tech.easyflow.system.service.SysDeptService;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigInteger;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyCollection;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.mockStatic;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* {@link SysDeptController} 部门状态保存测试。
|
||||
*/
|
||||
public class SysDeptControllerTest {
|
||||
|
||||
/**
|
||||
* 验证批量状态修改使用单次更新并写入审计字段。
|
||||
*/
|
||||
@Test
|
||||
public void changeStatusBatchShouldUpdateAllDepartmentsOnce() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
SysDeptMapper mapper = mock(SysDeptMapper.class);
|
||||
SysDeptController controller = createController(service);
|
||||
List<BigInteger> ids = List.of(BigInteger.ONE, BigInteger.TWO);
|
||||
when(service.listByIds(anyCollection()))
|
||||
.thenReturn(List.of(buildDept(BigInteger.ONE, "dept_1"), buildDept(BigInteger.TWO, "dept_2")));
|
||||
when(service.getMapper()).thenReturn(mapper);
|
||||
when(mapper.updateByQuery(any(SysDept.class), any(QueryWrapper.class))).thenReturn(2);
|
||||
|
||||
LoginAccount loginAccount = mock(LoginAccount.class);
|
||||
when(loginAccount.getId()).thenReturn(BigInteger.TEN);
|
||||
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
|
||||
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(loginAccount);
|
||||
|
||||
Result<Integer> result = controller.changeStatusBatch(ids, EnumDataStatus.UNAVAILABLE.getCode());
|
||||
|
||||
assertEquals(result.getErrorCode(), 0);
|
||||
assertEquals(result.getData(), Integer.valueOf(2));
|
||||
}
|
||||
|
||||
ArgumentCaptor<SysDept> updateCaptor = ArgumentCaptor.forClass(SysDept.class);
|
||||
verify(mapper).updateByQuery(updateCaptor.capture(), any(QueryWrapper.class));
|
||||
assertEquals(updateCaptor.getValue().getStatus(), EnumDataStatus.UNAVAILABLE.getCode());
|
||||
assertEquals(updateCaptor.getValue().getModifiedBy(), BigInteger.TEN);
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证根部门不能通过批量接口禁用。
|
||||
*/
|
||||
@Test
|
||||
public void changeStatusBatchShouldRejectRootDepartmentDisable() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
SysDeptMapper mapper = mock(SysDeptMapper.class);
|
||||
SysDeptController controller = createController(service);
|
||||
SysDept root = buildDept(BigInteger.ONE, Constants.ROOT_DEPT);
|
||||
when(service.listByIds(anyCollection())).thenReturn(List.of(root));
|
||||
when(service.getMapper()).thenReturn(mapper);
|
||||
|
||||
Result<Integer> result = controller.changeStatusBatch(
|
||||
List.of(BigInteger.ONE),
|
||||
EnumDataStatus.UNAVAILABLE.getCode());
|
||||
|
||||
assertEquals(result.getErrorCode(), 1);
|
||||
assertEquals(result.getMessage(), "根部门不能禁用");
|
||||
verify(mapper, never()).updateByQuery(any(SysDept.class), any(QueryWrapper.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证批量状态修改拒绝非法状态。
|
||||
*/
|
||||
@Test
|
||||
public void changeStatusBatchShouldRejectInvalidStatus() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
SysDeptController controller = createController(service);
|
||||
|
||||
Result<Integer> result = controller.changeStatusBatch(List.of(BigInteger.ONE), 2);
|
||||
|
||||
assertEquals(result.getErrorCode(), 1);
|
||||
assertEquals(result.getMessage(), "部门状态不合法");
|
||||
verify(service, never()).listByIds(anyCollection());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证存在未选中下级部门时禁止批量删除。
|
||||
*/
|
||||
@Test
|
||||
public void removeBatchShouldRejectUnselectedChildDepartment() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
SysDeptController controller = createController(service);
|
||||
Collection<Serializable> ids = List.of(BigInteger.ONE);
|
||||
when(service.listByIds(ids)).thenReturn(List.of(buildDept(BigInteger.ONE, "dept_1")));
|
||||
when(service.count(any(QueryWrapper.class))).thenReturn(1L);
|
||||
|
||||
Result<?> result = controller.onRemoveBefore(ids);
|
||||
|
||||
assertEquals(result.getErrorCode(), 1);
|
||||
assertEquals(result.getMessage(), "所选部门包含未选中的下级部门,不能删除");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证审批步骤引用的部门不能禁用。
|
||||
*/
|
||||
@Test
|
||||
public void changeStatusBatchShouldRejectApprovalStepReference() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
ApprovalFlowStepAssigneeMapper assigneeMapper = mock(ApprovalFlowStepAssigneeMapper.class);
|
||||
SysDeptController controller = new SysDeptController(
|
||||
service,
|
||||
mock(SysAccountService.class),
|
||||
assigneeMapper,
|
||||
mock(ApprovalFlowScopeMapper.class));
|
||||
when(service.listByIds(anyCollection()))
|
||||
.thenReturn(List.of(buildDept(BigInteger.ONE, "dept_1")));
|
||||
when(assigneeMapper.selectCountByQuery(any(QueryWrapper.class))).thenReturn(1L);
|
||||
|
||||
Result<Integer> result = controller.changeStatusBatch(
|
||||
List.of(BigInteger.ONE),
|
||||
EnumDataStatus.UNAVAILABLE.getCode());
|
||||
|
||||
assertEquals(result.getErrorCode(), 1);
|
||||
assertEquals(result.getMessage(), "所选部门已被审批流程使用,不能禁用");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证审批范围引用的部门不能删除。
|
||||
*/
|
||||
@Test
|
||||
public void removeBatchShouldRejectApprovalScopeReference() {
|
||||
SysDeptService service = mock(SysDeptService.class);
|
||||
ApprovalFlowScopeMapper scopeMapper = mock(ApprovalFlowScopeMapper.class);
|
||||
SysDeptController controller = new SysDeptController(
|
||||
service,
|
||||
mock(SysAccountService.class),
|
||||
mock(ApprovalFlowStepAssigneeMapper.class),
|
||||
scopeMapper);
|
||||
Collection<Serializable> ids = List.of(BigInteger.ONE);
|
||||
when(service.listByIds(ids)).thenReturn(List.of(buildDept(BigInteger.ONE, "dept_1")));
|
||||
when(service.count(any(QueryWrapper.class))).thenReturn(0L);
|
||||
when(scopeMapper.selectCountByQuery(any(QueryWrapper.class))).thenReturn(1L);
|
||||
|
||||
Result<?> result = controller.onRemoveBefore(ids);
|
||||
|
||||
assertEquals(result.getErrorCode(), 1);
|
||||
assertEquals(result.getMessage(), "所选部门已被审批流程使用,请先调整审批配置");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证新增部门未传状态时默认启用。
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldDefaultMissingStatusToAvailable() {
|
||||
SysDept entity = buildDept(null);
|
||||
|
||||
invokeSaveBefore(entity);
|
||||
|
||||
assertEquals(entity.getStatus(), EnumDataStatus.AVAILABLE.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证新增部门显式传入未启用状态时保持原值。
|
||||
*/
|
||||
@Test
|
||||
public void saveShouldPreserveExplicitUnavailableStatus() {
|
||||
SysDept entity = buildDept(EnumDataStatus.UNAVAILABLE.getCode());
|
||||
|
||||
invokeSaveBefore(entity);
|
||||
|
||||
assertEquals(entity.getStatus(), EnumDataStatus.UNAVAILABLE.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造待保存的部门。
|
||||
*
|
||||
* @param status 部门状态
|
||||
* @return 部门实体
|
||||
*/
|
||||
private SysDept buildDept(Integer status) {
|
||||
SysDept entity = new SysDept();
|
||||
entity.setParentId(BigInteger.ZERO);
|
||||
entity.setStatus(status);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构造指定主键和编码的部门。
|
||||
*
|
||||
* @param id 部门主键
|
||||
* @param deptCode 部门编码
|
||||
* @return 部门实体
|
||||
*/
|
||||
private SysDept buildDept(BigInteger id, String deptCode) {
|
||||
SysDept entity = new SysDept();
|
||||
entity.setId(id);
|
||||
entity.setDeptCode(deptCode);
|
||||
return entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用新增前置处理。
|
||||
*
|
||||
* @param entity 部门实体
|
||||
*/
|
||||
private void invokeSaveBefore(SysDept entity) {
|
||||
LoginAccount loginAccount = mock(LoginAccount.class);
|
||||
SysDeptController controller = createController(mock(SysDeptService.class));
|
||||
try (MockedStatic<SaTokenUtil> saToken = mockStatic(SaTokenUtil.class)) {
|
||||
saToken.when(SaTokenUtil::getLoginAccount).thenReturn(loginAccount);
|
||||
controller.onSaveOrUpdateBefore(entity, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带有隔离依赖的部门控制器。
|
||||
*
|
||||
* @param service 部门服务
|
||||
* @return 部门控制器
|
||||
*/
|
||||
private SysDeptController createController(SysDeptService service) {
|
||||
return new SysDeptController(
|
||||
service,
|
||||
mock(SysAccountService.class),
|
||||
mock(ApprovalFlowStepAssigneeMapper.class),
|
||||
mock(ApprovalFlowScopeMapper.class));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user