Skip to content

Commit 970549f

Browse files
Create script.js
This Business Rule runs 'before' a record is updated on the 'sn_compliance_policy' table. Its purpose is to prevent a policy from being retired if it is currently linked to any active controls. This enforces a proper decommissioning process, ensuring that controls are retired before the policy that governs them, thereby preventing compliance gaps. The condition for this rule would be: 'State' changes to 'Retired'.
1 parent 901ea70 commit 970549f

File tree

1 file changed

+52
-0
lines changed
  • Server-Side Components/Business Rules/GRC Policy Retirement Gaurd

1 file changed

+52
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
(function executeRule(current, previous /*null when async*/ ) {
2+
// This Business Rule runs 'before' a record is updated on the 'sn_compliance_policy' table.
3+
// Its purpose is to prevent a policy from being retired if it is currently linked to any active controls.
4+
// This enforces a proper decommissioning process, ensuring that controls are retired
5+
// before the policy that governs them, thereby preventing compliance gaps.
6+
// The condition for this rule would be: 'State' changes to 'Retired'.
7+
8+
// Instantiate a GlideAggregate object on the many-to-many (m2m) table
9+
// 'sn_compliance_m2m_policy_policy_statement'. This table links policies (via the 'document' field)
10+
// to control statements (via the 'content' field). Using GlideAggregate is more
11+
// performant than GlideRecord for counting records, as it performs the aggregation
12+
// directly in the database.
13+
var grControlAggregate = new GlideAggregate('sn_compliance_m2m_policy_policy_statement');
14+
15+
// Add a query to filter for records in the m2m table where the 'document' field matches
16+
// the sys_id of the policy record currently being retired.
17+
grControlAggregate.addQuery('document', current.getUniqueValue());
18+
19+
// Add a second query using 'dot-walking' to filter for records where the related
20+
// control statement ('content' field) is currently active. This ensures only active
21+
// controls are considered.
22+
grControlAggregate.addQuery('content.active', true);
23+
24+
// Set the aggregate function to COUNT. This tells the database to return the total
25+
// number of records that match the query conditions.
26+
grControlAggregate.addAggregate('COUNT');
27+
28+
// Execute the database query.
29+
grControlAggregate.query();
30+
31+
// Initialize a variable to store the count of active controls.
32+
var activeControlCount = 0;
33+
34+
// Check if the query returned any results. If it did, retrieve the count.
35+
// Note: GlideAggregate.next() returns a row even if the count is zero.
36+
if (grControlAggregate.next()) {
37+
// Retrieve the aggregated count result and assign it to the variable.
38+
activeControlCount = grControlAggregate.getAggregate('COUNT');
39+
}
40+
41+
// Check if the count of active controls is greater than zero.
42+
if (activeControlCount > 0) {
43+
// If active controls were found, add an error message to display to the user.
44+
// The message includes the count for better clarity.
45+
gs.addErrorMessage('Cannot retire this policy because it has ' + activeControlCount + ' active controls linked to it. All controls must be retired first.');
46+
47+
// This crucial line aborts the current database transaction (the update operation).
48+
// It prevents the policy record from being marked as 'Retired'.
49+
current.setAbortAction(true);
50+
}
51+
52+
})(current, previous);

0 commit comments

Comments
 (0)