본문으로 건너뛰기

스크립팅 참조

이 문서는 워크플로 규칙에서 스크립트를 작성하기 위한 포괄적인 참조를 제공합니다. 스크립트를 사용하면 JavaScript를 사용하여 고급 자동화 로직을 구현할 수 있습니다.


개요​

워크플로 규칙의 Run Script 작업은 JavaScript 코드를 실행하여 복잡한 티켓 처리 시나리오를 자동화합니다. 스크립트는 티켓 데이터, 메시지 컨텍스트 및 헬퍼 함수에 대한 액세스 권한이 있는 샌드박스 환경에서 실행됩니다.

주요 기능:

  • 티켓 속성 읽기 및 수정
  • 고객 및 소유자 정보 액세스
  • 사용자 정의 필드 작업
  • 조건부 로직 및 루프 사용
  • 안전을 위한 10초 실행 시간 초과

티켓 객체​

ticket 객체는 스크립트의 기본 컨텍스트입니다. 티켓 데이터에 대한 읽기 및 쓰기 액세스를 모두 제공합니다.

읽기 전용 속성​

// 기본 티켓 정보
ticket.id // UUID 문자열
ticket.subject // 티켓 제목 줄

// 현재 상태(객체)
ticket.status.id // 상태 UUID
ticket.status.code // 상태 코드(예: "open", "closed")
ticket.status.name // 상태 표시 이름

// 현재 우선순위(객체)
ticket.priority.id // 우선순위 UUID
ticket.priority.name // 우선순위 표시 이름

// 현재 부서(객체)
ticket.department.id // 부서 UUID
ticket.department.name // 부서 표시 이름

// 할당된 소유자(객체, undefined일 수 있음)
ticket.owner.id // 사용자 UUID
ticket.owner.email // 사용자 이메일
ticket.owner.firstname // 사용자 이름
ticket.owner.lastname // 사용자 성

// 고객 정보(객체)
ticket.customer.id // 고객 UUID
ticket.customer.email // 고객 이메일
ticket.customer.firstname // 고객 이름
ticket.customer.lastname // 고객 성
ticket.customer.name // 고객 전체 이름

// 폴더 및 태그
ticket.folder // 현재 폴더: "INBOX", "ASSIGNED", "SPAM", "ARCHIVE"
ticket.tags // 태그 문자열 배열

쓰기 가능한 속성​

직접 할당으로 이러한 속성을 수정할 수 있습니다:

// 코드 또는 ID로 상태 설정
ticket.status = "closed";
ticket.status = "550e8400-e29b-41d4-a716-446655440000";

// 이름 또는 ID로 우선순위 설정
ticket.priority = "High";
ticket.priority = "550e8400-e29b-41d4-a716-446655440001";

// 이름 또는 ID로 부서 설정
ticket.department = "Sales";
ticket.department = "550e8400-e29b-41d4-a716-446655440002";

// 이메일 또는 ID로 소유자 설정
ticket.owner = "[email protected]";
ticket.owner = "550e8400-e29b-41d4-a716-446655440003";

// 폴더 설정
ticket.folder = "ASSIGNED";
ticket.folder = "SPAM";
ticket.folder = "ARCHIVE";
ticket.folder = "INBOX";

// 태그 설정(기존 태그 모두 대체)
ticket.tags = ["urgent", "vip"];

사용자 정의 필드​

사용자 정의 필드는 코드(표시 이름이 아님)를 사용하여 읽고 쓸 수 있습니다.

사용자 정의 필드 읽기​

// 사용자 정의 필드 값에 직접 액세스
var orderId = ticket.order_id; // 텍스트 필드
var amount = ticket.order_amount; // 숫자 필드
var isVip = ticket.is_vip; // 부울 필드
var region = ticket.region; // 선택 필드

사용자 정의 필드 쓰기​

// 텍스트 사용자 정의 필드 설정
ticket.order_id = "ORD-12345";

// 숫자 사용자 정의 필드 설정
ticket.order_amount = 199.99;

// 부울 사용자 정의 필드 설정
ticket.is_vip = true;

// 선택 사용자 정의 필드 설정
ticket.category = "billing";

// 날짜 사용자 정의 필드 설정(ISO 8601 형식)
ticket.due_date = "2024-12-31T23:59:59Z";
ticket.due_date = "2024-12-31";

메시지 객체​

message 객체는 규칙이 메시지 이벤트(새 고객 답장, 새 직원 답장 등)에 의해 트리거될 때 사용할 수 있습니다.

if (message) {
message.id // 메시지 UUID
message.body_text // 메시지 내용(일반 텍스트)
message.body_html // 메시지 내용(HTML)
message.createdAt // ISO 8601 타임스탬프
}

예:

if (message && message.body_text) {
var bodyLower = message.body_text.toLowerCase();

if (bodyLower.includes("cancel subscription")) {
ticket.department = "Retention";
ticket.priority = "High";
}
}

헬퍼 함수​

getStatuses()​

사용 가능한 모든 상태의 배열을 반환합니다.

var statuses = getStatuses();
// 반환: [{ id: "...", code: "open", name: "Open" }, ...]

// 특정 상태 찾기
for (var i = 0; i < statuses.length; i++) {
if (statuses[i].code === "pending") {
ticket.status = statuses[i].id;
break;
}
}

getPriorities()​

사용 가능한 모든 우선순위의 배열을 반환합니다.

var priorities = getPriorities();
// 반환: [{ id: "...", name: "Low" }, { id: "...", name: "High" }, ...]

getDepartments()​

사용 가능한 모든 부서의 배열을 반환합니다.

var departments = getDepartments();
// 반환: [{ id: "...", name: "Support" }, { id: "...", name: "Sales" }, ...]

getUsers()​

사용 가능한 모든 사용자(상담원)의 배열을 반환합니다.

var users = getUsers();
// 반환: [{ id: "...", email: "[email protected]", firstname: "John", lastname: "Doe" }, ...]

fetch()​

외부 API에 HTTP 요청을 합니다. 동기식 - 결과를 직접 반환합니다.

var response = fetch(url, options);
// response: { ok, status, statusText, text, json }

옵션: method(GET/POST/PUT/DELETE), headers(객체), body(문자열 또는 객체)

예: CRM에서 가져와서 사용자 정의 필드 업데이트

var response = fetch("https://api.example.com/customers/" + ticket.customer.email, {
headers: { "Authorization": "Bearer YOUR_API_KEY" }
});

if (response.ok && response.json) {
ticket.customer_tier = response.json.tier;
ticket.lifetime_value = response.json.lifetime_value;

if (response.json.tier === "enterprise") {
ticket.priority = "High";
}
}

예: 웹훅에 POST

var response = fetch("https://hooks.example.com/helpdesk", {
method: "POST",
body: { ticket_id: ticket.id, customer_email: ticket.customer.email }
});

참고: HTTPS만, 5초 시간 초과, 1MB 응답 제한, 내부 네트워크 차단됨.


일반적인 패턴​

조건부 할당​

// 제목을 기반으로 우선순위 설정
if (ticket.subject.toLowerCase().includes("urgent")) {
ticket.priority = "High";
} else if (ticket.subject.toLowerCase().includes("question")) {
ticket.priority = "Low";
}

부서 라우팅​

var subject = ticket.subject.toLowerCase();

if (subject.includes("billing") || subject.includes("payment") || subject.includes("invoice")) {
ticket.department = "Billing";
} else if (subject.includes("technical") || subject.includes("bug") || subject.includes("error")) {
ticket.department = "Technical Support";
} else if (subject.includes("sales") || subject.includes("pricing") || subject.includes("quote")) {
ticket.department = "Sales";
}

고객 도메인 기반 로직​

if (ticket.customer && ticket.customer.email) {
var email = ticket.customer.email;
var domain = email.split("@")[1];

// 엔터프라이즈 고객 처리
if (domain === "bigcorp.com" || domain === "enterprise.org") {
ticket.priority = "High";
ticket.department = "Enterprise Support";
ticket.is_enterprise = true;
}

// 교육 기관
if (domain.endsWith(".edu")) {
ticket.segment = "education";
}
}

태그 관리​

// 기존 태그를 잃지 않고 태그 추가
var existingTags = ticket.tags || [];
existingTags.push("processed");
existingTags.push("automated");
ticket.tags = existingTags;

메시지 작업​

if (message && message.body_text) {
var body = message.body_text.toLowerCase();

// 불만 키워드 감지
var frustrationKeywords = ["frustrated", "angry", "terrible", "worst", "unacceptable"];
for (var i = 0; i < frustrationKeywords.length; i++) {
if (body.includes(frustrationKeywords[i])) {
ticket.priority = "High";
ticket.needs_attention = true;
break;
}
}
}

라운드 로빈 할당​

var users = getUsers();
if (users.length > 0) {
// 티켓 ID 해시를 기반으로 한 간단한 라운드 로빈
var ticketHash = 0;
for (var i = 0; i < ticket.id.length; i++) {
ticketHash += ticket.id.charCodeAt(i);
}
var assigneeIndex = ticketHash % users.length;
ticket.owner = users[assigneeIndex].email;
}

오류 처리​

스크립트는 안전한 환경에서 실행됩니다:

  • 구문 오류는 포착되어 로그에 기록됩니다. 스크립트는 건너뜁니다.
  • 잘못된 필드 값(예: 존재하지 않는 상태 이름)은 무시됩니다.
  • 시간 초과(10초)는 무한 루프를 방지합니다.
  • 오류는 다른 규칙이나 시스템 구성 요소로 전파되지 않습니다.

모범 사례:

// 속성에 액세스하기 전에 null/undefined 확인
if (ticket.customer && ticket.customer.email) {
// ticket.customer.email에 안전하게 액세스
}

if (message) {
// 메시지 속성에 안전하게 액세스
}

// 복잡한 로직에 try-catch 사용
try {
var data = JSON.parse(ticket.custom_json);
ticket.parsed_field = data.value;
} catch (e) {
// 오류를 우아하게 처리
}

제한 사항​

  • 실행 시간 초과: 스크립트는 10초 후에 종료됩니다.
  • 파일 시스템 액세스 없음: 파일 작업을 사용할 수 없습니다.
  • 영구 상태 없음: 변수는 스크립트 실행 간에 지속되지 않습니다.
  • 읽기 전용 필드: ticket.id, ticket.subject, ticket.customer는 수정할 수 없습니다.
  • ES5 JavaScript: 최신 JavaScript 기능(화살표 함수, const/let 등)을 사용할 수 없습니다.