feat(engine): NOTIFY 抄送 + CONDITION 条件路由 + JOIN scope 修复(两批全栈)
build / build-push (push) Successful in 47s
build / build-push (push) Successful in 47s
- NOTIFY:TYPE_NOTIFY 瞬时抄送(flw_cc 逐人留痕 + CC_SENT 事件 + 站内通知不加待办角标)、/api/flow/cc/my、轨迹 kind=CC 与 oapi progress 抄送步、示意图青框卡片
- CONDITION:flw_router 判断服务注册 + flw_route_log 决策留痕(REQUIRES_NEW,reroute 回滚不丢失败行)+ 同步判断调用(服务目录寻址 + 平台签名,3s×3 退避重试)+ 失败挂起/管理端重跑(不配默认出口)+ 可选事件 flow.route.decided
- JOIN scope:branch_key 路径前缀编码 + scope 级到齐放行 + DefValidator SPLIT/JOIN 配对与键长守卫(存量无点号键零迁移,历史直连图回退实例级口径)
- 管理端:/api/flow/admin/router/* CRUD + POST /api/flow/admin/instance/{id}/reroute
- 生产 SQL:sql/20260923_create_flw_cc.sql(含 flw_task 时间列升 DATETIME(3))、20260924_create_flw_router_and_route_log.sql
- 测试:全量 125 绿(FlowEngineIT 24,含条件/嵌套并行/退回重走用例)
This commit is contained in:
@@ -43,6 +43,8 @@ class FlowEngineIT extends FlowTestSupport {
|
||||
private FlowTaskService taskService;
|
||||
@Autowired
|
||||
private com.yunhai.flowcenter.service.FlowQueryService queryService;
|
||||
@Autowired
|
||||
private com.yunhai.flowcenter.service.FlowRouterAdminService routerAdminService;
|
||||
|
||||
@TestConfiguration
|
||||
static class StubConfig {
|
||||
@@ -51,11 +53,47 @@ class FlowEngineIT extends FlowTestSupport {
|
||||
public com.yunhai.flowcenter.stub.StubUserClient stubUserClient() {
|
||||
return new com.yunhai.flowcenter.stub.StubUserClient();
|
||||
}
|
||||
|
||||
/**
|
||||
* 路由判断桩(2026-09-24 CONDITION):替换真实 RouteJudgeClient(不出网),
|
||||
* 每次调用取 StubJudge 当前编程值——出口名或抛错。真实客户端的重试/寻址逻辑
|
||||
* 由 RouteJudgeClientTest 覆盖;本类聚焦引擎行为(选路/挂起/重跑/重判)。
|
||||
*/
|
||||
@Bean
|
||||
@Primary
|
||||
public RouteJudgeClient stubRouteJudgeClient() {
|
||||
return new RouteJudgeClient(null, new com.fasterxml.jackson.databind.ObjectMapper()) {
|
||||
@Override
|
||||
public RouteJudgeClient.JudgeResult call(com.yunhai.flowcenter.entity.FlwRouter router,
|
||||
RouteJudgeClient.JudgeBody body) {
|
||||
return StubJudge.next();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/** 判断桩的编程值:outlet=命中出口;failure=非空时抛出(模拟服务不可用) */
|
||||
static final class StubJudge {
|
||||
static volatile String outlet = "甲线";
|
||||
static volatile RuntimeException failure;
|
||||
|
||||
static RouteJudgeClient.JudgeResult next() {
|
||||
if (failure != null) {
|
||||
throw failure;
|
||||
}
|
||||
return new RouteJudgeClient.JudgeResult(outlet, "{\"outlet\":\"" + outlet + "\"}");
|
||||
}
|
||||
|
||||
static void reset(String defaultOutlet) {
|
||||
outlet = defaultOutlet;
|
||||
failure = null;
|
||||
}
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
cleanDb();
|
||||
StubJudge.reset("甲线");
|
||||
}
|
||||
|
||||
private FlowInstanceService.ApplyOutcome apply(String flowGuid, String bizId,
|
||||
@@ -433,6 +471,286 @@ class FlowEngineIT extends FlowTestSupport {
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTIFY 抄送·主线(2026-09-23):激活即逐人落 flw_cc,不建任务、不进 currentNodes,
|
||||
* 流程无停顿直达下一审批节点;办件轨迹出现 kind=CC 行且"抄送我的"可查到。
|
||||
*/
|
||||
@Test
|
||||
void notify_onMainline_writesCcRows_andKeepsFlowMoving() {
|
||||
mapDept("km", 101, "甲");
|
||||
FlwDef def = saveAndPublishDef("t16", "抄送主线", notifyMainlineDef("km"));
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-16", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
|
||||
// 抄送瞬时放行:两个接收人各一行,无 cc 节点任务,直接建审核待办
|
||||
List<com.yunhai.flowcenter.entity.FlwCc> ccs = ccRepository.findByInstanceIdOrderByIdAsc(instanceId);
|
||||
assertEquals(2, ccs.size());
|
||||
assertEquals("cc1", ccs.get(0).getNodeId());
|
||||
assertEquals("抄送校领导", ccs.get(0).getNodeName());
|
||||
assertEquals(301, ccs.get(0).getUserId());
|
||||
assertEquals(302, ccs.get(1).getUserId());
|
||||
assertEquals(1, taskRepository.findByInstanceIdAndStatus(instanceId, 0).size());
|
||||
FlwInstance instance = instanceRepository.findById(instanceId).get();
|
||||
assertEquals("n1", instance.getCurrentNodes());
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(), instance.getStatus());
|
||||
// 审核通过 → 完成(抄送节点从未阻塞过推进)
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
|
||||
// 轨迹:发起 → 抄送×2 → 同意。时间列毫秒精度(DATETIME(3))后亚秒机器链因果序可复现;
|
||||
// 展示字符串截断到秒(str),排序用原值。
|
||||
java.util.List<java.util.Map<String, Object>> trace =
|
||||
queryService.detail(SCH, instanceId, null).getTrace();
|
||||
java.util.List<String> kinds = new java.util.ArrayList<>();
|
||||
for (java.util.Map<String, Object> row : trace) {
|
||||
kinds.add((String) row.get("kind"));
|
||||
}
|
||||
assertEquals(java.util.Arrays.asList("SUBMIT", "CC", "CC", "APPROVE"), kinds);
|
||||
// 抄送我的:301 视角一行,回填办件信息
|
||||
com.yunhai.platform.utils.model.BasePageResult<com.yunhai.flowcenter.model.FlowModels.CcItem>
|
||||
ccPage = queryService.pageCc(SCH, 301, 1, 10);
|
||||
assertEquals(1, ccPage.getContent().size());
|
||||
assertEquals(instanceId, ccPage.getContent().get(0).getInstanceId());
|
||||
assertEquals("张三的测试办件", ccPage.getContent().get(0).getBizTitle());
|
||||
}
|
||||
|
||||
/** NOTIFY 在并行分支内:瞬时到达 JOIN 不占等待(审批支到齐即放行),落库与轨迹同主线口径 */
|
||||
@Test
|
||||
void notify_inParallelBranch_reachesJoin_withoutBlocking() {
|
||||
mapDept("km", 101, "甲");
|
||||
FlwDef def = saveAndPublishDef("t17", "抄送并行", notifyParallelDef("km"));
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-17", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
// 抄送支激活即写行并到达 JOIN:分支一 RUNNING(审批支)、一 ARRIVED(抄送支)
|
||||
List<FlwBranch> branches = branchRows(instanceId);
|
||||
assertEquals(2, branches.size());
|
||||
assertEquals(1, branches.stream()
|
||||
.filter(b -> FlwEnums.BranchStatus.RUNNING.getCode() == b.getStatus()).count());
|
||||
assertEquals(1, ccRepository.findByInstanceIdOrderByIdAsc(instanceId).size());
|
||||
// 办件仍在途等审批支:乙支瞬时完成没有让 JOIN 提前放行
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
// 审批支到齐 → JOIN 放行 → 完成
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
}
|
||||
|
||||
/** NOTIFY 接收人解析不出人(映射停用/名单空):不阻塞推进,只是没有抄送行 */
|
||||
@Test
|
||||
void notify_unresolvableReceivers_skipsCc_butFlowContinues() {
|
||||
mapDept("km", 101, "甲");
|
||||
// deptKey 未注册任何映射(mapDept 只注册 km,抄送挂 kx)
|
||||
String json = notifyMainlineDef("km").replace(
|
||||
"\"receivers\":{\"type\":\"USERS\",\"userIds\":[301,302]}}",
|
||||
"\"receivers\":{\"type\":\"DEPT_KEY\",\"deptKey\":\"kx\"}}");
|
||||
FlwDef def = saveAndPublishDef("t18", "抄送空对象", json);
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-18", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
assertTrue(ccRepository.findByInstanceIdOrderByIdAsc(instanceId).isEmpty(),
|
||||
"解析不出人不应落行");
|
||||
assertEquals("n1", instanceRepository.findById(instanceId).get().getCurrentNodes());
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* 嵌套并行 scope 修复(2026-09-24 §4.6):外层分支 tb 内再套并行段 s2{tc,td}——
|
||||
* 修复前 JOIN 计数是实例级(tb 行仍在进行),内层 join2 到不齐、外层 join1 等 tb,互锁死。
|
||||
* 修复后:内层两支到齐 → join2 放行并以外层上下文 tb 续走 → join1 两轮到齐才完成。
|
||||
*/
|
||||
@Test
|
||||
void nestedParallel_innerJoinReleasesFirst_outerCompletesAfterBoth() {
|
||||
mapDept("km", 103, "主");
|
||||
mapDept("ka", 101, "甲");
|
||||
mapDept("kb", 102, "乙");
|
||||
mapDept("kc", 104, "丙");
|
||||
mapDept("kd", 105, "丁");
|
||||
FlwDef def = saveAndPublishDef("t19", "嵌套并行", nestedParallelDef("km", "ka", "kb", "kc", "kd"));
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-19", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
taskService.handle(SCH, tasksOf(instanceId, 103).get(0).getId(), true, "ok", 103);
|
||||
// 外层 split:顶层分支键无点号(存量口径)
|
||||
assertEquals(new java.util.TreeSet<>(java.util.Arrays.asList("ta", "tb")),
|
||||
branchRows(instanceId).stream().map(FlwBranch::getBranchKey)
|
||||
.collect(java.util.stream.Collectors.toCollection(java.util.TreeSet::new)));
|
||||
// 甲支先过:join1 等外层 tb(其内层段未走),办件仍在途
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
// 乙支过 → 进入内层并行段:分支键=路径前缀 tb.tc / tb.td
|
||||
taskService.handle(SCH, tasksOf(instanceId, 102).get(0).getId(), true, "ok", 102);
|
||||
java.util.Map<String, Integer> byKey = branchRows(instanceId).stream()
|
||||
.collect(java.util.stream.Collectors.toMap(FlwBranch::getBranchKey, FlwBranch::getStatus));
|
||||
assertEquals(4, byKey.size());
|
||||
assertEquals(FlwEnums.BranchStatus.ARRIVED.getCode(), (int) byKey.get("ta"));
|
||||
assertEquals(FlwEnums.BranchStatus.RUNNING.getCode(), (int) byKey.get("tb"));
|
||||
assertEquals(FlwEnums.BranchStatus.RUNNING.getCode(), (int) byKey.get("tb.tc"));
|
||||
assertEquals(FlwEnums.BranchStatus.RUNNING.getCode(), (int) byKey.get("tb.td"));
|
||||
// 内层丙支先过:join2 等丁支(修复前这里会因实例级计数连带等 tb 而死锁)
|
||||
taskService.handle(SCH, tasksOf(instanceId, 104).get(0).getId(), true, "ok", 104);
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
// 丁支到齐 → join2 放行(tb 标记到达)→ join1 两轮到齐 → END 完成
|
||||
taskService.handle(SCH, tasksOf(instanceId, 105).get(0).getId(), true, "ok", 105);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
}
|
||||
|
||||
/** 出口分支内并行段(CONDITION 分支内并行的前置形态):选"乙线"出口 → 并行段两支到齐 → 汇聚完成 */
|
||||
@Test
|
||||
void outletBranch_withParallelSegment_joinsAndCompletes() {
|
||||
mapDept("km", 103, "主");
|
||||
mapDept("ka", 101, "甲");
|
||||
mapDept("kb", 102, "乙");
|
||||
FlwDef def = saveAndPublishDef("t21", "出口并行", outletParallelDef("km", "ka", "kb"));
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-21", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
// 选"乙线"出口进入并行段(scope=主线,出口校验应放行)
|
||||
taskService.handle(SCH, tasksOf(instanceId, 103).get(0).getId(), true, "走乙线", 103, "乙线");
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
assertEquals(2, taskRepository.findByInstanceIdAndStatus(instanceId, 0).size());
|
||||
// 两支到齐 → join2 放行 → END 完成
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
taskService.handle(SCH, tasksOf(instanceId, 102).get(0).getId(), true, "ok", 102);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
}
|
||||
|
||||
/**
|
||||
* CONDITION 命中选路(2026-09-24 §4):判断返回"甲线"→ 只激活甲线待办,乙线不建任务;
|
||||
* 办理后完成;轨迹出现 kind=ROUTE 行("系统判断 → 甲线"),留痕 outlet=甲线。
|
||||
*/
|
||||
@Test
|
||||
void condition_routesByOutlet_andTraceShowsRouteRow() {
|
||||
mapDept("km", 101, "甲");
|
||||
mapDept("kb", 102, "乙");
|
||||
registerRouter("test.judge");
|
||||
FlwDef def = saveAndPublishDef("t22", "条件分支", conditionDef("test.judge", "km", "kb"));
|
||||
StubJudge.reset("甲线");
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-22", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
|
||||
// 甲线命中:仅甲科一条待办,CONDITION 已放行(不在 currentNodes)
|
||||
List<FlwTask> pending = taskRepository.findByInstanceIdAndStatus(instanceId, 0);
|
||||
assertEquals(1, pending.size());
|
||||
assertEquals("n1", pending.get(0).getNodeId());
|
||||
assertEquals("n1", instanceRepository.findById(instanceId).get().getCurrentNodes());
|
||||
|
||||
taskService.handle(SCH, pending.get(0).getId(), true, "ok", 101);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
|
||||
// 留痕 + 轨迹:ROUTE 行在发起之后、办理之前
|
||||
List<com.yunhai.flowcenter.entity.FlwRouteLog> logs =
|
||||
routeLogRepository.findByInstanceIdOrderByIdAsc(instanceId);
|
||||
assertEquals(1, logs.size());
|
||||
assertEquals("甲线", logs.get(0).getOutlet());
|
||||
assertEquals(1, logs.get(0).getAttempt());
|
||||
java.util.List<java.util.Map<String, Object>> trace =
|
||||
queryService.detail(SCH, instanceId, null).getTrace();
|
||||
java.util.List<String> kinds = new java.util.ArrayList<>();
|
||||
for (java.util.Map<String, Object> row : trace) {
|
||||
kinds.add((String) row.get("kind"));
|
||||
}
|
||||
assertEquals(java.util.Arrays.asList("SUBMIT", "ROUTE", "APPROVE"), kinds);
|
||||
assertEquals("甲线", trace.get(1).get("outlet"));
|
||||
}
|
||||
|
||||
/**
|
||||
* CONDITION 判断失败挂起 + 管理端重跑(§4.4 已定策略):失败=节点保持在途、办件仍 10、
|
||||
* 落 outlet=NULL 留痕行(无默认出口,宁挂起);重跑成功后按新出口续走到完成。
|
||||
*/
|
||||
@Test
|
||||
void condition_judgeFails_suspends_thenAdminReroute_resumes() {
|
||||
mapDept("km", 101, "甲");
|
||||
mapDept("kb", 102, "乙");
|
||||
registerRouter("test.judge");
|
||||
FlwDef def = saveAndPublishDef("t23", "条件挂起", conditionDef("test.judge", "km", "kb"));
|
||||
StubJudge.failure = new RouteJudgeClient.JudgeUnavailableException("服务不可用", null);
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-23", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
|
||||
// 挂起:办件在途、CONDITION 占位在 currentNodes、无待办任务
|
||||
FlwInstance suspended = instanceRepository.findById(instanceId).get();
|
||||
assertEquals(FlwEnums.InstanceStatus.APPROVING.getCode(), suspended.getStatus());
|
||||
assertEquals("cond1", suspended.getCurrentNodes());
|
||||
assertTrue(taskRepository.findByInstanceIdAndStatus(instanceId, 0).isEmpty());
|
||||
List<com.yunhai.flowcenter.entity.FlwRouteLog> failLogs =
|
||||
routeLogRepository.findByInstanceIdOrderByIdAsc(instanceId);
|
||||
assertEquals(1, failLogs.size());
|
||||
assertNull(failLogs.get(0).getOutlet(), "失败行 outlet=NULL");
|
||||
assertEquals(1, failLogs.get(0).getAttempt());
|
||||
|
||||
// 重跑仍失败:留痕 attempt=2,办件继续挂起(业务错抛出)
|
||||
assertThrows(com.yunhai.platform.apistd.BizException.class,
|
||||
() -> routerAdminService.reroute(SCH, instanceId));
|
||||
assertEquals(2, routeLogRepository.findByInstanceIdOrderByIdAsc(instanceId).size());
|
||||
assertEquals("cond1", instanceRepository.findById(instanceId).get().getCurrentNodes());
|
||||
|
||||
// 判断恢复 → 重跑成功:按乙线续走建待办,办理完成;attempt=3 留痕 outlet=乙线
|
||||
StubJudge.reset("乙线");
|
||||
routerAdminService.reroute(SCH, instanceId);
|
||||
FlwInstance resumed = instanceRepository.findById(instanceId).get();
|
||||
assertEquals("n2", resumed.getCurrentNodes());
|
||||
List<FlwTask> pending = taskRepository.findByInstanceIdAndStatus(instanceId, 0);
|
||||
assertEquals(1, pending.size());
|
||||
assertEquals(102, pending.get(0).getAssigneeId());
|
||||
taskService.handle(SCH, pending.get(0).getId(), true, "ok", 102);
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
List<com.yunhai.flowcenter.entity.FlwRouteLog> logs =
|
||||
routeLogRepository.findByInstanceIdOrderByIdAsc(instanceId);
|
||||
assertEquals(3, logs.size());
|
||||
assertEquals("乙线", logs.get(2).getOutlet());
|
||||
assertEquals(3, logs.get(2).getAttempt());
|
||||
// 完成后的办件不再可重跑
|
||||
assertThrows(com.yunhai.platform.apistd.BizException.class,
|
||||
() -> routerAdminService.reroute(SCH, instanceId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 退回重走 CONDITION 必须重新调判断(§4.4:单据可能已改,留痕只增不改多轮可见):
|
||||
* 一轮判"甲线"到 n1,退回 n0 重走判"乙线"直达 END;route_log 两行 attempt 递增。
|
||||
*/
|
||||
@Test
|
||||
void condition_returnBack_rewalk_rejudges() {
|
||||
mapDept("km", 101, "甲");
|
||||
mapDept("ka", 102, "乙");
|
||||
registerRouter("test.judge");
|
||||
FlwDef def = saveAndPublishDef("t24", "条件重判", mainlineConditionDef("test.judge", "km", "ka"));
|
||||
StubJudge.reset("甲线");
|
||||
FlowInstanceService.ApplyOutcome outcome = apply(def.getFlowGuid(), "biz-24", 201, "张三");
|
||||
Long instanceId = outcome.getInstanceId();
|
||||
|
||||
// 一轮:n0 过 → 判甲线 → n1 待办
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "ok", 101);
|
||||
assertEquals("n1", instanceRepository.findById(instanceId).get().getCurrentNodes());
|
||||
// 退回入口 n0 重走(改判乙线)
|
||||
StubJudge.reset("乙线");
|
||||
FlwTask n1Task = taskRepository.findByInstanceIdAndStatus(instanceId, 0).get(0);
|
||||
taskService.returnBack(SCH, n1Task.getId(), "n0", "改判乙线", 102);
|
||||
taskService.handle(SCH, tasksOf(instanceId, 101).get(0).getId(), true, "再走一遍", 101);
|
||||
// 乙线直达 END:办件完成(n1 未再激活)
|
||||
assertEquals(FlwEnums.InstanceStatus.COMPLETED.getCode(),
|
||||
instanceRepository.findById(instanceId).get().getStatus());
|
||||
// 留痕两轮:attempt 1=甲线、2=乙线(只增不改)
|
||||
List<com.yunhai.flowcenter.entity.FlwRouteLog> logs =
|
||||
routeLogRepository.findByInstanceIdOrderByIdAsc(instanceId);
|
||||
assertEquals(2, logs.size());
|
||||
assertEquals("甲线", logs.get(0).getOutlet());
|
||||
assertEquals(1, logs.get(0).getAttempt());
|
||||
assertEquals("乙线", logs.get(1).getOutlet());
|
||||
assertEquals(2, logs.get(1).getAttempt());
|
||||
}
|
||||
|
||||
private List<FlwBranch> branchRows(Long instanceId) {
|
||||
return branchRepository.findByInstanceId(instanceId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user