ManualProcessor.java 29.8 KB
Newer Older
R
roo00 已提交
1 2 3 4
package com.x.processplatform.service.processing.processor.manual;

import java.util.ArrayList;
import java.util.Calendar;
5
import java.util.Comparator;
R
roo00 已提交
6
import java.util.Date;
NoSubject's avatar
NoSubject 已提交
7
import java.util.LinkedHashMap;
R
roo00 已提交
8
import java.util.List;
9 10
import java.util.Map;
import java.util.Map.Entry;
R
roo00 已提交
11
import java.util.Objects;
12
import java.util.Optional;
R
roo00 已提交
13 14
import java.util.stream.Collectors;

R
roo00 已提交
15 16 17
import javax.script.Bindings;
import javax.script.ScriptContext;

NoSubject's avatar
NoSubject 已提交
18
import org.apache.commons.collections4.ListUtils;
R
roo00 已提交
19
import org.apache.commons.lang3.BooleanUtils;
20
import org.apache.commons.lang3.ObjectUtils;
R
roo00 已提交
21 22 23 24 25 26 27 28
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;

import com.x.base.core.container.EntityManagerContainer;
import com.x.base.core.entity.JpaObject;
import com.x.base.core.project.config.Config;
import com.x.base.core.project.logger.Logger;
import com.x.base.core.project.logger.LoggerFactory;
R
roo00 已提交
29
import com.x.base.core.project.organization.EmpowerLog;
R
roo00 已提交
30
import com.x.base.core.project.script.ScriptFactory;
R
roo00 已提交
31 32 33 34
import com.x.base.core.project.tools.DateTools;
import com.x.base.core.project.tools.ListTools;
import com.x.base.core.project.tools.NumberTools;
import com.x.base.core.project.utils.time.WorkTime;
R
roo00 已提交
35
import com.x.processplatform.core.entity.content.Read;
R
roo00 已提交
36 37 38 39 40 41 42 43
import com.x.processplatform.core.entity.content.Task;
import com.x.processplatform.core.entity.content.TaskCompleted;
import com.x.processplatform.core.entity.content.Work;
import com.x.processplatform.core.entity.content.WorkLog;
import com.x.processplatform.core.entity.element.ActivityType;
import com.x.processplatform.core.entity.element.Manual;
import com.x.processplatform.core.entity.element.Route;
import com.x.processplatform.core.entity.element.util.WorkLogTree;
NoSubject's avatar
NoSubject 已提交
44
import com.x.processplatform.core.entity.element.util.WorkLogTree.Node;
R
roo00 已提交
45
import com.x.processplatform.service.processing.Business;
R
roo00 已提交
46 47
import com.x.processplatform.service.processing.processor.AeiObjects;

48 49 50
/**
 * @author Zhou Rui
 */
R
roo00 已提交
51 52 53 54 55 56 57 58 59 60
public class ManualProcessor extends AbstractManualProcessor {

	private static Logger logger = LoggerFactory.getLogger(ManualProcessor.class);

	public ManualProcessor(EntityManagerContainer entityManagerContainer) throws Exception {
		super(entityManagerContainer);
	}

	@Override
	protected Work arriving(AeiObjects aeiObjects, Manual manual) throws Exception {
61
		// 根据manual计算出来的活动处理人
R
roo00 已提交
62
		List<String> identities = calculateTaskIdentities(aeiObjects, manual);
63
		// 启用同类工作相同活动节点合并,如果有合并的工作,那么直接返回这个工作.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
		Work merge = this.arrivingMergeSameJob(aeiObjects, manual, identities);
		if (null != merge) {
			return merge;
		}
		this.arrivingPassSame(aeiObjects, identities);
		aeiObjects.getWork().setManualTaskIdentityList(new ArrayList<String>(identities));
		return aeiObjects.getWork();
	}

	private Work arrivingMergeSameJob(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
		if (!BooleanUtils.isTrue(manual.getManualMergeSameJobActivity())) {
			return null;
		}
		List<String> exists = this.arriving_sameJobActivityExistIdentities(aeiObjects, manual);
		if (ListTools.isNotEmpty(exists)) {
			Work other = aeiObjects.getWorks().stream().filter(o -> {
				return StringUtils.equals(aeiObjects.getWork().getJob(), o.getJob())
						&& StringUtils.equals(aeiObjects.getWork().getActivity(), o.getActivity())
						&& (!Objects.equals(aeiObjects.getWork(), o));
			}).findFirst().orElse(null);
			if (null != other) {
				identities.removeAll(exists);
				if (ListTools.isEmpty(identities)) {
					this.mergeTaskCompleted(aeiObjects, aeiObjects.getWork(), other);
					this.mergeRead(aeiObjects, aeiObjects.getWork(), other);
					this.mergeReadCompleted(aeiObjects, aeiObjects.getWork(), other);
					this.mergeReview(aeiObjects, aeiObjects.getWork(), other);
					this.mergeAttachment(aeiObjects, aeiObjects.getWork(), other);
					this.mergeWorkLog(aeiObjects, aeiObjects.getWork(), other);
					if (ListTools.size(aeiObjects.getWork().getSplitTokenList()) > ListTools
							.size(other.getSplitTokenList())) {
						other.setSplitTokenList(aeiObjects.getWork().getSplitTokenList());
						other.setSplitToken(aeiObjects.getWork().getSplitToken());
						other.setSplitValue(aeiObjects.getWork().getSplitValue());
						other.setSplitting(true);
R
update  
roo00 已提交
99
					}
100 101 102
					aeiObjects.getUpdateWorks().add(other);
					aeiObjects.getDeleteWorks().add(aeiObjects.getWork());
					return other;
R
update  
roo00 已提交
103 104 105
				}
			}
		}
106 107
		return null;
	}
R
update  
roo00 已提交
108

109
	private void arrivingPassSame(AeiObjects aeiObjects, List<String> identities) throws Exception {
110
		// 查找是否有passSameTarget设置
111 112
		Route route = aeiObjects.getRoutes().stream().filter(o -> BooleanUtils.isTrue(o.getPassSameTarget()))
				.findFirst().orElse(null);
113
		// 如果有passSameTarget,有到达ArriveWorkLog,不是调度到这个节点的
114
		if ((null != route) && ((null != aeiObjects.getArriveWorkLog(aeiObjects.getWork())))
NoSubject's avatar
NoSubject 已提交
115
				&& (!aeiObjects.getProcessingAttributes().ifForceJoinAtArrive())) {
116 117 118 119 120 121 122
			WorkLog workLog = findPassSameTargetWorkLog(aeiObjects);
			logger.debug("pass same target work:{}, workLog:{}.", aeiObjects.getWork(), workLog);
			if (null == workLog) {
				return;
			}
			for (TaskCompleted o : aeiObjects.getJoinInquireTaskCompleteds()) {
				if (StringUtils.equals(o.getActivityToken(), workLog.getArrivedActivityToken())) {
Z
zhourui 已提交
123
					List<String> values = ListUtils.intersection(identities,
124 125 126 127
							aeiObjects.business().organization().identity().listWithPerson(o.getPerson()));
					if (!values.isEmpty()) {
						TaskCompleted obj = new TaskCompleted(aeiObjects.getWork(), route, o);
						obj.setIdentity(values.get(0));
128
						obj.setUnit(aeiObjects.business().organization().unit().getWithIdentity(obj.getIdentity()));
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
						obj.setProcessingType(TaskCompleted.PROCESSINGTYPE_SAMETARGET);
						obj.setRouteName(route.getName());
						Date now = new Date();
						obj.setStartTime(now);
						obj.setStartTimeMonth(DateTools.format(now, DateTools.format_yyyyMM));
						obj.setCompletedTime(now);
						obj.setCompletedTimeMonth(DateTools.format(now, DateTools.format_yyyyMM));
						obj.setDuration(0L);
						obj.setExpired(false);
						obj.setExpireTime(null);
						obj.setTask(null);
						obj.setLatest(true);
						aeiObjects.getCreateTaskCompleteds().add(obj);
					}
				}
R
roo00 已提交
144 145 146 147
			}
		}
	}

148
	// 计算处理人
R
roo00 已提交
149
	private List<String> calculateTaskIdentities(AeiObjects aeiObjects, Manual manual) throws Exception {
NoSubject's avatar
NoSubject 已提交
150
		TaskIdentities taskIdentities = new TaskIdentities();
151
		// 先计算强制处理人
NoSubject's avatar
NoSubject 已提交
152 153 154 155 156 157 158 159
		if (!aeiObjects.getWork().getProperties().getManualForceTaskIdentityList().isEmpty()) {
			List<String> identities = new ArrayList<>();
			identities.addAll(aeiObjects.getWork().getProperties().getManualForceTaskIdentityList());
			identities = aeiObjects.business().organization().identity().list(identities);
			if (ListTools.isNotEmpty(identities)) {
				taskIdentities.addIdentities(identities);
			}
		}
160
		// 计算退回的结果
NoSubject's avatar
NoSubject 已提交
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
		if (taskIdentities.isEmpty()) {
			Route route = aeiObjects.business().element().get(aeiObjects.getWork().getDestinationRoute(), Route.class);
			if ((null != route) && (StringUtils.equals(route.getType(), Route.TYPE_BACK))) {
				List<String> identities = new ArrayList<>();
				List<WorkLog> workLogs = new ArrayList<>();
				workLogs.addAll(aeiObjects.getUpdateWorkLogs());
				workLogs.addAll(aeiObjects.getCreateWorkLogs());
				for (WorkLog o : aeiObjects.getWorkLogs()) {
					if (!workLogs.contains(o)) {
						workLogs.add(o);
					}
				}
				WorkLogTree tree = new WorkLogTree(workLogs);
				Node node = tree.location(aeiObjects.getWork());
				if (null != node) {
					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);
					}
				}
			}
		}
		if (taskIdentities.isEmpty()) {
			taskIdentities = TranslateTaskIdentityTools.translate(aeiObjects, manual);
			this.ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(aeiObjects, manual, taskIdentities);
			this.writeToEmpowerMap(aeiObjects, taskIdentities);
		}
R
roo00 已提交
199 200 201
		return taskIdentities.identities();
	}

202
	// 如果活动没有找到任何可用的处理人,那么强制设置处理人为文档创建者,或者配置的 maintenanceIdentity
NoSubject's avatar
NoSubject 已提交
203 204
	private void ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(AeiObjects aeiObjects, Manual manual,
			TaskIdentities taskIdentities) throws Exception {
R
update  
roo00 已提交
205 206 207 208
		if (taskIdentities.isEmpty()) {
			String identity = aeiObjects.business().organization().identity()
					.get(aeiObjects.getWork().getCreatorIdentity());
			if (StringUtils.isNotEmpty(identity)) {
NoSubject's avatar
NoSubject 已提交
209 210
				logger.info("{}[{}]未能找到指定的处理人, 标题:{}, id:{}, 强制指定处理人为活动的创建身份:{}.", aeiObjects.getProcess().getName(),
						manual.getName(), aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(), identity);
R
update  
roo00 已提交
211 212 213 214 215
				taskIdentities.addIdentity(identity);
			} else {
				identity = aeiObjects.business().organization().identity()
						.get(Config.processPlatform().getMaintenanceIdentity());
				if (StringUtils.isNotEmpty(identity)) {
NoSubject's avatar
NoSubject 已提交
216 217 218
					logger.info("{}[{}]未能找到指定的处理人, 也没有能找到工作创建人, 标题:{}, id:{},  强制指定处理人为系统维护身份:{}.",
							aeiObjects.getProcess().getName(), manual.getName(), aeiObjects.getWork().getTitle(),
							aeiObjects.getWork().getId(), identity);
R
update  
roo00 已提交
219 220 221 222 223 224 225 226 227
					taskIdentities.addIdentity(identity);
				} else {
					throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(),
							aeiObjects.getActivity().getName(), aeiObjects.getActivity().getId());
				}
			}
		}
	}

228
	// 更新授权,通过surface创建且workThroughManual=false 代表是草稿,那么不需要授权.
NoSubject's avatar
NoSubject 已提交
229

R
roo00 已提交
230
	private void writeToEmpowerMap(AeiObjects aeiObjects, TaskIdentities taskIdentities) throws Exception {
231
		// 先清空EmpowerMap
NoSubject's avatar
NoSubject 已提交
232
		aeiObjects.getWork().getProperties().setManualEmpowerMap(new LinkedHashMap<String, String>());
R
update  
roo00 已提交
233 234
		if (!(StringUtils.equals(aeiObjects.getWork().getWorkCreateType(), Work.WORKCREATETYPE_SURFACE)
				&& BooleanUtils.isFalse(aeiObjects.getWork().getWorkThroughManual()))) {
NoSubject's avatar
NoSubject 已提交
235 236
			List<String> values = taskIdentities.identities();
			values = ListUtils.subtract(values, aeiObjects.getProcessingAttributes().getIgnoreEmpowerIdentityList());
R
update  
roo00 已提交
237
			taskIdentities.empower(aeiObjects.business().organization().empower().listWithIdentityObject(
Z
Zhou Rui 已提交
238 239
					aeiObjects.getWork().getApplication(), aeiObjects.getProcess().getEdition(),
					aeiObjects.getWork().getProcess(), aeiObjects.getWork().getId(), values));
R
update  
roo00 已提交
240 241
			for (TaskIdentity taskIdentity : taskIdentities) {
				if (StringUtils.isNotEmpty(taskIdentity.getFromIdentity())) {
NoSubject's avatar
NoSubject 已提交
242
					aeiObjects.getWork().getProperties().getManualEmpowerMap().put(taskIdentity.getIdentity(),
R
roo00 已提交
243
							taskIdentity.getFromIdentity());
R
update  
roo00 已提交
244 245 246 247 248
				}
			}
		}
	}

R
roo00 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275
	private WorkLog findPassSameTargetWorkLog(AeiObjects aeiObjects) throws Exception {
		WorkLogTree tree = new WorkLogTree(aeiObjects.getWorkLogs());
		List<WorkLog> parents = tree.parents(aeiObjects.getArriveWorkLog(aeiObjects.getWork()));
		logger.debug("pass same target rollback parents:{}.", parents);
		WorkLog workLog = null;
		for (WorkLog o : parents) {
			if (Objects.equals(ActivityType.manual, o.getArrivedActivityType())) {
				workLog = o;
				break;
			} else if (Objects.equals(ActivityType.choice, o.getArrivedActivityType())) {
				continue;
			} else if (Objects.equals(ActivityType.agent, o.getArrivedActivityType())) {
				continue;
			} else if (Objects.equals(ActivityType.invoke, o.getArrivedActivityType())) {
				continue;
			} else if (Objects.equals(ActivityType.service, o.getArrivedActivityType())) {
				continue;
			} else {
				break;
			}
		}
		logger.debug("pass same target find workLog:{}.", workLog);
		return workLog;
	}

	@Override
	protected void arrivingCommitted(AeiObjects aeiObjects, Manual manual) throws Exception {
Z
zhourui 已提交
276
		// nothing
R
roo00 已提交
277 278 279 280 281 282
	}

	@Override
	protected List<Work> executing(AeiObjects aeiObjects, Manual manual) throws Exception {
		List<Work> results = new ArrayList<>();
		boolean passThrough = false;
R
roo00 已提交
283

R
roo00 已提交
284 285
		List<String> identities = aeiObjects.business().organization().identity()
				.list(aeiObjects.getWork().getManualTaskIdentityList());
R
roo00 已提交
286
		identities = aeiObjects.business().organization().identity().list(identities);
R
roo00 已提交
287 288
		if (identities.isEmpty()) {
			identities = calculateTaskIdentities(aeiObjects, manual);
R
roo00 已提交
289

290
			logger.info("工作设置的处理人已经全部无效,重新计算当前环节所有处理人进行处理,标题:{}, id:{}, 设置的处理人:{}.", aeiObjects.getWork().getTitle(),
R
roo00 已提交
291
					aeiObjects.getWork().getId(), identities);
292
			// 后面进行了identitis.remove()这里必须用一个新对象包装
R
roo00 已提交
293
			aeiObjects.getWork().setManualTaskIdentityList(new ArrayList<String>(identities));
R
roo00 已提交
294
		}
R
roo00 已提交
295

R
roo00 已提交
296
		switch (manual.getManualMode()) {
297 298 299 300 301 302 303 304 305 306 307 308 309 310
		case single:
			passThrough = this.single(aeiObjects, manual, identities);
			break;
		case parallel:
			passThrough = this.parallel(aeiObjects, manual, identities);
			break;
		case queue:
			passThrough = this.queue(aeiObjects, manual, identities);
			break;
		case grab:
			passThrough = this.single(aeiObjects, manual, identities);
			break;
		default:
			throw new ExceptionManualModeError(manual.getId());
R
roo00 已提交
311
		}
NoSubject's avatar
NoSubject 已提交
312

R
roo00 已提交
313 314 315 316 317 318 319 320
		if (passThrough) {
			results.add(aeiObjects.getWork());
		}
		return results;
	}

	@Override
	protected void executingCommitted(AeiObjects aeiObjects, Manual manual) throws Exception {
Z
zhourui 已提交
321
		// nothing
R
roo00 已提交
322 323 324 325 326
	}

	@Override
	protected List<Route> inquiring(AeiObjects aeiObjects, Manual manual) throws Exception {
		List<Route> results = new ArrayList<>();
327
		// 仅有单条路由
R
roo00 已提交
328 329 330
		if (aeiObjects.getRoutes().size() == 1) {
			results.add(aeiObjects.getRoutes().get(0));
		} else if (aeiObjects.getRoutes().size() > 1) {
331
			// 存在多条路由
R
update  
roo00 已提交
332
			List<TaskCompleted> taskCompletedList = aeiObjects.getJoinInquireTaskCompleteds().stream()
R
roo00 已提交
333
					.filter(o -> StringUtils.equals(o.getActivityToken(), aeiObjects.getWork().getActivityToken())
R
update  
roo00 已提交
334
							&& aeiObjects.getWork().getManualTaskIdentityList().contains(o.getIdentity()))
R
roo00 已提交
335
					.collect(Collectors.toList());
R
roo00 已提交
336

R
bug fix  
roo00 已提交
337
			String name = this.choiceRouteName(taskCompletedList, aeiObjects.getRoutes());
R
roo00 已提交
338 339 340 341 342 343 344
			for (Route o : aeiObjects.getRoutes()) {
				if (o.getName().equalsIgnoreCase(name)) {
					results.add(o);
					break;
				}
			}
		}
NoSubject's avatar
NoSubject 已提交
345
		if (!results.isEmpty()) {
346
			// 清理掉强制的指定的处理人
NoSubject's avatar
NoSubject 已提交
347 348 349
			aeiObjects.getWork().getProperties().setManualForceTaskIdentityList(new ArrayList<String>());
		}

R
roo00 已提交
350 351 352
		return results;
	}

353
	// 通过已办存根选择某条路由
R
bug fix  
roo00 已提交
354
	private String choiceRouteName(List<TaskCompleted> list, List<Route> routes) throws Exception {
R
roo00 已提交
355
		String result = "";
R
roo00 已提交
356
		List<String> names = new ArrayList<>();
357 358
		ListTools.trim(list, false, false).stream().forEach(o -> names.add(o.getRouteName()));
		// 进行优先路由的判断
359
		Route soleRoute = routes.stream().filter(o -> BooleanUtils.isTrue(o.getSole())).findFirst().orElse(null);
R
roo00 已提交
360
		if ((null != soleRoute) && names.contains(soleRoute.getName())) {
R
bug fix  
roo00 已提交
361 362
			result = soleRoute.getName();
		} else {
363 364
			// 进行默认的策略,选择占比多的
			result = maxCountOrLatest(list);
R
roo00 已提交
365 366 367 368 369 370 371 372
		}
		if (StringUtils.isEmpty(result)) {
			throw new ExceptionChoiceRouteNameError(
					ListTools.extractProperty(list, JpaObject.id_FIELDNAME, String.class, false, false));
		}
		return result;
	}

373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
	private String maxCountOrLatest(List<TaskCompleted> list) {
		Map<String, List<TaskCompleted>> map = list.stream()
				.collect(Collectors.groupingBy(TaskCompleted::getRouteName));
		Optional<Entry<String, List<TaskCompleted>>> optional = map.entrySet().stream().sorted((o1, o2) -> {
			int c = o2.getValue().size() - o1.getValue().size();
			if (c == 0) {
				Date d1 = o1.getValue().stream().sorted(Comparator.comparing(TaskCompleted::getCreateTime).reversed())
						.findFirst().get().getCreateTime();
				Date d2 = o2.getValue().stream().sorted(Comparator.comparing(TaskCompleted::getCreateTime).reversed())
						.findFirst().get().getCreateTime();
				return ObjectUtils.compare(d2, d1);
			} else {
				return c;
			}
		}).findFirst();
		return optional.isPresent() ? optional.get().getKey() : null;
	}

R
roo00 已提交
391
	private boolean single(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
392
		boolean passThrough = false;
R
update  
roo00 已提交
393
		Long count = aeiObjects.getJoinInquireTaskCompleteds().stream().filter(o -> {
R
roo00 已提交
394
			if (StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
395
					&& (identities.contains(o.getIdentity()))) {
R
roo00 已提交
396 397 398 399 400 401
				return true;
			} else {
				return false;
			}
		}).count();
		if (count > 0) {
402
			// 已经确定要通过此节点,清除可能是多余的待办
R
roo00 已提交
403 404 405
			aeiObjects.getTasks().stream().filter(o -> {
				return StringUtils.equals(aeiObjects.getWork().getId(), o.getWork());
			}).forEach(o -> {
Z
zhourui 已提交
406 407 408 409 410
				// 如果启用了将未处理待办转待阅,那么进行转换
				if (BooleanUtils.isTrue(manual.getManualUncompletedTaskToRead())) {
					aeiObjects.getCreateReads()
							.add(new Read(aeiObjects.getWork(), o.getIdentity(), o.getUnit(), o.getPerson()));
				}
R
roo00 已提交
411 412
				aeiObjects.deleteTask(o);
			});
413
			// 所有预计的处理人中已经有已办,这个环节已经产生了已办,可以离开换个环节。
R
roo00 已提交
414 415
			passThrough = true;
		} else {
416
			// 取到期望的待办人员,由于要进行处理需要转换成可读写List
R
roo00 已提交
417
			if (ListTools.isEmpty(identities)) {
R
roo00 已提交
418 419 420
				throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(),
						manual.getName(), manual.getId());
			}
421
			// 删除多余的待办
R
roo00 已提交
422 423
			aeiObjects.getTasks().stream()
					.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
424
							&& (!ListTools.contains(identities, o.getIdentity())))
425 426
					.forEach(aeiObjects::deleteTask);
			// 将待办已经产生的人从预期值中删除
R
roo00 已提交
427 428
			aeiObjects.getTasks().stream()
					.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
429
							&& (ListTools.contains(identities, o.getIdentity())))
430 431
					.forEach(o -> identities.remove(o.getIdentity()));
			// 这里剩余的应该是没有生成待办的人员
R
roo00 已提交
432 433 434
			if (!identities.isEmpty()) {
				for (String identity : identities) {
					aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
435 436 437 438 439 440
				}
			}
		}
		return passThrough;
	}

R
roo00 已提交
441
	private boolean parallel(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
442
		boolean passThrough = false;
443
		// 取得本环节已经处理的已办
R
roo00 已提交
444
		List<TaskCompleted> taskCompleteds = this.listJoinInquireTaskCompleted(aeiObjects, identities);
445
		// 存在优先路由,如果有人选择了优先路由那么直接流转.
R
roo00 已提交
446 447 448 449 450 451 452 453
		Route soleRoute = aeiObjects.getRoutes().stream().filter(r -> BooleanUtils.isTrue(r.getSole())).findFirst()
				.orElse(null);
		if (null != soleRoute) {
			TaskCompleted soleTaskCompleted = taskCompleteds.stream()
					.filter(t -> BooleanUtils.isTrue(t.getJoinInquire())
							&& StringUtils.equals(t.getRouteName(), soleRoute.getName()))
					.findFirst().orElse(null);
			if (null != soleTaskCompleted) {
Z
zhourui 已提交
454
				this.parallelSoleTaskCompleted(aeiObjects);
R
roo00 已提交
455
				return true;
R
roo00 已提交
456 457
			}
		}
458
		// 将已经处理的人从期望值中移除
R
update  
roo00 已提交
459
		aeiObjects.getJoinInquireTaskCompleteds().stream().filter(o -> {
R
roo00 已提交
460
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken());
461 462
		}).forEach(o -> identities.remove(o.getIdentity()));
		// 清空可能的多余的待办
R
roo00 已提交
463 464
		aeiObjects.getTasks().stream().filter(o -> {
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
465
					&& (!ListTools.contains(identities, o.getIdentity()));
466
		}).forEach(aeiObjects::deleteTask);
R
roo00 已提交
467
		if (identities.isEmpty()) {
468
			// 所有人已经处理完成。
R
roo00 已提交
469 470 471
			passThrough = true;
		} else {
			passThrough = false;
472 473 474 475 476
			// 先清空已经有待办的身份
			aeiObjects.getTasks().stream()
					.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken()))
					.forEach(o -> identities.remove(o.getIdentity()));
			// 这里剩余的应该是没有生成待办的人员
R
roo00 已提交
477 478 479
			if (!identities.isEmpty()) {
				for (String identity : identities) {
					aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
480 481 482 483 484 485
				}
			}
		}
		return passThrough;
	}

486
	// 并行环节下如果有优先路由,那么直接走优先路由,处理的时候需要晴空所有代办
Z
zhourui 已提交
487
	private void parallelSoleTaskCompleted(AeiObjects aeiObjects) throws Exception {
488
		// 清空可能的多余的待办
Z
zhourui 已提交
489 490
		aeiObjects.getTasks().stream().filter(o -> {
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken());
491
		}).forEach(aeiObjects::deleteTask);
Z
zhourui 已提交
492 493
	}

R
roo00 已提交
494
	private boolean queue(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
495
		boolean passThrough = false;
R
roo00 已提交
496
		List<TaskCompleted> taskCompleteds = this.listJoinInquireTaskCompleted(aeiObjects, identities);
497
		// 存在优先路由
R
roo00 已提交
498 499 500 501 502 503 504 505 506 507
		Route soleRoute = aeiObjects.getRoutes().stream().filter(r -> BooleanUtils.isTrue(r.getSole())).findFirst()
				.orElse(null);
		if (null != soleRoute) {
			TaskCompleted soleTaskCompleted = taskCompleteds.stream()
					.filter(t -> BooleanUtils.isTrue(t.getJoinInquire())
							&& StringUtils.equals(t.getRouteName(), soleRoute.getName()))
					.findFirst().orElse(null);
			if (null != soleTaskCompleted) {
				return true;
			}
R
roo00 已提交
508
		}
509
		// 存在优先路由结束
R
roo00 已提交
510

511
		// 将已经处理的人从期望值中移除
R
roo00 已提交
512
		for (TaskCompleted o : taskCompleteds) {
R
roo00 已提交
513
			identities.remove(o.getIdentity());
R
roo00 已提交
514
		}
R
roo00 已提交
515
		if (identities.isEmpty()) {
516
			// 所有人已经处理完成。
R
roo00 已提交
517 518 519
			passThrough = true;
		} else {
			passThrough = false;
R
roo00 已提交
520
			String identity = identities.get(0);
521
			// 还有人没有处理,开始判断待办,取到本环节的所有待办,理论上只能有一条待办
R
roo00 已提交
522
			boolean find = false;
R
roo00 已提交
523 524 525 526 527 528 529
			for (Task t : aeiObjects.getTasks()) {
				if (StringUtils.equals(aeiObjects.getWork().getActivityToken(), t.getActivityToken())) {
					if (!StringUtils.equals(t.getIdentity(), identity)) {
						aeiObjects.deleteTask(t);
					} else {
						find = true;
					}
R
roo00 已提交
530 531
				}
			}
532
			// 当前处理人没有待办
R
roo00 已提交
533
			if (!find) {
R
roo00 已提交
534
				aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
535 536 537
			}
		}
		return passThrough;
R
roo00 已提交
538

R
roo00 已提交
539 540
	}

541
	// 所有有效的已办,去除 reset,retract,appendTask
R
roo00 已提交
542
	private List<TaskCompleted> listJoinInquireTaskCompleted(AeiObjects aeiObjects, List<String> identities)
R
roo00 已提交
543
			throws Exception {
544 545 546 547
		return aeiObjects.getJoinInquireTaskCompleteds().stream()
				.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
						&& identities.contains(o.getIdentity()) && BooleanUtils.isTrue(o.getJoinInquire()))
				.collect(Collectors.toList());
R
roo00 已提交
548 549 550 551
	}

	@Override
	protected void inquiringCommitted(AeiObjects aeiObjects, Manual manual) throws Exception {
Z
zhourui 已提交
552
		// nothing
R
roo00 已提交
553 554 555 556 557
	}

	private void calculateExpire(AeiObjects aeiObjects, Manual manual, Task task) throws Exception {
		if (null != manual.getTaskExpireType()) {
			switch (manual.getTaskExpireType()) {
558 559 560 561 562 563 564 565 566 567 568
			case never:
				this.expireNever(task);
				break;
			case appoint:
				this.expireAppoint(manual, task);
				break;
			case script:
				this.expireScript(aeiObjects, manual, task);
				break;
			default:
				break;
R
roo00 已提交
569 570
			}
		}
571
		// 如果work有截至时间
R
roo00 已提交
572 573 574 575 576 577 578 579 580
		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());
				}
			}
		}
581
		// 已经有过期时间了,那么设置催办时间
R
roo00 已提交
582 583 584 585 586 587 588 589 590
		if (null != task.getExpireTime()) {
			task.setUrgeTime(DateUtils.addHours(task.getExpireTime(), -2));
		} else {
			task.setExpired(false);
			task.setUrgeTime(null);
			task.setUrged(false);
		}
	}

591
	// 从不过期
R
roo00 已提交
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
	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 = new WorkTime();
607
		if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) {
R
roo00 已提交
608 609
			m += manual.getTaskExpireDay() * wt.minutesOfWorkDay();
		}
610
		if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) {
R
roo00 已提交
611 612 613 614 615 616 617 618 619 620 621 622
			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) throws Exception {
		Integer m = 0;
Z
zhourui 已提交
623
		if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireDay(), 0))) {
R
roo00 已提交
624 625
			m += manual.getTaskExpireDay() * 60 * 24;
		}
Z
zhourui 已提交
626
		if (BooleanUtils.isTrue(NumberTools.greaterThan(manual.getTaskExpireHour(), 0))) {
R
roo00 已提交
627 628 629 630 631 632 633 634 635 636 637 638
			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 {
R
roo00 已提交
639
		ExpireScriptResult expire = new ExpireScriptResult();
R
roo00 已提交
640 641 642
		ScriptContext scriptContext = aeiObjects.scriptContext();
		Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
		bindings.put(ScriptFactory.BINDING_NAME_TASK, task);
R
roo00 已提交
643
		bindings.put(ScriptFactory.BINDING_NAME_EXPIRE, expire);
644
		// 重新注入对象需要重新运行
R
roo00 已提交
645 646
		ScriptFactory.initialScriptText().eval(scriptContext);
		aeiObjects.business().element()
R
roo00 已提交
647 648
				.getCompiledScript(aeiObjects.getWork().getApplication(), manual, Business.EVENT_MANUALTASKEXPIRE)
				.eval(scriptContext);
649
		if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getWorkHour(), 0))) {
R
roo00 已提交
650 651 652 653 654 655 656 657
			Integer m = 0;
			m += expire.getWorkHour() * 60;
			if (m > 0) {
				WorkTime wt = new WorkTime();
				task.setExpireTime(wt.forwardMinutes(new Date(), m));
			} else {
				task.setExpireTime(null);
			}
658
		} else if (BooleanUtils.isTrue(NumberTools.greaterThan(expire.getHour(), 0))) {
R
roo00 已提交
659 660 661 662 663 664 665 666 667 668 669
			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());
R
roo00 已提交
670 671 672 673 674
		} else {
			task.setExpireTime(null);
		}
	}

R
roo00 已提交
675
	private Task createTask(AeiObjects aeiObjects, Manual manual, String identity) throws Exception {
NoSubject's avatar
NoSubject 已提交
676
		String fromIdentity = aeiObjects.getWork().getProperties().getManualEmpowerMap().get(identity);
R
roo00 已提交
677 678 679 680
		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());
681 682
		// 是第一条待办,进行标记
		task.setFirst(ListTools.isEmpty(aeiObjects.getJoinInquireTaskCompleteds()));
R
roo00 已提交
683
		this.calculateExpire(aeiObjects, manual, task);
R
roo00 已提交
684
		if (StringUtils.isNotEmpty(fromIdentity)) {
R
roo00 已提交
685
			aeiObjects.business().organization().empowerLog()
R
roo00 已提交
686 687 688 689
					.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());
NoSubject's avatar
NoSubject 已提交
690
			empowerTaskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_EMPOWER);
R
roo00 已提交
691 692 693 694 695
			empowerTaskCompleted.setIdentity(fromIdentity);
			empowerTaskCompleted.setUnit(fromUnit);
			empowerTaskCompleted.setPerson(fromPerson);
			empowerTaskCompleted.setEmpowerToIdentity(identity);
			aeiObjects.createTaskCompleted(empowerTaskCompleted);
R
roo00 已提交
696
			Read empowerRead = new Read(aeiObjects.getWork(), fromIdentity, fromUnit, fromPerson);
R
roo00 已提交
697
			aeiObjects.createRead(empowerRead);
R
roo00 已提交
698
		}
R
roo00 已提交
699 700 701
		return task;
	}

R
roo00 已提交
702
	private EmpowerLog createEmpowerLog(Work work, String fromIdentity, String toIdentity) {
703 704 705 706
		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)
R
roo00 已提交
707
				.setActivity(work.getActivity()).setActivityAlias(work.getActivityAlias())
R
roo00 已提交
708
				.setActivityName(work.getActivityName()).setEmpowerTime(new Date());
R
roo00 已提交
709 710
	}

R
update  
roo00 已提交
711 712 713 714 715 716
	private List<String> arriving_sameJobActivityExistIdentities(AeiObjects aeiObjects, Manual manual)
			throws Exception {
		List<String> exists = new ArrayList<>();
		aeiObjects.getTasks().stream().filter(o -> {
			return StringUtils.equals(o.getActivity(), manual.getId())
					&& StringUtils.equals(o.getJob(), aeiObjects.getWork().getJob());
717
		}).forEach(o -> exists.add(o.getIdentity()));
R
update  
roo00 已提交
718
		return exists;
R
roo00 已提交
719 720
	}

R
roo00 已提交
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759
	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);
			}
		}

	}
}