diff --git a/o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExternalDataSource.java b/o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExternalDataSource.java index 479cc94dc780edb7c5f8b995e65b43fcb1f9ae12..79f8a5124640f26a5469d9ac4ddbdcc1fe07c012 100644 --- a/o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExternalDataSource.java +++ b/o2server/x_base_core_project/src/main/java/com/x/base/core/project/config/ExternalDataSource.java @@ -44,7 +44,7 @@ public class ExternalDataSource extends ConfigObject { public static final Integer DEFAULT_SLOWSQLMILLIS = 2000; - public static final String DEFAULT_LOGLEVEL = "WARN"; + public static final String DEFAULT_LOGLEVEL = "ERROR"; public static final String DEFAULT_TRANSACTIONISOLATION = "read-committed"; diff --git a/o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Task.java b/o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Task.java index 572158441ecac5df4def096d02fe4a0fb47bc081..91868cda5ce22a600452dfba5a779e83b389fa64 100644 --- a/o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Task.java +++ b/o2server/x_processplatform_core_entity/src/main/java/com/x/processplatform/core/entity/content/Task.java @@ -158,6 +158,19 @@ public class Task extends SliceJpaObject implements ProjectionInterface { this.creatorUnit = work.getCreatorUnit(); this.workCreateType = work.getWorkCreateType(); this.expireTime = expireTime; + this.routeName = ""; + this.opinion = ""; + this.modified = false; + this.allowRapid = allowRapid; + this.copyProjectionFields(work); + updateRoute(routes); + } + + public Task updateRoute(List routes) { + this.routeList = new ArrayList<>(); + this.routeNameList = new ArrayList<>(); + this.routeOpinionList = new ArrayList<>(); + this.routeDecisionOpinionList = new ArrayList<>(); if (ListTools.isNotEmpty(routes)) { routes.stream().sorted(Comparator.comparing(Route::getOrderNumber, Comparator.nullsLast(Integer::compareTo)) .thenComparing(Route::getUpdateTime, Date::compareTo)).forEach(o -> { @@ -167,11 +180,7 @@ public class Task extends SliceJpaObject implements ProjectionInterface { this.routeDecisionOpinionList.add(StringUtils.trimToEmpty(o.getDecisionOpinion())); }); } - this.routeName = ""; - this.opinion = ""; - this.modified = false; - this.allowRapid = allowRapid; - this.copyProjectionFields(work); + return this; } public TaskProperties getProperties() { diff --git a/o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/processor/manual/ManualProcessor.java b/o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/processor/manual/ManualProcessor.java index cec3457816a8211e2d7eb105119a092a9a2d04e8..98f5a7cb68ff038bce16fdbdbd65517b3b66aeaf 100644 --- a/o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/processor/manual/ManualProcessor.java +++ b/o2server/x_processplatform_service_processing/src/main/java/com/x/processplatform/service/processing/processor/manual/ManualProcessor.java @@ -5,11 +5,13 @@ import java.util.Calendar; import java.util.Collection; import java.util.Comparator; import java.util.Date; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map.Entry; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -21,6 +23,7 @@ import javax.script.ScriptContext; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.SetUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; @@ -60,354 +63,353 @@ import com.x.processplatform.service.processing.processor.AeiObjects; */ public class ManualProcessor extends AbstractManualProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(ManualProcessor.class); - - private static final String DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST = "manualTaskIdentityList"; - - public ManualProcessor(EntityManagerContainer entityManagerContainer) throws Exception { - super(entityManagerContainer); - } - - @Override - protected Work arriving(AeiObjects aeiObjects, Manual manual) throws Exception { - // 发送ProcessingSignal - aeiObjects.getProcessingAttributes().push(Signal.manualArrive(aeiObjects.getWork().getActivityToken(), manual)); - // 根据manual计算出来的活动处理人 - ManualTaskIdentityMatrix manualTaskIdentityMatrix = manual - .identitiesToManualTaskIdentityMatrix(calculateTaskIdentities(aeiObjects, manual)); - // 启用同类工作相同活动节点合并,如果有合并的工作,那么直接返回这个工作. - Optional mergeWork = this.arrivingMergeSameJob(aeiObjects, manual, manualTaskIdentityMatrix); - if (mergeWork.isPresent()) { - return mergeWork.get(); - } - this.arrivingPassSame(aeiObjects, manualTaskIdentityMatrix); - aeiObjects.getWork().setManualTaskIdentityMatrix(manualTaskIdentityMatrix); - return aeiObjects.getWork(); - } - - private Optional arrivingMergeSameJob(AeiObjects aeiObjects, Manual manual, - ManualTaskIdentityMatrix manualTaskIdentityMatrix) throws Exception { - if (!BooleanUtils.isTrue(manual.getManualMergeSameJobActivity())) { - return Optional.empty(); - } - List exists = this.arrivingSameJobActivityExistIdentities(aeiObjects, manual); - if (ListTools.isNotEmpty(exists)) { - Optional other = aeiObjects.getWorks().stream() - .filter(o -> StringUtils.equals(aeiObjects.getWork().getJob(), o.getJob()) - && StringUtils.equals(aeiObjects.getWork().getActivity(), o.getActivity()) - && (!Objects.equals(aeiObjects.getWork(), o))) - .findFirst(); - if (other.isPresent()) { - manualTaskIdentityMatrix.remove(exists); - if (manualTaskIdentityMatrix.isEmpty()) { - this.mergeTaskCompleted(aeiObjects, aeiObjects.getWork(), other.get()); - this.mergeRead(aeiObjects, aeiObjects.getWork(), other.get()); - this.mergeReadCompleted(aeiObjects, aeiObjects.getWork(), other.get()); - this.mergeReview(aeiObjects, aeiObjects.getWork(), other.get()); - this.mergeAttachment(aeiObjects, aeiObjects.getWork(), other.get()); - this.mergeWorkLog(aeiObjects, aeiObjects.getWork(), other.get()); - if (ListTools.size(aeiObjects.getWork().getSplitTokenList()) > ListTools - .size(other.get().getSplitTokenList())) { - other.get().setSplitTokenList(aeiObjects.getWork().getSplitTokenList()); - other.get().setSplitToken(aeiObjects.getWork().getSplitToken()); - other.get().setSplitValue(aeiObjects.getWork().getSplitValue()); - other.get().setSplitting(true); - } - aeiObjects.getUpdateWorks().add(other.get()); - aeiObjects.getDeleteWorks().add(aeiObjects.getWork()); - return other; - } - } - } - return Optional.empty(); - } - - private void arrivingPassSame(AeiObjects aeiObjects, ManualTaskIdentityMatrix matrix) throws Exception { - // 查找是否有passSameTarget设置 - if (BooleanUtils.isTrue(aeiObjects.getProcessingAttributes().ifForceJoinAtArrive())) { - return; - } - Optional route = aeiObjects.getRoutes().stream().filter(o -> BooleanUtils.isTrue(o.getPassSameTarget())) - .findFirst(); - // 如果有passSameTarget,有到达ArriveWorkLog,不是调度到这个节点的 - if (route.isPresent() && (null != aeiObjects.getArriveWorkLog(aeiObjects.getWork()))) { - WorkLog workLog = findPassSameTargetWorkLog(aeiObjects); - if (null == workLog) { - return; - } - LOGGER.debug("pass same target work:{}, workLog:{}.", aeiObjects::getWork, workLog::toString); - List identities = matrix.flat(); - aeiObjects.getJoinInquireTaskCompletedsWithActivityToken(workLog.getArrivedActivityToken()).stream() - .forEach(o -> { - try { - List values = ListUtils.intersection(identities, - aeiObjects.business().organization().identity().listWithPerson(o.getPerson())); - if (!values.isEmpty()) { - TaskCompleted taskCompleted = arrivingPassSameCreateTaskCompleted(aeiObjects, - route.get(), o, values.get(0)); - aeiObjects.getCreateTaskCompleteds().add(taskCompleted); - matrix.completed(values); - } - } catch (Exception e) { - LOGGER.error(e); - } - }); - } - } - - private TaskCompleted arrivingPassSameCreateTaskCompleted(AeiObjects aeiObjects, Route route, TaskCompleted o, - String identity) throws Exception { - TaskCompleted taskCompleted = new TaskCompleted(aeiObjects.getWork(), route, o); - taskCompleted.setIdentity(identity); - taskCompleted.setUnit(aeiObjects.business().organization().unit().getWithIdentity(taskCompleted.getIdentity())); - taskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_SAMETARGET); - taskCompleted.setRouteName(route.getName()); - taskCompleted.setOpinion(route.getOpinion()); - Date now = new Date(); - taskCompleted.setStartTime(now); - taskCompleted.setStartTimeMonth(DateTools.format(now, DateTools.format_yyyyMM)); - taskCompleted.setCompletedTime(now); - taskCompleted.setCompletedTimeMonth(DateTools.format(now, DateTools.format_yyyyMM)); - taskCompleted.setDuration(0L); - taskCompleted.setExpired(false); - taskCompleted.setExpireTime(null); - taskCompleted.setTask(null); - taskCompleted.setLatest(true); - return taskCompleted; - } - - // 计算处理人 - private List calculateTaskIdentities(AeiObjects aeiObjects, Manual manual) throws Exception { - TaskIdentities taskIdentities = new TaskIdentities(); - // 先计算强制处理人 - if (!aeiObjects.getWork().getProperties().getManualForceTaskIdentityList().isEmpty()) { - List identities = new ArrayList<>(); - identities.addAll(aeiObjects.getWork().getProperties().getManualForceTaskIdentityList()); - identities = aeiObjects.business().organization().identity().list(identities); - if (ListTools.isNotEmpty(identities)) { - taskIdentities.addIdentities(identities); - } - } - // 计算退回的结果 - if (taskIdentities.isEmpty()) { - Route route = aeiObjects.business().element().get(aeiObjects.getWork().getDestinationRoute(), Route.class); - if ((null != route) && (StringUtils.equals(route.getType(), Route.TYPE_BACK))) { - calculateRouteTypeBack(aeiObjects, manual, taskIdentities); - } - } - if (taskIdentities.isEmpty()) { - taskIdentities = TranslateTaskIdentityTools.translate(aeiObjects, manual); - this.ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(aeiObjects, manual, taskIdentities); - // 处理授权 - this.writeToEmpowerMap(aeiObjects, taskIdentities); - } - return taskIdentities.identities(); - } - - private void calculateRouteTypeBack(AeiObjects aeiObjects, Manual manual, TaskIdentities taskIdentities) - throws Exception { - List identities = new ArrayList<>(); - List workLogs = Stream - .concat(Stream.concat(aeiObjects.getUpdateWorkLogs().stream(), aeiObjects.getCreateWorkLogs().stream()), - aeiObjects.getWorkLogs().stream()) - .distinct().collect(Collectors.toList()); - WorkLogTree tree = new WorkLogTree(workLogs); - Node node = tree.location(aeiObjects.getWork()); - if (null != node) { - calculateRouteTypeBackIdentityByTaskCompleted(aeiObjects, manual, taskIdentities, identities, tree, node); - } - } - - private void calculateRouteTypeBackIdentityByTaskCompleted(AeiObjects aeiObjects, Manual manual, - TaskIdentities taskIdentities, List identities, WorkLogTree tree, Node node) throws Exception { - for (Node n : tree.up(node)) { - if (StringUtils.equals(manual.getId(), n.getWorkLog().getFromActivity())) { - for (TaskCompleted t : aeiObjects.getTaskCompleteds()) { - if (StringUtils.equals(n.getWorkLog().getFromActivityToken(), t.getActivityToken()) - && BooleanUtils.isTrue(t.getJoinInquire())) { - identities.add(t.getIdentity()); - } - } - break; - } - } - identities = aeiObjects.business().organization().identity().list(identities); - if (ListTools.isNotEmpty(identities)) { - taskIdentities.addIdentities(identities); - } - } - - /** - * 如果没能计算到活动处理人,先判断人员活动是否有设置人员,如果有那么先返回工作创建者,再按照流程维护人,应用维护人,工作创建者,平台维护人顺序查找处理人 - * - * @param aeiObjects - * @param manual - * @param taskIdentities - * @throws Exception - */ - private void ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(AeiObjects aeiObjects, Manual manual, - TaskIdentities taskIdentities) throws Exception { - if (taskIdentities.isEmpty()) { - String identity = null; - if (!ifManualAssignTaskIdentity(manual)) { - identity = aeiObjects.business().organization().identity() - .get(aeiObjects.getWork().getCreatorIdentity()); - } - if (StringUtils.isEmpty(identity) - && StringUtils.isNotBlank(aeiObjects.getProcess().getMaintenanceIdentity())) { - identity = aeiObjects.business().organization().identity() - .get(aeiObjects.getProcess().getMaintenanceIdentity()); - } - if (StringUtils.isEmpty(identity) - && StringUtils.isNotBlank(aeiObjects.getApplication().getMaintenanceIdentity())) { - identity = aeiObjects.business().organization().identity() - .get(aeiObjects.getApplication().getMaintenanceIdentity()); - } - if (StringUtils.isEmpty(identity)) { - identity = aeiObjects.business().organization().identity() - .get(aeiObjects.getWork().getCreatorIdentity()); - } - if (StringUtils.isEmpty(identity) - && StringUtils.isNotBlank(Config.processPlatform().getMaintenanceIdentity())) { - identity = aeiObjects.business().organization().identity() - .get(Config.processPlatform().getMaintenanceIdentity()); - } - if (StringUtils.isEmpty(identity)) { - throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(), - aeiObjects.getActivity().getName(), aeiObjects.getActivity().getId()); - } - taskIdentities.addIdentity(identity); - } - } - - /** - * 判读是否在活动中制定了处理人,这里没有对脚本的注解和空行进行判断 - * - * @param manual - * @return - */ - private boolean ifManualAssignTaskIdentity(Manual manual) { - /* 指定了的身份 */ - if (ListTools.isNotEmpty(manual.getTaskIdentityList())) { - return true; - } - /* 选择了职务 */ - if (StringUtils.isNotBlank(manual.getTaskDuty())) { - return true; - } - /* 指定data数据路径值 */ - if (ListTools.isNotEmpty(manual.getTaskDataPathList())) { - return true; - } - /* 使用脚本计算 */ - if (StringUtils.isNotEmpty(manual.getTaskScript())) { - return true; - } else { - if (StringUtils.isNotEmpty(manual.getTaskScriptText())) { - String clean = manual.getTaskScriptText().replaceAll("/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/|//.*", ""); - clean = StringUtils.trimToEmpty(clean); - if (StringUtils.isNotBlank(clean)) { - return true; - } - } - } - /* 指定处理组织 */ - if (ListTools.isNotEmpty(manual.getTaskUnitList())) { - return true; - } - /* 指定处理群组 */ - return (ListTools.isNotEmpty(manual.getTaskGroupList())); - } - - // 更新授权,通过surface创建且workThroughManual=false 代表是草稿,那么不需要授权. - - private void writeToEmpowerMap(AeiObjects aeiObjects, TaskIdentities taskIdentities) throws Exception { - // 先清空EmpowerMap - aeiObjects.getWork().getProperties().setManualEmpowerMap(new LinkedHashMap<>()); - if (!(StringUtils.equals(aeiObjects.getWork().getWorkCreateType(), Work.WORKCREATETYPE_SURFACE) - && BooleanUtils.isFalse(aeiObjects.getWork().getWorkThroughManual()))) { - List values = taskIdentities.identities(); - values = ListUtils.subtract(values, aeiObjects.getProcessingAttributes().getIgnoreEmpowerIdentityList()); - taskIdentities.empower(aeiObjects.business().organization().empower().listWithIdentityObject( - aeiObjects.getWork().getApplication(), aeiObjects.getProcess().getEdition(), - aeiObjects.getWork().getProcess(), aeiObjects.getWork().getId(), values)); - for (TaskIdentity taskIdentity : taskIdentities) { - if (StringUtils.isNotEmpty(taskIdentity.getFromIdentity())) { - aeiObjects.getWork().getProperties().getManualEmpowerMap().put(taskIdentity.getIdentity(), - taskIdentity.getFromIdentity()); - } - } - } - } - - private WorkLog findPassSameTargetWorkLog(AeiObjects aeiObjects) throws Exception { - WorkLogTree tree = new WorkLogTree(aeiObjects.getWorkLogs()); - List parents = tree.parents(aeiObjects.getArriveWorkLog(aeiObjects.getWork())); - LOGGER.debug("pass same target rollback parents:{}.", parents::toString); - WorkLog workLog = null; - for (WorkLog o : parents) { - // choice, agent, invoke, service, delay, embed, split, parallel 继续向上查找manual - ActivityType arrivedActivityType = o.getArrivedActivityType(); - if (Objects.equals(ActivityType.manual, arrivedActivityType) - || Objects.equals(ActivityType.begin, arrivedActivityType) - || Objects.equals(ActivityType.cancel, arrivedActivityType) - // || Objects.equals(ActivityType.embed, arrivedActivityType) - || Objects.equals(ActivityType.end, arrivedActivityType) - || Objects.equals(ActivityType.merge, arrivedActivityType) - // || Objects.equals(ActivityType.parallel, arrivedActivityType) - // || Objects.equals(ActivityType.split, arrivedActivityType) - ) { - if (Objects.equals(ActivityType.manual, arrivedActivityType)) { - workLog = o; - } - break; - } - } - return workLog; - } - - @Override - protected void arrivingCommitted(AeiObjects aeiObjects, Manual manual) throws Exception { - // nothing - } - - @Override - protected List executing(AeiObjects aeiObjects, Manual manual) throws Exception { - List results = new ArrayList<>(); - ManualTaskIdentityMatrix matrix = executingManualTaskIdentityMatrix(aeiObjects, manual); - List taskCompleteds = aeiObjects.getJoinInquireTaskCompletedsRouteNameAvailableWithActivityToken( - aeiObjects.getWork().getActivityToken()); - executingCompletedIdentityInTaskCompleteds(aeiObjects, matrix, taskCompleteds); - - // 发送ProcessingSignal - aeiObjects.getProcessingAttributes().push(Signal.manualExecute(aeiObjects.getWork().getActivityToken(), manual, - Objects.toString(manual.getManualMode(), ""), matrix.flat())); - if (matrix.isEmpty() && (!taskCompleteds.isEmpty())) { - results.add(aeiObjects.getWork()); - aeiObjects.getTasks().stream().filter( - t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) - .forEach(aeiObjects::deleteTask); - } else { - switch (manual.getManualMode()) { - case parallel: - this.parallel(aeiObjects, manual, matrix, taskCompleteds); - break; - case queue: - this.queue(aeiObjects, manual, matrix, taskCompleteds); - break; - case grab: - case single: - default: - this.single(aeiObjects, manual, matrix, taskCompleteds); - } - // 可能在处理过程中删除了所有的待办,比如有优先路由 - if (matrix.isEmpty()) { - results.add(aeiObjects.getWork()); - } - } - aeiObjects.getWork().setManualTaskIdentityMatrix(matrix); - return results; - } + private static final Logger LOGGER = LoggerFactory.getLogger(ManualProcessor.class); + + private static final String DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST = "manualTaskIdentityList"; + + public ManualProcessor(EntityManagerContainer entityManagerContainer) throws Exception { + super(entityManagerContainer); + } + + @Override + protected Work arriving(AeiObjects aeiObjects, Manual manual) throws Exception { + // 发送ProcessingSignal + aeiObjects.getProcessingAttributes().push(Signal.manualArrive(aeiObjects.getWork().getActivityToken(), manual)); + // 根据manual计算出来的活动处理人 + ManualTaskIdentityMatrix manualTaskIdentityMatrix = manual + .identitiesToManualTaskIdentityMatrix(calculateTaskIdentities(aeiObjects, manual)); + // 启用同类工作相同活动节点合并,如果有合并的工作,那么直接返回这个工作. + Optional mergeWork = this.arrivingMergeSameJob(aeiObjects, manual, manualTaskIdentityMatrix); + if (mergeWork.isPresent()) { + return mergeWork.get(); + } + this.arrivingPassSame(aeiObjects, manualTaskIdentityMatrix); + aeiObjects.getWork().setManualTaskIdentityMatrix(manualTaskIdentityMatrix); + return aeiObjects.getWork(); + } + + private Optional arrivingMergeSameJob(AeiObjects aeiObjects, Manual manual, + ManualTaskIdentityMatrix manualTaskIdentityMatrix) throws Exception { + if (!BooleanUtils.isTrue(manual.getManualMergeSameJobActivity())) { + return Optional.empty(); + } + List exists = this.arrivingSameJobActivityExistIdentities(aeiObjects, manual); + if (ListTools.isNotEmpty(exists)) { + Optional other = aeiObjects.getWorks().stream() + .filter(o -> StringUtils.equals(aeiObjects.getWork().getJob(), o.getJob()) + && StringUtils.equals(aeiObjects.getWork().getActivity(), o.getActivity()) + && (!Objects.equals(aeiObjects.getWork(), o))) + .findFirst(); + if (other.isPresent()) { + manualTaskIdentityMatrix.remove(exists); + if (manualTaskIdentityMatrix.isEmpty()) { + this.mergeTaskCompleted(aeiObjects, aeiObjects.getWork(), other.get()); + this.mergeRead(aeiObjects, aeiObjects.getWork(), other.get()); + this.mergeReadCompleted(aeiObjects, aeiObjects.getWork(), other.get()); + this.mergeReview(aeiObjects, aeiObjects.getWork(), other.get()); + this.mergeAttachment(aeiObjects, aeiObjects.getWork(), other.get()); + this.mergeWorkLog(aeiObjects, aeiObjects.getWork(), other.get()); + if (ListTools.size(aeiObjects.getWork().getSplitTokenList()) > ListTools + .size(other.get().getSplitTokenList())) { + other.get().setSplitTokenList(aeiObjects.getWork().getSplitTokenList()); + other.get().setSplitToken(aeiObjects.getWork().getSplitToken()); + other.get().setSplitValue(aeiObjects.getWork().getSplitValue()); + other.get().setSplitting(true); + } + aeiObjects.getUpdateWorks().add(other.get()); + aeiObjects.getDeleteWorks().add(aeiObjects.getWork()); + return other; + } + } + } + return Optional.empty(); + } + + private void arrivingPassSame(AeiObjects aeiObjects, ManualTaskIdentityMatrix matrix) throws Exception { + // 查找是否有passSameTarget设置 + if (BooleanUtils.isTrue(aeiObjects.getProcessingAttributes().ifForceJoinAtArrive())) { + return; + } + Optional route = aeiObjects.getRoutes().stream().filter(o -> BooleanUtils.isTrue(o.getPassSameTarget())) + .findFirst(); + // 如果有passSameTarget,有到达ArriveWorkLog,不是调度到这个节点的 + if (route.isPresent() && (null != aeiObjects.getArriveWorkLog(aeiObjects.getWork()))) { + Optional optional = findPassSameTargetWorkLog(aeiObjects); + if (optional.isEmpty()) { + return; + } + LOGGER.debug("pass same target work:{}, workLog:{}.", aeiObjects::getWork, optional.get()::toString); + List identities = matrix.flat(); + aeiObjects.getJoinInquireTaskCompletedsWithActivityToken(optional.get().getFromActivityToken()).stream() + .forEach(o -> { + try { + List values = ListUtils.intersection(identities, + aeiObjects.business().organization().identity().listWithPerson(o.getPerson())); + if (!values.isEmpty()) { + TaskCompleted taskCompleted = arrivingPassSameCreateTaskCompleted(aeiObjects, + route.get(), o, values.get(0)); + aeiObjects.getCreateTaskCompleteds().add(taskCompleted); + matrix.completed(values); + } + } catch (Exception e) { + LOGGER.error(e); + } + }); + } + } + + private TaskCompleted arrivingPassSameCreateTaskCompleted(AeiObjects aeiObjects, Route route, TaskCompleted o, + String identity) throws Exception { + TaskCompleted taskCompleted = new TaskCompleted(aeiObjects.getWork(), route, o); + taskCompleted.setIdentity(identity); + taskCompleted.setUnit(aeiObjects.business().organization().unit().getWithIdentity(taskCompleted.getIdentity())); + taskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_SAMETARGET); + taskCompleted.setRouteName(route.getName()); + taskCompleted.setOpinion(route.getOpinion()); + Date now = new Date(); + taskCompleted.setStartTime(now); + taskCompleted.setStartTimeMonth(DateTools.format(now, DateTools.format_yyyyMM)); + taskCompleted.setCompletedTime(now); + taskCompleted.setCompletedTimeMonth(DateTools.format(now, DateTools.format_yyyyMM)); + taskCompleted.setDuration(0L); + taskCompleted.setExpired(false); + taskCompleted.setExpireTime(null); + taskCompleted.setTask(null); + taskCompleted.setLatest(true); + return taskCompleted; + } + + // 计算处理人 + private List calculateTaskIdentities(AeiObjects aeiObjects, Manual manual) throws Exception { + TaskIdentities taskIdentities = new TaskIdentities(); + // 先计算强制处理人 + if (!aeiObjects.getWork().getProperties().getManualForceTaskIdentityList().isEmpty()) { + List identities = new ArrayList<>(); + identities.addAll(aeiObjects.getWork().getProperties().getManualForceTaskIdentityList()); + identities = aeiObjects.business().organization().identity().list(identities); + if (ListTools.isNotEmpty(identities)) { + taskIdentities.addIdentities(identities); + } + } + // 计算退回的结果 + if (taskIdentities.isEmpty()) { + Route route = aeiObjects.business().element().get(aeiObjects.getWork().getDestinationRoute(), Route.class); + if ((null != route) && (StringUtils.equals(route.getType(), Route.TYPE_BACK))) { + calculateRouteTypeBack(aeiObjects, manual, taskIdentities); + } + } + if (taskIdentities.isEmpty()) { + taskIdentities = TranslateTaskIdentityTools.translate(aeiObjects, manual); + this.ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(aeiObjects, manual, taskIdentities); + // 处理授权 + this.writeToEmpowerMap(aeiObjects, taskIdentities); + } + return taskIdentities.identities(); + } + + private void calculateRouteTypeBack(AeiObjects aeiObjects, Manual manual, TaskIdentities taskIdentities) + throws Exception { + List identities = new ArrayList<>(); + List workLogs = Stream + .concat(Stream.concat(aeiObjects.getUpdateWorkLogs().stream(), aeiObjects.getCreateWorkLogs().stream()), + aeiObjects.getWorkLogs().stream()) + .distinct().collect(Collectors.toList()); + WorkLogTree tree = new WorkLogTree(workLogs); + Node node = tree.location(aeiObjects.getWork()); + if (null != node) { + calculateRouteTypeBackIdentityByTaskCompleted(aeiObjects, manual, taskIdentities, identities, tree, node); + } + } + + private void calculateRouteTypeBackIdentityByTaskCompleted(AeiObjects aeiObjects, Manual manual, + TaskIdentities taskIdentities, List identities, WorkLogTree tree, Node node) throws Exception { + for (Node n : tree.up(node)) { + if (StringUtils.equals(manual.getId(), n.getWorkLog().getFromActivity())) { + for (TaskCompleted t : aeiObjects.getTaskCompleteds()) { + if (StringUtils.equals(n.getWorkLog().getFromActivityToken(), t.getActivityToken()) + && BooleanUtils.isTrue(t.getJoinInquire())) { + identities.add(t.getIdentity()); + } + } + break; + } + } + identities = aeiObjects.business().organization().identity().list(identities); + if (ListTools.isNotEmpty(identities)) { + taskIdentities.addIdentities(identities); + } + } + + /** + * 如果没能计算到活动处理人,先判断人员活动是否有设置人员,如果有那么先返回工作创建者,再按照流程维护人,应用维护人,工作创建者,平台维护人顺序查找处理人 + * + * @param aeiObjects + * @param manual + * @param taskIdentities + * @throws Exception + */ + private void ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(AeiObjects aeiObjects, Manual manual, + TaskIdentities taskIdentities) throws Exception { + if (taskIdentities.isEmpty()) { + String identity = null; + if (!ifManualAssignTaskIdentity(manual)) { + identity = aeiObjects.business().organization().identity() + .get(aeiObjects.getWork().getCreatorIdentity()); + } + if (StringUtils.isEmpty(identity) + && StringUtils.isNotBlank(aeiObjects.getProcess().getMaintenanceIdentity())) { + identity = aeiObjects.business().organization().identity() + .get(aeiObjects.getProcess().getMaintenanceIdentity()); + } + if (StringUtils.isEmpty(identity) + && StringUtils.isNotBlank(aeiObjects.getApplication().getMaintenanceIdentity())) { + identity = aeiObjects.business().organization().identity() + .get(aeiObjects.getApplication().getMaintenanceIdentity()); + } + if (StringUtils.isEmpty(identity)) { + identity = aeiObjects.business().organization().identity() + .get(aeiObjects.getWork().getCreatorIdentity()); + } + if (StringUtils.isEmpty(identity) + && StringUtils.isNotBlank(Config.processPlatform().getMaintenanceIdentity())) { + identity = aeiObjects.business().organization().identity() + .get(Config.processPlatform().getMaintenanceIdentity()); + } + if (StringUtils.isEmpty(identity)) { + throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(), + aeiObjects.getActivity().getName(), aeiObjects.getActivity().getId()); + } + taskIdentities.addIdentity(identity); + } + } + + /** + * 判读是否在活动中制定了处理人,这里没有对脚本的注解和空行进行判断 + * + * @param manual + * @return + */ + private boolean ifManualAssignTaskIdentity(Manual manual) { + /* 指定了的身份 */ + if (ListTools.isNotEmpty(manual.getTaskIdentityList())) { + return true; + } + /* 选择了职务 */ + if (StringUtils.isNotBlank(manual.getTaskDuty())) { + return true; + } + /* 指定data数据路径值 */ + if (ListTools.isNotEmpty(manual.getTaskDataPathList())) { + return true; + } + /* 使用脚本计算 */ + if (StringUtils.isNotEmpty(manual.getTaskScript())) { + return true; + } else { + if (StringUtils.isNotEmpty(manual.getTaskScriptText())) { + String clean = manual.getTaskScriptText().replaceAll("/\\*[^*]*(?:\\*(?!/)[^*]*)*\\*/|//.*", ""); + clean = StringUtils.trimToEmpty(clean); + if (StringUtils.isNotBlank(clean)) { + return true; + } + } + } + /* 指定处理组织 */ + if (ListTools.isNotEmpty(manual.getTaskUnitList())) { + return true; + } + /* 指定处理群组 */ + return (ListTools.isNotEmpty(manual.getTaskGroupList())); + } + + // 更新授权,通过surface创建且workThroughManual=false 代表是草稿,那么不需要授权. + + private void writeToEmpowerMap(AeiObjects aeiObjects, TaskIdentities taskIdentities) throws Exception { + // 先清空EmpowerMap + aeiObjects.getWork().getProperties().setManualEmpowerMap(new LinkedHashMap<>()); + if (!(StringUtils.equals(aeiObjects.getWork().getWorkCreateType(), Work.WORKCREATETYPE_SURFACE) + && BooleanUtils.isFalse(aeiObjects.getWork().getWorkThroughManual()))) { + List values = taskIdentities.identities(); + values = ListUtils.subtract(values, aeiObjects.getProcessingAttributes().getIgnoreEmpowerIdentityList()); + taskIdentities.empower(aeiObjects.business().organization().empower().listWithIdentityObject( + aeiObjects.getWork().getApplication(), aeiObjects.getProcess().getEdition(), + aeiObjects.getWork().getProcess(), aeiObjects.getWork().getId(), values)); + for (TaskIdentity taskIdentity : taskIdentities) { + if (StringUtils.isNotEmpty(taskIdentity.getFromIdentity())) { + aeiObjects.getWork().getProperties().getManualEmpowerMap().put(taskIdentity.getIdentity(), + taskIdentity.getFromIdentity()); + } + } + } + } + + private Optional findPassSameTargetWorkLog(AeiObjects aeiObjects) throws Exception { + WorkLog workLog = aeiObjects.getArriveWorkLog(aeiObjects.getWork()); + if (null == workLog) { + return Optional.empty(); + } + WorkLogTree tree = new WorkLogTree(aeiObjects.getWorkLogs()); + + List list = new ArrayList<>(); + list.add(workLog); + list.addAll(tree.parents(workLog)); + LOGGER.debug("pass same target rollback parents:{}.", list::toString); + for (WorkLog o : list) { + // choice, agent, invoke, service, delay, embed, split, parallel 继续向上查找manual + ActivityType activityType = o.getFromActivityType(); + if (Objects.equals(ActivityType.begin, activityType) + || Objects.equals(ActivityType.cancel, activityType) + || Objects.equals(ActivityType.end, activityType) + || Objects.equals(ActivityType.merge, activityType)) { + } else if (Objects.equals(ActivityType.manual, activityType)) { + return Optional.of(o); + } + } + return Optional.empty(); + } + + @Override + protected void arrivingCommitted(AeiObjects aeiObjects, Manual manual) throws Exception { + // nothing + } + + @Override + protected List executing(AeiObjects aeiObjects, Manual manual) throws Exception { + List results = new ArrayList<>(); + ManualTaskIdentityMatrix matrix = executingManualTaskIdentityMatrix(aeiObjects, manual); + List taskCompleteds = aeiObjects.getJoinInquireTaskCompletedsRouteNameAvailableWithActivityToken( + aeiObjects.getWork().getActivityToken()); + executingCompletedIdentityInTaskCompleteds(aeiObjects, matrix, taskCompleteds); + + // 发送ProcessingSignal + aeiObjects.getProcessingAttributes().push(Signal.manualExecute(aeiObjects.getWork().getActivityToken(), manual, + Objects.toString(manual.getManualMode(), ""), matrix.flat())); + if (matrix.isEmpty() && (!taskCompleteds.isEmpty())) { + results.add(aeiObjects.getWork()); + aeiObjects.getTasks().stream().filter( + t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) + .forEach(aeiObjects::deleteTask); + } else { + switch (manual.getManualMode()) { + case parallel: + this.parallel(aeiObjects, manual, matrix, taskCompleteds); + break; + case queue: + this.queue(aeiObjects, manual, matrix, taskCompleteds); + break; + case grab: + case single: + default: + this.single(aeiObjects, manual, matrix, taskCompleteds); + } + // 可能在处理过程中删除了所有的待办,比如有优先路由 + if (matrix.isEmpty()) { + results.add(aeiObjects.getWork()); + } + } + aeiObjects.getWork().setManualTaskIdentityMatrix(matrix); + return results; + } // /** // * 获取当前参与流转的已办,同时过滤路由决策在路由中的已办. @@ -426,476 +428,497 @@ public class ManualProcessor extends AbstractManualProcessor { // return taskCompleteds; // } - @SuppressWarnings("unchecked") - @Deprecated(forRemoval = true, since = "8.0") - private ManualTaskIdentityMatrix executingManualTaskIdentityMatrix(AeiObjects aeiObjects, Manual manual) - throws Exception { - ManualTaskIdentityMatrix matrix = aeiObjects.getWork().getManualTaskIdentityMatrix(); - List exists = matrix.flat(); - matrix.remove(ListUtils.subtract(exists, aeiObjects.business().organization().identity().list(exists))); - if (matrix.isEmpty()) { - List identities = new ArrayList<>(); - // 兼容7.2.0之前的版本 - if (PropertyUtils.isReadable(aeiObjects.getWork(), DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST)) { - identities.addAll((List) PropertyUtils.getProperty(aeiObjects.getWork(), - DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST)); - identities = aeiObjects.business().organization().identity().list(identities); - } - if (identities.isEmpty() && aeiObjects.getJoinInquireTaskCompletedsRouteNameAvailableWithActivityToken( - aeiObjects.getWork().getActivityToken()).isEmpty()) { - identities = calculateTaskIdentities(aeiObjects, manual); - LOGGER.info("工作设置的处理人已经全部无效,且没有已办,重新计算当前环节所有处理人进行处理,标题:{}, id:{}, 设置的处理人:{}.", - aeiObjects.getWork()::getTitle, aeiObjects.getWork()::getId, identities::toString); - } - matrix = manual.identitiesToManualTaskIdentityMatrix(identities); - } - // 重新绑定到对象上. - aeiObjects.getWork().setManualTaskIdentityMatrix(matrix); - return matrix; - } - - private void executingCompletedIdentityInTaskCompleteds(AeiObjects aeiObjects, ManualTaskIdentityMatrix matrix, - List taskCompleteds) throws Exception { - if (!matrix.isEmpty()) { - List identities = matrix.flat(); - List people = ListTools.extractProperty(taskCompleteds, TaskCompleted.person_FIELDNAME, - String.class, true, true); - taskCompleteds.stream().forEach(o -> identities.removeAll(matrix.completed(o.getIdentity()))); - if (!identities.isEmpty()) { - aeiObjects.business().organization().person().listPairIdentity(identities).stream().forEach(p -> { - if (people.contains(p.getPerson())) { - matrix.completed(p.getIdentity()); - } - }); - } - } - } - - @Override - protected void executingCommitted(AeiObjects aeiObjects, Manual manual, List works) throws Exception { - // Manual Work 还没有处理完 发生了停留,出发了停留事件 - if ((ListTools.isEmpty(works)) && (!aeiObjects.getCreateTasks().isEmpty())) { - boolean hasManualStayScript = this.hasManualStayScript(manual); - boolean processHasManualStayScript = this.hasManualStayScript(aeiObjects.getProcess()); - if (hasManualStayScript || processHasManualStayScript) { - ScriptContext scriptContext = aeiObjects.scriptContext(); - Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); - WorkContext workContext = (WorkContext) bindings.get(ScriptingFactory.BINDING_NAME_WORKCONTEXT); - // 只有一条待办绑定到task - if (aeiObjects.getCreateTasks().size() == 1) { - workContext.bindTask(aeiObjects.getCreateTasks().get(0)); - } - if (processHasManualStayScript) { - JsonScriptingExecutor - .eval(aeiObjects.business().element().getCompiledScript(aeiObjects.getApplication().getId(), - aeiObjects.getProcess(), Business.EVENT_MANUALSTAY), scriptContext); - } - if (hasManualStayScript) { - JsonScriptingExecutor - .eval(aeiObjects.business().element().getCompiledScript(aeiObjects.getApplication().getId(), - aeiObjects.getActivity(), Business.EVENT_MANUALSTAY), scriptContext); - } - // 解除绑定 - workContext.bindTask(null); - } - } - } - - @Override - protected List inquiring(AeiObjects aeiObjects, Manual manual) throws Exception { - // 发送ProcessingSignal - aeiObjects.getProcessingAttributes() - .push(Signal.manualInquire(aeiObjects.getWork().getActivityToken(), manual)); - List results = new ArrayList<>(); - // 仅有单条路由 - if (aeiObjects.getRoutes().size() == 1) { - results.add(aeiObjects.getRoutes().get(0)); - } else if (aeiObjects.getRoutes().size() > 1) { - // 存在多条路由 - Collection routeNames = aeiObjects.getRoutes().stream().map(Route::getName) - .collect(Collectors.toSet()); - List taskCompleteds = aeiObjects - .getJoinInquireTaskCompletedsWithActivityToken(aeiObjects.getWork().getActivityToken()).stream() - .filter(t -> routeNames.contains(t.getRouteName())).collect(Collectors.toList()); - String name = this.choiceRouteName(taskCompleteds, aeiObjects.getRoutes(), manual); - Optional optional = aeiObjects.getRoutes().stream() - .filter(r -> StringUtils.equalsIgnoreCase(name, r.getName())).findFirst(); - if (optional.isPresent()) { - results.add(optional.get()); - } - } else { - throw new ExceptionManualNotRoute(manual.getId()); - } - if (!results.isEmpty()) { - // 清理掉强制的指定的处理人 - aeiObjects.getWork().getProperties().setManualForceTaskIdentityList(new ArrayList<>()); - } - return results; - } - - /** - * 判断的逻辑如下: - * 1.是否有用户选择了"直接返回优先路由(soleDirect)",同时判断该值是否在路由列表中(可能修改路由名称),如果有就直接返回该值. - * 2.是否有用户选择了"优先路由(sole)",同时判断该值是否在路由列表中(可能修改路由名称),如果有就直接返回该值. - * 3.如果没有soleDirect或者sole被选择,那么根据活动类型进行判断,如果是并行活动(parallel)那么选择最多的路由决策,如果有多个路由决策同样数量,那么选择时间上最晚的那组,如果是single(单人),queue(串行),grab(抢办)那么最后的路由决策作为返回值(需要判断是否在路由列表中). - * - * @param taskCompleteds 按创建时间正序排列好的已办 - * @param manual 人工活动节点 - * @param routes 离开活动节点的路由列表 - * @return 路由名称 - * @throws Exception - */ - private String choiceRouteName(List taskCompleteds, List routes, Manual manual) - throws Exception { - final Triple, List, Manual> triple = Triple.of(taskCompleteds, routes, manual); - Optional optional = Stream - ., List, Manual>, Optional>>of( - this::chooseSoleDirectIfExist, this::chooseSoleIfExist, this::chooseMaxCountOrLatest) - .map(f -> f.apply(triple)).filter(Optional::isPresent).findFirst().orElse(Optional.empty()); - if (optional.isPresent()) { - return optional.get(); - } else { - throw new ExceptionChoiceRouteNameError(ListTools.extractProperty(taskCompleteds, - TaskCompleted.routeName_FIELDNAME, String.class, false, false)); - } - } - - /** - * 判断是否有选择了直接返回优先路由的路由决策被选择,如果有就直接返回该路由名称,这里的遍历顺序需要保持正序,先选择先执行. - * - * @param list - * @param routes - * @return - */ - - private Optional chooseSoleDirectIfExist(final Triple, List, Manual> triple) { - return chooseIfExist(triple, r -> BooleanUtils.isTrue(r.getSoleDirect())); - } - - /** - * 判断是否有选择了优先路由的路由决策被选择,如果有就直接返回该路由名称,这里的遍历顺序需要保持正序,先选择先执行. - * - * @param list - * @param routes - * @return - */ - private Optional chooseSoleIfExist(final Triple, List, Manual> triple) { - return chooseIfExist(triple, r -> BooleanUtils.isTrue(r.getSole())); - } - - private Optional chooseIfExist(final Triple, List, Manual> triple, - final Predicate predicate) { - final List taskCompleteds = triple.getLeft(); - final List routes = triple.getMiddle(); - final Collection names = routes.stream().filter(predicate).map(Route::getName) - .collect(Collectors.toSet()); - return taskCompleteds.stream().map(TaskCompleted::getRouteName).filter(names::contains).findFirst(); - } - - /** - * 已办中获取数量最多的路由决策,如果有组路由决策数量一样多,那么选择时间上最后被选择的路由决策,获取后需要进行判断是否在routes列表中 - * - * @param list - * @param routes - * @return - * @throws Exception - */ - private Optional chooseMaxCountOrLatest(Triple, List, Manual> triple) { - if (!Objects.equals(ManualMode.parallel, triple.getRight().getManualMode())) { - return triple.getLeft().stream().sorted(Comparator.comparing(TaskCompleted::getCreateTime).reversed()) - .findFirst().map(TaskCompleted::getRouteName); - } - return triple.getLeft().stream().collect(Collectors.groupingBy(TaskCompleted::getRouteName)).entrySet().stream() - .max((o1, o2) -> { - int c = o1.getValue().size() - o2.getValue().size(); - if (c == 0) { - return ObjectUtils.compare( - o1.getValue().stream().mapToLong(t -> t.getCreateTime().getTime()).max().getAsLong(), - o2.getValue().stream().mapToLong(t -> t.getCreateTime().getTime()).max().getAsLong()); - } else { - return c; - } - }).map(Entry::getKey); - } - - // 是否有优先路由 - private void single(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, - List taskCompleteds) throws Exception { - if (soleDirect(aeiObjects, taskCompleteds)) { - matrix.clear(); - aeiObjects.getTasks().stream().filter( - t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) - .forEach(aeiObjects::deleteTask); - } else { - task(aeiObjects, manual, matrix.read()); - } - } - - private void parallel(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, - List taskCompleteds) throws Exception { - // 是否有优先路由 - if (soleDirect(aeiObjects, taskCompleteds)) { - matrix.clear(); - aeiObjects.getTasks().stream().filter( - t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) - .forEach(aeiObjects::deleteTask); - } else { - task(aeiObjects, manual, matrix.flat()); - } - } - - private void queue(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, - List taskCompleteds) throws Exception { - if (soleDirect(aeiObjects, taskCompleteds)) { - matrix.clear(); - aeiObjects.getTasks().stream().filter( - t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) - .forEach(aeiObjects::deleteTask); - } else { - task(aeiObjects, manual, matrix.read()); - } - } - - private boolean soleDirect(AeiObjects aeiObjects, List taskCompleteds) throws Exception { - // 存在优先路由,如果有人选择了优先路由那么直接流转.需要判断是否启用了soleDirect - Optional route = aeiObjects.getRoutes().stream().filter(r -> BooleanUtils.isTrue(r.getSoleDirect())) - .findFirst(); - if (route.isPresent()) { - Optional taskCompleted = taskCompleteds.stream() - .filter(t -> StringUtils.equals(t.getRouteName(), route.get().getName())).findFirst(); - if (taskCompleted.isPresent()) { - return true; - } - } - return false; - } - - private void task(AeiObjects aeiObjects, Manual manual, List identities) throws Exception { - String activityToken = aeiObjects.getWork().getActivityToken(); - aeiObjects.getTasks().stream().filter(t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), activityToken)) - .forEach(t -> { - if (!identities.contains(t.getIdentity())) { - aeiObjects.deleteTask(t); - } else { - identities.remove(t.getIdentity()); - } - }); - for (String identity : identities) { - aeiObjects.createTask(this.createTask(aeiObjects, manual, identity)); - } - } - - @Override - protected void inquiringCommitted(AeiObjects aeiObjects, Manual manual) throws Exception { - // nothing - } - - private void calculateExpire(AeiObjects aeiObjects, Manual manual, Task task) throws Exception { - if (null != manual.getTaskExpireType()) { - switch (manual.getTaskExpireType()) { - case never: - this.expireNever(task); - break; - case appoint: - this.expireAppoint(manual, task); - break; - case script: - this.expireScript(aeiObjects, manual, task); - break; - default: - break; - } - } - // 如果work有截至时间 - if (null != aeiObjects.getWork().getExpireTime()) { - if (null == task.getExpireTime()) { - task.setExpireTime(aeiObjects.getWork().getExpireTime()); - } else { - if (task.getExpireTime().after(aeiObjects.getWork().getExpireTime())) { - task.setExpireTime(aeiObjects.getWork().getExpireTime()); - } - } - } - // 已经有过期时间了,那么设置催办时间 - if (null != task.getExpireTime()) { - task.setUrgeTime(DateUtils.addHours(task.getExpireTime(), -2)); - } else { - task.setExpired(false); - task.setUrgeTime(null); - task.setUrged(false); - } - } - - // 从不过期 - private void expireNever(Task task) { - task.setExpireTime(null); - } - - private void expireAppoint(Manual manual, Task task) throws Exception { - if (BooleanUtils.isTrue(manual.getTaskExpireWorkTime())) { - this.expireAppointWorkTime(task, manual); - } else { - this.expireAppointNaturalDay(task, manual); - } - } - - private void expireAppointWorkTime(Task task, Manual manual) throws Exception { - Integer m = 0; - WorkTime wt = Config.workTime(); - if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) { - m += manual.getTaskExpireDay() * wt.minutesOfWorkDay(); - } - if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) { - m += manual.getTaskExpireHour() * 60; - } - if (m > 0) { - Date expire = wt.forwardMinutes(new Date(), m); - task.setExpireTime(expire); - } else { - task.setExpireTime(null); - } - } - - private void expireAppointNaturalDay(Task task, Manual manual) { - Integer m = 0; - if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) { - m += manual.getTaskExpireDay() * 60 * 24; - } - if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) { - m += manual.getTaskExpireHour() * 60; - } - if (m > 0) { - Calendar cl = Calendar.getInstance(); - cl.add(Calendar.MINUTE, m); - task.setExpireTime(cl.getTime()); - } else { - task.setExpireTime(null); - } - } - - private void expireScript(AeiObjects aeiObjects, Manual manual, Task task) throws Exception { - ExpireScriptResult expire = new ExpireScriptResult(); - ScriptContext scriptContext = aeiObjects.scriptContext(); - CompiledScript cs = aeiObjects.business().element().getCompiledScript(aeiObjects.getWork().getApplication(), - manual, Business.EVENT_MANUALTASKEXPIRE); - scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put(ScriptingFactory.BINDING_NAME_EXPIRE, expire); - JsonScriptingExecutor.eval(cs, scriptContext, ExpireScriptResult.class, o -> { - if (null != o) { - expire.setDate(o.getDate()); - expire.setHour(o.getHour()); - expire.setWorkHour(o.getWorkHour()); - } - }); - if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getWorkHour(), 0))) { - Integer m = 0; - m += expire.getWorkHour() * 60; - if (m > 0) { - task.setExpireTime(Config.workTime().forwardMinutes(new Date(), m)); - } else { - task.setExpireTime(null); - } - } else if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getHour(), 0))) { - Integer m = 0; - m += expire.getHour() * 60; - if (m > 0) { - Calendar cl = Calendar.getInstance(); - cl.add(Calendar.MINUTE, m); - task.setExpireTime(cl.getTime()); - } else { - task.setExpireTime(null); - } - } else if (null != expire.getDate()) { - task.setExpireTime(expire.getDate()); - } else { - task.setExpireTime(null); - } - } - - private Task createTask(AeiObjects aeiObjects, Manual manual, String identity) throws Exception { - String fromIdentity = aeiObjects.getWork().getProperties().getManualEmpowerMap().get(identity); - String person = aeiObjects.business().organization().person().getWithIdentity(identity); - String unit = aeiObjects.business().organization().unit().getWithIdentity(identity); - Task task = new Task(aeiObjects.getWork(), identity, person, unit, fromIdentity, new Date(), null, - aeiObjects.getRoutes(), manual.getAllowRapid()); - // 是第一条待办,进行标记,调度过的待办都标记为非第一个待办 - if (BooleanUtils.isTrue(aeiObjects.getProcessingAttributes().getForceJoinAtArrive())) { - task.setFirst(false); - } else { - task.setFirst(ListTools.isEmpty(aeiObjects.getJoinInquireTaskCompleteds())); - } - this.calculateExpire(aeiObjects, manual, task); - if (StringUtils.isNotEmpty(fromIdentity)) { - aeiObjects.business().organization().empowerLog() - .log(this.createEmpowerLog(aeiObjects.getWork(), fromIdentity, identity)); - String fromPerson = aeiObjects.business().organization().person().getWithIdentity(fromIdentity); - String fromUnit = aeiObjects.business().organization().unit().getWithIdentity(fromIdentity); - TaskCompleted empowerTaskCompleted = new TaskCompleted(aeiObjects.getWork()); - empowerTaskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_EMPOWER); - empowerTaskCompleted.setIdentity(fromIdentity); - empowerTaskCompleted.setUnit(fromUnit); - empowerTaskCompleted.setPerson(fromPerson); - empowerTaskCompleted.setEmpowerToIdentity(identity); - aeiObjects.createTaskCompleted(empowerTaskCompleted); - Read empowerRead = new Read(aeiObjects.getWork(), fromIdentity, fromUnit, fromPerson); - aeiObjects.createRead(empowerRead); - } - return task; - } - - private EmpowerLog createEmpowerLog(Work work, String fromIdentity, String toIdentity) { - return new EmpowerLog().setApplication(work.getApplication()).setApplicationAlias(work.getApplicationAlias()) - .setApplicationName(work.getApplicationName()).setProcess(work.getProcess()) - .setProcessAlias(work.getProcessAlias()).setProcessName(work.getProcessName()).setTitle(work.getTitle()) - .setWork(work.getId()).setJob(work.getJob()).setFromIdentity(fromIdentity).setToIdentity(toIdentity) - .setActivity(work.getActivity()).setActivityAlias(work.getActivityAlias()) - .setActivityName(work.getActivityName()).setEmpowerTime(new Date()); - } - - private List arrivingSameJobActivityExistIdentities(AeiObjects aeiObjects, Manual manual) throws Exception { - List exists = new ArrayList<>(); - aeiObjects.getTasks().stream() - .filter(o -> StringUtils.equals(o.getActivity(), manual.getId()) - && StringUtils.equals(o.getJob(), aeiObjects.getWork().getJob())) - .forEach(o -> exists.add(o.getIdentity())); - return exists; - } - - public class ExpireScriptResult { - Integer hour; - Integer workHour; - Date date; - - public Integer getHour() { - return hour; - } - - public void setHour(Integer hour) { - this.hour = hour; - } - - public Integer getWorkHour() { - return workHour; - } - - public void setWorkHour(Integer workHour) { - this.workHour = workHour; - } - - public Date getDate() { - return date; - } - - public void setDate(Date date) { - this.date = date; - } - - public void setDate(String str) { - try { - this.date = DateTools.parse(str); - } catch (Exception e) { - LOGGER.error(e); - } - } - - } + @SuppressWarnings("unchecked") + @Deprecated(forRemoval = true, since = "8.0") + private ManualTaskIdentityMatrix executingManualTaskIdentityMatrix(AeiObjects aeiObjects, Manual manual) + throws Exception { + ManualTaskIdentityMatrix matrix = aeiObjects.getWork().getManualTaskIdentityMatrix(); + List exists = matrix.flat(); + matrix.remove(ListUtils.subtract(exists, aeiObjects.business().organization().identity().list(exists))); + if (matrix.isEmpty()) { + List identities = new ArrayList<>(); + // 兼容7.2.0之前的版本 + if (PropertyUtils.isReadable(aeiObjects.getWork(), DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST)) { + identities.addAll((List) PropertyUtils.getProperty(aeiObjects.getWork(), + DEPRECATED_WORK_FIELD_MANUALTASKIDENTITYLIST)); + identities = aeiObjects.business().organization().identity().list(identities); + } + if (identities.isEmpty() && aeiObjects.getJoinInquireTaskCompletedsRouteNameAvailableWithActivityToken( + aeiObjects.getWork().getActivityToken()).isEmpty()) { + identities = calculateTaskIdentities(aeiObjects, manual); + LOGGER.info("工作设置的处理人已经全部无效,且没有已办,重新计算当前环节所有处理人进行处理,标题:{}, id:{}, 设置的处理人:{}.", + aeiObjects.getWork()::getTitle, aeiObjects.getWork()::getId, identities::toString); + } + matrix = manual.identitiesToManualTaskIdentityMatrix(identities); + } + // 重新绑定到对象上. + aeiObjects.getWork().setManualTaskIdentityMatrix(matrix); + return matrix; + } + + private void executingCompletedIdentityInTaskCompleteds(AeiObjects aeiObjects, ManualTaskIdentityMatrix matrix, + List taskCompleteds) throws Exception { + if (!matrix.isEmpty()) { + List identities = matrix.flat(); + List people = ListTools.extractProperty(taskCompleteds, TaskCompleted.person_FIELDNAME, + String.class, true, true); + taskCompleteds.stream().forEach(o -> identities.removeAll(matrix.completed(o.getIdentity()))); + if (!identities.isEmpty()) { + aeiObjects.business().organization().person().listPairIdentity(identities).stream().forEach(p -> { + if (people.contains(p.getPerson())) { + matrix.completed(p.getIdentity()); + } + }); + } + } + } + + @Override + protected void executingCommitted(AeiObjects aeiObjects, Manual manual, List works) throws Exception { + // Manual Work 还没有处理完 发生了停留,出发了停留事件 + if ((ListTools.isEmpty(works)) && (!aeiObjects.getCreateTasks().isEmpty())) { + boolean hasManualStayScript = this.hasManualStayScript(manual); + boolean processHasManualStayScript = this.hasManualStayScript(aeiObjects.getProcess()); + if (hasManualStayScript || processHasManualStayScript) { + ScriptContext scriptContext = aeiObjects.scriptContext(); + Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE); + WorkContext workContext = (WorkContext) bindings.get(ScriptingFactory.BINDING_NAME_WORKCONTEXT); + // 只有一条待办绑定到task + if (aeiObjects.getCreateTasks().size() == 1) { + workContext.bindTask(aeiObjects.getCreateTasks().get(0)); + } + if (processHasManualStayScript) { + JsonScriptingExecutor + .eval(aeiObjects.business().element().getCompiledScript(aeiObjects.getApplication().getId(), + aeiObjects.getProcess(), Business.EVENT_MANUALSTAY), scriptContext); + } + if (hasManualStayScript) { + JsonScriptingExecutor + .eval(aeiObjects.business().element().getCompiledScript(aeiObjects.getApplication().getId(), + aeiObjects.getActivity(), Business.EVENT_MANUALSTAY), scriptContext); + } + // 解除绑定 + workContext.bindTask(null); + } + } + } + + @Override + protected List inquiring(AeiObjects aeiObjects, Manual manual) throws Exception { + // 发送ProcessingSignal + aeiObjects.getProcessingAttributes() + .push(Signal.manualInquire(aeiObjects.getWork().getActivityToken(), manual)); + List results = new ArrayList<>(); + // 仅有单条路由 + if (aeiObjects.getRoutes().size() == 1) { + results.add(aeiObjects.getRoutes().get(0)); + } else if (aeiObjects.getRoutes().size() > 1) { + // 存在多条路由 + Collection routeNames = aeiObjects.getRoutes().stream().map(Route::getName) + .collect(Collectors.toSet()); + List taskCompleteds = aeiObjects + .getJoinInquireTaskCompletedsWithActivityToken(aeiObjects.getWork().getActivityToken()).stream() + .filter(t -> routeNames.contains(t.getRouteName())).collect(Collectors.toList()); + String name = this.choiceRouteName(taskCompleteds, aeiObjects.getRoutes(), manual); + Optional optional = aeiObjects.getRoutes().stream() + .filter(r -> StringUtils.equalsIgnoreCase(name, r.getName())).findFirst(); + if (optional.isPresent()) { + results.add(optional.get()); + } + } else { + throw new ExceptionManualNotRoute(manual.getId()); + } + if (!results.isEmpty()) { + // 清理掉强制的指定的处理人 + aeiObjects.getWork().getProperties().setManualForceTaskIdentityList(new ArrayList<>()); + } + return results; + } + + /** + * 判断的逻辑如下: + * 1.是否有用户选择了"直接返回优先路由(soleDirect)",同时判断该值是否在路由列表中(可能修改路由名称),如果有就直接返回该值. + * 2.是否有用户选择了"优先路由(sole)",同时判断该值是否在路由列表中(可能修改路由名称),如果有就直接返回该值. + * 3.如果没有soleDirect或者sole被选择,那么根据活动类型进行判断,如果是并行活动(parallel)那么选择最多的路由决策,如果有多个路由决策同样数量,那么选择时间上最晚的那组,如果是single(单人),queue(串行),grab(抢办)那么最后的路由决策作为返回值(需要判断是否在路由列表中). + * + * @param taskCompleteds 按创建时间正序排列好的已办 + * @param manual 人工活动节点 + * @param routes 离开活动节点的路由列表 + * @return 路由名称 + * @throws Exception + */ + private String choiceRouteName(List taskCompleteds, List routes, Manual manual) + throws Exception { + final Triple, List, Manual> triple = Triple.of(taskCompleteds, routes, manual); + Optional optional = Stream + ., List, Manual>, Optional>>of( + this::chooseSoleDirectIfExist, this::chooseSoleIfExist, this::chooseMaxCountOrLatest) + .map(f -> f.apply(triple)).filter(Optional::isPresent).findFirst().orElse(Optional.empty()); + if (optional.isPresent()) { + return optional.get(); + } else { + throw new ExceptionChoiceRouteNameError(ListTools.extractProperty(taskCompleteds, + TaskCompleted.routeName_FIELDNAME, String.class, false, false)); + } + } + + /** + * 判断是否有选择了直接返回优先路由的路由决策被选择,如果有就直接返回该路由名称,这里的遍历顺序需要保持正序,先选择先执行. + * + * @param list + * @param routes + * @return + */ + + private Optional chooseSoleDirectIfExist(final Triple, List, Manual> triple) { + return chooseIfExist(triple, r -> BooleanUtils.isTrue(r.getSoleDirect())); + } + + /** + * 判断是否有选择了优先路由的路由决策被选择,如果有就直接返回该路由名称,这里的遍历顺序需要保持正序,先选择先执行. + * + * @param list + * @param routes + * @return + */ + private Optional chooseSoleIfExist(final Triple, List, Manual> triple) { + return chooseIfExist(triple, r -> BooleanUtils.isTrue(r.getSole())); + } + + private Optional chooseIfExist(final Triple, List, Manual> triple, + final Predicate predicate) { + final List taskCompleteds = triple.getLeft(); + final List routes = triple.getMiddle(); + final Collection names = routes.stream().filter(predicate).map(Route::getName) + .collect(Collectors.toSet()); + return taskCompleteds.stream().map(TaskCompleted::getRouteName).filter(names::contains).findFirst(); + } + + /** + * 已办中获取数量最多的路由决策,如果有组路由决策数量一样多,那么选择时间上最后被选择的路由决策,获取后需要进行判断是否在routes列表中 + * + * @param list + * @param routes + * @return + * @throws Exception + */ + private Optional chooseMaxCountOrLatest(Triple, List, Manual> triple) { + if (!Objects.equals(ManualMode.parallel, triple.getRight().getManualMode())) { + return triple.getLeft().stream().sorted(Comparator.comparing(TaskCompleted::getCreateTime).reversed()) + .findFirst().map(TaskCompleted::getRouteName); + } + return triple.getLeft().stream().collect(Collectors.groupingBy(TaskCompleted::getRouteName)).entrySet().stream() + .max((o1, o2) -> { + int c = o1.getValue().size() - o2.getValue().size(); + if (c == 0) { + return ObjectUtils.compare( + o1.getValue().stream().mapToLong(t -> t.getCreateTime().getTime()).max().getAsLong(), + o2.getValue().stream().mapToLong(t -> t.getCreateTime().getTime()).max().getAsLong()); + } else { + return c; + } + }).map(Entry::getKey); + } + + // 是否有优先路由 + private void single(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, + List taskCompleteds) throws Exception { + if (soleDirect(aeiObjects, taskCompleteds)) { + matrix.clear(); + aeiObjects.getTasks().stream().filter( + t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) + .forEach(aeiObjects::deleteTask); + } else { + task(aeiObjects, manual, matrix.read()); + } + } + + private void parallel(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, + List taskCompleteds) throws Exception { + // 是否有优先路由 + if (soleDirect(aeiObjects, taskCompleteds)) { + matrix.clear(); + aeiObjects.getTasks().stream().filter( + t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) + .forEach(aeiObjects::deleteTask); + } else { + task(aeiObjects, manual, matrix.flat()); + } + } + + private void queue(AeiObjects aeiObjects, Manual manual, ManualTaskIdentityMatrix matrix, + List taskCompleteds) throws Exception { + if (soleDirect(aeiObjects, taskCompleteds)) { + matrix.clear(); + aeiObjects.getTasks().stream().filter( + t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), aeiObjects.getWork().getActivityToken())) + .forEach(aeiObjects::deleteTask); + } else { + task(aeiObjects, manual, matrix.read()); + } + } + + private boolean soleDirect(AeiObjects aeiObjects, List taskCompleteds) throws Exception { + // 存在优先路由,如果有人选择了优先路由那么直接流转.需要判断是否启用了soleDirect + Optional route = aeiObjects.getRoutes().stream().filter(r -> BooleanUtils.isTrue(r.getSoleDirect())) + .findFirst(); + if (route.isPresent()) { + Optional taskCompleted = taskCompleteds.stream() + .filter(t -> StringUtils.equals(t.getRouteName(), route.get().getName())).findFirst(); + if (taskCompleted.isPresent()) { + return true; + } + } + return false; + } + + private void task(AeiObjects aeiObjects, Manual manual, List identities) throws Exception { + String activityToken = aeiObjects.getWork().getActivityToken(); + final Set routeNameSet = new HashSet<>( + aeiObjects.getRoutes().stream().map(Route::getName).collect(Collectors.toList())); + aeiObjects.getTasks().stream().filter(t -> StringUtils.equalsIgnoreCase(t.getActivityToken(), activityToken)) + .forEach(t -> { + if (!identities.contains(t.getIdentity())) { + // 不在处理身份中 + LOGGER.warn("delete a task whose identity does not match, id:{}, identity:{}.", t::getId, + t::getIdentity); + aeiObjects.deleteTask(t); + } else if (!SetUtils.isEqualSet(routeNameSet, new HashSet<>(t.getRouteNameList()))) { + // 路由名称发生变化. + LOGGER.warn( + "update a task whose route name does not match, id:{}, route name:{}, expected route name:{}.", + t::getId, + () -> StringUtils.join(t.getRouteNameList()), () -> StringUtils.join(routeNameSet)); + try { + aeiObjects.getUpdateTasks().add(t.updateRoute(aeiObjects.getRoutes())); + identities.remove(t.getIdentity()); + } catch (Exception e) { + LOGGER.error(e); + } + } else { + identities.remove(t.getIdentity()); + } + }); + identities.stream().forEach(o -> { + try { + aeiObjects.createTask(this.createTask(aeiObjects, manual, o)); + } catch (Exception e) { + LOGGER.error(e); + } + }); + } + + @Override + protected void inquiringCommitted(AeiObjects aeiObjects, Manual manual) throws Exception { + // nothing + } + + private void calculateExpire(AeiObjects aeiObjects, Manual manual, Task task) throws Exception { + if (null != manual.getTaskExpireType()) { + switch (manual.getTaskExpireType()) { + case never: + this.expireNever(task); + break; + case appoint: + this.expireAppoint(manual, task); + break; + case script: + this.expireScript(aeiObjects, manual, task); + break; + default: + break; + } + } + // 如果work有截至时间 + if (null != aeiObjects.getWork().getExpireTime()) { + if (null == task.getExpireTime()) { + task.setExpireTime(aeiObjects.getWork().getExpireTime()); + } else { + if (task.getExpireTime().after(aeiObjects.getWork().getExpireTime())) { + task.setExpireTime(aeiObjects.getWork().getExpireTime()); + } + } + } + // 已经有过期时间了,那么设置催办时间 + if (null != task.getExpireTime()) { + task.setUrgeTime(DateUtils.addHours(task.getExpireTime(), -2)); + } else { + task.setExpired(false); + task.setUrgeTime(null); + task.setUrged(false); + } + } + + // 从不过期 + private void expireNever(Task task) { + task.setExpireTime(null); + } + + private void expireAppoint(Manual manual, Task task) throws Exception { + if (BooleanUtils.isTrue(manual.getTaskExpireWorkTime())) { + this.expireAppointWorkTime(task, manual); + } else { + this.expireAppointNaturalDay(task, manual); + } + } + + private void expireAppointWorkTime(Task task, Manual manual) throws Exception { + Integer m = 0; + WorkTime wt = Config.workTime(); + if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) { + m += manual.getTaskExpireDay() * wt.minutesOfWorkDay(); + } + if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) { + m += manual.getTaskExpireHour() * 60; + } + if (m > 0) { + Date expire = wt.forwardMinutes(new Date(), m); + task.setExpireTime(expire); + } else { + task.setExpireTime(null); + } + } + + private void expireAppointNaturalDay(Task task, Manual manual) { + Integer m = 0; + if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) { + m += manual.getTaskExpireDay() * 60 * 24; + } + if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) { + m += manual.getTaskExpireHour() * 60; + } + if (m > 0) { + Calendar cl = Calendar.getInstance(); + cl.add(Calendar.MINUTE, m); + task.setExpireTime(cl.getTime()); + } else { + task.setExpireTime(null); + } + } + + private void expireScript(AeiObjects aeiObjects, Manual manual, Task task) throws Exception { + ExpireScriptResult expire = new ExpireScriptResult(); + ScriptContext scriptContext = aeiObjects.scriptContext(); + CompiledScript cs = aeiObjects.business().element().getCompiledScript(aeiObjects.getWork().getApplication(), + manual, Business.EVENT_MANUALTASKEXPIRE); + scriptContext.getBindings(ScriptContext.ENGINE_SCOPE).put(ScriptingFactory.BINDING_NAME_EXPIRE, expire); + JsonScriptingExecutor.eval(cs, scriptContext, ExpireScriptResult.class, o -> { + if (null != o) { + expire.setDate(o.getDate()); + expire.setHour(o.getHour()); + expire.setWorkHour(o.getWorkHour()); + } + }); + if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getWorkHour(), 0))) { + Integer m = 0; + m += expire.getWorkHour() * 60; + if (m > 0) { + task.setExpireTime(Config.workTime().forwardMinutes(new Date(), m)); + } else { + task.setExpireTime(null); + } + } else if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getHour(), 0))) { + Integer m = 0; + m += expire.getHour() * 60; + if (m > 0) { + Calendar cl = Calendar.getInstance(); + cl.add(Calendar.MINUTE, m); + task.setExpireTime(cl.getTime()); + } else { + task.setExpireTime(null); + } + } else if (null != expire.getDate()) { + task.setExpireTime(expire.getDate()); + } else { + task.setExpireTime(null); + } + } + + private Task createTask(AeiObjects aeiObjects, Manual manual, String identity) throws Exception { + String fromIdentity = aeiObjects.getWork().getProperties().getManualEmpowerMap().get(identity); + String person = aeiObjects.business().organization().person().getWithIdentity(identity); + String unit = aeiObjects.business().organization().unit().getWithIdentity(identity); + Task task = new Task(aeiObjects.getWork(), identity, person, unit, fromIdentity, new Date(), null, + aeiObjects.getRoutes(), manual.getAllowRapid()); + // 是第一条待办,进行标记,调度过的待办都标记为非第一个待办 + if (BooleanUtils.isTrue(aeiObjects.getProcessingAttributes().getForceJoinAtArrive())) { + task.setFirst(false); + } else { + task.setFirst(ListTools.isEmpty(aeiObjects.getJoinInquireTaskCompleteds())); + } + this.calculateExpire(aeiObjects, manual, task); + if (StringUtils.isNotEmpty(fromIdentity)) { + aeiObjects.business().organization().empowerLog() + .log(this.createEmpowerLog(aeiObjects.getWork(), fromIdentity, identity)); + String fromPerson = aeiObjects.business().organization().person().getWithIdentity(fromIdentity); + String fromUnit = aeiObjects.business().organization().unit().getWithIdentity(fromIdentity); + TaskCompleted empowerTaskCompleted = new TaskCompleted(aeiObjects.getWork()); + empowerTaskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_EMPOWER); + empowerTaskCompleted.setIdentity(fromIdentity); + empowerTaskCompleted.setUnit(fromUnit); + empowerTaskCompleted.setPerson(fromPerson); + empowerTaskCompleted.setEmpowerToIdentity(identity); + aeiObjects.createTaskCompleted(empowerTaskCompleted); + Read empowerRead = new Read(aeiObjects.getWork(), fromIdentity, fromUnit, fromPerson); + aeiObjects.createRead(empowerRead); + } + return task; + } + + private EmpowerLog createEmpowerLog(Work work, String fromIdentity, String toIdentity) { + return new EmpowerLog().setApplication(work.getApplication()).setApplicationAlias(work.getApplicationAlias()) + .setApplicationName(work.getApplicationName()).setProcess(work.getProcess()) + .setProcessAlias(work.getProcessAlias()).setProcessName(work.getProcessName()).setTitle(work.getTitle()) + .setWork(work.getId()).setJob(work.getJob()).setFromIdentity(fromIdentity).setToIdentity(toIdentity) + .setActivity(work.getActivity()).setActivityAlias(work.getActivityAlias()) + .setActivityName(work.getActivityName()).setEmpowerTime(new Date()); + } + + private List arrivingSameJobActivityExistIdentities(AeiObjects aeiObjects, Manual manual) throws Exception { + List exists = new ArrayList<>(); + aeiObjects.getTasks().stream() + .filter(o -> StringUtils.equals(o.getActivity(), manual.getId()) + && StringUtils.equals(o.getJob(), aeiObjects.getWork().getJob())) + .forEach(o -> exists.add(o.getIdentity())); + return exists; + } + + public class ExpireScriptResult { + Integer hour; + Integer workHour; + Date date; + + public Integer getHour() { + return hour; + } + + public void setHour(Integer hour) { + this.hour = hour; + } + + public Integer getWorkHour() { + return workHour; + } + + public void setWorkHour(Integer workHour) { + this.workHour = workHour; + } + + public Date getDate() { + return date; + } + + public void setDate(Date date) { + this.date = date; + } + + public void setDate(String str) { + try { + this.date = DateTools.parse(str); + } catch (Exception e) { + LOGGER.error(e); + } + } + + } }