Work notes business rule

AnushaB40463536
Giga Contributor

I have a project that syncs service now incidents and connectwise tickets. I need the work notes that are added or updated to an incident be sent to connectwise via my middleware. I developed dev using admin account but for prod I am supposed to take the least previleged account without admin access. Therefore in dev I removed the admin role and  I have added the role ITIL but the work notes buisness rule triggers but sends empty payload. 

this is my buisness rule that is set for table sys_journal_field. I reckon an ACL must be written for this, but the IT admin is not keen on doing this. Is there a better way of doing? Please help.


(function executeRule(current, previous /*null when async*/) {
try {
var L2_GROUP = "1192f4fc938bd2504c6fb9b17cba104b"; // SNOW - Service Desk L2
var CW_GROUP = "1704153f3b56d610271ffa9aa4e45ad7"; // Escalate - Client-Specific Queue (mapped)

var isCreate = current.operation() === "insert";
var isUpdate = current.operation() === "update";
var isDelete = current.operation() === "delete";

// One-shot suppression: skip if origin is ConnectWise, then clear flag safely
if (current.u_integration_source == "connectwise") {
gs.log("[Incident BR] Skipped (origin connectwise) for " + current.number);

var inc2 = new GlideRecord('incident');
if (inc2.get(current.sys_id.toString())) {
inc2.setWorkflow(false);
if (inc2.setUseEngines) inc2.setUseEngines(false);
inc2.u_integration_source = '';
inc2.update();
}
return;
}

var currentGroup = current.assignment_group ? current.assignment_group.toString() : "";
var previousGroup = previous.assignment_group ? previous.assignment_group.toString() : "";

// CREATE guard
if (isCreate) {
if (currentGroup !== L2_GROUP) {
gs.log("[Incident BR] Skipped CREATE because assignment_group is not L2");
return;
}
}

// UPDATE rules
var blockStatus = false;
if (isUpdate) {
var onlyWorknotesChanged =
current.work_notes.changes() &&
!current.impact.changes() &&
!current.priority.changes() &&
!current.state.changes() &&
!current.assignment_group.changes() &&
!current.short_description.changes() &&
!current.description.changes();

if (onlyWorknotesChanged) {
gs.log("[Incident BR] Skipped UPDATE because only work_notes changed");
return;
}

if (currentGroup !== L2_GROUP && currentGroup !== CW_GROUP) {
gs.log("[Incident BR] Skipped UPDATE because assignment_group not allowed");
return;
}

if (currentGroup === CW_GROUP) {
var stateVal = current.state ? current.state.toString() : "";
if (stateVal !== "7" && stateVal !== "8") {
current.state = previous.state;
blockStatus = true;
gs.log("[Incident BR] CW group update → status blocked, other fields allowed");
}
}

if (previousGroup === CW_GROUP && currentGroup === L2_GROUP) {
current.u_connectwise_ticket_id = "";
gs.log("[Incident BR] Assignment group changed CW → L2, forcing CREATE in CW");
}
}

// DELETE
if (isDelete) {
var deletePayload = {
sys_id: current.sys_id.toString(),
number: current.number.toString(),
u_connectwise_ticket_id: current.u_connectwise_ticket_id ? current.u_connectwise_ticket_id.toString() : ""
};

var deleteEndpoint = "webhooks/business-rules/incident-deleted";
var deleteRequest = new sn_ws.RESTMessageV2();
deleteRequest.setHttpMethod("post");
deleteRequest.setEndpoint(deleteEndpoint);
deleteRequest.setRequestHeader("Content-Type", "application/json");
deleteRequest.setRequestBody(JSON.stringify(deletePayload));
deleteRequest.executeAsync();

gs.log("[Incident BR] Sent delete payload: " + JSON.stringify(deletePayload));
return;
}

// Payload building
var stateMapping = {
"1": { name: "New" },
"2": { name: "In Progress" },
"3": { name: "On Hold" },
"4": { name: "Pending" },
"5": { name: "Resolved" },
"6": { name: "Resolved" },
"7": { name: "Closed" },
"8": { name: "Cancelled" }
};

var baseUrl = gs.getProperty("glide.servlet.uri") || "";
function soLink(id) { return baseUrl + "api/now/table/service_offering/" + id; }
function bsLink(id) { return baseUrl + "api/now/table/cmdb_ci_service/" + id; }

var soId = current.service_offering ? current.service_offering.toString() : "";
var bsId = current.business_service ? current.business_service.toString() : "";

var service_offering = soId ? { link: soLink(soId), value: soId } : undefined;
var business_service = bsId ? { link: bsLink(bsId), value: bsId } : undefined;

var callerEmail = "";
var callerUsername = "";
if (current.caller_id) {
try {
var callerGr = new GlideRecord("sys_user");
if (callerGr.get(current.caller_id.toString())) {
callerEmail = callerGr.email ? callerGr.email.toString() : "";
callerUsername = callerGr.user_name ? callerGr.user_name.toString() : "";
}
} catch (e) {
gs.log("[Incident BR] Error fetching caller details: " + e.message);
}
}

var payload = {
sys_id: current.sys_id.toString(),
number: current.number.toString(),
u_connectwise_ticket_id: current.u_connectwise_ticket_id ? current.u_connectwise_ticket_id.toString() : "",
summary: current.short_description ? current.short_description.toString() : "",
severity: "Medium",
impact: current.impact ? current.impact.toString() : "3",
priority: { id: parseInt(current.priority, 10) || 8 },
description: current.description ? current.description.toString() : "",
caller_id: current.caller_id ? current.caller_id.getDisplayValue() : "",
email: callerEmail,
username: callerUsername,
created_on: current.sys_created_on ? current.sys_created_on.toString() : "",
updated_on: current.sys_updated_on ? current.sys_updated_on.toString() : "",
sys_created_by: (current.sys_created_by || "").toString(),
service_offering: service_offering,
business_service: business_service
};

if (!blockStatus) {
payload.status = stateMapping[(current.state || "").toString()] || { name: "New" };
}

if (!payload.service_offering) delete payload.service_offering;
if (!payload.business_service) delete payload.business_service;

var endpoint = payload.u_connectwise_ticket_id
? "webhooks/business-rules/incident-updated"
: "webhooks/business-rules/incident-created";

var request = new sn_ws.RESTMessageV2();
request.setHttpMethod("post");
request.setEndpoint(endpoint);
request.setRequestHeader("Content-Type", "application/json");
request.setRequestBody(JSON.stringify(payload));
request.executeAsync();

gs.log("[Incident BR] Sent payload (" + (payload.u_connectwise_ticket_id ? "UPDATE" : "CREATE") + "): " + JSON.stringify(payload));
} catch (err) {
gs.error("[Incident BR] Error: " + err.message);
}
})(current, previous);

1 ACCEPTED SOLUTION

Rafael Batistot
Kilo Patron

Hi @AnushaB40463536 

 

Your problem isn’t with the Business Rule itself, but with permissions.

 

  • In Dev, with admin, you had access to sys_journal_field and could read work_notes.
  • In Prod, with only itil, your script runs but the work_notes values are empty because work_notes (sys_journal_field) is protected by ACLs.

So yes, you’re correct: an ACL is required if you want a non-admin integration account to read work notes.

If you found this response helpful, please mark it as Helpful. If it fully answered your question, consider marking it as Correct. Doing so helps other users find accurate and useful information more easily.

View solution in original post

2 REPLIES 2

Rafael Batistot
Kilo Patron

Hi @AnushaB40463536 

 

Your problem isn’t with the Business Rule itself, but with permissions.

 

  • In Dev, with admin, you had access to sys_journal_field and could read work_notes.
  • In Prod, with only itil, your script runs but the work_notes values are empty because work_notes (sys_journal_field) is protected by ACLs.

So yes, you’re correct: an ACL is required if you want a non-admin integration account to read work notes.

If you found this response helpful, please mark it as Helpful. If it fully answered your question, consider marking it as Correct. Doing so helps other users find accurate and useful information more easily.

AnushaB40463536
Giga Contributor

Thank you for taking the time to answer my question.