스크립팅 참조
이 문서는 워크플로 규칙에서 스크립트를 작성하기 위한 포괄적인 참조를 제공합니다. 스크립트를 사용하면 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 등)을 사용할 수 없습니다.