allow option to complete single tasks with or without execution
This commit is contained in:
parent
e6391a2aa3
commit
afb630c78d
|
@ -1565,7 +1565,7 @@ paths:
|
|||
schema:
|
||||
type: string
|
||||
post:
|
||||
operationId: spiffworkflow_backend.routes.process_api_blueprint.mark_task_complete
|
||||
operationId: spiffworkflow_backend.routes.process_api_blueprint.manual_complete_task
|
||||
summary: Mark a task complete without executing it
|
||||
tags:
|
||||
- Process Instances
|
||||
|
|
|
@ -28,11 +28,6 @@ from lxml import etree # type: ignore
|
|||
from lxml.builder import ElementMaker # type: ignore
|
||||
from SpiffWorkflow.task import Task as SpiffTask # type: ignore
|
||||
from SpiffWorkflow.task import TaskState
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import asc
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy import or_
|
||||
|
||||
from spiffworkflow_backend.exceptions.process_entity_not_found_error import (
|
||||
ProcessEntityNotFoundError,
|
||||
)
|
||||
|
@ -99,6 +94,10 @@ from spiffworkflow_backend.services.secret_service import SecretService
|
|||
from spiffworkflow_backend.services.service_task_service import ServiceTaskService
|
||||
from spiffworkflow_backend.services.spec_file_service import SpecFileService
|
||||
from spiffworkflow_backend.services.user_service import UserService
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy import asc
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy import or_
|
||||
|
||||
|
||||
class TaskDataSelectOption(TypedDict):
|
||||
|
@ -2189,23 +2188,24 @@ def send_bpmn_event(
|
|||
)
|
||||
|
||||
|
||||
def mark_task_complete(
|
||||
def manual_complete_task(
|
||||
modified_process_model_identifier: str,
|
||||
process_instance_id: str,
|
||||
task_id: str,
|
||||
body: Dict,
|
||||
) -> Response:
|
||||
"""Mark a task complete without executing it."""
|
||||
execute = body.get("execute", True)
|
||||
process_instance = ProcessInstanceModel.query.filter(
|
||||
ProcessInstanceModel.id == int(process_instance_id)
|
||||
).first()
|
||||
if process_instance:
|
||||
processor = ProcessInstanceProcessor(process_instance)
|
||||
processor.mark_task_complete(task_id)
|
||||
processor.manual_complete_task(task_id, execute)
|
||||
else:
|
||||
raise ApiError(
|
||||
error_code="send_bpmn_event_error",
|
||||
message=f"Could not skip Task {task_id} in Instance {process_instance_id}",
|
||||
error_code="complete_task",
|
||||
message=f"Could not complete Task {task_id} in Instance {process_instance_id}",
|
||||
)
|
||||
return Response(
|
||||
json.dumps(ProcessInstanceModelSchema().dump(process_instance)),
|
||||
|
|
|
@ -621,7 +621,7 @@ class ProcessInstanceProcessor:
|
|||
db.session.add(pim)
|
||||
db.session.commit()
|
||||
|
||||
def save(self) -> None:
|
||||
def _save(self) -> None:
|
||||
"""Saves the current state of this processor to the database."""
|
||||
self.process_instance_model.bpmn_json = self.serialize()
|
||||
|
||||
|
@ -643,6 +643,9 @@ class ProcessInstanceProcessor:
|
|||
db.session.add(self.process_instance_model)
|
||||
db.session.commit()
|
||||
|
||||
def save(self) -> None:
|
||||
"""Saves the current state and moves on to the next state."""
|
||||
self._save()
|
||||
human_tasks = HumanTaskModel.query.filter_by(
|
||||
process_instance_id=self.process_instance_model.id
|
||||
).all()
|
||||
|
@ -729,17 +732,25 @@ class ProcessInstanceProcessor:
|
|||
self.bpmn_process_instance.catch(event_definition)
|
||||
self.do_engine_steps(save=True)
|
||||
|
||||
def mark_task_complete(self, task_id: str) -> None:
|
||||
"""Mark the task complete without executing it."""
|
||||
def manual_complete_task(self, task_id: str, execute: bool) -> None:
|
||||
"""Mark the task complete optionally executing it."""
|
||||
spiff_task = self.bpmn_process_instance.get_task(UUID(task_id))
|
||||
spiff_task._set_state(TaskState.COMPLETED)
|
||||
if execute:
|
||||
current_app.logger.info(
|
||||
f"Manually executing Task {spiff_task.task_spec.name} of process instance {self.process_instance_model.id}"
|
||||
)
|
||||
spiff_task.complete()
|
||||
else:
|
||||
current_app.logger.info(
|
||||
f"Skipping Task {spiff_task.task_spec.name} of process instance {self.process_instance_model.id}"
|
||||
)
|
||||
spiff_task._set_state(TaskState.COMPLETED)
|
||||
for child in spiff_task.children:
|
||||
child.task_spec._update(child)
|
||||
self.bpmn_process_instance.last_task = spiff_task
|
||||
for child in spiff_task.children:
|
||||
child.task_spec._update(child)
|
||||
current_app.logger.info(
|
||||
f"Task {spiff_task.task_spec.name} of process instance {self.process_instance_model.id} skipped"
|
||||
)
|
||||
self.do_engine_steps(save=True)
|
||||
self._save()
|
||||
# Saving the workflow seems to reset the status
|
||||
self.suspend()
|
||||
|
||||
@staticmethod
|
||||
def get_parser() -> MyCustomParser:
|
||||
|
|
|
@ -529,6 +529,8 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
// We actually could allow this for any waiting events
|
||||
const taskTypes = ['Event Based Gateway'];
|
||||
return (
|
||||
processInstance &&
|
||||
processInstance.status === 'waiting' &&
|
||||
ability.can('POST', targetUris.processInstanceSendEventPath) &&
|
||||
taskTypes.filter((t) => t === task.type).length > 0 &&
|
||||
task.state === 'WAITING' &&
|
||||
|
@ -536,8 +538,10 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
);
|
||||
};
|
||||
|
||||
const canMarkTaskComplete = (task: any) => {
|
||||
const canCompleteTask = (task: any) => {
|
||||
return (
|
||||
processInstance &&
|
||||
processInstance.status === 'suspended' &&
|
||||
ability.can('POST', targetUris.processInstanceCompleteTaskPath) &&
|
||||
task.state === 'READY' &&
|
||||
showingLastSpiffStep()
|
||||
|
@ -546,6 +550,7 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
|
||||
const canResetProcess = (task: any) => {
|
||||
return (
|
||||
ability.can('POST', targetUris.processInstanceResetPath) &&
|
||||
processInstance &&
|
||||
processInstance.status === 'suspended' &&
|
||||
task.state === 'READY' &&
|
||||
|
@ -627,13 +632,14 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
});
|
||||
};
|
||||
|
||||
const markTaskComplete = () => {
|
||||
const completeTask = (execute: boolean) => {
|
||||
const taskToUse: any = taskToDisplay;
|
||||
HttpService.makeCallToBackend({
|
||||
path: `/task-complete/${modifiedProcessModelId}/${params.process_instance_id}/${taskToUse.id}`,
|
||||
httpMethod: 'POST',
|
||||
successCallback: saveTaskDataResult,
|
||||
failureCallback: saveTaskDataFailure,
|
||||
postBody: { execute },
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -705,15 +711,23 @@ export default function ProcessInstanceShow({ variant }: OwnProps) {
|
|||
</Button>
|
||||
);
|
||||
}
|
||||
if (canMarkTaskComplete(task)) {
|
||||
if (canCompleteTask(task)) {
|
||||
buttons.push(
|
||||
<Button
|
||||
data-qa="mark-task-complete-button"
|
||||
onClick={() => markTaskComplete()}
|
||||
onClick={() => completeTask(false)}
|
||||
>
|
||||
Mark Complete
|
||||
</Button>
|
||||
);
|
||||
buttons.push(
|
||||
<Button
|
||||
data-qa="execute-task-complete-button"
|
||||
onClick={() => completeTask(true)}
|
||||
>
|
||||
Execute Task
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
if (canSendEvent(task)) {
|
||||
buttons.push(
|
||||
|
|
Loading…
Reference in New Issue