見出し画像

新米情シスが簡易ヘルプデスク機能を作ってみた話

こんばんは、新米情シスでリーダーしている ふみふみです!
前回の初投稿では思っていた以上に多くの方に見ていただき、ありがとうございました!

記事を投稿するのは緊張しますが、あくまで新米情シスが現状をアウトプットしてみているものなので、暖かく応援いただけたらと思います。

きっかけ

さて、今回は入社して2ヶ月目に SlackとGoogleフォームとGASで作成した「簡易ヘルプデスク機能」についてお話したいと思います。

弊社では僕が入社した時点でSlackにQA用のチャンネルがあり、そこに社員が思うがままに問い合わせ内容を入力していました。元々の運用ルールとしては、、、

 ・1つの問い合わせに関する応答は、スレッドに返信する形で行う
  ※ チャンネルにそのまま投稿すると、問い合わせが流れる為

当初はZendeskやServiceNowの導入を検討していたようなのですが、予算的に導入できずに上記の対応となっていたようです。
そこで僕が入社しヘルプデスク業務は2人体制となり、問題が発生。

 1. お互い見ていて対応中なのか、そもそも見ていないのか分からない
 2. 問い合わせ・依頼に対して不足事項があれば、都度確認する必要がある
 3. そもそも何が不足しているのか、都度考える必要がある

1. については「👀」(目) アイコンのリアクションをつける運用をすることで解決させました。
2. をどうしたものかと。社内wikiとかメモに「この時は〇〇、あの時は△△」とか書いてもいいのですが、対応時に忘れてたら均一な対応ができないと思いました(+面倒くさい...。

目的


上記を解決することが目的ですが、改めて書くと大きく3点。

 1. Googleフォームにより項目を明確化させ、必要な内容はユーザーに記入させたい
 2. 情シス側が確認するべき内容の漏れ防止
 3. フォームが投稿されたらQA用チャンネルに自動投稿され、「情シス」と「投稿者」に自動でメンション通知させたい (メール見たくない

構成図

構成図はざっくりこんな感じです。

スクリーンショット 2020-08-30 23.20.43

フォーム部分

まずは元となるGoogleフォームから。ここら辺はよく来る問い合わせの情報と過去の対応内容から必要な項目を作成します。僕の場合は以下のような感じで作成しました。

 1. まず問い合わせ種別を選択させるセクションを作成する
 2. 種別毎にそれぞれセクションを作成する
 3. 各セクション内に、必要な入力項目を作成する
 4. 1の問い合わせ種別の回答に応じて適切なセクションに移動するように設定する
 5. [設定] から、「メールアドレスを収集する」「自社と信頼できる組織のユーザーに限定する」にチェックを入れる

スクリーンショット 2020-08-30 22.43.45

GAS部分①

担当者へのメンション部分です。
Googleフォームから取得できる情報だけではSlack上でメンションできない為、Slack APIを用いて別のスプレッドシート上に定期的に出力させています。そのGASをライブラリ化させ、もう一つのGASで読み込み、使用します。(ライブラリ化やAPIトークンの取得方法は調べてみて下さい)。

 1. 作成したスプレッドシートの [ツール] > [スクリプト エディタ] をクリックする
 2. scriptを書く
 3. [現在のプロジェクトのトリガー] > [トリガーを追加] から、1日1回実行されるように設定

※ スプレッドシートの参考

スクリーンショット 2020-08-30 22.20.49

※ scriptの参考(あくまで自分用

/* ===========================================

 SlackAPIを利用しSlackID等を取得し、スプレッドシートに書き込む
 ※ これをトリガーに設定

=========================================== */
function writeUserIds() {

 const userIds = getUserIds();
 
 // 読み込み・書き込みに必要なシート情報
 const sheetId   = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
 const sheetName = "xxxxx"; 
 const writeRow  = userIds.length;
 const writeCol  = userIds[0].length;
 
 // スプレッドシート読み込み
 const spreadsheet = SpreadsheetApp.openById(sheetId);
 const sheet       = spreadsheet.getSheetByName(sheetName);
 const lastRow     = sheet.getLastRow();
 const lastCol     = sheet.getLastColumn();
 
 // 一度既存の情報をクリアする
 sheet.getRange(2, 3, lastRow - 1, lastCol - 2).clearContent();
 
 // ユーザー情報をセットする
 sheet.getRange(2, 3, writeRow, writeCol).setValues(userIds);
 
 // 罫線引く
 sheet.getRange(2, 3, writeRow, writeCol).setBorder(
   /* top        = */ true,
   /* left       = */ true,
   /* bottom     = */ true,
   /* right      = */ true,
   /* vertical   = */ true,
   /* horizontal = */ true,
   /* color      = */ "#9d9b9b",
   /* style      = */ SpreadsheetApp.BorderStyle.SOLID
 );

}

/* ===========================================

 Slack APIを使用してユーザーID一覧を取得する

=========================================== */
function getUserIds() {
 
 // Slack apiのアクセストークン
 const token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
 
 // インテグレーションのWebhook URL
 const url = "https://slack.com/api/users.list" + "?token=" + token;
 
 // curlの結果
 const response = UrlFetchApp.fetch(url);

 const json    = JSON.parse(response.getContentText());
 const members = json["members"];

 // ユーザー名とユーザーIDを配列に入れる
 const userIds = [];
 members.forEach(function(member) {
   if (member["is_bot"] == true || member["deleted"] == true) { return; };
   userIds.push([member["name"], member["id"]]);
 });

 Logger.log(userIds);
 return userIds;

}


/* ===========================================

 emailから、SlackのIDを取得

=========================================== */
function getSlackIdFromEmail(email) {
 
 // スプレッドシート読み込み情報
 const sheetId   = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
 const sheetName = "xxxxxx"; 
 
 // スプレッドシート読み込み
 const spreadsheet = SpreadsheetApp.openById(sheetId);
 const sheet       = spreadsheet.getSheetByName(sheetName);
 const values      = sheet.getDataRange().getValues();
 
 // メールアドレスと一致する配列を取得
 const result = values.filter(value => value[1] == email);
 
 // 取得した配列からSlackIDを返す
 return result[0][3];
 
}


GAS部分②

フォーム連動部分です。

 1. 作成したフォームの [ ⋮ ] > [スクリプト エディタ] をクリックする
 2. scriptを書く
 3. [現在のプロジェクトのトリガー] > [トリガーを追加] から、フォーム送信時に実行されるように設定
 4. スクリプトエディタの [リソース] > [ライブラリ] > からGAS①で作成したscriptのライブラリキーを入力し、[追加] をクリック

※ scriptの参考(あくまで自分用

/* ===========================================

 作業依頼フォームが送信されたら、Slackへ通知
 ※ これをトリガーに設定

=========================================== */
function getItemResponses(e) {
 
 FormApp.getActiveForm();
 
 const itemResponses = e.response.getItemResponses();
 const email         = e.response.getRespondentEmail();
 
 let result = [];
 
 for (let i = 0; i < itemResponses.length; i++) {
   
   const itemResponse = itemResponses[i];
   const type         = itemResponse.getItem().getType();
   const question     = itemResponse.getItem().getTitle();
   const answer       = itemResponse.getResponse();
    
   
   // チェックボックスグリッドの場合、そのままでは行見出しが取得できないので個別処理
   if (type == "CHECKBOX_GRID") {
     
     let checkGridOrder = "";
     const rows = itemResponse.getItem().asCheckboxGridItem().getRows();
     
     for(let j = 0; j < rows.length; j++){
       const titleRow  = rows[j];
       const answerCol = answer[j];
       checkGridOrder += titleRow + ' : ' + answerCol + '\n';
     }
   
     result.push([question, checkGridOrder]);
     
   } 
   // グリッドの場合も、そのままでは行見出しが取得できないので個別処理
   else if (type == "GRID") {
     
     let gridOrder = "";
     const rows = itemResponse.getItem().asGridItem().getRows();
     
     for(let j = 0; j < rows.length; j++){
       const titleRow  = rows[j];
       const answerCol = answer[j];
       gridOrder += titleRow + ' : ' + answerCol + '\n';
     }
     
     result.push([question, gridOrder]);
     
   } else {
     
     result.push([question, answer]);
   }
 }
     
 const body = makeBody(email, result);
 postSlack(body);
 
}


/* ===========================================

 Slack通知用のフィールド (本文の部分) 作成

=========================================== */
function makeBody(email, result) {

 let fields = [];
 
 for (let i = 0; i < result.length; i++) {
   
   const question = result[i][0];
   const answer   = result[i][1];
       
   if (i == 0) {
     fields.push({"title": question, "value": "`" + answer.toString() + "`", "short": false});
   } else {
     fields.push({"title": question, "value": answer.toString(), "short": false});
   }
 }
   
 const body =
 {
   "attachments" : [
     {
       "fallback": "作業依頼がきたよ:bulb:",
       "color": "#4169e1",
       "pretext": "<@xxxxxxxxx> san\n\n" + "<@" + pg.getSlackIdFromEmail(email) + "> san から作業依頼がきました:bulb:",
       "fields": fields
     }
   ], 
 };
 
 return body;
 
}


/* ===========================================

 Slack通知部分

=========================================== */
function postSlack(body) {
 
 // インテグレーションのWebhook URL(検証用)
 const url = "https://hooks.slack.com/services/xxxxxxxx/xxxxxxxxx/xxxxxxxxxxxxxxxxxxxxxx";
 
 // 送信オプション
 const options = {
   method      : "post",
   contentType : "application/json",
   payload     : JSON.stringify(body),
 };

 // 送信処理
 UrlFetchApp.fetch(url, options);
 
}

完成品

上記で出来上がった(通知された)ものはこんな感じになります!

スクリーンショット 2020-08-30 21.46.28

現在のヘルプデスクの運用方法は以下で行っています。

 1. ユーザーがフォームから問い合わせ→Slack自動通知
 2. Slackに問い合わせが来てスレッドを見たら、「👀」(目) アイコンでリアクション
 3. スレッドに返信する形で、対応内容を記載
 4. 対応が完了したらスレッドに「done」アイコンでリアクション

どんな問い合わせが何件あったかなどはGoogleフォームで自動収集されるので、簡単な問い合わせ分析は可能と思います(分析はしてないけど...
また、問い合わせへの基本的な対応方法・方針は社内wiki (Confluence) にまとめている為、対応に関しては概ね誰でも対応できるようにしています(2人しかいないけど...

最後に

これはあくまで自分が今までGASを利用する機会があったのでこの構成で作成しましたし、社員数も200人くらいなので成り立っている部分はあると思います。
所属する会社によって状況はマチマチだと思いますのですが、無料でカバーできる範囲はやってみるのもアリかなと思います(属人化は避けたいですが...

現在メールやDM、チャンネルに漠然と問い合わせもらっている場合は、参考にしていただければ幸いです!

この記事が気に入ったらサポートをしてみませんか?