approval-workflows

安装量: 54
排名: #13832

安装

npx skills add https://github.com/groeimetai/snow-flow --skill approval-workflows

Approval Workflows for ServiceNow

Approval workflows route records through configurable approval chains.

Approval Architecture Record (change_request, sc_req_item, etc.) ↓ Approval Rules (sysapproval_rule) ↓ Approval Records (sysapproval_approver) ↓ Approve/Reject Record State Updated

Key Tables Table Purpose sysapproval_approver Individual approval records sysapproval_group Group approval configuration sysapproval_rule Approval rules sys_approval_workflow Approval workflow stages Approval Rules (ES5) Create Approval Rule // Create approval rule (ES5 ONLY!) var rule = new GlideRecord('sysapproval_rule'); rule.initialize();

// Rule identification rule.setValue('name', 'Change Request Manager Approval'); rule.setValue('table', 'change_request'); rule.setValue('order', 100); rule.setValue('active', true);

// Conditions - when rule applies rule.setValue('conditions', 'type=normal^priority<=2');

// Approver type rule.setValue('approver', 'manager'); // manager, group, user, script // For user: rule.setValue('approver_user', userSysId); // For group: rule.setValue('approver_group', groupSysId);

// Approval type rule.setValue('approval_type', 'and'); // and (all must approve), or (any can approve)

// Wait for previous level rule.setValue('wait_for', true);

rule.insert();

Script-Based Approver Selection // Approval rule with script (ES5 ONLY!) var rule = new GlideRecord('sysapproval_rule'); rule.initialize(); rule.setValue('name', 'Cost-Based Approval'); rule.setValue('table', 'sc_req_item'); rule.setValue('approver', 'script');

// Script to determine approvers (ES5 ONLY!) rule.setValue('script', '(function getApprovers(current) {\n' + ' var approvers = [];\n' + ' var cost = parseFloat(current.getValue("estimated_cost")) || 0;\n' + ' \n' + ' // Manager approval for all\n' + ' var caller = current.requested_for.getRefRecord();\n' + ' if (caller.manager) {\n' + ' approvers.push(caller.manager.toString());\n' + ' }\n' + ' \n' + ' // Director approval for > $5000\n' + ' if (cost > 5000) {\n' + ' var director = getDirector(caller);\n' + ' if (director) approvers.push(director);\n' + ' }\n' + ' \n' + ' // VP approval for > $25000\n' + ' if (cost > 25000) {\n' + ' var vp = getVP(caller);\n' + ' if (vp) approvers.push(vp);\n' + ' }\n' + ' \n' + ' return approvers;\n' + '})(current);' );

rule.insert();

Managing Approvals (ES5) Create Approval Manually // Create approval record (ES5 ONLY!) function createApproval(recordSysId, approverSysId, source) { var approval = new GlideRecord('sysapproval_approver'); approval.initialize(); approval.setValue('sysapproval', recordSysId); approval.setValue('approver', approverSysId); approval.setValue('state', 'requested'); approval.setValue('source_table', source.table || '');

return approval.insert();

}

Process Approval Decision // Approve or reject (ES5 ONLY!) function processApprovalDecision(approvalSysId, decision, comments) { var approval = new GlideRecord('sysapproval_approver'); if (!approval.get(approvalSysId)) { return { success: false, message: 'Approval not found' }; }

// Validate current state
if (approval.getValue('state') !== 'requested') {
    return { success: false, message: 'Approval already processed' };
}

// Validate approver
if (approval.getValue('approver') !== gs.getUserID()) {
    if (!canActOnBehalf(approval.getValue('approver'))) {
        return { success: false, message: 'Not authorized to approve' };
    }
}

// Set decision
approval.setValue('state', decision);  // 'approved' or 'rejected'
approval.setValue('comments', comments);
approval.setValue('actual_approver', gs.getUserID());
approval.update();

// Update parent record approval status
updateParentApprovalStatus(approval.getValue('sysapproval'));

return {
    success: true,
    decision: decision,
    record: approval.sysapproval.getDisplayValue()
};

}

function canActOnBehalf(originalApproverId) { // Check delegation var delegation = new GlideRecord('sys_user_delegate'); delegation.addQuery('user', originalApproverId); delegation.addQuery('delegate', gs.getUserID()); delegation.addQuery('starts', '<=', new GlideDateTime()); delegation.addQuery('ends', '>=', new GlideDateTime()); delegation.addQuery('approvals', true); delegation.query(); return delegation.hasNext(); }

Update Parent Record // Update approval status on parent record (ES5 ONLY!) function updateParentApprovalStatus(recordSysId) { // Get all approvals for this record var approvals = new GlideRecord('sysapproval_approver'); approvals.addQuery('sysapproval', recordSysId); approvals.query();

var requested = 0;
var approved = 0;
var rejected = 0;

while (approvals.next()) {
    var state = approvals.getValue('state');
    if (state === 'requested') requested++;
    else if (state === 'approved') approved++;
    else if (state === 'rejected') rejected++;
}

// Determine overall status
var overallStatus = 'not requested';

if (rejected > 0) {
    overallStatus = 'rejected';
} else if (requested > 0) {
    overallStatus = 'requested';
} else if (approved > 0) {
    overallStatus = 'approved';
}

// Update parent record
var parent = new GlideRecord('change_request');
if (parent.get(recordSysId)) {
    parent.setValue('approval', overallStatus);
    parent.update();
}

}

Group Approvals (ES5) Configure Group Approval // Create group approval configuration (ES5 ONLY!) var groupApproval = new GlideRecord('sysapproval_group'); groupApproval.initialize(); groupApproval.setValue('parent', recordSysId); groupApproval.setValue('group', groupSysId);

// Approval requirement groupApproval.setValue('approval', 'any'); // any, all, specific_count groupApproval.setValue('specific_count', 2); // If specific_count

groupApproval.insert();

Group Approval with Minimum // Check if group approval threshold met (ES5 ONLY!) function checkGroupApprovalThreshold(groupApprovalSysId) { var groupConfig = new GlideRecord('sysapproval_group'); if (!groupConfig.get(groupApprovalSysId)) { return false; }

var approvalType = groupConfig.getValue('approval');
var groupId = groupConfig.getValue('group');
var parentId = groupConfig.getValue('parent');

// Count approvals from group members
var ga = new GlideAggregate('sysapproval_approver');
ga.addQuery('sysapproval', parentId);
ga.addQuery('approver.sys_id', 'IN', getGroupMembers(groupId));
ga.addQuery('state', 'approved');
ga.addAggregate('COUNT');
ga.query();

var approvedCount = 0;
if (ga.next()) {
    approvedCount = parseInt(ga.getAggregate('COUNT'), 10);
}

// Check based on type
if (approvalType === 'any') {
    return approvedCount >= 1;
} else if (approvalType === 'all') {
    var memberCount = getGroupMemberCount(groupId);
    return approvedCount >= memberCount;
} else if (approvalType === 'specific_count') {
    var required = parseInt(groupConfig.getValue('specific_count'), 10);
    return approvedCount >= required;
}

return false;

}

Approval Delegation (ES5) Create Delegation // Create approval delegation (ES5 ONLY!) function createDelegation(userId, delegateId, startDate, endDate) { var delegation = new GlideRecord('sys_user_delegate'); delegation.initialize(); delegation.setValue('user', userId); delegation.setValue('delegate', delegateId); delegation.setValue('starts', startDate); delegation.setValue('ends', endDate); delegation.setValue('approvals', true); delegation.setValue('assignments', false);

return delegation.insert();

}

Find Active Delegates // Get delegates who can approve for a user (ES5 ONLY!) function getActiveDelegates(userId) { var delegates = []; var now = new GlideDateTime();

var delegation = new GlideRecord('sys_user_delegate');
delegation.addQuery('user', userId);
delegation.addQuery('approvals', true);
delegation.addQuery('starts', '<=', now);
delegation.addQuery('ends', '>=', now);
delegation.query();

while (delegation.next()) {
    delegates.push({
        delegate: delegation.delegate.getDisplayValue(),
        delegate_id: delegation.getValue('delegate'),
        ends: delegation.getValue('ends')
    });
}

return delegates;

}

Approval Notifications (ES5) Send Approval Request // Trigger approval notification (ES5 ONLY!) function sendApprovalNotification(approvalSysId) { var approval = new GlideRecord('sysapproval_approver'); if (!approval.get(approvalSysId)) return;

var parent = new GlideRecord(approval.source_table);
if (parent.get(approval.getValue('sysapproval'))) {
    gs.eventQueue('approval.request', approval, approval.getValue('approver'), '');
}

}

MCP Tool Integration Available Tools Tool Purpose snow_query_table Query approvals snow_find_artifact Find approval rules snow_execute_script_with_output Test approval scripts snow_create_business_rule Create approval triggers Example Workflow // 1. Query pending approvals await snow_query_table({ table: 'sysapproval_approver', query: 'state=requested^approver=javascript:gs.getUserID()', fields: 'sysapproval,state,sys_created_on' });

// 2. Find approval rules await snow_query_table({ table: 'sysapproval_rule', query: 'table=change_request^active=true', fields: 'name,conditions,approver,approval_type' });

// 3. Check delegations await snow_execute_script_with_output({ script: var delegates = getActiveDelegates(gs.getUserID()); gs.info('Active delegates: ' + JSON.stringify(delegates)); });

Best Practices Clear Conditions - Specific rule conditions Logical Order - Rule ordering matters Escalation - Handle non-response Delegation - Support out-of-office Notifications - Timely reminders Audit Trail - Track all decisions Testing - Test all approval paths ES5 Only - No modern JavaScript syntax

返回排行榜