CodeX Scripts in Zoho Projects are advanced conditional logic scripts that help enforce specific rules and validations. Users can control how and when tasks can be created, edited, or transitioned. This ensures better compliance and process alignment.
CodeX Scripts are supported in all data centers except CN JP and AE.
However, you can contact support@zohoprojects.com to enable CodeX Scripts for your portal in these data centers. Use Cases :
Restrict Subtask Creation Beyond One Level
Restricts creating a subtask under another subtask to maintain a simple and manageable task hierarchy, allowing only one level of subtasks.
- function main() {
- if(current.record.parent_task !== current.record.root_task) {
- throw new ScriptError('Disable subtasks creation with more than 1 level');
- }
- }
Disable Task Creation in Projects with On-Hold status
Restricts task creation if the associated project is marked as On Hold.
- function main() {
-
- const projectId = current.record.projectId;
- const moduleItr = client.getModules();
-
- /**
- * @type {Module}
- */
- let module
-
- console.log('started');
- for (let mod of moduleItr) {
- console.log(`${mod}`);
- if (mod.name === 'Projects') {
- module = mod;
- }
- }
-
- if (!module) {
- return;
- }
-
- let projectDtl = client.getRecordById(module.id, projectId);
- let statusDtl = client.getStatusDetails(module.id, projectDtl.layoutId, projectDtl.status);
-
- if (statusDtl.name === 'zp.projstatus.onhold') {
- throw new ScriptError('Task Creation disabled for On Hold Projects');
- }
- }
-
Restrict Manual Date Change After Status Update
Restricts editing start date, end date, or duration if the status is not the layout’s default.
- function main() {
-
- //base condition #1
- if (!current.affectedFields.start_date
- && !current.affectedFields.end_date
- && !current.affectedFields.duration_value
- && !current.affectedFields.duration_unit) {
- return;
- }
-
- const statusDtl = client.getStatusDetails(current.module.id, current.record.layoutId, current.record.status);
- console.log(`${statusDtl}`);
-
- if (!statusDtl.isLayoutDefault) {
- throw new ScriptError('Start Date and End date change are only allowed in default status');
- }
- }
-
Restrict Task Closure if Open Subtasks Exist
Restricts the parent task's status to change to Closed if any open subtasks exists. This ensures that the parent task cannot be marked as complete until all its subtasks are closed.
-
- function main() {
-
- console.log(current.affectedFields.toString());
-
- //base condition handling
- if (!current.affectedFields?.status) {
- return;
- }
-
- const url = `https://projects.zoho.com/restapi/portal/${current.org.zohoOrgId}/projects/${current.record.projectId}/tasks/${current.record.id}/subtasks/`;
- let hasMore = true;
- const range = 200;
- let index = 1;
- console.log(url);
-
- while (hasMore) {
- let request = new HttpRequest();
- request.url(url);
- request.connection('zprojects');
- request.params({ index, range });
-
- const response = request.execute();
-
- console.log(response.asText());
- /**
- * @type {[]}
- */
- const tasks = response.asJson()?.statusMessage?.responseText?.tasks;
-
- //no subtasks present for current task
- if (!tasks || tasks.length == 0) {
- console.log('No subtasks exists for current task');
- return;
- }
-
- hasMore = tasks.length == range;
- index += range;
-
- console.log(tasks);
- console.log(tasks.length);
-
- for (let task of tasks) {
- console.log(task.completed);
- if (!task.completed) {
- throw new ScriptError('Task cannot be closed since it contains open subtask(s)');
- }
- }
- }
-
-
- }
Restrict Status Change if Predecessors are Open
Restricts status updates if any of the predecessor tasks are incomplete to ensure dependency logic so that a successor task can only proceed once its predecessors are closed.
- function main() {
- console.log(current.affectedFields.toString());
-
- //base condition handling
- if(!current.affectedFields?.status) {
- return;
- }
- const url = `https://projects.zoho.com/restapi/portal/${current.org.zohoOrgId}/projects/${current.record.projectId}/tasks/${current.record.id}/`;
- console.log(url);
-
- let request = new HttpRequest();
- request.url(url);
- request.connection('zprojects');
- const response = request.execute();
- const taskDependencyDtl = response.asJson()?.statusMessage?.responseText?.tasks[0]?.dependency;
- //no dependency present in previous task
- if(!taskDependencyDtl || !taskDependencyDtl?.predecessor) {
- return;
- }
- console.log(taskDependencyDtl);
- for(let predecessorId of taskDependencyDtl.predecessor) {
- console.log(predecessorId);
- if(!taskDependencyDtl.dependencyDetails[predecessorId]?.IS_COMPLETED) {
- throw new ScriptError('Open predecessor tasks exists, please close them to proceed');
- }
- }
- }
Restrict Subtask Creation
Restricts subtask creation to maintain a flat task structure.
- function main() {
- let task = current.record;
- let startDate = task.start_date;
- if(task.parent_task || task.root_task) {
- Logger.info("Subtask creation is disabled");
- throw new ScriptError("Subtask creation is disabled"));
- }
- }
-
Update Task Duration and Status Based on Conditions
Update task duration and status based on a specific custom field and current status.
For example, this script updates the duration of a task and its status when specific conditions are met:
- If the current status of the task is “On Hold”, it automatically changes the status to a specific ID (e.g., "In Progress").
- If a specific value is selected in a multi-select custom field, it sets the duration to 30 days.
- It also checks and logs the task’s billing type and affected fields.
- function main() {
- let task = current.record;
- const statusDetails = client.getStatusDetails(task.moduleId, task.layoutId, task.status);
- if(statusDetails.name === 'On Hold') {
- task.status = '5000000000362';
- client.save(task);
- }
- console.log(JSON.stringify(statusDetails));
- if(task.weightage.includes("Medium") { //check if the multi select field is some options
- console.log('setting status to In Progress');
- task.duration_unit = TaskDurationUnit.DAYS;
- task.duration_value = 30;
- }
- }
Restrict Edits for Archived Projects
Restricts any update to a task if its project is archived to ensure that no task edits can be made under such projects.
- function main() {
- let task = current.record;
- let projectId = task.projectId;
- const moduleItr = client.getModules(0, 10);
- let moduleId;
- console.log(JSON.stringify(current.affectedFields));
- while(moduleItr.hasNext()) {
- let moduleObj = moduleItr.next();
- if(moduleObj.name == 'Projects') {
- moduleId = moduleObj.id;
- }
- }
- let project = client.getRecordById(moduleId, projectId);
- if(project._status == 'archived') {
- throw new ScriptError("Edits are disabled for archived projects");
- }
- }
Restricts Past Start Dates
Throws an error if the selected start date is in the past to maintain accurate schedules.
- function main() {
- let task = current.record;
- let date = Date.now();
- for(let key of Object.keys(current)) {
- console.log(key);
- }
- const startDate = new Date(task.start_date)
- if(date > startDate) {
- console.log('Start date is in past date');
- throw new ScriptError('Start date cannot be updated with past dates');
- }
- }
Restrict Editing Task on a Condition
Restricts any updates to the task if the checkbox field is enabled, except when changing the checkbox itself to prevent unintended changes.
- function main() {
-
- const affectedFields = current.affectedFields;
- const task = current.record;
-
- if(affectedFields && typeof affectedFields['checkbox_cf'] != 'undefined') {
- return; //Do nothing in case the checkbox itself is updated.
- }
-
- //boolean value for checkbox type field
- if(task.checkbox_cf) {
- throw new ScriptError('The check box is enabled, task is locked. ')
- }
- }
-
Got an idea for how you would like CodeX to work in your project setup? Drop your use case in the comments below!
More Reads