csm-patterns

Customer Service Management for ServiceNow

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "csm-patterns" with this command: npx skills add groeimetai/snow-flow/groeimetai-snow-flow-csm-patterns

Customer Service Management for ServiceNow

CSM enables organizations to deliver exceptional customer service through cases, accounts, and self-service.

CSM Architecture

Account (customer_account) ├── Contacts (customer_contact) ├── Contracts (ast_contract) │ └── Entitlements (service_entitlement) ├── Assets (alm_asset) └── Cases (sn_customerservice_case) ├── Case Tasks └── Communications

Key Tables

Table Purpose

customer_account

Customer accounts

customer_contact

Account contacts

sn_customerservice_case

Customer cases

service_entitlement

Service entitlements

ast_contract

Service contracts

Customer Accounts (ES5)

Create Customer Account

// Create customer account (ES5 ONLY!) var account = new GlideRecord("customer_account") account.initialize()

// Basic info account.setValue("name", "Acme Corporation") account.setValue("account_code", "ACME-001") account.setValue("industry", "Technology")

// Contact info account.setValue("phone", "+1-555-123-4567") account.setValue("email", "info@acme.com") account.setValue("website", "https://www.acme.com")

// Address account.setValue("street", "123 Main Street") account.setValue("city", "San Francisco") account.setValue("state", "CA") account.setValue("zip", "94105") account.setValue("country", "US")

// Account details account.setValue("account_type", "customer") // customer, partner, vendor account.setValue("tier", "gold") // bronze, silver, gold, platinum

// Assignment account.setValue("account_manager", accountManagerSysId)

account.insert()

Create Contact

// Create contact for account (ES5 ONLY!) var contact = new GlideRecord("customer_contact") contact.initialize()

// Link to account contact.setValue("account", accountSysId)

// Contact info contact.setValue("name", "John Smith") contact.setValue("email", "john.smith@acme.com") contact.setValue("phone", "+1-555-123-4568") contact.setValue("title", "IT Manager")

// Contact type contact.setValue("type", "primary") // primary, billing, technical contact.setValue("active", true)

// Create user for portal access var user = createUserFromContact(contact) contact.setValue("user", user)

contact.insert()

Customer Cases (ES5)

Create Customer Case

// Create customer case (ES5 ONLY!) var caseRecord = new GlideRecord("sn_customerservice_case") caseRecord.initialize()

// Case info caseRecord.setValue("short_description", "Unable to access product features") caseRecord.setValue("description", "Customer reports error when trying to use premium features")

// Classification caseRecord.setValue("category", "product_issue") caseRecord.setValue("subcategory", "access_problem") caseRecord.setValue("priority", 2)

// Customer caseRecord.setValue("account", accountSysId) caseRecord.setValue("contact", contactSysId)

// Product/Asset caseRecord.setValue("product", productSysId) caseRecord.setValue("asset", assetSysId)

// Assignment caseRecord.setValue("assignment_group", getGroupSysId("Customer Support"))

// Channel caseRecord.setValue("channel", "email") // email, phone, chat, web

caseRecord.insert()

Case Routing

// Route case based on account and product (ES5 ONLY!) // Business Rule: before, insert, sn_customerservice_case

;(function executeRule(current, previous) { if (current.assignment_group) { return // Already assigned }

var group = determineAssignmentGroup(current) if (group) { current.assignment_group = group } })(current, previous)

function determineAssignmentGroup(caseRecord) { // Check for premium support entitlement if (hasPremiumSupport(caseRecord.getValue("account"))) { return getGroupSysId("Premium Support") }

// Route by product var product = caseRecord.product.getRefRecord() if (product.isValidRecord()) { var supportGroup = product.getValue("support_group") if (supportGroup) { return supportGroup } }

// Default return getGroupSysId("General Support") }

function hasPremiumSupport(accountSysId) { var entitlement = new GlideRecord("service_entitlement") entitlement.addQuery("account", accountSysId) entitlement.addQuery("type", "premium_support") entitlement.addQuery("start_date", "<=", new GlideDateTime()) entitlement.addQuery("end_date", ">=", new GlideDateTime()) entitlement.query() return entitlement.hasNext() }

Entitlements (ES5)

Create Service Entitlement

// Create entitlement (ES5 ONLY!) var entitlement = new GlideRecord("service_entitlement") entitlement.initialize()

entitlement.setValue("name", "Premium Support - Acme Corp") entitlement.setValue("account", accountSysId) entitlement.setValue("contract", contractSysId)

// Entitlement type entitlement.setValue("type", "premium_support")

// Dates entitlement.setValue("start_date", "2024-01-01") entitlement.setValue("end_date", "2024-12-31")

// Limits entitlement.setValue("total_cases", 100) entitlement.setValue("used_cases", 0) entitlement.setValue("remaining_cases", 100)

// SLA entitlement.setValue("response_sla", "4 hours") entitlement.setValue("resolution_sla", "24 hours")

entitlement.insert()

Check Entitlement

// Check if customer is entitled to service (ES5 ONLY!) function checkEntitlement(accountSysId, entitlementType) { var now = new GlideDateTime()

var entitlement = new GlideRecord("service_entitlement") entitlement.addQuery("account", accountSysId) entitlement.addQuery("type", entitlementType) entitlement.addQuery("start_date", "<=", now) entitlement.addQuery("end_date", ">=", now) entitlement.query()

if (entitlement.next()) { var remaining = parseInt(entitlement.getValue("remaining_cases"), 10)

return {
  entitled: true,
  remaining: remaining,
  unlimited: remaining &#x3C; 0, // -1 = unlimited
  expiration: entitlement.getValue("end_date"),
  sla: {
    response: entitlement.getValue("response_sla"),
    resolution: entitlement.getValue("resolution_sla"),
  },
}

}

return { entitled: false, message: "No active entitlement found", } }

Decrement Entitlement

// Use entitlement when case created (ES5 ONLY!) // Business Rule: after, insert, sn_customerservice_case

;(function executeRule(current, previous) { var accountSysId = current.getValue("account") if (!accountSysId) return

var entitlement = new GlideRecord("service_entitlement") entitlement.addQuery("account", accountSysId) entitlement.addQuery("type", "support") entitlement.addQuery("start_date", "<=", new GlideDateTime()) entitlement.addQuery("end_date", ">=", new GlideDateTime()) entitlement.addQuery("remaining_cases", ">", 0) entitlement.orderBy("end_date") // Use earliest expiring first entitlement.setLimit(1) entitlement.query()

if (entitlement.next()) { var used = parseInt(entitlement.getValue("used_cases"), 10) var remaining = parseInt(entitlement.getValue("remaining_cases"), 10)

entitlement.setValue("used_cases", used + 1)
entitlement.setValue("remaining_cases", remaining - 1)
entitlement.update()

// Link case to entitlement
current.u_entitlement = entitlement.getUniqueValue()
current.update()

// Alert if running low
if (remaining - 1 &#x3C;= 5) {
  gs.eventQueue("entitlement.low", entitlement, accountSysId, (remaining - 1).toString())
}

} })(current, previous)

Customer Portal (ES5)

Portal Case Submission

// Widget Server Script for case submission (ES5 ONLY!) ;(function () { // Handle case creation if (input && input.action === "createCase") { var contactId = getContactForUser(gs.getUserID()) if (!contactId) { data.error = "No contact record found" return }

var contact = new GlideRecord("customer_contact")
contact.get(contactId)

// Create case
var caseRecord = new GlideRecord("sn_customerservice_case")
caseRecord.initialize()
caseRecord.setValue("short_description", input.subject)
caseRecord.setValue("description", input.description)
caseRecord.setValue("contact", contactId)
caseRecord.setValue("account", contact.getValue("account"))
caseRecord.setValue("priority", input.priority || 3)
caseRecord.setValue("channel", "web")

var caseSysId = caseRecord.insert()

data.success = true
data.case_number = caseRecord.getValue("number")
data.case_sys_id = caseSysId

}

// Get user's cases if (!input || input.action === "getCases") { var contactId = getContactForUser(gs.getUserID()) data.cases = []

if (contactId) {
  var gr = new GlideRecord("sn_customerservice_case")
  gr.addQuery("contact", contactId)
  gr.orderByDesc("sys_created_on")
  gr.setLimit(20)
  gr.query()

  while (gr.next()) {
    data.cases.push({
      sys_id: gr.getUniqueValue(),
      number: gr.getValue("number"),
      short_description: gr.getValue("short_description"),
      state: gr.state.getDisplayValue(),
      priority: gr.priority.getDisplayValue(),
      opened_at: gr.getValue("opened_at"),
    })
  }
}

}

function getContactForUser(userId) { var contact = new GlideRecord("customer_contact") contact.addQuery("user", userId) contact.query() if (contact.next()) { return contact.getUniqueValue() } return null } })()

MCP Tool Integration

Available Tools

Tool Purpose

snow_query_table

Query CSM tables

snow_find_artifact

Find CSM configurations

snow_execute_script_with_output

Test CSM scripts

snow_deploy

Deploy CSM widgets

Example Workflow

// 1. Query customer cases await snow_query_table({ table: "sn_customerservice_case", query: "active=true^priority<=2", fields: "number,short_description,account,contact,state", })

// 2. Check entitlements await snow_execute_script_with_output({ script: var result = checkEntitlement('account_sys_id', 'premium_support'); gs.info(JSON.stringify(result)); , })

// 3. Find accounts with expiring contracts await snow_query_table({ table: "ast_contract", query: "endsBETWEENjavascript:gs.beginningOfToday()@javascript:gs.daysAgoEnd(-30)", fields: "number,vendor,ends,account", })

Best Practices

  • Account Hierarchy - Parent/child accounts

  • Contact Roles - Clear contact types

  • Entitlements - Track usage limits

  • SLA Mapping - Account tier to SLA

  • Portal Access - Secure customer data

  • Case Routing - Smart assignment

  • Communication - Audit trail

  • ES5 Only - No modern JavaScript syntax

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

predictive-intelligence

No summary provided by upstream source.

Repository SourceNeeds Review
General

scheduled-jobs

No summary provided by upstream source.

Repository SourceNeeds Review
General

document-management

No summary provided by upstream source.

Repository SourceNeeds Review