Codex Scripts for Custom Modules

Codex Scripts for Custom Modules

CodeX Scripts in Zoho Projects are advanced conditional logic scripts that help enforce specific rules and validations. Users can control how and when custom modules can be created, updated, and deleted using the CodeX Scripts.

Info
CodeX Scripts are supported in all data centers except CN, JP and AE.

Notes
ReviewModule custom module is used here as an example to demonstrate how CodeX scripts can enforce business rules within a custom module.

You can replace this module with any custom module that fits your organization's workflow, such as Change Requests, Asset Requests, or any other business process.

Update the module, field names, and validation logic to match your requirements while reusing the same scripts.

Use cases

Validate Start and End Date Order

Ensure the End Date is not earlier than the Start Date during record creation. Records with an invalid date sequence are rejected.

Event: Before Create
Code
  1. function main() {
  2.     const DATE_ORDER_ERROR = "End date cannot be earlier than start date";
  3.     try {
  4.         const record = current.record;
  5.         const startDate = record.starting_date;
  6.         const endDate   = record.ending_date;
  7.         if (!startDate || !endDate) return;   // need both to compare
  8.         const start = new Date(startDate);
  9.         const end   = new Date(endDate);
  10.         start.setHours(0, 0, 0, 0);
  11.         end.setHours(0, 0, 0, 0);
  12.         if (end < start) {
  13.             throw new ScriptError(DATE_ORDER_ERROR);
  14.         }
  15.     } catch (err) {
  16.         const msg = err.getMessage ? err.getMessage() : err.message;
  17.         if (msg === DATE_ORDER_ERROR) {
  18.             throw new ScriptError(msg);
  19.         }
  20.         throw new ScriptError("Error in script, please contact portal admin");
  21.     }
  22. }

 Restrict Past Dates on Update

Restrict users from updating the Start Date, End Date, or Review Completion Date to a past date.

Event: Before Update
Code
  1. function main() {
  2.     const PAST_DATE_ERROR = "Date cannot be in the past";
  3.     const DATE_FIELDS = ["review_completion_date", "starting_date", "ending_date"];

  4.     try {
  5.         const today = new Date();
  6.         today.setHours(0, 0, 0, 0);

  7.         for (let i = 0; i < DATE_FIELDS.length; i++) {
  8.             const diff = current.affectedFields[DATE_FIELDS[i]];
  9.             if (!diff) continue;

  10.             const newDate = new Date(diff.newValue);
  11.             newDate.setHours(0, 0, 0, 0);

  12.             if (newDate < today) {
  13.                 throw new ScriptError(PAST_DATE_ERROR);
  14.             }
  15.         }
  16.     } catch (err) {
  17.         const msg = err.getMessage ? err.getMessage() : err.message;
  18.         if (msg === PAST_DATE_ERROR) {
  19.             throw new ScriptError(msg);
  20.         }
  21.         throw new ScriptError("Error in script, please contact portal admin");
  22.     }
  23. }

 Validate Start and End Date Order on Update

Ensure the End Date is not earlier than the Start Date when updating a record. The script also requires a Start Date if an End Date is provided.

Event: Before Update
Code
  1. function main() {
  2.     const DATE_ORDER_ERROR = "End date cannot be earlier than start date";
  3.     const START_REQUIRED_ERROR = "Start date is required when end date is set";

  4.     try {
  5.         const record = current.record;

  6.         const startDate = current.affectedFields.starting_date
  7.             ? current.affectedFields.starting_date.newValue
  8.             : record.starting_date;
  9.         const endDate = current.affectedFields.ending_date
  10.             ? current.affectedFields.ending_date.newValue
  11.             : record.ending_date;

  12.         if (endDate && !startDate) {
  13.             throw new ScriptError("Start date is required when end date is set");
  14.         }

  15.         if (!startDate || !endDate) return;

  16.         const start = new Date(startDate);
  17.         const end = new Date(endDate);
  18.         start.setHours(0, 0, 0, 0);
  19.         end.setHours(0, 0, 0, 0);

  20.         if (end < start) {
  21.             throw new ScriptError(DATE_ORDER_ERROR);
  22.         }
  23.     } catch (err) {
  24.         const msg = err.getMessage ? err.getMessage() : err.message;
  25.         if (msg === DATE_ORDER_ERROR || msg === START_REQUIRED_ERROR) {
  26.             throw new ScriptError(msg);
  27.         }
  28.         throw new ScriptError("Error in script, please contact portal admin");
  29.     }
  30. }

 Restrict Open Record Limit per User

Restrict users from creating new records when they already have more than 10 open records in the module.

Event: Before Create
Code
  1. function main() {
  2.     const LIMIT_REACHED = "10 or more Open record. limit reached — you cannot create more";
  3.     const MAX_OPEN = 10;

  4.     try {
  5.         const url = "https://projectsforce.localzoho.com";
  6.         const portalId = current.org.zohoOrgId;
  7.         const moduleId = current.record.moduleId;
  8.         const currentUser = current.user;

  9.         let openCount = 0;
  10.         let page = 1;
  11.         const perPage = 100;
  12.         let hasNext = true;

  13.         while (hasNext && openCount <= MAX_OPEN) {
  14.             let req = new HttpRequest();
  15.             req.url(`${url}/api/v3/portal/${portalId}/module/${moduleId}/entities?page=${page}&per_page=${perPage}`);
  16.             req.method("GET");
  17.             req.connection("zconnect");

  18.             const res = req.execute().asJson()?.statusMessage?.responseText;
  19.             // throw new ScriptError(req.execute().asText());
  20.             const records = res.entities || res;

  21.             for (let i = 0; i < records.length; i++) {
  22.                 const rec = records[i];
  23.                 const createdBy = rec.created_by && rec.created_by.zpuid;
  24.                 const isOpen = rec.status && rec.status.is_closed_type === false;

  25.                 if (isOpen && createdBy === currentUser.id) {
  26.                     openCount++;
  27.                     if (openCount > MAX_OPEN) break;
  28.                 }
  29.             }

  30.             hasNext = res.page_info ? res.page_info.has_next_page === true : false;
  31.             page++;
  32.         }

  33.         if (openCount > MAX_OPEN) {
  34.             throw new ScriptError(LIMIT_REACHED);
  35.         }

  36.     } catch (err) {
  37.         // throw new ScriptError(err);
  38.         const msg = err.getMessage ? err.getMessage() : err.message;
  39.         if (msg === LIMIT_REACHED) {
  40.             throw new ScriptError(msg);
  41.         }
  42.         throw new ScriptError("Error in script, please contact portal admin");
  43.     }
  44. }

 Restrict Past Dates on Creation

Restrict users from creating records with a Start Date, End Date, or Review Completion Date set in the past.

Event: Before Create
Code
  1. function main() {
  2.     const PAST_DATE_ERROR = "Date cannot be in the past";
  3.     const DATE_FIELDS = ["review_completion_date", "starting_date", "ending_date"];

  4.     try {
  5.         const record = current.record;
  6.         const today  = new Date();
  7.         today.setHours(0, 0, 0, 0);

  8.         for (let i = 0; i < DATE_FIELDS.length; i++) {
  9.             const value = record[DATE_FIELDS[i]];
  10.             if (!value) continue;

  11.             const newDate = new Date(value);
  12.             newDate.setHours(0, 0, 0, 0);

  13.             if (newDate < today) {
  14.                 throw new ScriptError(PAST_DATE_ERROR);
  15.             }
  16.         }
  17.     } catch (err) {
  18.         const msg = err.getMessage ? err.getMessage() : err.message;
  19.         if (msg === PAST_DATE_ERROR) {
  20.             throw new ScriptError(msg);
  21.         }
  22.         throw new ScriptError("Error in script, please contact portal admin");
  23.     }
  24. }
Allow record updates only for users associated with the record (such as the creator or assigned users) or users with the Administrator role. Unauthorized users cannot edit the record.

Event: Before Update
Code
  1. function main() {
  2.     const NOT_ALLOWED = "You are not allowed to edit this record";

  3.     try {
  4.         const url         = "https://projectsforce.localzoho.com";
  5.         const record      = current.record;
  6.         const currentUser = current.user;        // acting user — confirm name/shape

  7.         // 1. Users related to this record (compare on id / ZPUID)
  8.         const relatedIds = new Set();
  9.         if (record.created_by)            relatedIds.add(record.created_by.id);
  10.         if (record.review_module_cf_0002) relatedIds.add(record.review_module_cf_0002.id);
  11.         if (Array.isArray(record.review_module_cf_0001)) {
  12.             record.review_module_cf_0001.forEach(u => relatedIds.add(u.id));
  13.         }

  14.         if (relatedIds.has(currentUser.id)) {
  15.             return;  // related -> allowed
  16.         }

  17.         // 2. Not related -> fetch acting user, allow only Administrator
  18.         let req = new HttpRequest();
  19.         req.url(`${url}/api/v3.1/portal/${current.org.zohoOrgId}/users/${currentUser.id}`);
  20.         req.method("GET");
  21.         req.connection("zprojects");

  22.         const user = req.execute().asJson().statusMessage.responseText;   // already an object
  23.         const role = (user.role && user.role.name || "").toLowerCase();

  24.         if (role !== "administrator") {
  25.             throw new ScriptError(NOT_ALLOWED);
  26.         }

  27.     } catch (err) {
  28.         const msg = err.getMessage ? err.getMessage() : err.message;
  29.         if (msg === NOT_ALLOWED) {
  30.             throw new ScriptError(msg);
  31.         }
  32.         throw new ScriptError("Error in script, please contact portal admin");
  33.     }
  34. }

 

More Reads
CodeX Scripts - Intro
Working with CodeX Scripts
JavaScript SDK for CodeX Scripts
CodeX Scripts for Projects
CodeX Scripts for Tasks