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

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
NoSubject's avatar
NoSubject 已提交
6
import java.util.LinkedHashMap;
R
roo00 已提交
7 8 9 10
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

R
roo00 已提交
11 12 13
import javax.script.Bindings;
import javax.script.ScriptContext;

NoSubject's avatar
NoSubject 已提交
14
import org.apache.commons.collections4.ListUtils;
R
roo00 已提交
15 16 17 18 19 20 21 22 23
import org.apache.commons.lang3.BooleanUtils;
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 已提交
24
import com.x.base.core.project.organization.EmpowerLog;
R
roo00 已提交
25
import com.x.base.core.project.script.ScriptFactory;
R
roo00 已提交
26 27 28 29
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 已提交
30
import com.x.processplatform.core.entity.content.Read;
R
roo00 已提交
31 32 33 34 35 36 37 38
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 已提交
39
import com.x.processplatform.core.entity.element.util.WorkLogTree.Node;
R
roo00 已提交
40
import com.x.processplatform.service.processing.Business;
R
roo00 已提交
41 42
import com.x.processplatform.service.processing.processor.AeiObjects;

43 44 45
/**
 * @author Zhou Rui
 */
R
roo00 已提交
46 47 48 49 50 51 52 53 54 55
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 {
R
roo00 已提交
56
		/* 根据manual计算出来的活动处理人 */
R
roo00 已提交
57
		List<String> identities = calculateTaskIdentities(aeiObjects, manual);
R
update  
roo00 已提交
58
		/* 启用同类工作相同活动节点合并,如果有合并的工作,那么直接返回这个工作. */
59 60 61 62 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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 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
		Work merge = this.arrivingMergeSameJob(aeiObjects, manual, identities);
		if (null != merge) {
			return merge;
		}
		this.arrivingPassSame(aeiObjects, identities);
		// if (BooleanUtils.isTrue(manual.getManualMergeSameJobActivity())) {
		// 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);
		// }
		// aeiObjects.getUpdateWorks().add(other);
		// aeiObjects.getDeleteWorks().add(aeiObjects.getWork());
		// return other;
		// }
		// }
		// }
		// }
		aeiObjects.getWork().setManualTaskIdentityList(new ArrayList<String>(identities));
		// /* 查找是否有passSameTarget设置 */
		// Route passSameTargetRoute = aeiObjects.getRoutes().stream()
		// .filter(o ->
		// BooleanUtils.isTrue(o.getPassSameTarget())).findFirst().orElse(null);
		// /* 如果有passSameTarget,有到达ArriveWorkLog,不是调度到这个节点的 */
		// if ((null != passSameTargetRoute) && ((null !=
		// aeiObjects.getArriveWorkLog(aeiObjects.getWork())))
		// && (!aeiObjects.getProcessingAttributes().ifForceJoinAtArrive())) {
		// logger.debug("pass same target work:{}.", aeiObjects.getWork());
		// WorkLog rollbackWorkLog = findPassSameTargetWorkLog(aeiObjects);
		// logger.debug("pass same target workLog:{}.", rollbackWorkLog);
		// // if (null != rollbackWorkLog) {
		// // final String arriveActivityToken =
		// rollbackWorkLog.getArrivedActivityToken();
		// // aeiObjects.getJoinInquireTaskCompleteds().stream()
		// // .filter(o ->
		// // aeiObjects.getWork().getManualTaskIdentityList().contains(o.getIdentity())
		// // && StringUtils.equals(o.getActivityToken(), arriveActivityToken))
		// // .forEach(o -> {
		// // TaskCompleted obj = new TaskCompleted(aeiObjects.getWork(),
		// // passSameTargetRoute, o);
		// // try {
		// // obj.setProcessingType(TaskCompleted.PROCESSINGTYPE_SAMETARGET);
		// // obj.setRouteName(passSameTargetRoute.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);
		// // } catch (Exception e) {
		// // e.printStackTrace();
		// // }
		// // });
		// // }
		// if (null != rollbackWorkLog) {
		// for (TaskCompleted o : aeiObjects.getJoinInquireTaskCompleteds()) {
		// if (StringUtils.equals(o.getActivityToken(),
		// rollbackWorkLog.getArrivedActivityToken())) {
		// List<String> values =
		// ListUtils.union(aeiObjects.getWork().getManualTaskIdentityList(),
		// aeiObjects.business().organization().identity().listWithPerson(o.getPerson()));
		// if (!values.isEmpty()) {
		// TaskCompleted obj = new TaskCompleted(aeiObjects.getWork(),
		// passSameTargetRoute, o);
		// obj.setIdentity(values.get(0));
		// obj.setProcessingType(TaskCompleted.PROCESSINGTYPE_SAMETARGET);
		// obj.setRouteName(passSameTargetRoute.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);
		// }
		// }
		// }
		// }
		// }
		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 已提交
195
					}
196 197 198
					aeiObjects.getUpdateWorks().add(other);
					aeiObjects.getDeleteWorks().add(aeiObjects.getWork());
					return other;
R
update  
roo00 已提交
199 200 201
				}
			}
		}
202 203
		return null;
	}
R
update  
roo00 已提交
204

205
	private void arrivingPassSame(AeiObjects aeiObjects, List<String> identities) throws Exception {
R
roo00 已提交
206
		/* 查找是否有passSameTarget设置 */
207 208
		Route route = aeiObjects.getRoutes().stream().filter(o -> BooleanUtils.isTrue(o.getPassSameTarget()))
				.findFirst().orElse(null);
R
roo00 已提交
209
		/* 如果有passSameTarget,有到达ArriveWorkLog,不是调度到这个节点的 */
210
		if ((null != route) && ((null != aeiObjects.getArriveWorkLog(aeiObjects.getWork())))
NoSubject's avatar
NoSubject 已提交
211
				&& (!aeiObjects.getProcessingAttributes().ifForceJoinAtArrive())) {
212 213 214 215 216 217 218
			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 已提交
219
					List<String> values = ListUtils.intersection(identities,
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
							aeiObjects.business().organization().identity().listWithPerson(o.getPerson()));
					if (!values.isEmpty()) {
						TaskCompleted obj = new TaskCompleted(aeiObjects.getWork(), route, o);
						obj.setIdentity(values.get(0));
						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 已提交
239 240 241 242
			}
		}
	}

R
roo00 已提交
243 244
	/* 计算处理人 */
	private List<String> calculateTaskIdentities(AeiObjects aeiObjects, Manual manual) throws Exception {
NoSubject's avatar
NoSubject 已提交
245 246 247 248 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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
		TaskIdentities taskIdentities = new TaskIdentities();
		/* 先计算强制处理人 */
		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);
			}
		}
		/* 计算退回的结果 */
		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 已提交
294 295 296
		return taskIdentities.identities();
	}

R
update  
roo00 已提交
297
	/* 如果活动没有找到任何可用的处理人,那么强制设置处理人为文档创建者,或者配置的 maintenanceIdentity */
NoSubject's avatar
NoSubject 已提交
298 299
	private void ifTaskIdentitiesEmptyForceToCreatorOrMaintenance(AeiObjects aeiObjects, Manual manual,
			TaskIdentities taskIdentities) throws Exception {
R
update  
roo00 已提交
300 301 302 303
		if (taskIdentities.isEmpty()) {
			String identity = aeiObjects.business().organization().identity()
					.get(aeiObjects.getWork().getCreatorIdentity());
			if (StringUtils.isNotEmpty(identity)) {
NoSubject's avatar
NoSubject 已提交
304 305
				logger.info("{}[{}]未能找到指定的处理人, 标题:{}, id:{}, 强制指定处理人为活动的创建身份:{}.", aeiObjects.getProcess().getName(),
						manual.getName(), aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(), identity);
R
update  
roo00 已提交
306 307 308 309 310
				taskIdentities.addIdentity(identity);
			} else {
				identity = aeiObjects.business().organization().identity()
						.get(Config.processPlatform().getMaintenanceIdentity());
				if (StringUtils.isNotEmpty(identity)) {
NoSubject's avatar
NoSubject 已提交
311 312 313
					logger.info("{}[{}]未能找到指定的处理人, 也没有能找到工作创建人, 标题:{}, id:{},  强制指定处理人为系统维护身份:{}.",
							aeiObjects.getProcess().getName(), manual.getName(), aeiObjects.getWork().getTitle(),
							aeiObjects.getWork().getId(), identity);
R
update  
roo00 已提交
314 315 316 317 318 319 320 321 322
					taskIdentities.addIdentity(identity);
				} else {
					throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(),
							aeiObjects.getActivity().getName(), aeiObjects.getActivity().getId());
				}
			}
		}
	}

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

R
roo00 已提交
325
	private void writeToEmpowerMap(AeiObjects aeiObjects, TaskIdentities taskIdentities) throws Exception {
NoSubject's avatar
NoSubject 已提交
326 327
		/* 先清空EmpowerMap */
		aeiObjects.getWork().getProperties().setManualEmpowerMap(new LinkedHashMap<String, String>());
R
update  
roo00 已提交
328 329
		if (!(StringUtils.equals(aeiObjects.getWork().getWorkCreateType(), Work.WORKCREATETYPE_SURFACE)
				&& BooleanUtils.isFalse(aeiObjects.getWork().getWorkThroughManual()))) {
NoSubject's avatar
NoSubject 已提交
330 331
			List<String> values = taskIdentities.identities();
			values = ListUtils.subtract(values, aeiObjects.getProcessingAttributes().getIgnoreEmpowerIdentityList());
R
update  
roo00 已提交
332
			taskIdentities.empower(aeiObjects.business().organization().empower().listWithIdentityObject(
Z
Zhou Rui 已提交
333 334
					aeiObjects.getWork().getApplication(), aeiObjects.getProcess().getEdition(),
					aeiObjects.getWork().getProcess(), aeiObjects.getWork().getId(), values));
R
update  
roo00 已提交
335 336
			for (TaskIdentity taskIdentity : taskIdentities) {
				if (StringUtils.isNotEmpty(taskIdentity.getFromIdentity())) {
NoSubject's avatar
NoSubject 已提交
337
					aeiObjects.getWork().getProperties().getManualEmpowerMap().put(taskIdentity.getIdentity(),
R
roo00 已提交
338
							taskIdentity.getFromIdentity());
R
update  
roo00 已提交
339 340 341 342 343
				}
			}
		}
	}

R
roo00 已提交
344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376
	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 {
	}

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

R
roo00 已提交
378 379
		List<String> identities = aeiObjects.business().organization().identity()
				.list(aeiObjects.getWork().getManualTaskIdentityList());
R
roo00 已提交
380
		identities = aeiObjects.business().organization().identity().list(identities);
R
roo00 已提交
381 382
		if (identities.isEmpty()) {
			identities = calculateTaskIdentities(aeiObjects, manual);
R
roo00 已提交
383

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

R
roo00 已提交
390
		switch (manual.getManualMode()) {
391 392 393 394 395 396 397 398 399 400 401 402 403 404
			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 已提交
405
		}
NoSubject's avatar
NoSubject 已提交
406

R
roo00 已提交
407 408 409 410 411 412 413 414
		if (passThrough) {
			results.add(aeiObjects.getWork());
		}
		return results;
	}

	@Override
	protected void executingCommitted(AeiObjects aeiObjects, Manual manual) throws Exception {
R
roo00 已提交
415

R
roo00 已提交
416 417 418 419 420
	}

	@Override
	protected List<Route> inquiring(AeiObjects aeiObjects, Manual manual) throws Exception {
		List<Route> results = new ArrayList<>();
R
fix  
roo00 已提交
421
		/* 仅有单条路由 */
R
roo00 已提交
422 423 424
		if (aeiObjects.getRoutes().size() == 1) {
			results.add(aeiObjects.getRoutes().get(0));
		} else if (aeiObjects.getRoutes().size() > 1) {
R
fix  
roo00 已提交
425
			/* 存在多条路由 */
R
update  
roo00 已提交
426
			List<TaskCompleted> taskCompletedList = aeiObjects.getJoinInquireTaskCompleteds().stream()
R
roo00 已提交
427
					.filter(o -> StringUtils.equals(o.getActivityToken(), aeiObjects.getWork().getActivityToken())
R
update  
roo00 已提交
428
							&& aeiObjects.getWork().getManualTaskIdentityList().contains(o.getIdentity()))
R
roo00 已提交
429
					.collect(Collectors.toList());
R
roo00 已提交
430

R
bug fix  
roo00 已提交
431
			String name = this.choiceRouteName(taskCompletedList, aeiObjects.getRoutes());
R
roo00 已提交
432 433 434 435 436 437 438
			for (Route o : aeiObjects.getRoutes()) {
				if (o.getName().equalsIgnoreCase(name)) {
					results.add(o);
					break;
				}
			}
		}
NoSubject's avatar
NoSubject 已提交
439 440 441 442 443
		if (!results.isEmpty()) {
			/* 清理掉强制的指定的处理人 */
			aeiObjects.getWork().getProperties().setManualForceTaskIdentityList(new ArrayList<String>());
		}

R
roo00 已提交
444 445 446
		return results;
	}

R
bug fix  
roo00 已提交
447 448
	/* 通过已办存根选择某条路由 */
	private String choiceRouteName(List<TaskCompleted> list, List<Route> routes) throws Exception {
R
roo00 已提交
449
		String result = "";
R
roo00 已提交
450
		List<String> names = new ArrayList<>();
R
update  
roo00 已提交
451
		ListTools.trim(list, false, false).stream().forEach(o -> {
R
roo00 已提交
452
			names.add(o.getRouteName());
R
update  
roo00 已提交
453
		});
R
roo00 已提交
454
		/* 进行优先路由的判断 */
455
		Route soleRoute = routes.stream().filter(o -> BooleanUtils.isTrue(o.getSole())).findFirst().orElse(null);
R
roo00 已提交
456
		if ((null != soleRoute) && names.contains(soleRoute.getName())) {
R
bug fix  
roo00 已提交
457 458 459
			result = soleRoute.getName();
		} else {
			/* 进行默认的策略,选择占比多的 */
R
roo00 已提交
460
			result = ListTools.maxCountElement(names);
R
roo00 已提交
461 462 463 464 465 466 467 468
		}
		if (StringUtils.isEmpty(result)) {
			throw new ExceptionChoiceRouteNameError(
					ListTools.extractProperty(list, JpaObject.id_FIELDNAME, String.class, false, false));
		}
		return result;
	}

R
roo00 已提交
469
	private boolean single(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
470
		boolean passThrough = false;
R
update  
roo00 已提交
471
		Long count = aeiObjects.getJoinInquireTaskCompleteds().stream().filter(o -> {
R
roo00 已提交
472
			if (StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
473
					&& (identities.contains(o.getIdentity()))) {
R
roo00 已提交
474 475 476 477 478 479 480 481 482 483 484 485
				return true;
			} else {
				return false;
			}
		}).count();
		if (count > 0) {
			/* 已经确定要通过此节点,清除可能是多余的待办 */
			aeiObjects.getTasks().stream().filter(o -> {
				return StringUtils.equals(aeiObjects.getWork().getId(), o.getWork());
			}).forEach(o -> {
				aeiObjects.deleteTask(o);
			});
R
roo00 已提交
486
			/* 所有预计的处理人中已经有已办,这个环节已经产生了已办,可以离开换个环节。 */
R
roo00 已提交
487 488 489
			passThrough = true;
		} else {
			/* 取到期望的待办人员,由于要进行处理需要转换成可读写List */
R
roo00 已提交
490
			if (ListTools.isEmpty(identities)) {
R
roo00 已提交
491 492 493 494 495 496
				throw new ExceptionExpectedEmpty(aeiObjects.getWork().getTitle(), aeiObjects.getWork().getId(),
						manual.getName(), manual.getId());
			}
			/* 删除多余的待办 */
			aeiObjects.getTasks().stream()
					.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
497
							&& (!ListTools.contains(identities, o.getIdentity())))
R
roo00 已提交
498 499 500 501 502 503
					.forEach(o -> {
						aeiObjects.deleteTask(o);
					});
			/* 将待办已经产生的人从预期值中删除 */
			aeiObjects.getTasks().stream()
					.filter(o -> StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
504
							&& (ListTools.contains(identities, o.getIdentity())))
R
roo00 已提交
505
					.forEach(o -> {
R
roo00 已提交
506
						identities.remove(o.getIdentity());
R
roo00 已提交
507 508
					});
			/* 这里剩余的应该是没有生成待办的人员 */
R
roo00 已提交
509 510 511
			if (!identities.isEmpty()) {
				for (String identity : identities) {
					aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
512 513 514 515 516 517
				}
			}
		}
		return passThrough;
	}

R
roo00 已提交
518
	private boolean parallel(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
519
		boolean passThrough = false;
R
update  
roo00 已提交
520
		/* 取得本环节已经处理的已办 */
R
roo00 已提交
521
		List<TaskCompleted> taskCompleteds = this.listJoinInquireTaskCompleted(aeiObjects, identities);
NoSubject's avatar
NoSubject 已提交
522
		/* 存在优先路由,如果有人选择了优先路由那么直接流转. */
R
roo00 已提交
523 524 525 526 527 528 529 530 531
		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 已提交
532 533 534
			}
		}
		/* 将已经处理的人从期望值中移除 */
R
update  
roo00 已提交
535
		aeiObjects.getJoinInquireTaskCompleteds().stream().filter(o -> {
R
roo00 已提交
536 537
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken());
		}).forEach(o -> {
R
roo00 已提交
538
			identities.remove(o.getIdentity());
R
roo00 已提交
539 540 541 542
		});
		/* 清空可能的多余的待办 */
		aeiObjects.getTasks().stream().filter(o -> {
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
R
roo00 已提交
543
					&& (!ListTools.contains(identities, o.getIdentity()));
R
roo00 已提交
544 545 546
		}).forEach(o -> {
			aeiObjects.deleteTask(o);
		});
R
roo00 已提交
547
		if (identities.isEmpty()) {
R
roo00 已提交
548 549 550 551 552 553 554 555
			/* 所有人已经处理完成。 */
			passThrough = true;
		} else {
			passThrough = false;
			/* 先清空已经有待办的身份 */
			aeiObjects.getTasks().stream().filter(o -> {
				return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken());
			}).forEach(o -> {
R
roo00 已提交
556
				identities.remove(o.getIdentity());
R
roo00 已提交
557 558
			});
			/* 这里剩余的应该是没有生成待办的人员 */
R
roo00 已提交
559 560 561
			if (!identities.isEmpty()) {
				for (String identity : identities) {
					aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
562 563 564 565 566 567
				}
			}
		}
		return passThrough;
	}

R
roo00 已提交
568
	private boolean queue(AeiObjects aeiObjects, Manual manual, List<String> identities) throws Exception {
R
roo00 已提交
569
		boolean passThrough = false;
R
roo00 已提交
570 571 572 573 574 575 576 577 578 579 580 581
		List<TaskCompleted> taskCompleteds = this.listJoinInquireTaskCompleted(aeiObjects, identities);
		/* 存在优先路由 */
		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 已提交
582
		}
R
roo00 已提交
583 584
		/* 存在优先路由结束 */

R
update  
roo00 已提交
585
		/* 将已经处理的人从期望值中移除 */
R
roo00 已提交
586
		for (TaskCompleted o : taskCompleteds) {
R
roo00 已提交
587
			identities.remove(o.getIdentity());
R
roo00 已提交
588
		}
R
roo00 已提交
589
		if (identities.isEmpty()) {
R
update  
roo00 已提交
590
			/* 所有人已经处理完成。 */
R
roo00 已提交
591 592 593
			passThrough = true;
		} else {
			passThrough = false;
R
roo00 已提交
594
			String identity = identities.get(0);
R
update  
roo00 已提交
595
			/* 还有人没有处理,开始判断待办,取到本环节的所有待办,理论上只能有一条待办 */
R
roo00 已提交
596
			boolean find = false;
R
roo00 已提交
597 598 599 600 601 602 603
			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 已提交
604 605
				}
			}
R
update  
roo00 已提交
606
			/* 当前处理人没有待办 */
R
roo00 已提交
607
			if (!find) {
R
roo00 已提交
608
				aeiObjects.createTask(this.createTask(aeiObjects, manual, identity));
R
roo00 已提交
609 610 611
			}
		}
		return passThrough;
R
roo00 已提交
612

R
roo00 已提交
613 614
	}

R
update  
roo00 已提交
615
	/* 所有有效的已办,去除 reset,retract,appendTask */
R
roo00 已提交
616
	private List<TaskCompleted> listJoinInquireTaskCompleted(AeiObjects aeiObjects, List<String> identities)
R
roo00 已提交
617
			throws Exception {
R
update  
roo00 已提交
618
		return aeiObjects.getJoinInquireTaskCompleteds().stream().filter(o -> {
R
roo00 已提交
619
			return StringUtils.equals(aeiObjects.getWork().getActivityToken(), o.getActivityToken())
NoSubject's avatar
NoSubject 已提交
620
					&& identities.contains(o.getIdentity()) && BooleanUtils.isTrue(o.getJoinInquire());
R
roo00 已提交
621
		}).collect(Collectors.toList());
R
roo00 已提交
622 623 624 625 626 627 628 629 630
	}

	@Override
	protected void inquiringCommitted(AeiObjects aeiObjects, Manual manual) throws Exception {
	}

	private void calculateExpire(AeiObjects aeiObjects, Manual manual, Task task) throws Exception {
		if (null != manual.getTaskExpireType()) {
			switch (manual.getTaskExpireType()) {
631 632 633 634 635 636 637 638 639 640 641
				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 已提交
642 643
			}
		}
R
update  
roo00 已提交
644
		/* 如果work有截至时间 */
R
roo00 已提交
645 646 647 648 649 650 651 652 653
		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());
				}
			}
		}
R
update  
roo00 已提交
654
		/* 已经有过期时间了,那么设置催办时间 */
R
roo00 已提交
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
		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 = new WorkTime();
		if (NumberTools.greaterThan(manual.getTaskExpireDay(), 0)) {
			m += manual.getTaskExpireDay() * wt.minutesOfWorkDay();
		}
		if (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) throws Exception {
		Integer m = 0;
		if (NumberTools.greaterThan(manual.getTaskExpireDay(), 0)) {
			m += manual.getTaskExpireDay() * 60 * 24;
		}
		if (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);
		}
	}

713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
	// private void expireScript(AeiObjects aeiObjects, Manual manual, Task task)
	// throws Exception {
	// ScriptContext scriptContext = aeiObjects.scriptContext();
	// Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
	// bindings.put(ScriptFactory.BINDING_NAME_TASK, task);
	// Object objectValue = aeiObjects.business().element()
	// .getCompiledScript(aeiObjects.getWork().getApplication(), manual,
	// Business.EVENT_MANUALTASKEXPIRE)
	// .eval(scriptContext);
	// WorkTime wt = new WorkTime();
	// if (NumberUtils.isCreatable(objectValue.toString())) {
	// task.setExpireTime(wt.forwardMinutes(new Date(),
	// NumberUtils.toInt(ScriptFactory.asString(objectValue))));
	// } else {
	// task.setExpireTime(null);
	// }
	//
	// }
R
roo00 已提交
731

R
roo00 已提交
732
	private void expireScript(AeiObjects aeiObjects, Manual manual, Task task) throws Exception {
R
roo00 已提交
733
		ExpireScriptResult expire = new ExpireScriptResult();
R
roo00 已提交
734 735 736
		ScriptContext scriptContext = aeiObjects.scriptContext();
		Bindings bindings = scriptContext.getBindings(ScriptContext.ENGINE_SCOPE);
		bindings.put(ScriptFactory.BINDING_NAME_TASK, task);
R
roo00 已提交
737 738 739 740
		bindings.put(ScriptFactory.BINDING_NAME_EXPIRE, expire);
		/* 重新注入对象需要重新运行 */
		ScriptFactory.initialScriptText().eval(scriptContext);
		aeiObjects.business().element()
R
roo00 已提交
741 742
				.getCompiledScript(aeiObjects.getWork().getApplication(), manual, Business.EVENT_MANUALTASKEXPIRE)
				.eval(scriptContext);
R
roo00 已提交
743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
		if (NumberTools.greaterThan(expire.getWorkHour(), 0)) {
			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);
			}
		} else if (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());
R
roo00 已提交
764 765 766 767 768
		} else {
			task.setExpireTime(null);
		}
	}

R
roo00 已提交
769
	private Task createTask(AeiObjects aeiObjects, Manual manual, String identity) throws Exception {
NoSubject's avatar
NoSubject 已提交
770
		String fromIdentity = aeiObjects.getWork().getProperties().getManualEmpowerMap().get(identity);
R
roo00 已提交
771 772 773 774
		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());
R
roo00 已提交
775
		/* 是第一条待办,进行标记 */
R
update  
roo00 已提交
776
		if (ListTools.isEmpty(aeiObjects.getJoinInquireTaskCompleteds())) {
R
roo00 已提交
777 778 779 780
			task.setFirst(true);
		} else {
			task.setFirst(false);
		}
R
roo00 已提交
781
		this.calculateExpire(aeiObjects, manual, task);
R
roo00 已提交
782
		if (StringUtils.isNotEmpty(fromIdentity)) {
R
roo00 已提交
783
			aeiObjects.business().organization().empowerLog()
R
roo00 已提交
784 785 786 787
					.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 已提交
788
			empowerTaskCompleted.setProcessingType(TaskCompleted.PROCESSINGTYPE_EMPOWER);
R
roo00 已提交
789 790 791 792 793
			empowerTaskCompleted.setIdentity(fromIdentity);
			empowerTaskCompleted.setUnit(fromUnit);
			empowerTaskCompleted.setPerson(fromPerson);
			empowerTaskCompleted.setEmpowerToIdentity(identity);
			aeiObjects.createTaskCompleted(empowerTaskCompleted);
R
roo00 已提交
794
			Read empowerRead = new Read(aeiObjects.getWork(), fromIdentity, fromUnit, fromPerson);
R
roo00 已提交
795
			aeiObjects.createRead(empowerRead);
R
roo00 已提交
796
		}
R
roo00 已提交
797 798 799
		return task;
	}

R
roo00 已提交
800
	private EmpowerLog createEmpowerLog(Work work, String fromIdentity, String toIdentity) {
R
roo00 已提交
801
		EmpowerLog empowerLog = new EmpowerLog().setApplication(work.getApplication())
R
roo00 已提交
802 803 804
				.setApplicationAlias(work.getApplicationAlias()).setApplicationName(work.getApplicationName())
				.setProcess(work.getProcess()).setProcessAlias(work.getProcessAlias())
				.setProcessName(work.getProcessName()).setTitle(work.getTitle()).setWork(work.getId())
R
roo00 已提交
805 806
				.setJob(work.getJob()).setFromIdentity(fromIdentity).setToIdentity(toIdentity)
				.setActivity(work.getActivity()).setActivityAlias(work.getActivityAlias())
R
roo00 已提交
807
				.setActivityName(work.getActivityName()).setEmpowerTime(new Date());
R
roo00 已提交
808
		return empowerLog;
R
roo00 已提交
809 810
	}

R
update  
roo00 已提交
811 812 813 814 815 816 817 818 819 820
	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());
		}).forEach(o -> {
			exists.add(o.getIdentity());
		});
		return exists;
R
roo00 已提交
821 822
	}

R
roo00 已提交
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
	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);
			}
		}

	}
}