diff --git a/ChangeLog.md b/ChangeLog.md index 623edec..15cfeff 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,12 @@ # Change Log +## v0.0.2.3 + +### New Features + +- Task: add non static methods: get_workflow, close, approve, reject, cancel, create +- Workflow: add non static methods: create_task + ## v0.0.2.2 ### New Features diff --git a/README.md b/README.md index a2ea1d6..6101e6a 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ This module is used to interact with the Xurrent API. It provides a set of class ``` ### Requests + ```python from xurrent.requests import Request @@ -104,4 +105,19 @@ This module is used to interact with the Xurrent API. It provides a set of class "subject": "Example Subject" }) + # get workflow of task (use expand: True to get the full workflow object) + workflow = task.get_workflow(expand=True) + # or statically + workflow = Task.get_workflow_by_template_id(x_api_helper, , expand=True) + + # close + task.close() + #cancel + task.cancel() # only possible before the task is started + #reject + task.reject() + #approve + task.approve() + + ``` diff --git a/pyproject.toml b/pyproject.toml index 86a5ab7..5159cfa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "xurrent" -version = "0.0.2.2" +version = "0.0.2.3" authors = [ { name="Fabian Steiner", email="fabian@stei-ner.net" }, ] diff --git a/src/xurrent/tasks.py b/src/xurrent/tasks.py index 7ba48a2..ae5df7c 100644 --- a/src/xurrent/tasks.py +++ b/src/xurrent/tasks.py @@ -14,8 +14,20 @@ class TaskPredefinedFilter(str, Enum): assigned_to_me = "assigned_to_me" # List all tasks that are assigned to the API user approval_by_me = "approval_by_me" # List all approval tasks that are assigned to the API user and which status is different from ‘Registered’ - - +class TaskStatus(str, Enum): + registered = "registered" # Registered + declined = "declined" # Declined + assigned = "assigned" # Assigned + accepted = "accepted" # Accepted + in_progress = "in_progress" # In Progress + waiting_for = "waiting_for" # Waiting for… + waiting_for_customer = "waiting_for_customer" # Waiting for Customer + request_pending = "request_pending" # Request Pending + failed = "failed" # Failed + rejected = "rejected" # Rejected + completed = "completed" # Completed + approved = "approved" # Approved + canceled = "canceled" # Canceled class Task(): @@ -61,7 +73,7 @@ def get_tasks(cls, connection_object: XurrentApiHelper, predefinedFilter: TaskPr if predefinedFilter: uri = f'{uri}/{predefinedFilter}' if queryfilter: - uri = f'{uri}?{queryfilter}' + uri += '?' + self._connection_object.create_filter_string(queryfilter) return connection_object.api_call(uri, 'GET') @staticmethod @@ -71,6 +83,15 @@ def get_workflow_of_task(connection_object: XurrentApiHelper, id, expand: bool = return Workflow.get_by_id(connection_object, task.workflow.id) return Workflow.from_data(connection_object, task.workflow) + def get_workflow(self, expand: bool = False) -> Workflow: + if task.workflow and not expand: + return Workflow.from_data(self._connection_object, self.workflow) + elif task.workflow and expand: + return Workflow.get_by_id(self._connection_object, self.workflow.id) + elif not task.workflow: + return Task.get_workflow_of_task(self._connection_object, self.id, expand) + + @staticmethod def update_by_id(connection_object: XurrentApiHelper, id, data) -> T: task = Task(connection_object=connection_object, id=id) @@ -81,3 +102,74 @@ def update(self, data) -> T: response = self._connection_object.api_call(uri, 'PATCH', data) self.__update_object__(response) return self + + def close(self, note: str = None, member_id: int = None) -> T: + """ + Close the task. + + :param note: Note to add to the task + :param member_id: ID of the member who should close the task + """ + if(self.category == "approval"): + raise ValueError("Approval tasks cannot be closed. Use the 'approve' or 'reject' method instead.") + return self.update({ + 'status': 'completed', + 'note': note or "Task closed by API user", + 'member_id': member_id or self._connection_object.api_user.id + }) + + def approve(self, note: str = None, member_id: int = None) -> T: + """ + Approve the task. + + :param note: Note to add to the task + :param member_id: ID of the member who should approve the task + """ + if(self.category != "approval"): + raise ValueError("Only approval tasks can be approved.") + return self.update({ + 'status': 'approved', + 'note': note or "Task approved by API user", + 'member_id': member_id or self._connection_object.api_user.id + }) + + def reject(self, note: str = None, member_id: int = None) -> T: + """ + Reject the task. + + :param note: Note to add to the task + :param member_id: ID of the member who should reject the task + """ + + if(self.category != "approval"): + raise ValueError("Only approval tasks can be rejected.") + return self.update({ + 'status': 'rejected', + 'note': note or "Task rejected by API user", + 'member_id': member_id or self._connection_object.api_user.id + }) + + def cancel(self, note: str = None, member_id: int = None) -> T: + """ + Cancel the task. + + :param note: Note to add to the task + :param member_id: ID of the member who should cancel the task + """ + return self.update({ + 'status': 'canceled', + 'note': note or "Task canceled by API user", + 'member_id': member_id or self._connection_object.api_user.id + }) + + @classmethod + def create(cls, connection_object: XurrentApiHelper, workflowID: int,data: dict) -> T: + """ + Create a new task. + + :param workflowID: ID of the workflow to create the task in + :param data: Data to create the task with + """ + uri = f'{connection_object.base_url}/workflows/{workflowID}/{cls.resourceUrl}' + response = connection_object.api_call(uri, 'POST', data) + return cls.from_data(connection_object, response) diff --git a/src/xurrent/workflows.py b/src/xurrent/workflows.py index 004aebd..ed5c987 100644 --- a/src/xurrent/workflows.py +++ b/src/xurrent/workflows.py @@ -147,6 +147,13 @@ def create(cls, connection_object: XurrentApiHelper, data: dict): response = connection_object.api_call(uri, 'POST', data) return cls.from_data(connection_object, response) + def create_task(self, data: dict): + """ + Create a new task associated with the current workflow instance. + """ + from .tasks import Task + return Task.create(self._connection_object, self.id, data) + def close(self, note="closed.", completion_reason=WorkflowCompletionReason.complete): """ Close the current workflow instance.