package com.jspxcms.core.service.impl;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.jspxcms.common.orm.Limitable;
import com.jspxcms.common.orm.SearchFilter;
import com.jspxcms.common.util.RowSide;
import com.jspxcms.core.domain.Site;
import com.jspxcms.core.domain.User;
import com.jspxcms.core.domain.Workflow;
import com.jspxcms.core.domain.WorkflowGroup;
import com.jspxcms.core.domain.WorkflowProcess;
import com.jspxcms.core.domain.WorkflowStep;
import com.jspxcms.core.listener.SiteDeleteListener;
import com.jspxcms.core.listener.WorkflowDeleteListener;
import com.jspxcms.core.listener.WorkflowGroupDeleteListener;
import com.jspxcms.core.repository.WorkflowDao;
import com.jspxcms.core.service.SiteService;
import com.jspxcms.core.service.WorkflowGroupService;
import com.jspxcms.core.service.WorkflowProcessService;
import com.jspxcms.core.service.WorkflowProcessUserService;
import com.jspxcms.core.service.WorkflowService;
import com.jspxcms.core.service.WorkflowStepService;
import com.jspxcms.core.support.DeleteException;
/**
* WorkflowServiceImpl
*
* @author liufang
*
*/
@Service
@Transactional(readOnly = true)
public class WorkflowServiceImpl implements WorkflowService,
WorkflowGroupDeleteListener, SiteDeleteListener {
public List<Workflow> findList(Map<String, String[]> params, Sort sort) {
return dao.findAll(spec(params), sort);
}
public RowSide<Workflow> findSide(Map<String, String[]> params,
Workflow bean, Integer position, Sort sort) {
if (position == null) {
return new RowSide<Workflow>();
}
Limitable limit = RowSide.limitable(position, sort);
List<Workflow> list = dao.findAll(spec(params), limit);
return RowSide.create(list, bean);
}
private Specification<Workflow> spec(Map<String, String[]> params) {
Collection<SearchFilter> filters = SearchFilter.parse(params).values();
Specification<Workflow> sp = SearchFilter.spec(filters, Workflow.class);
return sp;
}
public List<Workflow> findList(Integer siteId) {
Sort sort = new Sort("group.seq", "group.id", "seq", "id");
return dao.findBySiteId(siteId, sort);
}
public Workflow get(Integer id) {
return dao.findOne(id);
}
/**
* 新发表、审核。 无工作流或无步骤,结束。 判断操作人在步骤位置。 新流程(无流程、无步骤)
*
* @param workflow
* @param operator
* @param type
* @param dataId
* @return -1:终审通过;0:无审核权限;其他代表审核步骤
*/
@Transactional
public int auditPass(Workflow workflow, User owner, User operator,
Integer type, Integer dataId, String opinion) {
WorkflowProcess process = processService.findOne(type, dataId);
if (workflow == null) {
// 没有工作流,但有流程代表:原有流程,现在没有。审核通过。
if (process != null) {
// TODO 写流程日志
process.passEnd();
}
return -1;
}
// 流程存在,且为结束,使用原流程工作流
if (process != null && !process.getEnd()) {
workflow = process.getWorkflow();
}
List<WorkflowStep> steps = workflow.getSteps();
int size = steps.size();
if (size <= 0) {
// 无审核流程,审核通过。
if (process != null) {
// TODO 写流程日志
process.passEnd();
}
return -1;
}
// 提交人在工作流中的最后步骤
int step;
for (step = size; step > 0; step--) {
WorkflowStep workflowStep = steps.get(step - 1);
if (CollectionUtils.containsAny(workflowStep.getRoles(),
operator.getRoles())) {
break;
}
}
// step==0代表没有在工作流中。
// 不在工作流中,可以提交新流程,但不能审核已终审流程。
// 在工作流中,可以审核流程,但不能审核超过自己步骤的流程。
// 流程存在&&未结束&&操作者步骤小于流程步骤,则不能操作
// 已终审,则不能操作(本条由调用方控制)
if (process != null && !process.getEnd() && step < process.getStep()) {
return 0;
}
// TODO 写审核log
int nextStep;
Set<User> users;
Date endDate;
Boolean isEnd;
if (step == size) {
// 终审人员,审核结束。
users = null;
nextStep = -1;
endDate = new Timestamp(System.currentTimeMillis());
isEnd = true;
} else {
// 获得下一步审核人员
users = steps.get(step).getUsers();
// -1代表不是审核人员,则应为1,所以加2。
nextStep = step + 1;
endDate = null;
isEnd = false;
}
Boolean isRejection = false;
if (process != null) {
process.setWorkflow(workflow);
process.setStep(nextStep);
process.setEndDate(endDate);
process.setRejection(isRejection);
process.setEnd(isEnd);
processUserService.update(process, users);
} else {
Site site = workflow.getSite();
processService.save(site, workflow, owner, users, dataId, nextStep,
type, isRejection, isEnd);
}
return nextStep;
}
/**
*
* @param workflow
* @param operator
* @param type
* @param dataId
* @param opinion
* @return -1:退稿;
*/
// TODO 退到哪一步?直接退稿。
public int auditReject(Workflow workflow, User owner, User operator,
Integer type, Integer dataId, String opinion) {
WorkflowProcess process = processService.findOne(type, dataId);
if (workflow == null) {
// 没有工作流,退稿。
if (process != null) {
// TODO 写流程日志
process.rejectEnd();
}
return -1;
}
// 流程存在,且为结束,使用原流程工作流
if (process != null && !process.getEnd()) {
workflow = process.getWorkflow();
}
List<WorkflowStep> steps = workflow.getSteps();
int size = steps.size();
if (size <= 0) {
// 无审核流程,退稿。
if (process != null) {
// TODO 写流程日志
process.rejectEnd();
}
return -1;
}
// 提交人在工作流中的步骤
int step;
for (step = 0; step < size; step++) {
WorkflowStep workfolwStep = steps.get(step);
if (CollectionUtils.containsAny(workfolwStep.getRoles(),
operator.getRoles())) {
break;
}
}
if (step == size) {
// 不在审核流程中
step = 0;
} else {
// 在审核流程中的步骤
step++;
}
// step==0代表没有在工作流程中
// 小于流程步骤不能退;已终审的,非终审人员不能退。
// 已退回,不能再操作(由调用方控制)。
// 流程存在&&未结束&&非当前步骤人员(直接退稿且大于等于当前步骤除外),不做任何处理。
// (流程不存在||(流程存在&&已结束))&&非终审人员,不能操作。
if (process != null && !process.getEnd()) {
if (step != process.getStep()) {
return 0;
}
} else if ((process == null || process.getEnd()) && step != size) {
return 0;
}
// TODO 写审核log
// 已经退回到发稿人
boolean ownerRejection = false;
if (step > 1) {
for (int i = step - 2; i < size; i++) {
WorkflowStep workfolwStep = steps.get(i);
if (workfolwStep.getUsers().contains(owner)) {
ownerRejection = true;
break;
}
}
}
int nextStep;
Set<User> users;
Date endDate;
Boolean isEnd;
if (step == 1 || ownerRejection) {
// 第一个审核人员,退稿。
users = null;
nextStep = -1;
endDate = new Timestamp(System.currentTimeMillis());
isEnd = true;
} else {
// 获得上一步审核人员。下标从0开始,需-1,上一步审核人员再-1,共-2。
users = steps.get(step - 2).getUsers();
nextStep = step - 1;
endDate = null;
isEnd = false;
}
Boolean isRejection = true;
if (process != null) {
process.setWorkflow(workflow);
process.setStep(nextStep);
process.setEndDate(endDate);
process.setEnd(isEnd);
process.setRejection(isRejection);
processUserService.update(process, users);
} else {
Site site = workflow.getSite();
processService.save(site, workflow, owner, users, dataId, nextStep,
type, isRejection, isEnd);
}
return nextStep;
}
@Transactional
public Workflow save(Workflow bean, Integer groupId, String[] stepName,
Integer[] stepRoleId, Integer siteId) {
Site site = siteService.get(siteId);
bean.setSite(site);
WorkflowGroup group = groupService.get(groupId);
bean.setGroup(group);
bean.applyDefaultValue();
bean = dao.save(bean);
stepService.save(stepName, stepRoleId, bean);
return bean;
}
@Transactional
public Workflow update(Workflow bean, Integer groupId, String[] stepName,
Integer[] stepRoleId) {
WorkflowGroup group = groupService.get(groupId);
bean.setGroup(group);
List<WorkflowStep> steps = bean.getSteps();
stepService.delete(steps);
bean.getSteps().clear();
stepService.save(stepName, stepRoleId, bean);
bean.applyDefaultValue();
bean = dao.save(bean);
return bean;
}
private Workflow doDelete(Integer id) {
Workflow entity = dao.findOne(id);
if (entity != null) {
dao.delete(entity);
}
return entity;
}
@Transactional
public Workflow delete(Integer id) {
firePreDelete(new Integer[] { id });
return doDelete(id);
}
@Transactional
public Workflow[] delete(Integer[] ids) {
firePreDelete(ids);
Workflow[] beans = new Workflow[ids.length];
for (int i = 0; i < ids.length; i++) {
beans[i] = doDelete(ids[i]);
}
return beans;
}
public void preSiteDelete(Integer[] ids) {
if (ArrayUtils.isNotEmpty(ids)) {
if (dao.countBySiteId(Arrays.asList(ids)) > 0) {
throw new DeleteException("workflow.management");
}
}
}
public void preWorkflowGroupDelete(Integer[] ids) {
if (ArrayUtils.isNotEmpty(ids)) {
if (dao.countByGroupId(Arrays.asList(ids)) > 0) {
throw new DeleteException("workflow.management");
}
}
}
private void firePreDelete(Integer[] ids) {
if (!CollectionUtils.isEmpty(deleteListeners)) {
for (WorkflowDeleteListener listener : deleteListeners) {
listener.preWorkflowDelete(ids);
}
}
}
private List<WorkflowDeleteListener> deleteListeners;
@Autowired(required = false)
public void setDeleteListeners(List<WorkflowDeleteListener> deleteListeners) {
this.deleteListeners = deleteListeners;
}
private WorkflowProcessUserService processUserService;
private WorkflowProcessService processService;
private WorkflowStepService stepService;
private WorkflowGroupService groupService;
private SiteService siteService;
@Autowired
public void setProcessUserService(
WorkflowProcessUserService processUserService) {
this.processUserService = processUserService;
}
@Autowired
public void setProcessService(WorkflowProcessService processService) {
this.processService = processService;
}
@Autowired
public void setStepService(WorkflowStepService stepService) {
this.stepService = stepService;
}
@Autowired
public void setGroupService(WorkflowGroupService groupService) {
this.groupService = groupService;
}
@Autowired
public void setSiteService(SiteService siteService) {
this.siteService = siteService;
}
private WorkflowDao dao;
@Autowired
public void setDao(WorkflowDao dao) {
this.dao = dao;
}
}