mcpField
A
approval-workflows

approval-workflows

github.com/serac-labs其他7791 次安装9 周前更新
代码仓库

关于 approval-workflows

面向 ServiceNow 的审批工作流技能,用于为记录设计和管理审批链。内容涵盖审批规则、个人与群组审批、委派、通知及相关 MCP 工具,并提供 ES5 示例。

主要功能

  1. 01可配置审批规则
  2. 02个人与群组审批
  3. 03审批委派
  4. 04处理决定并更新父记录
  5. 05审批通知
  6. 06ES5 脚本示例

适用场景

  1. 01为变更请求设置审批流程
  2. 02配置群组审批门槛
  3. 03缺勤期间委派审批
  4. 04检查并测试审批脚本

MCP 相关

文档列出用于查询审批记录、定义审批链、查找相关业务规则、测试脚本及创建审批触发器的 MCP 工具。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/serac-labs/serac --skill approval-workflows

安装后在 Claude Code 中输入/approval-workflows确认已加载。

详细介绍

ServiceNow 的审批工作流

审批工作流会通过可配置的审批链路由记录。

审批架构

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

关键表

表用途
sysapproval_approver单条审批记录
sysapproval_group群组审批配置
sysapproval_rule审批规则
sys_approval_workflow审批工作流阶段

审批规则(ES5)

创建审批规则
// 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()
基于脚本选择审批人
// 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()

管理审批(ES5)

手动创建审批
// 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()
}
处理审批决定
// 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 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()
  }
}

群组审批(ES5)

配置群组审批
// 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()
设置最低人数的群组审批
// 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
}

审批委派(ES5)

创建委派
// 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()
}
查找活跃的受委派人
// 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
}

审批通知(ES5)

发送审批请求
// 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 工具集成

可用工具
工具用途
snow_query_table查询审批和审批规则
snow_approval_chain_manage定义多步骤审批链(define_chain)
snow_artifact_manage查找审批业务规则(action='find')
snow_execute_script测试审批脚本
snow_create_business_rule创建审批触发器
示例工作流
// 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({
  script: `
        var delegates = getActiveDelegates(gs.getUserID());
        gs.info('Active delegates: ' + JSON.stringify(delegates));
    `,
})

最佳实践

  1. 明确条件 - 使用具体的规则条件
  2. 逻辑顺序 - 规则顺序很重要
  3. 升级处理 - 处理未响应的情况
  4. 委派 - 支持不在岗时的委派
  5. 通知 - 及时发送提醒
  6. 审计跟踪 - 跟踪所有决定
  7. 测试 - 测试所有审批路径
  8. 仅限 ES5 - 不使用现代 JavaScript 语法

评论

支持 Markdown