Automation Series: Close all tasks once the project is completed
When a project is marked as Completed, it might still have open tasks such as recurring tasks that were not marked as complete, tasks that are no longer relevant, or tasks that no longer need attention after closure.
To ensure the project reflects its final state, you can use a task workflow rule to automatically close all open tasks once the project reaches the Completed status.
To set this up,
First create a connection with Zoho Projects using these scopes: - ZohoProjects.tasks.ALL
- ZohoProjects.projects.READ
- ZohoProjects.portals.READ
- ZohoProjects.milestones.ALL
Create a
Custom Function and add the Deluge script below. Replace 'xxxxxxxxx' with your Zoho Projects connection name, and map the arguments listed below.
The below script removes task recurrences and closes all tasks in a project. In the below script, the connection name is "closealltasks"
- // TODO: Please create a connection for the Zoho Projects service with the scopes "ZohoProjects.tasks.ALL, ZohoProjects.projects.READ, ZohoProjects.portals.READ, ZohoProjects.milestones.ALL". Replace 'closealltasks' with the connection name. Click this link below to learn how to create the connection.
- // Link - https://help.zoho.com/portal/en/kb/projects/integration/connections/articles/connections-23-5-2022#How_to_establish_a_Connection
- // TODO: Replace the status name (Closed status type) in Line No. 6, if needed.
- projectsAPIEndPoint = "https://projectsapi.zoho.com/restapi";
- projectsv3APIEndPoint = "https://projectsapi.zoho.com/api/v3";
- statusName = "Closed";
- statusId = null;
- /* Close all tasks */
- //Fetch task layouts
- taskLayoutDetails = invokeurl
- [
- url :projectsAPIEndPoint + "/portal/" + portalId + "/projects/" + projectId + "/tasklayouts"
- type :GET
- connection:"closealltasks"
- ];
- // info taskLayoutDetails;
- if(taskLayoutDetails != null && taskLayoutDetails.get("status_details") != null)
- {
- statusDetails = taskLayoutDetails.get("status_details");
- for each status in statusDetails
- {
- if(status.get("name").equalsIgnoreCase(statusName))
- {
- // Fetch task status id based on status name
- statusId = status.get("id");
- info status.get("name") + " : " + statusId;
- break;
- }
- }
- }
- if(statusId != null)
- {
- indexValue = 1;
- rangeValue = 100;
- loop = {1,2,3,4,5,6,7,8,9,10};
- predStatusMap = Map();
- // This loop fetches up to 300 tasks. Increase the count as needed, e.g., loop = {1,2,3,4,5}; to fetch 500 tasks.
- for each i in loop
- {
- taskParameter = Map();
- taskParameter.put("index",indexValue);
- taskParameter.put("range",rangeValue);
- taskParameter.put("status","notcompleted");
- // info taskParameter;
- taskResponse = zoho.projects.getRecords(portalId,projectId,"tasks",taskParameter,0,"closealltasks");
- // info taskResponse;
- if(taskResponse.containKey("tasks"))
- {
- taskIds = list();
- for each task in taskResponse.get("tasks")
- {
- taskId = task.get("id");
- if(task.get("is_recurrence_set"))
- {
- updateTaskParameter = Map();
- updateTaskParameter.put("json_string",{"recurrence":{"recurring_frequency":"none","time_span":"1","number_of_occurrences":"2","is_comments_recurred":false,"recurrence_type":"after_current_task_completed"}});
- updateTaskResponse = zoho.projects.update(portalId,projectId,"tasks",taskId,updateTaskParameter,"closealltasks");
- info updateTaskResponse;
- }
- if(task.containsKey("dependency") && task.get("dependency").containsKey("predecessor"))
- {
- predTasks = task.get("dependency").get("predecessor");
- predList = list();
- for each predTaskId in predTasks
- {
- predList.add(task.get("dependency").get("dependencyDetails").get(predTaskId).get("IS_COMPLETED"));
- }
- if(!predList.contains(false))
- {
- taskIds.add(taskId);
- }
- }
- else
- {
- taskIds.add(taskId);
- }
- info "taskIds : " + taskIds;
- }
- bulkUpdateParams = Map();
- bulkUpdateParams.put("taskids",taskIds.toText().remove("[").remove("]"));
- bulkUpdateParams.put("status",{"id":statusId});
- info bulkUpdateParams;
- /* Bulk update */
- taskBulkUpdate = invokeurl
- [
- url :projectsv3APIEndPoint + "/portal/" + portalId + "/projects/" + projectId + "/tasks/bulk-update"
- type :PATCH
- parameters:bulkUpdateParams.toString()
- connection:"closealltasks"
- ];
- info taskBulkUpdate;
- }
- else
- {
- break;
- }
- }
- }
- return "success";
- portalId - Portal System ID
- projectId - Project System ID

After saving the custom function, create a workflow rule with the following settings:

Once the rule is saved, all open tasks are completed automatically whenever a project is marked as Completed. This ensures the project reflects its true closure state, avoids manual cleanup and keeps your project up to date.
If you have any questions, please drop comments below or email us at support@zohoprojects.com.