001/*
002 *    Copyright 2024-2025, Warm-Flow (290631660@qq.com).
003 *
004 *    Licensed under the Apache License, Version 2.0 (the "License");
005 *    you may not use this file except in compliance with the License.
006 *    You may obtain a copy of the License at
007 *
008 *       https://www.apache.org/licenses/LICENSE-2.0
009 *
010 *    Unless required by applicable law or agreed to in writing, software
011 *    distributed under the License is distributed on an "AS IS" BASIS,
012 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *    See the License for the specific language governing permissions and
014 *    limitations under the License.
015 */
016package org.dromara.warm.flow.core.service.impl;
017
018import org.dromara.warm.flow.core.FlowFactory;
019import org.dromara.warm.flow.core.constant.ExceptionCons;
020import org.dromara.warm.flow.core.dao.FlowInstanceDao;
021import org.dromara.warm.flow.core.dto.FlowParams;
022import org.dromara.warm.flow.core.entity.*;
023import org.dromara.warm.flow.core.enums.ActivityStatus;
024import org.dromara.warm.flow.core.enums.FlowStatus;
025import org.dromara.warm.flow.core.enums.NodeType;
026import org.dromara.warm.flow.core.listener.Listener;
027import org.dromara.warm.flow.core.listener.ListenerVariable;
028import org.dromara.warm.flow.core.orm.service.impl.WarmServiceImpl;
029import org.dromara.warm.flow.core.service.InsService;
030import org.dromara.warm.flow.core.utils.*;
031
032import java.util.ArrayList;
033import java.util.Date;
034import java.util.List;
035import java.util.stream.Collectors;
036
037/**
038 * 流程实例Service业务层处理
039 *
040 * @author warm
041 * @since 2023-03-29
042 */
043public class InsServiceImpl extends WarmServiceImpl<FlowInstanceDao<Instance>, Instance> implements InsService {
044
045    @Override
046    public InsService setDao(FlowInstanceDao<Instance> warmDao) {
047        this.warmDao = warmDao;
048        return this;
049    }
050
051    @Override
052    public Instance start(String businessId, FlowParams flowParams) {
053        AssertUtil.isNull(flowParams.getFlowCode(), ExceptionCons.NULL_FLOW_CODE);
054        AssertUtil.isEmpty(businessId, ExceptionCons.NULL_BUSINESS_ID);
055        // 获取已发布的流程节点
056        List<Node> nodes = FlowFactory.nodeService().getByFlowCode(flowParams.getFlowCode());
057        AssertUtil.isEmpty(nodes, String.format(ExceptionCons.NOT_PUBLISH_NODE, flowParams.getFlowCode()));
058        // 获取开始节点
059        Node startNode = nodes.stream().filter(t -> NodeType.isStart(t.getNodeType())).findFirst().orElse(null);
060        AssertUtil.isNull(startNode, ExceptionCons.LOST_START_NODE);
061        // 获取下一个节点,如果是网关节点,则重新获取后续节点
062        List<Node> nextNodes = FlowFactory.nodeService().getNextByCheckGateway(flowParams.getVariable()
063                , getFirstBetween(startNode));
064
065        // 判断流程定义是否激活状态
066        Definition definition = FlowFactory.defService().getById(nextNodes.get(0).getDefinitionId());
067        AssertUtil.isTrue(definition.getActivityStatus().equals(ActivityStatus.SUSPENDED.getKey())
068                , ExceptionCons.NOT_DEFINITION_ACTIVITY);
069
070        // 执行开始监听器
071        ListenerUtil.executeListener(new ListenerVariable(definition, null, startNode, flowParams.getVariable())
072                .setFlowParams(flowParams), Listener.LISTENER_START);
073
074        // 设置流程实例对象
075        Instance instance = setStartInstance(nextNodes.get(0), businessId, flowParams);
076
077        // 判断开始结点和下一结点是否有权限监听器,有执行权限监听器node.setPermissionFlag,无走数据库的权限标识符
078        ListenerUtil.executeGetNodePermission(new ListenerVariable(definition, instance, startNode, flowParams.getVariable()
079                , null, nextNodes).setFlowParams(flowParams));
080
081        // 设置历史任务
082        List<HisTask> hisTasks = setHisTask(nextNodes, flowParams, startNode, instance.getId());
083
084        List<Task> addTasks = StreamUtils.toList(nextNodes, node -> FlowFactory.taskService()
085                .addTask(node, instance, definition, flowParams));
086
087        // 办理人变量替换
088        if (CollUtil.isNotEmpty(addTasks)) {
089            addTasks.forEach(addTask -> addTask.getPermissionList().replaceAll(s -> VariableUtil.eval(s, flowParams.getVariable())));
090        }
091
092        // 执行分派监听器
093        ListenerUtil.executeListener(new ListenerVariable(definition, instance, startNode, flowParams.getVariable()
094                , null, nextNodes, addTasks).setFlowParams(flowParams), Listener.LISTENER_ASSIGNMENT);
095
096
097        // 开启流程,保存流程信息
098        saveFlowInfo(instance, addTasks, hisTasks);
099
100        // 执行结束监听器和下一节点的节点开始监听器
101        ListenerUtil.endCreateListener(new ListenerVariable(definition, instance, startNode, flowParams.getVariable()
102                , null, nextNodes, addTasks).setFlowParams(flowParams));
103
104        return instance;
105    }
106
107    @Override
108    public Instance skipByInsId(Long instanceId, FlowParams flowParams) {
109        AssertUtil.isTrue(StringUtils.isNotEmpty(flowParams.getMessage())
110                && flowParams.getMessage().length() > 500, ExceptionCons.MSG_OVER_LENGTH);
111        // 获取待办任务
112        List<Task> taskList = FlowFactory.taskService().list(FlowFactory.newTask().setInstanceId(instanceId));
113        AssertUtil.isEmpty(taskList, ExceptionCons.NOT_FOUNT_TASK);
114        AssertUtil.isTrue(taskList.size() > 1, ExceptionCons.TASK_NOT_ONE);
115        Task task = taskList.get(0);
116        return FlowFactory.taskService().skip(flowParams, task);
117    }
118
119    @Override
120    public Instance termination(Long instanceId, FlowParams flowParams) {
121        // 获取待办任务
122        List<Task> taskList = FlowFactory.taskService().list(FlowFactory.newTask().setInstanceId(instanceId));
123        AssertUtil.isEmpty(taskList, ExceptionCons.NOT_FOUNT_TASK);
124        Task task = taskList.get(0);
125        return FlowFactory.taskService().termination(task, flowParams);
126    }
127
128    @Override
129    public boolean remove(List<Long> instanceIds) {
130        return toRemoveTask(instanceIds);
131    }
132
133
134    /**
135     * 设置历史任务
136     *
137     * @param nextNodes 下一节点集合
138     * @param flowParams 流程参数
139     * @param startNode 开始节点
140     * @param instanceId 流程实例id
141     */
142    private List<HisTask> setHisTask(List<Node> nextNodes, FlowParams flowParams, Node startNode, Long instanceId) {
143        Task startTask = FlowFactory.newTask()
144                .setInstanceId(instanceId)
145                .setDefinitionId(startNode.getDefinitionId())
146                .setNodeCode(startNode.getNodeCode())
147                .setNodeName(startNode.getNodeName())
148                .setNodeType(startNode.getNodeType());
149        FlowFactory.dataFillHandler().idFill(startTask);
150        // 开始任务转历史任务
151        return FlowFactory.hisTaskService().setSkipInsHis(startTask, nextNodes, flowParams);
152    }
153
154    /**
155     * 开启流程,保存流程信息
156     *
157     * @param instance 流程实例
158     * @param addTasks 新增任务
159     * @param hisTasks 历史任务
160     */
161    private void saveFlowInfo(Instance instance, List<Task> addTasks, List<HisTask> hisTasks) {
162        // 待办任务设置处理人
163        List<User> users = FlowFactory.userService().taskAddUsers(addTasks);
164        FlowFactory.hisTaskService().saveBatch(hisTasks);
165        FlowFactory.taskService().saveBatch(addTasks);
166        FlowFactory.userService().saveBatch(users);
167        save(instance);
168    }
169
170    /**
171     * 设置流程实例对象
172     *
173     * @param firstBetweenNode 第一个中间节点
174     * @param businessId 业务id
175     * @return Instance
176     */
177    private Instance setStartInstance(Node firstBetweenNode, String businessId
178            , FlowParams flowParams) {
179        Instance instance = FlowFactory.newIns();
180        Date now = new Date();
181        FlowFactory.dataFillHandler().idFill(instance);
182        // 关联业务id,起始后面可以不用到业务id,传业务id目前来看只是为了批量创建流程的时候能创建出有区别化的流程,也是为了后期需要用到businessId。
183        instance.setDefinitionId(firstBetweenNode.getDefinitionId())
184                .setBusinessId(businessId)
185                .setNodeType(firstBetweenNode.getNodeType())
186                .setNodeCode(firstBetweenNode.getNodeCode())
187                .setNodeName(firstBetweenNode.getNodeName())
188                .setFlowStatus(ObjectUtil.isNotNull(flowParams.getFlowStatus())? flowParams.getFlowStatus()
189                        : FlowStatus.TOBESUBMIT.getKey())
190                .setActivityStatus(ActivityStatus.ACTIVITY.getKey())
191                .setVariable(FlowFactory.jsonConvert.mapToStr(flowParams.getVariable()))
192                .setCreateTime(now)
193                .setUpdateTime(now)
194                .setCreateBy(flowParams.getHandler())
195                .setExt(flowParams.getExt());
196        return instance;
197    }
198
199    /**
200     * 有且只能有一个开始节点
201     *
202     * @param startNode 开始节点
203     * @return Node
204     */
205    private Node getFirstBetween(Node startNode) {
206        List<Skip> skips = FlowFactory.skipService().list(FlowFactory.newSkip()
207                .setDefinitionId(startNode.getDefinitionId()).setNowNodeCode(startNode.getNodeCode()));
208        Skip skip = skips.get(0);
209        return FlowFactory.nodeService().getOne(FlowFactory.newNode().setDefinitionId(startNode.getDefinitionId())
210                .setNodeCode(skip.getNextNodeCode()));
211    }
212
213    private boolean toRemoveTask(List<Long> instanceIds) {
214        AssertUtil.isEmpty(instanceIds, ExceptionCons.NULL_INSTANCE_ID);
215
216        List<Long> taskIds = new ArrayList<>();
217        instanceIds.forEach(instanceId -> taskIds.addAll(
218                FlowFactory.taskService()
219                        .list(FlowFactory.newTask().setInstanceId(instanceId))
220                        .stream()
221                        .map(Task::getId)
222                        .collect(Collectors.toList())));
223
224        FlowFactory.userService().deleteByTaskIds(taskIds);
225
226        boolean success = FlowFactory.taskService().deleteByInsIds(instanceIds);
227        if (success) {
228            FlowFactory.hisTaskService().deleteByInsIds(instanceIds);
229            return FlowFactory.insService().removeByIds(instanceIds);
230        }
231        return false;
232    }
233
234    @Override
235    public boolean active(Long id) {
236        Instance instance = getById(id);
237        AssertUtil.isTrue(instance.getActivityStatus().equals(ActivityStatus.ACTIVITY.getKey()), ExceptionCons.INSTANCE_ALREADY_ACTIVITY);
238        instance.setActivityStatus(ActivityStatus.ACTIVITY.getKey());
239        return updateById(instance);
240    }
241
242    @Override
243    public boolean unActive(Long id) {
244        Instance instance = getById(id);
245        AssertUtil.isTrue(instance.getActivityStatus().equals(ActivityStatus.SUSPENDED.getKey()), ExceptionCons.INSTANCE_ALREADY_SUSPENDED);
246        instance.setActivityStatus(ActivityStatus.SUSPENDED.getKey());
247        return updateById(instance);
248    }
249}