Commit 61ca559f97b82d04e181c403dccbb8c4eb105822
1 parent
ed24181e
fix(bpm): 修复流程详情表单权限错配
校验任务归属流程与当前用户,并在发起人无待办时回落为只读权限。补充跨流程任务、他人待办及流程结束场景的 Flowable 集成测试。
Showing
4 changed files
with
247 additions
and
17 deletions
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java
| ... | ... | @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; |
| 22 | 22 | import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionInfoDO; |
| 23 | 23 | import cn.iocoder.yudao.module.bpm.dal.redis.BpmProcessIdRedisDAO; |
| 24 | 24 | import cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants; |
| 25 | +import cn.iocoder.yudao.module.bpm.enums.definition.BpmFieldPermissionEnum; | |
| 25 | 26 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelFormTypeEnum; |
| 26 | 27 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmModelTypeEnum; |
| 27 | 28 | import cn.iocoder.yudao.module.bpm.enums.definition.BpmSimpleModelNodeTypeEnum; |
| ... | ... | @@ -152,19 +153,82 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 152 | 153 | .list(); |
| 153 | 154 | } |
| 154 | 155 | |
| 155 | - private Map<String, String> getFormFieldsPermission(BpmnModel bpmnModel, | |
| 156 | - String activityId, String taskId) { | |
| 157 | - // 1. 获取流程活动编号。流程活动 Id 为空事,从流程任务中获取流程活动 Id | |
| 158 | - if (StrUtil.isEmpty(activityId) && StrUtil.isNotEmpty(taskId)) { | |
| 159 | - activityId = Optional.ofNullable(taskService.getHistoricTask(taskId)) | |
| 160 | - .map(HistoricTaskInstance::getTaskDefinitionKey).orElse(null); | |
| 156 | + /** | |
| 157 | + * 获得当前登录用户的表单字段权限 | |
| 158 | + * | |
| 159 | + * @param loginUserId 当前登录用户编号 | |
| 160 | + * @param bpmnModel 流程模型 | |
| 161 | + * @param reqVO 审批详情请求 | |
| 162 | + * @param processInstance 流程实例;为 null 时,表示流程未发起 | |
| 163 | + * @param todoTask 当前登录用户的待办任务 | |
| 164 | + * @return 表单字段权限 | |
| 165 | + */ | |
| 166 | + private Map<String, String> getFormFieldsPermission(Long loginUserId, BpmnModel bpmnModel, | |
| 167 | + BpmApprovalDetailReqVO reqVO, | |
| 168 | + HistoricProcessInstance processInstance, | |
| 169 | + BpmTaskRespVO todoTask) { | |
| 170 | + // 情况一:有待办任务,以待办任务所在节点的表单权限为准,可编辑 | |
| 171 | + if (todoTask != null) { | |
| 172 | + return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, todoTask.getTaskDefinitionKey()); | |
| 173 | + } | |
| 174 | + // 情况二:流程未发起,使用传递的流程活动(例如说,发起人节点)的表单权限,可编辑 | |
| 175 | + if (processInstance == null) { | |
| 176 | + return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, reqVO.getActivityId()); | |
| 161 | 177 | } |
| 178 | + | |
| 179 | + // 情况三:流程已发起,但没有待办任务,只能查看 | |
| 180 | + // 3.1 优先,使用自己办理过的任务(已办)所在节点 | |
| 181 | + String activityId = getMyHistoricTaskDefinitionKey(loginUserId, reqVO.getTaskId(), processInstance.getId()); | |
| 182 | + // 3.2 其次,使用传递的流程活动(例如说,抄送节点) | |
| 162 | 183 | if (StrUtil.isEmpty(activityId)) { |
| 184 | + activityId = reqVO.getActivityId(); | |
| 185 | + } | |
| 186 | + // 3.3 最后,如果是流程发起人(例如说,从“我的流程”进入),使用发起人节点 | |
| 187 | + if (StrUtil.isEmpty(activityId) && ObjUtil.equal(String.valueOf(loginUserId), processInstance.getStartUserId())) { | |
| 188 | + activityId = START_USER_NODE_ID; | |
| 189 | + } | |
| 190 | + // 没有待办任务,无法提交表单,所以将“可编辑”降级为“只读”,避免误导 | |
| 191 | + return downgradeWritePermission(BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId)); | |
| 192 | + } | |
| 193 | + | |
| 194 | + /** | |
| 195 | + * 获得用户在指定流程实例中,办理过的 taskId 任务所在的节点编号 | |
| 196 | + * | |
| 197 | + * @param userId 用户编号 | |
| 198 | + * @param taskId 任务编号 | |
| 199 | + * @param processInstanceId 流程实例编号 | |
| 200 | + * @return 节点编号;任务不存在、不属于该流程实例、或者不是该用户办理的,返回 null | |
| 201 | + */ | |
| 202 | + private String getMyHistoricTaskDefinitionKey(Long userId, String taskId, String processInstanceId) { | |
| 203 | + if (StrUtil.isEmpty(taskId)) { | |
| 163 | 204 | return null; |
| 164 | 205 | } |
| 206 | + HistoricTaskInstance task = taskService.getHistoricTask(taskId); | |
| 207 | + if (task == null || ObjUtil.notEqual(task.getProcessInstanceId(), processInstanceId)) { | |
| 208 | + return null; | |
| 209 | + } | |
| 210 | + // 校验是该用户办理(审批人或拥有人)的任务 | |
| 211 | + String userIdStr = String.valueOf(userId); | |
| 212 | + if (ObjUtil.notEqual(userIdStr, task.getAssignee()) && ObjUtil.notEqual(userIdStr, task.getOwner())) { | |
| 213 | + return null; | |
| 214 | + } | |
| 215 | + return task.getTaskDefinitionKey(); | |
| 216 | + } | |
| 165 | 217 | |
| 166 | - // 2. 从 BpmnModel 中解析表单字段权限 | |
| 167 | - return BpmnModelUtils.parseFormFieldsPermission(bpmnModel, activityId); | |
| 218 | + /** | |
| 219 | + * 将表单字段权限中的“可编辑”降级为“只读” | |
| 220 | + * | |
| 221 | + * @param fieldsPermission 表单字段权限 | |
| 222 | + * @return 表单字段权限 | |
| 223 | + */ | |
| 224 | + private static Map<String, String> downgradeWritePermission(Map<String, String> fieldsPermission) { | |
| 225 | + if (CollUtil.isEmpty(fieldsPermission)) { | |
| 226 | + return fieldsPermission; | |
| 227 | + } | |
| 228 | + String write = String.valueOf(BpmFieldPermissionEnum.WRITE.getPermission()); | |
| 229 | + String read = String.valueOf(BpmFieldPermissionEnum.READ.getPermission()); | |
| 230 | + fieldsPermission.replaceAll((field, permission) -> write.equals(permission) ? read : permission); | |
| 231 | + return fieldsPermission; | |
| 168 | 232 | } |
| 169 | 233 | |
| 170 | 234 | @Override |
| ... | ... | @@ -221,7 +285,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 221 | 285 | |
| 222 | 286 | // 2.2 流程已经结束,直接 return,无需预测 |
| 223 | 287 | if (BpmProcessInstanceStatusEnum.isProcessEndStatus(processInstanceStatus)) { |
| 224 | - return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, | |
| 288 | + return buildApprovalDetail(loginUserId, reqVO, bpmnModel, processDefinition, processDefinitionInfo, | |
| 225 | 289 | historicProcessInstance, |
| 226 | 290 | processInstanceStatus, endActivityNodes, runActivityNodes, null, null); |
| 227 | 291 | } |
| ... | ... | @@ -246,7 +310,7 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 246 | 310 | processVariables, activities, needSimulateTaskDefKeysByReturn); |
| 247 | 311 | |
| 248 | 312 | // 4. 拼接最终数据 |
| 249 | - return buildApprovalDetail(reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, | |
| 313 | + return buildApprovalDetail(loginUserId, reqVO, bpmnModel, processDefinition, processDefinitionInfo, historicProcessInstance, | |
| 250 | 314 | processInstanceStatus, endActivityNodes, runActivityNodes, simulateActivityNodes, todoTask); |
| 251 | 315 | } |
| 252 | 316 | |
| ... | ... | @@ -371,7 +435,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 371 | 435 | * <p> |
| 372 | 436 | * 主要是,拼接审批人的用户信息、部门信息 |
| 373 | 437 | */ |
| 374 | - private BpmApprovalDetailRespVO buildApprovalDetail(BpmApprovalDetailReqVO reqVO, | |
| 438 | + private BpmApprovalDetailRespVO buildApprovalDetail(Long loginUserId, | |
| 439 | + BpmApprovalDetailReqVO reqVO, | |
| 375 | 440 | BpmnModel bpmnModel, |
| 376 | 441 | ProcessDefinition processDefinition, |
| 377 | 442 | BpmProcessDefinitionInfoDO processDefinitionInfo, |
| ... | ... | @@ -389,8 +454,8 @@ public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService |
| 389 | 454 | Map<Long, DeptRespDTO> deptMap = deptApi.getDeptMap(convertSet(userMap.values(), AdminUserRespDTO::getDeptId)); |
| 390 | 455 | |
| 391 | 456 | // 2. 表单权限 |
| 392 | - String taskId = reqVO.getTaskId() == null && todoTask != null ? todoTask.getId() : reqVO.getTaskId(); | |
| 393 | - Map<String, String> formFieldsPermission = getFormFieldsPermission(bpmnModel, reqVO.getActivityId(), taskId); | |
| 457 | + Map<String, String> formFieldsPermission = getFormFieldsPermission(loginUserId, bpmnModel, reqVO, | |
| 458 | + processInstance, todoTask); | |
| 394 | 459 | |
| 395 | 460 | // 3. 拼接数据 |
| 396 | 461 | return BpmProcessInstanceConvert.INSTANCE.buildApprovalDetail(bpmnModel, processDefinition, | ... | ... |
yudao-module-bpm/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java
| ... | ... | @@ -148,7 +148,7 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 148 | 148 | @Override |
| 149 | 149 | public BpmTaskRespVO getTodoTask(Long userId, String taskId, String processInstanceId) { |
| 150 | 150 | // 1.1 获取指定的用户待办任务 |
| 151 | - Task todoTask = getMyTodoTask(userId, taskId); | |
| 151 | + Task todoTask = getMyTodoTask(userId, taskId, processInstanceId); | |
| 152 | 152 | // 1.2 获取不到,则获取该流程实例下,第一个用户的待办任务 |
| 153 | 153 | if (todoTask == null) { |
| 154 | 154 | todoTask = getMyFirstTodoTask(userId, processInstanceId); |
| ... | ... | @@ -181,11 +181,12 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 181 | 181 | /** |
| 182 | 182 | * 获得用户指定 taskId 任务编号的“待办”(未审批、且可审核)的任务 |
| 183 | 183 | * |
| 184 | - * @param userId 用户编号 | |
| 185 | - * @param taskId 任务编号 | |
| 184 | + * @param userId 用户编号 | |
| 185 | + * @param taskId 任务编号 | |
| 186 | + * @param processInstanceId 流程编号 | |
| 186 | 187 | * @return 任务 |
| 187 | 188 | */ |
| 188 | - private Task getMyTodoTask(Long userId, String taskId) { | |
| 189 | + private Task getMyTodoTask(Long userId, String taskId, String processInstanceId) { | |
| 189 | 190 | if (StrUtil.isEmpty(taskId)) { |
| 190 | 191 | return null; |
| 191 | 192 | } |
| ... | ... | @@ -193,6 +194,10 @@ public class BpmTaskServiceImpl implements BpmTaskService { |
| 193 | 194 | if (task == null) { |
| 194 | 195 | return null; |
| 195 | 196 | } |
| 197 | + // 校验任务属于该流程实例,避免使用其它流程实例的任务 | |
| 198 | + if (ObjectUtil.notEqual(task.getProcessInstanceId(), processInstanceId)) { | |
| 199 | + return null; | |
| 200 | + } | |
| 196 | 201 | if (!isAssignUserTask(userId, task) && !isAddSignUserTask(userId, task)) { |
| 197 | 202 | return null; |
| 198 | 203 | } | ... | ... |
yudao-module-bpm/src/test/java/cn/iocoder/yudao/module/bpm/framework/flowable/BpmProcessInstanceQueryFlowableTest.java
| ... | ... | @@ -18,6 +18,7 @@ import jakarta.annotation.Resource; |
| 18 | 18 | import org.flowable.engine.RepositoryService; |
| 19 | 19 | import org.flowable.engine.RuntimeService; |
| 20 | 20 | import org.flowable.engine.TaskService; |
| 21 | +import org.flowable.engine.delegate.DelegateExecution; | |
| 21 | 22 | import org.flowable.engine.history.HistoricProcessInstance; |
| 22 | 23 | import org.flowable.engine.repository.Deployment; |
| 23 | 24 | import org.flowable.engine.runtime.ProcessInstance; |
| ... | ... | @@ -36,6 +37,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.PROCESS_INSTA |
| 36 | 37 | import static cn.iocoder.yudao.module.bpm.framework.flowable.core.enums.BpmnModelConstants.START_USER_NODE_ID; |
| 37 | 38 | import static org.junit.jupiter.api.Assertions.*; |
| 38 | 39 | import static org.mockito.ArgumentMatchers.any; |
| 40 | +import static org.mockito.Mockito.doAnswer; | |
| 39 | 41 | import static org.mockito.Mockito.when; |
| 40 | 42 | |
| 41 | 43 | /** |
| ... | ... | @@ -186,6 +188,120 @@ public class BpmProcessInstanceQueryFlowableTest extends BaseFlowableUnitTest { |
| 186 | 188 | new BpmApprovalDetailReqVO().setProcessDefinitionId("not-exists")), PROCESS_DEFINITION_NOT_EXISTS); |
| 187 | 189 | } |
| 188 | 190 | |
| 191 | + // ========== getApprovalDetail 表单字段权限 ========== | |
| 192 | + | |
| 193 | + @Test // 发起人从“我的流程”进入,待办属于其他审批人:使用发起人节点的权限,可编辑降级为只读 | |
| 194 | + public void testGetApprovalDetail_formFieldsPermission_startUserWithoutTodo() { | |
| 195 | + // 准备参数:发起人 1,task1 待用户 2 审批 | |
| 196 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 197 | + | |
| 198 | + // 调用 | |
| 199 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(1L, | |
| 200 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId)); | |
| 201 | + // 断言 | |
| 202 | + assertNull(respVO.getTodoTask()); | |
| 203 | + assertEquals(Map.of("a", "1", "b", "3", "c", "1"), respVO.getFormFieldsPermission()); | |
| 204 | + } | |
| 205 | + | |
| 206 | + @Test // 审批人有本流程的待办:使用待办所在节点的权限,保留可编辑 | |
| 207 | + public void testGetApprovalDetail_formFieldsPermission_todoTask() { | |
| 208 | + // 准备参数:task1 待用户 2 审批 | |
| 209 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 210 | + Task task1 = getRunningTask(processInstanceId); | |
| 211 | + | |
| 212 | + // 调用 | |
| 213 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(2L, | |
| 214 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId)); | |
| 215 | + // 断言 | |
| 216 | + assertEquals(task1.getId(), respVO.getTodoTask().getId()); | |
| 217 | + assertEquals(Map.of("a", "1", "b", "2", "c", "3"), respVO.getFormFieldsPermission()); | |
| 218 | + } | |
| 219 | + | |
| 220 | + @Test // 传递其它流程实例的待办 taskId:忽略该任务,使用本流程实例的待办 | |
| 221 | + public void testGetApprovalDetail_formFieldsPermission_todoTaskOfOtherProcessInstance() { | |
| 222 | + // 准备参数:两个流程实例,task1 均待用户 2 审批 | |
| 223 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 224 | + Task task1 = getRunningTask(processInstanceId); | |
| 225 | + Task otherTask1 = getRunningTask(startFormPermissionProcessInstance()); | |
| 226 | + | |
| 227 | + // 调用 | |
| 228 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(2L, | |
| 229 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId).setTaskId(otherTask1.getId())); | |
| 230 | + // 断言 | |
| 231 | + assertEquals(task1.getId(), respVO.getTodoTask().getId()); | |
| 232 | + assertEquals(processInstanceId, respVO.getTodoTask().getProcessInstanceId()); | |
| 233 | + assertEquals(Map.of("a", "1", "b", "2", "c", "3"), respVO.getFormFieldsPermission()); | |
| 234 | + } | |
| 235 | + | |
| 236 | + @Test // 发起人传递其他审批人的 taskId:忽略该任务,回落发起人节点的权限 | |
| 237 | + public void testGetApprovalDetail_formFieldsPermission_taskIdOfOtherUser() { | |
| 238 | + // 准备参数:task1 待用户 2 审批 | |
| 239 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 240 | + Task task1 = getRunningTask(processInstanceId); | |
| 241 | + | |
| 242 | + // 调用 | |
| 243 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(1L, | |
| 244 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId).setTaskId(task1.getId())); | |
| 245 | + // 断言 | |
| 246 | + assertNull(respVO.getTodoTask()); | |
| 247 | + assertEquals(Map.of("a", "1", "b", "3", "c", "1"), respVO.getFormFieldsPermission()); | |
| 248 | + } | |
| 249 | + | |
| 250 | + @Test // 流程已结束:已办使用办理节点的权限,发起人使用发起人节点的权限,均降级为只读;其他人不返回权限 | |
| 251 | + public void testGetApprovalDetail_formFieldsPermission_processEnd() { | |
| 252 | + // 准备参数:用户 2 审批通过 task1,流程结束 | |
| 253 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 254 | + Task task1 = getRunningTask(processInstanceId); | |
| 255 | + taskService.approveTask(2L, new BpmTaskApproveReqVO().setId(task1.getId()).setReason("同意")); | |
| 256 | + | |
| 257 | + // 调用 + 断言:用户 2 从“已办”进入 | |
| 258 | + BpmApprovalDetailRespVO doneRespVO = processInstanceService.getApprovalDetail(2L, | |
| 259 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId).setTaskId(task1.getId())); | |
| 260 | + assertEquals(BpmProcessInstanceStatusEnum.APPROVE.getStatus(), doneRespVO.getStatus()); | |
| 261 | + assertNull(doneRespVO.getTodoTask()); | |
| 262 | + assertEquals(Map.of("a", "1", "b", "1", "c", "3"), doneRespVO.getFormFieldsPermission()); | |
| 263 | + // 调用 + 断言:发起人 1 从“我的流程”进入 | |
| 264 | + BpmApprovalDetailRespVO startUserRespVO = processInstanceService.getApprovalDetail(1L, | |
| 265 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId)); | |
| 266 | + assertEquals(Map.of("a", "1", "b", "3", "c", "1"), startUserRespVO.getFormFieldsPermission()); | |
| 267 | + // 调用 + 断言:用户 2 不传 taskId,既不是发起人也没有待办 | |
| 268 | + BpmApprovalDetailRespVO otherRespVO = processInstanceService.getApprovalDetail(2L, | |
| 269 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId)); | |
| 270 | + assertNull(otherRespVO.getFormFieldsPermission()); | |
| 271 | + } | |
| 272 | + | |
| 273 | + @Test // 传递其它流程实例的已办 taskId:忽略该任务 | |
| 274 | + public void testGetApprovalDetail_formFieldsPermission_doneTaskOfOtherProcessInstance() { | |
| 275 | + // 准备参数:两个流程实例,task1 均由用户 2 审批通过 | |
| 276 | + String processInstanceId = startFormPermissionProcessInstance(); | |
| 277 | + taskService.approveTask(2L, new BpmTaskApproveReqVO().setId(getRunningTask(processInstanceId).getId()) | |
| 278 | + .setReason("同意")); | |
| 279 | + String otherProcessInstanceId = startFormPermissionProcessInstance(); | |
| 280 | + Task otherTask1 = getRunningTask(otherProcessInstanceId); | |
| 281 | + taskService.approveTask(2L, new BpmTaskApproveReqVO().setId(otherTask1.getId()).setReason("同意")); | |
| 282 | + | |
| 283 | + // 调用 | |
| 284 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(2L, | |
| 285 | + new BpmApprovalDetailReqVO().setProcessInstanceId(processInstanceId).setTaskId(otherTask1.getId())); | |
| 286 | + // 断言 | |
| 287 | + assertNull(respVO.getFormFieldsPermission()); | |
| 288 | + } | |
| 289 | + | |
| 290 | + @Test // 流程未发起:使用传递的发起人节点的权限,保留可编辑 | |
| 291 | + public void testGetApprovalDetail_formFieldsPermission_notStart() { | |
| 292 | + // 准备参数 | |
| 293 | + deploy("bpmn/form-permission.bpmn20.xml"); | |
| 294 | + String processDefinitionId = repositoryService.createProcessDefinitionQuery() | |
| 295 | + .processDefinitionKey("formPermission").latestVersion().singleResult().getId(); | |
| 296 | + | |
| 297 | + // 调用 | |
| 298 | + BpmApprovalDetailRespVO respVO = processInstanceService.getApprovalDetail(1L, new BpmApprovalDetailReqVO() | |
| 299 | + .setProcessDefinitionId(processDefinitionId).setActivityId(START_USER_NODE_ID)); | |
| 300 | + // 断言 | |
| 301 | + assertNull(respVO.getTodoTask()); | |
| 302 | + assertEquals(Map.of("a", "2", "b", "3", "c", "1"), respVO.getFormFieldsPermission()); | |
| 303 | + } | |
| 304 | + | |
| 189 | 305 | // ========== getProcessInstanceBpmnModelView ========== |
| 190 | 306 | |
| 191 | 307 | @Test |
| ... | ... | @@ -313,6 +429,21 @@ public class BpmProcessInstanceQueryFlowableTest extends BaseFlowableUnitTest { |
| 313 | 429 | .setProcessDefinitionKey("twoStepApprove").setVariables(variables)); |
| 314 | 430 | } |
| 315 | 431 | |
| 432 | + /** | |
| 433 | + * 发起表单字段权限流程:发起人 1 的发起人节点自动通过,task1 待用户 2 审批 | |
| 434 | + */ | |
| 435 | + private String startFormPermissionProcessInstance() { | |
| 436 | + if (repositoryService.createProcessDefinitionQuery().processDefinitionKey("formPermission").count() == 0) { | |
| 437 | + deploy("bpmn/form-permission.bpmn20.xml"); | |
| 438 | + } | |
| 439 | + doAnswer(invocation -> { | |
| 440 | + DelegateExecution execution = invocation.getArgument(0); | |
| 441 | + return START_USER_NODE_ID.equals(execution.getCurrentActivityId()) ? Set.of(1L) : Set.of(2L); | |
| 442 | + }).when(taskCandidateInvoker).calculateUsersByTask(any()); | |
| 443 | + return processInstanceService.createProcessInstance(1L, new BpmProcessInstanceCreateReqDTO() | |
| 444 | + .setProcessDefinitionKey("formPermission")); | |
| 445 | + } | |
| 446 | + | |
| 316 | 447 | private Task getRunningTask(String processInstanceId) { |
| 317 | 448 | List<Task> tasks = flowableTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); |
| 318 | 449 | assertEquals(1, tasks.size()); | ... | ... |
yudao-module-bpm/src/test/resources/bpmn/form-permission.bpmn20.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" | |
| 3 | + xmlns:flowable="http://flowable.org/bpmn" | |
| 4 | + targetNamespace="http://www.yudao.iocoder.cn/bpm"> | |
| 5 | + <!-- 表单字段权限:1 只读、2 可编辑、3 隐藏;发起人节点、审批节点配置不同的权限,用于区分权限来源 --> | |
| 6 | + <process id="formPermission" name="表单字段权限" isExecutable="true"> | |
| 7 | + <startEvent id="start"/> | |
| 8 | + <sequenceFlow id="flow-start" sourceRef="start" targetRef="StartUserNode"/> | |
| 9 | + <userTask id="StartUserNode" name="发起人"> | |
| 10 | + <extensionElements> | |
| 11 | + <flowable:candidateStrategy>36</flowable:candidateStrategy> | |
| 12 | + <flowable:fieldsPermission field="a" permission="2"/> | |
| 13 | + <flowable:fieldsPermission field="b" permission="3"/> | |
| 14 | + <flowable:fieldsPermission field="c" permission="1"/> | |
| 15 | + </extensionElements> | |
| 16 | + </userTask> | |
| 17 | + <sequenceFlow id="flow-start-user" sourceRef="StartUserNode" targetRef="task1"/> | |
| 18 | + <userTask id="task1" name="审批"> | |
| 19 | + <extensionElements> | |
| 20 | + <flowable:candidateStrategy>30</flowable:candidateStrategy> | |
| 21 | + <flowable:fieldsPermission field="a" permission="1"/> | |
| 22 | + <flowable:fieldsPermission field="b" permission="2"/> | |
| 23 | + <flowable:fieldsPermission field="c" permission="3"/> | |
| 24 | + </extensionElements> | |
| 25 | + </userTask> | |
| 26 | + <sequenceFlow id="flow-task1" sourceRef="task1" targetRef="end"/> | |
| 27 | + <endEvent id="end"/> | |
| 28 | + </process> | |
| 29 | +</definitions> | ... | ... |